diff --git a/UserRepos/readme.md b/UserRepos/readme.md deleted file mode 100644 index 80243ba..0000000 --- a/UserRepos/readme.md +++ /dev/null @@ -1,9 +0,0 @@ -# User Repositories & Applications - -Here are links to the repos of people that use olcPixelGameEngine! If you want your stuff added, send me the link and a very brief description of what it is. - -# Games - * CodeJam2020 - Logic Puzzle game - * https://github.com/Jack-Punter/olcCodeJam2020_TheGreatMachine - * CodeJam2020 - A very simple dungeon rogue-like with a twist - * https://github.com/benkyd/OLCCodeJam2020-The-Great-Machine diff --git a/Videos/CarCrimeCity/Part1/City_Roads1_mip0.png b/Videos/CarCrimeCity/Part1/City_Roads1_mip0.png deleted file mode 100644 index 46cec50..0000000 Binary files a/Videos/CarCrimeCity/Part1/City_Roads1_mip0.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part1/OneLoneCoder_CarCrimeCity1.cpp b/Videos/CarCrimeCity/Part1/OneLoneCoder_CarCrimeCity1.cpp deleted file mode 100644 index 3febabc..0000000 --- a/Videos/CarCrimeCity/Part1/OneLoneCoder_CarCrimeCity1.cpp +++ /dev/null @@ -1,670 +0,0 @@ -/* - BIG PROJECT - Top Down City Based Car Crime Game Part #1 - "Probably gonna regret starting this one..." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Instructions: - ~~~~~~~~~~~~~ - This is the source that accompanies part 1 of the video series which - can be viewed via the link below. Here you can create and edit a city - from a top down perspective ad navigate it with the car. - - Using the mouse left click you can select cells. Using right click clears - all the selected cells. - - "E" - Lowers building height - "T" - Raises building height - "R" - Places road - "Z, X" - Zoom - "Up, Left, Right" - Control car - "F5" - Save current city - "F8" - Load existing city - - A default city is provided for you - "example1.city", please ensure - you have this file also. - - Relevant Video: https://youtu.be/mD6b_hP17WI - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" -#include "olcPGEX_Graphics3D.h" - -#include -#include -#include -#include -#include -#include -#include - -// Override base class with your custom functionality -class CarCrimeCity : public olc::PixelGameEngine -{ -public: - CarCrimeCity() - { - sAppName = "Car Crime City"; - } - -private: - - // Define the cell - struct sCell - { - int nHeight = 0; - int nWorldX = 0; - int nWorldY = 0; - bool bRoad = false; - bool bBuilding = true; - }; - - // Map variables - int nMapWidth; - int nMapHeight; - sCell *pMap; - - olc::Sprite *sprAll; - olc::Sprite *sprGround; - olc::Sprite *sprRoof; - olc::Sprite *sprFrontage; - olc::Sprite *sprWindows; - olc::Sprite *sprRoad[12]; - olc::Sprite *sprCar; - - float fCameraX = 0.0f; - float fCameraY = 0.0f; - float fCameraZ = -10.0f; - - olc::GFX3D::mesh meshCube; - olc::GFX3D::mesh meshFlat; - olc::GFX3D::mesh meshWallsOut; - - float fCarAngle = 0.0f; - float fCarSpeed = 2.0f; - olc::GFX3D::vec3d vecCarVel = { 0,0,0 }; - olc::GFX3D::vec3d vecCarPos = { 0,0,0 }; - - - int nMouseWorldX = 0; - int nMouseWorldY = 0; - int nOldMouseWorldX = 0; - int nOldMouseWorldY = 0; - - bool bMouseDown = false; - std::unordered_set setSelectedCells; - - olc::GFX3D::PipeLine pipeRender; - olc::GFX3D::mat4x4 matProj; - olc::GFX3D::vec3d vUp = { 0,1,0 }; - olc::GFX3D::vec3d vEye = { 0,0,-10 }; - olc::GFX3D::vec3d vLookDir = { 0,0,1 }; - - olc::GFX3D::vec3d viewWorldTopLeft, viewWorldBottomRight; - - - void SaveCity(std::string sFilename) - { - std::ofstream file(sFilename, std::ios::out | std::ios::binary); - file.write((char*)&nMapWidth, sizeof(int)); - file.write((char*)&nMapHeight, sizeof(int)); - for (int x = 0; x < nMapWidth; x++) - { - for (int y = 0; y < nMapHeight; y++) - { - file.write((char*)&pMap[y*nMapWidth + x], sizeof(sCell)); - } - } - } - - void LoadCity(std::string sFilename) - { - std::ifstream file(sFilename, std::ios::in | std::ios::binary); - file.read((char*)&nMapWidth, sizeof(int)); - file.read((char*)&nMapHeight, sizeof(int)); - delete[] pMap; - pMap = new sCell[nMapWidth * nMapHeight]; - for (int x = 0; x < nMapWidth; x++) - { - for (int y = 0; y < nMapHeight; y++) - { - file.read((char*)&pMap[y*nMapWidth + x], sizeof(sCell)); - } - } - } - -public: - bool OnUserCreate() override - { - // Load Sprite Sheet - sprAll = new olc::Sprite("City_Roads1_mip0.png"); - - // Here we break up the sprite sheet into individual textures. This is more - // out of convenience than anything else, as it keeps the texture coordinates - // easy to manipulate - - // Building Lowest Floor - sprFrontage = new olc::Sprite(32, 96); - SetDrawTarget(sprFrontage); - DrawPartialSprite(0, 0, sprAll, 288, 64, 32, 96); - - // Building Windows - sprWindows = new olc::Sprite(32, 96); - SetDrawTarget(sprWindows); - DrawPartialSprite(0, 0, sprAll, 320, 64, 32, 96); - - // Plain Grass Field - sprGround = new olc::Sprite(96, 96); - SetDrawTarget(sprGround); - DrawPartialSprite(0, 0, sprAll, 192, 0, 96, 96); - - // Building Roof - sprRoof = new olc::Sprite(96, 96); - SetDrawTarget(sprRoof); - DrawPartialSprite(0, 0, sprAll, 352, 64, 96, 96); - - // There are 12 Road Textures, aranged in a 3x4 grid - for (int r = 0; r < 12; r++) - { - sprRoad[r] = new olc::Sprite(96, 96); - SetDrawTarget(sprRoad[r]); - DrawPartialSprite(0, 0, sprAll, (r%3)*96, (r/3)*96, 96, 96); - } - - // Don't foregt to set the draw target back to being the main screen (been there... wasted 1.5 hours :| ) - SetDrawTarget(nullptr); - - // The Yellow Car - sprCar = new olc::Sprite("car_top.png"); - - - - // Define the city map, a 64x32 array of Cells. Initialise cells - // to be just grass fields - nMapWidth = 64; - nMapHeight = 32; - pMap = new sCell[nMapWidth * nMapHeight]; - for (int x = 0; x < nMapWidth; x++) - { - for (int y = 0; y < nMapHeight; y++) - { - pMap[y*nMapWidth + x].bRoad = false; - pMap[y*nMapWidth + x].nHeight = 0; - pMap[y*nMapWidth + x].nWorldX = x; - pMap[y*nMapWidth + x].nWorldY = y; - } - } - - - // Now we'll hand construct some meshes. These are DELIBERATELY simple and not optimised (see a later video) - // Here the geometry is unit in size (1x1x1) - - // A Full cube - Always useful for debugging - meshCube.tris = - { - // SOUTH - { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, }, - { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, }, - - // EAST - { 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, }, - { 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, }, - - // NORTH - { 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, }, - { 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, }, - - // WEST - { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, }, - { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, }, - - // TOP - { 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, }, - { 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, }, - - // BOTTOM - { 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, }, - { 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, }, - - }; - - // A Flat quad - meshFlat.tris = - { - { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, }, - { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, }, - }; - - // The four outer walls of a cell - meshWallsOut.tris = - { - // EAST - { 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, }, - { 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, }, - - // WEST - { 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, }, - { 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, }, - - // TOP - { 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, }, - { 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, }, - - // BOTTOM - { 1.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, }, - { 1.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, }, - }; - - - // Initialise the 3D Graphics PGE Extension. This is required - // to setup internal buffers to the same size as the main output - olc::GFX3D::ConfigureDisplay(); - - // Configure the rendering pipeline with projection and viewport properties - pipeRender.SetProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.1f, 1000.0f, 0.0f, 0.0f, ScreenWidth(), ScreenHeight()); - - // Also make a projection matrix, we might need this later - matProj = olc::GFX3D::Math::Mat_MakeProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.1f, 1000.0f); - - LoadCity("example1.city"); - - // Ok, lets go! - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - // Directly manipulate camera - //if (GetKey(olc::Key::W).bHeld) fCameraY -= 2.0f * fElapsedTime; - //if (GetKey(olc::Key::S).bHeld) fCameraY += 2.0f * fElapsedTime; - //if (GetKey(olc::Key::A).bHeld) fCameraX -= 2.0f * fElapsedTime; - //if (GetKey(olc::Key::D).bHeld) fCameraX += 2.0f * fElapsedTime; - if (GetKey(olc::Key::Z).bHeld) fCameraZ += 5.0f * fElapsedTime; - if (GetKey(olc::Key::X).bHeld) fCameraZ -= 5.0f * fElapsedTime; - - if (GetKey(olc::Key::F5).bReleased) SaveCity("example1.city"); - if (GetKey(olc::Key::F8).bReleased) LoadCity("example1.city"); - - // === Handle User Input for Editing == - - // If there are no selected cells, then only edit the cell under the current mouse cursor - // otherwise iterate through the set of sleected cells and apply to all of them - - // Check that cell exists in valid 2D map space - if (nMouseWorldX >= 0 && nMouseWorldX < nMapWidth && nMouseWorldY >= 0 && nMouseWorldY < nMapHeight) - { - // Press "R" to toggle Road flag for selected cell(s) - if (GetKey(olc::Key::R).bPressed) - { - if (!setSelectedCells.empty()) - { - for (auto &cell : setSelectedCells) - { - cell->bRoad = !cell->bRoad; - } - } - else - pMap[nMouseWorldY*nMapWidth + nMouseWorldX].bRoad = !pMap[nMouseWorldY*nMapWidth + nMouseWorldX].bRoad; - } - - // Press "T" to increase height for selected cell(s) - if (GetKey(olc::Key::T).bPressed) - { - if (!setSelectedCells.empty()) - { - for (auto &cell : setSelectedCells) - { - cell->nHeight++; - } - } - else - pMap[nMouseWorldY*nMapWidth + nMouseWorldX].nHeight++; - } - - // Press "E" to decrease height for selected cell(s) - if (GetKey(olc::Key::E).bPressed) - { - if (!setSelectedCells.empty()) - { - for (auto &cell : setSelectedCells) - { - cell->nHeight--; - } - } - else - pMap[nMouseWorldY*nMapWidth + nMouseWorldX].nHeight--; - } - } - - - // === Car User Input === - - if (GetKey(olc::Key::LEFT).bHeld) fCarAngle -= 4.0f * fElapsedTime; - if (GetKey(olc::Key::RIGHT).bHeld) fCarAngle += 4.0f * fElapsedTime; - - olc::GFX3D::vec3d a = { 1, 0, 0 }; - olc::GFX3D::mat4x4 m = olc::GFX3D::Math::Mat_MakeRotationZ(fCarAngle); - vecCarVel = olc::GFX3D::Math::Mat_MultiplyVector(m, a); - - if (GetKey(olc::Key::UP).bHeld) - { - vecCarPos.x += vecCarVel.x * fCarSpeed * fElapsedTime; - vecCarPos.y += vecCarVel.y * fCarSpeed * fElapsedTime; - } - - // === Position Camera === - - // Our camera currently follows the car, and the car stays in the middle of - // the screen. We need to know where the camera is before we can work with - // on screen interactions - fCameraY = vecCarPos.y; - fCameraX = vecCarPos.x; - vEye = { fCameraX,fCameraY,fCameraZ }; - olc::GFX3D::vec3d vLookTarget = olc::GFX3D::Math::Vec_Add(vEye, vLookDir); - - // Setup the camera properties for the pipeline - aka "view" transform - pipeRender.SetCamera(vEye, vLookTarget, vUp); - - - // === Calculate Mouse Position on Ground Plane === - - // Here we take the screen coordinate of the mouse, transform it into normalised space (-1 --> +1) - // for both axes. Instead of inverting and multiplying by the projection matrix, we only need the - // aspect ratio parameters, with which we'll scale the mouse coordinate. This new point is then - // multiplied by the inverse of the look at matrix (camera view matrix) aka a point at matrix, to - // transform the new point into world space. - // - // Now, the thing is, a 2D point is no good on its own, our world has depth. If we treat the 2D - // point as a ray cast from (0, 0)->(mx, my), we can see where this ray intersects with a plane - // at a specific depth. - - // Create a point at matrix, if you recall, this is the inverse of the look at matrix - // used by the camera - olc::GFX3D::mat4x4 matView = olc::GFX3D::Math::Mat_PointAt(vEye, vLookTarget, vUp); - - // Assume the origin of the mouse ray is the middle of the screen... - olc::GFX3D::vec3d vecMouseOrigin = { 0.0f, 0.0f, 0.0f }; - - // ...and that a ray is cast to the mouse location from the origin. Here we translate - // the mouse coordinates into viewport coordinates - olc::GFX3D::vec3d vecMouseDir = { - 2.0f * ((GetMouseX() / (float)ScreenWidth()) - 0.5f) / matProj.m[0][0], - 2.0f * ((GetMouseY() / (float)ScreenHeight()) - 0.5f) / matProj.m[1][1], - 1.0f, - 0.0f }; - - // Now transform the origin point and ray direction by the inverse of the camera - vecMouseOrigin = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseOrigin); - vecMouseDir = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseDir); - - // Extend the mouse ray to a large length - vecMouseDir = olc::GFX3D::Math::Vec_Mul(vecMouseDir, 1000.0f); - - // Offset the mouse ray by the mouse origin - vecMouseDir = olc::GFX3D::Math::Vec_Add(vecMouseOrigin, vecMouseDir); - - // All of our intersections for mouse checks occur in the ground plane (z=0), so - // define a plane at that location - olc::GFX3D::vec3d plane_p = { 0.0f, 0.0f, 0.0f }; - olc::GFX3D::vec3d plane_n = { 0.0f, 0.0f, 1.0f }; - - // Calculate Mouse Location in plane, by doing a line/plane intersection test - float t = 0.0f; - olc::GFX3D::vec3d mouse3d = olc::GFX3D::Math::Vec_IntersectPlane(plane_p, plane_n, vecMouseOrigin, vecMouseDir, t); - - - - // === Now we have the mouse in 3D! Handle mouse user input === - - // Left click & left click drag selects cells by adding them to the set of selected cells - // Here I make sure only to do this if the cell under the mouse has changed from the - // previous frame, but the set will also reject duplicate cells being added - if (GetMouse(0).bHeld && ((nMouseWorldX != nOldMouseWorldX) || (nMouseWorldY != nOldMouseWorldY))) - setSelectedCells.emplace(&pMap[nMouseWorldY * nMapWidth + nMouseWorldX]); - - // Single clicking cells also adds them - if (GetMouse(0).bPressed) - setSelectedCells.emplace(&pMap[nMouseWorldY * nMapWidth + nMouseWorldX]); - - // If the user right clicks, the set of selected cells is emptied - if (GetMouse(1).bReleased) - setSelectedCells.clear(); - - // Cache the current mouse position to use during comparison in next frame - nOldMouseWorldX = nMouseWorldX; - nOldMouseWorldY = nMouseWorldY; - - nMouseWorldX = (int)mouse3d.x; - nMouseWorldY = (int)mouse3d.y; - - - - - // === Rendering === - - // Right, now we're gonna render the scene! - - // First Clear the screen and the depth buffer - Clear(olc::BLUE); - olc::GFX3D::ClearDepth(); - - // === Calculate Visible World === - - // Since we now have the transforms to convert screen space into ground plane space, we - // can calculate the visible extents of the world, regardless of zoom level! The method is - // exactly the same for the mouse, but we use fixed screen coordinates that represent the - // top left, and bottom right of the screen - - // Work out Top Left Ground Cell - vecMouseDir = { -1.0f / matProj.m[0][0],-1.0f / matProj.m[1][1], 1.0f, 0.0f }; - vecMouseDir = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseDir); - vecMouseDir = olc::GFX3D::Math::Vec_Mul(vecMouseDir, 1000.0f); - vecMouseDir = olc::GFX3D::Math::Vec_Add(vecMouseOrigin, vecMouseDir); - viewWorldTopLeft = olc::GFX3D::Math::Vec_IntersectPlane(plane_p, plane_n, vecMouseOrigin, vecMouseDir, t); - - // Work out Bottom Right Ground Cell - vecMouseDir = { 1.0f / matProj.m[0][0], 1.0f / matProj.m[1][1], 1.0f, 0.0f }; - vecMouseDir = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseDir); - vecMouseDir = olc::GFX3D::Math::Vec_Mul(vecMouseDir, 1000.0f); - vecMouseDir = olc::GFX3D::Math::Vec_Add(vecMouseOrigin, vecMouseDir); - viewWorldBottomRight = olc::GFX3D::Math::Vec_IntersectPlane(plane_p, plane_n, vecMouseOrigin, vecMouseDir, t); - - // Calculate visible tiles - //int nStartX = 0; - //int nEndX = nMapWidth; - //int nStartY = 0; - //int nEndY = nMapHeight; - - int nStartX = std::max(0, (int)viewWorldTopLeft.x - 1); - int nEndX = std::min(nMapWidth, (int)viewWorldBottomRight.x + 1); - int nStartY = std::max(0, (int)viewWorldTopLeft.y - 1); - int nEndY = std::min(nMapHeight, (int)viewWorldBottomRight.y + 1); - - - // Iterate through all the cells we wish to draw. Each cell is 1x1 and elevates in the Z -Axis - for (int x = nStartX; x < nEndX; x++) - { - for (int y = nStartY; y < nEndY; y++) - { - if (pMap[y*nMapWidth + x].bRoad) - { - // Cell is a road, look at neighbouring cells. If they are roads also, - // then choose the appropriate texture that joins up correctly - - int road = 0; - auto r = [&](int i, int j) - { - return pMap[(y + j) * nMapWidth + (x + i)].bRoad; - }; - - if (r(0, -1) && r(0, +1) && !r(-1, 0) && !r(+1, 0)) road = 0; - if (!r(0, -1) && !r(0, +1) && r(-1, 0) && r(+1, 0)) road = 1; - - if (!r(0, -1) && r(0, +1) && !r(-1, 0) && r(+1, 0)) road = 3; - if (!r(0, -1) && r(0, +1) && r(-1, 0) && r(+1, 0)) road = 4; - if (!r(0, -1) && r(0, +1) && r(-1, 0) && !r(+1, 0)) road = 5; - - if (r(0, -1) && r(0, +1) && !r(-1, 0) && r(+1, 0)) road = 6; - if (r(0, -1) && r(0, +1) && r(-1, 0) && r(+1, 0)) road = 7; - if (r(0, -1) && r(0, +1) && r(-1, 0) && !r(+1, 0)) road = 8; - - if (r(0, -1) && !r(0, +1) && !r(-1, 0) && r(+1, 0)) road = 9; - if (r(0, -1) && !r(0, +1) && r(-1, 0) && r(+1, 0)) road = 10; - if (r(0, -1) && !r(0, +1) && r(-1, 0) && !r(+1, 0)) road = 11; - - // Create a translation transform to position the cell in the world - olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation(x, y, 0.0f); - pipeRender.SetTransform(matWorld); - - // Set the appropriate texture to use - pipeRender.SetTexture(sprRoad[road]); - - // Draw a flat quad - pipeRender.Render(meshFlat.tris); - - } - else // Not Road - { - // If the cell is not considered road, then draw it appropriately - - if (pMap[y*nMapWidth + x].nHeight < 0) - { - // Cell is blank - for now ;-P - } - - if (pMap[y*nMapWidth + x].nHeight == 0) - { - // Cell is ground, draw a flat grass quad at height 0 - olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation(x, y, 0.0f); - pipeRender.SetTransform(matWorld); - pipeRender.SetTexture(sprGround); - pipeRender.Render(meshFlat.tris); - } - - if (pMap[y*nMapWidth + x].nHeight > 0) - { - // Cell is Building, for now, we'll draw each storey as a seperate mesh - int h, t; - t = pMap[y*nMapWidth + x].nHeight; - - for (h = 0; h < t; h++) - { - // Create a transform that positions the storey according to its height - olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation(x, y, -(h + 1) * 0.2f); - pipeRender.SetTransform(matWorld); - - // Choose a texture, if its ground level, use the "street level front", otherwise use windows - pipeRender.SetTexture(h == 0 ? sprFrontage : sprWindows); - pipeRender.Render(meshWallsOut.tris); - } - - // Top the building off with a roof - olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation(x, y, -(h) * 0.2f); - pipeRender.SetTransform(matWorld); - pipeRender.SetTexture(sprRoof); - pipeRender.Render(meshFlat.tris); - } - } - } - } - - // Draw Selected Cells, iterate through the set of cells, and draw a wireframe quad at ground level - // to indicate it is in the selection set - for (auto &cell : setSelectedCells) - { - // Draw CursorCube - olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation(cell->nWorldX, cell->nWorldY, 0.0f); - pipeRender.SetTransform(matWorld); - pipeRender.SetTexture(sprRoof); - pipeRender.Render(meshFlat.tris, olc::GFX3D::RENDER_WIRE); - } - - // Draw Car, a few transforms required for this - - // 1) Offset the car to the middle of the quad - olc::GFX3D::mat4x4 matCarOffset = olc::GFX3D::Math::Mat_MakeTranslation(-0.5f, -0.5f, -0.0f); - // 2) The quad is currently unit square, scale it to be more rectangular and smaller than the cells - olc::GFX3D::mat4x4 matCarScale = olc::GFX3D::Math::Mat_MakeScale(0.4f, 0.2f, 1.0f); - // 3) Combine into matrix - olc::GFX3D::mat4x4 matCar = olc::GFX3D::Math::Mat_MultiplyMatrix(matCarOffset, matCarScale); - // 4) Rotate the car around its offset origin, according to its angle - olc::GFX3D::mat4x4 matCarRot = olc::GFX3D::Math::Mat_MakeRotationZ(fCarAngle); - matCar = olc::GFX3D::Math::Mat_MultiplyMatrix(matCar, matCarRot); - // 5) Translate the car into its position in the world. Give it a little elevation so its baove the ground - olc::GFX3D::mat4x4 matCarTrans = olc::GFX3D::Math::Mat_MakeTranslation(vecCarPos.x, vecCarPos.y, -0.01f); - matCar = olc::GFX3D::Math::Mat_MultiplyMatrix(matCar, matCarTrans); - - // Set the car texture to the pipeline - pipeRender.SetTexture(sprCar); - // Apply "world" transform to pipeline - pipeRender.SetTransform(matCar); - - // The car has transparency, so enable it - SetPixelMode(olc::Pixel::ALPHA); - // Render the quad - pipeRender.Render(meshFlat.tris); - // Set transparency back to none to optimise drawing other pixels - SetPixelMode(olc::Pixel::NORMAL); - - - // Draw the current camera position for debug information - //DrawString(10, 30, "CX: " + std::to_string(fCameraX) + " CY: " + std::to_string(fCameraY) + " CZ: " + std::to_string(fCameraZ)); - return true; - } -}; - - - -int main() -{ - CarCrimeCity demo; - if (demo.Construct(768, 480, 2, 2)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/CarCrimeCity/Part1/car_top.png b/Videos/CarCrimeCity/Part1/car_top.png deleted file mode 100644 index ad89ae4..0000000 Binary files a/Videos/CarCrimeCity/Part1/car_top.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part1/car_top1.png b/Videos/CarCrimeCity/Part1/car_top1.png deleted file mode 100644 index 15ceb1d..0000000 Binary files a/Videos/CarCrimeCity/Part1/car_top1.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part1/example1.city b/Videos/CarCrimeCity/Part1/example1.city deleted file mode 100644 index 47dfb0b..0000000 Binary files a/Videos/CarCrimeCity/Part1/example1.city and /dev/null differ diff --git a/Videos/CarCrimeCity/Part1/olcPGEX_Graphics3D.h b/Videos/CarCrimeCity/Part1/olcPGEX_Graphics3D.h deleted file mode 100644 index 9c6dd80..0000000 --- a/Videos/CarCrimeCity/Part1/olcPGEX_Graphics3D.h +++ /dev/null @@ -1,1174 +0,0 @@ -/* - olcPGEX_Graphics3D.h - - +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine Extension | - | 3D Rendering - v0.1 | - +-------------------------------------------------------------+ - - What is this? - ~~~~~~~~~~~~~ - This is an extension to the olcPixelGameEngine, which provides - support for software rendering 3D graphics. - - NOTE!!! This file is under development and may change! - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018 -*/ - - -#ifndef OLC_PGEX_GFX3D -#define OLC_PGEX_GFX3D - -#include -#include -#include -#undef min -#undef max - -namespace olc -{ - // Container class for Advanced 2D Drawing functions - class GFX3D : public olc::PGEX - { - - public: - - struct vec2d - { - float x = 0; - float y = 0; - float z = 0; - }; - - struct vec3d - { - float x = 0; - float y = 0; - float z = 0; - float w = 1; // Need a 4th term to perform sensible matrix vector multiplication - }; - - struct triangle - { - vec3d p[3]; - vec2d t[3]; - olc::Pixel col; - }; - - struct mat4x4 - { - float m[4][4] = { 0 }; - }; - - struct mesh - { - std::vector tris; - }; - - class Math - { - public: - inline Math(); - public: - inline static vec3d Mat_MultiplyVector(mat4x4 &m, vec3d &i); - inline static mat4x4 Mat_MultiplyMatrix(mat4x4 &m1, mat4x4 &m2); - inline static mat4x4 Mat_MakeIdentity(); - inline static mat4x4 Mat_MakeRotationX(float fAngleRad); - inline static mat4x4 Mat_MakeRotationY(float fAngleRad); - inline static mat4x4 Mat_MakeRotationZ(float fAngleRad); - inline static mat4x4 Mat_MakeScale(float x, float y, float z); - inline static mat4x4 Mat_MakeTranslation(float x, float y, float z); - inline static mat4x4 Mat_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar); - inline static mat4x4 Mat_PointAt(vec3d &pos, vec3d &target, vec3d &up); - inline static mat4x4 Mat_QuickInverse(mat4x4 &m); // Only for Rotation/Translation Matrices - inline static mat4x4 Mat_Inverse(olc::GFX3D::mat4x4 &m); - - inline static vec3d Vec_Add(vec3d &v1, vec3d &v2); - inline static vec3d Vec_Sub(vec3d &v1, vec3d &v2); - inline static vec3d Vec_Mul(vec3d &v1, float k); - inline static vec3d Vec_Div(vec3d &v1, float k); - inline static float Vec_DotProduct(vec3d &v1, vec3d &v2); - inline static float Vec_Length(vec3d &v); - inline static vec3d Vec_Normalise(vec3d &v); - inline static vec3d Vec_CrossProduct(vec3d &v1, vec3d &v2); - inline static vec3d Vec_IntersectPlane(vec3d &plane_p, vec3d &plane_n, vec3d &lineStart, vec3d &lineEnd, float &t); - - inline static int Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2); - }; - - enum RENDERFLAGS - { - RENDER_WIRE = 0x01, - RENDER_FLAT = 0x02, - RENDER_TEXTURED = 0x04, - RENDER_CULL_CW = 0x08, - RENDER_CULL_CCW = 0x10, - RENDER_DEPTH = 0x20, - }; - - - class PipeLine - { - public: - PipeLine(); - - public: - void SetProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar, float fLeft, float fTop, float fWidth, float fHeight); - void SetCamera(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &lookat, olc::GFX3D::vec3d &up); - void SetTransform(olc::GFX3D::mat4x4 &transform); - void SetTexture(olc::Sprite *texture); - void SetLightSource(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &dir, olc::Pixel &col); - uint32_t Render(std::vector &triangles, uint32_t flags = RENDER_CULL_CW | RENDER_TEXTURED | RENDER_DEPTH); - - private: - olc::GFX3D::mat4x4 matProj; - olc::GFX3D::mat4x4 matView; - olc::GFX3D::mat4x4 matWorld; - olc::Sprite *sprTexture; - float fViewX; - float fViewY; - float fViewW; - float fViewH; - }; - - - - public: - //static const int RF_TEXTURE = 0x00000001; - //static const int RF_ = 0x00000002; - - inline static void ConfigureDisplay(); - inline static void ClearDepth(); - inline static void AddTriangleToScene(olc::GFX3D::triangle &tri); - inline static void RenderScene(); - - inline static void DrawTriangleFlat(olc::GFX3D::triangle &tri); - inline static void DrawTriangleWire(olc::GFX3D::triangle &tri, olc::Pixel col = olc::WHITE); - inline static void DrawTriangleTex(olc::GFX3D::triangle &tri, olc::Sprite* spr); - inline static void TexturedTriangle(int x1, int y1, float u1, float v1, float w1, - int x2, int y2, float u2, float v2, float w2, - int x3, int y3, float u3, float v3, float w3, olc::Sprite* spr); - - // Draws a sprite with the transform applied - //inline static void DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform); - - private: - static float* m_DepthBuffer; - }; -} - - - - -namespace olc -{ - olc::GFX3D::Math::Math() - { - - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Mat_MultiplyVector(olc::GFX3D::mat4x4 &m, olc::GFX3D::vec3d &i) - { - vec3d v; - v.x = i.x * m.m[0][0] + i.y * m.m[1][0] + i.z * m.m[2][0] + i.w * m.m[3][0]; - v.y = i.x * m.m[0][1] + i.y * m.m[1][1] + i.z * m.m[2][1] + i.w * m.m[3][1]; - v.z = i.x * m.m[0][2] + i.y * m.m[1][2] + i.z * m.m[2][2] + i.w * m.m[3][2]; - v.w = i.x * m.m[0][3] + i.y * m.m[1][3] + i.z * m.m[2][3] + i.w * m.m[3][3]; - return v; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeIdentity() - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = 1.0f; - matrix.m[1][1] = 1.0f; - matrix.m[2][2] = 1.0f; - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeRotationX(float fAngleRad) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = 1.0f; - matrix.m[1][1] = cosf(fAngleRad); - matrix.m[1][2] = sinf(fAngleRad); - matrix.m[2][1] = -sinf(fAngleRad); - matrix.m[2][2] = cosf(fAngleRad); - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeRotationY(float fAngleRad) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = cosf(fAngleRad); - matrix.m[0][2] = sinf(fAngleRad); - matrix.m[2][0] = -sinf(fAngleRad); - matrix.m[1][1] = 1.0f; - matrix.m[2][2] = cosf(fAngleRad); - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeRotationZ(float fAngleRad) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = cosf(fAngleRad); - matrix.m[0][1] = sinf(fAngleRad); - matrix.m[1][0] = -sinf(fAngleRad); - matrix.m[1][1] = cosf(fAngleRad); - matrix.m[2][2] = 1.0f; - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeScale(float x, float y, float z) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = x; - matrix.m[1][1] = y; - matrix.m[2][2] = z; - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeTranslation(float x, float y, float z) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = 1.0f; - matrix.m[1][1] = 1.0f; - matrix.m[2][2] = 1.0f; - matrix.m[3][3] = 1.0f; - matrix.m[3][0] = x; - matrix.m[3][1] = y; - matrix.m[3][2] = z; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar) - { - float fFovRad = 1.0f / tanf(fFovDegrees * 0.5f / 180.0f * 3.14159f); - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = fAspectRatio * fFovRad; - matrix.m[1][1] = fFovRad; - matrix.m[2][2] = fFar / (fFar - fNear); - matrix.m[3][2] = (-fFar * fNear) / (fFar - fNear); - matrix.m[2][3] = 1.0f; - matrix.m[3][3] = 0.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MultiplyMatrix(olc::GFX3D::mat4x4 &m1, olc::GFX3D::mat4x4 &m2) - { - olc::GFX3D::mat4x4 matrix; - for (int c = 0; c < 4; c++) - for (int r = 0; r < 4; r++) - matrix.m[r][c] = m1.m[r][0] * m2.m[0][c] + m1.m[r][1] * m2.m[1][c] + m1.m[r][2] * m2.m[2][c] + m1.m[r][3] * m2.m[3][c]; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_PointAt(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &target, olc::GFX3D::vec3d &up) - { - // Calculate new forward direction - olc::GFX3D::vec3d newForward = Vec_Sub(target, pos); - newForward = Vec_Normalise(newForward); - - // Calculate new Up direction - olc::GFX3D::vec3d a = Vec_Mul(newForward, Vec_DotProduct(up, newForward)); - olc::GFX3D::vec3d newUp = Vec_Sub(up, a); - newUp = Vec_Normalise(newUp); - - // New Right direction is easy, its just cross product - olc::GFX3D::vec3d newRight = Vec_CrossProduct(newUp, newForward); - - // Construct Dimensioning and Translation Matrix - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = newRight.x; matrix.m[0][1] = newRight.y; matrix.m[0][2] = newRight.z; matrix.m[0][3] = 0.0f; - matrix.m[1][0] = newUp.x; matrix.m[1][1] = newUp.y; matrix.m[1][2] = newUp.z; matrix.m[1][3] = 0.0f; - matrix.m[2][0] = newForward.x; matrix.m[2][1] = newForward.y; matrix.m[2][2] = newForward.z; matrix.m[2][3] = 0.0f; - matrix.m[3][0] = pos.x; matrix.m[3][1] = pos.y; matrix.m[3][2] = pos.z; matrix.m[3][3] = 1.0f; - return matrix; - - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_QuickInverse(olc::GFX3D::mat4x4 &m) // Only for Rotation/Translation Matrices - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = m.m[0][0]; matrix.m[0][1] = m.m[1][0]; matrix.m[0][2] = m.m[2][0]; matrix.m[0][3] = 0.0f; - matrix.m[1][0] = m.m[0][1]; matrix.m[1][1] = m.m[1][1]; matrix.m[1][2] = m.m[2][1]; matrix.m[1][3] = 0.0f; - matrix.m[2][0] = m.m[0][2]; matrix.m[2][1] = m.m[1][2]; matrix.m[2][2] = m.m[2][2]; matrix.m[2][3] = 0.0f; - matrix.m[3][0] = -(m.m[3][0] * matrix.m[0][0] + m.m[3][1] * matrix.m[1][0] + m.m[3][2] * matrix.m[2][0]); - matrix.m[3][1] = -(m.m[3][0] * matrix.m[0][1] + m.m[3][1] * matrix.m[1][1] + m.m[3][2] * matrix.m[2][1]); - matrix.m[3][2] = -(m.m[3][0] * matrix.m[0][2] + m.m[3][1] * matrix.m[1][2] + m.m[3][2] * matrix.m[2][2]); - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_Inverse(olc::GFX3D::mat4x4 &m) - { - double det; - - - mat4x4 matInv; - - matInv.m[0][0] = m.m[1][1] * m.m[2][2] * m.m[3][3] - m.m[1][1] * m.m[2][3] * m.m[3][2] - m.m[2][1] * m.m[1][2] * m.m[3][3] + m.m[2][1] * m.m[1][3] * m.m[3][2] + m.m[3][1] * m.m[1][2] * m.m[2][3] - m.m[3][1] * m.m[1][3] * m.m[2][2]; - matInv.m[1][0] = -m.m[1][0] * m.m[2][2] * m.m[3][3] + m.m[1][0] * m.m[2][3] * m.m[3][2] + m.m[2][0] * m.m[1][2] * m.m[3][3] - m.m[2][0] * m.m[1][3] * m.m[3][2] - m.m[3][0] * m.m[1][2] * m.m[2][3] + m.m[3][0] * m.m[1][3] * m.m[2][2]; - matInv.m[2][0] = m.m[1][0] * m.m[2][1] * m.m[3][3] - m.m[1][0] * m.m[2][3] * m.m[3][1] - m.m[2][0] * m.m[1][1] * m.m[3][3] + m.m[2][0] * m.m[1][3] * m.m[3][1] + m.m[3][0] * m.m[1][1] * m.m[2][3] - m.m[3][0] * m.m[1][3] * m.m[2][1]; - matInv.m[3][0] = -m.m[1][0] * m.m[2][1] * m.m[3][2] + m.m[1][0] * m.m[2][2] * m.m[3][1] + m.m[2][0] * m.m[1][1] * m.m[3][2] - m.m[2][0] * m.m[1][2] * m.m[3][1] - m.m[3][0] * m.m[1][1] * m.m[2][2] + m.m[3][0] * m.m[1][2] * m.m[2][1]; - matInv.m[0][1] = -m.m[0][1] * m.m[2][2] * m.m[3][3] + m.m[0][1] * m.m[2][3] * m.m[3][2] + m.m[2][1] * m.m[0][2] * m.m[3][3] - m.m[2][1] * m.m[0][3] * m.m[3][2] - m.m[3][1] * m.m[0][2] * m.m[2][3] + m.m[3][1] * m.m[0][3] * m.m[2][2]; - matInv.m[1][1] = m.m[0][0] * m.m[2][2] * m.m[3][3] - m.m[0][0] * m.m[2][3] * m.m[3][2] - m.m[2][0] * m.m[0][2] * m.m[3][3] + m.m[2][0] * m.m[0][3] * m.m[3][2] + m.m[3][0] * m.m[0][2] * m.m[2][3] - m.m[3][0] * m.m[0][3] * m.m[2][2]; - matInv.m[2][1] = -m.m[0][0] * m.m[2][1] * m.m[3][3] + m.m[0][0] * m.m[2][3] * m.m[3][1] + m.m[2][0] * m.m[0][1] * m.m[3][3] - m.m[2][0] * m.m[0][3] * m.m[3][1] - m.m[3][0] * m.m[0][1] * m.m[2][3] + m.m[3][0] * m.m[0][3] * m.m[2][1]; - matInv.m[3][1] = m.m[0][0] * m.m[2][1] * m.m[3][2] - m.m[0][0] * m.m[2][2] * m.m[3][1] - m.m[2][0] * m.m[0][1] * m.m[3][2] + m.m[2][0] * m.m[0][2] * m.m[3][1] + m.m[3][0] * m.m[0][1] * m.m[2][2] - m.m[3][0] * m.m[0][2] * m.m[2][1]; - matInv.m[0][2] = m.m[0][1] * m.m[1][2] * m.m[3][3] - m.m[0][1] * m.m[1][3] * m.m[3][2] - m.m[1][1] * m.m[0][2] * m.m[3][3] + m.m[1][1] * m.m[0][3] * m.m[3][2] + m.m[3][1] * m.m[0][2] * m.m[1][3] - m.m[3][1] * m.m[0][3] * m.m[1][2]; - matInv.m[1][2] = -m.m[0][0] * m.m[1][2] * m.m[3][3] + m.m[0][0] * m.m[1][3] * m.m[3][2] + m.m[1][0] * m.m[0][2] * m.m[3][3] - m.m[1][0] * m.m[0][3] * m.m[3][2] - m.m[3][0] * m.m[0][2] * m.m[1][3] + m.m[3][0] * m.m[0][3] * m.m[1][2]; - matInv.m[2][2] = m.m[0][0] * m.m[1][1] * m.m[3][3] - m.m[0][0] * m.m[1][3] * m.m[3][1] - m.m[1][0] * m.m[0][1] * m.m[3][3] + m.m[1][0] * m.m[0][3] * m.m[3][1] + m.m[3][0] * m.m[0][1] * m.m[1][3] - m.m[3][0] * m.m[0][3] * m.m[1][1]; - matInv.m[3][2] = -m.m[0][0] * m.m[1][1] * m.m[3][2] + m.m[0][0] * m.m[1][2] * m.m[3][1] + m.m[1][0] * m.m[0][1] * m.m[3][2] - m.m[1][0] * m.m[0][2] * m.m[3][1] - m.m[3][0] * m.m[0][1] * m.m[1][2] + m.m[3][0] * m.m[0][2] * m.m[1][1]; - matInv.m[0][3] = -m.m[0][1] * m.m[1][2] * m.m[2][3] + m.m[0][1] * m.m[1][3] * m.m[2][2] + m.m[1][1] * m.m[0][2] * m.m[2][3] - m.m[1][1] * m.m[0][3] * m.m[2][2] - m.m[2][1] * m.m[0][2] * m.m[1][3] + m.m[2][1] * m.m[0][3] * m.m[1][2]; - matInv.m[1][3] = m.m[0][0] * m.m[1][2] * m.m[2][3] - m.m[0][0] * m.m[1][3] * m.m[2][2] - m.m[1][0] * m.m[0][2] * m.m[2][3] + m.m[1][0] * m.m[0][3] * m.m[2][2] + m.m[2][0] * m.m[0][2] * m.m[1][3] - m.m[2][0] * m.m[0][3] * m.m[1][2]; - matInv.m[2][3] = -m.m[0][0] * m.m[1][1] * m.m[2][3] + m.m[0][0] * m.m[1][3] * m.m[2][1] + m.m[1][0] * m.m[0][1] * m.m[2][3] - m.m[1][0] * m.m[0][3] * m.m[2][1] - m.m[2][0] * m.m[0][1] * m.m[1][3] + m.m[2][0] * m.m[0][3] * m.m[1][1]; - matInv.m[3][3] = m.m[0][0] * m.m[1][1] * m.m[2][2] - m.m[0][0] * m.m[1][2] * m.m[2][1] - m.m[1][0] * m.m[0][1] * m.m[2][2] + m.m[1][0] * m.m[0][2] * m.m[2][1] + m.m[2][0] * m.m[0][1] * m.m[1][2] - m.m[2][0] * m.m[0][2] * m.m[1][1]; - - det = m.m[0][0] * matInv.m[0][0] + m.m[0][1] * matInv.m[1][0] + m.m[0][2] * matInv.m[2][0] + m.m[0][3] * matInv.m[3][0]; - // if (det == 0) return false; - - det = 1.0 / det; - - for (int i = 0; i < 4; i++) - for (int j = 0; j < 4; j++) - matInv.m[i][j] *= (float)det; - - return matInv; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Add(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) - { - return { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Sub(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) - { - return { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Mul(olc::GFX3D::vec3d &v1, float k) - { - return { v1.x * k, v1.y * k, v1.z * k }; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Div(olc::GFX3D::vec3d &v1, float k) - { - return { v1.x / k, v1.y / k, v1.z / k }; - } - - float olc::GFX3D::Math::Vec_DotProduct(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) - { - return v1.x*v2.x + v1.y*v2.y + v1.z * v2.z; - } - - float olc::GFX3D::Math::Vec_Length(olc::GFX3D::vec3d &v) - { - return sqrtf(Vec_DotProduct(v, v)); - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Normalise(olc::GFX3D::vec3d &v) - { - float l = Vec_Length(v); - return { v.x / l, v.y / l, v.z / l }; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_CrossProduct(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) - { - vec3d v; - v.x = v1.y * v2.z - v1.z * v2.y; - v.y = v1.z * v2.x - v1.x * v2.z; - v.z = v1.x * v2.y - v1.y * v2.x; - return v; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_IntersectPlane(olc::GFX3D::vec3d &plane_p, olc::GFX3D::vec3d &plane_n, olc::GFX3D::vec3d &lineStart, olc::GFX3D::vec3d &lineEnd, float &t) - { - plane_n = Vec_Normalise(plane_n); - float plane_d = -Vec_DotProduct(plane_n, plane_p); - float ad = Vec_DotProduct(lineStart, plane_n); - float bd = Vec_DotProduct(lineEnd, plane_n); - t = (-plane_d - ad) / (bd - ad); - olc::GFX3D::vec3d lineStartToEnd = Vec_Sub(lineEnd, lineStart); - olc::GFX3D::vec3d lineToIntersect = Vec_Mul(lineStartToEnd, t); - return Vec_Add(lineStart, lineToIntersect); - } - - - int olc::GFX3D::Math::Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2) - { - // Make sure plane normal is indeed normal - plane_n = Math::Vec_Normalise(plane_n); - - out_tri1.t[0] = in_tri.t[0]; - out_tri2.t[0] = in_tri.t[0]; - out_tri1.t[1] = in_tri.t[1]; - out_tri2.t[1] = in_tri.t[1]; - out_tri1.t[2] = in_tri.t[2]; - out_tri2.t[2] = in_tri.t[2]; - - // Return signed shortest distance from point to plane, plane normal must be normalised - auto dist = [&](vec3d &p) - { - vec3d n = Math::Vec_Normalise(p); - return (plane_n.x * p.x + plane_n.y * p.y + plane_n.z * p.z - Math::Vec_DotProduct(plane_n, plane_p)); - }; - - // Create two temporary storage arrays to classify points either side of plane - // If distance sign is positive, point lies on "inside" of plane - vec3d* inside_points[3]; int nInsidePointCount = 0; - vec3d* outside_points[3]; int nOutsidePointCount = 0; - vec2d* inside_tex[3]; int nInsideTexCount = 0; - vec2d* outside_tex[3]; int nOutsideTexCount = 0; - - - // Get signed distance of each point in triangle to plane - float d0 = dist(in_tri.p[0]); - float d1 = dist(in_tri.p[1]); - float d2 = dist(in_tri.p[2]); - - if (d0 >= 0) { inside_points[nInsidePointCount++] = &in_tri.p[0]; inside_tex[nInsideTexCount++] = &in_tri.t[0]; } - else { - outside_points[nOutsidePointCount++] = &in_tri.p[0]; outside_tex[nOutsideTexCount++] = &in_tri.t[0]; - } - if (d1 >= 0) { - inside_points[nInsidePointCount++] = &in_tri.p[1]; inside_tex[nInsideTexCount++] = &in_tri.t[1]; - } - else { - outside_points[nOutsidePointCount++] = &in_tri.p[1]; outside_tex[nOutsideTexCount++] = &in_tri.t[1]; - } - if (d2 >= 0) { - inside_points[nInsidePointCount++] = &in_tri.p[2]; inside_tex[nInsideTexCount++] = &in_tri.t[2]; - } - else { - outside_points[nOutsidePointCount++] = &in_tri.p[2]; outside_tex[nOutsideTexCount++] = &in_tri.t[2]; - } - - // Now classify triangle points, and break the input triangle into - // smaller output triangles if required. There are four possible - // outcomes... - - if (nInsidePointCount == 0) - { - // All points lie on the outside of plane, so clip whole triangle - // It ceases to exist - - return 0; // No returned triangles are valid - } - - if (nInsidePointCount == 3) - { - // All points lie on the inside of plane, so do nothing - // and allow the triangle to simply pass through - out_tri1 = in_tri; - - return 1; // Just the one returned original triangle is valid - } - - if (nInsidePointCount == 1 && nOutsidePointCount == 2) - { - // Triangle should be clipped. As two points lie outside - // the plane, the triangle simply becomes a smaller triangle - - // Copy appearance info to new triangle - out_tri1.col = olc::MAGENTA;// in_tri.col; - - // The inside point is valid, so keep that... - out_tri1.p[0] = *inside_points[0]; - out_tri1.t[0] = *inside_tex[0]; - - // but the two new points are at the locations where the - // original sides of the triangle (lines) intersect with the plane - float t; - out_tri1.p[1] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); - out_tri1.t[1].x = t * (outside_tex[0]->x - inside_tex[0]->x) + inside_tex[0]->x; - out_tri1.t[1].y = t * (outside_tex[0]->y - inside_tex[0]->y) + inside_tex[0]->y; - out_tri1.t[1].z = t * (outside_tex[0]->z - inside_tex[0]->z) + inside_tex[0]->z; - - out_tri1.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[1], t); - out_tri1.t[2].x = t * (outside_tex[1]->x - inside_tex[0]->x) + inside_tex[0]->x; - out_tri1.t[2].y = t * (outside_tex[1]->y - inside_tex[0]->y) + inside_tex[0]->y; - out_tri1.t[2].z = t * (outside_tex[1]->z - inside_tex[0]->z) + inside_tex[0]->z; - - return 1; // Return the newly formed single triangle - } - - if (nInsidePointCount == 2 && nOutsidePointCount == 1) - { - // Triangle should be clipped. As two points lie inside the plane, - // the clipped triangle becomes a "quad". Fortunately, we can - // represent a quad with two new triangles - - // Copy appearance info to new triangles - out_tri1.col = olc::GREEN;// in_tri.col; - out_tri2.col = olc::RED;// in_tri.col; - - // The first triangle consists of the two inside points and a new - // point determined by the location where one side of the triangle - // intersects with the plane - out_tri1.p[0] = *inside_points[0]; - out_tri1.t[0] = *inside_tex[0]; - - out_tri1.p[1] = *inside_points[1]; - out_tri1.t[1] = *inside_tex[1]; - - float t; - out_tri1.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); - out_tri1.t[2].x = t * (outside_tex[0]->x - inside_tex[0]->x) + inside_tex[0]->x; - out_tri1.t[2].y = t * (outside_tex[0]->y - inside_tex[0]->y) + inside_tex[0]->y; - out_tri1.t[2].z = t * (outside_tex[0]->z - inside_tex[0]->z) + inside_tex[0]->z; - - // The second triangle is composed of one of he inside points, a - // new point determined by the intersection of the other side of the - // triangle and the plane, and the newly created point above - out_tri2.p[1] = *inside_points[1]; - out_tri2.t[1] = *inside_tex[1]; - out_tri2.p[0] = out_tri1.p[2]; - out_tri2.t[0] = out_tri1.t[2]; - out_tri2.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[1], *outside_points[0], t); - out_tri2.t[2].x = t * (outside_tex[0]->x - inside_tex[1]->x) + inside_tex[1]->x; - out_tri2.t[2].y = t * (outside_tex[0]->y - inside_tex[1]->y) + inside_tex[1]->y; - out_tri2.t[2].z = t * (outside_tex[0]->z - inside_tex[1]->z) + inside_tex[1]->z; - return 2; // Return two newly formed triangles which form a quad - } - - return 0; - } - - void GFX3D::DrawTriangleFlat(olc::GFX3D::triangle &tri) - { - pge->FillTriangle(tri.p[0].x, tri.p[0].y, tri.p[1].x, tri.p[1].y, tri.p[2].x, tri.p[2].y, tri.col); - } - - void GFX3D::DrawTriangleWire(olc::GFX3D::triangle &tri, olc::Pixel col) - { - pge->DrawTriangle(tri.p[0].x, tri.p[0].y, tri.p[1].x, tri.p[1].y, tri.p[2].x, tri.p[2].y, col); - } - - void GFX3D::TexturedTriangle(int x1, int y1, float u1, float v1, float w1, - int x2, int y2, float u2, float v2, float w2, - int x3, int y3, float u3, float v3, float w3, olc::Sprite* spr) - - { - if (y2 < y1) - { - std::swap(y1, y2); - std::swap(x1, x2); - std::swap(u1, u2); - std::swap(v1, v2); - std::swap(w1, w2); - } - - if (y3 < y1) - { - std::swap(y1, y3); - std::swap(x1, x3); - std::swap(u1, u3); - std::swap(v1, v3); - std::swap(w1, w3); - } - - if (y3 < y2) - { - std::swap(y2, y3); - std::swap(x2, x3); - std::swap(u2, u3); - std::swap(v2, v3); - std::swap(w2, w3); - } - - int dy1 = y2 - y1; - int dx1 = x2 - x1; - float dv1 = v2 - v1; - float du1 = u2 - u1; - float dw1 = w2 - w1; - - int dy2 = y3 - y1; - int dx2 = x3 - x1; - float dv2 = v3 - v1; - float du2 = u3 - u1; - float dw2 = w3 - w1; - - float tex_u, tex_v, tex_w; - - float dax_step = 0, dbx_step = 0, - du1_step = 0, dv1_step = 0, - du2_step = 0, dv2_step = 0, - dw1_step = 0, dw2_step = 0; - - if (dy1) dax_step = dx1 / (float)abs(dy1); - if (dy2) dbx_step = dx2 / (float)abs(dy2); - - if (dy1) du1_step = du1 / (float)abs(dy1); - if (dy1) dv1_step = dv1 / (float)abs(dy1); - if (dy1) dw1_step = dw1 / (float)abs(dy1); - - if (dy2) du2_step = du2 / (float)abs(dy2); - if (dy2) dv2_step = dv2 / (float)abs(dy2); - if (dy2) dw2_step = dw2 / (float)abs(dy2); - - if (dy1) - { - for (int i = y1; i <= y2; i++) - { - int ax = x1 + (float)(i - y1) * dax_step; - int bx = x1 + (float)(i - y1) * dbx_step; - - float tex_su = u1 + (float)(i - y1) * du1_step; - float tex_sv = v1 + (float)(i - y1) * dv1_step; - float tex_sw = w1 + (float)(i - y1) * dw1_step; - - float tex_eu = u1 + (float)(i - y1) * du2_step; - float tex_ev = v1 + (float)(i - y1) * dv2_step; - float tex_ew = w1 + (float)(i - y1) * dw2_step; - - if (ax > bx) - { - std::swap(ax, bx); - std::swap(tex_su, tex_eu); - std::swap(tex_sv, tex_ev); - std::swap(tex_sw, tex_ew); - } - - tex_u = tex_su; - tex_v = tex_sv; - tex_w = tex_sw; - - float tstep = 1.0f / ((float)(bx - ax)); - float t = 0.0f; - - for (int j = ax; j < bx; j++) - { - tex_u = (1.0f - t) * tex_su + t * tex_eu; - tex_v = (1.0f - t) * tex_sv + t * tex_ev; - tex_w = (1.0f - t) * tex_sw + t * tex_ew; - if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j]) - { - pge->Draw(j, i, spr->Sample(tex_u / tex_w, tex_v / tex_w)); - m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w; - } - t += tstep; - } - - } - } - - dy1 = y3 - y2; - dx1 = x3 - x2; - dv1 = v3 - v2; - du1 = u3 - u2; - dw1 = w3 - w2; - - if (dy1) dax_step = dx1 / (float)abs(dy1); - if (dy2) dbx_step = dx2 / (float)abs(dy2); - - du1_step = 0, dv1_step = 0; - if (dy1) du1_step = du1 / (float)abs(dy1); - if (dy1) dv1_step = dv1 / (float)abs(dy1); - if (dy1) dw1_step = dw1 / (float)abs(dy1); - - if (dy1) - { - for (int i = y2; i <= y3; i++) - { - int ax = x2 + (float)(i - y2) * dax_step; - int bx = x1 + (float)(i - y1) * dbx_step; - - float tex_su = u2 + (float)(i - y2) * du1_step; - float tex_sv = v2 + (float)(i - y2) * dv1_step; - float tex_sw = w2 + (float)(i - y2) * dw1_step; - - float tex_eu = u1 + (float)(i - y1) * du2_step; - float tex_ev = v1 + (float)(i - y1) * dv2_step; - float tex_ew = w1 + (float)(i - y1) * dw2_step; - - if (ax > bx) - { - std::swap(ax, bx); - std::swap(tex_su, tex_eu); - std::swap(tex_sv, tex_ev); - std::swap(tex_sw, tex_ew); - } - - tex_u = tex_su; - tex_v = tex_sv; - tex_w = tex_sw; - - float tstep = 1.0f / ((float)(bx - ax)); - float t = 0.0f; - - for (int j = ax; j < bx; j++) - { - tex_u = (1.0f - t) * tex_su + t * tex_eu; - tex_v = (1.0f - t) * tex_sv + t * tex_ev; - tex_w = (1.0f - t) * tex_sw + t * tex_ew; - - if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j]) - { - pge->Draw(j, i, spr->Sample(tex_u / tex_w, tex_v / tex_w)); - m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w; - } - t += tstep; - } - } - } - } - - - void GFX3D::DrawTriangleTex(olc::GFX3D::triangle &tri, olc::Sprite* spr) - { - if (tri.p[1].y < tri.p[0].y) - { - std::swap(tri.p[0].y, tri.p[1].y); - std::swap(tri.p[0].x, tri.p[1].x); - std::swap(tri.t[0].x, tri.t[1].x); - std::swap(tri.t[0].y, tri.t[1].y); - std::swap(tri.t[0].z, tri.t[1].z); - } - - if (tri.p[2].y < tri.p[0].y) - { - std::swap(tri.p[0].y, tri.p[2].y); - std::swap(tri.p[0].x, tri.p[2].x); - std::swap(tri.t[0].x, tri.t[2].x); - std::swap(tri.t[0].y, tri.t[2].y); - std::swap(tri.t[0].z, tri.t[2].z); - } - - if (tri.p[2].y < tri.p[1].y) - { - std::swap(tri.p[1].y, tri.p[2].y); - std::swap(tri.p[1].x, tri.p[2].x); - std::swap(tri.t[1].x, tri.t[2].x); - std::swap(tri.t[1].y, tri.t[2].y); - std::swap(tri.t[1].z, tri.t[2].z); - } - - int dy1 = tri.p[1].y - tri.p[0].y; - int dx1 = tri.p[1].x - tri.p[0].x; - float dv1 = tri.t[1].y - tri.t[0].y; - float du1 = tri.t[1].x - tri.t[0].x; - float dz1 = tri.t[1].z - tri.t[0].z; - - int dy2 = tri.p[2].y - tri.p[0].y; - int dx2 = tri.p[2].x - tri.p[0].x; - float dv2 = tri.t[2].y - tri.t[0].y; - float du2 = tri.t[2].x - tri.t[0].x; - float dz2 = tri.t[2].z - tri.t[0].z; - - float tex_x, tex_y, tex_z; - - float du1_step = 0, dv1_step = 0, du2_step = 0, dv2_step = 0, dz1_step = 0, dz2_step = 0; - float dax_step = 0, dbx_step = 0; - - if (dy1) dax_step = dx1 / (float)abs(dy1); - if (dy2) dbx_step = dx2 / (float)abs(dy2); - - if (dy1) du1_step = du1 / (float)abs(dy1); - if (dy1) dv1_step = dv1 / (float)abs(dy1); - if (dy1) dz1_step = dz1 / (float)abs(dy1); - - if (dy2) du2_step = du2 / (float)abs(dy2); - if (dy2) dv2_step = dv2 / (float)abs(dy2); - if (dy2) dz2_step = dz2 / (float)abs(dy2); - - - - if (dy1) - { - for (int i = tri.p[0].y; i <= tri.p[1].y; i++) - { - int ax = tri.p[0].x + (i - tri.p[0].y) * dax_step; - int bx = tri.p[0].x + (i - tri.p[0].y) * dbx_step; - - // Start and end points in texture space - float tex_su = tri.t[0].x + (float)(i - tri.p[0].y) * du1_step; - float tex_sv = tri.t[0].y + (float)(i - tri.p[0].y) * dv1_step; - float tex_sz = tri.t[0].z + (float)(i - tri.p[0].y) * dz1_step; - - float tex_eu = tri.t[0].x + (float)(i - tri.p[0].y) * du2_step; - float tex_ev = tri.t[0].y + (float)(i - tri.p[0].y) * dv2_step; - float tex_ez = tri.t[0].z + (float)(i - tri.p[0].y) * dz2_step; - - if (ax > bx) - { - std::swap(ax, bx); - std::swap(tex_su, tex_eu); - std::swap(tex_sv, tex_ev); - std::swap(tex_sz, tex_ez); - } - - tex_x = tex_su; - tex_y = tex_sv; - tex_z = tex_sz; - - - float tstep = 1.0f / ((float)(bx - ax)); - float t = 0; - - for (int j = ax; j < bx; j++) - { - tex_x = (1.0f - t) * tex_su + t * tex_eu; - tex_y = (1.0f - t) * tex_sv + t * tex_ev; - tex_z = (1.0f - t) * tex_sz + t * tex_ez; - - if (tex_z > m_DepthBuffer[i*pge->ScreenWidth() + j]) - { - pge->Draw(j, i, spr->Sample(tex_x / tex_z, tex_y / tex_z)); - m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_z; - } - t += tstep; - } - - - } - } - - dy1 = tri.p[2].y - tri.p[1].y; - dx1 = tri.p[2].x - tri.p[1].x; - dv1 = tri.t[2].y - tri.t[1].y; - du1 = tri.t[2].x - tri.t[1].x; - dz1 = tri.t[2].z - tri.t[1].z; - - if (dy1) dax_step = dx1 / (float)abs(dy1); - if (dy2) dbx_step = dx2 / (float)abs(dy2); - - - du1_step = 0, dv1_step = 0;// , dz1_step = 0;// , du2_step = 0, dv2_step = 0; - if (dy1) du1_step = du1 / (float)abs(dy1); - if (dy1) dv1_step = dv1 / (float)abs(dy1); - if (dy1) dz1_step = dz1 / (float)abs(dy1); - - if (dy1) - { - for (int i = tri.p[1].y; i <= tri.p[2].y; i++) - { - int ax = tri.p[1].x + (i - tri.p[1].y) * dax_step; - int bx = tri.p[0].x + (i - tri.p[0].y) * dbx_step; - - // Start and end points in texture space - float tex_su = tri.t[1].x + (float)(i - tri.p[1].y) * du1_step; - float tex_sv = tri.t[1].y + (float)(i - tri.p[1].y) * dv1_step; - float tex_sz = tri.t[1].z + (float)(i - tri.p[1].y) * dz1_step; - - float tex_eu = tri.t[0].x + (float)(i - tri.p[0].y) * du2_step; - float tex_ev = tri.t[0].y + (float)(i - tri.p[0].y) * dv2_step; - float tex_ez = tri.t[0].z + (float)(i - tri.p[0].y) * dz2_step; - - if (ax > bx) - { - std::swap(ax, bx); - std::swap(tex_su, tex_eu); - std::swap(tex_sv, tex_ev); - std::swap(tex_sz, tex_ez); - } - - tex_x = tex_su; - tex_y = tex_sv; - tex_z = tex_sz; - - - float tstep = 1.0f / ((float)(bx - ax)); - float t = 0; - - for (int j = ax; j < bx; j++) - { - tex_x = (1.0f - t) * tex_su + t * tex_eu; - tex_y = (1.0f - t) * tex_sv + t * tex_ev; - tex_z = (1.0f - t) * tex_sz + t * tex_ez; - - if (tex_z > m_DepthBuffer[i*pge->ScreenWidth() + j]) - { - pge->Draw(j, i, spr->Sample(tex_x / tex_z, tex_y / tex_z)); - m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_z; - } - - t += tstep; - } - } - } - - } - - float* GFX3D::m_DepthBuffer = nullptr; - - void GFX3D::ConfigureDisplay() - { - m_DepthBuffer = new float[pge->ScreenWidth() * pge->ScreenHeight()]{ 0 }; - } - - - void GFX3D::ClearDepth() - { - memset(m_DepthBuffer, 0, pge->ScreenWidth() * pge->ScreenHeight() * sizeof(float)); - } - - - - - GFX3D::PipeLine::PipeLine() - { - - } - - void GFX3D::PipeLine::SetProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar, float fLeft, float fTop, float fWidth, float fHeight) - { - matProj = GFX3D::Math::Mat_MakeProjection(fFovDegrees, fAspectRatio, fNear, fFar); - fViewX = fLeft; - fViewY = fTop; - fViewW = fWidth; - fViewH = fHeight; - } - - void GFX3D::PipeLine::SetCamera(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &lookat, olc::GFX3D::vec3d &up) - { - matView = GFX3D::Math::Mat_PointAt(pos, lookat, up); - matView = GFX3D::Math::Mat_QuickInverse(matView); - } - - void GFX3D::PipeLine::SetTransform(olc::GFX3D::mat4x4 &transform) - { - matWorld = transform; - } - - void GFX3D::PipeLine::SetTexture(olc::Sprite *texture) - { - sprTexture = texture; - } - - void GFX3D::PipeLine::SetLightSource(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &dir, olc::Pixel &col) - { - - } - - uint32_t GFX3D::PipeLine::Render(std::vector &triangles, uint32_t flags) - { - // Calculate Transformation Matrix - mat4x4 matWorldView = Math::Mat_MultiplyMatrix(matWorld, matView); - //matWorldViewProj = Math::Mat_MultiplyMatrix(matWorldView, matProj); - - // Store triangles for rastering later - std::vector vecTrianglesToRaster; - - int nTriangleDrawnCount = 0; - - // Process Triangles - for (auto &tri : triangles) - { - GFX3D::triangle triTransformed; - - // Just copy through texture coordinates - triTransformed.t[0] = { tri.t[0].x, tri.t[0].y, tri.t[0].z }; - triTransformed.t[1] = { tri.t[1].x, tri.t[1].y, tri.t[1].z }; - triTransformed.t[2] = { tri.t[2].x, tri.t[2].y, tri.t[2].z }; // Think! - - // Transform Triangle from object into projected space - triTransformed.p[0] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[0]); - triTransformed.p[1] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[1]); - triTransformed.p[2] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[2]); - - // Calculate Triangle Normal in WorldView Space - GFX3D::vec3d normal, line1, line2; - line1 = GFX3D::Math::Vec_Sub(triTransformed.p[1], triTransformed.p[0]); - line2 = GFX3D::Math::Vec_Sub(triTransformed.p[2], triTransformed.p[0]); - normal = GFX3D::Math::Vec_CrossProduct(line1, line2); - normal = GFX3D::Math::Vec_Normalise(normal); - - // Cull triangles that face away from viewer - if (flags & RENDER_CULL_CW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) > 0.0f) continue; - if (flags & RENDER_CULL_CCW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) < 0.0f) continue; - - // If Lighting, calculate shading - triTransformed.col = olc::WHITE; - - // Clip triangle against near plane - int nClippedTriangles = 0; - triangle clipped[2]; - nClippedTriangles = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.1f }, { 0.0f, 0.0f, 1.0f }, triTransformed, clipped[0], clipped[1]); - - // This may yield two new triangles - for (int n = 0; n < nClippedTriangles; n++) - { - triangle triProjected = clipped[n]; - - // Project new triangle - triProjected.p[0] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[0]); - triProjected.p[1] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[1]); - triProjected.p[2] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[2]); - - // Apply Projection to Verts - triProjected.p[0].x = triProjected.p[0].x / triProjected.p[0].w; - triProjected.p[1].x = triProjected.p[1].x / triProjected.p[1].w; - triProjected.p[2].x = triProjected.p[2].x / triProjected.p[2].w; - - triProjected.p[0].y = triProjected.p[0].y / triProjected.p[0].w; - triProjected.p[1].y = triProjected.p[1].y / triProjected.p[1].w; - triProjected.p[2].y = triProjected.p[2].y / triProjected.p[2].w; - - triProjected.p[0].z = triProjected.p[0].z / triProjected.p[0].w; - triProjected.p[1].z = triProjected.p[1].z / triProjected.p[1].w; - triProjected.p[2].z = triProjected.p[2].z / triProjected.p[2].w; - - // Apply Projection to Tex coords - triProjected.t[0].x = triProjected.t[0].x / triProjected.p[0].w; - triProjected.t[1].x = triProjected.t[1].x / triProjected.p[1].w; - triProjected.t[2].x = triProjected.t[2].x / triProjected.p[2].w; - - triProjected.t[0].y = triProjected.t[0].y / triProjected.p[0].w; - triProjected.t[1].y = triProjected.t[1].y / triProjected.p[1].w; - triProjected.t[2].y = triProjected.t[2].y / triProjected.p[2].w; - - triProjected.t[0].z = 1.0f / triProjected.p[0].w; - triProjected.t[1].z = 1.0f / triProjected.p[1].w; - triProjected.t[2].z = 1.0f / triProjected.p[2].w; - - // Clip against viewport in screen space - // Clip triangles against all four screen edges, this could yield - // a bunch of triangles, so create a queue that we traverse to - // ensure we only test new triangles generated against planes - triangle sclipped[2]; - std::list listTriangles; - - - // Add initial triangle - listTriangles.push_back(triProjected); - int nNewTriangles = 1; - - for (int p = 0; p < 4; p++) - { - int nTrisToAdd = 0; - while (nNewTriangles > 0) - { - // Take triangle from front of queue - triangle test = listTriangles.front(); - listTriangles.pop_front(); - nNewTriangles--; - - // Clip it against a plane. We only need to test each - // subsequent plane, against subsequent new triangles - // as all triangles after a plane clip are guaranteed - // to lie on the inside of the plane. I like how this - // comment is almost completely and utterly justified - switch (p) - { - case 0: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, -1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - case 1: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, +1.0f, 0.0f }, { 0.0f, -1.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - case 2: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ -1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - case 3: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ +1.0f, 0.0f, 0.0f }, { -1.0f, 0.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - } - - - // Clipping may yield a variable number of triangles, so - // add these new ones to the back of the queue for subsequent - // clipping against next planes - for (int w = 0; w < nTrisToAdd; w++) - listTriangles.push_back(sclipped[w]); - } - nNewTriangles = listTriangles.size(); - } - - for (auto &triRaster : listTriangles) - { - // Scale to viewport - /*triRaster.p[0].x *= -1.0f; - triRaster.p[1].x *= -1.0f; - triRaster.p[2].x *= -1.0f; - triRaster.p[0].y *= -1.0f; - triRaster.p[1].y *= -1.0f; - triRaster.p[2].y *= -1.0f;*/ - vec3d vOffsetView = { 1,1,0 }; - triRaster.p[0] = Math::Vec_Add(triRaster.p[0], vOffsetView); - triRaster.p[1] = Math::Vec_Add(triRaster.p[1], vOffsetView); - triRaster.p[2] = Math::Vec_Add(triRaster.p[2], vOffsetView); - triRaster.p[0].x *= 0.5f * fViewW; - triRaster.p[0].y *= 0.5f * fViewH; - triRaster.p[1].x *= 0.5f * fViewW; - triRaster.p[1].y *= 0.5f * fViewH; - triRaster.p[2].x *= 0.5f * fViewW; - triRaster.p[2].y *= 0.5f * fViewH; - vOffsetView = { fViewX,fViewY,0 }; - triRaster.p[0] = Math::Vec_Add(triRaster.p[0], vOffsetView); - triRaster.p[1] = Math::Vec_Add(triRaster.p[1], vOffsetView); - triRaster.p[2] = Math::Vec_Add(triRaster.p[2], vOffsetView); - - // For now, just draw triangle - - if (flags & RENDER_TEXTURED) - { - TexturedTriangle( - triRaster.p[0].x, triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, - triRaster.p[1].x, triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, - triRaster.p[2].x, triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, - sprTexture); - } - - if (flags & RENDER_WIRE) - { - DrawTriangleWire(triRaster, olc::RED); - } - - if (flags & RENDER_FLAT) - { - DrawTriangleFlat(triRaster); - } - - nTriangleDrawnCount++; - } - } - } - - return nTriangleDrawnCount; - } -} - -#endif \ No newline at end of file diff --git a/Videos/CarCrimeCity/Part1/olcPixelGameEngine.h b/Videos/CarCrimeCity/Part1/olcPixelGameEngine.h deleted file mode 100644 index 0c524ac..0000000 --- a/Videos/CarCrimeCity/Part1/olcPixelGameEngine.h +++ /dev/null @@ -1,2067 +0,0 @@ -/* - olcPixelGameEngine.h - - +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine v1.12 | - | "Like the command prompt console one, but not..." - javidx9 | - +-------------------------------------------------------------+ - - What is this? - ~~~~~~~~~~~~~ - The olcConsoleGameEngine has been a surprsing and wonderful - success for me, and I'm delighted how people have reacted so - positively towards it, so thanks for that. - - However, there are limitations that I simply cannot avoid. - Firstly, I need to maintain several different versions of - it to accommodate users on Windows7, 8, 10, Linux, Mac, - Visual Studio & Code::Blocks. Secondly, this year I've been - pushing the console to the limits of its graphical capabilities - and the effect is becoming underwhelming. The engine itself - is not slow at all, but the process that Windows uses to - draw the command prompt to the screen is, and worse still, - it's dynamic based upon the variation of character colours - and glyphs. Sadly I have no control over this, and recent - videos that are extremely graphical (for a command prompt :P ) - have been dipping to unacceptable framerates. As the channel - has been popular with aspiring game developers, I'm concerned - that the visual appeal of the command prompt is perhaps - limited to us oldies, and I dont want to alienate younger - learners. Finally, I'd like to demonstrate many more - algorithms and image processing that exist in the graphical - domain, for which the console is insufficient. - - For this reason, I have created olcPixelGameEngine! The look - and feel to the programmer is almost identical, so all of my - existing code from the videos is easily portable, and the - programmer uses this file in exactly the same way. But I've - decided that rather than just build a command prompt emulator, - that I would at least harness some modern(ish) portable - technologies. - - As a result, the olcPixelGameEngine supports 32-bit colour, is - written in a cross-platform style, uses modern(ish) C++ - conventions and most importantly, renders much much faster. I - will use this version when my applications are predominantly - graphics based, but use the console version when they are - predominantly text based - Don't worry, loads more command - prompt silliness to come yet, but evolution is important!! - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - Patreon: https://www.patreon.com/javidx9 - - Relevant Videos - ~~~~~~~~~~~~~~~ - https://youtu.be/kRH6oJLFYxY Introducing olcPixelGameEngine - - Compiling in Linux - ~~~~~~~~~~~~~~~~~~ - You will need a modern C++ compiler, so update yours! - To compile use the command: - - g++ -o YourProgName YourSource.cpp -lX11 -lGL -lpthread -lpng - - On some Linux configurations, the frame rate is locked to the refresh - rate of the monitor. This engine tries to unlock it but may not be - able to, in which case try launching your program like this: - - vblank_mode=0 ./YourProgName - - - Compiling in Code::Blocks on Windows - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Well I wont judge you, but make sure your Code::Blocks installation - is really up to date - you may even consider updating your C++ toolchain - to use MinGW32-W64, so google this. You will also need to enable C++14 - in your build options, and add to your linker the following libraries: - user32 gdi32 opengl32 gdiplus - - Thanks - ~~~~~~ - I'd like to extend thanks to Eremiell, slavka, gurkanctn, Phantim, - JackOJC, KrossX, Huhlig, Dragoneye, Appa, JustinRichardsMusic, SliceNDice - Ralakus, Gorbit99, raoul & MagetzUb for advice, ideas and testing, and I'd like - to extend my appreciation to the 23K YouTube followers and 1.5K Discord server - members who give me the motivation to keep going with all this :D - - Special thanks to those who bring gifts! - GnarGnarHead.......Domina - Gorbit99...........Bastion - - Special thanks to my Patreons too - I wont name you on here, but I've - certainly enjoyed my tea and flapjacks :D - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019 -*/ - -////////////////////////////////////////////////////////////////////////////////////////// - -/* Example Usage (main.cpp) - #define OLC_PGE_APPLICATION - #include "olcPixelGameEngine.h" - // Override base class with your custom functionality - class Example : public olc::PixelGameEngine - { - public: - Example() - { - sAppName = "Example"; - } - public: - bool OnUserCreate() override - { - // Called once at the start, so create things here - return true; - } - bool OnUserUpdate(float fElapsedTime) override - { - // called once per frame, draws random coloured pixels - for (int x = 0; x < ScreenWidth(); x++) - for (int y = 0; y < ScreenHeight(); y++) - Draw(x, y, olc::Pixel(rand() % 255, rand() % 255, rand()% 255)); - return true; - } - }; - int main() - { - Example demo; - if (demo.Construct(256, 240, 4, 4)) - demo.Start(); - return 0; - } -*/ - -#ifndef OLC_PGE_DEF -#define OLC_PGE_DEF - -#ifdef _WIN32 - // Link to libraries -#ifndef __MINGW32__ - #pragma comment(lib, "user32.lib") // Visual Studio Only - #pragma comment(lib, "gdi32.lib") // For other Windows Compilers please add - #pragma comment(lib, "opengl32.lib") // these libs to your linker input - #pragma comment(lib, "gdiplus.lib") -#else - // In Code::Blocks, Select C++14 in your build options, and add the - // following libs to your linker: user32 gdi32 opengl32 gdiplus -#endif - // Include WinAPI - #include - #include - - // OpenGL Extension - #include - typedef BOOL(WINAPI wglSwapInterval_t) (int interval); - static wglSwapInterval_t *wglSwapInterval; -#else - #include - #include - #include - #include - #include - typedef int(glSwapInterval_t) (Display *dpy, GLXDrawable drawable, int interval); - static glSwapInterval_t *glSwapIntervalEXT; -#endif - - -// Standard includes -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef min -#undef max - -namespace olc // All OneLoneCoder stuff will now exist in the "olc" namespace -{ - struct Pixel - { - union - { - uint32_t n = 0xFF000000; - struct - { - uint8_t r; uint8_t g; uint8_t b; uint8_t a; - }; - }; - - Pixel(); - Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255); - Pixel(uint32_t p); - enum Mode { NORMAL, MASK, ALPHA, CUSTOM }; - }; - - // Some constants for symbolic naming of Pixels - static const Pixel - WHITE(255, 255, 255), - GREY(192, 192, 192), DARK_GREY(128, 128, 128), VERY_DARK_GREY(64, 64, 64), - RED(255, 0, 0), DARK_RED(128, 0, 0), VERY_DARK_RED(64, 0, 0), - YELLOW(255, 255, 0), DARK_YELLOW(128, 128, 0), VERY_DARK_YELLOW(64, 64, 0), - GREEN(0, 255, 0), DARK_GREEN(0, 128, 0), VERY_DARK_GREEN(0, 64, 0), - CYAN(0, 255, 255), DARK_CYAN(0, 128, 128), VERY_DARK_CYAN(0, 64, 64), - BLUE(0, 0, 255), DARK_BLUE(0, 0, 128), VERY_DARK_BLUE(0, 0, 64), - MAGENTA(255, 0, 255), DARK_MAGENTA(128, 0, 128), VERY_DARK_MAGENTA(64, 0, 64), - BLACK(0, 0, 0), - BLANK(0, 0, 0, 0); - - enum rcode - { - FAIL = 0, - OK = 1, - NO_FILE = -1, - }; - - //============================================================= - - struct HWButton - { - bool bPressed = false; // Set once during the frame the event occurs - bool bReleased = false; // Set once during the frame the event occurs - bool bHeld = false; // Set tru for all frames between pressed and released events - }; - - //============================================================= - - class ResourcePack - { - public: - ResourcePack(); - ~ResourcePack(); - struct sEntry : public std::streambuf { - uint32_t nID, nFileOffset, nFileSize; uint8_t* data; void _config() { this->setg((char*)data, (char*)data, (char*)(data + nFileSize)); } - }; - - public: - olc::rcode AddToPack(std::string sFile); - - public: - olc::rcode SavePack(std::string sFile); - olc::rcode LoadPack(std::string sFile); - olc::rcode ClearPack(); - - public: - olc::ResourcePack::sEntry GetStreamBuffer(std::string sFile); - - private: - - std::map mapFiles; - }; - - //============================================================= - - // A bitmap-like structure that stores a 2D array of Pixels - class Sprite - { - public: - Sprite(); - Sprite(std::string sImageFile); - Sprite(std::string sImageFile, olc::ResourcePack *pack); - Sprite(int32_t w, int32_t h); - ~Sprite(); - - public: - olc::rcode LoadFromFile(std::string sImageFile, olc::ResourcePack *pack = nullptr); - olc::rcode LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack = nullptr); - olc::rcode SaveToPGESprFile(std::string sImageFile); - - public: - int32_t width = 0; - int32_t height = 0; - enum Mode { NORMAL, PERIODIC }; - - public: - void SetSampleMode(olc::Sprite::Mode mode = olc::Sprite::Mode::NORMAL); - Pixel GetPixel(int32_t x, int32_t y); - void SetPixel(int32_t x, int32_t y, Pixel p); - Pixel Sample(float x, float y); - Pixel* GetData(); - - private: - Pixel *pColData = nullptr; - Mode modeSample = Mode::NORMAL; - -#ifdef OLC_DBG_OVERDRAW - public: - static int nOverdrawCount; -#endif - - }; - - //============================================================= - - enum Key - { - A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, - K0, K1, K2, K3, K4, K5, K6, K7, K8, K9, - F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, - UP, DOWN, LEFT, RIGHT, - SPACE, TAB, SHIFT, CTRL, INS, DEL, HOME, END, PGUP, PGDN, - BACK, ESCAPE, RETURN, ENTER, PAUSE, SCROLL, - NP0, NP1, NP2, NP3, NP4, NP5, NP6, NP7, NP8, NP9, - NP_MUL, NP_DIV, NP_ADD, NP_SUB, NP_DECIMAL, - }; - - - //============================================================= - - class PixelGameEngine - { - public: - PixelGameEngine(); - - public: - olc::rcode Construct(uint32_t screen_w, uint32_t screen_h, uint32_t pixel_w, uint32_t pixel_h); - olc::rcode Start(); - - public: // Override Interfaces - // Called once on application startup, use to load your resources - virtual bool OnUserCreate(); - // Called every frame, and provides you with a time per frame value - virtual bool OnUserUpdate(float fElapsedTime); - // Called once on application termination, so you can be a clean coder - virtual bool OnUserDestroy(); - - public: // Hardware Interfaces - // Returns true if window is currently in focus - bool IsFocused(); - // Get the state of a specific keyboard button - HWButton GetKey(Key k); - // Get the state of a specific mouse button - HWButton GetMouse(uint32_t b); - // Get Mouse X coordinate in "pixel" space - int32_t GetMouseX(); - // Get Mouse Y coordinate in "pixel" space - int32_t GetMouseY(); - - public: // Utility - // Returns the width of the screen in "pixels" - int32_t ScreenWidth(); - // Returns the height of the screen in "pixels" - int32_t ScreenHeight(); - // Returns the width of the currently selected drawing target in "pixels" - int32_t GetDrawTargetWidth(); - // Returns the height of the currently selected drawing target in "pixels" - int32_t GetDrawTargetHeight(); - // Returns the currently active draw target - Sprite* GetDrawTarget(); - - public: // Draw Routines - // Specify which Sprite should be the target of drawing functions, use nullptr - // to specify the primary screen - void SetDrawTarget(Sprite *target); - // Change the pixel mode for different optimisations - // olc::Pixel::NORMAL = No transparency - // olc::Pixel::MASK = Transparent if alpha is < 255 - // olc::Pixel::ALPHA = Full transparency - void SetPixelMode(Pixel::Mode m); - Pixel::Mode GetPixelMode(); - // Use a custom blend function - void SetPixelMode(std::function pixelMode); - // Change the blend factor form between 0.0f to 1.0f; - void SetPixelBlend(float fBlend); - // Offset texels by sub-pixel amount (advanced, do not use) - void SetSubPixelOffset(float ox, float oy); - - // Draws a single Pixel - virtual void Draw(int32_t x, int32_t y, Pixel p = olc::WHITE); - // Draws a line from (x1,y1) to (x2,y2) - void DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p = olc::WHITE); - // Draws a circle located at (x,y) with radius - void DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p = olc::WHITE); - // Fills a circle located at (x,y) with radius - void FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p = olc::WHITE); - // Draws a rectangle at (x,y) to (x+w,y+h) - void DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p = olc::WHITE); - // Fills a rectangle at (x,y) to (x+w,y+h) - void FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p = olc::WHITE); - // Draws a triangle between points (x1,y1), (x2,y2) and (x3,y3) - void DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p = olc::WHITE); - // Flat fills a triangle between points (x1,y1), (x2,y2) and (x3,y3) - void FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p = olc::WHITE); - // Draws an entire sprite at location (x,y) - void DrawSprite(int32_t x, int32_t y, Sprite *sprite, uint32_t scale = 1); - // Draws an area of a sprite at location (x,y), where the - // selected area is (ox,oy) to (ox+w,oy+h) - void DrawPartialSprite(int32_t x, int32_t y, Sprite *sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale = 1); - // Draws a single line of text - void DrawString(int32_t x, int32_t y, std::string sText, Pixel col = olc::WHITE, uint32_t scale = 1); - // Clears entire draw target to Pixel - void Clear(Pixel p); - - public: // Branding - std::string sAppName; - - private: // Inner mysterious workings - Sprite *pDefaultDrawTarget = nullptr; - Sprite *pDrawTarget = nullptr; - Pixel::Mode nPixelMode = Pixel::NORMAL; - float fBlendFactor = 1.0f; - uint32_t nScreenWidth = 256; - uint32_t nScreenHeight = 240; - uint32_t nPixelWidth = 4; - uint32_t nPixelHeight = 4; - int32_t nMousePosX = 0; - int32_t nMousePosY = 0; - float fPixelX = 1.0f; - float fPixelY = 1.0f; - float fSubPixelOffsetX = 0.0f; - float fSubPixelOffsetY = 0.0f; - bool bHasInputFocus = false; - bool bHasMouseFocus = false; - float fFrameTimer = 1.0f; - int nFrameCount = 0; - Sprite *fontSprite = nullptr; - std::function funcPixelMode; - - static std::map mapKeys; - bool pKeyNewState[256]{ 0 }; - bool pKeyOldState[256]{ 0 }; - HWButton pKeyboardState[256]; - - bool pMouseNewState[5]{ 0 }; - bool pMouseOldState[5]{ 0 }; - HWButton pMouseState[5]; - -#ifdef _WIN32 - HDC glDeviceContext = nullptr; - HGLRC glRenderContext = nullptr; -#else - GLXContext glDeviceContext = nullptr; - GLXContext glRenderContext = nullptr; -#endif - GLuint glBuffer; - - void EngineThread(); - - // If anything sets this flag to false, the engine - // "should" shut down gracefully - static std::atomic bAtomActive; - - // Common initialisation functions - void olc_UpdateMouse(int32_t x, int32_t y); - bool olc_OpenGLCreate(); - void olc_ConstructFontSheet(); - -#ifdef _WIN32 - // Windows specific window handling - HWND olc_hWnd = nullptr; - HWND olc_WindowCreate(); - std::wstring wsAppName; - static LRESULT CALLBACK olc_WindowEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -#else - // Non-Windows specific window handling - Display* olc_Display = nullptr; - Window olc_WindowRoot; - Window olc_Window; - XVisualInfo* olc_VisualInfo; - Colormap olc_ColourMap; - XSetWindowAttributes olc_SetWindowAttribs; - Display* olc_WindowCreate(); -#endif - - }; - - - class PGEX - { - friend class olc::PixelGameEngine; - protected: - static PixelGameEngine* pge; - }; - - //============================================================= -} - -#endif // OLC_PGE_DEF - - - - -/* - Object Oriented Mode - ~~~~~~~~~~~~~~~~~~~~ - - If the olcPixelGameEngine.h is called from several sources it can cause - multiple definitions of objects. To prevent this, ONLY ONE of the pathways - to including this file must have OLC_PGE_APPLICATION defined before it. This prevents - the definitions being duplicated. - - Consider the following project structure: - - Class1.h - Includes olcPixelGameEngine.h, overrides olc::PixelGameEngine - Class1.cpp - #define OLC_PGE_APPLICATION #include "Class1.h" - Class2.h - Includes Class1.h, which includes olcPixelGameEngine.h - Class2.cpp - #define OLC_PGE_APPLICATION #include "Class2.h" - main.cpp - Includes Class1.h and Class2.h - - If all of this is a bit too confusing, you can split this file in two! - Everything below this comment block can go into olcPixelGameEngineOOP.cpp - and everything above it can go into olcPixelGameEngineOOP.h - -*/ - -#ifdef OLC_PGE_APPLICATION -#undef OLC_PGE_APPLICATION - -namespace olc -{ - Pixel::Pixel() - { - r = 0; g = 0; b = 0; a = 255; - } - - Pixel::Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) - { - r = red; g = green; b = blue; a = alpha; - } - - Pixel::Pixel(uint32_t p) - { - n = p; - } - - //========================================================== - - std::wstring ConvertS2W(std::string s) - { -#ifdef _WIN32 - int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0); - wchar_t* buffer = new wchar_t[count]; - MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count); - std::wstring w(buffer); - delete[] buffer; - return w; -#endif -//#ifdef __MINGW32__ -// wchar_t *buffer = new wchar_t[sImageFile.length() + 1]; -// mbstowcs(buffer, sImageFile.c_str(), sImageFile.length()); -// buffer[sImageFile.length()] = L'\0'; -// wsImageFile = buffer; -// delete[] buffer; -//#else - } - - Sprite::Sprite() - { - pColData = nullptr; - width = 0; - height = 0; - } - - Sprite::Sprite(std::string sImageFile) - { - LoadFromFile(sImageFile); - } - - Sprite::Sprite(std::string sImageFile, olc::ResourcePack *pack) - { - LoadFromPGESprFile(sImageFile, pack); - } - - Sprite::Sprite(int32_t w, int32_t h) - { - if(pColData) delete[] pColData; - width = w; height = h; - pColData = new Pixel[width * height]; - for (int32_t i = 0; i < width*height; i++) - pColData[i] = Pixel(); - } - - Sprite::~Sprite() - { - if (pColData) delete pColData; - } - - olc::rcode Sprite::LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack) - { - if (pColData) delete[] pColData; - - auto ReadData = [&](std::istream &is) - { - is.read((char*)&width, sizeof(int32_t)); - is.read((char*)&height, sizeof(int32_t)); - pColData = new Pixel[width * height]; - is.read((char*)pColData, width * height * sizeof(uint32_t)); - }; - - // These are essentially Memory Surfaces represented by olc::Sprite - // which load very fast, but are completely uncompressed - if (pack == nullptr) - { - std::ifstream ifs; - ifs.open(sImageFile, std::ifstream::binary); - if (ifs.is_open()) - { - ReadData(ifs); - return olc::OK; - } - else - return olc::FAIL; - } - else - { - auto streamBuffer = pack->GetStreamBuffer(sImageFile); - std::istream is(&streamBuffer); - ReadData(is); - } - - - return olc::FAIL; - } - - olc::rcode Sprite::SaveToPGESprFile(std::string sImageFile) - { - if (pColData == nullptr) return olc::FAIL; - - std::ofstream ofs; - ofs.open(sImageFile, std::ifstream::binary); - if (ofs.is_open()) - { - ofs.write((char*)&width, sizeof(int32_t)); - ofs.write((char*)&height, sizeof(int32_t)); - ofs.write((char*)pColData, width*height*sizeof(uint32_t)); - ofs.close(); - return olc::OK; - } - - return olc::FAIL; - } - - olc::rcode Sprite::LoadFromFile(std::string sImageFile, olc::ResourcePack *pack) - { -#ifdef _WIN32 - // Use GDI+ - std::wstring wsImageFile; -#ifdef __MINGW32__ - wchar_t *buffer = new wchar_t[sImageFile.length() + 1]; - mbstowcs(buffer, sImageFile.c_str(), sImageFile.length()); - buffer[sImageFile.length()] = L'\0'; - wsImageFile = buffer; - delete [] buffer; -#else - wsImageFile = ConvertS2W(sImageFile); -#endif - Gdiplus::Bitmap *bmp = Gdiplus::Bitmap::FromFile(wsImageFile.c_str()); - if (bmp == nullptr) - return olc::NO_FILE; - - width = bmp->GetWidth(); - height = bmp->GetHeight(); - pColData = new Pixel[width * height]; - - for(int x=0; xGetPixel(x, y, &c); - SetPixel(x, y, Pixel(c.GetRed(), c.GetGreen(), c.GetBlue(), c.GetAlpha())); - } - delete bmp; - return olc::OK; -#else - //////////////////////////////////////////////////////////////////////////// - // Use libpng, Thanks to Guillaume Cottenceau - // https://gist.github.com/niw/5963798 - png_structp png; - png_infop info; - - FILE *f = fopen(sImageFile.c_str(), "rb"); - if (!f) return olc::NO_FILE; - - png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png) goto fail_load; - - info = png_create_info_struct(png); - if (!info) goto fail_load; - - if (setjmp(png_jmpbuf(png))) goto fail_load; - - png_init_io(png, f); - png_read_info(png, info); - - png_byte color_type; - png_byte bit_depth; - png_bytep *row_pointers; - width = png_get_image_width(png, info); - height = png_get_image_height(png, info); - color_type = png_get_color_type(png, info); - bit_depth = png_get_bit_depth(png, info); - -#ifdef _DEBUG - std::cout << "Loading PNG: " << sImageFile << "\n"; - std::cout << "W:" << width << " H:" << height << " D:" << (int)bit_depth << "\n"; -#endif - - if (bit_depth == 16) png_set_strip_16(png); - if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png); - if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_PALETTE) - png_set_filler(png, 0xFF, PNG_FILLER_AFTER); - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png); - - png_read_update_info(png, info); - row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height); - for (int y = 0; y < height; y++) { - row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info)); - } - png_read_image(png, row_pointers); - //////////////////////////////////////////////////////////////////////////// - - // Create sprite array - pColData = new Pixel[width * height]; - - // Iterate through image rows, converting into sprite format - for (int y = 0; y < height; y++) - { - png_bytep row = row_pointers[y]; - for (int x = 0; x < width; x++) - { - png_bytep px = &(row[x * 4]); - SetPixel(x, y, Pixel(px[0], px[1], px[2], px[3])); - } - } - - fclose(f); - return olc::OK; - - fail_load: - width = 0; - height = 0; - fclose(f); - pColData = nullptr; - return olc::FAIL; -#endif - } - - void Sprite::SetSampleMode(olc::Sprite::Mode mode) - { - modeSample = mode; - } - - - Pixel Sprite::GetPixel(int32_t x, int32_t y) - { - if (modeSample == olc::Sprite::Mode::NORMAL) - { - if (x >= 0 && x < width && y >= 0 && y < height) - return pColData[y*width + x]; - else - return Pixel(0, 0, 0, 0); - } - else - { - return pColData[abs(y%height)*width + abs(x%width)]; - } - } - - void Sprite::SetPixel(int32_t x, int32_t y, Pixel p) - { - -#ifdef OLC_DBG_OVERDRAW - nOverdrawCount++; -#endif - - if (x >= 0 && x < width && y >= 0 && y < height) - pColData[y*width + x] = p; - } - - Pixel Sprite::Sample(float x, float y) - { - int32_t sx = (int32_t)((x * (float)width) - 0.5f); - int32_t sy = (int32_t)((y * (float)height) - 0.5f); - return GetPixel(sx, sy); - } - - Pixel* Sprite::GetData() { return pColData; } - - //========================================================== - - ResourcePack::ResourcePack() - { - - } - - ResourcePack::~ResourcePack() - { - ClearPack(); - } - - olc::rcode ResourcePack::AddToPack(std::string sFile) - { - std::ifstream ifs(sFile, std::ifstream::binary); - if (!ifs.is_open()) return olc::FAIL; - - // Get File Size - std::streampos p = 0; - p = ifs.tellg(); - ifs.seekg(0, std::ios::end); - p = ifs.tellg() - p; - ifs.seekg(0, std::ios::beg); - - // Create entry - sEntry e; - e.data = nullptr; - e.nFileSize = (uint32_t)p; - - // Read file into memory - e.data = new uint8_t[(uint32_t)e.nFileSize]; - ifs.read((char*)e.data, e.nFileSize); - ifs.close(); - - // Add To Map - mapFiles[sFile] = e; - return olc::OK; - } - - olc::rcode ResourcePack::SavePack(std::string sFile) - { - std::ofstream ofs(sFile, std::ofstream::binary); - if (!ofs.is_open()) return olc::FAIL; - - // 1) Write Map - size_t nMapSize = mapFiles.size(); - ofs.write((char*)&nMapSize, sizeof(size_t)); - for (auto &e : mapFiles) - { - size_t nPathSize = e.first.size(); - ofs.write((char*)&nPathSize, sizeof(size_t)); - ofs.write(e.first.c_str(), nPathSize); - ofs.write((char*)&e.second.nID, sizeof(uint32_t)); - ofs.write((char*)&e.second.nFileSize, sizeof(uint32_t)); - ofs.write((char*)&e.second.nFileOffset, sizeof(uint32_t)); - } - - // 2) Write Data - std::streampos offset = ofs.tellp(); - for (auto &e : mapFiles) - { - e.second.nFileOffset = (uint32_t)offset; - ofs.write((char*)e.second.data, e.second.nFileSize); - offset += e.second.nFileSize; - } - - // 3) Rewrite Map (it has been updated with offsets now) - ofs.seekp(std::ios::beg); - ofs.write((char*)&nMapSize, sizeof(size_t)); - for (auto &e : mapFiles) - { - size_t nPathSize = e.first.size(); - ofs.write((char*)&nPathSize, sizeof(size_t)); - ofs.write(e.first.c_str(), nPathSize); - ofs.write((char*)&e.second.nID, sizeof(uint32_t)); - ofs.write((char*)&e.second.nFileSize, sizeof(uint32_t)); - ofs.write((char*)&e.second.nFileOffset, sizeof(uint32_t)); - } - ofs.close(); - - return olc::OK; - } - - olc::rcode ResourcePack::LoadPack(std::string sFile) - { - std::ifstream ifs(sFile, std::ifstream::binary); - if (!ifs.is_open()) return olc::FAIL; - - // 1) Read Map - size_t nMapEntries; - ifs.read((char*)&nMapEntries, sizeof(size_t)); - for (size_t i = 0; i < nMapEntries; i++) - { - size_t nFilePathSize = 0; - ifs.read((char*)&nFilePathSize, sizeof(size_t)); - - std::string sFileName(nFilePathSize, ' '); - for (size_t j = 0; j < nFilePathSize; j++) - sFileName[j] = ifs.get(); - - sEntry e; - e.data = nullptr; - ifs.read((char*)&e.nID, sizeof(uint32_t)); - ifs.read((char*)&e.nFileSize, sizeof(uint32_t)); - ifs.read((char*)&e.nFileOffset, sizeof(uint32_t)); - mapFiles[sFileName] = e; - } - - // 2) Read Data - for (auto &e : mapFiles) - { - e.second.data = new uint8_t[(uint32_t)e.second.nFileSize]; - ifs.seekg(e.second.nFileOffset); - ifs.read((char*)e.second.data, e.second.nFileSize); - e.second._config(); - } - - ifs.close(); - return olc::OK; - } - - olc::ResourcePack::sEntry ResourcePack::GetStreamBuffer(std::string sFile) - { - return mapFiles[sFile]; - } - - olc::rcode ResourcePack::ClearPack() - { - for (auto &e : mapFiles) - { - if (e.second.data != nullptr) - delete[] e.second.data; - } - - mapFiles.clear(); - return olc::OK; - } - - //========================================================== - - PixelGameEngine::PixelGameEngine() - { - sAppName = "Undefined"; - olc::PGEX::pge = this; - } - - olc::rcode PixelGameEngine::Construct(uint32_t screen_w, uint32_t screen_h, uint32_t pixel_w, uint32_t pixel_h) - { - nScreenWidth = screen_w; - nScreenHeight = screen_h; - nPixelWidth = pixel_w; - nPixelHeight = pixel_h; - - fPixelX = 2.0f / (float)(nScreenWidth); - fPixelY = 2.0f / (float)(nScreenHeight); - - if (nPixelWidth == 0 || nPixelHeight == 0 || nScreenWidth == 0 || nScreenHeight == 0) - return olc::FAIL; - -#ifdef _WIN32 -#ifdef UNICODE -#ifndef __MINGW32__ - wsAppName = ConvertS2W(sAppName); -#endif -#endif -#endif - // Load the default font sheet - olc_ConstructFontSheet(); - - // Create a sprite that represents the primary drawing target - pDefaultDrawTarget = new Sprite(nScreenWidth, nScreenHeight); - SetDrawTarget(nullptr); - return olc::OK; - } - - olc::rcode PixelGameEngine::Start() - { - // Construct the window - if (!olc_WindowCreate()) - return olc::FAIL; - - // Load libraries required for PNG file interaction -#ifdef _WIN32 - // Windows use GDI+ - Gdiplus::GdiplusStartupInput startupInput; - ULONG_PTR token; - Gdiplus::GdiplusStartup(&token, &startupInput, NULL); -#else - // Linux use libpng - -#endif - // Start the thread - bAtomActive = true; - std::thread t = std::thread(&PixelGameEngine::EngineThread, this); - -#ifdef _WIN32 - // Handle Windows Message Loop - MSG msg; - while (GetMessage(&msg, NULL, 0, 0) > 0) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } -#endif - - // Wait for thread to be exited - t.join(); - return olc::OK; - } - - void PixelGameEngine::SetDrawTarget(Sprite *target) - { - if (target) - pDrawTarget = target; - else - pDrawTarget = pDefaultDrawTarget; - } - - Sprite* PixelGameEngine::GetDrawTarget() - { - return pDrawTarget; - } - - int32_t PixelGameEngine::GetDrawTargetWidth() - { - if (pDrawTarget) - return pDrawTarget->width; - else - return 0; - } - - int32_t PixelGameEngine::GetDrawTargetHeight() - { - if (pDrawTarget) - return pDrawTarget->height; - else - return 0; - } - - bool PixelGameEngine::IsFocused() - { - return bHasInputFocus; - } - - HWButton PixelGameEngine::GetKey(Key k) - { - return pKeyboardState[k]; - } - - HWButton PixelGameEngine::GetMouse(uint32_t b) - { - return pMouseState[b]; - } - - int32_t PixelGameEngine::GetMouseX() - { - return nMousePosX; - } - - int32_t PixelGameEngine::GetMouseY() - { - return nMousePosY; - } - - int32_t PixelGameEngine::ScreenWidth() - { - return nScreenWidth; - } - - int32_t PixelGameEngine::ScreenHeight() - { - return nScreenHeight; - } - - void PixelGameEngine::Draw(int32_t x, int32_t y, Pixel p) - { - if (!pDrawTarget) return; - - - if (nPixelMode == Pixel::NORMAL) - { - pDrawTarget->SetPixel(x, y, p); - return; - } - - if (nPixelMode == Pixel::MASK) - { - if(p.a == 255) - pDrawTarget->SetPixel(x, y, p); - return; - } - - if (nPixelMode == Pixel::ALPHA) - { - Pixel d = pDrawTarget->GetPixel(x, y); - float a = (float)(p.a / 255.0f) * fBlendFactor; - float c = 1.0f - a; - float r = a * (float)p.r + c * (float)d.r; - float g = a * (float)p.g + c * (float)d.g; - float b = a * (float)p.b + c * (float)d.b; - pDrawTarget->SetPixel(x, y, Pixel((uint8_t)r, (uint8_t)g, (uint8_t)b)); - return; - } - - if (nPixelMode == Pixel::CUSTOM) - { - pDrawTarget->SetPixel(x, y, funcPixelMode(x, y, p, pDrawTarget->GetPixel(x, y))); - return; - } - } - - void PixelGameEngine::SetSubPixelOffset(float ox, float oy) - { - fSubPixelOffsetX = ox * fPixelX; - fSubPixelOffsetY = oy * fPixelY; - } - - void PixelGameEngine::DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p) - { - int x, y, dx, dy, dx1, dy1, px, py, xe, ye, i; - dx = x2 - x1; dy = y2 - y1; - - // straight lines idea by gurkanctn - if (dx == 0) // Line is vertical - { - if (y2 < y1) std::swap(y1, y2); - for (y = y1; y <= y2; y++) - Draw(x1, y, p); - return; - } - - if (dy == 0) // Line is horizontal - { - if (x2 < x1) std::swap(x1, x2); - for (x = x1; x <= x2; x++) - Draw(x, y1, p); - return; - } - - // Line is Funk-aye - dx1 = abs(dx); dy1 = abs(dy); - px = 2 * dy1 - dx1; py = 2 * dx1 - dy1; - if (dy1 <= dx1) - { - if (dx >= 0) - { - x = x1; y = y1; xe = x2; - } - else - { - x = x2; y = y2; xe = x1; - } - - Draw(x, y, p); - - for (i = 0; x0 && dy>0)) y = y + 1; else y = y - 1; - px = px + 2 * (dy1 - dx1); - } - Draw(x, y, p); - } - } - else - { - if (dy >= 0) - { - x = x1; y = y1; ye = y2; - } - else - { - x = x2; y = y2; ye = y1; - } - - Draw(x, y, p); - - for (i = 0; y0 && dy>0)) x = x + 1; else x = x - 1; - py = py + 2 * (dx1 - dy1); - } - Draw(x, y, p); - } - } - } - - void PixelGameEngine::DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p) - { - int x0 = 0; - int y0 = radius; - int d = 3 - 2 * radius; - if (!radius) return; - - while (y0 >= x0) // only formulate 1/8 of circle - { - Draw(x - x0, y - y0, p);//upper left left - Draw(x - y0, y - x0, p);//upper upper left - Draw(x + y0, y - x0, p);//upper upper right - Draw(x + x0, y - y0, p);//upper right right - Draw(x - x0, y + y0, p);//lower left left - Draw(x - y0, y + x0, p);//lower lower left - Draw(x + y0, y + x0, p);//lower lower right - Draw(x + x0, y + y0, p);//lower right right - if (d < 0) d += 4 * x0++ + 6; - else d += 4 * (x0++ - y0--) + 10; - } - } - - void PixelGameEngine::FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p) - { - // Taken from wikipedia - int x0 = 0; - int y0 = radius; - int d = 3 - 2 * radius; - if (!radius) return; - - auto drawline = [&](int sx, int ex, int ny) - { - for (int i = sx; i <= ex; i++) - Draw(i, ny, p); - }; - - while (y0 >= x0) - { - // Modified to draw scan-lines instead of edges - drawline(x - x0, x + x0, y - y0); - drawline(x - y0, x + y0, y - x0); - drawline(x - x0, x + x0, y + y0); - drawline(x - y0, x + y0, y + x0); - if (d < 0) d += 4 * x0++ + 6; - else d += 4 * (x0++ - y0--) + 10; - } - } - - void PixelGameEngine::DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p) - { - DrawLine(x, y, x+w, y, p); - DrawLine(x+w, y, x+w, y+h, p); - DrawLine(x+w, y+h, x, y+h, p); - DrawLine(x, y+h, x, y, p); - } - - void PixelGameEngine::Clear(Pixel p) - { - int pixels = GetDrawTargetWidth() * GetDrawTargetHeight(); - Pixel* m = GetDrawTarget()->GetData(); - for (int i = 0; i < pixels; i++) - m[i] = p; -#ifdef OLC_DBG_OVERDRAW - olc::Sprite::nOverdrawCount += pixels; -#endif - } - - void PixelGameEngine::FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p) - { - int32_t x2 = x + w; - int32_t y2 = y + h; - - if (x < 0) x = 0; - if (x >= (int32_t)nScreenWidth) x = (int32_t)nScreenWidth; - if (y < 0) y = 0; - if (y >= (int32_t)nScreenHeight) y = (int32_t)nScreenHeight; - - if (x2 < 0) x2 = 0; - if (x2 >= (int32_t)nScreenWidth) x2 = (int32_t)nScreenWidth; - if (y2 < 0) y2 = 0; - if (y2 >= (int32_t)nScreenHeight) y2 = (int32_t)nScreenHeight; - - for (int i = x; i < x2; i++) - for (int j = y; j < y2; j++) - Draw(i, j, p); - } - - void PixelGameEngine::DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p) - { - DrawLine(x1, y1, x2, y2, p); - DrawLine(x2, y2, x3, y3, p); - DrawLine(x3, y3, x1, y1, p); - } - - // https://www.avrfreaks.net/sites/default/files/triangles.c - void PixelGameEngine::FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p) - { - auto SWAP = [](int &x, int &y) { int t = x; x = y; y = t; }; - auto drawline = [&](int sx, int ex, int ny) { for (int i = sx; i <= ex; i++) Draw(i, ny, p); }; - - int t1x, t2x, y, minx, maxx, t1xp, t2xp; - bool changed1 = false; - bool changed2 = false; - int signx1, signx2, dx1, dy1, dx2, dy2; - int e1, e2; - // Sort vertices - if (y1>y2) { SWAP(y1, y2); SWAP(x1, x2); } - if (y1>y3) { SWAP(y1, y3); SWAP(x1, x3); } - if (y2>y3) { SWAP(y2, y3); SWAP(x2, x3); } - - t1x = t2x = x1; y = y1; // Starting points - dx1 = (int)(x2 - x1); if (dx1<0) { dx1 = -dx1; signx1 = -1; } - else signx1 = 1; - dy1 = (int)(y2 - y1); - - dx2 = (int)(x3 - x1); if (dx2<0) { dx2 = -dx2; signx2 = -1; } - else signx2 = 1; - dy2 = (int)(y3 - y1); - - if (dy1 > dx1) { // swap values - SWAP(dx1, dy1); - changed1 = true; - } - if (dy2 > dx2) { // swap values - SWAP(dy2, dx2); - changed2 = true; - } - - e2 = (int)(dx2 >> 1); - // Flat top, just process the second half - if (y1 == y2) goto next; - e1 = (int)(dx1 >> 1); - - for (int i = 0; i < dx1;) { - t1xp = 0; t2xp = 0; - if (t1x= dx1) { - e1 -= dx1; - if (changed1) t1xp = signx1;//t1x += signx1; - else goto next1; - } - if (changed1) break; - else t1x += signx1; - } - // Move line - next1: - // process second line until y value is about to change - while (1) { - e2 += dy2; - while (e2 >= dx2) { - e2 -= dx2; - if (changed2) t2xp = signx2;//t2x += signx2; - else goto next2; - } - if (changed2) break; - else t2x += signx2; - } - next2: - if (minx>t1x) minx = t1x; if (minx>t2x) minx = t2x; - if (maxx dx1) { // swap values - SWAP(dy1, dx1); - changed1 = true; - } - else changed1 = false; - - e1 = (int)(dx1 >> 1); - - for (int i = 0; i <= dx1; i++) { - t1xp = 0; t2xp = 0; - if (t1x= dx1) { - e1 -= dx1; - if (changed1) { t1xp = signx1; break; }//t1x += signx1; - else goto next3; - } - if (changed1) break; - else t1x += signx1; - if (i= dx2) { - e2 -= dx2; - if (changed2) t2xp = signx2; - else goto next4; - } - if (changed2) break; - else t2x += signx2; - } - next4: - - if (minx>t1x) minx = t1x; if (minx>t2x) minx = t2x; - if (maxxy3) return; - } - } - - void PixelGameEngine::DrawSprite(int32_t x, int32_t y, Sprite *sprite, uint32_t scale) - { - if (sprite == nullptr) - return; - - if (scale > 1) - { - for (int32_t i = 0; i < sprite->width; i++) - for (int32_t j = 0; j < sprite->height; j++) - for (uint32_t is = 0; is < scale; is++) - for (uint32_t js = 0; js < scale; js++) - Draw(x + (i*scale) + is, y + (j*scale) + js, sprite->GetPixel(i, j)); - } - else - { - for (int32_t i = 0; i < sprite->width; i++) - for (int32_t j = 0; j < sprite->height; j++) - Draw(x + i, y + j, sprite->GetPixel(i, j)); - } - } - - void PixelGameEngine::DrawPartialSprite(int32_t x, int32_t y, Sprite *sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale) - { - if (sprite == nullptr) - return; - - if (scale > 1) - { - for (int32_t i = 0; i < w; i++) - for (int32_t j = 0; j < h; j++) - for (uint32_t is = 0; is < scale; is++) - for (uint32_t js = 0; js < scale; js++) - Draw(x + (i*scale) + is, y + (j*scale) + js, sprite->GetPixel(i + ox, j + oy)); - } - else - { - for (int32_t i = 0; i < w; i++) - for (int32_t j = 0; j < h; j++) - Draw(x + i, y + j, sprite->GetPixel(i + ox, j + oy)); - } - } - - void PixelGameEngine::DrawString(int32_t x, int32_t y, std::string sText, Pixel col, uint32_t scale) - { - int32_t sx = 0; - int32_t sy = 0; - Pixel::Mode m = nPixelMode; - if(col.ALPHA != 255) SetPixelMode(Pixel::ALPHA); - else SetPixelMode(Pixel::MASK); - for (auto c : sText) - { - if (c == '\n') - { - sx = 0; sy += 8 * scale; - } - else - { - int32_t ox = (c - 32) % 16; - int32_t oy = (c - 32) / 16; - - if (scale > 1) - { - for (uint32_t i = 0; i < 8; i++) - for (uint32_t j = 0; j < 8; j++) - if (fontSprite->GetPixel(i + ox * 8, j + oy * 8).r > 0) - for (uint32_t is = 0; is < scale; is++) - for (uint32_t js = 0; js < scale; js++) - Draw(x + sx + (i*scale) + is, y + sy + (j*scale) + js, col); - } - else - { - for (uint32_t i = 0; i < 8; i++) - for (uint32_t j = 0; j < 8; j++) - if (fontSprite->GetPixel(i + ox * 8, j + oy * 8).r > 0) - Draw(x + sx + i, y + sy + j, col); - } - sx += 8 * scale; - } - } - SetPixelMode(m); - } - - void PixelGameEngine::SetPixelMode(Pixel::Mode m) - { - nPixelMode = m; - } - - Pixel::Mode PixelGameEngine::GetPixelMode() - { - return nPixelMode; - } - - void PixelGameEngine::SetPixelMode(std::function pixelMode) - { - funcPixelMode = pixelMode; - nPixelMode = Pixel::Mode::CUSTOM; - } - - void PixelGameEngine::SetPixelBlend(float fBlend) - { - fBlendFactor = fBlend; - if (fBlendFactor < 0.0f) fBlendFactor = 0.0f; - if (fBlendFactor > 1.0f) fBlendFactor = 1.0f; - } - - // User must override these functions as required. I have not made - // them abstract because I do need a default behaviour to occur if - // they are not overwritten - bool PixelGameEngine::OnUserCreate() - { return false; } - bool PixelGameEngine::OnUserUpdate(float fElapsedTime) - { return false; } - bool PixelGameEngine::OnUserDestroy() - { return true; } - ////////////////////////////////////////////////////////////////// - - void PixelGameEngine::olc_UpdateMouse(int32_t x, int32_t y) - { - // Mouse coords come in screen space - // But leave in pixel space - nMousePosX = x / (int32_t)nPixelWidth; - nMousePosY = y / (int32_t)nPixelHeight; - - if (nMousePosX >= (int32_t)nScreenWidth) - nMousePosX = nScreenWidth - 1; - if (nMousePosY >= (int32_t)nScreenHeight) - nMousePosY = nScreenHeight - 1; - - if (nMousePosX < 0) - nMousePosX = 0; - if (nMousePosY < 0) - nMousePosY = 0; - } - - void PixelGameEngine::EngineThread() - { - // Start OpenGL, the context is owned by the game thread - olc_OpenGLCreate(); - - // Create Screen Texture - disable filtering - glEnable(GL_TEXTURE_2D); - glGenTextures(1, &glBuffer); - glBindTexture(GL_TEXTURE_2D, glBuffer); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nScreenWidth, nScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pDefaultDrawTarget->GetData()); - - - // Create user resources as part of this thread - if (!OnUserCreate()) - bAtomActive = false; - - auto tp1 = std::chrono::system_clock::now(); - auto tp2 = std::chrono::system_clock::now(); - - while (bAtomActive) - { - // Run as fast as possible - while (bAtomActive) - { - // Handle Timing - tp2 = std::chrono::system_clock::now(); - std::chrono::duration elapsedTime = tp2 - tp1; - tp1 = tp2; - - // Our time per frame coefficient - float fElapsedTime = elapsedTime.count(); - -#ifndef _WIN32 - // Handle Xlib Message Loop - we do this in the - // same thread that OpenGL was created so we dont - // need to worry too much about multithreading with X11 - XEvent xev; - while (XPending(olc_Display)) - { - XNextEvent(olc_Display, &xev); - if (xev.type == Expose) - { - XWindowAttributes gwa; - XGetWindowAttributes(olc_Display, olc_Window, &gwa); - glViewport(0, 0, gwa.width, gwa.height); - } - else if (xev.type == KeyPress) - { - KeySym sym = XLookupKeysym(&xev.xkey, 0); - pKeyNewState[mapKeys[sym]] = true; - } - else if (xev.type == KeyRelease) - { - KeySym sym = XLookupKeysym(&xev.xkey, 0); - pKeyNewState[mapKeys[sym]] = false; - } - else if (xev.type == ButtonPress) - { - pMouseNewState[xev.xbutton.button-1] = true; - } - else if (xev.type == ButtonRelease) - { - pMouseNewState[xev.xbutton.button-1] = false; - } - else if (xev.type == MotionNotify) - { - olc_UpdateMouse(xev.xmotion.x, xev.xmotion.y); - } - else if (xev.type == FocusIn) - { - bHasInputFocus = true; - } - else if (xev.type == FocusOut) - { - bHasInputFocus = false; - } - else if (xev.type == ClientMessage) - { - bAtomActive = false; - } - } -#endif - - // Handle User Input - Keyboard - for (int i = 0; i < 256; i++) - { - pKeyboardState[i].bPressed = false; - pKeyboardState[i].bReleased = false; - - if (pKeyNewState[i] != pKeyOldState[i]) - { - if (pKeyNewState[i]) - { - pKeyboardState[i].bPressed = !pKeyboardState[i].bHeld; - pKeyboardState[i].bHeld = true; - } - else - { - pKeyboardState[i].bReleased = true; - pKeyboardState[i].bHeld = false; - } - } - - pKeyOldState[i] = pKeyNewState[i]; - } - - // Handle User Input - Mouse - for (int i = 0; i < 5; i++) - { - pMouseState[i].bPressed = false; - pMouseState[i].bReleased = false; - - if (pMouseNewState[i] != pMouseOldState[i]) - { - if (pMouseNewState[i]) - { - pMouseState[i].bPressed = !pMouseState[i].bHeld; - pMouseState[i].bHeld = true; - } - else - { - pMouseState[i].bReleased = true; - pMouseState[i].bHeld = false; - } - } - - pMouseOldState[i] = pMouseNewState[i]; - } - -#ifdef OLC_DBG_OVERDRAW - olc::Sprite::nOverdrawCount = 0; -#endif - - // Handle Frame Update - if (!OnUserUpdate(fElapsedTime)) - bAtomActive = false; - - // Display Graphics - - // TODO: This is a bit slow (especially in debug, but 100x faster in release mode???) - // Copy pixel array into texture - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, nScreenWidth, nScreenHeight, GL_RGBA, GL_UNSIGNED_BYTE, pDefaultDrawTarget->GetData()); - - // Display texture on screen - glBegin(GL_QUADS); - glTexCoord2f(0.0, 1.0); glVertex3f(-1.0f + (fSubPixelOffsetX), -1.0f + (fSubPixelOffsetY), 0.0f); - glTexCoord2f(0.0, 0.0); glVertex3f(-1.0f + (fSubPixelOffsetX), 1.0f + (fSubPixelOffsetY), 0.0f); - glTexCoord2f(1.0, 0.0); glVertex3f( 1.0f + (fSubPixelOffsetX), 1.0f + (fSubPixelOffsetY), 0.0f); - glTexCoord2f(1.0, 1.0); glVertex3f( 1.0f + (fSubPixelOffsetX), -1.0f + (fSubPixelOffsetY), 0.0f); - glEnd(); - - // Present Graphics to screen -#ifdef _WIN32 - SwapBuffers(glDeviceContext); -#else - glXSwapBuffers(olc_Display, olc_Window); -#endif - - // Update Title Bar - fFrameTimer += fElapsedTime; - nFrameCount++; - if (fFrameTimer >= 1.0f) - { - fFrameTimer -= 1.0f; - - std::string sTitle = "OneLoneCoder.com - Pixel Game Engine - " + sAppName + " - FPS: " + std::to_string(nFrameCount); -#ifdef _WIN32 -#ifdef UNICODE - SetWindowText(olc_hWnd, ConvertS2W(sTitle).c_str()); -#else - SetWindowText(olc_hWnd, sTitle.c_str()); -#endif -#else - XStoreName(olc_Display, olc_Window, sTitle.c_str()); -#endif - nFrameCount = 0; - } - } - - // Allow the user to free resources if they have overrided the destroy function - if (OnUserDestroy()) - { - // User has permitted destroy, so exit and clean up - } - else - { - // User denied destroy for some reason, so continue running - bAtomActive = true; - } - } - -#ifdef _WIN32 - wglDeleteContext(glRenderContext); - PostMessage(olc_hWnd, WM_DESTROY, 0, 0); -#else - glXMakeCurrent(olc_Display, None, NULL); - glXDestroyContext(olc_Display, glDeviceContext); - XDestroyWindow(olc_Display, olc_Window); - XCloseDisplay(olc_Display); -#endif - - } - - - void PixelGameEngine::olc_ConstructFontSheet() - { - std::string data; - data += "?Q`0001oOch0o01o@F40o000000000"; - data += "O000000nOT0063Qo4d8>?7a14Gno94AA4gno94AaOT0>o3`oO400o7QN00000400"; - data += "Of80001oOg<7O7moBGT7O7lABET024@aBEd714AiOdl717a_=TH013Q>00000000"; - data += "720D000V?V5oB3Q_HdUoE7a9@DdDE4A9@DmoE4A;Hg]oM4Aj8S4D84@`00000000"; - data += "OaPT1000Oa`^13P1@AI[?g`1@A=[OdAoHgljA4Ao?WlBA7l1710007l100000000"; - data += "ObM6000oOfMV?3QoBDD`O7a0BDDH@5A0BDD<@5A0BGeVO5ao@CQR?5Po00000000"; - data += "Oc``000?Ogij70PO2D]??0Ph2DUM@7i`2DTg@7lh2GUj?0TO0C1870T?00000000"; - data += "70<4001o?P<7?1QoHg43O;`h@GT0@:@LB@d0>:@hN@L0@?aoN@<0O7ao0000?000"; - data += "OcH0001SOglLA7mg24TnK7ln24US>0PL24U140PnOgl0>7QgOcH0K71S0000A000"; - data += "00H00000@Dm1S007@DUSg00?OdTnH7YhOfTL<7Yh@Cl0700?@Ah0300700000000"; - data += "<008001QL00ZA41a@6HnI<1i@FHLM81M@@0LG81?O`0nC?Y7?`0ZA7Y300080000"; - data += "O`082000Oh0827mo6>Hn?Wmo?6HnMb11MP08@C11H`08@FP0@@0004@000000000"; - data += "00P00001Oab00003OcKP0006@6=PMgl<@440MglH@000000`@000001P00000000"; - data += "Ob@8@@00Ob@8@Ga13R@8Mga172@8?PAo3R@827QoOb@820@0O`0007`0000007P0"; - data += "O`000P08Od400g`<3V=P0G`673IP0`@3>1`00P@6O`P00g`SetPixel(px, py, olc::Pixel(k, k, k, k)); - if (++py == 48) { px++; py = 0; } - } - } - } - -#ifdef _WIN32 - HWND PixelGameEngine::olc_WindowCreate() - { - WNDCLASS wc; - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - wc.hInstance = GetModuleHandle(nullptr); - wc.lpfnWndProc = olc_WindowEvent; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.lpszMenuName = nullptr; - wc.hbrBackground = nullptr; -#ifdef UNICODE - wc.lpszClassName = L"OLC_PIXEL_GAME_ENGINE"; -#else - wc.lpszClassName = "OLC_PIXEL_GAME_ENGINE"; -#endif - - RegisterClass(&wc); - - // Define window furniture - DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - DWORD dwStyle = WS_CAPTION | WS_SYSMENU | WS_VISIBLE; - RECT rWndRect = { 0, 0, (LONG)nScreenWidth * (LONG)nPixelWidth, (LONG)nScreenHeight * (LONG)nPixelHeight }; - - // Keep client size as requested - AdjustWindowRectEx(&rWndRect, dwStyle, FALSE, dwExStyle); - - int width = rWndRect.right - rWndRect.left; - int height = rWndRect.bottom - rWndRect.top; - -#ifdef UNICODE - olc_hWnd = CreateWindowEx(dwExStyle, L"OLC_PIXEL_GAME_ENGINE", L"", dwStyle, - 30, 30, width, height, NULL, NULL, GetModuleHandle(nullptr), this); -#else - olc_hWnd = CreateWindowEx(dwExStyle, "OLC_PIXEL_GAME_ENGINE", "", dwStyle, - 30, 30, width, height, NULL, NULL, GetModuleHandle(nullptr), this); -#endif - - // Create Keyboard Mapping - mapKeys[0x41] = Key::A; mapKeys[0x42] = Key::B; mapKeys[0x43] = Key::C; mapKeys[0x44] = Key::D; mapKeys[0x45] = Key::E; - mapKeys[0x46] = Key::F; mapKeys[0x47] = Key::G; mapKeys[0x48] = Key::H; mapKeys[0x49] = Key::I; mapKeys[0x4A] = Key::J; - mapKeys[0x4B] = Key::K; mapKeys[0x4C] = Key::L; mapKeys[0x4D] = Key::M; mapKeys[0x4E] = Key::N; mapKeys[0x4F] = Key::O; - mapKeys[0x50] = Key::P; mapKeys[0x51] = Key::Q; mapKeys[0x52] = Key::R; mapKeys[0x53] = Key::S; mapKeys[0x54] = Key::T; - mapKeys[0x55] = Key::U; mapKeys[0x56] = Key::V; mapKeys[0x57] = Key::W; mapKeys[0x58] = Key::X; mapKeys[0x59] = Key::Y; - mapKeys[0x5A] = Key::Z; - - mapKeys[VK_F1] = Key::F1; mapKeys[VK_F2] = Key::F2; mapKeys[VK_F3] = Key::F3; mapKeys[VK_F4] = Key::F4; - mapKeys[VK_F5] = Key::F5; mapKeys[VK_F6] = Key::F6; mapKeys[VK_F7] = Key::F7; mapKeys[VK_F8] = Key::F8; - mapKeys[VK_F9] = Key::F9; mapKeys[VK_F10] = Key::F10; mapKeys[VK_F11] = Key::F11; mapKeys[VK_F12] = Key::F12; - - mapKeys[VK_DOWN] = Key::DOWN; mapKeys[VK_LEFT] = Key::LEFT; mapKeys[VK_RIGHT] = Key::RIGHT; mapKeys[VK_UP] = Key::UP; - mapKeys[VK_RETURN] = Key::ENTER; //mapKeys[VK_RETURN] = Key::RETURN; - - mapKeys[VK_BACK] = Key::BACK; mapKeys[VK_ESCAPE] = Key::ESCAPE; mapKeys[VK_RETURN] = Key::ENTER; mapKeys[VK_PAUSE] = Key::PAUSE; - mapKeys[VK_SCROLL] = Key::SCROLL; mapKeys[VK_TAB] = Key::TAB; mapKeys[VK_DELETE] = Key::DEL; mapKeys[VK_HOME] = Key::HOME; - mapKeys[VK_END] = Key::END; mapKeys[VK_PRIOR] = Key::PGUP; mapKeys[VK_NEXT] = Key::PGDN; mapKeys[VK_INSERT] = Key::INS; - mapKeys[VK_SHIFT] = Key::SHIFT; mapKeys[VK_CONTROL] = Key::CTRL; - mapKeys[VK_SPACE] = Key::SPACE; - - mapKeys[0x30] = Key::K0; mapKeys[0x31] = Key::K1; mapKeys[0x32] = Key::K2; mapKeys[0x33] = Key::K3; mapKeys[0x34] = Key::K4; - mapKeys[0x35] = Key::K5; mapKeys[0x36] = Key::K6; mapKeys[0x37] = Key::K7; mapKeys[0x38] = Key::K8; mapKeys[0x39] = Key::K9; - - mapKeys[VK_NUMPAD0] = Key::NP0; mapKeys[VK_NUMPAD1] = Key::NP1; mapKeys[VK_NUMPAD2] = Key::NP2; mapKeys[VK_NUMPAD3] = Key::NP3; mapKeys[VK_NUMPAD4] = Key::NP4; - mapKeys[VK_NUMPAD5] = Key::NP5; mapKeys[VK_NUMPAD6] = Key::NP6; mapKeys[VK_NUMPAD7] = Key::NP7; mapKeys[VK_NUMPAD8] = Key::NP8; mapKeys[VK_NUMPAD9] = Key::NP9; - mapKeys[VK_MULTIPLY] = Key::NP_MUL; mapKeys[VK_ADD] = Key::NP_ADD; mapKeys[VK_DIVIDE] = Key::NP_DIV; mapKeys[VK_SUBTRACT] = Key::NP_SUB; mapKeys[VK_DECIMAL] = Key::NP_DECIMAL; - - return olc_hWnd; - } - - bool PixelGameEngine::olc_OpenGLCreate() - { - // Create Device Context - glDeviceContext = GetDC(olc_hWnd); - PIXELFORMATDESCRIPTOR pfd = - { - sizeof(PIXELFORMATDESCRIPTOR), 1, - PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, - PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - PFD_MAIN_PLANE, 0, 0, 0, 0 - }; - - int pf = 0; - if (!(pf = ChoosePixelFormat(glDeviceContext, &pfd))) return false; - SetPixelFormat(glDeviceContext, pf, &pfd); - - if (!(glRenderContext = wglCreateContext(glDeviceContext))) return false; - wglMakeCurrent(glDeviceContext, glRenderContext); - - // Remove Frame cap - wglSwapInterval = (wglSwapInterval_t*)wglGetProcAddress("wglSwapIntervalEXT"); - wglSwapInterval(0); - return true; - } - - // Windows Event Handler - LRESULT CALLBACK PixelGameEngine::olc_WindowEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) - { - static PixelGameEngine *sge; - switch (uMsg) - { - case WM_CREATE: sge = (PixelGameEngine*)((LPCREATESTRUCT)lParam)->lpCreateParams; return 0; - case WM_MOUSEMOVE: - { - uint16_t x = lParam & 0xFFFF; // Thanks @ForAbby (Discord) - uint16_t y = (lParam >> 16) & 0xFFFF; - int16_t ix = *(int16_t*)&x; - int16_t iy = *(int16_t*)&y; - sge->olc_UpdateMouse(ix, iy); - return 0; - } - case WM_MOUSELEAVE: sge->bHasMouseFocus = false; - case WM_SETFOCUS: sge->bHasInputFocus = true; return 0; - case WM_KILLFOCUS: sge->bHasInputFocus = false; return 0; - case WM_KEYDOWN: sge->pKeyNewState[mapKeys[wParam]] = true; return 0; - case WM_KEYUP: sge->pKeyNewState[mapKeys[wParam]] = false; return 0; - case WM_LBUTTONDOWN:sge->pMouseNewState[0] = true; return 0; - case WM_LBUTTONUP: sge->pMouseNewState[0] = false; return 0; - case WM_RBUTTONDOWN:sge->pMouseNewState[1] = true; return 0; - case WM_RBUTTONUP: sge->pMouseNewState[1] = false; return 0; - case WM_MBUTTONDOWN:sge->pMouseNewState[2] = true; return 0; - case WM_MBUTTONUP: sge->pMouseNewState[2] = false; return 0; - case WM_CLOSE: bAtomActive = false; return 0; - case WM_DESTROY: PostQuitMessage(0); return 0; - } - return DefWindowProc(hWnd, uMsg, wParam, lParam); - } -#else - // Do the Linux stuff! - Display* PixelGameEngine::olc_WindowCreate() - { - XInitThreads(); - - // Grab the deafult display and window - olc_Display = XOpenDisplay(NULL); - olc_WindowRoot = DefaultRootWindow(olc_Display); - - // Based on the display capabilities, configure the appearance of the window - GLint olc_GLAttribs[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; - olc_VisualInfo = glXChooseVisual(olc_Display, 0, olc_GLAttribs); - olc_ColourMap = XCreateColormap(olc_Display, olc_WindowRoot, olc_VisualInfo->visual, AllocNone); - olc_SetWindowAttribs.colormap = olc_ColourMap; - - // Register which events we are interested in receiving - olc_SetWindowAttribs.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask; - - // Create the window - olc_Window = XCreateWindow(olc_Display, olc_WindowRoot, 30, 30, nScreenWidth * nPixelWidth, nScreenHeight * nPixelHeight, 0, olc_VisualInfo->depth, InputOutput, olc_VisualInfo->visual, CWColormap | CWEventMask, &olc_SetWindowAttribs); - - Atom wmDelete = XInternAtom(olc_Display, "WM_DELETE_WINDOW", true); - XSetWMProtocols(olc_Display, olc_Window, &wmDelete, 1); - - XMapWindow(olc_Display, olc_Window); - XStoreName(olc_Display, olc_Window, "OneLoneCoder.com - Pixel Game Engine"); - - // Create Keyboard Mapping - mapKeys[0x61] = Key::A; mapKeys[0x62] = Key::B; mapKeys[0x63] = Key::C; mapKeys[0x64] = Key::D; mapKeys[0x65] = Key::E; - mapKeys[0x66] = Key::F; mapKeys[0x67] = Key::G; mapKeys[0x68] = Key::H; mapKeys[0x69] = Key::I; mapKeys[0x6A] = Key::J; - mapKeys[0x6B] = Key::K; mapKeys[0x6C] = Key::L; mapKeys[0x6D] = Key::M; mapKeys[0x6E] = Key::N; mapKeys[0x6F] = Key::O; - mapKeys[0x70] = Key::P; mapKeys[0x71] = Key::Q; mapKeys[0x72] = Key::R; mapKeys[0x73] = Key::S; mapKeys[0x74] = Key::T; - mapKeys[0x75] = Key::U; mapKeys[0x76] = Key::V; mapKeys[0x77] = Key::W; mapKeys[0x78] = Key::X; mapKeys[0x79] = Key::Y; - mapKeys[0x7A] = Key::Z; - - mapKeys[XK_F1] = Key::F1; mapKeys[XK_F2] = Key::F2; mapKeys[XK_F3] = Key::F3; mapKeys[XK_F4] = Key::F4; - mapKeys[XK_F5] = Key::F5; mapKeys[XK_F6] = Key::F6; mapKeys[XK_F7] = Key::F7; mapKeys[XK_F8] = Key::F8; - mapKeys[XK_F9] = Key::F9; mapKeys[XK_F10] = Key::F10; mapKeys[XK_F11] = Key::F11; mapKeys[XK_F12] = Key::F12; - - mapKeys[XK_Down] = Key::DOWN; mapKeys[XK_Left] = Key::LEFT; mapKeys[XK_Right] = Key::RIGHT; mapKeys[XK_Up] = Key::UP; - mapKeys[XK_KP_Enter] = Key::ENTER; mapKeys[XK_Return] = Key::ENTER; - - mapKeys[XK_BackSpace] = Key::BACK; mapKeys[XK_Escape] = Key::ESCAPE; mapKeys[XK_Linefeed] = Key::ENTER; mapKeys[XK_Pause] = Key::PAUSE; - mapKeys[XK_Scroll_Lock] = Key::SCROLL; mapKeys[XK_Tab] = Key::TAB; mapKeys[XK_Delete] = Key::DEL; mapKeys[XK_Home] = Key::HOME; - mapKeys[XK_End] = Key::END; mapKeys[XK_Page_Up] = Key::PGUP; mapKeys[XK_Page_Down] = Key::PGDN; mapKeys[XK_Insert] = Key::INS; - mapKeys[XK_Shift_L] = Key::SHIFT; mapKeys[XK_Shift_R] = Key::SHIFT; mapKeys[XK_Control_L] = Key::CTRL; mapKeys[XK_Control_R] = Key::CTRL; - mapKeys[XK_space] = Key::SPACE; - - mapKeys[XK_0] = Key::K0; mapKeys[XK_1] = Key::K1; mapKeys[XK_2] = Key::K2; mapKeys[XK_3] = Key::K3; mapKeys[XK_4] = Key::K4; - mapKeys[XK_5] = Key::K5; mapKeys[XK_6] = Key::K6; mapKeys[XK_7] = Key::K7; mapKeys[XK_8] = Key::K8; mapKeys[XK_9] = Key::K9; - - mapKeys[XK_KP_0] = Key::NP0; mapKeys[XK_KP_1] = Key::NP1; mapKeys[XK_KP_2] = Key::NP2; mapKeys[XK_KP_3] = Key::NP3; mapKeys[XK_KP_4] = Key::NP4; - mapKeys[XK_KP_5] = Key::NP5; mapKeys[XK_KP_6] = Key::NP6; mapKeys[XK_KP_7] = Key::NP7; mapKeys[XK_KP_8] = Key::NP8; mapKeys[XK_KP_9] = Key::NP9; - mapKeys[XK_KP_Multiply] = Key::NP_MUL; mapKeys[XK_KP_Add] = Key::NP_ADD; mapKeys[XK_KP_Divide] = Key::NP_DIV; mapKeys[XK_KP_Subtract] = Key::NP_SUB; mapKeys[XK_KP_Decimal] = Key::NP_DECIMAL; - - return olc_Display; - } - - bool PixelGameEngine::olc_OpenGLCreate() - { - glDeviceContext = glXCreateContext(olc_Display, olc_VisualInfo, nullptr, GL_TRUE); - glXMakeCurrent(olc_Display, olc_Window, glDeviceContext); - - XWindowAttributes gwa; - XGetWindowAttributes(olc_Display, olc_Window, &gwa); - glViewport(0, 0, gwa.width, gwa.height); - - glSwapIntervalEXT = nullptr; - glSwapIntervalEXT = (glSwapInterval_t*)glXGetProcAddress((unsigned char*)"glXSwapIntervalEXT"); - if (glSwapIntervalEXT) - glSwapIntervalEXT(olc_Display, olc_Window, 0); - else - { - printf("NOTE: Could not disable VSYNC, glXSwapIntervalEXT() was not found!\n"); - printf(" Don't worry though, things will still work, it's just the\n"); - printf(" frame rate will be capped to your monitors refresh rate - javidx9\n"); - } - - return true; - } - -#endif - - // Need a couple of statics as these are singleton instances - // read from multiple locations - std::atomic PixelGameEngine::bAtomActive{ false }; - std::map PixelGameEngine::mapKeys; - olc::PixelGameEngine* olc::PGEX::pge = nullptr; -#ifdef OLC_DBG_OVERDRAW - int olc::Sprite::nOverdrawCount = 0; -#endif - //============================================================= -} - -#endif \ No newline at end of file diff --git a/Videos/CarCrimeCity/Part2/Lua533/include/lauxlib.h b/Videos/CarCrimeCity/Part2/Lua533/include/lauxlib.h deleted file mode 100644 index ddb7c22..0000000 --- a/Videos/CarCrimeCity/Part2/Lua533/include/lauxlib.h +++ /dev/null @@ -1,256 +0,0 @@ -/* -** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $ -** Auxiliary functions for building Lua libraries -** See Copyright Notice in lua.h -*/ - - -#ifndef lauxlib_h -#define lauxlib_h - - -#include -#include - -#include "lua.h" - - - -/* extra error code for 'luaL_load' */ -#define LUA_ERRFILE (LUA_ERRERR+1) - - -typedef struct luaL_Reg { - const char *name; - lua_CFunction func; -} luaL_Reg; - - -#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) - -LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); -#define luaL_checkversion(L) \ - luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) - -LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); -LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); -LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); -LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); -LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, - size_t *l); -LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, - const char *def, size_t *l); -LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); -LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); - -LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); -LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, - lua_Integer def); - -LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); -LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t); -LUALIB_API void (luaL_checkany) (lua_State *L, int arg); - -LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); -LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); -LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); -LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); - -LUALIB_API void (luaL_where) (lua_State *L, int lvl); -LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); - -LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, - const char *const lst[]); - -LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); -LUALIB_API int (luaL_execresult) (lua_State *L, int stat); - -/* predefined references */ -#define LUA_NOREF (-2) -#define LUA_REFNIL (-1) - -LUALIB_API int (luaL_ref) (lua_State *L, int t); -LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); - -LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, - const char *mode); - -#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) - -LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, - const char *name, const char *mode); -LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); - -LUALIB_API lua_State *(luaL_newstate) (void); - -LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); - -LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, - const char *r); - -LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); - -LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname); - -LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, - const char *msg, int level); - -LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, - lua_CFunction openf, int glb); - -/* -** =============================================================== -** some useful macros -** =============================================================== -*/ - - -#define luaL_newlibtable(L,l) \ - lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) - -#define luaL_newlib(L,l) \ - (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) - -#define luaL_argcheck(L, cond,arg,extramsg) \ - ((void)((cond) || luaL_argerror(L, (arg), (extramsg)))) -#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) -#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) - -#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) - -#define luaL_dofile(L, fn) \ - (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) - -#define luaL_dostring(L, s) \ - (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) - -#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) - -#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) - -#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) - - -/* -** {====================================================== -** Generic Buffer manipulation -** ======================================================= -*/ - -typedef struct luaL_Buffer { - char *b; /* buffer address */ - size_t size; /* buffer size */ - size_t n; /* number of characters in buffer */ - lua_State *L; - char initb[LUAL_BUFFERSIZE]; /* initial buffer */ -} luaL_Buffer; - - -#define luaL_addchar(B,c) \ - ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ - ((B)->b[(B)->n++] = (c))) - -#define luaL_addsize(B,s) ((B)->n += (s)) - -LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); -LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); -LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); -LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); -LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); -LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); -LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); -LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); - -#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) - -/* }====================================================== */ - - - -/* -** {====================================================== -** File handles for IO library -** ======================================================= -*/ - -/* -** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and -** initial structure 'luaL_Stream' (it may contain other fields -** after that initial structure). -*/ - -#define LUA_FILEHANDLE "FILE*" - - -typedef struct luaL_Stream { - FILE *f; /* stream (NULL for incompletely created streams) */ - lua_CFunction closef; /* to close stream (NULL for closed streams) */ -} luaL_Stream; - -/* }====================================================== */ - - - -/* compatibility with old module system */ -#if defined(LUA_COMPAT_MODULE) - -LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname, - int sizehint); -LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, - const luaL_Reg *l, int nup); - -#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) - -#endif - - -/* -** {================================================================== -** "Abstraction Layer" for basic report of messages and errors -** =================================================================== -*/ - -/* print a string */ -#if !defined(lua_writestring) -#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) -#endif - -/* print a newline and flush the output */ -#if !defined(lua_writeline) -#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) -#endif - -/* print an error message */ -#if !defined(lua_writestringerror) -#define lua_writestringerror(s,p) \ - (fprintf(stderr, (s), (p)), fflush(stderr)) -#endif - -/* }================================================================== */ - - -/* -** {============================================================ -** Compatibility with deprecated conversions -** ============================================================= -*/ -#if defined(LUA_COMPAT_APIINTCASTS) - -#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a)) -#define luaL_optunsigned(L,a,d) \ - ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d))) - -#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) -#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) - -#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) -#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) - -#endif -/* }============================================================ */ - - - -#endif - - diff --git a/Videos/CarCrimeCity/Part2/Lua533/include/lua.h b/Videos/CarCrimeCity/Part2/Lua533/include/lua.h deleted file mode 100644 index f78899f..0000000 --- a/Videos/CarCrimeCity/Part2/Lua533/include/lua.h +++ /dev/null @@ -1,486 +0,0 @@ -/* -** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $ -** Lua - A Scripting Language -** Lua.org, PUC-Rio, Brazil (http://www.lua.org) -** See Copyright Notice at the end of this file -*/ - - -#ifndef lua_h -#define lua_h - -#include -#include - - -#include "luaconf.h" - - -#define LUA_VERSION_MAJOR "5" -#define LUA_VERSION_MINOR "3" -#define LUA_VERSION_NUM 503 -#define LUA_VERSION_RELEASE "3" - -#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR -#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2016 Lua.org, PUC-Rio" -#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" - - -/* mark for precompiled code ('Lua') */ -#define LUA_SIGNATURE "\x1bLua" - -/* option for multiple returns in 'lua_pcall' and 'lua_call' */ -#define LUA_MULTRET (-1) - - -/* -** Pseudo-indices -** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty -** space after that to help overflow detection) -*/ -#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000) -#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) - - -/* thread status */ -#define LUA_OK 0 -#define LUA_YIELD 1 -#define LUA_ERRRUN 2 -#define LUA_ERRSYNTAX 3 -#define LUA_ERRMEM 4 -#define LUA_ERRGCMM 5 -#define LUA_ERRERR 6 - - -typedef struct lua_State lua_State; - - -/* -** basic types -*/ -#define LUA_TNONE (-1) - -#define LUA_TNIL 0 -#define LUA_TBOOLEAN 1 -#define LUA_TLIGHTUSERDATA 2 -#define LUA_TNUMBER 3 -#define LUA_TSTRING 4 -#define LUA_TTABLE 5 -#define LUA_TFUNCTION 6 -#define LUA_TUSERDATA 7 -#define LUA_TTHREAD 8 - -#define LUA_NUMTAGS 9 - - - -/* minimum Lua stack available to a C function */ -#define LUA_MINSTACK 20 - - -/* predefined values in the registry */ -#define LUA_RIDX_MAINTHREAD 1 -#define LUA_RIDX_GLOBALS 2 -#define LUA_RIDX_LAST LUA_RIDX_GLOBALS - - -/* type of numbers in Lua */ -typedef LUA_NUMBER lua_Number; - - -/* type for integer functions */ -typedef LUA_INTEGER lua_Integer; - -/* unsigned integer type */ -typedef LUA_UNSIGNED lua_Unsigned; - -/* type for continuation-function contexts */ -typedef LUA_KCONTEXT lua_KContext; - - -/* -** Type for C functions registered with Lua -*/ -typedef int (*lua_CFunction) (lua_State *L); - -/* -** Type for continuation functions -*/ -typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); - - -/* -** Type for functions that read/write blocks when loading/dumping Lua chunks -*/ -typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); - -typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud); - - -/* -** Type for memory-allocation functions -*/ -typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); - - - -/* -** generic extra include file -*/ -#if defined(LUA_USER_H) -#include LUA_USER_H -#endif - - -/* -** RCS ident string -*/ -extern const char lua_ident[]; - - -/* -** state manipulation -*/ -LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); -LUA_API void (lua_close) (lua_State *L); -LUA_API lua_State *(lua_newthread) (lua_State *L); - -LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); - - -LUA_API const lua_Number *(lua_version) (lua_State *L); - - -/* -** basic stack manipulation -*/ -LUA_API int (lua_absindex) (lua_State *L, int idx); -LUA_API int (lua_gettop) (lua_State *L); -LUA_API void (lua_settop) (lua_State *L, int idx); -LUA_API void (lua_pushvalue) (lua_State *L, int idx); -LUA_API void (lua_rotate) (lua_State *L, int idx, int n); -LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); -LUA_API int (lua_checkstack) (lua_State *L, int n); - -LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); - - -/* -** access functions (stack -> C) -*/ - -LUA_API int (lua_isnumber) (lua_State *L, int idx); -LUA_API int (lua_isstring) (lua_State *L, int idx); -LUA_API int (lua_iscfunction) (lua_State *L, int idx); -LUA_API int (lua_isinteger) (lua_State *L, int idx); -LUA_API int (lua_isuserdata) (lua_State *L, int idx); -LUA_API int (lua_type) (lua_State *L, int idx); -LUA_API const char *(lua_typename) (lua_State *L, int tp); - -LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); -LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); -LUA_API int (lua_toboolean) (lua_State *L, int idx); -LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); -LUA_API size_t (lua_rawlen) (lua_State *L, int idx); -LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); -LUA_API void *(lua_touserdata) (lua_State *L, int idx); -LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); -LUA_API const void *(lua_topointer) (lua_State *L, int idx); - - -/* -** Comparison and arithmetic functions -*/ - -#define LUA_OPADD 0 /* ORDER TM, ORDER OP */ -#define LUA_OPSUB 1 -#define LUA_OPMUL 2 -#define LUA_OPMOD 3 -#define LUA_OPPOW 4 -#define LUA_OPDIV 5 -#define LUA_OPIDIV 6 -#define LUA_OPBAND 7 -#define LUA_OPBOR 8 -#define LUA_OPBXOR 9 -#define LUA_OPSHL 10 -#define LUA_OPSHR 11 -#define LUA_OPUNM 12 -#define LUA_OPBNOT 13 - -LUA_API void (lua_arith) (lua_State *L, int op); - -#define LUA_OPEQ 0 -#define LUA_OPLT 1 -#define LUA_OPLE 2 - -LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); -LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); - - -/* -** push functions (C -> stack) -*/ -LUA_API void (lua_pushnil) (lua_State *L); -LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); -LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); -LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len); -LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); -LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, - va_list argp); -LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); -LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); -LUA_API void (lua_pushboolean) (lua_State *L, int b); -LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); -LUA_API int (lua_pushthread) (lua_State *L); - - -/* -** get functions (Lua -> stack) -*/ -LUA_API int (lua_getglobal) (lua_State *L, const char *name); -LUA_API int (lua_gettable) (lua_State *L, int idx); -LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k); -LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n); -LUA_API int (lua_rawget) (lua_State *L, int idx); -LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); -LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p); - -LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); -LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); -LUA_API int (lua_getmetatable) (lua_State *L, int objindex); -LUA_API int (lua_getuservalue) (lua_State *L, int idx); - - -/* -** set functions (stack -> Lua) -*/ -LUA_API void (lua_setglobal) (lua_State *L, const char *name); -LUA_API void (lua_settable) (lua_State *L, int idx); -LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); -LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n); -LUA_API void (lua_rawset) (lua_State *L, int idx); -LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n); -LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); -LUA_API int (lua_setmetatable) (lua_State *L, int objindex); -LUA_API void (lua_setuservalue) (lua_State *L, int idx); - - -/* -** 'load' and 'call' functions (load and run Lua code) -*/ -LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, - lua_KContext ctx, lua_KFunction k); -#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) - -LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, - lua_KContext ctx, lua_KFunction k); -#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) - -LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, - const char *chunkname, const char *mode); - -LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); - - -/* -** coroutine functions -*/ -LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, - lua_KFunction k); -LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); -LUA_API int (lua_status) (lua_State *L); -LUA_API int (lua_isyieldable) (lua_State *L); - -#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) - - -/* -** garbage-collection function and options -*/ - -#define LUA_GCSTOP 0 -#define LUA_GCRESTART 1 -#define LUA_GCCOLLECT 2 -#define LUA_GCCOUNT 3 -#define LUA_GCCOUNTB 4 -#define LUA_GCSTEP 5 -#define LUA_GCSETPAUSE 6 -#define LUA_GCSETSTEPMUL 7 -#define LUA_GCISRUNNING 9 - -LUA_API int (lua_gc) (lua_State *L, int what, int data); - - -/* -** miscellaneous functions -*/ - -LUA_API int (lua_error) (lua_State *L); - -LUA_API int (lua_next) (lua_State *L, int idx); - -LUA_API void (lua_concat) (lua_State *L, int n); -LUA_API void (lua_len) (lua_State *L, int idx); - -LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); - -LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); -LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); - - - -/* -** {============================================================== -** some useful macros -** =============================================================== -*/ - -#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE)) - -#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL) -#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL) - -#define lua_pop(L,n) lua_settop(L, -(n)-1) - -#define lua_newtable(L) lua_createtable(L, 0, 0) - -#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) - -#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) - -#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) -#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) -#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) -#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) -#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) -#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) -#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) -#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) - -#define lua_pushliteral(L, s) lua_pushstring(L, "" s) - -#define lua_pushglobaltable(L) \ - ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)) - -#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) - - -#define lua_insert(L,idx) lua_rotate(L, (idx), 1) - -#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1)) - -#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1)) - -/* }============================================================== */ - - -/* -** {============================================================== -** compatibility macros for unsigned conversions -** =============================================================== -*/ -#if defined(LUA_COMPAT_APIINTCASTS) - -#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) -#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) -#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) - -#endif -/* }============================================================== */ - -/* -** {====================================================================== -** Debug API -** ======================================================================= -*/ - - -/* -** Event codes -*/ -#define LUA_HOOKCALL 0 -#define LUA_HOOKRET 1 -#define LUA_HOOKLINE 2 -#define LUA_HOOKCOUNT 3 -#define LUA_HOOKTAILCALL 4 - - -/* -** Event masks -*/ -#define LUA_MASKCALL (1 << LUA_HOOKCALL) -#define LUA_MASKRET (1 << LUA_HOOKRET) -#define LUA_MASKLINE (1 << LUA_HOOKLINE) -#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) - -typedef struct lua_Debug lua_Debug; /* activation record */ - - -/* Functions to be called by the debugger in specific events */ -typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); - - -LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); -LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); -LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); -LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); -LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n); -LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n); - -LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); -LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, - int fidx2, int n2); - -LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); -LUA_API lua_Hook (lua_gethook) (lua_State *L); -LUA_API int (lua_gethookmask) (lua_State *L); -LUA_API int (lua_gethookcount) (lua_State *L); - - -struct lua_Debug { - int event; - const char *name; /* (n) */ - const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ - const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ - const char *source; /* (S) */ - int currentline; /* (l) */ - int linedefined; /* (S) */ - int lastlinedefined; /* (S) */ - unsigned char nups; /* (u) number of upvalues */ - unsigned char nparams;/* (u) number of parameters */ - char isvararg; /* (u) */ - char istailcall; /* (t) */ - char short_src[LUA_IDSIZE]; /* (S) */ - /* private part */ - struct CallInfo *i_ci; /* active function */ -}; - -/* }====================================================================== */ - - -/****************************************************************************** -* Copyright (C) 1994-2016 Lua.org, PUC-Rio. -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -******************************************************************************/ - - -#endif diff --git a/Videos/CarCrimeCity/Part2/Lua533/include/lua.hpp b/Videos/CarCrimeCity/Part2/Lua533/include/lua.hpp deleted file mode 100644 index ec417f5..0000000 --- a/Videos/CarCrimeCity/Part2/Lua533/include/lua.hpp +++ /dev/null @@ -1,9 +0,0 @@ -// lua.hpp -// Lua header files for C++ -// <> not supplied automatically because Lua also compiles as C++ - -extern "C" { -#include "lua.h" -#include "lualib.h" -#include "lauxlib.h" -} diff --git a/Videos/CarCrimeCity/Part2/Lua533/include/luaconf.h b/Videos/CarCrimeCity/Part2/Lua533/include/luaconf.h deleted file mode 100644 index 867e9cb..0000000 --- a/Videos/CarCrimeCity/Part2/Lua533/include/luaconf.h +++ /dev/null @@ -1,769 +0,0 @@ -/* -** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $ -** Configuration file for Lua -** See Copyright Notice in lua.h -*/ - - -#ifndef luaconf_h -#define luaconf_h - -#include -#include - - -/* -** =================================================================== -** Search for "@@" to find all configurable definitions. -** =================================================================== -*/ - - -/* -** {==================================================================== -** System Configuration: macros to adapt (if needed) Lua to some -** particular platform, for instance compiling it with 32-bit numbers or -** restricting it to C89. -** ===================================================================== -*/ - -/* -@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You -** can also define LUA_32BITS in the make file, but changing here you -** ensure that all software connected to Lua will be compiled with the -** same configuration. -*/ -/* #define LUA_32BITS */ - - -/* -@@ LUA_USE_C89 controls the use of non-ISO-C89 features. -** Define it if you want Lua to avoid the use of a few C99 features -** or Windows-specific features on Windows. -*/ -/* #define LUA_USE_C89 */ - - -/* -** By default, Lua on Windows use (some) specific Windows features -*/ -#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE) -#define LUA_USE_WINDOWS /* enable goodies for regular Windows */ -#endif - - -#if defined(LUA_USE_WINDOWS) -#define LUA_DL_DLL /* enable support for DLL */ -#define LUA_USE_C89 /* broadly, Windows is C89 */ -#endif - - -#if defined(LUA_USE_LINUX) -#define LUA_USE_POSIX -#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ -#define LUA_USE_READLINE /* needs some extra libraries */ -#endif - - -#if defined(LUA_USE_MACOSX) -#define LUA_USE_POSIX -#define LUA_USE_DLOPEN /* MacOS does not need -ldl */ -#define LUA_USE_READLINE /* needs an extra library: -lreadline */ -#endif - - -/* -@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for -** C89 ('long' and 'double'); Windows always has '__int64', so it does -** not need to use this case. -*/ -#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) -#define LUA_C89_NUMBERS -#endif - - - -/* -@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'. -*/ -/* avoid undefined shifts */ -#if ((INT_MAX >> 15) >> 15) >= 1 -#define LUAI_BITSINT 32 -#else -/* 'int' always must have at least 16 bits */ -#define LUAI_BITSINT 16 -#endif - - -/* -@@ LUA_INT_TYPE defines the type for Lua integers. -@@ LUA_FLOAT_TYPE defines the type for Lua floats. -** Lua should work fine with any mix of these options (if supported -** by your C compiler). The usual configurations are 64-bit integers -** and 'double' (the default), 32-bit integers and 'float' (for -** restricted platforms), and 'long'/'double' (for C compilers not -** compliant with C99, which may not have support for 'long long'). -*/ - -/* predefined options for LUA_INT_TYPE */ -#define LUA_INT_INT 1 -#define LUA_INT_LONG 2 -#define LUA_INT_LONGLONG 3 - -/* predefined options for LUA_FLOAT_TYPE */ -#define LUA_FLOAT_FLOAT 1 -#define LUA_FLOAT_DOUBLE 2 -#define LUA_FLOAT_LONGDOUBLE 3 - -#if defined(LUA_32BITS) /* { */ -/* -** 32-bit integers and 'float' -*/ -#if LUAI_BITSINT >= 32 /* use 'int' if big enough */ -#define LUA_INT_TYPE LUA_INT_INT -#else /* otherwise use 'long' */ -#define LUA_INT_TYPE LUA_INT_LONG -#endif -#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT - -#elif defined(LUA_C89_NUMBERS) /* }{ */ -/* -** largest types available for C89 ('long' and 'double') -*/ -#define LUA_INT_TYPE LUA_INT_LONG -#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE - -#endif /* } */ - - -/* -** default configuration for 64-bit Lua ('long long' and 'double') -*/ -#if !defined(LUA_INT_TYPE) -#define LUA_INT_TYPE LUA_INT_LONGLONG -#endif - -#if !defined(LUA_FLOAT_TYPE) -#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE -#endif - -/* }================================================================== */ - - - - -/* -** {================================================================== -** Configuration for Paths. -** =================================================================== -*/ - -/* -@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for -** Lua libraries. -@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for -** C libraries. -** CHANGE them if your machine has a non-conventional directory -** hierarchy or if you want to install your libraries in -** non-conventional directories. -*/ -#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR -#if defined(_WIN32) /* { */ -/* -** In Windows, any exclamation mark ('!') in the path is replaced by the -** path of the directory of the executable file of the current process. -*/ -#define LUA_LDIR "!\\lua\\" -#define LUA_CDIR "!\\" -#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" -#define LUA_PATH_DEFAULT \ - LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ - LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ - LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ - ".\\?.lua;" ".\\?\\init.lua" -#define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.dll;" \ - LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ - LUA_CDIR"loadall.dll;" ".\\?.dll;" \ - LUA_CDIR"?53.dll;" ".\\?53.dll" - -#else /* }{ */ - -#define LUA_ROOT "/usr/local/" -#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/" -#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/" -#define LUA_PATH_DEFAULT \ - LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ - LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \ - "./?.lua;" "./?/init.lua" -#define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so;" \ - LUA_CDIR"lib?53.so;" "./lib?53.so" -#endif /* } */ - - -/* -@@ LUA_DIRSEP is the directory separator (for submodules). -** CHANGE it if your machine does not use "/" as the directory separator -** and is not Windows. (On Windows Lua automatically uses "\".) -*/ -#if defined(_WIN32) -#define LUA_DIRSEP "\\" -#else -#define LUA_DIRSEP "/" -#endif - -/* }================================================================== */ - - -/* -** {================================================================== -** Marks for exported symbols in the C code -** =================================================================== -*/ - -/* -@@ LUA_API is a mark for all core API functions. -@@ LUALIB_API is a mark for all auxiliary library functions. -@@ LUAMOD_API is a mark for all standard library opening functions. -** CHANGE them if you need to define those functions in some special way. -** For instance, if you want to create one Windows DLL with the core and -** the libraries, you may want to use the following definition (define -** LUA_BUILD_AS_DLL to get it). -*/ -#if defined(LUA_BUILD_AS_DLL) /* { */ - -#if defined(LUA_CORE) || defined(LUA_LIB) /* { */ -#define LUA_API __declspec(dllexport) -#else /* }{ */ -#define LUA_API __declspec(dllimport) -#endif /* } */ - -#else /* }{ */ - -#define LUA_API extern - -#endif /* } */ - - -/* more often than not the libs go together with the core */ -#define LUALIB_API LUA_API -#define LUAMOD_API LUALIB_API - - -/* -@@ LUAI_FUNC is a mark for all extern functions that are not to be -** exported to outside modules. -@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables -** that are not to be exported to outside modules (LUAI_DDEF for -** definitions and LUAI_DDEC for declarations). -** CHANGE them if you need to mark them in some special way. Elf/gcc -** (versions 3.2 and later) mark them as "hidden" to optimize access -** when Lua is compiled as a shared library. Not all elf targets support -** this attribute. Unfortunately, gcc does not offer a way to check -** whether the target offers that support, and those without support -** give a warning about it. To avoid these warnings, change to the -** default definition. -*/ -#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ - defined(__ELF__) /* { */ -#define LUAI_FUNC __attribute__((visibility("hidden"))) extern -#else /* }{ */ -#define LUAI_FUNC extern -#endif /* } */ - -#define LUAI_DDEC LUAI_FUNC -#define LUAI_DDEF /* empty */ - -/* }================================================================== */ - - -/* -** {================================================================== -** Compatibility with previous versions -** =================================================================== -*/ - -/* -@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2. -@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1. -** You can define it to get all options, or change specific options -** to fit your specific needs. -*/ -#if defined(LUA_COMPAT_5_2) /* { */ - -/* -@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated -** functions in the mathematical library. -*/ -#define LUA_COMPAT_MATHLIB - -/* -@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'. -*/ -#define LUA_COMPAT_BITLIB - -/* -@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod. -*/ -#define LUA_COMPAT_IPAIRS - -/* -@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for -** manipulating other integer types (lua_pushunsigned, lua_tounsigned, -** luaL_checkint, luaL_checklong, etc.) -*/ -#define LUA_COMPAT_APIINTCASTS - -#endif /* } */ - - -#if defined(LUA_COMPAT_5_1) /* { */ - -/* Incompatibilities from 5.2 -> 5.3 */ -#define LUA_COMPAT_MATHLIB -#define LUA_COMPAT_APIINTCASTS - -/* -@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. -** You can replace it with 'table.unpack'. -*/ -#define LUA_COMPAT_UNPACK - -/* -@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'. -** You can replace it with 'package.searchers'. -*/ -#define LUA_COMPAT_LOADERS - -/* -@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall. -** You can call your C function directly (with light C functions). -*/ -#define lua_cpcall(L,f,u) \ - (lua_pushcfunction(L, (f)), \ - lua_pushlightuserdata(L,(u)), \ - lua_pcall(L,1,0,0)) - - -/* -@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. -** You can rewrite 'log10(x)' as 'log(x, 10)'. -*/ -#define LUA_COMPAT_LOG10 - -/* -@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base -** library. You can rewrite 'loadstring(s)' as 'load(s)'. -*/ -#define LUA_COMPAT_LOADSTRING - -/* -@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library. -*/ -#define LUA_COMPAT_MAXN - -/* -@@ The following macros supply trivial compatibility for some -** changes in the API. The macros themselves document how to -** change your code to avoid using them. -*/ -#define lua_strlen(L,i) lua_rawlen(L, (i)) - -#define lua_objlen(L,i) lua_rawlen(L, (i)) - -#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) -#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) - -/* -@@ LUA_COMPAT_MODULE controls compatibility with previous -** module functions 'module' (Lua) and 'luaL_register' (C). -*/ -#define LUA_COMPAT_MODULE - -#endif /* } */ - - -/* -@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a -@@ a float mark ('.0'). -** This macro is not on by default even in compatibility mode, -** because this is not really an incompatibility. -*/ -/* #define LUA_COMPAT_FLOATSTRING */ - -/* }================================================================== */ - - - -/* -** {================================================================== -** Configuration for Numbers. -** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* -** satisfy your needs. -** =================================================================== -*/ - -/* -@@ LUA_NUMBER is the floating-point type used by Lua. -@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' -@@ over a floating number. -@@ l_mathlim(x) corrects limit name 'x' to the proper float type -** by prefixing it with one of FLT/DBL/LDBL. -@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats. -@@ LUA_NUMBER_FMT is the format for writing floats. -@@ lua_number2str converts a float to a string. -@@ l_mathop allows the addition of an 'l' or 'f' to all math operations. -@@ l_floor takes the floor of a float. -@@ lua_str2number converts a decimal numeric string to a number. -*/ - - -/* The following definitions are good for most cases here */ - -#define l_floor(x) (l_mathop(floor)(x)) - -#define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n)) - -/* -@@ lua_numbertointeger converts a float number to an integer, or -** returns 0 if float is not within the range of a lua_Integer. -** (The range comparisons are tricky because of rounding. The tests -** here assume a two-complement representation, where MININTEGER always -** has an exact representation as a float; MAXINTEGER may not have one, -** and therefore its conversion to float may have an ill-defined value.) -*/ -#define lua_numbertointeger(n,p) \ - ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ - (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ - (*(p) = (LUA_INTEGER)(n), 1)) - - -/* now the variable definitions */ - -#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */ - -#define LUA_NUMBER float - -#define l_mathlim(n) (FLT_##n) - -#define LUAI_UACNUMBER double - -#define LUA_NUMBER_FRMLEN "" -#define LUA_NUMBER_FMT "%.7g" - -#define l_mathop(op) op##f - -#define lua_str2number(s,p) strtof((s), (p)) - - -#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */ - -#define LUA_NUMBER long double - -#define l_mathlim(n) (LDBL_##n) - -#define LUAI_UACNUMBER long double - -#define LUA_NUMBER_FRMLEN "L" -#define LUA_NUMBER_FMT "%.19Lg" - -#define l_mathop(op) op##l - -#define lua_str2number(s,p) strtold((s), (p)) - -#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */ - -#define LUA_NUMBER double - -#define l_mathlim(n) (DBL_##n) - -#define LUAI_UACNUMBER double - -#define LUA_NUMBER_FRMLEN "" -#define LUA_NUMBER_FMT "%.14g" - -#define l_mathop(op) op - -#define lua_str2number(s,p) strtod((s), (p)) - -#else /* }{ */ - -#error "numeric float type not defined" - -#endif /* } */ - - - -/* -@@ LUA_INTEGER is the integer type used by Lua. -** -@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. -** -@@ LUAI_UACINT is the result of an 'usual argument conversion' -@@ over a lUA_INTEGER. -@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. -@@ LUA_INTEGER_FMT is the format for writing integers. -@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. -@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. -@@ lua_integer2str converts an integer to a string. -*/ - - -/* The following definitions are good for most cases here */ - -#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" -#define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n)) - -#define LUAI_UACINT LUA_INTEGER - -/* -** use LUAI_UACINT here to avoid problems with promotions (which -** can turn a comparison between unsigneds into a signed comparison) -*/ -#define LUA_UNSIGNED unsigned LUAI_UACINT - - -/* now the variable definitions */ - -#if LUA_INT_TYPE == LUA_INT_INT /* { int */ - -#define LUA_INTEGER int -#define LUA_INTEGER_FRMLEN "" - -#define LUA_MAXINTEGER INT_MAX -#define LUA_MININTEGER INT_MIN - -#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */ - -#define LUA_INTEGER long -#define LUA_INTEGER_FRMLEN "l" - -#define LUA_MAXINTEGER LONG_MAX -#define LUA_MININTEGER LONG_MIN - -#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */ - -/* use presence of macro LLONG_MAX as proxy for C99 compliance */ -#if defined(LLONG_MAX) /* { */ -/* use ISO C99 stuff */ - -#define LUA_INTEGER long long -#define LUA_INTEGER_FRMLEN "ll" - -#define LUA_MAXINTEGER LLONG_MAX -#define LUA_MININTEGER LLONG_MIN - -#elif defined(LUA_USE_WINDOWS) /* }{ */ -/* in Windows, can use specific Windows types */ - -#define LUA_INTEGER __int64 -#define LUA_INTEGER_FRMLEN "I64" - -#define LUA_MAXINTEGER _I64_MAX -#define LUA_MININTEGER _I64_MIN - -#else /* }{ */ - -#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \ - or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)" - -#endif /* } */ - -#else /* }{ */ - -#error "numeric integer type not defined" - -#endif /* } */ - -/* }================================================================== */ - - -/* -** {================================================================== -** Dependencies with C99 and other C details -** =================================================================== -*/ - -/* -@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89. -** (All uses in Lua have only one format item.) -*/ -#if !defined(LUA_USE_C89) -#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i) -#else -#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i)) -#endif - - -/* -@@ lua_strx2number converts an hexadecimal numeric string to a number. -** In C99, 'strtod' does that conversion. Otherwise, you can -** leave 'lua_strx2number' undefined and Lua will provide its own -** implementation. -*/ -#if !defined(LUA_USE_C89) -#define lua_strx2number(s,p) lua_str2number(s,p) -#endif - - -/* -@@ lua_number2strx converts a float to an hexadecimal numeric string. -** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. -** Otherwise, you can leave 'lua_number2strx' undefined and Lua will -** provide its own implementation. -*/ -#if !defined(LUA_USE_C89) -#define lua_number2strx(L,b,sz,f,n) ((void)L, l_sprintf(b,sz,f,n)) -#endif - - -/* -** 'strtof' and 'opf' variants for math functions are not valid in -** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the -** availability of these variants. ('math.h' is already included in -** all files that use these macros.) -*/ -#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF)) -#undef l_mathop /* variants not available */ -#undef lua_str2number -#define l_mathop(op) (lua_Number)op /* no variant */ -#define lua_str2number(s,p) ((lua_Number)strtod((s), (p))) -#endif - - -/* -@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation -** functions. It must be a numerical type; Lua will use 'intptr_t' if -** available, otherwise it will use 'ptrdiff_t' (the nearest thing to -** 'intptr_t' in C89) -*/ -#define LUA_KCONTEXT ptrdiff_t - -#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ - __STDC_VERSION__ >= 199901L -#include -#if defined(INTPTR_MAX) /* even in C99 this type is optional */ -#undef LUA_KCONTEXT -#define LUA_KCONTEXT intptr_t -#endif -#endif - - -/* -@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point). -** Change that if you do not want to use C locales. (Code using this -** macro must include header 'locale.h'.) -*/ -#if !defined(lua_getlocaledecpoint) -#define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) -#endif - -/* }================================================================== */ - - -/* -** {================================================================== -** Language Variations -** ===================================================================== -*/ - -/* -@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some -** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from -** numbers to strings. Define LUA_NOCVTS2N to turn off automatic -** coercion from strings to numbers. -*/ -/* #define LUA_NOCVTN2S */ -/* #define LUA_NOCVTS2N */ - - -/* -@@ LUA_USE_APICHECK turns on several consistency checks on the C API. -** Define it as a help when debugging C code. -*/ -#if defined(LUA_USE_APICHECK) -#include -#define luai_apicheck(l,e) assert(e) -#endif - -/* }================================================================== */ - - -/* -** {================================================================== -** Macros that affect the API and must be stable (that is, must be the -** same when you compile Lua and when you compile code that links to -** Lua). You probably do not want/need to change them. -** ===================================================================== -*/ - -/* -@@ LUAI_MAXSTACK limits the size of the Lua stack. -** CHANGE it if you need a different limit. This limit is arbitrary; -** its only purpose is to stop Lua from consuming unlimited stack -** space (and to reserve some numbers for pseudo-indices). -*/ -#if LUAI_BITSINT >= 32 -#define LUAI_MAXSTACK 1000000 -#else -#define LUAI_MAXSTACK 15000 -#endif - - -/* -@@ LUA_EXTRASPACE defines the size of a raw memory area associated with -** a Lua state with very fast access. -** CHANGE it if you need a different size. -*/ -#define LUA_EXTRASPACE (sizeof(void *)) - - -/* -@@ LUA_IDSIZE gives the maximum size for the description of the source -@@ of a function in debug information. -** CHANGE it if you want a different size. -*/ -#define LUA_IDSIZE 60 - - -/* -@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. -** CHANGE it if it uses too much C-stack space. (For long double, -** 'string.format("%.99f", 1e4932)' needs ~5030 bytes, so a -** smaller buffer would force a memory allocation for each call to -** 'string.format'.) -*/ -#if defined(LUA_FLOAT_LONGDOUBLE) -#define LUAL_BUFFERSIZE 8192 -#else -#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer))) -#endif - -/* }================================================================== */ - - -/* -@@ LUA_QL describes how error messages quote program elements. -** Lua does not use these macros anymore; they are here for -** compatibility only. -*/ -#define LUA_QL(x) "'" x "'" -#define LUA_QS LUA_QL("%s") - - - - -/* =================================================================== */ - -/* -** Local configuration. You can use this space to add your redefinitions -** without modifying the main part of the file. -*/ - - - - - -#endif - diff --git a/Videos/CarCrimeCity/Part2/Lua533/include/lualib.h b/Videos/CarCrimeCity/Part2/Lua533/include/lualib.h deleted file mode 100644 index 5165c0f..0000000 --- a/Videos/CarCrimeCity/Part2/Lua533/include/lualib.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $ -** Lua standard libraries -** See Copyright Notice in lua.h -*/ - - -#ifndef lualib_h -#define lualib_h - -#include "lua.h" - - - -LUAMOD_API int (luaopen_base) (lua_State *L); - -#define LUA_COLIBNAME "coroutine" -LUAMOD_API int (luaopen_coroutine) (lua_State *L); - -#define LUA_TABLIBNAME "table" -LUAMOD_API int (luaopen_table) (lua_State *L); - -#define LUA_IOLIBNAME "io" -LUAMOD_API int (luaopen_io) (lua_State *L); - -#define LUA_OSLIBNAME "os" -LUAMOD_API int (luaopen_os) (lua_State *L); - -#define LUA_STRLIBNAME "string" -LUAMOD_API int (luaopen_string) (lua_State *L); - -#define LUA_UTF8LIBNAME "utf8" -LUAMOD_API int (luaopen_utf8) (lua_State *L); - -#define LUA_BITLIBNAME "bit32" -LUAMOD_API int (luaopen_bit32) (lua_State *L); - -#define LUA_MATHLIBNAME "math" -LUAMOD_API int (luaopen_math) (lua_State *L); - -#define LUA_DBLIBNAME "debug" -LUAMOD_API int (luaopen_debug) (lua_State *L); - -#define LUA_LOADLIBNAME "package" -LUAMOD_API int (luaopen_package) (lua_State *L); - - -/* open all previous libraries */ -LUALIB_API void (luaL_openlibs) (lua_State *L); - - - -#if !defined(lua_assert) -#define lua_assert(x) ((void)0) -#endif - - -#endif diff --git a/Videos/CarCrimeCity/Part2/Lua533/liblua53.a b/Videos/CarCrimeCity/Part2/Lua533/liblua53.a deleted file mode 100644 index 32646db..0000000 Binary files a/Videos/CarCrimeCity/Part2/Lua533/liblua53.a and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/Lua533/lua53.dll b/Videos/CarCrimeCity/Part2/Lua533/lua53.dll deleted file mode 100644 index 2ab8168..0000000 Binary files a/Videos/CarCrimeCity/Part2/Lua533/lua53.dll and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/buildings/udxs_building1.obj b/Videos/CarCrimeCity/Part2/assets/buildings/udxs_building1.obj deleted file mode 100644 index fe83e45..0000000 --- a/Videos/CarCrimeCity/Part2/assets/buildings/udxs_building1.obj +++ /dev/null @@ -1,716 +0,0 @@ -# Blender v2.79 (sub 0) OBJ File: 'olc_building0.blend' -# www.blender.org -mtllib olc_building0.mtl -o Plane -v 0.000000 0.000000 0.000000 -v 0.000000 -1.000000 0.000000 -v -1.000000 0.000000 0.000000 -v -1.000000 -1.000000 0.000000 -v -0.025000 -0.412671 -0.052133 -v -0.025000 -0.587329 -0.052133 -v -0.975000 -0.025000 -0.050000 -v -0.975000 -0.975000 -0.050000 -v -1.000000 0.000000 -0.050000 -v 0.000000 0.000000 -0.050000 -v 0.000000 -1.000000 -0.050000 -v -1.000000 -1.000000 -0.050000 -v -0.975000 -0.025000 -0.517611 -v -0.975000 -0.975000 -0.517611 -v -1.000000 0.000000 -0.527316 -v 0.000000 0.000000 -0.527316 -v 0.000000 -1.000000 -0.527316 -v -1.000000 -1.000000 -0.527316 -v -0.975000 -0.025000 -0.550000 -v -0.025000 -0.025000 -0.550000 -v -0.025000 -0.975000 -0.550000 -v -0.975000 -0.975000 -0.550000 -v -0.025000 -0.601364 -0.402078 -v -0.025000 -0.601364 -0.044706 -v -0.025000 -0.398636 -0.044706 -v -0.025000 -0.398636 -0.402078 -v -0.374620 -0.412671 -0.045097 -v -0.374620 -0.587329 -0.047815 -v -0.374620 -0.587329 -0.388044 -v -0.374620 -0.412671 -0.388044 -v -0.005099 -0.601364 -0.402078 -v -0.005099 -0.601364 -0.044706 -v -0.005099 -0.398636 -0.044706 -v -0.005099 -0.398636 -0.402078 -v -0.005099 -0.587329 -0.388044 -v -0.005099 -0.587329 -0.047815 -v -0.005099 -0.412671 -0.045097 -v -0.005099 -0.412671 -0.388044 -v -0.017305 -0.419472 -0.044438 -v -0.017305 -0.594130 -0.044438 -v -0.025000 -0.975000 -0.517611 -v -0.025000 -0.975000 -0.050000 -v -0.025000 -0.601364 -0.402078 -v -0.025000 -0.601364 -0.044706 -v -0.025000 -0.025000 -0.050000 -v -0.025000 -0.025000 -0.517611 -v -0.025000 -0.398636 -0.044706 -v -0.025000 -0.398636 -0.402078 -v -0.925000 -0.075000 -1.550000 -v -0.075000 -0.075000 -1.550000 -v -0.075000 -0.925000 -1.550000 -v -0.925000 -0.925000 -1.550000 -v -0.975000 -0.025000 -1.550000 -v -0.025000 -0.025000 -1.550000 -v -0.025000 -0.975000 -1.550000 -v -0.975000 -0.975000 -1.550000 -v -0.975000 -0.025000 -1.600000 -v -0.025000 -0.025000 -1.600000 -v -0.025000 -0.975000 -1.600000 -v -0.975000 -0.975000 -1.600000 -v -0.925000 -0.075000 -1.600000 -v -0.075000 -0.075000 -1.600000 -v -0.075000 -0.925000 -1.600000 -v -0.925000 -0.925000 -1.600000 -v 0.160449 -0.127295 -1.107365 -v 0.160449 -0.127295 -1.287365 -v -0.026426 -0.127295 -1.107365 -v -0.026426 -0.127295 -1.287365 -v 0.160449 -0.427295 -1.107365 -v 0.160449 -0.427295 -1.287365 -v -0.026426 -0.427295 -1.107365 -v -0.026426 -0.427295 -1.287365 -v -0.026426 -0.127295 -1.287365 -v -0.026426 -0.127295 -1.107365 -v 0.160449 -0.127295 -1.287365 -v 0.160449 -0.127295 -1.107365 -v 0.160449 -0.427295 -1.287365 -v 0.160449 -0.427295 -1.107365 -v 0.160449 -0.127295 -1.287365 -v 0.160449 -0.127295 -1.107365 -v -0.026426 -0.427295 -1.287365 -v -0.026426 -0.427295 -1.107365 -v 0.160449 -0.427295 -1.287365 -v 0.160449 -0.427295 -1.107365 -v -0.157753 -0.144986 -1.539514 -v -0.157753 -0.144986 -1.637282 -v -0.240677 -0.144986 -1.539514 -v -0.240677 -0.144986 -1.637282 -v -0.157753 -0.328413 -1.539514 -v -0.157753 -0.328413 -1.637282 -v -0.240677 -0.328413 -1.539514 -v -0.240677 -0.328413 -1.637282 -v -0.480538 -0.445573 -1.455033 -v -0.480538 -0.445573 -1.817243 -v -0.732419 -0.445573 -1.455033 -v -0.732419 -0.445573 -1.817243 -v -0.480538 -0.823959 -1.455033 -v -0.480538 -0.823959 -1.685969 -v -0.732419 -0.823959 -1.455033 -v -0.732419 -0.823959 -1.685969 -v -0.157753 -0.144986 -1.539514 -v -0.157753 -0.144986 -1.637282 -v -0.240677 -0.144986 -1.539514 -v -0.240677 -0.144986 -1.637282 -v -0.157753 -0.328413 -1.539514 -v -0.157753 -0.328413 -1.637282 -v -0.240677 -0.328413 -1.539514 -v -0.240677 -0.328413 -1.637282 -v -0.026426 -0.585532 -1.287365 -v -0.026426 -0.585532 -1.107365 -v 0.160449 -0.585532 -1.287365 -v 0.160449 -0.585532 -1.107365 -v 0.160449 -0.885532 -1.287365 -v 0.160449 -0.885532 -1.107365 -v 0.160449 -0.585532 -1.287365 -v 0.160449 -0.585532 -1.107365 -v -0.026426 -0.885532 -1.287365 -v -0.026426 -0.885532 -1.107365 -v 0.160449 -0.885532 -1.287365 -v 0.160449 -0.885532 -1.107365 -v 0.160449 -0.586497 -0.622366 -v 0.160449 -0.586497 -0.802366 -v -0.026426 -0.586497 -0.622366 -v -0.026426 -0.586497 -0.802366 -v 0.160449 -0.886497 -0.802366 -v 0.160449 -0.886497 -0.622366 -v 0.160449 -0.586497 -0.802366 -v 0.160449 -0.586497 -0.622366 -v -0.026426 -0.886497 -0.802366 -v -0.026426 -0.886497 -0.622366 -v 0.160449 -0.886497 -0.802366 -v 0.160449 -0.886497 -0.622366 -v 0.160449 -0.126028 -0.622366 -v 0.160449 -0.126028 -0.802366 -v -0.026426 -0.126028 -0.622366 -v -0.026426 -0.126028 -0.802366 -v 0.160449 -0.426028 -0.802366 -v 0.160449 -0.426028 -0.622366 -v 0.160449 -0.126028 -0.802366 -v 0.160449 -0.126028 -0.622366 -v -0.026426 -0.426028 -0.802366 -v -0.026426 -0.426028 -0.622366 -v 0.160449 -0.426028 -0.802366 -v 0.160449 -0.426028 -0.622366 -v -0.026426 -0.585532 -1.287365 -v -0.026426 -0.585532 -1.107365 -v 0.160449 -0.585532 -1.287365 -v 0.160449 -0.585532 -1.107365 -v 0.160449 -0.885532 -1.287365 -v 0.160449 -0.885532 -1.107365 -v 0.160449 -0.585532 -1.287365 -v 0.160449 -0.585532 -1.107365 -v -0.026426 -0.885532 -1.287365 -v -0.026426 -0.885532 -1.107365 -v 0.160449 -0.885532 -1.287365 -v 0.160449 -0.885532 -1.107365 -v 0.160449 -0.586497 -0.622366 -v 0.160449 -0.586497 -0.802366 -v -0.026426 -0.586497 -0.622366 -v -0.026426 -0.586497 -0.802366 -v 0.160449 -0.886497 -0.802366 -v 0.160449 -0.886497 -0.622366 -v 0.160449 -0.586497 -0.802366 -v 0.160449 -0.586497 -0.622366 -v -0.026426 -0.886497 -0.802366 -v -0.026426 -0.886497 -0.622366 -v 0.160449 -0.886497 -0.802366 -v 0.160449 -0.886497 -0.622366 -v 0.160449 -0.126028 -0.622366 -v 0.160449 -0.126028 -0.802366 -v -0.026426 -0.126028 -0.622366 -v -0.026426 -0.126028 -0.802366 -v 0.160449 -0.426028 -0.802366 -v 0.160449 -0.426028 -0.622366 -v 0.160449 -0.126028 -0.802366 -v 0.160449 -0.126028 -0.622366 -v -0.026426 -0.426028 -0.802366 -v -0.026426 -0.426028 -0.622366 -v 0.160449 -0.426028 -0.802366 -v 0.160449 -0.426028 -0.622366 -v 0.160449 -0.584850 -1.107365 -v -0.026426 -0.584850 -1.107365 -v 0.160449 -0.884850 -1.107365 -v -0.026426 -0.884850 -1.107365 -v 0.160449 -0.127295 -0.622373 -v -0.026426 -0.127295 -0.622373 -v 0.160449 -0.427295 -0.622373 -v -0.026426 -0.427295 -0.622373 -v 0.160449 -0.584850 -0.622373 -v -0.026426 -0.584850 -0.622373 -v 0.160449 -0.884850 -0.622373 -v -0.026426 -0.884850 -0.622373 -vt 0.014847 0.403582 -vt 0.153703 0.694145 -vt 0.014847 0.694145 -vt 0.034115 0.694145 -vt 0.048963 1.000000 -vt 0.034115 1.000000 -vt 0.047359 0.372997 -vt 0.032511 0.067142 -vt 0.047358 0.067142 -vt 0.048963 0.694145 -vt 0.063810 1.000000 -vt 0.048963 1.000000 -vt 0.019268 0.694145 -vt 0.034115 1.000000 -vt 0.019268 1.000000 -vt 0.710478 0.701791 -vt 1.000000 0.694145 -vt 0.992576 0.701791 -vt 1.000000 1.000000 -vt 0.992576 0.992353 -vt 0.703054 1.000000 -vt 0.710478 0.992354 -vt 0.703054 0.694145 -vt 1.000000 0.051849 -vt 0.717901 0.357704 -vt 0.717901 0.051849 -vt 0.047359 0.082435 -vt 0.186214 0.372997 -vt 0.047359 0.372997 -vt 0.186214 0.082435 -vt 0.325069 0.372997 -vt 0.186214 0.372997 -vt 1.000000 1.000000 -vt 1.000000 1.000000 -vt 1.000000 1.000000 -vt 0.703054 0.694145 -vt 0.413541 0.701796 -vt 0.406108 0.694145 -vt 0.703054 1.000000 -vt 0.695640 0.701796 -vt 0.406108 1.000000 -vt 0.695640 0.992358 -vt 0.413541 0.992358 -vt 0.004421 0.885721 -vt 0.002849 0.709438 -vt 0.004421 0.823716 -vt 0.118100 0.779467 -vt 0.115894 0.721754 -vt 0.118100 0.726047 -vt 1.000000 1.000000 -vt 1.000000 1.000000 -vt 0.119844 0.783760 -vt 0.124009 0.890693 -vt 0.124009 0.890693 -vt 0.509125 0.003716 -vt 0.515034 0.113020 -vt 0.509125 0.113020 -vt 0.616064 0.113020 -vt 0.717901 0.000000 -vt 0.717901 0.113020 -vt 1.000000 1.000000 -vt 1.000000 1.000000 -vt 0.119842 0.995708 -vt 0.124009 0.890696 -vt 0.124009 1.000000 -vt 0.067977 0.995708 -vt 0.063810 0.890696 -vt 0.067977 0.890815 -vt 0.063810 1.000000 -vt 0.515034 0.113020 -vt 0.616064 0.000000 -vt 0.616064 0.113020 -vt 0.118100 0.721754 -vt 0.124009 0.783760 -vt 0.118100 0.783760 -vt 0.509125 0.113020 -vt 0.503215 0.003716 -vt 0.509125 0.003716 -vt 0.115815 0.777387 -vt 0.115815 0.723967 -vt 0.431190 0.196713 -vt 0.465497 0.082435 -vt 0.465497 0.372997 -vt 0.465497 0.113020 -vt 0.717901 0.372997 -vt 0.465497 0.372997 -vt 0.717901 0.372997 -vt 0.435802 0.678852 -vt 0.435802 0.372997 -vt 1.000000 0.372997 -vt 0.717901 0.678852 -vt 0.717901 0.372997 -vt 0.435802 0.372997 -vt 0.153703 0.678852 -vt 0.153703 0.372997 -vt 0.717901 0.678852 -vt 0.435802 0.694145 -vt 0.017664 0.372997 -vt 0.002817 0.113020 -vt 0.017664 0.113020 -vt 1.000000 0.357704 -vt 0.717901 0.372997 -vt 0.032511 0.372997 -vt 0.017664 0.372997 -vt 0.138856 0.724730 -vt 0.406108 0.709437 -vt 0.391260 0.724730 -vt 0.406108 1.000000 -vt 0.391260 0.984707 -vt 0.124009 1.000000 -vt 0.138856 0.984707 -vt 0.124009 0.709438 -vt 0.014847 0.694145 -vt 0.000000 0.434168 -vt 0.014847 0.434168 -vt 1.000000 0.678852 -vt 0.717901 0.694145 -vt 0.435802 0.678852 -vt 0.153703 0.694145 -vt 0.004421 0.740023 -vt 0.019268 1.000000 -vt 0.004421 1.000000 -vt 0.316450 0.067652 -vt 0.252222 0.005787 -vt 0.316449 0.005787 -vt 0.483784 0.067652 -vt 0.419557 0.005787 -vt 0.483784 0.005787 -vt 0.419557 0.067652 -vt 0.248111 0.067096 -vt 0.165675 0.015745 -vt 0.248111 0.015745 -vt 0.252222 0.005787 -vt 0.316450 0.067652 -vt 0.316449 0.005787 -vt 0.316449 0.005787 -vt 0.419557 0.067652 -vt 0.419557 0.005787 -vt 0.419557 0.005787 -vt 0.483784 0.067652 -vt 0.483784 0.005787 -vt 0.000000 0.000000 -vt 0.000000 0.000000 -vt 0.000000 0.000000 -vt 0.000000 0.000000 -vt 0.000000 0.000000 -vt 0.000000 0.000000 -vt 0.000000 0.000000 -vt 0.000000 0.000000 -vt 0.525322 0.836366 -vt 0.586878 0.919862 -vt 0.525322 0.919862 -vt 0.552285 0.749140 -vt 0.608723 0.836366 -vt 0.552285 0.836366 -vt 0.586878 0.894429 -vt 0.643316 0.836366 -vt 0.643316 0.894429 -vt 0.520203 0.749140 -vt 0.463765 0.836366 -vt 0.463765 0.749140 -vt 0.463765 0.836366 -vt 0.525322 0.928691 -vt 0.463765 0.928691 -vt 0.892836 0.808021 -vt 0.844939 0.752099 -vt 0.892836 0.752099 -vt 0.884262 0.808021 -vt 0.827791 0.912939 -vt 0.827791 0.808021 -vt 0.940733 0.808021 -vt 0.892836 0.752099 -vt 0.940733 0.752099 -vt 0.884262 0.912939 -vt 0.940733 0.808021 -vt 0.940733 0.912939 -vt 0.779894 0.808021 -vt 0.827791 0.912939 -vt 0.779894 0.912939 -vt 0.252222 0.005787 -vt 0.316450 0.067652 -vt 0.316449 0.005787 -vt 0.316449 0.005787 -vt 0.419557 0.067652 -vt 0.419557 0.005787 -vt 0.419557 0.005787 -vt 0.483784 0.067652 -vt 0.483784 0.005787 -vt 0.252222 0.005787 -vt 0.316450 0.067652 -vt 0.316449 0.005787 -vt 0.316449 0.005787 -vt 0.419557 0.067652 -vt 0.419557 0.005787 -vt 0.419557 0.005787 -vt 0.483784 0.067652 -vt 0.483784 0.005787 -vt 0.252222 0.005787 -vt 0.316450 0.067652 -vt 0.316449 0.005787 -vt 0.316449 0.005787 -vt 0.419557 0.067652 -vt 0.419557 0.005787 -vt 0.419557 0.005787 -vt 0.483784 0.067652 -vt 0.483784 0.005787 -vt 0.316450 0.067652 -vt 0.252222 0.005787 -vt 0.316449 0.005787 -vt 0.419557 0.067652 -vt 0.316449 0.005787 -vt 0.419557 0.005787 -vt 0.483784 0.067652 -vt 0.419557 0.005787 -vt 0.483784 0.005787 -vt 0.316450 0.067652 -vt 0.252222 0.005787 -vt 0.316449 0.005787 -vt 0.419557 0.067652 -vt 0.316449 0.005787 -vt 0.419557 0.005787 -vt 0.483784 0.067652 -vt 0.419557 0.005787 -vt 0.483784 0.005787 -vt 0.316450 0.067652 -vt 0.252222 0.005787 -vt 0.316449 0.005787 -vt 0.419557 0.067652 -vt 0.316449 0.005787 -vt 0.419557 0.005787 -vt 0.483784 0.067652 -vt 0.419557 0.005787 -vt 0.483784 0.005787 -vt 0.248111 0.067096 -vt 0.165675 0.015745 -vt 0.248111 0.015745 -vt 0.248111 0.067096 -vt 0.165675 0.015745 -vt 0.248111 0.015745 -vt 0.248111 0.067096 -vt 0.165675 0.015745 -vt 0.248111 0.015745 -vt 0.153703 0.403582 -vt 0.048963 0.694145 -vt 0.032511 0.372997 -vt 0.063810 0.694145 -vt 0.034115 0.694145 -vt 0.186214 0.082435 -vt 0.325069 0.082435 -vt 0.002849 1.000000 -vt 0.115894 0.783760 -vt 1.000000 1.000000 -vt 0.119840 0.890696 -vt 0.067976 0.890695 -vt 0.067979 0.783760 -vt 0.063810 0.890691 -vt 0.063810 0.890691 -vt 0.515034 0.003716 -vt 0.616064 0.000000 -vt 0.119842 0.891647 -vt 0.515034 0.000000 -vt 0.124009 0.721754 -vt 0.503215 0.113020 -vt 0.326641 0.372997 -vt 0.431190 0.258718 -vt 0.325069 0.258718 -vt 0.325069 0.196713 -vt 0.326641 0.082435 -vt 0.717901 0.113020 -vt 0.717901 0.694145 -vt 0.002817 0.372997 -vt 1.000000 0.372997 -vt 0.032511 0.113020 -vt 0.000000 0.694145 -vt 1.000000 0.694145 -vt 0.435802 0.694145 -vt 0.019268 0.740023 -vt 0.252222 0.067652 -vt 0.165675 0.067096 -vt 0.252222 0.067652 -vt 0.316450 0.067652 -vt 0.419557 0.067652 -vt 0.586878 0.836366 -vt 0.640804 0.749140 -vt 0.586878 0.836366 -vt 0.552285 0.836366 -vt 0.844939 0.808021 -vt 0.884262 0.912939 -vt 0.892836 0.808021 -vt 0.884262 0.808021 -vt 0.827791 0.808021 -vt 0.252222 0.067652 -vt 0.316450 0.067652 -vt 0.419557 0.067652 -vt 0.252222 0.067652 -vt 0.316450 0.067652 -vt 0.419557 0.067652 -vt 0.252222 0.067652 -vt 0.316450 0.067652 -vt 0.419557 0.067652 -vt 0.252222 0.067652 -vt 0.316450 0.067652 -vt 0.419557 0.067652 -vt 0.252222 0.067652 -vt 0.316450 0.067652 -vt 0.419557 0.067652 -vt 0.252222 0.067652 -vt 0.316450 0.067652 -vt 0.419557 0.067652 -vt 0.165675 0.067096 -vt 0.165675 0.067096 -vt 0.165675 0.067096 -vn 0.0000 -1.0000 0.0000 -vn -1.0000 0.0000 0.0000 -vn 1.0000 0.0000 0.0000 -vn 0.0000 1.0000 0.0000 -vn 0.0000 0.0000 -1.0000 -vn 0.0000 0.0000 1.0000 -vn 0.0000 0.6720 -0.7406 -vn 0.6720 0.0000 -0.7406 -vn 0.0000 -0.6720 -0.7406 -vn -0.6720 0.0000 -0.7406 -vn 0.7071 0.0000 -0.7071 -vn 0.0000 -0.3278 -0.9448 -vn -0.0178 0.4677 -0.8837 -vn -0.0123 0.0000 -0.9999 -vn -0.0201 0.0156 -0.9997 -vn -0.0109 -0.4677 -0.8838 -usemtl Material.001 -s off -f 8/1/1 41/2/1 42/3/1 -f 3/4/2 12/5/2 4/6/2 -f 2/7/3 10/8/3 1/9/3 -f 4/10/1 11/11/1 2/12/1 -f 1/13/4 9/14/4 3/15/4 -f 7/16/5 10/17/5 45/18/5 -f 45/18/5 11/19/5 42/20/5 -f 42/20/5 12/21/5 8/22/5 -f 8/22/5 9/23/5 7/16/5 -f 22/24/1 55/25/1 21/26/1 -f 45/27/4 13/28/4 7/29/4 -f 7/30/2 14/31/2 8/32/2 -f 43/33/6 26/34/6 23/35/6 -f 16/36/7 19/37/7 15/38/7 -f 17/39/8 20/40/8 16/36/8 -f 18/41/9 21/42/9 17/39/9 -f 15/38/10 22/43/10 18/41/10 -f 47/44/2 42/45/2 44/46/2 -f 5/47/3 44/48/3 6/49/3 -f 48/50/6 25/51/6 26/34/6 -f 27/52/6 25/53/6 47/54/6 -f 25/55/4 34/56/4 26/57/4 -f 30/58/1 37/59/1 27/60/1 -f 44/61/6 23/35/6 24/62/6 -f 35/63/3 32/64/3 31/65/3 -f 38/66/3 33/67/3 37/68/3 -f 35/63/3 34/69/3 38/66/3 -f 28/70/4 35/71/4 29/72/4 -f 26/73/5 31/74/5 23/75/5 -f 23/76/1 32/77/1 24/78/1 -f 6/49/11 39/79/11 40/80/11 -f 43/81/3 41/82/3 46/83/3 -f 51/84/5 49/85/5 50/86/5 -f 20/87/4 53/88/4 19/89/4 -f 19/90/2 56/91/2 22/92/2 -f 21/93/3 54/94/3 20/95/3 -f 54/96/4 57/97/4 53/88/4 -f 52/98/3 61/99/3 49/100/3 -f 56/101/1 59/102/1 55/25/1 -f 49/100/1 62/103/1 50/104/1 -f 61/105/5 58/106/5 62/107/5 -f 62/107/5 59/108/5 63/109/5 -f 63/109/5 60/110/5 64/111/5 -f 64/111/5 57/112/5 61/105/5 -f 50/113/2 63/114/2 51/115/2 -f 53/116/2 60/117/2 56/91/2 -f 55/118/3 58/119/3 54/94/3 -f 51/120/4 64/121/4 52/122/4 -f 66/123/4 67/124/4 65/125/4 -f 72/126/1 69/127/1 71/128/1 -f 70/129/3 65/125/3 69/127/3 -f 65/130/5 71/131/5 67/132/5 -f 74/133/1 75/134/1 76/135/1 -f 80/136/2 77/137/2 78/138/2 -f 84/139/4 81/140/4 82/141/4 -f 86/142/4 87/143/4 85/144/4 -f 88/145/2 91/146/2 87/143/2 -f 92/147/1 89/148/1 91/146/1 -f 90/149/3 85/144/3 89/148/3 -f 88/145/5 90/149/5 92/147/5 -f 94/150/4 95/151/4 93/152/4 -f 95/153/2 100/154/2 99/155/2 -f 100/156/1 97/157/1 99/158/1 -f 98/159/3 93/160/3 97/161/3 -f 96/162/12 98/163/12 100/164/12 -f 102/165/4 103/166/4 101/167/4 -f 104/168/2 107/169/2 103/170/2 -f 108/171/1 105/172/1 107/173/1 -f 106/174/3 101/175/3 105/176/3 -f 104/177/5 106/178/5 108/179/5 -f 110/180/1 111/181/1 112/182/1 -f 116/183/2 113/184/2 114/185/2 -f 120/186/4 117/187/4 118/188/4 -f 123/189/1 122/190/1 121/191/1 -f 128/192/2 125/193/2 126/194/2 -f 132/195/4 129/196/4 130/197/4 -f 135/198/1 134/199/1 133/200/1 -f 140/201/2 137/202/2 138/203/2 -f 144/204/4 141/205/4 142/206/4 -f 147/207/4 146/208/4 148/209/4 -f 149/210/3 152/211/3 150/212/3 -f 153/213/1 156/214/1 154/215/1 -f 158/216/4 159/217/4 157/218/4 -f 161/219/3 164/220/3 162/221/3 -f 165/222/1 168/223/1 166/224/1 -f 170/225/4 171/226/4 169/227/4 -f 173/228/3 176/229/3 174/230/3 -f 177/231/1 180/232/1 178/233/1 -f 181/234/5 184/235/5 182/236/5 -f 185/237/5 188/238/5 186/239/5 -f 189/240/5 192/241/5 190/242/5 -f 8/1/1 14/243/1 41/2/1 -f 3/4/2 9/244/2 12/5/2 -f 2/7/3 11/245/3 10/8/3 -f 4/10/1 12/246/1 11/11/1 -f 1/13/4 10/247/4 9/14/4 -f 7/16/5 9/23/5 10/17/5 -f 45/18/5 10/17/5 11/19/5 -f 42/20/5 11/19/5 12/21/5 -f 8/22/5 12/21/5 9/23/5 -f 22/24/1 56/101/1 55/25/1 -f 45/27/4 46/248/4 13/28/4 -f 7/30/2 13/249/2 14/31/2 -f 43/33/6 48/50/6 26/34/6 -f 16/36/7 20/40/7 19/37/7 -f 17/39/8 21/42/8 20/40/8 -f 18/41/9 22/43/9 21/42/9 -f 15/38/10 19/37/10 22/43/10 -f 47/44/2 45/250/2 42/45/2 -f 5/47/3 47/251/3 44/48/3 -f 48/50/6 47/252/6 25/51/6 -f 47/54/13 5/253/13 27/52/13 -f 5/253/14 6/254/14 28/255/14 -f 44/256/6 24/257/6 28/255/6 -f 5/253/15 28/255/15 27/52/15 -f 6/254/16 44/256/16 28/255/16 -f 25/55/4 33/258/4 34/56/4 -f 30/58/1 38/259/1 37/59/1 -f 44/61/6 43/33/6 23/35/6 -f 35/63/3 36/260/3 32/64/3 -f 38/66/3 34/69/3 33/67/3 -f 35/63/3 31/65/3 34/69/3 -f 28/70/4 36/261/4 35/71/4 -f 26/73/5 34/262/5 31/74/5 -f 23/76/1 31/263/1 32/77/1 -f 6/49/11 5/47/11 39/79/11 -f 46/83/3 45/264/3 48/265/3 -f 45/264/3 47/266/3 48/265/3 -f 44/267/3 42/268/3 43/81/3 -f 42/268/3 41/82/3 43/81/3 -f 46/83/3 48/265/3 43/81/3 -f 51/84/5 52/269/5 49/85/5 -f 20/87/4 54/96/4 53/88/4 -f 19/90/2 53/116/2 56/91/2 -f 21/93/3 55/118/3 54/94/3 -f 54/96/4 58/270/4 57/97/4 -f 52/98/3 64/271/3 61/99/3 -f 56/101/1 60/272/1 59/102/1 -f 49/100/1 61/273/1 62/103/1 -f 61/105/5 57/112/5 58/106/5 -f 62/107/5 58/106/5 59/108/5 -f 63/109/5 59/108/5 60/110/5 -f 64/111/5 60/110/5 57/112/5 -f 50/113/2 62/274/2 63/114/2 -f 53/116/2 57/275/2 60/117/2 -f 55/118/3 59/276/3 58/119/3 -f 51/120/4 63/277/4 64/121/4 -f 66/123/4 68/278/4 67/124/4 -f 72/126/1 70/129/1 69/127/1 -f 70/129/3 66/123/3 65/125/3 -f 65/130/5 69/279/5 71/131/5 -f 74/133/1 73/280/1 75/134/1 -f 80/136/2 79/281/2 77/137/2 -f 84/139/4 83/282/4 81/140/4 -f 86/142/4 88/145/4 87/143/4 -f 88/145/2 92/147/2 91/146/2 -f 92/147/1 90/149/1 89/148/1 -f 90/149/3 86/142/3 85/144/3 -f 88/145/5 86/142/5 90/149/5 -f 94/150/4 96/283/4 95/151/4 -f 95/153/2 96/284/2 100/154/2 -f 100/156/1 98/285/1 97/157/1 -f 98/159/3 94/286/3 93/160/3 -f 96/162/12 94/150/12 98/163/12 -f 102/165/4 104/287/4 103/166/4 -f 104/168/2 108/288/2 107/169/2 -f 108/171/1 106/289/1 105/172/1 -f 106/174/3 102/290/3 101/175/3 -f 104/177/5 102/291/5 106/178/5 -f 110/180/1 109/292/1 111/181/1 -f 116/183/2 115/293/2 113/184/2 -f 120/186/4 119/294/4 117/187/4 -f 123/189/1 124/295/1 122/190/1 -f 128/192/2 127/296/2 125/193/2 -f 132/195/4 131/297/4 129/196/4 -f 135/198/1 136/298/1 134/199/1 -f 140/201/2 139/299/2 137/202/2 -f 144/204/4 143/300/4 141/205/4 -f 147/207/4 145/301/4 146/208/4 -f 149/210/3 151/302/3 152/211/3 -f 153/213/1 155/303/1 156/214/1 -f 158/216/4 160/304/4 159/217/4 -f 161/219/3 163/305/3 164/220/3 -f 165/222/1 167/306/1 168/223/1 -f 170/225/4 172/307/4 171/226/4 -f 173/228/3 175/308/3 176/229/3 -f 177/231/1 179/309/1 180/232/1 -f 181/234/5 183/310/5 184/235/5 -f 185/237/5 187/311/5 188/238/5 -f 189/240/5 191/312/5 192/241/5 diff --git a/Videos/CarCrimeCity/Part2/assets/buildings/udxs_building1.png b/Videos/CarCrimeCity/Part2/assets/buildings/udxs_building1.png deleted file mode 100644 index 746be5b..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/buildings/udxs_building1.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/buildings/unit_building.blend b/Videos/CarCrimeCity/Part2/assets/buildings/unit_building.blend deleted file mode 100644 index bcc3b6c..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/buildings/unit_building.blend and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/buildings/unit_building.blend1 b/Videos/CarCrimeCity/Part2/assets/buildings/unit_building.blend1 deleted file mode 100644 index f0ef2f6..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/buildings/unit_building.blend1 and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/buildings/unit_building.obj b/Videos/CarCrimeCity/Part2/assets/buildings/unit_building.obj deleted file mode 100644 index 3683256..0000000 --- a/Videos/CarCrimeCity/Part2/assets/buildings/unit_building.obj +++ /dev/null @@ -1,26 +0,0 @@ -# Blender v2.79 (sub 0) OBJ File: 'unit_building.blend' -# www.blender.org -v 1.0000 1.000 -0.000 -v 1.0000 1.0 -0.50 -v 0.0000 1.00 -0.000 -v 0.0000 1.000 -0.5 -v 1.0 0.00 0.000 -v 1.0 0.00000 -0.5 -v -0.000081 0.004528 0.004407 -v -0.000081 0.000101 -0.495573 -vn 0.0002 1.0000 -0.0089 -vn -1.0000 0.0002 -0.0000 -vn -0.0002 -1.0000 0.0089 -vn 1.0000 -0.0002 0.0000 -vn -0.0000 -0.0089 -1.0000 -s off -f 2//1 3//1 1//1 -f 4//2 7//2 3//2 -f 8//3 5//3 7//3 -f 6//4 1//4 5//4 -f 4//5 6//5 8//5 -f 2//1 4//1 3//1 -f 4//2 8//2 7//2 -f 8//3 6//3 5//3 -f 6//4 2//4 1//4 -f 4//5 2//5 6//5 diff --git a/Videos/CarCrimeCity/Part2/assets/cities/example1.city b/Videos/CarCrimeCity/Part2/assets/cities/example1.city deleted file mode 100644 index 47dfb0b..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/cities/example1.city and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/config.lua b/Videos/CarCrimeCity/Part2/assets/config.lua deleted file mode 100644 index bf19e0e..0000000 --- a/Videos/CarCrimeCity/Part2/assets/config.lua +++ /dev/null @@ -1,50 +0,0 @@ - - --- Size of pixel -PixelWidth = 2 -PixelHeight = 2 - --- Size of display window in pixels -ScreenWidth = 768 -ScreenHeight = 480 ---ScreenWidth = 384 ---ScreenHeight = 240 - -FullScreen = false - --- Default city parameters -DefaultMapWidth = 64 -DefaultMapHeight = 32 ---DefaultCityFile = "assets/cities/example1.city" - - --- Textures used by various game systems -Textures = {} -Textures[1] = {"Grass", "assets/system/grass1.png"} -Textures[2] = {"AllRoads", "assets/system/roads4.png"} -Textures[3] = {"Water", "assets/system/water1.png"} -Textures[4] = {"Clouds", "assets/system/clouds2.png"} -Textures[5] = {"WaterSide", "assets/system/waterside1.png"} -Textures[6] = {"Smoke", "assets/system/skidsmoke1.png"} - --- Buildings -Buildings = {} -Buildings[1] = {"javidx9", "UnitBuilding_1", "assets/buildings/unit_building.obj", "", - 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0} -Buildings[2] = {"UDXS", "Apartments_1", "assets/buildings/udxs_building1.obj", "assets/buildings/udxs_building1.png", - 0.0, 0.0, 0.0, 1.0, 1.0, 0.5, 1.0, 1.0, 0.0} - -Vehicles = {} -Vehicles[1] = {"JustinRM", "Sedan", "assets/vehicles/CarCrime_Sedan.obj", "assets/vehicles/CarTex_256.png", - 0.0, 0.0, 1.5708, 0.05, 0.05, 0.05, 0.0, 0.0, 0.0} -Vehicles[2] = {"JustinRM", "SUV", "assets/vehicles/CarCrime_SUV.obj", "assets/vehicles/CarTex_256.png", - 0.0, 0.0, 0.0, 0.05, 0.05, 0.05, 0.0, 0.0, 0.0} -Vehicles[3] = {"JustinRM", "TruckCab", "assets/vehicles/CarCrime_Truck_Cab.obj", "assets/vehicles/CarTex_256.png", - 0.0, 0.0, 0.0, 0.05, 0.05, 0.05, 0.0, 0.0, 0.0} -Vehicles[4] = {"JustinRM", "TruckTrailer", "assets/vehicles/CarCrime_Truck_Trailer.obj", "assets/vehicles/CarTex_256.png", - 0.0, 0.0, 0.0, 0.05, 0.05, 0.05, 0.0, 0.0, 0.0} -Vehicles[5] = {"JustinRM", "UTE", "assets/vehicles/CarCrime_Ute.obj", "assets/vehicles/CarTex_256.png", - 0.0, 0.0, 0.0, 0.05, 0.05, 0.05, 0.0, 0.0, 0.0} -Vehicles[6] = {"JustinRM", "Wagon", "assets/vehicles/CarCrime_Wahon.obj", "assets/vehicles/CarTex_256.png", - 0.0, 0.0, 0.0, 0.05, 0.05, 0.05, 0.0, 0.0, 0.0} - diff --git a/Videos/CarCrimeCity/Part2/assets/system/car_top.png b/Videos/CarCrimeCity/Part2/assets/system/car_top.png deleted file mode 100644 index ad89ae4..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/system/car_top.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/system/car_top3.png b/Videos/CarCrimeCity/Part2/assets/system/car_top3.png deleted file mode 100644 index 25db6a7..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/system/car_top3.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/system/ccctitle1.png b/Videos/CarCrimeCity/Part2/assets/system/ccctitle1.png deleted file mode 100644 index fd02a35..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/system/ccctitle1.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/system/clouds1.png b/Videos/CarCrimeCity/Part2/assets/system/clouds1.png deleted file mode 100644 index e0f20f4..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/system/clouds1.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/system/clouds2.png b/Videos/CarCrimeCity/Part2/assets/system/clouds2.png deleted file mode 100644 index 400f99a..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/system/clouds2.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/system/grass1.png b/Videos/CarCrimeCity/Part2/assets/system/grass1.png deleted file mode 100644 index bb1c9bf..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/system/grass1.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/system/roads1.png b/Videos/CarCrimeCity/Part2/assets/system/roads1.png deleted file mode 100644 index 24dce8c..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/system/roads1.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/system/roads2.png b/Videos/CarCrimeCity/Part2/assets/system/roads2.png deleted file mode 100644 index e2b6231..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/system/roads2.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/system/roads3.png b/Videos/CarCrimeCity/Part2/assets/system/roads3.png deleted file mode 100644 index 95b8752..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/system/roads3.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/system/roads4.png b/Videos/CarCrimeCity/Part2/assets/system/roads4.png deleted file mode 100644 index 04d56a4..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/system/roads4.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/system/skidsmoke1.png b/Videos/CarCrimeCity/Part2/assets/system/skidsmoke1.png deleted file mode 100644 index 78c9b3d..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/system/skidsmoke1.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/system/water1.png b/Videos/CarCrimeCity/Part2/assets/system/water1.png deleted file mode 100644 index 9194ae0..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/system/water1.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/system/waterside1.png b/Videos/CarCrimeCity/Part2/assets/system/waterside1.png deleted file mode 100644 index 9cb1f44..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/system/waterside1.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_SUV.obj b/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_SUV.obj deleted file mode 100644 index 0952689..0000000 --- a/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_SUV.obj +++ /dev/null @@ -1,121 +0,0 @@ -# Blender v2.69 (sub 0) OBJ File: 'Car002.blend' -# www.blender.org -v 0.600000 -0.400000 -1.700000 -v 0.600000 1.700000 -1.700000 -v -0.600000 -0.400000 -1.700000 -v -0.600000 1.700000 -1.700000 -v -0.800000 2.000000 -1.100000 -v 0.800000 2.000000 -1.100000 -v -0.800000 2.000000 -1.100000 -v 0.800000 2.000000 -1.100000 -v -0.800000 -1.000000 -0.950000 -v 0.800000 -1.000000 -0.950000 -v -0.800000 -2.000000 -0.900000 -v 0.800000 -2.000000 -0.900000 -v -0.800000 2.000000 -0.400000 -v 0.800000 2.000000 -0.400000 -v -0.800000 -2.000000 -0.400000 -v 0.800000 -2.000000 -0.400000 -v 0.800000 -2.000000 -0.400000 -v 0.800000 2.000000 -0.400000 -v 0.800000 -2.000000 -0.900000 -v 0.800000 2.000000 -1.100000 -v -0.800000 -2.000000 -0.900000 -v -0.800000 2.000000 -1.100000 -v -0.800000 -2.000000 -0.400000 -v -0.800000 2.000000 -0.400000 -v 0.780000 1.200000 -0.400000 -v 0.780000 1.500000 -0.400000 -v 0.780000 1.400000 0.000000 -v 0.780000 1.000000 0.000000 -v 0.780000 0.900000 -0.400000 -v 0.780000 -1.100000 -0.400000 -v 0.780000 -0.800000 -0.400000 -v 0.780000 -0.900000 0.000000 -v 0.780000 -1.300000 0.000000 -v 0.780000 -1.400000 -0.400000 -v -0.780000 -1.100000 -0.400000 -v -0.780000 -1.400000 -0.400000 -v -0.780000 -1.300000 0.000000 -v -0.780000 -0.900000 0.000000 -v -0.780000 -0.800000 -0.400000 -v -0.780000 1.200000 -0.400000 -v -0.780000 0.900000 -0.400000 -v -0.780000 1.000000 0.000000 -v -0.780000 1.400000 0.000000 -v -0.780000 1.500000 -0.400000 -vt 0.564792 0.689981 -vt 0.564792 0.953949 -vt 0.338554 0.953949 -vt 0.338554 0.689981 -vt 0.334296 0.692438 -vt 0.334296 0.954445 -vt 0.203294 0.986197 -vt 0.203294 0.656186 -vt 0.695616 0.984433 -vt 0.572654 0.959219 -vt 0.695616 0.657719 -vt 0.572795 0.683358 -vt 0.941945 0.999442 -vt 0.694306 0.999442 -vt 0.941945 0.647349 -vt 0.694306 0.647349 -vt 0.070499 0.643570 -vt 0.070499 0.998147 -vt 0.003817 0.998147 -vt 0.003817 0.643570 -vt 0.997239 0.998410 -vt 0.940308 0.998410 -vt 0.997239 0.647262 -vt 0.940308 0.647262 -vt 0.331416 0.690927 -vt 0.238667 0.577426 -vt 0.563274 0.690927 -vt 0.735343 0.574985 -vt 0.970266 0.522520 -vt 0.962942 0.572543 -vt 0.072079 0.572543 -vt 0.079403 0.522520 -vt 0.744362 0.446044 -vt 0.780351 0.385565 -vt 0.817830 0.446044 -vt 0.854309 0.385565 -vt 0.891299 0.446044 -vt 0.743883 0.446331 -vt 0.779872 0.385852 -vt 0.817351 0.446331 -vt 0.853830 0.385852 -vt 0.890820 0.446331 -s off -f 1/1 3/2 4/3 -f 2/4 1/1 4/3 -f 2/5 4/6 5/7 -f 5/7 6/8 2/5 -f 9/9 3/10 10/11 -f 3/10 1/12 10/11 -f 11/13 9/14 12/15 -f 10/16 12/15 9/14 -f 8/17 7/18 13/19 -f 13/19 14/20 8/17 -f 15/21 11/22 16/23 -f 12/24 16/23 11/22 -f 2/25 6/26 1/27 -f 10/28 1/27 6/26 -f 4/25 3/27 5/26 -f 9/28 5/26 3/27 -f 17/29 19/30 20/31 -f 18/32 17/29 20/31 -f 21/30 23/29 24/32 -f 22/31 21/30 24/32 -f 26/33 27/34 25/35 -f 27/34 28/36 25/35 -f 28/36 29/37 25/35 -f 31/38 32/39 30/40 -f 32/39 33/41 30/40 -f 33/41 34/42 30/40 -f 36/42 37/41 35/40 -f 37/41 38/39 35/40 -f 38/39 39/38 35/40 -f 41/37 42/36 40/35 -f 42/36 43/34 40/35 -f 43/34 44/33 40/35 diff --git a/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Sedan.obj b/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Sedan.obj deleted file mode 100644 index 77daa43..0000000 --- a/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Sedan.obj +++ /dev/null @@ -1,127 +0,0 @@ -# Blender v2.69 (sub 0) OBJ File: 'Car002.blend' -# www.blender.org -v 0.600000 -0.200000 -1.100000 -v 0.600000 1.000000 -1.100000 -v -0.600000 -0.200000 -1.100000 -v -0.600000 1.000000 -1.100000 -v -0.800000 1.400000 -0.700000 -v 0.800000 1.400000 -0.700000 -v -0.800000 2.000000 -0.700000 -v 0.800000 2.000000 -0.700000 -v -0.800000 -1.000000 -0.700000 -v 0.800000 -1.000000 -0.700000 -v -0.800000 -2.000000 -0.700000 -v 0.800000 -2.000000 -0.700000 -v -0.800000 2.000000 -0.300000 -v 0.800000 2.000000 -0.300000 -v -0.800000 -2.000000 -0.300000 -v 0.800000 -2.000000 -0.300000 -v 0.800000 -2.000000 -0.300000 -v 0.800000 2.000000 -0.300000 -v 0.800000 -2.000000 -0.700000 -v 0.800000 2.000000 -0.700000 -v -0.800000 -2.000000 -0.700000 -v -0.800000 2.000000 -0.700000 -v -0.800000 -2.000000 -0.300000 -v -0.800000 2.000000 -0.300000 -v 0.780000 1.200000 -0.300000 -v 0.780000 1.500000 -0.300000 -v 0.780000 1.400000 0.000000 -v 0.780000 1.000000 0.000000 -v 0.780000 0.900000 -0.300000 -v 0.780000 -1.100000 -0.300000 -v 0.780000 -0.800000 -0.300000 -v 0.780000 -0.900000 0.000000 -v 0.780000 -1.300000 0.000000 -v 0.780000 -1.400000 -0.300000 -v -0.780000 -1.100000 -0.300000 -v -0.780000 -1.400000 -0.300000 -v -0.780000 -1.300000 0.000000 -v -0.780000 -0.900000 0.000000 -v -0.780000 -0.800000 -0.300000 -v -0.780000 1.200000 -0.300000 -v -0.780000 0.900000 -0.300000 -v -0.780000 1.000000 0.000000 -v -0.780000 1.400000 0.000000 -v -0.780000 1.500000 -0.300000 -vt 0.564792 0.689981 -vt 0.564792 0.953949 -vt 0.338554 0.953949 -vt 0.338554 0.689981 -vt 0.334296 0.692438 -vt 0.334296 0.954445 -vt 0.203294 0.986197 -vt 0.203294 0.656186 -vt 0.203326 0.657931 -vt 0.203326 0.986286 -vt 0.080997 0.986286 -vt 0.080997 0.657931 -vt 0.695616 0.984433 -vt 0.572654 0.959219 -vt 0.695616 0.657719 -vt 0.572795 0.683358 -vt 0.941945 0.999442 -vt 0.694306 0.999442 -vt 0.941945 0.647349 -vt 0.694306 0.647349 -vt 0.070499 0.643570 -vt 0.070499 0.998147 -vt 0.003817 0.998147 -vt 0.003817 0.643570 -vt 0.997239 0.998410 -vt 0.940308 0.998410 -vt 0.997239 0.647262 -vt 0.940308 0.647262 -vt 0.331416 0.690927 -vt 0.238667 0.577426 -vt 0.563274 0.690927 -vt 0.735343 0.574985 -vt 0.970266 0.522520 -vt 0.962942 0.572543 -vt 0.072079 0.572543 -vt 0.079403 0.522520 -vt 0.744362 0.446044 -vt 0.780351 0.385565 -vt 0.817830 0.446044 -vt 0.854309 0.385565 -vt 0.891299 0.446044 -vt 0.743883 0.446331 -vt 0.779872 0.385852 -vt 0.817351 0.446331 -vt 0.853830 0.385852 -vt 0.890820 0.446331 -s off -f 1/1 3/2 4/3 -f 2/4 1/1 4/3 -f 2/5 4/6 5/7 -f 5/7 6/8 2/5 -f 6/9 5/10 7/11 -f 7/11 8/12 6/9 -f 9/13 3/14 10/15 -f 3/14 1/16 10/15 -f 11/17 9/18 12/19 -f 10/20 12/19 9/18 -f 8/21 7/22 13/23 -f 13/23 14/24 8/21 -f 15/25 11/26 16/27 -f 12/28 16/27 11/26 -f 2/29 6/30 1/31 -f 10/32 1/31 6/30 -f 4/29 3/31 5/30 -f 9/32 5/30 3/31 -f 17/33 19/34 20/35 -f 18/36 17/33 20/35 -f 21/34 23/33 24/36 -f 22/35 21/34 24/36 -f 26/37 27/38 25/39 -f 27/38 28/40 25/39 -f 28/40 29/41 25/39 -f 31/42 32/43 30/44 -f 32/43 33/45 30/44 -f 33/45 34/46 30/44 -f 36/46 37/45 35/44 -f 37/45 38/43 35/44 -f 38/43 39/42 35/44 -f 41/41 42/40 40/39 -f 42/40 43/38 40/39 -f 43/38 44/37 40/39 diff --git a/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Truck_Cab.obj b/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Truck_Cab.obj deleted file mode 100644 index f4806a9..0000000 --- a/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Truck_Cab.obj +++ /dev/null @@ -1,137 +0,0 @@ -# Blender v2.69 (sub 0) OBJ File: 'Car002.blend' -# www.blender.org -v 0.600000 -1.900000 -1.500000 -v 0.600000 -1.000000 -1.500000 -v -0.600000 -1.900000 -1.500000 -v -0.600000 -1.000000 -1.500000 -v -0.800000 -0.900000 -0.700000 -v 0.800000 -0.900000 -0.700000 -v -0.800000 0.600000 -0.700000 -v 0.800000 0.600000 -0.700000 -v -0.800000 -2.400000 -0.700000 -v 0.800000 -2.400000 -0.700000 -v -0.800000 -2.400000 -0.700000 -v 0.800000 -2.400000 -0.700000 -v -0.800000 0.600000 -0.300000 -v 0.800000 0.600000 -0.300000 -v -0.800000 -2.400000 -0.300000 -v 0.800000 -2.400000 -0.300000 -v 0.800000 -2.400000 -0.300000 -v 0.800000 0.600000 -0.300000 -v 0.800000 -2.400000 -0.700000 -v 0.800000 0.600000 -0.700000 -v -0.800000 -2.400000 -0.700000 -v -0.800000 0.600000 -0.700000 -v -0.800000 -2.400000 -0.300000 -v -0.800000 0.600000 -0.300000 -v 0.780000 0.100000 -0.300000 -v 0.780000 0.400000 -0.300000 -v 0.780000 0.300000 0.000000 -v 0.780000 -0.100000 0.000000 -v 0.780000 -0.200000 -0.300000 -v 0.780000 -1.900000 -0.300000 -v 0.780000 -1.600000 -0.300000 -v 0.780000 -1.700000 0.000000 -v 0.780000 -2.100000 0.000000 -v 0.780000 -2.200000 -0.300000 -v -0.780000 -1.900000 -0.300000 -v -0.780000 -2.200000 -0.300000 -v -0.780000 -2.100000 0.000000 -v -0.780000 -1.700000 0.000000 -v -0.780000 -1.600000 -0.300000 -v -0.780000 0.100000 -0.300000 -v -0.780000 -0.200000 -0.300000 -v -0.780000 -0.100000 0.000000 -v -0.780000 0.300000 0.000000 -v -0.780000 0.400000 -0.300000 -v 0.780000 -0.600000 -0.300000 -v 0.780000 -0.300000 -0.300000 -v 0.780000 -0.400000 0.000000 -v 0.780000 -0.800000 0.000000 -v 0.780000 -0.900000 -0.300000 -v -0.780000 -0.600000 -0.300000 -v -0.780000 -0.900000 -0.300000 -v -0.780000 -0.800000 0.000000 -v -0.780000 -0.400000 0.000000 -v -0.780000 -0.300000 -0.300000 -vt 0.564792 0.689981 -vt 0.564792 0.953949 -vt 0.338554 0.953949 -vt 0.338554 0.689981 -vt 0.334296 0.692438 -vt 0.334296 0.954445 -vt 0.203294 0.986197 -vt 0.203294 0.656186 -vt 0.695616 0.984433 -vt 0.572654 0.959219 -vt 0.695616 0.657719 -vt 0.572795 0.683358 -vt 0.070499 0.643570 -vt 0.070499 0.998147 -vt 0.003817 0.998147 -vt 0.003817 0.643570 -vt 0.997239 0.998410 -vt 0.940308 0.998410 -vt 0.997239 0.647262 -vt 0.940308 0.647262 -vt 0.471796 0.690927 -vt 0.487691 0.573764 -vt 0.563274 0.690927 -vt 0.735343 0.574985 -vt 0.970266 0.522520 -vt 0.962942 0.572543 -vt 0.072079 0.572543 -vt 0.079403 0.522520 -vt 0.744362 0.446044 -vt 0.780351 0.385565 -vt 0.817830 0.446044 -vt 0.854309 0.385565 -vt 0.891299 0.446044 -vt 0.743883 0.446331 -vt 0.779872 0.385852 -vt 0.817351 0.446331 -vt 0.853830 0.385852 -vt 0.890820 0.446331 -vt 0.122341 0.504785 -vt 0.003867 0.504785 -vt 0.122341 0.378413 -vt 0.003867 0.378413 -s off -f 1/1 3/2 4/3 -f 2/4 1/1 4/3 -f 2/5 4/6 5/7 -f 5/7 6/8 2/5 -f 9/9 3/10 10/11 -f 3/10 1/12 10/11 -f 8/13 7/14 13/15 -f 13/15 14/16 8/13 -f 15/17 11/18 16/19 -f 12/20 16/19 11/18 -f 2/21 6/22 1/23 -f 10/24 1/23 6/22 -f 4/21 3/23 5/22 -f 9/24 5/22 3/23 -f 17/25 19/26 20/27 -f 18/28 17/25 20/27 -f 21/26 23/25 24/28 -f 22/27 21/26 24/28 -f 26/29 27/30 25/31 -f 27/30 28/32 25/31 -f 28/32 29/33 25/31 -f 31/34 32/35 30/36 -f 32/35 33/37 30/36 -f 33/37 34/38 30/36 -f 36/38 37/37 35/36 -f 37/37 38/35 35/36 -f 38/35 39/34 35/36 -f 41/33 42/32 40/31 -f 42/32 43/30 40/31 -f 43/30 44/29 40/31 -f 5/39 7/40 6/41 -f 7/40 8/42 6/41 -f 46/29 47/30 45/31 -f 47/30 48/32 45/31 -f 48/32 49/33 45/31 -f 51/33 52/32 50/31 -f 52/32 53/30 50/31 -f 53/30 54/29 50/31 diff --git a/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Truck_Trailer.obj b/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Truck_Trailer.obj deleted file mode 100644 index bc18133..0000000 --- a/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Truck_Trailer.obj +++ /dev/null @@ -1,106 +0,0 @@ -# Blender v2.69 (sub 0) OBJ File: 'Car002.blend' -# www.blender.org -v -0.800000 2.900000 -0.700000 -v 0.800000 2.900000 -0.700000 -v -0.800000 1.200000 -0.700000 -v 0.800000 1.200000 -0.700000 -v -0.800000 2.900000 -0.300000 -v 0.800000 2.900000 -0.300000 -v -0.800000 1.200000 -0.300000 -v 0.800000 1.200000 -0.300000 -v 0.800000 1.200000 -0.300000 -v 0.800000 2.900000 -0.300000 -v 0.800000 1.200000 -0.700000 -v 0.800000 2.900000 -0.700000 -v -0.800000 1.200000 -0.700000 -v -0.800000 2.900000 -0.700000 -v -0.800000 1.200000 -0.300000 -v -0.800000 2.900000 -0.300000 -v 0.780000 2.400000 -0.300000 -v 0.780000 2.700000 -0.300000 -v 0.780000 2.600000 0.000000 -v 0.780000 2.200000 0.000000 -v 0.780000 2.100000 -0.300000 -v -0.780000 2.400000 -0.300000 -v -0.780000 2.100000 -0.300000 -v -0.780000 2.200000 0.000000 -v -0.780000 2.600000 0.000000 -v -0.780000 2.700000 -0.300000 -v 0.780000 1.700000 -0.300000 -v 0.780000 2.000000 -0.300000 -v 0.780000 1.900000 0.000000 -v 0.780000 1.500000 0.000000 -v 0.780000 1.400000 -0.300000 -v -0.780000 1.700000 -0.300000 -v -0.780000 1.400000 -0.300000 -v -0.780000 1.500000 0.000000 -v -0.780000 1.900000 0.000000 -v -0.780000 2.000000 -0.300000 -v 0.800000 -0.600000 -2.000000 -v 0.800000 2.900000 -2.000000 -v -0.800000 -0.600000 -2.000000 -v -0.800000 2.900000 -2.000000 -v 0.800000 -0.600000 -0.800000 -v 0.800000 2.900000 -0.800000 -v -0.800000 -0.600000 -0.800000 -v -0.800000 2.900000 -0.800000 -vt 0.070499 0.643570 -vt 0.070499 0.998147 -vt 0.003817 0.998147 -vt 0.003817 0.643570 -vt 0.997239 0.998410 -vt 0.940308 0.998410 -vt 0.997239 0.647262 -vt 0.940308 0.647262 -vt 0.970266 0.522520 -vt 0.962942 0.572543 -vt 0.072079 0.572543 -vt 0.079403 0.522520 -vt 0.744362 0.446044 -vt 0.780351 0.385565 -vt 0.817830 0.446044 -vt 0.854309 0.385565 -vt 0.891299 0.446044 -vt 0.880027 0.325855 -vt 0.591008 0.325855 -vt 0.880027 0.000323 -vt 0.589446 0.324644 -vt 0.001453 0.324644 -vt 0.589446 0.001209 -vt 0.584620 0.002788 -vt 0.584620 0.324497 -vt 0.001010 0.324497 -vt 0.001010 0.002788 -vt 0.591008 0.000323 -vt 0.001453 0.001209 -s off -f 2/1 1/2 5/3 -f 5/3 6/4 2/1 -f 7/5 3/6 8/7 -f 4/8 8/7 3/6 -f 9/9 11/10 12/11 -f 10/12 9/9 12/11 -f 13/10 15/9 16/12 -f 14/11 13/10 16/12 -f 18/13 19/14 17/15 -f 19/14 20/16 17/15 -f 20/16 21/17 17/15 -f 23/17 24/16 22/15 -f 24/16 25/14 22/15 -f 25/14 26/13 22/15 -f 39/18 37/19 43/20 -f 37/21 38/22 41/23 -f 28/13 29/14 27/15 -f 29/14 30/16 27/15 -f 30/16 31/17 27/15 -f 33/17 34/16 32/15 -f 34/16 35/14 32/15 -f 35/14 36/13 32/15 -f 37/24 39/25 40/26 -f 38/27 37/24 40/26 -f 37/19 41/28 43/20 -f 40/18 44/20 42/28 -f 39/21 43/23 44/29 -f 38/22 42/29 41/23 -f 38/19 40/18 42/28 -f 40/22 39/21 44/29 diff --git a/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Ute.obj b/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Ute.obj deleted file mode 100644 index 1d3e8bb..0000000 --- a/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Ute.obj +++ /dev/null @@ -1,127 +0,0 @@ -# Blender v2.69 (sub 0) OBJ File: 'Car002.blend' -# www.blender.org -v 0.600000 -0.200000 -1.100000 -v 0.600000 0.200000 -1.100000 -v -0.600000 -0.200000 -1.100000 -v -0.600000 0.200000 -1.100000 -v -0.800000 0.300000 -0.700000 -v 0.800000 0.300000 -0.700000 -v -0.800000 2.000000 -0.700000 -v 0.800000 2.000000 -0.700000 -v -0.800000 -1.000000 -0.700000 -v 0.800000 -1.000000 -0.700000 -v -0.800000 -2.000000 -0.700000 -v 0.800000 -2.000000 -0.700000 -v -0.800000 2.000000 -0.300000 -v 0.800000 2.000000 -0.300000 -v -0.800000 -2.000000 -0.300000 -v 0.800000 -2.000000 -0.300000 -v 0.800000 -2.000000 -0.300000 -v 0.800000 2.000000 -0.300000 -v 0.800000 -2.000000 -0.700000 -v 0.800000 2.000000 -0.700000 -v -0.800000 -2.000000 -0.700000 -v -0.800000 2.000000 -0.700000 -v -0.800000 -2.000000 -0.300000 -v -0.800000 2.000000 -0.300000 -v 0.780000 1.200000 -0.300000 -v 0.780000 1.500000 -0.300000 -v 0.780000 1.400000 0.000000 -v 0.780000 1.000000 0.000000 -v 0.780000 0.900000 -0.300000 -v 0.780000 -1.100000 -0.300000 -v 0.780000 -0.800000 -0.300000 -v 0.780000 -0.900000 0.000000 -v 0.780000 -1.300000 0.000000 -v 0.780000 -1.400000 -0.300000 -v -0.780000 -1.100000 -0.300000 -v -0.780000 -1.400000 -0.300000 -v -0.780000 -1.300000 0.000000 -v -0.780000 -0.900000 0.000000 -v -0.780000 -0.800000 -0.300000 -v -0.780000 1.200000 -0.300000 -v -0.780000 0.900000 -0.300000 -v -0.780000 1.000000 0.000000 -v -0.780000 1.400000 0.000000 -v -0.780000 1.500000 -0.300000 -vt 0.564792 0.689981 -vt 0.564792 0.953949 -vt 0.338554 0.953949 -vt 0.338554 0.689981 -vt 0.334296 0.692438 -vt 0.334296 0.954445 -vt 0.203294 0.986197 -vt 0.203294 0.656186 -vt 0.695616 0.984433 -vt 0.572654 0.959219 -vt 0.695616 0.657719 -vt 0.572795 0.683358 -vt 0.941945 0.999442 -vt 0.694306 0.999442 -vt 0.941945 0.647349 -vt 0.694306 0.647349 -vt 0.070499 0.643570 -vt 0.070499 0.998147 -vt 0.003817 0.998147 -vt 0.003817 0.643570 -vt 0.997239 0.998410 -vt 0.940308 0.998410 -vt 0.997239 0.647262 -vt 0.940308 0.647262 -vt 0.471796 0.690927 -vt 0.487691 0.573764 -vt 0.563274 0.690927 -vt 0.735343 0.574985 -vt 0.970266 0.522520 -vt 0.962942 0.572543 -vt 0.072079 0.572543 -vt 0.079403 0.522520 -vt 0.744362 0.446044 -vt 0.780351 0.385565 -vt 0.817830 0.446044 -vt 0.854309 0.385565 -vt 0.891299 0.446044 -vt 0.743883 0.446331 -vt 0.779872 0.385852 -vt 0.817351 0.446331 -vt 0.853830 0.385852 -vt 0.890820 0.446331 -vt 0.122341 0.504785 -vt 0.003867 0.504785 -vt 0.122341 0.378413 -vt 0.003867 0.378413 -s off -f 1/1 3/2 4/3 -f 2/4 1/1 4/3 -f 2/5 4/6 5/7 -f 5/7 6/8 2/5 -f 9/9 3/10 10/11 -f 3/10 1/12 10/11 -f 11/13 9/14 12/15 -f 10/16 12/15 9/14 -f 8/17 7/18 13/19 -f 13/19 14/20 8/17 -f 15/21 11/22 16/23 -f 12/24 16/23 11/22 -f 2/25 6/26 1/27 -f 10/28 1/27 6/26 -f 4/25 3/27 5/26 -f 9/28 5/26 3/27 -f 17/29 19/30 20/31 -f 18/32 17/29 20/31 -f 21/30 23/29 24/32 -f 22/31 21/30 24/32 -f 26/33 27/34 25/35 -f 27/34 28/36 25/35 -f 28/36 29/37 25/35 -f 31/38 32/39 30/40 -f 32/39 33/41 30/40 -f 33/41 34/42 30/40 -f 36/42 37/41 35/40 -f 37/41 38/39 35/40 -f 38/39 39/38 35/40 -f 41/37 42/36 40/35 -f 42/36 43/34 40/35 -f 43/34 44/33 40/35 -f 5/43 7/44 6/45 -f 7/44 8/46 6/45 diff --git a/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Wagon.obj b/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Wagon.obj deleted file mode 100644 index d6774d9..0000000 --- a/Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Wagon.obj +++ /dev/null @@ -1,121 +0,0 @@ -# Blender v2.69 (sub 0) OBJ File: 'Car002.blend' -# www.blender.org -v 0.600000 -0.200000 -1.100000 -v 0.600000 1.600000 -1.100000 -v -0.600000 -0.200000 -1.100000 -v -0.600000 1.600000 -1.100000 -v -0.800000 2.000000 -0.700000 -v 0.800000 2.000000 -0.700000 -v -0.800000 2.000000 -0.700000 -v 0.800000 2.000000 -0.700000 -v -0.800000 -1.000000 -0.700000 -v 0.800000 -1.000000 -0.700000 -v -0.800000 -2.000000 -0.700000 -v 0.800000 -2.000000 -0.700000 -v -0.800000 2.000000 -0.300000 -v 0.800000 2.000000 -0.300000 -v -0.800000 -2.000000 -0.300000 -v 0.800000 -2.000000 -0.300000 -v 0.800000 -2.000000 -0.300000 -v 0.800000 2.000000 -0.300000 -v 0.800000 -2.000000 -0.700000 -v 0.800000 2.000000 -0.700000 -v -0.800000 -2.000000 -0.700000 -v -0.800000 2.000000 -0.700000 -v -0.800000 -2.000000 -0.300000 -v -0.800000 2.000000 -0.300000 -v 0.780000 1.200000 -0.300000 -v 0.780000 1.500000 -0.300000 -v 0.780000 1.400000 0.000000 -v 0.780000 1.000000 0.000000 -v 0.780000 0.900000 -0.300000 -v 0.780000 -1.100000 -0.300000 -v 0.780000 -0.800000 -0.300000 -v 0.780000 -0.900000 0.000000 -v 0.780000 -1.300000 0.000000 -v 0.780000 -1.400000 -0.300000 -v -0.780000 -1.100000 -0.300000 -v -0.780000 -1.400000 -0.300000 -v -0.780000 -1.300000 0.000000 -v -0.780000 -0.900000 0.000000 -v -0.780000 -0.800000 -0.300000 -v -0.780000 1.200000 -0.300000 -v -0.780000 0.900000 -0.300000 -v -0.780000 1.000000 0.000000 -v -0.780000 1.400000 0.000000 -v -0.780000 1.500000 -0.300000 -vt 0.564792 0.689981 -vt 0.564792 0.953949 -vt 0.338554 0.953949 -vt 0.338554 0.689981 -vt 0.334296 0.692438 -vt 0.334296 0.954445 -vt 0.203294 0.986197 -vt 0.203294 0.656186 -vt 0.695616 0.984433 -vt 0.572654 0.959219 -vt 0.695616 0.657719 -vt 0.572795 0.683358 -vt 0.941945 0.999442 -vt 0.694306 0.999442 -vt 0.941945 0.647349 -vt 0.694306 0.647349 -vt 0.070499 0.643570 -vt 0.070499 0.998147 -vt 0.003817 0.998147 -vt 0.003817 0.643570 -vt 0.997239 0.998410 -vt 0.940308 0.998410 -vt 0.997239 0.647262 -vt 0.940308 0.647262 -vt 0.331416 0.690927 -vt 0.238667 0.577426 -vt 0.563274 0.690927 -vt 0.735343 0.574985 -vt 0.970266 0.522520 -vt 0.962942 0.572543 -vt 0.072079 0.572543 -vt 0.079403 0.522520 -vt 0.744362 0.446044 -vt 0.780351 0.385565 -vt 0.817830 0.446044 -vt 0.854309 0.385565 -vt 0.891299 0.446044 -vt 0.743883 0.446331 -vt 0.779872 0.385852 -vt 0.817351 0.446331 -vt 0.853830 0.385852 -vt 0.890820 0.446331 -s off -f 1/1 3/2 4/3 -f 2/4 1/1 4/3 -f 2/5 4/6 5/7 -f 5/7 6/8 2/5 -f 9/9 3/10 10/11 -f 3/10 1/12 10/11 -f 11/13 9/14 12/15 -f 10/16 12/15 9/14 -f 8/17 7/18 13/19 -f 13/19 14/20 8/17 -f 15/21 11/22 16/23 -f 12/24 16/23 11/22 -f 2/25 6/26 1/27 -f 10/28 1/27 6/26 -f 4/25 3/27 5/26 -f 9/28 5/26 3/27 -f 17/29 19/30 20/31 -f 18/32 17/29 20/31 -f 21/30 23/29 24/32 -f 22/31 21/30 24/32 -f 26/33 27/34 25/35 -f 27/34 28/36 25/35 -f 28/36 29/37 25/35 -f 31/38 32/39 30/40 -f 32/39 33/41 30/40 -f 33/41 34/42 30/40 -f 36/42 37/41 35/40 -f 37/41 38/39 35/40 -f 38/39 39/38 35/40 -f 41/37 42/36 40/35 -f 42/36 43/34 40/35 -f 43/34 44/33 40/35 diff --git a/Videos/CarCrimeCity/Part2/assets/vehicles/CarTex_256.png b/Videos/CarCrimeCity/Part2/assets/vehicles/CarTex_256.png deleted file mode 100644 index 049eb5c..0000000 Binary files a/Videos/CarCrimeCity/Part2/assets/vehicles/CarTex_256.png and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/cAutomata.cpp b/Videos/CarCrimeCity/Part2/cAutomata.cpp deleted file mode 100644 index b289bbc..0000000 --- a/Videos/CarCrimeCity/Part2/cAutomata.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include "cAutomata.h" - - -cAuto_Node::cAuto_Node() -{ - pos = { 0,0 }; -} - -cAuto_Node::cAuto_Node(const olc::vf2d &worldpos) -{ - pos = worldpos; -} - -olc::vf2d cAuto_Track::GetPostion(float t, cAuto_Node *pStart) -{ - // pStart indicates the node the automata first encounted this track - if (node[0] == pStart) - { - return node[0]->pos + (node[1]->pos - node[0]->pos) * (t / fTrackLength); - } - else - { - return node[1]->pos + (node[0]->pos - node[1]->pos) * (t / fTrackLength); - } -} - - - -cAuto_Body::cAuto_Body() -{ -} - - -cAuto_Body::~cAuto_Body() -{ -} - - -void cAuto_Body::UpdateAuto(float fElapsedTime) -{ - // Work out which node is the target destination - cAuto_Node *pExitNode = pCurrentTrack->node[0]; - if (pExitNode == pTrackOriginNode) - pExitNode = pCurrentTrack->node[1]; - - bool bAutomataCanMove = true; - - float fDistanceToAutoInFront = 1.0f; - - // First check if the vehicle overlaps with the one in front of it - - // Get an iterator for this automata - auto itThisAutomata = std::find(pCurrentTrack->listAutos.begin(), pCurrentTrack->listAutos.end(), this); - - // If this automata is at the front of this track segment - if (*itThisAutomata == pCurrentTrack->listAutos.front()) - { - // Then check all the following track segments. Take the position of - // each vehicle at the back of the track segments auto list - for (auto &track : pExitNode->listTracks) - { - if (track != pCurrentTrack && !track->listAutos.empty()) - { - // Get Auto at back - float fDistanceFromTrackStartToAutoRear = track->listAutos.back()->fAutoPos - track->listAutos.back()->fAutoLength; - - if ((*itThisAutomata)->fAutoPos < (pCurrentTrack->fTrackLength + fDistanceFromTrackStartToAutoRear - fAutoLength)) - { - // Move Automata along track, as there is space - //bAutomataCanMove = true; - fDistanceToAutoInFront = (pCurrentTrack->fTrackLength + fDistanceFromTrackStartToAutoRear - 0.1f) - (*itThisAutomata)->fAutoPos; - } - else - { - // No space, so do not move automata - bAutomataCanMove = false; - } - } - else - { - // Track in front was empty, node is clear to pass through so - //bAutomataCanMove = true; - } - } - - - - } - else - { - // Get the automata in front - auto itAutomataInFront = itThisAutomata; - itAutomataInFront--; - - // If the distance between the front of the automata in front and the fornt of this automata - // is greater than the length of the automata in front, then there is space for this automata - // to enter - if (fabs((*itAutomataInFront)->fAutoPos - (*itThisAutomata)->fAutoPos) > ((*itAutomataInFront)->fAutoLength + 0.1f)) - { - // Move Automata along track - //bAutomataCanMove = true; - fDistanceToAutoInFront = ((*itAutomataInFront)->fAutoPos - (*itAutomataInFront)->fAutoLength - 0.1f) - (*itThisAutomata)->fAutoPos; - } - else - { - // No space, so do not move automata - bAutomataCanMove = false; - } - } - - if (bAutomataCanMove) - { - if (fDistanceToAutoInFront > pCurrentTrack->fTrackLength) fDistanceToAutoInFront = pCurrentTrack->fTrackLength; - fAutoPos += fElapsedTime * std::max(fDistanceToAutoInFront, 1.0f) * (fAutoLength < 0.1f ? 0.3f : 0.5f); - } - - - if (fAutoPos >= pCurrentTrack->fTrackLength) - { - // Automata has reached end of current track - - // Check if it can transition beyond node - if (!pExitNode->bBlock) - { - // It can, so reset position along track back to start - fAutoPos -= pCurrentTrack->fTrackLength; - - // Choose a track from the node not equal to this one, that has an unblocked exit node - - // For now choose at random - cAuto_Track *pNewTrack = nullptr; - - if (pExitNode->listTracks.size() == 2) - { - // Automata is travelling along straight joined sections, one of the - // tracks is the track its just come in on, the other is the exit, so - // choose the exit. - auto it = pExitNode->listTracks.begin(); - pNewTrack = (*it); - if (pCurrentTrack == pNewTrack) - { - ++it; - pNewTrack = (*it); - } - } - else - { - // Automata has reached a junction with several exits - while (pNewTrack == nullptr) - { - int i = rand() % pExitNode->listTracks.size(); - int j = 0; - for (auto it = pExitNode->listTracks.begin(); it != pExitNode->listTracks.end(); ++it) - { - cAuto_Track* track = (*it); - - // Work out which node is the target destination - cAuto_Node *pNewExitNode = track->node[0]; - if (pNewExitNode == pExitNode) - pNewExitNode = track->node[1]; - - if (j == i && track != pCurrentTrack && !pNewExitNode->bBlock /*((*it)->cell != pCurrentTrack->cell)*/) - { - pNewTrack = track; - break; - } - - j++; - } - } - } - - - // Change to new track, the origin node of the next - // track is the same as the exit node to the current track - pTrackOriginNode = pExitNode; - - // Remove the automata from the front of the queue - // on the current track - pCurrentTrack->listAutos.pop_front(); - - // Switch the automatas track link to the new track - pCurrentTrack = pNewTrack; - - // Push the automata onto the back of the new track queue - pCurrentTrack->listAutos.push_back(this); - - } - else - { - // It cant pass the node, so clamp automata at this location - fAutoPos = pCurrentTrack->fTrackLength; - } - - } - else - { - // Automata is travelling - vAutoPos = pCurrentTrack->GetPostion(fAutoPos, pTrackOriginNode); - } -} - - - - - diff --git a/Videos/CarCrimeCity/Part2/cAutomata.h b/Videos/CarCrimeCity/Part2/cAutomata.h deleted file mode 100644 index f612481..0000000 --- a/Videos/CarCrimeCity/Part2/cAutomata.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - Top Down City Based Car Crime Game - Part #2 - "Colin, I hope you're shooting 600+ wherever you are buddy. RIP." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Instructions: - ~~~~~~~~~~~~~ - Scroll with middle mouse wheel, TAB toggle edit mode, R to place road - P to place pavement, Q to place building, Arrow keys to drive car - - Relevant Video: https://youtu.be/fIV6P1W-wuo - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - - -#pragma once - -#include "olcPixelGameEngine.h" - -class cAuto_Track; -class cAuto_Node; -class cAuto_Body; -class cCell; - -class cAuto_Node -{ -public: - cAuto_Node(); - cAuto_Node(const olc::vf2d &worldpos); - olc::vf2d pos; - bool bBlock = false; - std::list listTracks; -}; - -class cAuto_Track -{ -public: - cAuto_Node* node[2]; // Two end nodes - cCell* cell; // Pointer to host cell - olc::vf2d GetPostion(float t, cAuto_Node *pstart); - std::list listAutos; - float fTrackLength = 1.0f; -}; - -class cAuto_Body -{ -public: - cAuto_Body(); - ~cAuto_Body(); - -public: - void UpdateAuto(float fElapsedTime); - -public: - olc::vf2d vAutoPos = { 0.0f, 0.0f }; - float fAutoPos = 0.0f; // Location of automata along track - float fAutoLength = 0.0f; // Physical length of automata - cAuto_Track *pCurrentTrack = nullptr; - cAuto_Node *pTrackOriginNode = nullptr; - -}; diff --git a/Videos/CarCrimeCity/Part2/cCarCrimeCity.cpp b/Videos/CarCrimeCity/Part2/cCarCrimeCity.cpp deleted file mode 100644 index 6067839..0000000 --- a/Videos/CarCrimeCity/Part2/cCarCrimeCity.cpp +++ /dev/null @@ -1,709 +0,0 @@ -#include "cCarCrimeCity.h" - -cCarCrimeCity::cCarCrimeCity() -{ - sAppName = "Car Crime City"; -} - -cCarCrimeCity::~cCarCrimeCity() -{ -} - -bool cCarCrimeCity::OnUserCreate() -{ - // Initialise PGEX 3D - olc::GFX3D::ConfigureDisplay(); - - // Load fixed system assets, i.e. those need to simply do anything - if (!LoadAssets()) return false; - - // Create Default city - pCity = new cCityMap(cGameSettings::nDefaultMapWidth, cGameSettings::nDefaultMapHeight, mapAssetTextures, mapAssetMeshes, mapAssetTransform); - - // If a city map file has been specified, then load it - if (!cGameSettings::sDefaultCityFile.empty()) - { - if (!pCity->LoadCity(cGameSettings::sDefaultCityFile)) - { - std::cout << "Failed to load '" << cGameSettings::sDefaultCityFile << "'" << std::endl; - return false; - } - } - - return true; -} - -bool cCarCrimeCity::LoadAssets() -{ - // Game Settings should have loaded all the relevant file information - // to start loading asset information. Game assets will be stored in - // a map structure. Maps can have slightly longer access times, so each - // in game object will have facility to extract required resources once - // when it is created, meaning no map search during normal use - - // System Meshes - // A simple flat unit quad - olc::GFX3D::mesh* meshQuad = new olc::GFX3D::mesh(); - meshQuad->tris = - { - { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE }, - { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE }, - }; - mapAssetMeshes["UnitQuad"] = meshQuad; - - //// The four outer walls of a cell - olc::GFX3D::mesh* meshWallsOut = new olc::GFX3D::mesh(); - meshWallsOut->tris = - { - // EAST - { 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE }, - { 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE }, - - // WEST - { 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE }, - { 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE }, - - // TOP - { 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE }, - { 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE }, - - // BOTTOM - { 1.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE }, - { 1.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE }, - }; - mapAssetMeshes["WallsOut"] = meshWallsOut; - - - // System Textures - for (auto &asset : cGameSettings::vecAssetTextures) - { - olc::Sprite *sprAsset = new olc::Sprite(); - if (sprAsset->LoadFromFile(asset.sFile)) - { - mapAssetTextures[asset.sName] = sprAsset; - } - else - { - std::cout << "Failed to load " << asset.sName << std::endl; - return false; - } - } - - // Break up roads sprite into individual sprites. Why? Its easier to maintain - // the roads sprite as a single image, but easier to use if they are all individual. - // Breaking it up manually in the image editing software is time consuming so just - // do it here - int nRoadTexSize = 256; // In pixels in base texture - int nRoadTexOffset = 64; // There exists a 64 pixel offset from top left of source image - for (int r = 0; r < 12; r++) - { - olc::Sprite* road = new olc::Sprite(nRoadTexSize, nRoadTexSize); - SetDrawTarget(road); - DrawPartialSprite(0, 0, mapAssetTextures["AllRoads"], ((r % 3) * nRoadTexSize) + nRoadTexOffset, ((r / 3) * nRoadTexSize) + nRoadTexOffset, nRoadTexSize, nRoadTexSize); - switch (r) - { - case 0: mapAssetTextures["Road_V"] = road; break; - case 1: mapAssetTextures["Road_H"] = road; break; - case 2: mapAssetTextures["Pavement"] = road; break; - case 3: mapAssetTextures["Road_C1"] = road; break; - case 4: mapAssetTextures["Road_T1"] = road; break; - case 5: mapAssetTextures["Road_C2"] = road; break; - case 6: mapAssetTextures["Road_T2"] = road; break; - case 7: mapAssetTextures["Road_X"] = road; break; - case 8: mapAssetTextures["Road_T3"] = road; break; - case 9: mapAssetTextures["Road_C3"] = road; break; - case 10: mapAssetTextures["Road_T4"] = road; break; - case 11: mapAssetTextures["Road_C4"] = road; break; - } - } - SetDrawTarget(nullptr); - - - // Load Buildings - for (auto &asset : cGameSettings::vecAssetBuildings) - { - mapAssetMeshes[asset.sDescription] = new olc::GFX3D::mesh(); - mapAssetMeshes[asset.sDescription]->LoadOBJFile(asset.sModelOBJ); - mapAssetTextures[asset.sDescription] = new olc::Sprite(asset.sModelPNG); - - olc::GFX3D::mat4x4 matScale = olc::GFX3D::Math::Mat_MakeScale(asset.fScale[0], asset.fScale[1], asset.fScale[2]); - olc::GFX3D::mat4x4 matTranslate = olc::GFX3D::Math::Mat_MakeTranslation(asset.fTranslate[0], asset.fTranslate[1], asset.fTranslate[2]); - olc::GFX3D::mat4x4 matRotateX = olc::GFX3D::Math::Mat_MakeRotationX(asset.fRotate[0]); - olc::GFX3D::mat4x4 matRotateY = olc::GFX3D::Math::Mat_MakeRotationY(asset.fRotate[1]); - olc::GFX3D::mat4x4 matRotateZ = olc::GFX3D::Math::Mat_MakeRotationZ(asset.fRotate[2]); - olc::GFX3D::mat4x4 matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTranslate, matScale); - matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateX); - matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateY); - matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateZ); - mapAssetTransform[asset.sDescription] = matTransform; - } - - // Load Vehicles - for (auto &asset : cGameSettings::vecAssetVehicles) - { - mapAssetMeshes[asset.sDescription] = new olc::GFX3D::mesh(); - mapAssetMeshes[asset.sDescription]->LoadOBJFile(asset.sModelOBJ); - mapAssetTextures[asset.sDescription] = new olc::Sprite(asset.sModelPNG); - - olc::GFX3D::mat4x4 matScale = olc::GFX3D::Math::Mat_MakeScale(asset.fScale[0], asset.fScale[1], asset.fScale[2]); - olc::GFX3D::mat4x4 matTranslate = olc::GFX3D::Math::Mat_MakeTranslation(asset.fTranslate[0], asset.fTranslate[1], asset.fTranslate[2]); - olc::GFX3D::mat4x4 matRotateX = olc::GFX3D::Math::Mat_MakeRotationX(asset.fRotate[0]); - olc::GFX3D::mat4x4 matRotateY = olc::GFX3D::Math::Mat_MakeRotationY(asset.fRotate[1]); - olc::GFX3D::mat4x4 matRotateZ = olc::GFX3D::Math::Mat_MakeRotationZ(asset.fRotate[2]); - olc::GFX3D::mat4x4 matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTranslate, matScale); - matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateX); - matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateY); - matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateZ); - mapAssetTransform[asset.sDescription] = matTransform; - } - - return true; -} - -void cCarCrimeCity::SpawnPedestrian(int x, int y) -{ - cCell* cell = pCity->Cell(x, y); - - cAuto_Track *t = ((cCell_Road*)cell)->pSafePedestrianTrack; - if (t == nullptr) return; - - cAuto_Body *a = new cAuto_Body(); - a->fAutoLength = 0.05f; - a->pCurrentTrack = t; - a->pCurrentTrack->listAutos.push_back(a); - a->pTrackOriginNode = t->node[0]; - a->UpdateAuto(0.0f); - listAutomata.push_back(a); -} - -void cCarCrimeCity::SpawnVehicle(int x, int y) -{ - cCell* cell = pCity->Cell(x, y); - - cAuto_Track *t = ((cCell_Road*)cell)->pSafeCarTrack; - if (t == nullptr) return; - - cAuto_Body *a = new cAuto_Body(); - a->fAutoLength = 0.2f; - a->pCurrentTrack = t; - a->pCurrentTrack->listAutos.push_back(a); - a->pTrackOriginNode = t->node[0]; - a->UpdateAuto(0.0f); - listAutomata.push_back(a); -} - -void cCarCrimeCity::DoEditMode(float fElapsedTime) -{ - // Get cell under mouse cursor - cCell* mcell = pCity->Cell(nMouseX, nMouseY); - bool bTempCellAdded = false; - - // Left click and drag adds cells - if (mcell != nullptr && GetMouse(0).bHeld) - setSelectedCells.emplace(nMouseY * pCity->GetWidth() + nMouseX); - - // Right click clears selection - if (GetMouse(1).bReleased) - setSelectedCells.clear(); - - if (setSelectedCells.empty()) - { - // If nothing can be edited validly then just exit - if (mcell == nullptr) - return; - - // else set is empty, so temporarily add current cell to it - setSelectedCells.emplace(nMouseY * pCity->GetWidth() + nMouseX); - bTempCellAdded = true; - } - - // If the map changes, we will need to update - // the automata, and adjacency - bool bMapChanged = false; - - // Press "G" to apply grass - if (GetKey(olc::Key::G).bPressed) - { - for (auto &c : setSelectedCells) - { - int x = c % pCity->GetWidth(); - int y = c / pCity->GetWidth(); - cCell* cell = pCity->Replace(x, y, new cCell_Plane(pCity, x, y, PLANE_GRASS)); - cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform); - } - - bMapChanged = true; - } - - // Press "P" to apply Pavement - if (GetKey(olc::Key::P).bPressed) - { - for (auto &c : setSelectedCells) - { - int x = c % pCity->GetWidth(); - int y = c / pCity->GetWidth(); - cCell* cell = pCity->Replace(x, y, new cCell_Plane(pCity, x, y, PLANE_ASPHALT)); - cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform); - } - - bMapChanged = true; - } - - // Press "W" to apply Water - if (GetKey(olc::Key::W).bPressed) - { - for (auto &c : setSelectedCells) - { - int x = c % pCity->GetWidth(); - int y = c / pCity->GetWidth(); - cCell* cell = pCity->Replace(x, y, new cCell_Water(pCity, x, y)); - cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform); - } - - bMapChanged = true; - } - - // Press "R" to apply Roads - if (GetKey(olc::Key::Q).bPressed) - { - for (auto &c : setSelectedCells) - { - int x = c % pCity->GetWidth(); - int y = c / pCity->GetWidth(); - cCell* cell = pCity->Replace(x, y, new cCell_Building("Apartments_1", pCity, x, y)); - cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform); - } - - bMapChanged = true; - } - - - // Press "R" to apply Roads - if (GetKey(olc::Key::R).bPressed) - { - for (auto &c : setSelectedCells) - { - int x = c % pCity->GetWidth(); - int y = c / pCity->GetWidth(); - cCell* cell = pCity->Replace(x, y, new cCell_Road(pCity, x, y)); - cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform); - } - - bMapChanged = true; - } - - - - if (GetKey(olc::Key::C).bPressed) - { - for (auto &c : setSelectedCells) - { - int x = c % pCity->GetWidth(); - int y = c / pCity->GetWidth(); - SpawnVehicle(x, y); - } - } - - - if (GetKey(olc::Key::V).bPressed) - { - for (auto &c : setSelectedCells) - { - int x = c % pCity->GetWidth(); - int y = c / pCity->GetWidth(); - SpawnPedestrian(x, y); - } - } - - if (bMapChanged) - { - // The navigation nodes may have tracks attached to them, so get rid of them - // all. Below we will reconstruct all tracks because city has changed - pCity->RemoveAllTracks(); - - for (auto &a : listAutomata) delete a; - listAutomata.clear(); - - for (int x = 0; x < pCity->GetWidth(); x++) - { - for (int y = 0; y < pCity->GetHeight(); y++) - { - cCell *c = pCity->Cell(x, y); - - // Update adjacency information, i.e. those cells whose - // state changes based on neighbouring cells - c->CalculateAdjacency(); - } - } - } - - - // To facilitate "edit under cursor" we added a temporary cell - // which needs to be removed now - if (bTempCellAdded) - setSelectedCells.clear(); -} - -olc::vf2d cCarCrimeCity::GetMouseOnGround(const olc::vf2d &vMouseScreen) -{ - olc::GFX3D::vec3d vLookTarget = olc::GFX3D::Math::Vec_Add(vEye, vLookDir); - olc::GFX3D::mat4x4 matProj = olc::GFX3D::Math::Mat_MakeProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.1f, 1000.0f); - olc::GFX3D::mat4x4 matView = olc::GFX3D::Math::Mat_PointAt(vEye, vLookTarget, vUp); - olc::GFX3D::vec3d vecMouseDir = { - 2.0f * ((vMouseScreen.x / (float)ScreenWidth()) - 0.5f) / matProj.m[0][0], - 2.0f * ((vMouseScreen.y / (float)ScreenHeight()) - 0.5f) / matProj.m[1][1], - 1.0f, - 0.0f }; - - olc::GFX3D::vec3d vecMouseOrigin = { 0.0f, 0.0f, 0.0f }; - vecMouseOrigin = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseOrigin); - vecMouseDir = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseDir); - vecMouseDir = olc::GFX3D::Math::Vec_Mul(vecMouseDir, 1000.0f); - vecMouseDir = olc::GFX3D::Math::Vec_Add(vecMouseOrigin, vecMouseDir); - - // Perform line/plane intersection to determine mouse position in world space - olc::GFX3D::vec3d plane_p = { 0.0f, 0.0f, 0.0f }; - olc::GFX3D::vec3d plane_n = { 0.0f, 0.0f, 1.0f }; - float t = 0.0f; - olc::GFX3D::vec3d mouse3d = olc::GFX3D::Math::Vec_IntersectPlane(plane_p, plane_n, vecMouseOrigin, vecMouseDir, t); - return { mouse3d.x, mouse3d.y }; -} - -bool cCarCrimeCity::OnUserUpdate(float fElapsedTime) -{ - fGlobalTime += fElapsedTime; - - if (GetKey(olc::Key::TAB).bReleased) bEditMode = !bEditMode; - - if (bEditMode) // Use mouse to pan and zoom, and place objects - { - vEye = vCamera; - olc::vf2d vMouseScreen = { (float)GetMouseX(), (float)GetMouseY() }; - olc::vf2d vMouseOnGroundBeforeZoom = GetMouseOnGround(vMouseScreen); - - vOffset = { 0,0 }; - - if (IsFocused()) - { - if (GetMouse(2).bPressed) { vStartPan = vMouseOnGroundBeforeZoom; } - if (GetMouse(2).bHeld) { vOffset = (vStartPan - vMouseOnGroundBeforeZoom); }; - - if (GetMouseWheel() > 0) - { - vCamera.z *= 0.5f; - } - - if (GetMouseWheel() < 0) - { - vCamera.z *= 1.5f; - } - } - - vEye = vCamera; - olc::vf2d vMouseOnGroundAfterZoom = GetMouseOnGround(vMouseScreen); - vOffset += (vMouseOnGroundBeforeZoom - vMouseOnGroundAfterZoom); - vCamera.x += vOffset.x; - vCamera.y += vOffset.y; - vEye = vCamera; - - // Get Integer versions of mouse coords in world space - nMouseX = (int)vMouseOnGroundAfterZoom.x; - nMouseY = (int)vMouseOnGroundAfterZoom.y; - - DoEditMode(fElapsedTime); - } - else - { - // Not in edit mode, so camera follows player - if (GetKey(olc::Key::LEFT).bHeld) fAngle += -2.5f * fElapsedTime; - if (GetKey(olc::Key::RIGHT).bHeld) fAngle += 2.5f * fElapsedTime; - if (GetKey(olc::Key::UP).bHeld) - { - carvel = { cos(fAngle), sin(fAngle) }; - carpos += carvel * 2.0f * fElapsedTime; - } - - vCamera.x = carpos.x; - vCamera.y = carpos.y; - vEye = vCamera; - } - - /*fAngle = 0.0f; - if (GetKey(olc::Key::LEFT).bHeld) fAngle = -0.8f; - if (GetKey(olc::Key::RIGHT).bHeld) fAngle = 0.8f;*/ - - - //car.UpdateDrive(fElapsedTime, 1.0f, GetKey(olc::Key::UP).bHeld, GetKey(olc::Key::SPACE).bHeld, GetKey(olc::Key::DOWN).bHeld, fAngle); - - - //if (car.bSkidding && fmod(fGlobalTime, 0.05f) < 0.01f) - //{ - // listDecalSmoke.push_front({ 0.1f, {car.vPosRear.x, car.vPosRear.y, -0.03f} }); - //} - - - //// Update Decals - //for (auto &d : listDecalSmoke) - //{ - // d.fLifetime += fElapsedTime; - //} - - //listDecalSmoke.remove_if([](const sSmokeDecal &d) {return d.fLifetime > 2.0f; }); - - //if (!bEditMode) - //{ - // vCamera.x = car.GetOrigin().x; - // vCamera.y = car.GetOrigin().y; - //} - - - //float fTargetHeight = -1.0f; - //int nCarX = vCamera.x; - //int nCarY = vCamera.y; - - std::vector vecNeighbours; - - //// Check surrounding cells height - //for (int x = nCarX - 1; x < nCarX + 2; x++) - // for (int y = nCarY - 1; y < nCarY + 2; y++) - // { - // if (pCity->Cell(x,y) && pCity->Cell(x, y)->bBuilding) - // { - // cGameObjectQuad ob(1.0f, 1.0f); - // ob.pos = { (float)x + 0.5f, (float)y + 0.5f, 0.0f, 1.0f }; - // ob.TransformModelToWorld(); - // vecNeighbours.push_back(ob); - // fTargetHeight = -2.0f; - // } - // } - - //goCar->pos.x = car.GetOrigin().x; - //goCar->pos.y = car.GetOrigin().y; - //goCar->fAngle = car.GetRotation(); - //goCar->TransformModelToWorld(); - - //for (auto &ob : vecNeighbours) - //{ - // if (goCar->StaticCollisionWith(ob, true)) - // { - // goCar->TransformModelToWorld(); - // car.vPosRear.x += goCar->pos.x - car.GetOrigin().x; - // car.vPosRear.y += goCar->pos.y - car.GetOrigin().y; - // car.vPosFront.x += goCar->pos.x - car.GetOrigin().x; - // car.vPosFront.y += goCar->pos.y - car.GetOrigin().y; - // car.fSpeed = 0.0f; - // } - //} - - //if(!bEditMode) - // vCamera.z += (fTargetHeight - vCamera.z) * 10.0f * fElapsedTime; - - - //car.UpdateTow(fElapsedTime, { mouse3d.x, mouse3d.y }); - - - - //for (int v = 1; vGetWidth(), (int)viewWorldBottomRight.x + 1); - int nStartY = std::max(0, (int)viewWorldTopLeft.y - 1); - int nEndY = std::min(pCity->GetHeight(), (int)viewWorldBottomRight.y + 1); - - // Only update automata for cells near player - int nAutomStartX = std::max(0, (int)viewWorldTopLeft.x - 3); - int nAutomEndX = std::min(pCity->GetWidth(), (int)viewWorldBottomRight.x + 3); - int nAutomStartY = std::max(0, (int)viewWorldTopLeft.y - 3); - int nAutomEndY = std::min(pCity->GetHeight(), (int)viewWorldBottomRight.y + 3); - - int nLocalStartX = std::max(0, (int)vCamera.x - 3); - int nLocalEndX = std::min(pCity->GetWidth(), (int)vCamera.x + 3); - int nLocalStartY = std::max(0, (int)vCamera.y - 3); - int nLocalEndY = std::min(pCity->GetHeight(), (int)vCamera.y + 3); - - - // Update Cells - for (int x = nStartX; x < nEndX; x++) - { - for (int y = nStartY; y < nEndY; y++) - { - pCity->Cell(x, y)->Update(fElapsedTime); - } - } - - // Update Automata - for (auto &a : listAutomata) - { - a->UpdateAuto(fElapsedTime); - - // If automata is too far from camera, remove it - if ((a->vAutoPos - olc::vf2d(vCamera.x, vCamera.y)).mag() > 5.0f) - { - // Despawn automata - - // 1) Disconnect it from track - a->pCurrentTrack->listAutos.remove(a); - - // 2) Erase it from memory - delete a; a = nullptr; - } - } - - // Remove dead automata, their pointer has been set to nullptr in the list - listAutomata.remove(nullptr); - - // Maintain a certain level of automata in vicinty of player - if (listAutomata.size() < 20) - { - bool bSpawnOK = false; - int nSpawnAttempt = 20; - while (!bSpawnOK && nSpawnAttempt > 0) - { - // Find random cell on edge of vicinty, which is out of view of the player - float fRandomAngle = ((float)rand() / (float)RAND_MAX) * 2.0f * 3.14159f; - int nRandomCellX = vCamera.x + cos(fRandomAngle) * 3.0f; - int nRandomCellY = vCamera.y + sin(fRandomAngle) * 3.0f; - - nSpawnAttempt--; - - if (pCity->Cell(nRandomCellX, nRandomCellY) && pCity->Cell(nRandomCellX, nRandomCellY)->nCellType == CELL_ROAD) - { - bSpawnOK = true; - - // Add random automata - if (rand() % 100 < 50) - { - // Spawn Pedestrian - SpawnPedestrian(nRandomCellX, nRandomCellY); - } - else - { - // Spawn Vehicle - SpawnVehicle(nRandomCellX, nRandomCellY); - // TODO: Get % chance of vehicle spawn from lua script - } - } - } - } - - - - - // Render Scene - Clear(olc::BLUE); - olc::GFX3D::ClearDepth(); - - // Create rendering pipeline - olc::GFX3D::PipeLine pipe; - pipe.SetProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.1f, 1000.0f, 0.0f, 0.0f, (float)ScreenWidth(), (float)ScreenHeight()); - olc::GFX3D::vec3d vLookTarget = olc::GFX3D::Math::Vec_Add(vEye, vLookDir); - pipe.SetCamera(vEye, vLookTarget, vUp); - - - // Add global illumination vector (sunlight) - olc::GFX3D::vec3d lightdir = { 1.0f, 1.0f, -1.0f }; - pipe.SetLightSource(0, olc::GFX3D::LIGHT_AMBIENT, olc::Pixel(100,100,100), { 0,0,0 }, lightdir); - pipe.SetLightSource(1, olc::GFX3D::LIGHT_DIRECTIONAL, olc::WHITE, { 0,0,0 }, lightdir); - - - // RENDER CELL CONTENTS - - // Render Base Objects (those without alpha components) - for (int x = nStartX; x < nEndX; x++) - { - //omp_set_dynamic(0); - //omp_set_num_threads(4); - //#pragma omp parallel for - for (int y = nStartY; y < nEndY; y++) - { - pCity->Cell(x, y)->DrawBase(this, pipe); - } - //#pragma omp barrier - } - - // Render Upper Objects (those with alpha components) - for (int x = nStartX; x < nEndX; x++) - { - for (int y = nStartY; y < nEndY; y++) - { - pCity->Cell(x, y)->DrawAlpha(this, pipe); - } - } - - if (bEditMode) - { - // Render additional per cell debug information - for (int x = nStartX; x < nEndX; x++) - { - for (int y = nStartY; y < nEndY; y++) - { - pCity->Cell(x, y)->DrawDebug(this, pipe); - } - } - } - - if (bEditMode) - { - // Draw Selections - for (auto &c : setSelectedCells) - { - int x = c % pCity->GetWidth(); - int y = c / pCity->GetWidth(); - olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)x, (float)y, 0.01f); - pipe.SetTransform(matWorld); - pipe.Render(mapAssetMeshes["UnitQuad"]->tris, olc::GFX3D::RENDER_WIRE); - } - } - - // RENDER AUTOMATA - - std::string test[] = { "Sedan", "SUV", "TruckCab", "TruckTrailer", "UTE", "Wagon" }; - int i = 0; - for (auto &a : listAutomata) - { - olc::GFX3D::vec3d v = { a->vAutoPos.x, a->vAutoPos.y, 0.0f }; - - /*olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation(a->vAutoPos.x, a->vAutoPos.y, 0.01f); - matWorld = olc::GFX3D::Math::Mat_MultiplyMatrix(mapAssetTransform[test[i]], matWorld); - pipe.SetTransform(matWorld); - pipe.SetTexture(mapAssetTextures[test[i]]); - pipe.Render(mapAssetMeshes[test[i]]->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_LIGHTS); - i++; - i = i % 6;*/ - - pipe.RenderCircleXZ(v, a->fAutoLength < 0.1f ? 0.05f : 0.07f, a->fAutoLength < 0.1f ? olc::MAGENTA : olc::YELLOW); - } - - - // Draw Player Vehicle - { - olc::GFX3D::mat4x4 matRotateZ = olc::GFX3D::Math::Mat_MakeRotationZ(fAngle); - olc::GFX3D::mat4x4 matTranslate = olc::GFX3D::Math::Mat_MakeTranslation(carpos.x, carpos.y, 0.01f); - olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MultiplyMatrix(mapAssetTransform["Sedan"], matRotateZ); - matWorld = olc::GFX3D::Math::Mat_MultiplyMatrix(matWorld, matTranslate); - pipe.SetTransform(matWorld); - pipe.SetTexture(mapAssetTextures["Sedan"]); - pipe.Render(mapAssetMeshes[test[i]]->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_LIGHTS); - } - - DrawString(10, 10, "Automata: " + std::to_string(listAutomata.size()), olc::WHITE); - - - if (GetKey(olc::Key::ESCAPE).bPressed) - return false; - - return true; -} - -bool cCarCrimeCity::OnUserDestroy() -{ - return true; -} diff --git a/Videos/CarCrimeCity/Part2/cCarCrimeCity.h b/Videos/CarCrimeCity/Part2/cCarCrimeCity.h deleted file mode 100644 index a2a481c..0000000 --- a/Videos/CarCrimeCity/Part2/cCarCrimeCity.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - Top Down City Based Car Crime Game - Part #2 - "Colin, I hope you're shooting 600+ wherever you are buddy. RIP." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Instructions: - ~~~~~~~~~~~~~ - Scroll with middle mouse wheel, TAB toggle edit mode, R to place road - P to place pavement, Q to place building, Arrow keys to drive car - - Relevant Video: https://youtu.be/fIV6P1W-wuo - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - - -#pragma once - -#include "olcPixelGameEngine.h" -#include "olcPGEX_Graphics3D.h" - -#include "cGameSettings.h" -#include "cCityMap.h" - -#include -#include - -struct sSmokeDecal -{ - float fLifetime = 0.1f; - olc::GFX3D::vec3d pos; -}; - -class cCarCrimeCity : public olc::PixelGameEngine -{ -public: - cCarCrimeCity(); - ~cCarCrimeCity(); - -private: - bool OnUserCreate() override; - bool OnUserUpdate(float fElapsedTime) override; - bool OnUserDestroy() override; - -private: - - class cGameObjectQuad - { - public: - cGameObjectQuad(float w, float h) - { - fWidth = w; - fHeight = h; - fAngle = 0.0f; - - // Construct Model Quad Geometry - vecPointsModel = { {-fWidth / 2.0f, -fHeight / 2.0f, -0.01f, 1.0f}, - {-fWidth / 2.0f, +fHeight / 2.0f, -0.01f, 1.0f}, - {+fWidth / 2.0f, +fHeight / 2.0f, -0.01f, 1.0f}, - {+fWidth / 2.0f, -fHeight / 2.0f, -0.01f, 1.0f} }; - - vecPointsWorld.resize(vecPointsModel.size()); - TransformModelToWorld(); - } - - void TransformModelToWorld() - { - for (size_t i = 0; i < vecPointsModel.size(); ++i) - { - vecPointsWorld[i] = { - (vecPointsModel[i].x * cosf(fAngle)) - (vecPointsModel[i].y * sinf(fAngle)) + pos.x, - (vecPointsModel[i].x * sinf(fAngle)) + (vecPointsModel[i].y * cosf(fAngle)) + pos.y, - vecPointsModel[i].z, - vecPointsModel[i].w - }; - } - } - - std::vector GetTriangles() - { - // Return triangles based upon this quad - return - { - {vecPointsWorld[0], vecPointsWorld[1], vecPointsWorld[2], 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::RED}, - {vecPointsWorld[0], vecPointsWorld[2], vecPointsWorld[3], 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, olc::RED}, - }; - } - - // Use rectangle edge intersections. - bool StaticCollisionWith(cGameObjectQuad &r2, bool bResolveStatic = false) - { - struct vec2d { float x; float y; }; - - bool bCollision = false; - - // Check diagonals of R1 against edges of R2 - for (size_t p = 0; p < vecPointsWorld.size(); p++) - { - vec2d line_r1s = { pos.x, pos.y }; - vec2d line_r1e = { vecPointsWorld[p].x, vecPointsWorld[p].y }; - - vec2d displacement = { 0,0 }; - - for (size_t q = 0; q < r2.vecPointsWorld.size(); q++) - { - vec2d line_r2s = { r2.vecPointsWorld[q].x, r2.vecPointsWorld[q].y }; - vec2d line_r2e = { r2.vecPointsWorld[(q + 1) % r2.vecPointsWorld.size()].x, r2.vecPointsWorld[(q + 1) % r2.vecPointsWorld.size()].y }; - - // Standard "off the shelf" line segment intersection - float h = (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r1e.y) - (line_r1s.x - line_r1e.x) * (line_r2e.y - line_r2s.y); - float t1 = ((line_r2s.y - line_r2e.y) * (line_r1s.x - line_r2s.x) + (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r2s.y)) / h; - float t2 = ((line_r1s.y - line_r1e.y) * (line_r1s.x - line_r2s.x) + (line_r1e.x - line_r1s.x) * (line_r1s.y - line_r2s.y)) / h; - - if (t1 >= 0.0f && t1 <= 1.0f && t2 >= 0.0f && t2 <= 1.0f) - { - if (bResolveStatic) - { - displacement.x += (1.0f - t1) * (line_r1e.x - line_r1s.x); - displacement.y += (1.0f - t1) * (line_r1e.y - line_r1s.y); - bCollision = true; - } - else - return true; - } - } - - pos.x -= displacement.x; - pos.y -= displacement.y; - } - - // Check diagonals of R2 against edges of R1 - for (size_t p = 0; p < r2.vecPointsWorld.size(); p++) - { - vec2d line_r1s = { r2.pos.x, r2.pos.y }; - vec2d line_r1e = { r2.vecPointsWorld[p].x, r2.vecPointsWorld[p].y }; - - vec2d displacement = { 0,0 }; - - for (size_t q = 0; q < vecPointsWorld.size(); q++) - { - vec2d line_r2s = { vecPointsWorld[q].x, vecPointsWorld[q].y }; - vec2d line_r2e = { vecPointsWorld[(q + 1) % vecPointsWorld.size()].x, vecPointsWorld[(q + 1) % vecPointsWorld.size()].y }; - - // Standard "off the shelf" line segment intersection - float h = (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r1e.y) - (line_r1s.x - line_r1e.x) * (line_r2e.y - line_r2s.y); - float t1 = ((line_r2s.y - line_r2e.y) * (line_r1s.x - line_r2s.x) + (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r2s.y)) / h; - float t2 = ((line_r1s.y - line_r1e.y) * (line_r1s.x - line_r2s.x) + (line_r1e.x - line_r1s.x) * (line_r1s.y - line_r2s.y)) / h; - - if (t1 >= 0.0f && t1 <= 1.0f && t2 >= 0.0f && t2 <= 1.0f) - { - if (bResolveStatic) - { - displacement.x += (1.0f - t1) * (line_r1e.x - line_r1s.x); - displacement.y += (1.0f - t1) * (line_r1e.y - line_r1s.y); - bCollision = true; - } - else - return true; - } - } - - - pos.x += displacement.x; - pos.y += displacement.y; - } - - return bCollision; - } - - std::vector meshTris; - std::vector vecPointsModel; - std::vector vecPointsWorld; - olc::GFX3D::vec3d pos; - - float fWidth; - float fHeight; - float fOriginX; - float fOriginY; - float fAngle; - }; - - bool LoadAssets(); - - std::map mapAssetTextures; - std::map mapAssetMeshes; - std::map mapAssetTransform; - - // Camera variables - olc::GFX3D::vec3d vCamera = { 0.0f, 0.0f, -3.0f }; - olc::GFX3D::vec3d vUp = { 0.0f, 1.0f, 0.0f }; - olc::GFX3D::vec3d vEye = { 0.0f, 0.0f, -3.0f }; - olc::GFX3D::vec3d vLookDir = { 0.0f, 0.0f, 1.0f }; - - // Ray Casting Parameters - olc::vf2d viewWorldTopLeft; - olc::vf2d viewWorldBottomRight; - - // Cloud movement variables - float fCloudOffsetX = 0.0f; - float fCloudOffsetY = 0.0f; - - // Mouse Control - olc::vf2d vOffset = { 0.0f, 0.0f }; - olc::vf2d vStartPan = { 0.0f, 0.0f }; - olc::vf2d vMouseOnGround = { 0.0f, 0.0f }; - float fScale = 1.0f; - - olc::vf2d GetMouseOnGround(const olc::vf2d &vMouseScreen); - - //cVehicle car; - olc::vf2d carvel; - olc::vf2d carpos; - float fSpeed = 0.0f; - float fAngle = 0.0f; - - std::list listAutomata; // Holds all automata, note its a pointer because we use polymorphism - - void SpawnPedestrian(int x, int y); - void SpawnVehicle(int x, int y); - - //cGameObjectQuad *goCar = nullptr; - //cGameObjectQuad *goObstacle = nullptr; - - //std::vector vecObstacles; - - cCityMap *pCity = nullptr; - - float fGlobalTime = 0.0f; - - // Editing Utilities - bool bEditMode = true; - int nMouseX = 0; - int nMouseY = 0; - - struct sCellLoc { int x, y; }; - std::unordered_set setSelectedCells; - - //std::list listDecalSmoke; - - //int nTrafficState = 0; - - void DoEditMode(float fElapsedTime); -}; - diff --git a/Videos/CarCrimeCity/Part2/cCell.cpp b/Videos/CarCrimeCity/Part2/cCell.cpp deleted file mode 100644 index 9f37d8d..0000000 --- a/Videos/CarCrimeCity/Part2/cCell.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "cCell.h" - -#include "cCityMap.h" -#include "olcPixelGameEngine.h" -#include - -cCell::cCell() -{ -} - - -cCell::~cCell() -{ - // Cells own a list of automata navigation tracks - // but this will be destroyed when the cell is deleted -} - -cCell::cCell(cCityMap* map, int x, int y) -{ - pMap = map; - nWorldX = x; - nWorldY = y; - nCellType = CELL_BLANK; - - // Connect internal nodes - for (int i = 0; i < 49; i++) - pNaviNodes[i] = pMap->GetAutoNodeBase(x, y) + i; - - // Link cell into maps node pool - if (y > 0) - { - for (int i = 0; i < 7; i++) - pNaviNodes[i] = pMap->GetAutoNodeBase(x, y - 1) + 42 + i; - } - else - { - for (int i = 0; i < 7; i++) - pNaviNodes[i] = nullptr; - } - - if (x > 0) - { - // Link West side - for (int i = 0; i < 7; i++) - pNaviNodes[i * 7] = pMap->GetAutoNodeBase(x - 1, y) + 6 + i * 7; - } - else - { - for (int i = 0; i < 7; i++) - pNaviNodes[i * 7] = nullptr; - } - - // South Side - if (y < pMap->GetHeight() - 1) - { - - } - else - { - for (int i = 0; i < 7; i++) - pNaviNodes[42 + i] = nullptr; - } - - // East Side - if (x < pMap->GetWidth() - 1) - { - } - else - { - for (int i = 0; i < 7; i++) - pNaviNodes[6 + i * 7] = nullptr; - } - - // Unused Nodes - pNaviNodes[9] = nullptr; - pNaviNodes[11] = nullptr; - pNaviNodes[15] = nullptr; - pNaviNodes[19] = nullptr; - pNaviNodes[29] = nullptr; - pNaviNodes[33] = nullptr; - pNaviNodes[37] = nullptr; - pNaviNodes[39] = nullptr; - pNaviNodes[0] = nullptr; - pNaviNodes[6] = nullptr; - pNaviNodes[42] = nullptr; - pNaviNodes[48] = nullptr; - -} - - -bool cCell::LinkAssets(std::map &mapTextures, std::map &mapMesh, std::map &mapTransforms) -{ - return false; -} - -bool cCell::Update(float fElapsedTime) -{ - return false; -} - -bool cCell::DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe) -{ - return false; -} - -bool cCell::DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe) -{ - return false; -} - -bool cCell::DrawDebug(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe) -{ - - - return false; -} - -void cCell::CalculateAdjacency() -{ - -} diff --git a/Videos/CarCrimeCity/Part2/cCell.h b/Videos/CarCrimeCity/Part2/cCell.h deleted file mode 100644 index 4f27a29..0000000 --- a/Videos/CarCrimeCity/Part2/cCell.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include - -#include "olcPixelGameEngine.h" -#include "olcPGEX_Graphics3D.h" - -#include "cAutomata.h" - - -class cCityMap; - -enum CellType -{ - CELL_BLANK, - CELL_GRASS, - CELL_CONCRETE, - CELL_WATER, - CELL_BUILDING, - CELL_ROAD, - CELL_PAVEMENT, -}; - -class cCell -{ -public: - cCell(); - cCell(cCityMap* map, int x, int y); - ~cCell(); - -protected: - cCityMap* pMap = nullptr; - -public: - int nWorldX = 0; - int nWorldY = 0; - bool bSolid = false; - CellType nCellType = CELL_BLANK; - - // This cell may actuall be occupied by a multi-cell body - // so this pointer points to the host cell that contains - // that body - cCell* pHostCell = nullptr; - - // Each cell links to 20 automata transport nodes, 5 on each side - cAuto_Node* pNaviNodes[49]; - - // Each cell can have a number of automata transport tracks, it owns them - // These connect nodes together as determined by the cell - std::list listTracks; - -public: - virtual void CalculateAdjacency(); - virtual bool LinkAssets(std::map &mapTextures, std::map &mapMesh, std::map &mapTransforms); - virtual bool Update(float fElapsedTime); - virtual bool DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe); - virtual bool DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe); - virtual bool DrawDebug(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe); -}; - diff --git a/Videos/CarCrimeCity/Part2/cCell_Building.cpp b/Videos/CarCrimeCity/Part2/cCell_Building.cpp deleted file mode 100644 index 6635163..0000000 --- a/Videos/CarCrimeCity/Part2/cCell_Building.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "cCell_Building.h" - - - -cCell_Building::cCell_Building(const std::string &name, cCityMap* map, int x, int y) : cCell(map, x, y) -{ - sName = name; -} - - -cCell_Building::~cCell_Building() -{ -} - -void cCell_Building::CalculateAdjacency() -{ -} - -bool cCell_Building::LinkAssets(std::map& mapTextures, std::map& mapMesh, std::map &mapTransforms) -{ - texture = mapTextures[sName]; - mesh = mapMesh[sName]; - transform = mapTransforms[sName]; - return false; -} - -bool cCell_Building::Update(float fElapsedTime) -{ - return false; -} - -bool cCell_Building::DrawBase(olc::PixelGameEngine * pge, olc::GFX3D::PipeLine & pipe) -{ - olc::GFX3D::mat4x4 matTranslate = olc::GFX3D::Math::Mat_MakeTranslation((float)nWorldX, (float)nWorldY, 0.0f); - olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MultiplyMatrix(transform, matTranslate); - pipe.SetTransform(matWorld); - if (texture != nullptr) - { - pipe.SetTexture(texture); - pipe.Render(mesh->tris,olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_LIGHTS); - } - else - { - pipe.Render(mesh->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_FLAT | olc::GFX3D::RENDER_LIGHTS); - } - return false; -} - -bool cCell_Building::DrawAlpha(olc::PixelGameEngine * pge, olc::GFX3D::PipeLine & pipe) -{ - - return false; -} diff --git a/Videos/CarCrimeCity/Part2/cCell_Building.h b/Videos/CarCrimeCity/Part2/cCell_Building.h deleted file mode 100644 index 874ab42..0000000 --- a/Videos/CarCrimeCity/Part2/cCell_Building.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "cCell.h" -#include "olcPGEX_Graphics3D.h" - - -class cCell_Building : public cCell -{ -public: - cCell_Building(const std::string &name, cCityMap* map, int x, int y); - ~cCell_Building(); - -private: - std::string sName; - olc::Sprite* texture = nullptr; - olc::GFX3D::mesh* mesh = nullptr; - olc::GFX3D::mat4x4 transform; - -public: - virtual void CalculateAdjacency(); - virtual bool LinkAssets(std::map &mapTextures, std::map &mapMesh, std::map &mapTransforms); - virtual bool Update(float fElapsedTime); - virtual bool DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe); - virtual bool DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe); -}; - diff --git a/Videos/CarCrimeCity/Part2/cCell_Plane.cpp b/Videos/CarCrimeCity/Part2/cCell_Plane.cpp deleted file mode 100644 index a0a3da7..0000000 --- a/Videos/CarCrimeCity/Part2/cCell_Plane.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "cCell_Plane.h" - - - -cCell_Plane::cCell_Plane(cCityMap* map, int x, int y, CELL_PLANE type) : cCell(map, x, y) -{ - bSolid = false; - nType = type; - if (nType == PLANE_GRASS) nCellType = CELL_GRASS; - if (nType == PLANE_ASPHALT) nCellType = CELL_PAVEMENT; -} - - -cCell_Plane::~cCell_Plane() -{ -} - -bool cCell_Plane::LinkAssets(std::map &mapTextures, std::map &mapMesh, std::map &mapTransforms) -{ - sprGrass = mapTextures["Grass"]; - sprPavement = mapTextures["Pavement"]; - meshUnitQuad = mapMesh["UnitQuad"]; - return true; -} - -bool cCell_Plane::Update(float fElapsedTime) -{ - return false; -} - -bool cCell_Plane::DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe) -{ - olc::GFX3D::mat4x4 matWorld; - matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)nWorldX, (float)nWorldY, 0.0f); - pipe.SetTransform(matWorld); - - if(nType == PLANE_GRASS) - pipe.SetTexture(sprGrass); - else - pipe.SetTexture(sprPavement); - - pipe.Render(meshUnitQuad->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED); - return false; -} - -bool cCell_Plane::DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe) -{ - return false; -} diff --git a/Videos/CarCrimeCity/Part2/cCell_Plane.h b/Videos/CarCrimeCity/Part2/cCell_Plane.h deleted file mode 100644 index 252296c..0000000 --- a/Videos/CarCrimeCity/Part2/cCell_Plane.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include "cCell.h" -#include "olcPixelGameEngine.h" -#include "olcPGEX_Graphics3D.h" -#include - - -enum CELL_PLANE -{ - PLANE_GRASS, - PLANE_ASPHALT -}; - -class cCell_Plane : public cCell -{ -public: - cCell_Plane(cCityMap* map, int x, int y, CELL_PLANE type); - ~cCell_Plane(); - -protected: - CELL_PLANE nType = PLANE_GRASS; - -private: - olc::GFX3D::mesh* meshUnitQuad = nullptr; - olc::Sprite* sprGrass = nullptr; - olc::Sprite* sprPavement = nullptr; - -public: - virtual bool LinkAssets(std::map &mapTextures, std::map &mapMesh, std::map &mapTransforms); - virtual bool Update(float fElapsedTime); - virtual bool DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe); - virtual bool DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe); -}; - diff --git a/Videos/CarCrimeCity/Part2/cCell_Road.cpp b/Videos/CarCrimeCity/Part2/cCell_Road.cpp deleted file mode 100644 index 5887e07..0000000 --- a/Videos/CarCrimeCity/Part2/cCell_Road.cpp +++ /dev/null @@ -1,812 +0,0 @@ -#include "cCell_Road.h" -#include "cCityMap.h" - - -cCell_Road::cCell_Road(cCityMap* map, int x, int y) : cCell(map, x, y) -{ - bSolid = false; - nCellType = CELL_ROAD; -} - -cCell_Road::~cCell_Road() -{ -} - -void cCell_Road::CalculateAdjacency() -{ - - // Calculate suitable road junction type - auto r = [&](int i, int j) - { - return (pMap->Cell(nWorldX + i, nWorldY + j) != nullptr && pMap->Cell(nWorldX + i, nWorldY + j)->nCellType == CELL_ROAD); - }; - - if (r(0, -1) && r(0, +1) && !r(-1, 0) && !r(+1, 0)) nRoadType = ROAD_V; - if (!r(0, -1) && !r(0, +1) && r(-1, 0) && r(+1, 0)) nRoadType =ROAD_H; - if (!r(0, -1) && r(0, +1) && !r(-1, 0) && r(+1, 0)) nRoadType = ROAD_C1; - if (!r(0, -1) && r(0, +1) && r(-1, 0) && r(+1, 0)) nRoadType =ROAD_T1; - if (!r(0, -1) && r(0, +1) && r(-1, 0) && !r(+1, 0)) nRoadType = ROAD_C2; - if (r(0, -1) && r(0, +1) && !r(-1, 0) && r(+1, 0)) nRoadType = ROAD_T2; - if (r(0, -1) && r(0, +1) && r(-1, 0) && r(+1, 0)) nRoadType = ROAD_X; - if (r(0, -1) && r(0, +1) && r(-1, 0) && !r(+1, 0)) nRoadType = ROAD_T3; - if (r(0, -1) && !r(0, +1) && !r(-1, 0) && r(+1, 0)) nRoadType = ROAD_C3; - if (r(0, -1) && !r(0, +1) && r(-1, 0) && r(+1, 0)) nRoadType = ROAD_T4; - if (r(0, -1) && !r(0, +1) && r(-1, 0) && !r(+1, 0)) nRoadType = ROAD_C4; - - // Add navigation tracks based on type - - auto AddTrack = [&](int n1, int n2) -> cAuto_Track* - { - if (pNaviNodes[n1] == nullptr || pNaviNodes[n2] == nullptr) - { - // Can't add track - return nullptr; - } - else - { - // Nodes exist so add track - cAuto_Track t; - t.node[0] = pNaviNodes[n1]; - t.node[1] = pNaviNodes[n2]; - t.cell = this; - t.fTrackLength = (pNaviNodes[n1]->pos - pNaviNodes[n2]->pos).mag(); - listTracks.push_back(t); - - // Add pointers to track to start and end nodes - pNaviNodes[n1]->listTracks.push_back(&listTracks.back()); - pNaviNodes[n2]->listTracks.push_back(&listTracks.back()); - - return &listTracks.back(); - } - }; - - // Ensure list of tracks for this cell is clear - listTracks.clear(); - - // Add tracks depending on junction type - pSafePedestrianTrack = nullptr; - pSafeCarTrack = nullptr; - pSafeChaseTrack = nullptr; - - // Add Pedestrian Tracks - switch (nRoadType) - { - case ROAD_H: pSafePedestrianTrack = AddTrack(7, 13); AddTrack(41, 35); break; - case ROAD_V: pSafePedestrianTrack = AddTrack(1, 43); AddTrack(5, 47); break; - - case ROAD_C1: pSafePedestrianTrack = AddTrack(43, 8); AddTrack(8, 13); AddTrack(47, 40); AddTrack(40, 41); break; - case ROAD_C2: AddTrack(7, 12); AddTrack(12, 47); pSafePedestrianTrack = AddTrack(35, 36); AddTrack(36, 43); break; - case ROAD_C3: AddTrack(1, 36); pSafePedestrianTrack = AddTrack(36, 41); AddTrack(5, 12); AddTrack(12, 13); break; - case ROAD_C4: AddTrack(35, 40); AddTrack(40, 5); pSafePedestrianTrack = AddTrack(7, 8); AddTrack(8, 1); break; - - case ROAD_T1: pSafePedestrianTrack = AddTrack(7, 8); AddTrack(8, 12); AddTrack(12, 13); AddTrack(35, 36); AddTrack(36, 38); AddTrack(38, 40); AddTrack(40, 41); AddTrack(8, 22); AddTrack(22, 36); AddTrack(36, 43); AddTrack(12, 26); AddTrack(26, 40); AddTrack(40, 47); break; - case ROAD_T2: pSafePedestrianTrack = AddTrack(1, 8); AddTrack(8, 36); AddTrack(36, 43); AddTrack(5, 12); AddTrack(12, 26); AddTrack(26, 40); AddTrack(40, 47); AddTrack(8, 10); AddTrack(10, 12); AddTrack(12, 13); AddTrack(36, 38), AddTrack(38, 40); AddTrack(40, 41); break; - case ROAD_T3: pSafePedestrianTrack = AddTrack(5, 12); AddTrack(12, 40); AddTrack(40, 47); AddTrack(1, 8); AddTrack(8, 22); AddTrack(22, 36); AddTrack(36, 43); AddTrack(12, 10); AddTrack(10, 8); AddTrack(8, 7); AddTrack(40, 38); AddTrack(38, 36); AddTrack(36, 35); break; - case ROAD_T4: pSafePedestrianTrack = AddTrack(35, 36); AddTrack(36, 40); AddTrack(40, 41); AddTrack(7, 8); AddTrack(8, 10); AddTrack(10, 12); AddTrack(12, 13); AddTrack(36, 22); AddTrack(22, 8); AddTrack(8, 1); AddTrack(40, 26); AddTrack(26, 12); AddTrack(12, 5); break; - - case ROAD_X: AddTrack(35, 36); AddTrack(36, 38); AddTrack(38, 40); AddTrack(40, 41); AddTrack(7, 8); AddTrack(8, 10); AddTrack(10, 12); AddTrack(12, 13); AddTrack(36, 22); AddTrack(22, 8); AddTrack(8, 1); AddTrack(40, 26); AddTrack(26, 12); AddTrack(12, 5); pSafePedestrianTrack = AddTrack(36, 43); AddTrack(40, 47); break; - } - - - // Add Chase Tracks - switch (nRoadType) - { - case ROAD_H: AddTrack(21, 27); break; - case ROAD_V: AddTrack(3, 45); break; - - case ROAD_C1: AddTrack(45, 24); AddTrack(24, 27); break; - case ROAD_C2: AddTrack(21, 24); AddTrack(24, 45); break; - case ROAD_C3: AddTrack(3, 24); AddTrack(24, 27); break; - case ROAD_C4: AddTrack(21, 24); AddTrack(24, 3); break; - - case ROAD_T1: AddTrack(21, 24); AddTrack(24, 27); AddTrack(24, 45); break; - case ROAD_T2: AddTrack(3, 24); AddTrack(24, 45); AddTrack(24, 27); break; - case ROAD_T3: AddTrack(3, 24); AddTrack(24, 45); AddTrack(24, 21); break; - case ROAD_T4: AddTrack(21, 24); AddTrack(24, 27); AddTrack(24, 3); break; - - case ROAD_X: AddTrack(3, 24); AddTrack(27, 24); AddTrack(45, 24); AddTrack(21, 24); break; - } - - - //// Road traffic tracks - switch (nRoadType) - { - case ROAD_H: pSafeCarTrack = AddTrack(14, 20); AddTrack(28, 34); break; - case ROAD_V: AddTrack(2, 44); pSafeCarTrack = AddTrack(4, 46); break; - - case ROAD_C1: pSafeCarTrack = AddTrack(44, 16); AddTrack(16, 20); AddTrack(46, 32); AddTrack(32, 34); break; - case ROAD_C2: pSafeCarTrack = AddTrack(14, 18); AddTrack(18, 46); AddTrack(28, 30); AddTrack(30, 44); break; - case ROAD_C3: AddTrack(2, 30); AddTrack(30, 34); pSafeCarTrack = AddTrack(4, 18); AddTrack(18, 20); break; - case ROAD_C4: AddTrack(2, 16); AddTrack(16, 14); pSafeCarTrack = AddTrack(4, 32); AddTrack(32, 28); break; - - - case ROAD_T1: AddTrack(14, 16); AddTrack(16, 18); AddTrack(18, 20); AddTrack(28, 30); AddTrack(30, 32); AddTrack(32, 34); - AddTrack(16, 30); AddTrack(30, 44); AddTrack(18, 32); AddTrack(32, 46); break; - - case ROAD_T4: AddTrack(14, 16); AddTrack(16, 18); AddTrack(18, 20); AddTrack(28, 30); AddTrack(30, 32); AddTrack(32, 34); - AddTrack(16, 30); AddTrack(16, 2); AddTrack(18, 32); AddTrack(18, 4); break; - - case ROAD_T2: AddTrack(2, 16); AddTrack(16, 30); AddTrack(30, 44); AddTrack(4, 18); AddTrack(18, 32); AddTrack(32, 46); - AddTrack(16, 18); AddTrack(18, 20); AddTrack(30, 32); AddTrack(32, 34); break; - - case ROAD_T3: AddTrack(2, 16); AddTrack(16, 30); AddTrack(30, 44); AddTrack(4, 18); AddTrack(18, 32); AddTrack(32, 46); - AddTrack(14, 16); AddTrack(16, 18); AddTrack(28, 30); AddTrack(30, 32); break; - - case ROAD_X: - AddTrack(2, 16); AddTrack(16, 30); AddTrack(30, 44); AddTrack(4, 18); AddTrack(18, 32); AddTrack(32, 46); - AddTrack(14, 16); AddTrack(16, 18); AddTrack(18, 20); AddTrack(28, 30); AddTrack(30, 32); AddTrack(32, 34); break; - } - - - // Stop Patterns, here we go, loads of data... :( - - // .PO.OP. - // PP.P.PP - // O.O.O.O - // .P...P. - // O.O.O.O - // PP.P.PP - // .PO.OP. - - // .PO.OP. - // PP.P.PP - // O.X.X.O - // .P...P. - // O.X.X.O - // PP.P.PP - // .PO.OP. - - // .PO.OP. - // PP.X.PP - // O.X.X.O - // .X...X. - // O.X.X.O - // PP.X.PP - // .PO.OP. - - auto stopmap = [&](const std::string &s) - { - StopPattern p; - for (size_t i = 0; i < s.size(); i++) - p.bStop[i] = (s[i] == 'X'); - return p; - }; - - switch (nRoadType) - { - case ROAD_H: - case ROAD_V: - case ROAD_C1: - case ROAD_C2: - case ROAD_C3: - case ROAD_C4: - // Allow all - /*vStopPattern.push_back( - stopmap( - ".PO.OP." - "PP.P.PP" - "O.O.O.O" - ".P...P." - "O.O.O.O" - "PP.P.PP" - ".PO.OP."));*/ - break; - - case ROAD_X: - // Allow Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.X.X.X" - ".P...P." - "X.X.X.X" - "PP.P.PP" - ".PX.XP.")); - // Drain Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.X.PP" - "X.X.X.X" - ".X...X." - "X.X.X.X" - "PP.X.PP" - ".PX.XP.")); - // Allow West Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "O.O.O.O" - ".X...X." - "X.X.O.X" - "PP.X.PP" - ".PX.OP.")); - // Drain West Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.O.O" - ".X...X." - "X.X.O.X" - "PP.X.PP" - ".PX.OP.")); - // Allow North Traffic - vStopPattern.push_back( - stopmap( - ".PX.OP." - "PP.X.PP" - "X.X.O.O" - ".X...X." - "O.O.O.X" - "PP.X.PP" - ".PX.OP.")); - // Drain North Traffic - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.X.PP" - "X.X.O.O" - ".X...X." - "O.O.O.X" - "PP.X.PP" - ".PX.OP.")); - // Allow Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.X.X.X" - ".P...P." - "X.X.X.X" - "PP.P.PP" - ".PX.XP.")); - // Drain Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.X.PP" - "X.X.X.X" - ".X...X." - "X.X.X.X" - "PP.X.PP" - ".PX.XP.")); - // Allow EAST Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.X.X" - ".X...X." - "O.O.O.O" - "PP.X.PP" - ".PX.OP.")); - // Drain East Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.X.X" - ".X...X." - "O.O.O.X" - "PP.X.PP" - ".PX.OP.")); - // Allow SOUTH Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.O.O" - ".X...X." - "O.O.X.X" - "PP.X.PP" - ".PO.XP.")); - // Drain SOUTH Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.O.O" - ".X...X." - "O.O.X.X" - "PP.X.PP" - ".PX.XP.")); - - break; - - case ROAD_T1: - // Allow Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.X.X.X" - ".P...P." - "X.X.X.X" - "PP.P.PP" - ".PX.XP.")); - // Drain Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.X.X.X" - ".X...X." - "X.X.X.X" - "PP.X.PP" - ".PX.XP.")); - // Allow West Traffic - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "O.O.O.O" - ".X...X." - "X.X.O.X" - "PP.X.PP" - ".PX.OP.")); - // Drain West Traffic - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.O.O.O" - ".X...X." - "X.X.O.X" - "PP.X.PP" - ".PX.OP.")); - // Allow Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.X.X.X" - ".P...P." - "X.X.X.X" - "PP.P.PP" - ".PX.XP.")); - // Drain Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.X.PP" - "X.X.X.X" - ".X...X." - "X.X.X.X" - "PP.X.PP" - ".PX.XP.")); - // Allow EAST Traffic - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.X.X.X" - ".X...X." - "O.O.O.O" - "PP.X.PP" - ".PX.OP.")); - // Drain East Traffic - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.X.X.X" - ".X...X." - "O.O.O.X" - "PP.X.PP" - ".PX.OP.")); - // Allow SOUTH Traffic - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.O.O.O" - ".X...X." - "O.O.X.X" - "PP.X.PP" - ".PO.XP.")); - // Drain SOUTH Traffic - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.O.O.O" - ".X...X." - "O.O.X.X" - "PP.X.PP" - ".PX.XP.")); - break; - - case ROAD_T2: - // Allow Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.X.X.X" - ".P...P." - "X.X.X.X" - "PP.P.PP" - ".PX.XP.")); - // Drain Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.X.PP" - "X.X.X.X" - ".P...X." - "X.X.X.X" - "PP.X.PP" - ".PX.XP.")); - // Allow North Traffic - vStopPattern.push_back( - stopmap( - ".PX.OP." - "PP.X.PP" - "X.X.O.O" - ".P...X." - "X.X.O.X" - "PP.X.PP" - ".PX.OP.")); - // Drain North Traffic - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.X.PP" - "X.X.O.O" - ".P...X." - "X.X.O.X" - "PP.X.PP" - ".PX.OP.")); - // Allow Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.X.X.X" - ".P...P." - "X.X.X.X" - "PP.P.PP" - ".PX.XP.")); - // Drain Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.X.PP" - "X.X.X.X" - ".X...X." - "X.X.X.X" - "PP.X.PP" - ".PX.XP.")); - // Allow EAST Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.X.X" - ".P...X." - "X.O.O.O" - "PP.X.PP" - ".PX.OP.")); - // Drain East Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.X.X" - ".P...X." - "X.O.O.X" - "PP.X.PP" - ".PX.OP.")); - // Allow SOUTH Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.O.O" - ".P...X." - "X.O.X.X" - "PP.X.PP" - ".PO.XP.")); - // Drain SOUTH Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.O.O" - ".P...X." - "X.O.X.X" - "PP.X.PP" - ".PX.XP.")); - break; - case ROAD_T3: - // Allow Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.X.X.X" - ".P...P." - "X.X.X.X" - "PP.P.PP" - ".PX.XP.")); - // Drain Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.X.PP" - "X.X.X.X" - ".X...P." - "X.X.X.X" - "PP.X.PP" - ".PX.XP.")); - // Allow West Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "O.O.O.X" - ".X...P." - "X.X.O.X" - "PP.X.PP" - ".PX.OP.")); - // Drain West Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.O.X" - ".X...P." - "X.X.O.X" - "PP.X.PP" - ".PX.OP.")); - // Allow Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.X.X.X" - ".P...P." - "X.X.X.X" - "PP.P.PP" - ".PX.XP.")); - // Drain Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.X.PP" - "X.X.X.X" - ".X...X." - "X.X.X.X" - "PP.X.PP" - ".PX.XP.")); - // Allow North Traffic - vStopPattern.push_back( - stopmap( - ".PX.OP." - "PP.X.PP" - "X.X.O.X" - ".X...P." - "O.O.O.X" - "PP.X.PP" - ".PX.OP.")); - // Drain North Traffic - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.X.PP" - "X.X.O.X" - ".X...P." - "O.O.O.X" - "PP.X.PP" - ".PX.OP.")); - - // Allow SOUTH Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.X.X" - ".X...P." - "O.O.X.X" - "PP.X.PP" - ".PO.XP.")); - // Drain SOUTH Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.X.X" - ".X...P." - "O.O.X.X" - "PP.X.PP" - ".PX.XP.")); - break; - - case ROAD_T4: - // Allow Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.X.X.X" - ".P...P." - "X.X.X.X" - "PP.P.PP" - ".PX.XP.")); - // Drain Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.X.PP" - "X.X.X.X" - ".X...X." - "X.X.X.X" - "PP.P.PP" - ".PX.XP.")); - // Allow West Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "O.O.O.O" - ".X...X." - "X.X.X.X" - "PP.P.PP" - ".PX.XP.")); - // Drain West Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.O.O" - ".X...X." - "X.X.X.X" - "PP.P.PP" - ".PX.XP.")); - // Allow North Traffic - vStopPattern.push_back( - stopmap( - ".PX.OP." - "PP.X.PP" - "X.X.O.O" - ".X...X." - "O.O.O.X" - "PP.P.PP" - ".PX.XP.")); - // Drain North Traffic - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.X.PP" - "X.X.O.O" - ".X...X." - "O.O.O.X" - "PP.P.PP" - ".PX.XP.")); - // Allow Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.P.PP" - "X.X.X.X" - ".P...P." - "X.X.X.X" - "PP.P.PP" - ".PX.XP.")); - // Drain Pedestrians - vStopPattern.push_back( - stopmap( - ".PX.XP." - "PP.X.PP" - "X.X.X.X" - ".X...X." - "X.X.X.X" - "PP.X.PP" - ".PX.XP.")); - // Allow EAST Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.X.X" - ".X...X." - "O.O.O.O" - "PP.P.PP" - ".PX.XP.")); - // Drain East Traffic - vStopPattern.push_back( - stopmap( - ".PO.XP." - "PP.X.PP" - "X.O.X.X" - ".X...X." - "O.O.O.X" - "PP.P.PP" - ".PX.XP.")); - break; - - - } - -} - -bool cCell_Road::LinkAssets(std::map& mapTextures, std::map& mapMesh, std::map &mapTransforms) -{ - meshUnitQuad = mapMesh["UnitQuad"]; - sprRoadTex[ROAD_V] = mapTextures["Road_V"]; - sprRoadTex[ROAD_H] = mapTextures["Road_H"]; - sprRoadTex[ROAD_C1] = mapTextures["Road_C1"]; - sprRoadTex[ROAD_T1] = mapTextures["Road_T1"]; - sprRoadTex[ROAD_C2] = mapTextures["Road_C2"]; - sprRoadTex[ROAD_T2] = mapTextures["Road_T2"]; - sprRoadTex[ROAD_X] = mapTextures["Road_X"]; - sprRoadTex[ROAD_T3] = mapTextures["Road_T3"]; - sprRoadTex[ROAD_C3] = mapTextures["Road_C3"]; - sprRoadTex[ROAD_T4] = mapTextures["Road_T4"]; - sprRoadTex[ROAD_C4] = mapTextures["Road_C4"]; - return false; -} - -bool cCell_Road::Update(float fElapsedTime) -{ - if (vStopPattern.empty()) - return false; - - fStopPatternTimer += fElapsedTime; - if (fStopPatternTimer >= 5.0f) - { - fStopPatternTimer -= 5.0f; - nCurrentStopPattern++; - nCurrentStopPattern %= vStopPattern.size(); - for (int i = 0; i < 49; i++) - if(pNaviNodes[i] != nullptr) - pNaviNodes[i]->bBlock = vStopPattern[nCurrentStopPattern].bStop[i]; - } - - - return false; -} - -bool cCell_Road::DrawBase(olc::PixelGameEngine* pge, olc::GFX3D::PipeLine & pipe) -{ - olc::GFX3D::mat4x4 matWorld; - matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)nWorldX, (float)nWorldY, 0.0f); - pipe.SetTransform(matWorld); - pipe.SetTexture(sprRoadTex[nRoadType]); - pipe.Render(meshUnitQuad->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED); - return false; -} - -bool cCell_Road::DrawAlpha(olc::PixelGameEngine* pge, olc::GFX3D::PipeLine & pipe) -{ - return false; -} - -bool cCell_Road::DrawDebug(olc::PixelGameEngine* pge, olc::GFX3D::PipeLine & pipe) -{ - - - - // Draw Automata navigation tracks - for (auto &track : listTracks) - { - olc::GFX3D::vec3d p1 = { track.node[0]->pos.x, track.node[0]->pos.y, 0.0f }; - olc::GFX3D::vec3d p2 = { track.node[1]->pos.x, track.node[1]->pos.y, 0.0f }; - pipe.RenderLine(p1, p2, olc::CYAN); - } - - - for (int i = 0; i < 49; i++) - { - if (pNaviNodes[i] != nullptr) - { - olc::GFX3D::vec3d p1 = { pNaviNodes[i]->pos.x, pNaviNodes[i]->pos.y, 0.01f }; - pipe.RenderCircleXZ(p1, 0.03f, pNaviNodes[i]->bBlock ? olc::RED : olc::GREEN); - } - } - - return false; -} diff --git a/Videos/CarCrimeCity/Part2/cCell_Road.h b/Videos/CarCrimeCity/Part2/cCell_Road.h deleted file mode 100644 index d0f183e..0000000 --- a/Videos/CarCrimeCity/Part2/cCell_Road.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -#include "cCell.h" - -enum RoadType -{ - ROAD_H, - ROAD_V, - ROAD_C1, - ROAD_C2, - ROAD_C3, - ROAD_C4, - ROAD_T1, - ROAD_T2, - ROAD_T3, - ROAD_T4, - ROAD_X, -}; - - -class cCell_Road : public cCell -{ -public: - cCell_Road(cCityMap* map, int x, int y); - ~cCell_Road(); - -private: - struct StopPattern - { - bool bStop[49]; - }; - -private: - bool bNeighboursAreRoads[4]; - - olc::GFX3D::mesh *meshUnitQuad = nullptr; - olc::Sprite* sprRoadTex[11]; - - std::vector vStopPattern; - int nCurrentStopPattern = 0; - float fStopPatternTimer = 0.0f; -public: - RoadType nRoadType = ROAD_X; - cAuto_Track* pSafeCarTrack = nullptr; - cAuto_Track* pSafePedestrianTrack = nullptr; - cAuto_Track* pSafeChaseTrack = nullptr; - - virtual void CalculateAdjacency(); - virtual bool LinkAssets(std::map &mapTextures, std::map &mapMesh, std::map &mapTransforms); - virtual bool Update(float fElapsedTime); - virtual bool DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe); - virtual bool DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe); - virtual bool DrawDebug(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe); -}; - diff --git a/Videos/CarCrimeCity/Part2/cCell_Water.cpp b/Videos/CarCrimeCity/Part2/cCell_Water.cpp deleted file mode 100644 index 91f0fc3..0000000 --- a/Videos/CarCrimeCity/Part2/cCell_Water.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "cCell_Water.h" -#include "cCityMap.h" - - -cCell_Water::cCell_Water(cCityMap* map, int x, int y) : cCell(map, x, y) -{ - nCellType = CELL_WATER; - bNeighboursAreWater[0] = false; - bNeighboursAreWater[1] = false; - bNeighboursAreWater[2] = false; - bNeighboursAreWater[3] = false; -} - - -cCell_Water::~cCell_Water() -{ -} - -bool cCell_Water::LinkAssets(std::map& mapTextures, std::map& mapMesh, std::map &mapTransforms) -{ - meshUnitQuad = mapMesh["UnitQuad"]; - meshWalls = mapMesh["WallsOut"]; - sprWater = mapTextures["Water"]; - sprSides = mapTextures["WaterSide"]; - sprClouds = mapTextures["Clouds"]; - return false; -} - -bool cCell_Water::Update(float fElapsedTime) -{ - return false; -} - -bool cCell_Water::DrawBase(olc::PixelGameEngine * pge, olc::GFX3D::PipeLine & pipe) -{ - olc::GFX3D::mat4x4 matWorld; - matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)nWorldX, (float)nWorldY, 0.0f); - pipe.SetTransform(matWorld); - pipe.SetTexture(sprSides); - if (!bNeighboursAreWater[1]) pipe.Render(meshWalls->tris, olc::GFX3D::RENDER_LIGHTS | olc::GFX3D::RENDER_CULL_CCW | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_DEPTH, 0, 2); - if (!bNeighboursAreWater[3]) pipe.Render(meshWalls->tris, olc::GFX3D::RENDER_LIGHTS | olc::GFX3D::RENDER_CULL_CCW | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_DEPTH, 2, 2); - if (!bNeighboursAreWater[2]) pipe.Render(meshWalls->tris, olc::GFX3D::RENDER_LIGHTS | olc::GFX3D::RENDER_CULL_CCW | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_DEPTH, 4, 2); - if (!bNeighboursAreWater[0]) pipe.Render(meshWalls->tris, olc::GFX3D::RENDER_LIGHTS | olc::GFX3D::RENDER_CULL_CCW | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_DEPTH, 6, 2); - return false; -} - -bool cCell_Water::DrawAlpha(olc::PixelGameEngine * pge, olc::GFX3D::PipeLine & pipe) -{ - auto renderWater = [&](const int x, const int y, const olc::Pixel& pSource, const olc::Pixel& pDest) - { - float a = (float)(pSource.a / 255.0f) * 0.6f; - float c = 1.0f - a; - float r = a * (float)pSource.r + c * (float)pDest.r; - float g = a * (float)pSource.g + c * (float)pDest.g; - float b = a * (float)pSource.b + c * (float)pDest.b; - - a = 0.4f; - c = 1.0f - a; - olc::Pixel sky = sprClouds->GetPixel(x, y); - float sr = a * (float)sky.r + c * r; - float sg = a * (float)sky.g + c * g; - float sb = a * (float)sky.b + c * b; - - return olc::Pixel((uint8_t)sr, (uint8_t)sg, (uint8_t)sb); - }; - - pge->SetPixelMode(renderWater); - olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)nWorldX, (float)nWorldY, 0.07f); - pipe.SetTransform(matWorld); - pipe.SetTexture(sprWater); - pipe.Render(meshUnitQuad->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED); - pge->SetPixelMode(olc::Pixel::NORMAL); - return false; -} - - -void cCell_Water::CalculateAdjacency() -{ - auto r = [&](int i, int j) - { - if (pMap->Cell(nWorldX + i, nWorldY + j) != nullptr) - return pMap->Cell(nWorldX + i, nWorldY + j)->nCellType == CELL_WATER; - else - return false; - }; - - bNeighboursAreWater[0] = r(0, -1); - bNeighboursAreWater[1] = r(+1, 0); - bNeighboursAreWater[2] = r(0, +1); - bNeighboursAreWater[3] = r(-1, 0); -} \ No newline at end of file diff --git a/Videos/CarCrimeCity/Part2/cCell_Water.h b/Videos/CarCrimeCity/Part2/cCell_Water.h deleted file mode 100644 index 4ed0502..0000000 --- a/Videos/CarCrimeCity/Part2/cCell_Water.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "cCell.h" -class cCell_Water : public cCell -{ -public: - cCell_Water(cCityMap* map, int x, int y); - ~cCell_Water(); - -private: - olc::GFX3D::mesh* meshUnitQuad = nullptr; - olc::GFX3D::mesh* meshWalls = nullptr; - olc::Sprite* sprWater = nullptr; - olc::Sprite* sprSides = nullptr; - olc::Sprite* sprClouds = nullptr; - - bool bNeighboursAreWater[4]; - -public: - virtual void CalculateAdjacency(); - virtual bool LinkAssets(std::map &mapTextures, std::map &mapMesh, std::map &mapTransforms); - virtual bool Update(float fElapsedTime); - virtual bool DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe); - virtual bool DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe); -}; - diff --git a/Videos/CarCrimeCity/Part2/cCityMap.cpp b/Videos/CarCrimeCity/Part2/cCityMap.cpp deleted file mode 100644 index 712a225..0000000 --- a/Videos/CarCrimeCity/Part2/cCityMap.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include "cCityMap.h" - -#include - - - -cCityMap::cCityMap(int w, int h, std::map &mapTextures, std::map &mapMesh, std::map &mapTransforms) -{ - CreateCity(w, h, mapTextures, mapMesh, mapTransforms); -} - -cCityMap::~cCityMap() -{ - ReleaseCity(); -} - -int cCityMap::GetWidth() -{ - return nWidth; -} - -int cCityMap::GetHeight() -{ - return nHeight; -} - -cCell* cCityMap::Cell(int x, int y) -{ - if (x >= 0 && x < nWidth && y >= 0 && y < nHeight) - return pCells[y*nWidth + x]; - else - return nullptr; -} - -cCell* cCityMap::Replace(int x, int y, cCell* cell) -{ - if (cell == nullptr) - return nullptr; - - if (pCells[y * nWidth + x] != nullptr) - delete pCells[y * nWidth + x]; - - pCells[y * nWidth + x] = cell; - return cell; -} - -void cCityMap::CreateCity(int w, int h, std::map &mapTextures, std::map &mapMesh, std::map &mapTransforms) -{ - ReleaseCity(); - nWidth = w; - nHeight = h; - pCells = new cCell*[nHeight * nWidth]; - - // Create Navigation Node Pool, assumes 5 nodes on east and south - // side of each cell. The City owns these nodes, and cells in the - // city borrow them and link to them as required - pNodes = new cAuto_Node[nHeight * nWidth * 49]; - - // The cell has 49 nodes, though some are simply unused. This is less memory - // efficient certainly, but makes code more intuitive and easier to write - - for (int x = 0; x < nWidth; x++) - { - for (int y = 0; y < nHeight; y++) - { - // Nodes sit between cells, therefore each create nodes along - // the east and southern sides of the cell. This assumes that - // navigation along the top and left boundaries of the map - // will not occur. And it shouldnt, as its water - - int idx = (y * nWidth + x) * 49; - - for (int dx = 0; dx < 7; dx++) - { - float off_x = 0.0f; - switch (dx) - { - case 0: off_x = 0.000f; break; - case 1: off_x = 0.083f; break; - case 2: off_x = 0.333f; break; - case 3: off_x = 0.500f; break; - case 4: off_x = 0.667f; break; - case 5: off_x = 0.917f; break; - case 6: off_x = 1.000f; break; - } - - - for (int dy = 0; dy < 7; dy++) - { - float off_y = 0.0f; - switch (dy) - { - case 0: off_y = 0.000f; break; - case 1: off_y = 0.083f; break; - case 2: off_y = 0.333f; break; - case 3: off_y = 0.500f; break; - case 4: off_y = 0.667f; break; - case 5: off_y = 0.917f; break; - case 6: off_y = 1.000f; break; - } - - pNodes[idx + dy * 7 + dx].pos = { (float)x + off_x, (float)y + off_y }; - pNodes[idx + dy * 7 + dx].bBlock = false; - } - } - } - } - - - // Now create default Cell - for (int x = 0; x < nWidth; x++) - { - for (int y = 0; y < nHeight; y++) - { - // Default city, everything is grass - pCells[y * nWidth + x] = new cCell_Plane(this, x, y, PLANE_GRASS); - - // Give the cell the opportunity to locally reference the resources it needs - pCells[y * nWidth + x]->LinkAssets(mapTextures, mapMesh, mapTransforms); - } - } - -} - -cAuto_Node* cCityMap::GetAutoNodeBase(int x, int y) -{ - return pNodes + (y * nWidth + x) * 49; -} - -void cCityMap::RemoveAllTracks() -{ - for (int i = 0; i < nWidth * nHeight * 49; i++) - { - pNodes[i].listTracks.clear(); - } -} - -void cCityMap::ReleaseCity() -{ - for (int x = 0; x < nWidth; x++) - { - for (int y = 0; y < nHeight; y++) - { - // Erase any tracks attached to nodes - for(int i=0; i<49; i++) - Cell(x, y)->pNaviNodes[i]->listTracks.clear(); - - // Release individual cell objects - delete pCells[y * nWidth + x]; - } - } - - // Release array of cell pointers - if (pCells != nullptr) delete pCells; - - // Release array of automata navigation nodes - if (pNodes != nullptr) delete pNodes; - - nWidth = 0; - nHeight = 0; -} - - -bool cCityMap::SaveCity(std::string sFilename) -{ - /*std::ofstream file(sFilename, std::ios::out | std::ios::binary); - if (!file.is_open()) return false; - - file.write((char*)&m_nWidth, sizeof(int)); - file.write((char*)&m_nHeight, sizeof(int)); - - for (int x = 0; x < m_nWidth; x++) - { - for (int y = 0; y < m_nHeight; y++) - { - file.write((char*)Cell(x, y), sizeof(cCityCell)); - } - }*/ - - return true; -} - -bool cCityMap::LoadCity(std::string sFilename) -{ - /*std::ifstream file(sFilename, std::ios::in | std::ios::binary); - if (!file.is_open()) return false; - - int w, h; - file.read((char*)&w, sizeof(int)); - file.read((char*)&h, sizeof(int)); - CreateCity(w, h); - - for (int x = 0; x < m_nWidth; x++) - { - for (int y = 0; y < m_nHeight; y++) - { - file.read((char*)Cell(x, y), sizeof(cCityCell)); - } - }*/ - - return true; -} \ No newline at end of file diff --git a/Videos/CarCrimeCity/Part2/cCityMap.h b/Videos/CarCrimeCity/Part2/cCityMap.h deleted file mode 100644 index 43a4456..0000000 --- a/Videos/CarCrimeCity/Part2/cCityMap.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include -#include - -#include "olcPixelGameEngine.h" -#include "olcPGEX_Graphics3D.h" -#include "cCell.h" -#include "cCell_Plane.h" -#include "cCell_Water.h" -#include "cCell_Road.h" -#include "cCell_Building.h" - -/* - This class holds the definition of a map. The map data is actually - stored within this clap, as well as accessors to access the individual - map cells -*/ -class cCityMap -{ -public: - // Construct a "blank" city w units wide by h units high - cCityMap(int w, int h, std::map &mapTextures, std::map &mapMesh, std::map &mapTransforms); - - // Cleans up city, like Batman - ~cCityMap(); - -public: - // Save the current city to a file, this will overwrite an existing - // city file without warning. Returns true if successful - bool SaveCity(std::string sFilename); - - // Load a city from file and replace current city with it, retuns - // true if successful - bool LoadCity(std::string sFilename); - -public: - // Return width of city in cells - int GetWidth(); - // Return height of city in cells - int GetHeight(); - // Return a specific cell reference if inside city limits, or nullptr - cCell* Cell(int x, int y); - // Replace a specific cell - cCell* Replace(int x, int y, cCell* cell); - - cAuto_Node* GetAutoNodeBase(int x, int y); - - void RemoveAllTracks(); - -private: - int nWidth = 0; - int nHeight = 0; - cCell **pCells = nullptr; - cAuto_Node *pNodes = nullptr; - -private: - // Creates a "default" city of specified size - void CreateCity(int w, int h, std::map &mapTextures, std::map &mapMesh, std::map &mapTransforms); - // Destroy city - void ReleaseCity(); -}; - diff --git a/Videos/CarCrimeCity/Part2/cGameSettings.cpp b/Videos/CarCrimeCity/Part2/cGameSettings.cpp deleted file mode 100644 index 17842d3..0000000 --- a/Videos/CarCrimeCity/Part2/cGameSettings.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "cGameSettings.h" - - - -cGameSettings::cGameSettings() -{ -} - -cGameSettings::~cGameSettings() -{ -} - -bool cGameSettings::LoadConfigFile(std::string sFile) -{ - lua_State *L = luaL_newstate(); - luaL_openlibs(L); - - // Load game settings file - int r = luaL_loadfile(L, sFile.c_str()); - if (r != LUA_OK) - { - std::string errormsg = lua_tostring(L, -1); - std::cout << errormsg << std::endl; - return false; - } - - // Execute it - int i = lua_pcall(L, 0, LUA_MULTRET, 0); - if (i != LUA_OK) - { - std::string errormsg = lua_tostring(L, -1); - std::cout << errormsg << std::endl; - return false; - } - - lua_getglobal(L, "PixelWidth"); - if (lua_isinteger(L, -1)) cGameSettings::nPixelWidth = (int)lua_tointeger(L, -1); - - lua_getglobal(L, "PixelHeight"); - if (lua_isinteger(L, -1)) cGameSettings::nPixelHeight = (int)lua_tointeger(L, -1); - - lua_getglobal(L, "ScreenWidth"); - if (lua_isinteger(L, -1)) cGameSettings::nScreenWidth = (int)lua_tointeger(L, -1); - - lua_getglobal(L, "ScreenHeight"); - if (lua_isinteger(L, -1)) cGameSettings::nScreenHeight = (int)lua_tointeger(L, -1); - - lua_getglobal(L, "DefaultMapWidth"); - if (lua_isinteger(L, -1)) cGameSettings::nDefaultMapWidth = (int)lua_tointeger(L, -1); - - lua_getglobal(L, "DefaultMapHeight"); - if (lua_isinteger(L, -1)) cGameSettings::nDefaultMapHeight = (int)lua_tointeger(L, -1); - - lua_getglobal(L, "DefaultCityFile"); - if (lua_isstring(L, -1)) cGameSettings::sDefaultCityFile = lua_tostring(L, -1); - - lua_getglobal(L, "FullScreen"); - if (lua_isboolean(L, -1)) cGameSettings::bFullScreen = lua_toboolean(L, -1); - - - //// Load System Texture files - - // Load Texture Assets - lua_getglobal(L, "Textures"); // -1 Table "Teams" - if (lua_istable(L, -1)) - { - lua_pushnil(L); // -2 Key Nil : -1 Table "Teams" - - while (lua_next(L, -2) != 0) // -1 Table : -2 Key "TeamName" : -3 Table "Teams" - { - sAssetTexture texture; - int stage = 0; - if (lua_istable(L, -1)) - { - lua_gettable(L, -1); // -1 Table : -2 Table Value : -3 Key "TeamName" : -4 Table "Teams" - lua_pushnil(L); // -1 Key Nil : -2 Table : -3 Table Value : -4 Key "TeamName" : -5 Table "Teams" - while (lua_next(L, -2) != 0) // -1 Value "BotFile" : -2 Key Nil : -3 Table : -4 Table Value : -5 Key "TeamName" : -6 Table "Teams" - { - if (stage == 0) texture.sName = lua_tostring(L, -1); - if (stage == 1) texture.sFile = lua_tostring(L, -1); - lua_pop(L, 1); // -1 Key Nil : -2 Table : -3 Table Value : -4 Key "TeamName" : -5 Table "Teams" - stage++; - } - } - lua_pop(L, 1); // -1 Table : -2 Table Value : -3 Key "TeamName" : -4 Table "Teams" - vecAssetTextures.push_back(texture); - } - } - - auto GroupLoadAssets = [L](const std::string &group, std::vector &vec) - { - lua_getglobal(L, group.c_str()); - if (lua_istable(L, -1)) - { - lua_pushnil(L); - while (lua_next(L, -2) != 0) - { - sAssetModel model; - int stage = 0; - if (lua_istable(L, -1)) - { - lua_gettable(L, -1); - lua_pushnil(L); - while (lua_next(L, -2) != 0) - { - if (stage == 0) model.sCreator = lua_tostring(L, -1); - if (stage == 1) model.sDescription = lua_tostring(L, -1); - if (stage == 2) model.sModelOBJ = lua_tostring(L, -1); - if (stage == 3) model.sModelPNG = lua_tostring(L, -1); - - if (stage == 4) model.fRotate[0] = (float)lua_tonumber(L, -1); - if (stage == 5) model.fRotate[1] = (float)lua_tonumber(L, -1); - if (stage == 6) model.fRotate[2] = (float)lua_tonumber(L, -1); - - if (stage == 7) model.fScale[0] = (float)lua_tonumber(L, -1); - if (stage == 8) model.fScale[1] = (float)lua_tonumber(L, -1); - if (stage == 9) model.fScale[2] = (float)lua_tonumber(L, -1); - - if (stage == 10) model.fTranslate[0] = (float)lua_tonumber(L, -1); - if (stage == 11) model.fTranslate[1] = (float)lua_tonumber(L, -1); - if (stage == 12) model.fTranslate[2] = (float)lua_tonumber(L, -1); - lua_pop(L, 1); - stage++; - } - } - lua_pop(L, 1); - vec.push_back(model); - } - } - }; - - // Load Building Assets - GroupLoadAssets("Buildings", vecAssetBuildings); - - // Load Vehicle Assets - GroupLoadAssets("Vehicles", vecAssetVehicles); - - - lua_close(L); - - return true; -} - -int cGameSettings::nScreenWidth = 768; -int cGameSettings::nScreenHeight = 480; -int cGameSettings::nPixelWidth = 2; -int cGameSettings::nPixelHeight = 2; -bool cGameSettings::bFullScreen = false; - -int cGameSettings::nDefaultMapWidth = 64; -int cGameSettings::nDefaultMapHeight = 32; -std::string cGameSettings::sDefaultCityFile = ""; - -std::vector cGameSettings::vecAssetTextures; -std::vector cGameSettings::vecAssetBuildings; -std::vector cGameSettings::vecAssetVehicles; \ No newline at end of file diff --git a/Videos/CarCrimeCity/Part2/cGameSettings.h b/Videos/CarCrimeCity/Part2/cGameSettings.h deleted file mode 100644 index 7855461..0000000 --- a/Videos/CarCrimeCity/Part2/cGameSettings.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include -#include -#include - -extern "C" -{ -#include "lua533/include/lua.h" -#include "lua533/include/lauxlib.h" -#include "lua533/include/lualib.h" -} - -#ifdef _WIN32 - #pragma comment(lib, "lua533/liblua53.a") -#endif - -/* - This is a singleton that stores all the games configuration settings. - These settings are loaded on game start up and are to be considered - read-only. -*/ - -struct sAssetModel -{ - std::string sCreator; - std::string sDescription; - std::string sModelOBJ; - std::string sModelPNG; - float fRotate[3]; - float fScale[3]; - float fTranslate[3]; -}; - -struct sAssetTexture -{ - std::string sName; - std::string sFile; -}; - -class cGameSettings -{ -public: - cGameSettings(); - ~cGameSettings(); - -public: - bool LoadConfigFile(std::string sFile); - -public: - static int nScreenWidth; - static int nScreenHeight; - static int nPixelWidth; - static int nPixelHeight; - static bool bFullScreen; - - static int nDefaultMapWidth; - static int nDefaultMapHeight; - static std::string sDefaultCityFile; - - static std::vector vecAssetTextures; - static std::vector vecAssetBuildings; - static std::vector vecAssetVehicles; -}; - diff --git a/Videos/CarCrimeCity/Part2/lua53.dll b/Videos/CarCrimeCity/Part2/lua53.dll deleted file mode 100644 index 2ab8168..0000000 Binary files a/Videos/CarCrimeCity/Part2/lua53.dll and /dev/null differ diff --git a/Videos/CarCrimeCity/Part2/main.cpp b/Videos/CarCrimeCity/Part2/main.cpp deleted file mode 100644 index 7f5a732..0000000 --- a/Videos/CarCrimeCity/Part2/main.cpp +++ /dev/null @@ -1,367 +0,0 @@ -/* - Top Down City Based Car Crime Game - Part #2 - "Colin, I hope you're shooting 600+ wherever you are buddy. RIP." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Instructions: - ~~~~~~~~~~~~~ - Scroll with middle mouse wheel, TAB toggle edit mode, R to place road - P to place pavement, Q to place building, Arrow keys to drive car - - Relevant Video: https://youtu.be/fIV6P1W-wuo - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - - -#include "cGameSettings.h" -#include "cCarCrimeCity.h" - - -int main() -{ - // Load the settings singleton - cGameSettings config; - if (!config.LoadConfigFile("assets/config.lua")) - { - std::cout << "Failed to load '/assets/config.lua'" << std::endl; - std::cout << " -> Using default configuration" << std::endl; - } - - // Start the PixelGameEngine - cCarCrimeCity game; - if (game.Construct(config.nScreenWidth, config.nScreenHeight, config.nPixelWidth, config.nPixelHeight, config.bFullScreen)) - game.Start(); - - // Exit! - return 0; -} - -//#define OLC_PGE_APPLICATION -//#include "olcPixelGameEngine.h" -// -//#define OLC_PGEX_GRAPHICS3D -//#include "olcPGEX_Graphics3D.h" -// -// -// -//enum CELLTYPE -//{ -// CELL_BLANK = 0, -// CELL_GRASS = 1, -// CELL_CONCRETE = 2, -// CELL_WATER = 3, -// CELL_BUILDING = 4, -// CELL_ROAD_H = 5, -// CELL_ROAD_V = 6, -// CELL_ROAD_C1 = 7, -// CELL_ROAD_C2 = 8, -// CELL_ROAD_C3 = 9, -// CELL_ROAD_C4 = 10, -// CELL_ROAD_T1 = 11, -// CELL_ROAD_T2 = 12, -// CELL_ROAD_T3 = 13, -// CELL_ROAD_T4 = 14, -// CELL_ROAD_X = 15, -//}; -// -//struct cCityCell -//{ -// int nType = 5;// CELL_GRASS; -//}; -// -//class cCityMap -//{ -//public: -// // Construct a "blank" city w units wide by h units high -// cCityMap(int w, int h); -// -// // Cleans up city, like Batman -// ~cCityMap(); -// -// -//public: -// // Return width of city in cells -// int GetWidth(); -// // Return height of city in cells -// int GetHeight(); -// // Return a specific cell reference if inside city limits, or nullptr -// cCityCell* Cell(int x, int y); -// -//private: -// int m_nWidth = 0; -// int m_nHeight = 0; -// cCityCell *m_pCells = nullptr; -// -//private: -// // Creates a "default" city of specified size -// void CreateCity(int w, int h); -// // Destroy city -// void ReleaseCity(); -//}; -// -//cCityMap::cCityMap(int w, int h) -//{ -// CreateCity(w, h); -//} -// -//cCityMap::~cCityMap() -//{ -// //ReleaseCity(); -//} -// -//int cCityMap::GetWidth() -//{ -// return m_nWidth; -//} -// -//int cCityMap::GetHeight() -//{ -// return m_nHeight; -//} -// -//cCityCell* cCityMap::Cell(int x, int y) -//{ -// if (x >= 0 && x < m_nWidth && y >= 0 && y < m_nHeight) -// return &m_pCells[y*m_nWidth + x]; -// else -// return nullptr; -//} -// -//void cCityMap::CreateCity(int w, int h) -//{ -// //ReleaseCity(); -// m_nWidth = w; -// m_nHeight = h; -// m_pCells = new cCityCell[m_nHeight * m_nWidth]; -// -// for (int x = 0; x < m_nWidth; x++) -// { -// for (int y = 0; y < m_nHeight; y++) -// { -// //m_pCells[y*m_nWidth + x] = new cCityCell(); -// //Cell(x, y)->bRoad = false; -// //Cell(x, y)->nHeight = 0; -// //Cell(x, y)->nWorldX = x; -// //Cell(x, y)->nWorldY = y; -// Cell(x, y)->nType = CELL_GRASS; -// //Cell(x, y)->bBuilding = false; -// } -// } -//} -// -//void cCityMap::ReleaseCity() -//{ -// if (m_pCells != nullptr) delete m_pCells; -// m_nWidth = 0; -// m_nHeight = 0; -//} -// -// -//class cCarCrimeCity : public olc::PixelGameEngine -//{ -//public: -// cCarCrimeCity() -// { -// sAppName = "Car Crime City"; -// } -// -// ~cCarCrimeCity() -// { -// } -// -// bool OnUserCreate() -// { -// // Initialise PGEX 3D -// olc::GFX3D::ConfigureDisplay(); -// -// // Create Default city -// pCity = new cCityMap(64, 32);// cGameSettings::nDefaultMapWidth, cGameSettings::nDefaultMapHeight); -// -// -// // A simple flat unit quad -// meshQuad.tris = -// { -// { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::RED }, -// { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, olc::RED}, -// }; -// -// -// sprOld = new olc::Sprite("assets/system/grass1.png"); -// -// -// -// SetDrawTarget(nullptr); -// return true; -// } -// -// -// bool OnUserUpdate(float fElapsedTime) -// { -// // User Input -// if (GetKey(olc::Key::W).bHeld) vCamera.y -= 2.0f * fElapsedTime; -// if (GetKey(olc::Key::S).bHeld) vCamera.y += 2.0f * fElapsedTime; -// if (GetKey(olc::Key::A).bHeld) vCamera.x -= 2.0f * fElapsedTime; -// if (GetKey(olc::Key::D).bHeld) vCamera.x += 2.0f * fElapsedTime; -// if (GetKey(olc::Key::Z).bHeld) vCamera.z += 10.0f * fElapsedTime; -// if (GetKey(olc::Key::X).bHeld) vCamera.z -= 10.0f * fElapsedTime; -// -// -// vEye = vCamera; -// -// // Perform Ray casting to calculate visible world extents and mouse position -// olc::GFX3D::vec3d vLookTarget = olc::GFX3D::Math::Vec_Add(vEye, vLookDir); -// olc::GFX3D::mat4x4 matProj = olc::GFX3D::Math::Mat_MakeProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.5f, 1000.0f); -// olc::GFX3D::mat4x4 matView = olc::GFX3D::Math::Mat_PointAt(vEye, vLookTarget, vUp); -// -// -// -// // Render Scene -// Clear(olc::BLUE); -// olc::GFX3D::ClearDepth(); -// -// // Create rendering pipeline -// olc::GFX3D::PipeLine pipe; -// pipe.SetProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.5f, 1000.0f, 0.0f, 0.0f, (float)ScreenWidth(), (float)ScreenHeight()); -// pipe.SetCamera(vEye, vLookTarget, vUp); -// -// -// -// int nStartX = 0; -// int nEndX = pCity->GetWidth(); -// int nStartY = 0; -// int nEndY = pCity->GetHeight(); -// -// // Render Ground, Roads, Walls & Buildings -// for (int x = nStartX; x < nEndX; x++) -// { -// if (x == 15) -// int k = 7; -// -// for (int y = nStartY; y < nEndY; y++) -// { -// -// -// switch (pCity->Cell(x, y)->nType) -// { -// case CELL_GRASS: -// { -// olc::GFX3D::mat4x4 matWorld; -// matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)x, (float)y, 0.0f); -// pipe.SetTransform(matWorld); -// pipe.SetTexture(sprOld); -// //pipe.SetTexture(vecSpriteSystem[0]); -// //pipe.Render(vecMeshSystem[0].tris); -// pipe.Render(meshQuad.tris); -// //pipe.Render(vecMeshSystem[0].tris, olc::GFX3D::RENDER_FLAT); -// break; -// } -// -// -// default: -// { -// olc::GFX3D::mat4x4 matWorld; -// matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)x, (float)y, 0.0f); -// pipe.SetTransform(matWorld); -// pipe.Render(meshQuad.tris, olc::GFX3D::RENDER_WIRE); -// break; -// } -// } -// -// -// -// -// } -// } -// -// -// -// return true; -// } -// -// bool OnUserDestroy() -// { -// return true; -// } -// -// -//private: -// olc::GFX3D::vec3d vCamera = { 0.0f, 0.0f, -10.0f }; -// olc::GFX3D::vec3d vUp = { 0.0f, 1.0f, 0.0f }; -// olc::GFX3D::vec3d vEye = { 0.0f, 0.0f, -10.0f }; -// olc::GFX3D::vec3d vLookDir = { 0.0f, 0.0f, 1.0f }; -// -// -// -// olc::Sprite *sprOld = nullptr; -// olc::GFX3D::mesh meshQuad; -// -// cCityMap *pCity = nullptr; -// -// -// -//}; -// -//int main() -//{ -// // Load the settings singleton -// /*cGameSettings config; -// if (!config.LoadConfigFile("assets/config.lua")) -// { -// std::cout << "Failed to load '/assets/config.lua'" << std::endl; -// std::cout << " -> Using default configuration" << std::endl; -// }*/ -// -// // Start the PixelGameEngine -// cCarCrimeCity game; -// if (game.Construct(256, 240, 4, 4))// config.nScreenWidth, config.nScreenHeight, config.nPixelWidth, config.nPixelHeight)) -// game.Start(); -// -// // Exit! -// return 0; -//} \ No newline at end of file diff --git a/Videos/CarCrimeCity/Part2/olcPGEX_Graphics3D.h b/Videos/CarCrimeCity/Part2/olcPGEX_Graphics3D.h deleted file mode 100644 index 970c021..0000000 --- a/Videos/CarCrimeCity/Part2/olcPGEX_Graphics3D.h +++ /dev/null @@ -1,1725 +0,0 @@ -/* - olcPGEX_Graphics3D.h - - +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine Extension | - | 3D Rendering - v0.3 | - +-------------------------------------------------------------+ - - What is this? - ~~~~~~~~~~~~~ - This is an extension to the olcPixelGameEngine, which provides - support for software rendering 3D graphics. - - NOTE!!! This file is under development and may change! - - Big Thanks to MaGetzUb for finding an OOB error, and joshinils - for pointing out sampling inaccuracy. - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018 -*/ - - -#ifndef OLC_PGEX_GFX3D -#define OLC_PGEX_GFX3D - -#include -#include -#include -#include -#include -#include -#undef min -#undef max - -//#include - -namespace olc -{ - // Container class for Advanced 2D Drawing functions - class GFX3D : public olc::PGEX - { - - public: - - struct vec2d - { - float x = 0; - float y = 0; - float z = 0; - }; - - struct vec3d - { - float x = 0; - float y = 0; - float z = 0; - float w = 1; // Need a 4th term to perform sensible matrix vector multiplication - }; - - struct triangle - { - vec3d p[3]; - vec2d t[3]; - olc::Pixel col[3]; - }; - - struct mat4x4 - { - float m[4][4] = { 0 }; - }; - - struct mesh - { - std::vector tris; - bool LoadOBJFile(std::string sFilename, bool bHasTexture = false); - }; - - /*class MipMap : public olc::Sprite - { - public: - MipMap(); - MipMap(std::string sImageFile); - MipMap(std::string sImageFile, olc::ResourcePack *pack); - MipMap(int32_t w, int32_t h); - ~MipMap(); - - public: - olc::rcode LoadFromFile(std::string sImageFile, olc::ResourcePack *pack = nullptr); - olc::rcode LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack = nullptr); - Pixel Sample(float x, float y, float z); - Pixel SampleBL(float u, float v, float z); - - private: - int GenerateMipLevels(); - std::vector vecMipMaps; - - };*/ - - class Math - { - public: - Math(); - public: - static vec3d Mat_MultiplyVector(mat4x4 &m, vec3d &i); - static mat4x4 Mat_MultiplyMatrix(mat4x4 &m1, mat4x4 &m2); - static mat4x4 Mat_MakeIdentity(); - static mat4x4 Mat_MakeRotationX(float fAngleRad); - static mat4x4 Mat_MakeRotationY(float fAngleRad); - static mat4x4 Mat_MakeRotationZ(float fAngleRad); - static mat4x4 Mat_MakeScale(float x, float y, float z); - static mat4x4 Mat_MakeTranslation(float x, float y, float z); - static mat4x4 Mat_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar); - static mat4x4 Mat_PointAt(vec3d &pos, vec3d &target, vec3d &up); - static mat4x4 Mat_QuickInverse(mat4x4 &m); // Only for Rotation/Translation Matrices - static mat4x4 Mat_Inverse(olc::GFX3D::mat4x4 &m); - - static vec3d Vec_Add(vec3d &v1, vec3d &v2); - static vec3d Vec_Sub(vec3d &v1, vec3d &v2); - static vec3d Vec_Mul(vec3d &v1, float k); - static vec3d Vec_Div(vec3d &v1, float k); - static float Vec_DotProduct(vec3d &v1, vec3d &v2); - static float Vec_Length(vec3d &v); - static vec3d Vec_Normalise(vec3d &v); - static vec3d Vec_CrossProduct(vec3d &v1, vec3d &v2); - static vec3d Vec_IntersectPlane(vec3d &plane_p, vec3d &plane_n, vec3d &lineStart, vec3d &lineEnd, float &t); - - static int Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2); - }; - - enum RENDERFLAGS - { - RENDER_WIRE = 0x01, - RENDER_FLAT = 0x02, - RENDER_TEXTURED = 0x04, - RENDER_CULL_CW = 0x08, - RENDER_CULL_CCW = 0x10, - RENDER_DEPTH = 0x20, - RENDER_LIGHTS = 0x40, - }; - - enum LIGHTS - { - LIGHT_DISABLED, - LIGHT_AMBIENT, - LIGHT_DIRECTIONAL, - LIGHT_POINT - }; - - - class PipeLine - { - public: - PipeLine(); - - public: - void SetProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar, float fLeft, float fTop, float fWidth, float fHeight); - void SetCamera(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &lookat, olc::GFX3D::vec3d &up); - void SetTransform(olc::GFX3D::mat4x4 &transform); - void SetTexture(olc::Sprite *texture); - //void SetMipMapTexture(olc::GFX3D::MipMap *texture); - void SetLightSource(uint32_t nSlot, uint32_t nType, olc::Pixel col, olc::GFX3D::vec3d pos, olc::GFX3D::vec3d dir = { 0.0f, 0.0f, 1.0f }, float fParam = 0.0f); - uint32_t Render(std::vector &triangles, uint32_t flags = RENDER_CULL_CW | RENDER_TEXTURED | RENDER_DEPTH); - uint32_t Render(std::vector &triangles, uint32_t flags, int nOffset, int nCount); - uint32_t RenderLine(olc::GFX3D::vec3d &p1, olc::GFX3D::vec3d &p2, olc::Pixel col = olc::WHITE); - uint32_t RenderCircleXZ(olc::GFX3D::vec3d &p1, float r, olc::Pixel col = olc::WHITE); - - private: - olc::GFX3D::mat4x4 matProj; - olc::GFX3D::mat4x4 matView; - olc::GFX3D::mat4x4 matWorld; - olc::Sprite *sprTexture; - //olc::GFX3D::MipMap *sprMipMap; - //bool bUseMipMap; - float fViewX; - float fViewY; - float fViewW; - float fViewH; - - struct sLight - { - uint32_t type; - olc::GFX3D::vec3d pos; - olc::GFX3D::vec3d dir; - olc::Pixel col; - float param; - } lights[4]; - }; - - - - public: - //static const int RF_TEXTURE = 0x00000001; - //static const int RF_ = 0x00000002; - - static void ConfigureDisplay(); - static void ClearDepth(); - static void AddTriangleToScene(olc::GFX3D::triangle &tri); - static void RenderScene(); - - static void DrawTriangleFlat(olc::GFX3D::triangle &tri); - static void DrawTriangleWire(olc::GFX3D::triangle &tri, olc::Pixel col = olc::WHITE); - static void DrawTriangleTex(olc::GFX3D::triangle &tri, olc::Sprite* spr); - static void TexturedTriangle(int x1, int y1, float u1, float v1, float w1, - int x2, int y2, float u2, float v2, float w2, - int x3, int y3, float u3, float v3, float w3, olc::Sprite* spr); - - static void RasterTriangle(int x1, int y1, float u1, float v1, float w1, olc::Pixel c1, - int x2, int y2, float u2, float v2, float w2, olc::Pixel c2, - int x3, int y3, float u3, float v3, float w3, olc::Pixel c3, - olc::Sprite* spr, - uint32_t nFlags); - - // Draws a sprite with the transform applied - //inline static void DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform); - - private: - static float* m_DepthBuffer; - }; -} - -#endif - - -#ifdef OLC_PGEX_GRAPHICS3D -#undef OLC_PGEX_GRAPHICS3D - -namespace olc -{ - olc::GFX3D::Math::Math() - { - - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Mat_MultiplyVector(olc::GFX3D::mat4x4 &m, olc::GFX3D::vec3d &i) - { - vec3d v; - v.x = i.x * m.m[0][0] + i.y * m.m[1][0] + i.z * m.m[2][0] + i.w * m.m[3][0]; - v.y = i.x * m.m[0][1] + i.y * m.m[1][1] + i.z * m.m[2][1] + i.w * m.m[3][1]; - v.z = i.x * m.m[0][2] + i.y * m.m[1][2] + i.z * m.m[2][2] + i.w * m.m[3][2]; - v.w = i.x * m.m[0][3] + i.y * m.m[1][3] + i.z * m.m[2][3] + i.w * m.m[3][3]; - return v; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeIdentity() - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = 1.0f; - matrix.m[1][1] = 1.0f; - matrix.m[2][2] = 1.0f; - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeRotationX(float fAngleRad) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = 1.0f; - matrix.m[1][1] = cosf(fAngleRad); - matrix.m[1][2] = sinf(fAngleRad); - matrix.m[2][1] = -sinf(fAngleRad); - matrix.m[2][2] = cosf(fAngleRad); - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeRotationY(float fAngleRad) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = cosf(fAngleRad); - matrix.m[0][2] = sinf(fAngleRad); - matrix.m[2][0] = -sinf(fAngleRad); - matrix.m[1][1] = 1.0f; - matrix.m[2][2] = cosf(fAngleRad); - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeRotationZ(float fAngleRad) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = cosf(fAngleRad); - matrix.m[0][1] = sinf(fAngleRad); - matrix.m[1][0] = -sinf(fAngleRad); - matrix.m[1][1] = cosf(fAngleRad); - matrix.m[2][2] = 1.0f; - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeScale(float x, float y, float z) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = x; - matrix.m[1][1] = y; - matrix.m[2][2] = z; - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeTranslation(float x, float y, float z) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = 1.0f; - matrix.m[1][1] = 1.0f; - matrix.m[2][2] = 1.0f; - matrix.m[3][3] = 1.0f; - matrix.m[3][0] = x; - matrix.m[3][1] = y; - matrix.m[3][2] = z; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar) - { - float fFovRad = 1.0f / tanf(fFovDegrees * 0.5f / 180.0f * 3.14159f); - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = fAspectRatio * fFovRad; - matrix.m[1][1] = fFovRad; - matrix.m[2][2] = fFar / (fFar - fNear); - matrix.m[3][2] = (-fFar * fNear) / (fFar - fNear); - matrix.m[2][3] = 1.0f; - matrix.m[3][3] = 0.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MultiplyMatrix(olc::GFX3D::mat4x4 &m1, olc::GFX3D::mat4x4 &m2) - { - olc::GFX3D::mat4x4 matrix; - for (int c = 0; c < 4; c++) - for (int r = 0; r < 4; r++) - matrix.m[r][c] = m1.m[r][0] * m2.m[0][c] + m1.m[r][1] * m2.m[1][c] + m1.m[r][2] * m2.m[2][c] + m1.m[r][3] * m2.m[3][c]; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_PointAt(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &target, olc::GFX3D::vec3d &up) - { - // Calculate new forward direction - olc::GFX3D::vec3d newForward = Vec_Sub(target, pos); - newForward = Vec_Normalise(newForward); - - // Calculate new Up direction - olc::GFX3D::vec3d a = Vec_Mul(newForward, Vec_DotProduct(up, newForward)); - olc::GFX3D::vec3d newUp = Vec_Sub(up, a); - newUp = Vec_Normalise(newUp); - - // New Right direction is easy, its just cross product - olc::GFX3D::vec3d newRight = Vec_CrossProduct(newUp, newForward); - - // Construct Dimensioning and Translation Matrix - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = newRight.x; matrix.m[0][1] = newRight.y; matrix.m[0][2] = newRight.z; matrix.m[0][3] = 0.0f; - matrix.m[1][0] = newUp.x; matrix.m[1][1] = newUp.y; matrix.m[1][2] = newUp.z; matrix.m[1][3] = 0.0f; - matrix.m[2][0] = newForward.x; matrix.m[2][1] = newForward.y; matrix.m[2][2] = newForward.z; matrix.m[2][3] = 0.0f; - matrix.m[3][0] = pos.x; matrix.m[3][1] = pos.y; matrix.m[3][2] = pos.z; matrix.m[3][3] = 1.0f; - return matrix; - - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_QuickInverse(olc::GFX3D::mat4x4 &m) // Only for Rotation/Translation Matrices - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = m.m[0][0]; matrix.m[0][1] = m.m[1][0]; matrix.m[0][2] = m.m[2][0]; matrix.m[0][3] = 0.0f; - matrix.m[1][0] = m.m[0][1]; matrix.m[1][1] = m.m[1][1]; matrix.m[1][2] = m.m[2][1]; matrix.m[1][3] = 0.0f; - matrix.m[2][0] = m.m[0][2]; matrix.m[2][1] = m.m[1][2]; matrix.m[2][2] = m.m[2][2]; matrix.m[2][3] = 0.0f; - matrix.m[3][0] = -(m.m[3][0] * matrix.m[0][0] + m.m[3][1] * matrix.m[1][0] + m.m[3][2] * matrix.m[2][0]); - matrix.m[3][1] = -(m.m[3][0] * matrix.m[0][1] + m.m[3][1] * matrix.m[1][1] + m.m[3][2] * matrix.m[2][1]); - matrix.m[3][2] = -(m.m[3][0] * matrix.m[0][2] + m.m[3][1] * matrix.m[1][2] + m.m[3][2] * matrix.m[2][2]); - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_Inverse(olc::GFX3D::mat4x4 &m) - { - double det; - - - mat4x4 matInv; - - matInv.m[0][0] = m.m[1][1] * m.m[2][2] * m.m[3][3] - m.m[1][1] * m.m[2][3] * m.m[3][2] - m.m[2][1] * m.m[1][2] * m.m[3][3] + m.m[2][1] * m.m[1][3] * m.m[3][2] + m.m[3][1] * m.m[1][2] * m.m[2][3] - m.m[3][1] * m.m[1][3] * m.m[2][2]; - matInv.m[1][0] = -m.m[1][0] * m.m[2][2] * m.m[3][3] + m.m[1][0] * m.m[2][3] * m.m[3][2] + m.m[2][0] * m.m[1][2] * m.m[3][3] - m.m[2][0] * m.m[1][3] * m.m[3][2] - m.m[3][0] * m.m[1][2] * m.m[2][3] + m.m[3][0] * m.m[1][3] * m.m[2][2]; - matInv.m[2][0] = m.m[1][0] * m.m[2][1] * m.m[3][3] - m.m[1][0] * m.m[2][3] * m.m[3][1] - m.m[2][0] * m.m[1][1] * m.m[3][3] + m.m[2][0] * m.m[1][3] * m.m[3][1] + m.m[3][0] * m.m[1][1] * m.m[2][3] - m.m[3][0] * m.m[1][3] * m.m[2][1]; - matInv.m[3][0] = -m.m[1][0] * m.m[2][1] * m.m[3][2] + m.m[1][0] * m.m[2][2] * m.m[3][1] + m.m[2][0] * m.m[1][1] * m.m[3][2] - m.m[2][0] * m.m[1][2] * m.m[3][1] - m.m[3][0] * m.m[1][1] * m.m[2][2] + m.m[3][0] * m.m[1][2] * m.m[2][1]; - matInv.m[0][1] = -m.m[0][1] * m.m[2][2] * m.m[3][3] + m.m[0][1] * m.m[2][3] * m.m[3][2] + m.m[2][1] * m.m[0][2] * m.m[3][3] - m.m[2][1] * m.m[0][3] * m.m[3][2] - m.m[3][1] * m.m[0][2] * m.m[2][3] + m.m[3][1] * m.m[0][3] * m.m[2][2]; - matInv.m[1][1] = m.m[0][0] * m.m[2][2] * m.m[3][3] - m.m[0][0] * m.m[2][3] * m.m[3][2] - m.m[2][0] * m.m[0][2] * m.m[3][3] + m.m[2][0] * m.m[0][3] * m.m[3][2] + m.m[3][0] * m.m[0][2] * m.m[2][3] - m.m[3][0] * m.m[0][3] * m.m[2][2]; - matInv.m[2][1] = -m.m[0][0] * m.m[2][1] * m.m[3][3] + m.m[0][0] * m.m[2][3] * m.m[3][1] + m.m[2][0] * m.m[0][1] * m.m[3][3] - m.m[2][0] * m.m[0][3] * m.m[3][1] - m.m[3][0] * m.m[0][1] * m.m[2][3] + m.m[3][0] * m.m[0][3] * m.m[2][1]; - matInv.m[3][1] = m.m[0][0] * m.m[2][1] * m.m[3][2] - m.m[0][0] * m.m[2][2] * m.m[3][1] - m.m[2][0] * m.m[0][1] * m.m[3][2] + m.m[2][0] * m.m[0][2] * m.m[3][1] + m.m[3][0] * m.m[0][1] * m.m[2][2] - m.m[3][0] * m.m[0][2] * m.m[2][1]; - matInv.m[0][2] = m.m[0][1] * m.m[1][2] * m.m[3][3] - m.m[0][1] * m.m[1][3] * m.m[3][2] - m.m[1][1] * m.m[0][2] * m.m[3][3] + m.m[1][1] * m.m[0][3] * m.m[3][2] + m.m[3][1] * m.m[0][2] * m.m[1][3] - m.m[3][1] * m.m[0][3] * m.m[1][2]; - matInv.m[1][2] = -m.m[0][0] * m.m[1][2] * m.m[3][3] + m.m[0][0] * m.m[1][3] * m.m[3][2] + m.m[1][0] * m.m[0][2] * m.m[3][3] - m.m[1][0] * m.m[0][3] * m.m[3][2] - m.m[3][0] * m.m[0][2] * m.m[1][3] + m.m[3][0] * m.m[0][3] * m.m[1][2]; - matInv.m[2][2] = m.m[0][0] * m.m[1][1] * m.m[3][3] - m.m[0][0] * m.m[1][3] * m.m[3][1] - m.m[1][0] * m.m[0][1] * m.m[3][3] + m.m[1][0] * m.m[0][3] * m.m[3][1] + m.m[3][0] * m.m[0][1] * m.m[1][3] - m.m[3][0] * m.m[0][3] * m.m[1][1]; - matInv.m[3][2] = -m.m[0][0] * m.m[1][1] * m.m[3][2] + m.m[0][0] * m.m[1][2] * m.m[3][1] + m.m[1][0] * m.m[0][1] * m.m[3][2] - m.m[1][0] * m.m[0][2] * m.m[3][1] - m.m[3][0] * m.m[0][1] * m.m[1][2] + m.m[3][0] * m.m[0][2] * m.m[1][1]; - matInv.m[0][3] = -m.m[0][1] * m.m[1][2] * m.m[2][3] + m.m[0][1] * m.m[1][3] * m.m[2][2] + m.m[1][1] * m.m[0][2] * m.m[2][3] - m.m[1][1] * m.m[0][3] * m.m[2][2] - m.m[2][1] * m.m[0][2] * m.m[1][3] + m.m[2][1] * m.m[0][3] * m.m[1][2]; - matInv.m[1][3] = m.m[0][0] * m.m[1][2] * m.m[2][3] - m.m[0][0] * m.m[1][3] * m.m[2][2] - m.m[1][0] * m.m[0][2] * m.m[2][3] + m.m[1][0] * m.m[0][3] * m.m[2][2] + m.m[2][0] * m.m[0][2] * m.m[1][3] - m.m[2][0] * m.m[0][3] * m.m[1][2]; - matInv.m[2][3] = -m.m[0][0] * m.m[1][1] * m.m[2][3] + m.m[0][0] * m.m[1][3] * m.m[2][1] + m.m[1][0] * m.m[0][1] * m.m[2][3] - m.m[1][0] * m.m[0][3] * m.m[2][1] - m.m[2][0] * m.m[0][1] * m.m[1][3] + m.m[2][0] * m.m[0][3] * m.m[1][1]; - matInv.m[3][3] = m.m[0][0] * m.m[1][1] * m.m[2][2] - m.m[0][0] * m.m[1][2] * m.m[2][1] - m.m[1][0] * m.m[0][1] * m.m[2][2] + m.m[1][0] * m.m[0][2] * m.m[2][1] + m.m[2][0] * m.m[0][1] * m.m[1][2] - m.m[2][0] * m.m[0][2] * m.m[1][1]; - - det = m.m[0][0] * matInv.m[0][0] + m.m[0][1] * matInv.m[1][0] + m.m[0][2] * matInv.m[2][0] + m.m[0][3] * matInv.m[3][0]; - // if (det == 0) return false; - - det = 1.0 / det; - - for (int i = 0; i < 4; i++) - for (int j = 0; j < 4; j++) - matInv.m[i][j] *= (float)det; - - return matInv; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Add(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) - { - return { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Sub(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) - { - return { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Mul(olc::GFX3D::vec3d &v1, float k) - { - return { v1.x * k, v1.y * k, v1.z * k }; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Div(olc::GFX3D::vec3d &v1, float k) - { - return { v1.x / k, v1.y / k, v1.z / k }; - } - - float olc::GFX3D::Math::Vec_DotProduct(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) - { - return v1.x*v2.x + v1.y*v2.y + v1.z * v2.z; - } - - float olc::GFX3D::Math::Vec_Length(olc::GFX3D::vec3d &v) - { - return sqrtf(Vec_DotProduct(v, v)); - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Normalise(olc::GFX3D::vec3d &v) - { - float l = Vec_Length(v); - return { v.x / l, v.y / l, v.z / l }; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_CrossProduct(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) - { - vec3d v; - v.x = v1.y * v2.z - v1.z * v2.y; - v.y = v1.z * v2.x - v1.x * v2.z; - v.z = v1.x * v2.y - v1.y * v2.x; - return v; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_IntersectPlane(olc::GFX3D::vec3d &plane_p, olc::GFX3D::vec3d &plane_n, olc::GFX3D::vec3d &lineStart, olc::GFX3D::vec3d &lineEnd, float &t) - { - plane_n = Vec_Normalise(plane_n); - float plane_d = -Vec_DotProduct(plane_n, plane_p); - float ad = Vec_DotProduct(lineStart, plane_n); - float bd = Vec_DotProduct(lineEnd, plane_n); - t = (-plane_d - ad) / (bd - ad); - olc::GFX3D::vec3d lineStartToEnd = Vec_Sub(lineEnd, lineStart); - olc::GFX3D::vec3d lineToIntersect = Vec_Mul(lineStartToEnd, t); - return Vec_Add(lineStart, lineToIntersect); - } - - - int olc::GFX3D::Math::Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2) - { - // Make sure plane normal is indeed normal - plane_n = Math::Vec_Normalise(plane_n); - - out_tri1.t[0] = in_tri.t[0]; - out_tri2.t[0] = in_tri.t[0]; - out_tri1.t[1] = in_tri.t[1]; - out_tri2.t[1] = in_tri.t[1]; - out_tri1.t[2] = in_tri.t[2]; - out_tri2.t[2] = in_tri.t[2]; - - // Return signed shortest distance from point to plane, plane normal must be normalised - auto dist = [&](vec3d &p) - { - vec3d n = Math::Vec_Normalise(p); - return (plane_n.x * p.x + plane_n.y * p.y + plane_n.z * p.z - Math::Vec_DotProduct(plane_n, plane_p)); - }; - - // Create two temporary storage arrays to classify points either side of plane - // If distance sign is positive, point lies on "inside" of plane - vec3d* inside_points[3]; int nInsidePointCount = 0; - vec3d* outside_points[3]; int nOutsidePointCount = 0; - vec2d* inside_tex[3]; int nInsideTexCount = 0; - vec2d* outside_tex[3]; int nOutsideTexCount = 0; - - - // Get signed distance of each point in triangle to plane - float d0 = dist(in_tri.p[0]); - float d1 = dist(in_tri.p[1]); - float d2 = dist(in_tri.p[2]); - - if (d0 >= 0) { inside_points[nInsidePointCount++] = &in_tri.p[0]; inside_tex[nInsideTexCount++] = &in_tri.t[0]; } - else { - outside_points[nOutsidePointCount++] = &in_tri.p[0]; outside_tex[nOutsideTexCount++] = &in_tri.t[0]; - } - if (d1 >= 0) { - inside_points[nInsidePointCount++] = &in_tri.p[1]; inside_tex[nInsideTexCount++] = &in_tri.t[1]; - } - else { - outside_points[nOutsidePointCount++] = &in_tri.p[1]; outside_tex[nOutsideTexCount++] = &in_tri.t[1]; - } - if (d2 >= 0) { - inside_points[nInsidePointCount++] = &in_tri.p[2]; inside_tex[nInsideTexCount++] = &in_tri.t[2]; - } - else { - outside_points[nOutsidePointCount++] = &in_tri.p[2]; outside_tex[nOutsideTexCount++] = &in_tri.t[2]; - } - - // Now classify triangle points, and break the input triangle into - // smaller output triangles if required. There are four possible - // outcomes... - - if (nInsidePointCount == 0) - { - // All points lie on the outside of plane, so clip whole triangle - // It ceases to exist - - return 0; // No returned triangles are valid - } - - if (nInsidePointCount == 3) - { - // All points lie on the inside of plane, so do nothing - // and allow the triangle to simply pass through - out_tri1 = in_tri; - - return 1; // Just the one returned original triangle is valid - } - - if (nInsidePointCount == 1 && nOutsidePointCount == 2) - { - // Triangle should be clipped. As two points lie outside - // the plane, the triangle simply becomes a smaller triangle - - // Copy appearance info to new triangle - out_tri1.col[0] = in_tri.col[0]; - out_tri1.col[1] = in_tri.col[1]; - out_tri1.col[2] = in_tri.col[2]; - - // The inside point is valid, so keep that... - out_tri1.p[0] = *inside_points[0]; - out_tri1.t[0] = *inside_tex[0]; - - // but the two new points are at the locations where the - // original sides of the triangle (lines) intersect with the plane - float t; - out_tri1.p[1] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); - out_tri1.t[1].x = t * (outside_tex[0]->x - inside_tex[0]->x) + inside_tex[0]->x; - out_tri1.t[1].y = t * (outside_tex[0]->y - inside_tex[0]->y) + inside_tex[0]->y; - out_tri1.t[1].z = t * (outside_tex[0]->z - inside_tex[0]->z) + inside_tex[0]->z; - - out_tri1.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[1], t); - out_tri1.t[2].x = t * (outside_tex[1]->x - inside_tex[0]->x) + inside_tex[0]->x; - out_tri1.t[2].y = t * (outside_tex[1]->y - inside_tex[0]->y) + inside_tex[0]->y; - out_tri1.t[2].z = t * (outside_tex[1]->z - inside_tex[0]->z) + inside_tex[0]->z; - - return 1; // Return the newly formed single triangle - } - - if (nInsidePointCount == 2 && nOutsidePointCount == 1) - { - // Triangle should be clipped. As two points lie inside the plane, - // the clipped triangle becomes a "quad". Fortunately, we can - // represent a quad with two new triangles - - // Copy appearance info to new triangles - out_tri1.col[0] = in_tri.col[0]; - out_tri2.col[0] = in_tri.col[0]; - out_tri1.col[1] = in_tri.col[1]; - out_tri2.col[1] = in_tri.col[1]; - out_tri1.col[2] = in_tri.col[2]; - out_tri2.col[2] = in_tri.col[2]; - - // The first triangle consists of the two inside points and a new - // point determined by the location where one side of the triangle - // intersects with the plane - out_tri1.p[0] = *inside_points[0]; - out_tri1.t[0] = *inside_tex[0]; - - out_tri1.p[1] = *inside_points[1]; - out_tri1.t[1] = *inside_tex[1]; - - float t; - out_tri1.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); - out_tri1.t[2].x = t * (outside_tex[0]->x - inside_tex[0]->x) + inside_tex[0]->x; - out_tri1.t[2].y = t * (outside_tex[0]->y - inside_tex[0]->y) + inside_tex[0]->y; - out_tri1.t[2].z = t * (outside_tex[0]->z - inside_tex[0]->z) + inside_tex[0]->z; - - // The second triangle is composed of one of he inside points, a - // new point determined by the intersection of the other side of the - // triangle and the plane, and the newly created point above - out_tri2.p[1] = *inside_points[1]; - out_tri2.t[1] = *inside_tex[1]; - out_tri2.p[0] = out_tri1.p[2]; - out_tri2.t[0] = out_tri1.t[2]; - out_tri2.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[1], *outside_points[0], t); - out_tri2.t[2].x = t * (outside_tex[0]->x - inside_tex[1]->x) + inside_tex[1]->x; - out_tri2.t[2].y = t * (outside_tex[0]->y - inside_tex[1]->y) + inside_tex[1]->y; - out_tri2.t[2].z = t * (outside_tex[0]->z - inside_tex[1]->z) + inside_tex[1]->z; - return 2; // Return two newly formed triangles which form a quad - } - - return 0; - } - - void GFX3D::DrawTriangleFlat(olc::GFX3D::triangle &tri) - { - pge->FillTriangle(tri.p[0].x, tri.p[0].y, tri.p[1].x, tri.p[1].y, tri.p[2].x, tri.p[2].y, tri.col[0]); - } - - void GFX3D::DrawTriangleWire(olc::GFX3D::triangle &tri, olc::Pixel col) - { - pge->DrawTriangle(tri.p[0].x, tri.p[0].y, tri.p[1].x, tri.p[1].y, tri.p[2].x, tri.p[2].y, col); - } - - void GFX3D::TexturedTriangle(int x1, int y1, float u1, float v1, float w1, - int x2, int y2, float u2, float v2, float w2, - int x3, int y3, float u3, float v3, float w3, olc::Sprite* spr) - - { - if (y2 < y1) - { - std::swap(y1, y2); - std::swap(x1, x2); - std::swap(u1, u2); - std::swap(v1, v2); - std::swap(w1, w2); - } - - if (y3 < y1) - { - std::swap(y1, y3); - std::swap(x1, x3); - std::swap(u1, u3); - std::swap(v1, v3); - std::swap(w1, w3); - } - - if (y3 < y2) - { - std::swap(y2, y3); - std::swap(x2, x3); - std::swap(u2, u3); - std::swap(v2, v3); - std::swap(w2, w3); - } - - int dy1 = y2 - y1; - int dx1 = x2 - x1; - float dv1 = v2 - v1; - float du1 = u2 - u1; - float dw1 = w2 - w1; - - int dy2 = y3 - y1; - int dx2 = x3 - x1; - float dv2 = v3 - v1; - float du2 = u3 - u1; - float dw2 = w3 - w1; - - float tex_u, tex_v, tex_w; - - float dax_step = 0, dbx_step = 0, - du1_step = 0, dv1_step = 0, - du2_step = 0, dv2_step = 0, - dw1_step = 0, dw2_step = 0; - - if (dy1) dax_step = dx1 / (float)abs(dy1); - if (dy2) dbx_step = dx2 / (float)abs(dy2); - - if (dy1) du1_step = du1 / (float)abs(dy1); - if (dy1) dv1_step = dv1 / (float)abs(dy1); - if (dy1) dw1_step = dw1 / (float)abs(dy1); - - if (dy2) du2_step = du2 / (float)abs(dy2); - if (dy2) dv2_step = dv2 / (float)abs(dy2); - if (dy2) dw2_step = dw2 / (float)abs(dy2); - - if (dy1) - { - for (int i = y1; i <= y2; i++) - { - int ax = x1 + (float)(i - y1) * dax_step; - int bx = x1 + (float)(i - y1) * dbx_step; - - float tex_su = u1 + (float)(i - y1) * du1_step; - float tex_sv = v1 + (float)(i - y1) * dv1_step; - float tex_sw = w1 + (float)(i - y1) * dw1_step; - - float tex_eu = u1 + (float)(i - y1) * du2_step; - float tex_ev = v1 + (float)(i - y1) * dv2_step; - float tex_ew = w1 + (float)(i - y1) * dw2_step; - - if (ax > bx) - { - std::swap(ax, bx); - std::swap(tex_su, tex_eu); - std::swap(tex_sv, tex_ev); - std::swap(tex_sw, tex_ew); - } - - tex_u = tex_su; - tex_v = tex_sv; - tex_w = tex_sw; - - float tstep = 1.0f / ((float)(bx - ax)); - float t = 0.0f; - - for (int j = ax; j < bx; j++) - { - tex_u = (1.0f - t) * tex_su + t * tex_eu; - tex_v = (1.0f - t) * tex_sv + t * tex_ev; - tex_w = (1.0f - t) * tex_sw + t * tex_ew; - if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j]) - { - /*if (bMipMap) - pge->Draw(j, i, ((olc::GFX3D::MipMap*)spr)->Sample(tex_u / tex_w, tex_v / tex_w, tex_w)); - else*/ - if(pge->Draw(j, i, spr != nullptr ? spr->Sample(tex_u / tex_w, tex_v / tex_w) : olc::GREY)) - m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w; - } - t += tstep; - } - - } - } - - dy1 = y3 - y2; - dx1 = x3 - x2; - dv1 = v3 - v2; - du1 = u3 - u2; - dw1 = w3 - w2; - - if (dy1) dax_step = dx1 / (float)abs(dy1); - if (dy2) dbx_step = dx2 / (float)abs(dy2); - - du1_step = 0, dv1_step = 0; - if (dy1) du1_step = du1 / (float)abs(dy1); - if (dy1) dv1_step = dv1 / (float)abs(dy1); - if (dy1) dw1_step = dw1 / (float)abs(dy1); - - if (dy1) - { - for (int i = y2; i <= y3; i++) - { - int ax = x2 + (float)(i - y2) * dax_step; - int bx = x1 + (float)(i - y1) * dbx_step; - - float tex_su = u2 + (float)(i - y2) * du1_step; - float tex_sv = v2 + (float)(i - y2) * dv1_step; - float tex_sw = w2 + (float)(i - y2) * dw1_step; - - float tex_eu = u1 + (float)(i - y1) * du2_step; - float tex_ev = v1 + (float)(i - y1) * dv2_step; - float tex_ew = w1 + (float)(i - y1) * dw2_step; - - if (ax > bx) - { - std::swap(ax, bx); - std::swap(tex_su, tex_eu); - std::swap(tex_sv, tex_ev); - std::swap(tex_sw, tex_ew); - } - - tex_u = tex_su; - tex_v = tex_sv; - tex_w = tex_sw; - - float tstep = 1.0f / ((float)(bx - ax)); - float t = 0.0f; - - for (int j = ax; j < bx; j++) - { - tex_u = (1.0f - t) * tex_su + t * tex_eu; - tex_v = (1.0f - t) * tex_sv + t * tex_ev; - tex_w = (1.0f - t) * tex_sw + t * tex_ew; - - if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j]) - { - /*if(bMipMap) - pge->Draw(j, i, ((olc::GFX3D::MipMap*)spr)->Sample(tex_u / tex_w, tex_v / tex_w, tex_w)); - else*/ - if(pge->Draw(j, i, spr != nullptr ? spr->Sample(tex_u / tex_w, tex_v / tex_w) : olc::GREY)) - m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w; - } - t += tstep; - } - } - } - } - - - void GFX3D::DrawTriangleTex(olc::GFX3D::triangle &tri, olc::Sprite* spr) - { - - } - - float* GFX3D::m_DepthBuffer = nullptr; - - void GFX3D::ConfigureDisplay() - { - m_DepthBuffer = new float[pge->ScreenWidth() * pge->ScreenHeight()]{ 0 }; - } - - - void GFX3D::ClearDepth() - { - memset(m_DepthBuffer, 0, pge->ScreenWidth() * pge->ScreenHeight() * sizeof(float)); - } - - bool GFX3D::mesh::LoadOBJFile(std::string sFilename, bool bHasTexture) - { - std::ifstream f(sFilename); - if (!f.is_open()) return false; - - // Local cache of verts - std::vector verts; - std::vector norms; - std::vector texs; - - while (!f.eof()) - { - char line[128]; - f.getline(line, 128); - - std::strstream s; - s << line; - - char junk; - - if (line[0] == 'v') - { - if (line[1] == 't') - { - vec2d v; - s >> junk >> junk >> v.x >> v.y; - //v.x = 1.0f - v.x; - v.y = 1.0f - v.y; - texs.push_back(v); - } - else if (line[1] == 'n') - { - vec3d v; - s >> junk >> junk >> v.x >> v.y >> v.z; - norms.push_back(v); - } - else - { - vec3d v; - s >> junk >> v.x >> v.y >> v.z; - verts.push_back(v); - } - } - - - /*if (!bHasTexture) - { - if (line[0] == 'f') - { - int f[3]; - s >> junk >> f[0] >> f[1] >> f[2]; - tris.push_back({ verts[f[0] - 1], verts[f[1] - 1], verts[f[2] - 1] }); - } - } - else*/ - { - if (line[0] == 'f') - { - s >> junk; - - std::string tokens[9]; - int nTokenCount = -1; - while (!s.eof()) - { - char c = s.get(); - if (c == ' ' || c == '/') - { - if (tokens[nTokenCount].size() > 0) - { - nTokenCount++; - } - } - else - tokens[nTokenCount].append(1, c); - } - - tokens[nTokenCount].pop_back(); - - int stride = 1; - if (!texs.empty()) stride++; - if (!norms.empty()) stride++; - - if (!texs.empty()) - { - tris.push_back({ - verts[stoi(tokens[0 * stride]) - 1], - verts[stoi(tokens[1 * stride]) - 1], - verts[stoi(tokens[2 * stride]) - 1], - texs[stoi(tokens[0 * stride + 1]) - 1], - texs[stoi(tokens[1 * stride + 1]) - 1], - texs[stoi(tokens[2 * stride + 1]) - 1], - olc::WHITE, olc::WHITE, olc::WHITE}); - } - else - { - tris.push_back({ - verts[stoi(tokens[0 * stride]) - 1], - verts[stoi(tokens[1 * stride]) - 1], - verts[stoi(tokens[2 * stride]) - 1], - olc::GFX3D::vec2d{0,0,0}, - olc::GFX3D::vec2d{0,0,0}, - olc::GFX3D::vec2d{0,0,0}, - olc::WHITE, olc::WHITE, olc::WHITE }); - - } - } - } - } - return true; - } - - - GFX3D::PipeLine::PipeLine() - { - //bUseMipMap = false; - } - - void GFX3D::PipeLine::SetProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar, float fLeft, float fTop, float fWidth, float fHeight) - { - matProj = GFX3D::Math::Mat_MakeProjection(fFovDegrees, fAspectRatio, fNear, fFar); - fViewX = fLeft; - fViewY = fTop; - fViewW = fWidth; - fViewH = fHeight; - } - - void GFX3D::PipeLine::SetCamera(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &lookat, olc::GFX3D::vec3d &up) - { - matView = GFX3D::Math::Mat_PointAt(pos, lookat, up); - matView = GFX3D::Math::Mat_QuickInverse(matView); - } - - void GFX3D::PipeLine::SetTransform(olc::GFX3D::mat4x4 &transform) - { - matWorld = transform; - } - - void GFX3D::PipeLine::SetTexture(olc::Sprite *texture) - { - sprTexture = texture; - //bUseMipMap = false; - } - - /*void GFX3D::PipeLine::SetMipMapTexture(olc::GFX3D::MipMap *texture) - { - sprMipMap = texture; - bUseMipMap = true; - }*/ - - void GFX3D::PipeLine::SetLightSource(uint32_t nSlot, uint32_t nType, olc::Pixel col, olc::GFX3D::vec3d pos, olc::GFX3D::vec3d dir, float fParam) - { - if (nSlot < 4) - { - lights[nSlot].type = nType; - lights[nSlot].pos = pos; - lights[nSlot].dir = dir; - lights[nSlot].col = col; - lights[nSlot].param = fParam; - } - } - - uint32_t GFX3D::PipeLine::Render(std::vector &triangles, uint32_t flags) - { - return Render(triangles, flags, 0, triangles.size()); - } - - uint32_t GFX3D::PipeLine::RenderLine(olc::GFX3D::vec3d &p1, olc::GFX3D::vec3d &p2, olc::Pixel col) - { - // Coordinates are assumed to be in world space - olc::GFX3D::vec3d t1, t2; - - // Transform into view - t1 = GFX3D::Math::Mat_MultiplyVector(matView, p1); - t2 = GFX3D::Math::Mat_MultiplyVector(matView, p2); - - // Project onto screen - t1 = GFX3D::Math::Mat_MultiplyVector(matProj, t1); - t2 = GFX3D::Math::Mat_MultiplyVector(matProj, t2); - - // Project - t1.x = t1.x / t1.w; - t1.y = t1.y / t1.w; - t1.z = t1.z / t1.w; - - t2.x = t2.x / t2.w; - t2.y = t2.y / t2.w; - t2.z = t2.z / t2.w; - - vec3d vOffsetView = { 1,1,0 }; - t1 = Math::Vec_Add(t1, vOffsetView); - t2 = Math::Vec_Add(t2, vOffsetView); - - t1.x *= 0.5f * fViewW; - t1.y *= 0.5f * fViewH; - t2.x *= 0.5f * fViewW; - t2.y *= 0.5f * fViewH; - - vOffsetView = { fViewX,fViewY,0 }; - t1 = Math::Vec_Add(t1, vOffsetView); - t2 = Math::Vec_Add(t2, vOffsetView); - - pge->DrawLine(t1.x, t1.y, t2.x, t2.y, col); - - return 0; - } - - uint32_t GFX3D::PipeLine::RenderCircleXZ(olc::GFX3D::vec3d &p1, float r, olc::Pixel col) - { - // Coordinates are assumed to be in world space - olc::GFX3D::vec3d t1; - olc::GFX3D::vec3d t2 = { p1.x + r, p1.y, p1.z }; - - // Transform into view - t1 = GFX3D::Math::Mat_MultiplyVector(matView, p1); - t2 = GFX3D::Math::Mat_MultiplyVector(matView, t2); - - // Project onto screen - t1 = GFX3D::Math::Mat_MultiplyVector(matProj, t1); - t2 = GFX3D::Math::Mat_MultiplyVector(matProj, t2); - - // Project - t1.x = t1.x / t1.w; - t1.y = t1.y / t1.w; - t1.z = t1.z / t1.w; - - t2.x = t2.x / t2.w; - t2.y = t2.y / t2.w; - t2.z = t2.z / t2.w; - - vec3d vOffsetView = { 1,1,0 }; - t1 = Math::Vec_Add(t1, vOffsetView); - t2 = Math::Vec_Add(t2, vOffsetView); - - t1.x *= 0.5f * fViewW; - t1.y *= 0.5f * fViewH; - t2.x *= 0.5f * fViewW; - t2.y *= 0.5f * fViewH; - - vOffsetView = { fViewX,fViewY,0 }; - t1 = Math::Vec_Add(t1, vOffsetView); - t2 = Math::Vec_Add(t2, vOffsetView); - - pge->FillCircle(t1.x, t1.y, fabs(t2.x - t1.x), col); - - return 0; - } - - uint32_t GFX3D::PipeLine::Render(std::vector &triangles, uint32_t flags, int nOffset, int nCount) - { - // Calculate Transformation Matrix - mat4x4 matWorldView = Math::Mat_MultiplyMatrix(matWorld, matView); - //matWorldViewProj = Math::Mat_MultiplyMatrix(matWorldView, matProj); - - // Store triangles for rastering later - std::vector vecTrianglesToRaster; - - int nTriangleDrawnCount = 0; - - // Process Triangles - //for (auto &tri : triangles) -// omp_set_dynamic(0); -// omp_set_num_threads(4); -//#pragma omp parallel for schedule(static) - for(int tx = nOffset; tx < nOffset+nCount; tx++) - { - GFX3D::triangle &tri = triangles[tx]; - GFX3D::triangle triTransformed; - - // Just copy through texture coordinates - triTransformed.t[0] = { tri.t[0].x, tri.t[0].y, tri.t[0].z }; - triTransformed.t[1] = { tri.t[1].x, tri.t[1].y, tri.t[1].z }; - triTransformed.t[2] = { tri.t[2].x, tri.t[2].y, tri.t[2].z }; // Think! - - // Dont forget vertex colours - triTransformed.col[0] = tri.col[0]; - triTransformed.col[1] = tri.col[1]; - triTransformed.col[2] = tri.col[2]; - - // Transform Triangle from object into projected space - triTransformed.p[0] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[0]); - triTransformed.p[1] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[1]); - triTransformed.p[2] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[2]); - - // Calculate Triangle Normal in WorldView Space - GFX3D::vec3d normal, line1, line2; - line1 = GFX3D::Math::Vec_Sub(triTransformed.p[1], triTransformed.p[0]); - line2 = GFX3D::Math::Vec_Sub(triTransformed.p[2], triTransformed.p[0]); - normal = GFX3D::Math::Vec_CrossProduct(line1, line2); - normal = GFX3D::Math::Vec_Normalise(normal); - - // Cull triangles that face away from viewer - if (flags & RENDER_CULL_CW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) > 0.0f) continue; - if (flags & RENDER_CULL_CCW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) < 0.0f) continue; - - // If Lighting, calculate shading - if (flags & RENDER_LIGHTS) - { - olc::Pixel ambient_clamp = { 0,0,0 }; - olc::Pixel light_combined = { 0,0,0 }; - uint32_t nLightSources = 0; - float nLightR = 0, nLightG = 0, nLightB = 0; - - for (int i = 0; i < 4; i++) - { - switch (lights[i].type) - { - case LIGHT_DISABLED: - break; - case LIGHT_AMBIENT: - ambient_clamp = lights[i].col; - break; - case LIGHT_DIRECTIONAL: - { - nLightSources++; - GFX3D::vec3d light_dir = GFX3D::Math::Vec_Normalise(lights[i].dir); - float light = GFX3D::Math::Vec_DotProduct(light_dir, normal); - if (light > 0) - { - int j = 0; - } - - light = std::max(light, 0.0f); - nLightR += light * (lights[i].col.r/255.0f); - nLightG += light * (lights[i].col.g/255.0f); - nLightB += light * (lights[i].col.b/255.0f); - } - break; - case LIGHT_POINT: - break; - } - } - - //nLightR /= nLightSources; - //nLightG /= nLightSources; - //nLightB /= nLightSources; - - nLightR = std::max(nLightR, ambient_clamp.r / 255.0f); - nLightG = std::max(nLightG, ambient_clamp.g / 255.0f); - nLightB = std::max(nLightB, ambient_clamp.b / 255.0f); - - triTransformed.col[0] = olc::Pixel(nLightR * triTransformed.col[0].r, nLightG * triTransformed.col[0].g, nLightB * triTransformed.col[0].b); - triTransformed.col[1] = olc::Pixel(nLightR * triTransformed.col[1].r, nLightG * triTransformed.col[1].g, nLightB * triTransformed.col[1].b); - triTransformed.col[2] = olc::Pixel(nLightR * triTransformed.col[2].r, nLightG * triTransformed.col[2].g, nLightB * triTransformed.col[2].b); - - - - /*GFX3D::vec3d light_dir = { 1,1,1 }; - light_dir = GFX3D::Math::Vec_Normalise(light_dir); - float light = GFX3D::Math::Vec_DotProduct(light_dir, normal); - if (light < 0) light = 0; - triTransformed.col[0] = olc::Pixel(light * 255.0f, light * 255.0f, light * 255.0f); - triTransformed.col[1] = olc::Pixel(light * 255.0f, light * 255.0f, light * 255.0f); - triTransformed.col[2] = olc::Pixel(light * 255.0f, light * 255.0f, light * 255.0f);*/ - } - //else - // triTransformed.col = olc::WHITE; - - // Clip triangle against near plane - int nClippedTriangles = 0; - GFX3D::triangle clipped[2]; - nClippedTriangles = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.1f }, { 0.0f, 0.0f, 1.0f }, triTransformed, clipped[0], clipped[1]); - - // This may yield two new triangles - for (int n = 0; n < nClippedTriangles; n++) - { - triangle triProjected = clipped[n]; - - // Project new triangle - triProjected.p[0] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[0]); - triProjected.p[1] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[1]); - triProjected.p[2] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[2]); - - // Apply Projection to Verts - triProjected.p[0].x = triProjected.p[0].x / triProjected.p[0].w; - triProjected.p[1].x = triProjected.p[1].x / triProjected.p[1].w; - triProjected.p[2].x = triProjected.p[2].x / triProjected.p[2].w; - - triProjected.p[0].y = triProjected.p[0].y / triProjected.p[0].w; - triProjected.p[1].y = triProjected.p[1].y / triProjected.p[1].w; - triProjected.p[2].y = triProjected.p[2].y / triProjected.p[2].w; - - triProjected.p[0].z = triProjected.p[0].z / triProjected.p[0].w; - triProjected.p[1].z = triProjected.p[1].z / triProjected.p[1].w; - triProjected.p[2].z = triProjected.p[2].z / triProjected.p[2].w; - - // Apply Projection to Tex coords - triProjected.t[0].x = triProjected.t[0].x / triProjected.p[0].w; - triProjected.t[1].x = triProjected.t[1].x / triProjected.p[1].w; - triProjected.t[2].x = triProjected.t[2].x / triProjected.p[2].w; - - triProjected.t[0].y = triProjected.t[0].y / triProjected.p[0].w; - triProjected.t[1].y = triProjected.t[1].y / triProjected.p[1].w; - triProjected.t[2].y = triProjected.t[2].y / triProjected.p[2].w; - - triProjected.t[0].z = 1.0f / triProjected.p[0].w; - triProjected.t[1].z = 1.0f / triProjected.p[1].w; - triProjected.t[2].z = 1.0f / triProjected.p[2].w; - - // Clip against viewport in screen space - // Clip triangles against all four screen edges, this could yield - // a bunch of triangles, so create a queue that we traverse to - // ensure we only test new triangles generated against planes - GFX3D::triangle sclipped[2]; - std::list listTriangles; - - - // Add initial triangle - listTriangles.push_back(triProjected); - int nNewTriangles = 1; - - for (int p = 0; p < 4; p++) - { - int nTrisToAdd = 0; - while (nNewTriangles > 0) - { - // Take triangle from front of queue - triangle test = listTriangles.front(); - listTriangles.pop_front(); - nNewTriangles--; - - // Clip it against a plane. We only need to test each - // subsequent plane, against subsequent new triangles - // as all triangles after a plane clip are guaranteed - // to lie on the inside of the plane. I like how this - // comment is almost completely and utterly justified - switch (p) - { - case 0: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, -1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - case 1: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, +1.0f, 0.0f }, { 0.0f, -1.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - case 2: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ -1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - case 3: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ +1.0f, 0.0f, 0.0f }, { -1.0f, 0.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - } - - - // Clipping may yield a variable number of triangles, so - // add these new ones to the back of the queue for subsequent - // clipping against next planes - for (int w = 0; w < nTrisToAdd; w++) - listTriangles.push_back(sclipped[w]); - } - nNewTriangles = listTriangles.size(); - } - - for (auto &triRaster : listTriangles) - { - // Scale to viewport - /*triRaster.p[0].x *= -1.0f; - triRaster.p[1].x *= -1.0f; - triRaster.p[2].x *= -1.0f; - triRaster.p[0].y *= -1.0f; - triRaster.p[1].y *= -1.0f; - triRaster.p[2].y *= -1.0f;*/ - vec3d vOffsetView = { 1,1,0 }; - triRaster.p[0] = Math::Vec_Add(triRaster.p[0], vOffsetView); - triRaster.p[1] = Math::Vec_Add(triRaster.p[1], vOffsetView); - triRaster.p[2] = Math::Vec_Add(triRaster.p[2], vOffsetView); - triRaster.p[0].x *= 0.5f * fViewW; - triRaster.p[0].y *= 0.5f * fViewH; - triRaster.p[1].x *= 0.5f * fViewW; - triRaster.p[1].y *= 0.5f * fViewH; - triRaster.p[2].x *= 0.5f * fViewW; - triRaster.p[2].y *= 0.5f * fViewH; - vOffsetView = { fViewX,fViewY,0 }; - triRaster.p[0] = Math::Vec_Add(triRaster.p[0], vOffsetView); - triRaster.p[1] = Math::Vec_Add(triRaster.p[1], vOffsetView); - triRaster.p[2] = Math::Vec_Add(triRaster.p[2], vOffsetView); - - // For now, just draw triangle - - //if (flags & RENDER_TEXTURED) - //{/* - // TexturedTriangle( - // triRaster.p[0].x, triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, - // triRaster.p[1].x, triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, - // triRaster.p[2].x, triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, - // sprTexture);*/ - - // RasterTriangle( - // triRaster.p[0].x, triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, triRaster.col, - // triRaster.p[1].x, triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, triRaster.col, - // triRaster.p[2].x, triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, triRaster.col, - // sprTexture, nFlags); - - //} - - if (flags & RENDER_WIRE) - { - DrawTriangleWire(triRaster, olc::RED); - } - else - { - RasterTriangle( - triRaster.p[0].x, triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, triRaster.col[0], - triRaster.p[1].x, triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, triRaster.col[1], - triRaster.p[2].x, triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, triRaster.col[2], - sprTexture, flags); - - } - - - - - nTriangleDrawnCount++; - } - } - } - - return nTriangleDrawnCount; - } - - void GFX3D::RasterTriangle(int x1, int y1, float u1, float v1, float w1, olc::Pixel c1, - int x2, int y2, float u2, float v2, float w2, olc::Pixel c2, - int x3, int y3, float u3, float v3, float w3, olc::Pixel c3, - olc::Sprite* spr, - uint32_t nFlags) - - { - if (y2 < y1) - { - std::swap(y1, y2); std::swap(x1, x2); std::swap(u1, u2); std::swap(v1, v2); std::swap(w1, w2); std::swap(c1, c2); - } - - if (y3 < y1) - { - std::swap(y1, y3); std::swap(x1, x3); std::swap(u1, u3); std::swap(v1, v3); std::swap(w1, w3); std::swap(c1, c3); - } - - if (y3 < y2) - { - std::swap(y2, y3); std::swap(x2, x3); std::swap(u2, u3); std::swap(v2, v3); std::swap(w2, w3); std::swap(c2, c3); - } - - int dy1 = y2 - y1; - int dx1 = x2 - x1; - float dv1 = v2 - v1; - float du1 = u2 - u1; - float dw1 = w2 - w1; - int dcr1 = c2.r - c1.r; - int dcg1 = c2.g - c1.g; - int dcb1 = c2.b - c1.b; - int dca1 = c2.a - c1.a; - - int dy2 = y3 - y1; - int dx2 = x3 - x1; - float dv2 = v3 - v1; - float du2 = u3 - u1; - float dw2 = w3 - w1; - int dcr2 = c3.r - c1.r; - int dcg2 = c3.g - c1.g; - int dcb2 = c3.b - c1.b; - int dca2 = c3.a - c1.a; - - float tex_u, tex_v, tex_w; - float col_r, col_g, col_b, col_a; - - float dax_step = 0, dbx_step = 0, - du1_step = 0, dv1_step = 0, - du2_step = 0, dv2_step = 0, - dw1_step = 0, dw2_step = 0, - dcr1_step = 0, dcr2_step = 0, - dcg1_step = 0, dcg2_step = 0, - dcb1_step = 0, dcb2_step = 0, - dca1_step = 0, dca2_step = 0; - - if (dy1) dax_step = dx1 / (float)abs(dy1); - if (dy2) dbx_step = dx2 / (float)abs(dy2); - - if (dy1) du1_step = du1 / (float)abs(dy1); - if (dy1) dv1_step = dv1 / (float)abs(dy1); - if (dy1) dw1_step = dw1 / (float)abs(dy1); - - if (dy2) du2_step = du2 / (float)abs(dy2); - if (dy2) dv2_step = dv2 / (float)abs(dy2); - if (dy2) dw2_step = dw2 / (float)abs(dy2); - - if (dy1) dcr1_step = dcr1 / (float)abs(dy1); - if (dy1) dcg1_step = dcg1 / (float)abs(dy1); - if (dy1) dcb1_step = dcb1 / (float)abs(dy1); - if (dy1) dca1_step = dca1 / (float)abs(dy1); - - if (dy2) dcr2_step = dcr2 / (float)abs(dy2); - if (dy2) dcg2_step = dcg2 / (float)abs(dy2); - if (dy2) dcb2_step = dcb2 / (float)abs(dy2); - if (dy2) dca2_step = dca2 / (float)abs(dy2); - - float pixel_r = 0.0f; - float pixel_g = 0.0f; - float pixel_b = 0.0f; - float pixel_a = 1.0f; - - if (dy1) - { - for (int i = y1; i <= y2; i++) - { - int ax = x1 + (float)(i - y1) * dax_step; - int bx = x1 + (float)(i - y1) * dbx_step; - - float tex_su = u1 + (float)(i - y1) * du1_step; - float tex_sv = v1 + (float)(i - y1) * dv1_step; - float tex_sw = w1 + (float)(i - y1) * dw1_step; - - float tex_eu = u1 + (float)(i - y1) * du2_step; - float tex_ev = v1 + (float)(i - y1) * dv2_step; - float tex_ew = w1 + (float)(i - y1) * dw2_step; - - float col_sr = c1.r + (float)(i - y1) * dcr1_step; - float col_sg = c1.g + (float)(i - y1) * dcg1_step; - float col_sb = c1.b + (float)(i - y1) * dcb1_step; - float col_sa = c1.a + (float)(i - y1) * dca1_step; - - float col_er = c1.r + (float)(i - y1) * dcr2_step; - float col_eg = c1.g + (float)(i - y1) * dcg2_step; - float col_eb = c1.b + (float)(i - y1) * dcb2_step; - float col_ea = c1.a + (float)(i - y1) * dca2_step; - - if (ax > bx) - { - std::swap(ax, bx); - std::swap(tex_su, tex_eu); - std::swap(tex_sv, tex_ev); - std::swap(tex_sw, tex_ew); - std::swap(col_sr, col_er); - std::swap(col_sg, col_eg); - std::swap(col_sb, col_eb); - std::swap(col_sa, col_ea); - } - - tex_u = tex_su; - tex_v = tex_sv; - tex_w = tex_sw; - col_r = col_sr; - col_g = col_sg; - col_b = col_sb; - col_a = col_sa; - - float tstep = 1.0f / ((float)(bx - ax)); - float t = 0.0f; - - for (int j = ax; j < bx; j++) - { - tex_u = (1.0f - t) * tex_su + t * tex_eu; - tex_v = (1.0f - t) * tex_sv + t * tex_ev; - tex_w = (1.0f - t) * tex_sw + t * tex_ew; - col_r = (1.0f - t) * col_sr + t * col_er; - col_g = (1.0f - t) * col_sg + t * col_eg; - col_b = (1.0f - t) * col_sb + t * col_eb; - col_a = (1.0f - t) * col_sa + t * col_ea; - - pixel_r = col_r; - pixel_g = col_g; - pixel_b = col_b; - pixel_a = col_a; - - if (nFlags & GFX3D::RENDER_TEXTURED) - { - if (spr != nullptr) - { - olc::Pixel sample = spr->Sample(tex_u / tex_w, tex_v / tex_w); - pixel_r *= sample.r / 255.0f; - pixel_g *= sample.g / 255.0f; - pixel_b *= sample.b / 255.0f; - pixel_a *= sample.a / 255.0f; - } - } - - if (nFlags & GFX3D::RENDER_DEPTH) - { - if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j]) - if (pge->Draw(j, i, olc::Pixel(pixel_r * 1.0f, pixel_g * 1.0f, pixel_b * 1.0f, pixel_a * 1.0f))) - m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w; - } - else - { - pge->Draw(j, i, olc::Pixel(pixel_r * 1.0f, pixel_g * 1.0f, pixel_b * 1.0f, pixel_a * 1.0f)); - } - - t += tstep; - } - } - } - - dy1 = y3 - y2; - dx1 = x3 - x2; - dv1 = v3 - v2; - du1 = u3 - u2; - dw1 = w3 - w2; - dcr1 = c3.r - c2.r; - dcg1 = c3.g - c2.g; - dcb1 = c3.b - c2.b; - dca1 = c3.a - c2.a; - - if (dy1) dax_step = dx1 / (float)abs(dy1); - if (dy2) dbx_step = dx2 / (float)abs(dy2); - - du1_step = 0; dv1_step = 0; - if (dy1) du1_step = du1 / (float)abs(dy1); - if (dy1) dv1_step = dv1 / (float)abs(dy1); - if (dy1) dw1_step = dw1 / (float)abs(dy1); - - dcr1_step = 0; dcg1_step = 0; dcb1_step = 0; dca1_step = 0; - if (dy1) dcr1_step = dcr1 / (float)abs(dy1); - if (dy1) dcg1_step = dcg1 / (float)abs(dy1); - if (dy1) dcb1_step = dcb1 / (float)abs(dy1); - if (dy1) dca1_step = dca1 / (float)abs(dy1); - - if (dy1) - { - for (int i = y2; i <= y3; i++) - { - int ax = x2 + (float)(i - y2) * dax_step; - int bx = x1 + (float)(i - y1) * dbx_step; - - float tex_su = u2 + (float)(i - y2) * du1_step; - float tex_sv = v2 + (float)(i - y2) * dv1_step; - float tex_sw = w2 + (float)(i - y2) * dw1_step; - - float tex_eu = u1 + (float)(i - y1) * du2_step; - float tex_ev = v1 + (float)(i - y1) * dv2_step; - float tex_ew = w1 + (float)(i - y1) * dw2_step; - - float col_sr = c2.r + (float)(i - y2) * dcr1_step; - float col_sg = c2.g + (float)(i - y2) * dcg1_step; - float col_sb = c2.b + (float)(i - y2) * dcb1_step; - float col_sa = c2.a + (float)(i - y2) * dca1_step; - - float col_er = c1.r + (float)(i - y1) * dcr2_step; - float col_eg = c1.g + (float)(i - y1) * dcg2_step; - float col_eb = c1.b + (float)(i - y1) * dcb2_step; - float col_ea = c1.a + (float)(i - y1) * dca2_step; - - if (ax > bx) - { - std::swap(ax, bx); - std::swap(tex_su, tex_eu); - std::swap(tex_sv, tex_ev); - std::swap(tex_sw, tex_ew); - std::swap(col_sr, col_er); - std::swap(col_sg, col_eg); - std::swap(col_sb, col_eb); - std::swap(col_sa, col_ea); - } - - tex_u = tex_su; - tex_v = tex_sv; - tex_w = tex_sw; - col_r = col_sr; - col_g = col_sg; - col_b = col_sb; - col_a = col_sa; - - float tstep = 1.0f / ((float)(bx - ax)); - float t = 0.0f; - - for (int j = ax; j < bx; j++) - { - tex_u = (1.0f - t) * tex_su + t * tex_eu; - tex_v = (1.0f - t) * tex_sv + t * tex_ev; - tex_w = (1.0f - t) * tex_sw + t * tex_ew; - col_r = (1.0f - t) * col_sr + t * col_er; - col_g = (1.0f - t) * col_sg + t * col_eg; - col_b = (1.0f - t) * col_sb + t * col_eb; - col_a = (1.0f - t) * col_sa + t * col_ea; - - pixel_r = col_r; - pixel_g = col_g; - pixel_b = col_b; - pixel_a = col_a; - - if (nFlags & GFX3D::RENDER_TEXTURED) - { - if (spr != nullptr) - { - olc::Pixel sample = spr->Sample(tex_u / tex_w, tex_v / tex_w); - pixel_r *= sample.r / 255.0f; - pixel_g *= sample.g / 255.0f; - pixel_b *= sample.b / 255.0f; - pixel_a *= sample.a / 255.0f; - } - } - - if (nFlags & GFX3D::RENDER_DEPTH) - { - if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j]) - if (pge->Draw(j, i, olc::Pixel(pixel_r * 1.0f, pixel_g * 1.0f, pixel_b * 1.0f, pixel_a * 1.0f))) - m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w; - } - else - { - pge->Draw(j, i, olc::Pixel(pixel_r * 1.0f, pixel_g * 1.0f, pixel_b * 1.0f, pixel_a * 1.0f)); - } - - t += tstep; - } - } - } - } - - - - //GFX3D::MipMap::MipMap() : olc::Sprite(){} - //GFX3D::MipMap::MipMap(std::string sImageFile) : olc::Sprite(sImageFile) - //{ - // GenerateMipLevels(); - //} - //GFX3D::MipMap::MipMap(std::string sImageFile, olc::ResourcePack *pack) : olc::Sprite(sImageFile, pack){} - //GFX3D::MipMap::MipMap(int32_t w, int32_t h) : olc::Sprite(w, h) {} - - //int GFX3D::MipMap::GenerateMipLevels() - //{ - // int nLevelsW = 0; - // int nLevelsH = 0; - // int w = width; - // int h = height; - // while (w > 1) { w >>= 1; nLevelsW++; } - // while (h > 1) { h >>= 1; nLevelsH++; } - - // int nLevels = std::min(nLevelsW, nLevelsH); - - // w = width >> 1; - // h = height >> 1; - - // vecMipMaps.emplace_back(w, h); // Level 0 - // memcpy(vecMipMaps[0].GetData(), GetData(), w*h*sizeof(uint32_t)); - - // for (int i = 1; i < nLevels; i++) - // { - // vecMipMaps.emplace_back(w, h); - // pge->SetDrawTarget(&vecMipMaps[i]); - // for (int x = 0; x < w; x++) - // for (int y = 0; y < h; y++) - // pge->Draw(x, y, vecMipMaps[i-1].SampleBL((float)x / (float)w, (float)y / (float)h)); - // w >>= 1; h >>= 1; - // } - - // pge->SetDrawTarget(nullptr); - // return nLevels; - //} - // - //olc::rcode GFX3D::MipMap::LoadFromFile(std::string sImageFile, olc::ResourcePack *pack) - //{ - // olc::rcode r = olc::Sprite::LoadFromFile(sImageFile, pack); - // if (r == olc::FAIL) return r; - // GenerateMipLevels(); - // return r; - //} - - //olc::rcode GFX3D::MipMap::LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack) - //{ - // olc::rcode r = olc::Sprite::LoadFromPGESprFile(sImageFile, pack); - // if (r == olc::FAIL) return r; - // GenerateMipLevels(); - // return r; - //} - // - //olc::Pixel GFX3D::MipMap::Sample(float x, float y, float z) - //{ - // int nLevel = (int)(z * (float)vecMipMaps.size()); - // return vecMipMaps[nLevel].Sample(x, y); - //} - - //olc::Pixel GFX3D::MipMap::SampleBL(float u, float v, float z); - -} - -#endif \ No newline at end of file diff --git a/Videos/CarCrimeCity/Part2/olcPixelGameEngine.cpp b/Videos/CarCrimeCity/Part2/olcPixelGameEngine.cpp deleted file mode 100644 index 6ad6ab0..0000000 --- a/Videos/CarCrimeCity/Part2/olcPixelGameEngine.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#define OLC_PGEX_GRAPHICS3D -#include "olcPGEX_Graphics3D.h" diff --git a/Videos/CarCrimeCity/Part2/olcPixelGameEngine.h b/Videos/CarCrimeCity/Part2/olcPixelGameEngine.h deleted file mode 100644 index 4d13e6d..0000000 --- a/Videos/CarCrimeCity/Part2/olcPixelGameEngine.h +++ /dev/null @@ -1,2317 +0,0 @@ -/* - olcPixelGameEngine.h - - +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine v1.17 | - | "Like the command prompt console one, but not..." - javidx9 | - +-------------------------------------------------------------+ - - What is this? - ~~~~~~~~~~~~~ - The olcConsoleGameEngine has been a surprising and wonderful success for me, - and I'm delighted how people have reacted so positively towards it, so thanks - for that. - - However, there are limitations that I simply cannot avoid. Firstly, I need to - maintain several different versions of it to accommodate users on Windows7, - 8, 10, Linux, Mac, Visual Studio & Code::Blocks. Secondly, this year I've been - pushing the console to the limits of its graphical capabilities and the effect - is becoming underwhelming. The engine itself is not slow at all, but the process - that Windows uses to draw the command prompt to the screen is, and worse still, - it's dynamic based upon the variation of character colours and glyphs. Sadly - I have no control over this, and recent videos that are extremely graphical - (for a command prompt :P ) have been dipping to unacceptable framerates. As - the channel has been popular with aspiring game developers, I'm concerned that - the visual appeal of the command prompt is perhaps limited to us oldies, and I - dont want to alienate younger learners. Finally, I'd like to demonstrate many - more algorithms and image processing that exist in the graphical domain, for - which the console is insufficient. - - For this reason, I have created olcPixelGameEngine! The look and feel to the - programmer is almost identical, so all of my existing code from the videos is - easily portable, and the programmer uses this file in exactly the same way. But - I've decided that rather than just build a command prompt emulator, that I - would at least harness some modern(ish) portable technologies. - - As a result, the olcPixelGameEngine supports 32-bit colour, is written in a - cross-platform style, uses modern(ish) C++ conventions and most importantly, - renders much much faster. I will use this version when my applications are - predominantly graphics based, but use the console version when they are - predominantly text based - Don't worry, loads more command prompt silliness to - come yet, but evolution is important!! - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - 1. Redistributions or derivations of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce the above - copyright notice. This list of conditions and the following disclaimer must be - reproduced in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may - be used to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - Patreon: https://www.patreon.com/javidx9 - - Relevant Videos - ~~~~~~~~~~~~~~~ - https://youtu.be/kRH6oJLFYxY Introducing olcPixelGameEngine - - Compiling in Linux - ~~~~~~~~~~~~~~~~~~ - You will need a modern C++ compiler, so update yours! - To compile use the command: - - g++ -o YourProgName YourSource.cpp -lX11 -lGL -lpthread -lpng - - On some Linux configurations, the frame rate is locked to the refresh - rate of the monitor. This engine tries to unlock it but may not be - able to, in which case try launching your program like this: - - vblank_mode=0 ./YourProgName - - - Compiling in Code::Blocks on Windows - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Well I wont judge you, but make sure your Code::Blocks installation - is really up to date - you may even consider updating your C++ toolchain - to use MinGW32-W64, so google this. You will also need to enable C++14 - in your build options, and add to your linker the following libraries: - user32 gdi32 opengl32 gdiplus - - Ports - ~~~~~ - olc::PixelGameEngine has been ported and tested with varying degrees of - success to: WinXP, Win7, Win8, Win10, Various Linux, Rapberry Pi, - Chromebook, Playstation Portable (PSP) and Nintendo Switch. If you are - interested in the details of these ports, come and visit the Discord! - - Thanks - ~~~~~~ - I'd like to extend thanks to Eremiell, slavka, gurkanctn, Phantim, - JackOJC, KrossX, Huhlig, Dragoneye, Appa, JustinRichardsMusic, SliceNDice - Ralakus, Gorbit99, raoul, joshinils, benedani & MagetzUb for advice, ideas and - testing, and I'd like to extend my appreciation to the 40K YouTube followers, - 22 Patreons and 2.6K Discord server members who give me the motivation to keep - going with all this :D - - Special thanks to those who bring gifts! - GnarGnarHead.......Domina - Gorbit99...........Bastion, Ori & The Blind Forest - Marti Morta........Gris - - Special thanks to my Patreons too - I wont name you on here, but I've - certainly enjoyed my tea and flapjacks :D - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019 -*/ - -////////////////////////////////////////////////////////////////////////////////////////// - -/* Example Usage (main.cpp) - #define OLC_PGE_APPLICATION - #include "olcPixelGameEngine.h" - // Override base class with your custom functionality - class Example : public olc::PixelGameEngine - { - public: - Example() - { - sAppName = "Example"; - } - public: - bool OnUserCreate() override - { - // Called once at the start, so create things here - return true; - } - bool OnUserUpdate(float fElapsedTime) override - { - // called once per frame, draws random coloured pixels - for (int x = 0; x < ScreenWidth(); x++) - for (int y = 0; y < ScreenHeight(); y++) - Draw(x, y, olc::Pixel(rand() % 255, rand() % 255, rand()% 255)); - return true; - } - }; - int main() - { - Example demo; - if (demo.Construct(256, 240, 4, 4)) - demo.Start(); - return 0; - } -*/ - -#ifndef OLC_PGE_DEF -#define OLC_PGE_DEF - -#ifdef _WIN32 - // Link to libraries -#ifndef __MINGW32__ - #pragma comment(lib, "user32.lib") // Visual Studio Only - #pragma comment(lib, "gdi32.lib") // For other Windows Compilers please add - #pragma comment(lib, "opengl32.lib") // these libs to your linker input - #pragma comment(lib, "gdiplus.lib") -#else - // In Code::Blocks, Select C++14 in your build options, and add the - // following libs to your linker: user32 gdi32 opengl32 gdiplus - #if !defined _WIN32_WINNT - #ifdef HAVE_MSMF - #define _WIN32_WINNT 0x0600 // Windows Vista - #else - #define _WIN32_WINNT 0x0500 // Windows 2000 - #endif - #endif -#endif - // Include WinAPI - #include - #include - - // OpenGL Extension - #include - typedef BOOL(WINAPI wglSwapInterval_t) (int interval); - static wglSwapInterval_t *wglSwapInterval; -#else - #include - #include - #include - #include - #include - typedef int(glSwapInterval_t) (Display *dpy, GLXDrawable drawable, int interval); - static glSwapInterval_t *glSwapIntervalEXT; -#endif - - -// Standard includes -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef min -#undef max - -namespace olc // All OneLoneCoder stuff will now exist in the "olc" namespace -{ - struct Pixel - { - union - { - uint32_t n = 0xFF000000; - struct - { - uint8_t r; uint8_t g; uint8_t b; uint8_t a; - }; - }; - - Pixel(); - Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255); - Pixel(uint32_t p); - enum Mode { NORMAL, MASK, ALPHA, CUSTOM }; - }; - - // Some constants for symbolic naming of Pixels - static const Pixel - WHITE(255, 255, 255), - GREY(192, 192, 192), DARK_GREY(128, 128, 128), VERY_DARK_GREY(64, 64, 64), - RED(255, 0, 0), DARK_RED(128, 0, 0), VERY_DARK_RED(64, 0, 0), - YELLOW(255, 255, 0), DARK_YELLOW(128, 128, 0), VERY_DARK_YELLOW(64, 64, 0), - GREEN(0, 255, 0), DARK_GREEN(0, 128, 0), VERY_DARK_GREEN(0, 64, 0), - CYAN(0, 255, 255), DARK_CYAN(0, 128, 128), VERY_DARK_CYAN(0, 64, 64), - BLUE(0, 0, 255), DARK_BLUE(0, 0, 128), VERY_DARK_BLUE(0, 0, 64), - MAGENTA(255, 0, 255), DARK_MAGENTA(128, 0, 128), VERY_DARK_MAGENTA(64, 0, 64), - BLACK(0, 0, 0), - BLANK(0, 0, 0, 0); - - enum rcode - { - FAIL = 0, - OK = 1, - NO_FILE = -1, - }; - - //================================================================================== - - template - struct v2d_generic - { - T x = 0; - T y = 0; - - inline v2d_generic() : x(0), y(0) { } - inline v2d_generic(T _x, T _y) : x(_x), y(_y) { } - inline v2d_generic(const v2d_generic& v) : x(v.x), y(v.y){ } - inline T mag() { return sqrt(x * x + y * y); } - inline v2d_generic norm() { T r = 1 / mag(); return v2d_generic(x*r, y*r); } - inline v2d_generic perp() { return v2d_generic(-y, x); } - inline T dot(const v2d_generic& rhs) { return this->x * rhs.x + this->y * rhs.y; } - inline T cross(const v2d_generic& rhs) { return this->x * rhs.y - this->y * rhs.x; } - inline v2d_generic operator + (const v2d_generic& rhs) const { return v2d_generic(this->x + rhs.x, this->y + rhs.y);} - inline v2d_generic operator - (const v2d_generic& rhs) const { return v2d_generic(this->x - rhs.x, this->y - rhs.y);} - inline v2d_generic operator * (const T& rhs) const { return v2d_generic(this->x * rhs, this->y * rhs); } - inline v2d_generic operator / (const T& rhs) const { return v2d_generic(this->x / rhs, this->y / rhs); } - inline v2d_generic& operator += (const v2d_generic& rhs) { this->x += rhs.x; this->y += rhs.y; return *this; } - inline v2d_generic& operator -= (const v2d_generic& rhs) { this->x -= rhs.x; this->y -= rhs.y; return *this; } - inline v2d_generic& operator *= (const T& rhs) { this->x *= rhs; this->y *= rhs; return *this; } - inline v2d_generic& operator /= (const T& rhs) { this->x /= rhs; this->y /= rhs; return *this; } - inline T& operator [] (std::size_t i) { return *((T*)this + i); /* <-- D'oh :( */ } - }; - - template inline v2d_generic operator * (const float& lhs, const v2d_generic& rhs) { return v2d_generic(lhs * rhs.x, lhs * rhs.y); } - template inline v2d_generic operator * (const double& lhs, const v2d_generic& rhs){ return v2d_generic(lhs * rhs.x, lhs * rhs.y); } - template inline v2d_generic operator * (const int& lhs, const v2d_generic& rhs) { return v2d_generic(lhs * rhs.x, lhs * rhs.y); } - template inline v2d_generic operator / (const float& lhs, const v2d_generic& rhs) { return v2d_generic(lhs / rhs.x, lhs / rhs.y); } - template inline v2d_generic operator / (const double& lhs, const v2d_generic& rhs){ return v2d_generic(lhs / rhs.x, lhs / rhs.y); } - template inline v2d_generic operator / (const int& lhs, const v2d_generic& rhs) { return v2d_generic(lhs / rhs.x, lhs / rhs.y); } - - typedef v2d_generic vi2d; - typedef v2d_generic vf2d; - typedef v2d_generic vd2d; - - //============================================================= - - struct HWButton - { - bool bPressed = false; // Set once during the frame the event occurs - bool bReleased = false; // Set once during the frame the event occurs - bool bHeld = false; // Set true for all frames between pressed and released events - }; - - //============================================================= - - - class ResourcePack - { - public: - ResourcePack(); - ~ResourcePack(); - struct sEntry : public std::streambuf { - uint32_t nID, nFileOffset, nFileSize; uint8_t* data; void _config() { this->setg((char*)data, (char*)data, (char*)(data + nFileSize)); } - }; - - public: - olc::rcode AddToPack(std::string sFile); - - public: - olc::rcode SavePack(std::string sFile); - olc::rcode LoadPack(std::string sFile); - olc::rcode ClearPack(); - - public: - olc::ResourcePack::sEntry GetStreamBuffer(std::string sFile); - - private: - - std::map mapFiles; - }; - - //============================================================= - - // A bitmap-like structure that stores a 2D array of Pixels - class Sprite - { - public: - Sprite(); - Sprite(std::string sImageFile); - Sprite(std::string sImageFile, olc::ResourcePack *pack); - Sprite(int32_t w, int32_t h); - ~Sprite(); - - public: - olc::rcode LoadFromFile(std::string sImageFile, olc::ResourcePack *pack = nullptr); - olc::rcode LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack = nullptr); - olc::rcode SaveToPGESprFile(std::string sImageFile); - - public: - int32_t width = 0; - int32_t height = 0; - enum Mode { NORMAL, PERIODIC }; - - public: - void SetSampleMode(olc::Sprite::Mode mode = olc::Sprite::Mode::NORMAL); - Pixel GetPixel(int32_t x, int32_t y); - bool SetPixel(int32_t x, int32_t y, Pixel p); - - Pixel Sample(float x, float y); - Pixel SampleBL(float u, float v); - Pixel* GetData(); - - private: - Pixel *pColData = nullptr; - Mode modeSample = Mode::NORMAL; - -#ifdef OLC_DBG_OVERDRAW - public: - static int nOverdrawCount; -#endif - - }; - - //============================================================= - - enum Key - { - NONE, - A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, - K0, K1, K2, K3, K4, K5, K6, K7, K8, K9, - F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, - UP, DOWN, LEFT, RIGHT, - SPACE, TAB, SHIFT, CTRL, INS, DEL, HOME, END, PGUP, PGDN, - BACK, ESCAPE, RETURN, ENTER, PAUSE, SCROLL, - NP0, NP1, NP2, NP3, NP4, NP5, NP6, NP7, NP8, NP9, - NP_MUL, NP_DIV, NP_ADD, NP_SUB, NP_DECIMAL, - }; - - - //============================================================= - - class PixelGameEngine - { - public: - PixelGameEngine(); - - public: - olc::rcode Construct(uint32_t screen_w, uint32_t screen_h, uint32_t pixel_w, uint32_t pixel_h, bool full_screen = false); - olc::rcode Start(); - - public: // Override Interfaces - // Called once on application startup, use to load your resources - virtual bool OnUserCreate(); - // Called every frame, and provides you with a time per frame value - virtual bool OnUserUpdate(float fElapsedTime); - // Called once on application termination, so you can be a clean coder - virtual bool OnUserDestroy(); - - public: // Hardware Interfaces - // Returns true if window is currently in focus - bool IsFocused(); - // Get the state of a specific keyboard button - HWButton GetKey(Key k); - // Get the state of a specific mouse button - HWButton GetMouse(uint32_t b); - // Get Mouse X coordinate in "pixel" space - int32_t GetMouseX(); - // Get Mouse Y coordinate in "pixel" space - int32_t GetMouseY(); - // Get Mouse Wheel Delta - int32_t GetMouseWheel(); - - public: // Utility - // Returns the width of the screen in "pixels" - int32_t ScreenWidth(); - // Returns the height of the screen in "pixels" - int32_t ScreenHeight(); - // Returns the width of the currently selected drawing target in "pixels" - int32_t GetDrawTargetWidth(); - // Returns the height of the currently selected drawing target in "pixels" - int32_t GetDrawTargetHeight(); - // Returns the currently active draw target - Sprite* GetDrawTarget(); - - public: // Draw Routines - // Specify which Sprite should be the target of drawing functions, use nullptr - // to specify the primary screen - void SetDrawTarget(Sprite *target); - // Change the pixel mode for different optimisations - // olc::Pixel::NORMAL = No transparency - // olc::Pixel::MASK = Transparent if alpha is < 255 - // olc::Pixel::ALPHA = Full transparency - void SetPixelMode(Pixel::Mode m); - Pixel::Mode GetPixelMode(); - // Use a custom blend function - void SetPixelMode(std::function pixelMode); - // Change the blend factor form between 0.0f to 1.0f; - void SetPixelBlend(float fBlend); - // Offset texels by sub-pixel amount (advanced, do not use) - void SetSubPixelOffset(float ox, float oy); - - // Draws a single Pixel - virtual bool Draw(int32_t x, int32_t y, Pixel p = olc::WHITE); - // Draws a line from (x1,y1) to (x2,y2) - void DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p = olc::WHITE, uint32_t pattern = 0xFFFFFFFF); - // Draws a circle located at (x,y) with radius - void DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p = olc::WHITE, uint8_t mask = 0xFF); - // Fills a circle located at (x,y) with radius - void FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p = olc::WHITE); - // Draws a rectangle at (x,y) to (x+w,y+h) - void DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p = olc::WHITE); - // Fills a rectangle at (x,y) to (x+w,y+h) - void FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p = olc::WHITE); - // Draws a triangle between points (x1,y1), (x2,y2) and (x3,y3) - void DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p = olc::WHITE); - // Flat fills a triangle between points (x1,y1), (x2,y2) and (x3,y3) - void FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p = olc::WHITE); - // Draws an entire sprite at location (x,y) - void DrawSprite(int32_t x, int32_t y, Sprite *sprite, uint32_t scale = 1); - // Draws an area of a sprite at location (x,y), where the - // selected area is (ox,oy) to (ox+w,oy+h) - void DrawPartialSprite(int32_t x, int32_t y, Sprite *sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale = 1); - // Draws a single line of text - void DrawString(int32_t x, int32_t y, std::string sText, Pixel col = olc::WHITE, uint32_t scale = 1); - // Clears entire draw target to Pixel - void Clear(Pixel p); - - public: // Branding - std::string sAppName; - - private: // Inner mysterious workings - Sprite *pDefaultDrawTarget = nullptr; - Sprite *pDrawTarget = nullptr; - Pixel::Mode nPixelMode = Pixel::NORMAL; - float fBlendFactor = 1.0f; - uint32_t nScreenWidth = 256; - uint32_t nScreenHeight = 240; - uint32_t nPixelWidth = 4; - uint32_t nPixelHeight = 4; - int32_t nMousePosX = 0; - int32_t nMousePosY = 0; - int32_t nMouseWheelDelta = 0; - int32_t nMousePosXcache = 0; - int32_t nMousePosYcache = 0; - int32_t nMouseWheelDeltaCache = 0; - int32_t nWindowWidth = 0; - int32_t nWindowHeight = 0; - int32_t nViewX = 0; - int32_t nViewY = 0; - int32_t nViewW = 0; - int32_t nViewH = 0; - bool bFullScreen = false; - float fPixelX = 1.0f; - float fPixelY = 1.0f; - float fSubPixelOffsetX = 0.0f; - float fSubPixelOffsetY = 0.0f; - bool bHasInputFocus = false; - bool bHasMouseFocus = false; - float fFrameTimer = 1.0f; - int nFrameCount = 0; - Sprite *fontSprite = nullptr; - std::function funcPixelMode; - - static std::map mapKeys; - bool pKeyNewState[256]{ 0 }; - bool pKeyOldState[256]{ 0 }; - HWButton pKeyboardState[256]; - - bool pMouseNewState[5]{ 0 }; - bool pMouseOldState[5]{ 0 }; - HWButton pMouseState[5]; - -#ifdef _WIN32 - HDC glDeviceContext = nullptr; - HGLRC glRenderContext = nullptr; -#else - GLXContext glDeviceContext = nullptr; - GLXContext glRenderContext = nullptr; -#endif - GLuint glBuffer; - - void EngineThread(); - - // If anything sets this flag to false, the engine - // "should" shut down gracefully - static std::atomic bAtomActive; - - // Common initialisation functions - void olc_UpdateMouse(int32_t x, int32_t y); - void olc_UpdateMouseWheel(int32_t delta); - void olc_UpdateWindowSize(int32_t x, int32_t y); - void olc_UpdateViewport(); - bool olc_OpenGLCreate(); - void olc_ConstructFontSheet(); - - -#ifdef _WIN32 - // Windows specific window handling - HWND olc_hWnd = nullptr; - HWND olc_WindowCreate(); - std::wstring wsAppName; - static LRESULT CALLBACK olc_WindowEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -#else - // Non-Windows specific window handling - Display* olc_Display = nullptr; - Window olc_WindowRoot; - Window olc_Window; - XVisualInfo* olc_VisualInfo; - Colormap olc_ColourMap; - XSetWindowAttributes olc_SetWindowAttribs; - Display* olc_WindowCreate(); -#endif - - }; - - - class PGEX - { - friend class olc::PixelGameEngine; - protected: - static PixelGameEngine* pge; - }; - - //============================================================= -} - -#endif // OLC_PGE_DEF - - - - -/* - Object Oriented Mode - ~~~~~~~~~~~~~~~~~~~~ - - If the olcPixelGameEngine.h is called from several sources it can cause - multiple definitions of objects. To prevent this, ONLY ONE of the pathways - to including this file must have OLC_PGE_APPLICATION defined before it. This prevents - the definitions being duplicated. - - If all else fails, create a file called "olcPixelGameEngine.cpp" with the following - two lines. Then you can just #include "olcPixelGameEngine.h" as normal without worrying - about defining things. Dont forget to include that cpp file as part of your build! - - #define OLC_PGE_APPLICATION - #include "olcPixelGameEngine.h" - -*/ - -#ifdef OLC_PGE_APPLICATION -#undef OLC_PGE_APPLICATION - -namespace olc -{ - Pixel::Pixel() - { - r = 0; g = 0; b = 0; a = 255; - } - - Pixel::Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) - { - r = red; g = green; b = blue; a = alpha; - } - - Pixel::Pixel(uint32_t p) - { - n = p; - } - - //========================================================== - - std::wstring ConvertS2W(std::string s) - { -#ifdef _WIN32 - int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0); - wchar_t* buffer = new wchar_t[count]; - MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count); - std::wstring w(buffer); - delete[] buffer; - return w; -#else - return L"SVN FTW!"; -#endif - } - - Sprite::Sprite() - { - pColData = nullptr; - width = 0; - height = 0; - } - - Sprite::Sprite(std::string sImageFile) - { - LoadFromFile(sImageFile); - } - - Sprite::Sprite(std::string sImageFile, olc::ResourcePack *pack) - { - LoadFromPGESprFile(sImageFile, pack); - } - - Sprite::Sprite(int32_t w, int32_t h) - { - if(pColData) delete[] pColData; - width = w; height = h; - pColData = new Pixel[width * height]; - for (int32_t i = 0; i < width*height; i++) - pColData[i] = Pixel(); - } - - Sprite::~Sprite() - { - if (pColData) delete pColData; - } - - olc::rcode Sprite::LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack) - { - if (pColData) delete[] pColData; - - auto ReadData = [&](std::istream &is) - { - is.read((char*)&width, sizeof(int32_t)); - is.read((char*)&height, sizeof(int32_t)); - pColData = new Pixel[width * height]; - is.read((char*)pColData, width * height * sizeof(uint32_t)); - }; - - // These are essentially Memory Surfaces represented by olc::Sprite - // which load very fast, but are completely uncompressed - if (pack == nullptr) - { - std::ifstream ifs; - ifs.open(sImageFile, std::ifstream::binary); - if (ifs.is_open()) - { - ReadData(ifs); - return olc::OK; - } - else - return olc::FAIL; - } - else - { - auto streamBuffer = pack->GetStreamBuffer(sImageFile); - std::istream is(&streamBuffer); - ReadData(is); - } - - - return olc::FAIL; - } - - olc::rcode Sprite::SaveToPGESprFile(std::string sImageFile) - { - if (pColData == nullptr) return olc::FAIL; - - std::ofstream ofs; - ofs.open(sImageFile, std::ifstream::binary); - if (ofs.is_open()) - { - ofs.write((char*)&width, sizeof(int32_t)); - ofs.write((char*)&height, sizeof(int32_t)); - ofs.write((char*)pColData, width*height*sizeof(uint32_t)); - ofs.close(); - return olc::OK; - } - - return olc::FAIL; - } - - olc::rcode Sprite::LoadFromFile(std::string sImageFile, olc::ResourcePack *pack) - { -#ifdef _WIN32 - // Use GDI+ - std::wstring wsImageFile; -#ifdef __MINGW32__ - wchar_t *buffer = new wchar_t[sImageFile.length() + 1]; - mbstowcs(buffer, sImageFile.c_str(), sImageFile.length()); - buffer[sImageFile.length()] = L'\0'; - wsImageFile = buffer; - delete [] buffer; -#else - wsImageFile = ConvertS2W(sImageFile); -#endif - Gdiplus::Bitmap *bmp = Gdiplus::Bitmap::FromFile(wsImageFile.c_str()); - if (bmp == nullptr) - return olc::NO_FILE; - - width = bmp->GetWidth(); - height = bmp->GetHeight(); - pColData = new Pixel[width * height]; - - for(int x=0; xGetPixel(x, y, &c); - SetPixel(x, y, Pixel(c.GetRed(), c.GetGreen(), c.GetBlue(), c.GetAlpha())); - } - delete bmp; - return olc::OK; -#else - //////////////////////////////////////////////////////////////////////////// - // Use libpng, Thanks to Guillaume Cottenceau - // https://gist.github.com/niw/5963798 - png_structp png; - png_infop info; - - FILE *f = fopen(sImageFile.c_str(), "rb"); - if (!f) return olc::NO_FILE; - - png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png) goto fail_load; - - info = png_create_info_struct(png); - if (!info) goto fail_load; - - if (setjmp(png_jmpbuf(png))) goto fail_load; - - png_init_io(png, f); - png_read_info(png, info); - - png_byte color_type; - png_byte bit_depth; - png_bytep *row_pointers; - width = png_get_image_width(png, info); - height = png_get_image_height(png, info); - color_type = png_get_color_type(png, info); - bit_depth = png_get_bit_depth(png, info); - -#ifdef _DEBUG - std::cout << "Loading PNG: " << sImageFile << "\n"; - std::cout << "W:" << width << " H:" << height << " D:" << (int)bit_depth << "\n"; -#endif - - if (bit_depth == 16) png_set_strip_16(png); - if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png); - if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_PALETTE) - png_set_filler(png, 0xFF, PNG_FILLER_AFTER); - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png); - - png_read_update_info(png, info); - row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height); - for (int y = 0; y < height; y++) { - row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info)); - } - png_read_image(png, row_pointers); - //////////////////////////////////////////////////////////////////////////// - - // Create sprite array - pColData = new Pixel[width * height]; - - // Iterate through image rows, converting into sprite format - for (int y = 0; y < height; y++) - { - png_bytep row = row_pointers[y]; - for (int x = 0; x < width; x++) - { - png_bytep px = &(row[x * 4]); - SetPixel(x, y, Pixel(px[0], px[1], px[2], px[3])); - } - } - - fclose(f); - return olc::OK; - - fail_load: - width = 0; - height = 0; - fclose(f); - pColData = nullptr; - return olc::FAIL; -#endif - } - - void Sprite::SetSampleMode(olc::Sprite::Mode mode) - { - modeSample = mode; - } - - - Pixel Sprite::GetPixel(int32_t x, int32_t y) - { - if (modeSample == olc::Sprite::Mode::NORMAL) - { - if (x >= 0 && x < width && y >= 0 && y < height) - return pColData[y*width + x]; - else - return Pixel(0, 0, 0, 0); - } - else - { - return pColData[abs(y%height)*width + abs(x%width)]; - } - } - - bool Sprite::SetPixel(int32_t x, int32_t y, Pixel p) - { - -#ifdef OLC_DBG_OVERDRAW - nOverdrawCount++; -#endif - - if (x >= 0 && x < width && y >= 0 && y < height) - { - pColData[y*width + x] = p; - return true; - } - else - return false; - } - - Pixel Sprite::Sample(float x, float y) - { - int32_t sx = std::min((int32_t)((x * (float)width)), width - 1); - int32_t sy = std::min((int32_t)((y * (float)height)), height - 1); - return GetPixel(sx, sy); - } - - Pixel Sprite::SampleBL(float u, float v) - { - u = u * width - 0.5f; - v = v * height - 0.5f; - int x = (int)floor(u); // cast to int rounds toward zero, not downward - int y = (int)floor(v); // Thanks @joshinils - float u_ratio = u - x; - float v_ratio = v - y; - float u_opposite = 1 - u_ratio; - float v_opposite = 1 - v_ratio; - - olc::Pixel p1 = GetPixel(std::max(x, 0), std::max(y, 0)); - olc::Pixel p2 = GetPixel(std::min(x + 1, (int)width - 1), std::max(y, 0)); - olc::Pixel p3 = GetPixel(std::max(x, 0), std::min(y + 1, (int)height - 1)); - olc::Pixel p4 = GetPixel(std::min(x + 1, (int)width - 1), std::min(y + 1, (int)height - 1)); - - return olc::Pixel( - (uint8_t)((p1.r * u_opposite + p2.r * u_ratio) * v_opposite + (p3.r * u_opposite + p4.r * u_ratio) * v_ratio), - (uint8_t)((p1.g * u_opposite + p2.g * u_ratio) * v_opposite + (p3.g * u_opposite + p4.g * u_ratio) * v_ratio), - (uint8_t)((p1.b * u_opposite + p2.b * u_ratio) * v_opposite + (p3.b * u_opposite + p4.b * u_ratio) * v_ratio)); - } - - Pixel* Sprite::GetData() { return pColData; } - - //========================================================== - - ResourcePack::ResourcePack() - { - - } - - ResourcePack::~ResourcePack() - { - ClearPack(); - } - - olc::rcode ResourcePack::AddToPack(std::string sFile) - { - std::ifstream ifs(sFile, std::ifstream::binary); - if (!ifs.is_open()) return olc::FAIL; - - // Get File Size - std::streampos p = 0; - p = ifs.tellg(); - ifs.seekg(0, std::ios::end); - p = ifs.tellg() - p; - ifs.seekg(0, std::ios::beg); - - // Create entry - sEntry e; - e.data = nullptr; - e.nFileSize = (uint32_t)p; - - // Read file into memory - e.data = new uint8_t[(uint32_t)e.nFileSize]; - ifs.read((char*)e.data, e.nFileSize); - ifs.close(); - - // Add To Map - mapFiles[sFile] = e; - return olc::OK; - } - - olc::rcode ResourcePack::SavePack(std::string sFile) - { - std::ofstream ofs(sFile, std::ofstream::binary); - if (!ofs.is_open()) return olc::FAIL; - - // 1) Write Map - size_t nMapSize = mapFiles.size(); - ofs.write((char*)&nMapSize, sizeof(size_t)); - for (auto &e : mapFiles) - { - size_t nPathSize = e.first.size(); - ofs.write((char*)&nPathSize, sizeof(size_t)); - ofs.write(e.first.c_str(), nPathSize); - ofs.write((char*)&e.second.nID, sizeof(uint32_t)); - ofs.write((char*)&e.second.nFileSize, sizeof(uint32_t)); - ofs.write((char*)&e.second.nFileOffset, sizeof(uint32_t)); - } - - // 2) Write Data - std::streampos offset = ofs.tellp(); - for (auto &e : mapFiles) - { - e.second.nFileOffset = (uint32_t)offset; - ofs.write((char*)e.second.data, e.second.nFileSize); - offset += e.second.nFileSize; - } - - // 3) Rewrite Map (it has been updated with offsets now) - ofs.seekp(std::ios::beg); - ofs.write((char*)&nMapSize, sizeof(size_t)); - for (auto &e : mapFiles) - { - size_t nPathSize = e.first.size(); - ofs.write((char*)&nPathSize, sizeof(size_t)); - ofs.write(e.first.c_str(), nPathSize); - ofs.write((char*)&e.second.nID, sizeof(uint32_t)); - ofs.write((char*)&e.second.nFileSize, sizeof(uint32_t)); - ofs.write((char*)&e.second.nFileOffset, sizeof(uint32_t)); - } - ofs.close(); - - return olc::OK; - } - - olc::rcode ResourcePack::LoadPack(std::string sFile) - { - std::ifstream ifs(sFile, std::ifstream::binary); - if (!ifs.is_open()) return olc::FAIL; - - // 1) Read Map - size_t nMapEntries; - ifs.read((char*)&nMapEntries, sizeof(size_t)); - for (size_t i = 0; i < nMapEntries; i++) - { - size_t nFilePathSize = 0; - ifs.read((char*)&nFilePathSize, sizeof(size_t)); - - std::string sFileName(nFilePathSize, ' '); - for (size_t j = 0; j < nFilePathSize; j++) - sFileName[j] = ifs.get(); - - sEntry e; - e.data = nullptr; - ifs.read((char*)&e.nID, sizeof(uint32_t)); - ifs.read((char*)&e.nFileSize, sizeof(uint32_t)); - ifs.read((char*)&e.nFileOffset, sizeof(uint32_t)); - mapFiles[sFileName] = e; - } - - // 2) Read Data - for (auto &e : mapFiles) - { - e.second.data = new uint8_t[(uint32_t)e.second.nFileSize]; - ifs.seekg(e.second.nFileOffset); - ifs.read((char*)e.second.data, e.second.nFileSize); - e.second._config(); - } - - ifs.close(); - return olc::OK; - } - - olc::ResourcePack::sEntry ResourcePack::GetStreamBuffer(std::string sFile) - { - return mapFiles[sFile]; - } - - olc::rcode ResourcePack::ClearPack() - { - for (auto &e : mapFiles) - { - if (e.second.data != nullptr) - delete[] e.second.data; - } - - mapFiles.clear(); - return olc::OK; - } - - //========================================================== - - PixelGameEngine::PixelGameEngine() - { - sAppName = "Undefined"; - olc::PGEX::pge = this; - } - - olc::rcode PixelGameEngine::Construct(uint32_t screen_w, uint32_t screen_h, uint32_t pixel_w, uint32_t pixel_h, bool full_screen) - { - nScreenWidth = screen_w; - nScreenHeight = screen_h; - nPixelWidth = pixel_w; - nPixelHeight = pixel_h; - bFullScreen = full_screen; - - fPixelX = 2.0f / (float)(nScreenWidth); - fPixelY = 2.0f / (float)(nScreenHeight); - - if (nPixelWidth == 0 || nPixelHeight == 0 || nScreenWidth == 0 || nScreenHeight == 0) - return olc::FAIL; - -#ifdef _WIN32 -#ifdef UNICODE -#ifndef __MINGW32__ - wsAppName = ConvertS2W(sAppName); -#endif -#endif -#endif - // Load the default font sheet - olc_ConstructFontSheet(); - - // Create a sprite that represents the primary drawing target - pDefaultDrawTarget = new Sprite(nScreenWidth, nScreenHeight); - SetDrawTarget(nullptr); - return olc::OK; - } - - olc::rcode PixelGameEngine::Start() - { - // Construct the window - if (!olc_WindowCreate()) - return olc::FAIL; - - // Load libraries required for PNG file interaction -//#ifdef _WIN32 -// // Windows use GDI+ -// Gdiplus::GdiplusStartupInput startupInput; -// ULONG_PTR token; -// Gdiplus::GdiplusStartup(&token, &startupInput, NULL); -//#else -// // Linux use libpng -// -//#endif - // Start the thread - bAtomActive = true; - std::thread t = std::thread(&PixelGameEngine::EngineThread, this); - -#ifdef _WIN32 - // Handle Windows Message Loop - MSG msg; - while (GetMessage(&msg, NULL, 0, 0) > 0) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } -#endif - - // Wait for thread to be exited - t.join(); - return olc::OK; - } - - void PixelGameEngine::SetDrawTarget(Sprite *target) - { - if (target) - pDrawTarget = target; - else - pDrawTarget = pDefaultDrawTarget; - } - - Sprite* PixelGameEngine::GetDrawTarget() - { - return pDrawTarget; - } - - int32_t PixelGameEngine::GetDrawTargetWidth() - { - if (pDrawTarget) - return pDrawTarget->width; - else - return 0; - } - - int32_t PixelGameEngine::GetDrawTargetHeight() - { - if (pDrawTarget) - return pDrawTarget->height; - else - return 0; - } - - bool PixelGameEngine::IsFocused() - { - return bHasInputFocus; - } - - HWButton PixelGameEngine::GetKey(Key k) - { - return pKeyboardState[k]; - } - - HWButton PixelGameEngine::GetMouse(uint32_t b) - { - return pMouseState[b]; - } - - int32_t PixelGameEngine::GetMouseX() - { - return nMousePosX; - } - - int32_t PixelGameEngine::GetMouseY() - { - return nMousePosY; - } - - int32_t PixelGameEngine::GetMouseWheel() - { - return nMouseWheelDelta; - } - - int32_t PixelGameEngine::ScreenWidth() - { - return nScreenWidth; - } - - int32_t PixelGameEngine::ScreenHeight() - { - return nScreenHeight; - } - - bool PixelGameEngine::Draw(int32_t x, int32_t y, Pixel p) - { - if (!pDrawTarget) return false; - - - if (nPixelMode == Pixel::NORMAL) - { - return pDrawTarget->SetPixel(x, y, p); - } - - if (nPixelMode == Pixel::MASK) - { - if(p.a == 255) - return pDrawTarget->SetPixel(x, y, p); - } - - if (nPixelMode == Pixel::ALPHA) - { - Pixel d = pDrawTarget->GetPixel(x, y); - float a = (float)(p.a / 255.0f) * fBlendFactor; - float c = 1.0f - a; - float r = a * (float)p.r + c * (float)d.r; - float g = a * (float)p.g + c * (float)d.g; - float b = a * (float)p.b + c * (float)d.b; - return pDrawTarget->SetPixel(x, y, Pixel((uint8_t)r, (uint8_t)g, (uint8_t)b)); - } - - if (nPixelMode == Pixel::CUSTOM) - { - return pDrawTarget->SetPixel(x, y, funcPixelMode(x, y, p, pDrawTarget->GetPixel(x, y))); - } - - return false; - } - - void PixelGameEngine::SetSubPixelOffset(float ox, float oy) - { - fSubPixelOffsetX = ox * fPixelX; - fSubPixelOffsetY = oy * fPixelY; - } - - void PixelGameEngine::DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p, uint32_t pattern) - { - int x, y, dx, dy, dx1, dy1, px, py, xe, ye, i; - dx = x2 - x1; dy = y2 - y1; - - auto rol = [&](void) - { - pattern = (pattern << 1) | (pattern >> 31); - return pattern & 1; - }; - - // straight lines idea by gurkanctn - if (dx == 0) // Line is vertical - { - if (y2 < y1) std::swap(y1, y2); - for (y = y1; y <= y2; y++) - if (rol()) Draw(x1, y, p); - return; - } - - if (dy == 0) // Line is horizontal - { - if (x2 < x1) std::swap(x1, x2); - for (x = x1; x <= x2; x++) - if (rol()) Draw(x, y1, p); - return; - } - - // Line is Funk-aye - dx1 = abs(dx); dy1 = abs(dy); - px = 2 * dy1 - dx1; py = 2 * dx1 - dy1; - if (dy1 <= dx1) - { - if (dx >= 0) - { - x = x1; y = y1; xe = x2; - } - else - { - x = x2; y = y2; xe = x1; - } - - if (rol()) Draw(x, y, p); - - for (i = 0; x0 && dy>0)) y = y + 1; else y = y - 1; - px = px + 2 * (dy1 - dx1); - } - if (rol()) Draw(x, y, p); - } - } - else - { - if (dy >= 0) - { - x = x1; y = y1; ye = y2; - } - else - { - x = x2; y = y2; ye = y1; - } - - if (rol()) Draw(x, y, p); - - for (i = 0; y0 && dy>0)) x = x + 1; else x = x - 1; - py = py + 2 * (dx1 - dy1); - } - if (rol()) Draw(x, y, p); - } - } - } - - void PixelGameEngine::DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p, uint8_t mask) - { - int x0 = 0; - int y0 = radius; - int d = 3 - 2 * radius; - if (!radius) return; - - while (y0 >= x0) // only formulate 1/8 of circle - { - if (mask & 0x01) Draw(x + x0, y - y0, p); - if (mask & 0x02) Draw(x + y0, y - x0, p); - if (mask & 0x04) Draw(x + y0, y + x0, p); - if (mask & 0x08) Draw(x + x0, y + y0, p); - if (mask & 0x10) Draw(x - x0, y + y0, p); - if (mask & 0x20) Draw(x - y0, y + x0, p); - if (mask & 0x40) Draw(x - y0, y - x0, p); - if (mask & 0x80) Draw(x - x0, y - y0, p); - if (d < 0) d += 4 * x0++ + 6; - else d += 4 * (x0++ - y0--) + 10; - } - } - - void PixelGameEngine::FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p) - { - // Taken from wikipedia - int x0 = 0; - int y0 = radius; - int d = 3 - 2 * radius; - if (!radius) return; - - auto drawline = [&](int sx, int ex, int ny) - { - for (int i = sx; i <= ex; i++) - Draw(i, ny, p); - }; - - while (y0 >= x0) - { - // Modified to draw scan-lines instead of edges - drawline(x - x0, x + x0, y - y0); - drawline(x - y0, x + y0, y - x0); - drawline(x - x0, x + x0, y + y0); - drawline(x - y0, x + y0, y + x0); - if (d < 0) d += 4 * x0++ + 6; - else d += 4 * (x0++ - y0--) + 10; - } - } - - void PixelGameEngine::DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p) - { - DrawLine(x, y, x+w, y, p); - DrawLine(x+w, y, x+w, y+h, p); - DrawLine(x+w, y+h, x, y+h, p); - DrawLine(x, y+h, x, y, p); - } - - void PixelGameEngine::Clear(Pixel p) - { - int pixels = GetDrawTargetWidth() * GetDrawTargetHeight(); - Pixel* m = GetDrawTarget()->GetData(); - for (int i = 0; i < pixels; i++) - m[i] = p; -#ifdef OLC_DBG_OVERDRAW - olc::Sprite::nOverdrawCount += pixels; -#endif - } - - void PixelGameEngine::FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p) - { - int32_t x2 = x + w; - int32_t y2 = y + h; - - if (x < 0) x = 0; - if (x >= (int32_t)nScreenWidth) x = (int32_t)nScreenWidth; - if (y < 0) y = 0; - if (y >= (int32_t)nScreenHeight) y = (int32_t)nScreenHeight; - - if (x2 < 0) x2 = 0; - if (x2 >= (int32_t)nScreenWidth) x2 = (int32_t)nScreenWidth; - if (y2 < 0) y2 = 0; - if (y2 >= (int32_t)nScreenHeight) y2 = (int32_t)nScreenHeight; - - for (int i = x; i < x2; i++) - for (int j = y; j < y2; j++) - Draw(i, j, p); - } - - void PixelGameEngine::DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p) - { - DrawLine(x1, y1, x2, y2, p); - DrawLine(x2, y2, x3, y3, p); - DrawLine(x3, y3, x1, y1, p); - } - - // https://www.avrfreaks.net/sites/default/files/triangles.c - void PixelGameEngine::FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p) - { - auto SWAP = [](int &x, int &y) { int t = x; x = y; y = t; }; - auto drawline = [&](int sx, int ex, int ny) { for (int i = sx; i <= ex; i++) Draw(i, ny, p); }; - - int t1x, t2x, y, minx, maxx, t1xp, t2xp; - bool changed1 = false; - bool changed2 = false; - int signx1, signx2, dx1, dy1, dx2, dy2; - int e1, e2; - // Sort vertices - if (y1>y2) { SWAP(y1, y2); SWAP(x1, x2); } - if (y1>y3) { SWAP(y1, y3); SWAP(x1, x3); } - if (y2>y3) { SWAP(y2, y3); SWAP(x2, x3); } - - t1x = t2x = x1; y = y1; // Starting points - dx1 = (int)(x2 - x1); if (dx1<0) { dx1 = -dx1; signx1 = -1; } - else signx1 = 1; - dy1 = (int)(y2 - y1); - - dx2 = (int)(x3 - x1); if (dx2<0) { dx2 = -dx2; signx2 = -1; } - else signx2 = 1; - dy2 = (int)(y3 - y1); - - if (dy1 > dx1) { // swap values - SWAP(dx1, dy1); - changed1 = true; - } - if (dy2 > dx2) { // swap values - SWAP(dy2, dx2); - changed2 = true; - } - - e2 = (int)(dx2 >> 1); - // Flat top, just process the second half - if (y1 == y2) goto next; - e1 = (int)(dx1 >> 1); - - for (int i = 0; i < dx1;) { - t1xp = 0; t2xp = 0; - if (t1x= dx1) { - e1 -= dx1; - if (changed1) t1xp = signx1;//t1x += signx1; - else goto next1; - } - if (changed1) break; - else t1x += signx1; - } - // Move line - next1: - // process second line until y value is about to change - while (1) { - e2 += dy2; - while (e2 >= dx2) { - e2 -= dx2; - if (changed2) t2xp = signx2;//t2x += signx2; - else goto next2; - } - if (changed2) break; - else t2x += signx2; - } - next2: - if (minx>t1x) minx = t1x; if (minx>t2x) minx = t2x; - if (maxx dx1) { // swap values - SWAP(dy1, dx1); - changed1 = true; - } - else changed1 = false; - - e1 = (int)(dx1 >> 1); - - for (int i = 0; i <= dx1; i++) { - t1xp = 0; t2xp = 0; - if (t1x= dx1) { - e1 -= dx1; - if (changed1) { t1xp = signx1; break; }//t1x += signx1; - else goto next3; - } - if (changed1) break; - else t1x += signx1; - if (i= dx2) { - e2 -= dx2; - if (changed2) t2xp = signx2; - else goto next4; - } - if (changed2) break; - else t2x += signx2; - } - next4: - - if (minx>t1x) minx = t1x; if (minx>t2x) minx = t2x; - if (maxxy3) return; - } - } - - void PixelGameEngine::DrawSprite(int32_t x, int32_t y, Sprite *sprite, uint32_t scale) - { - if (sprite == nullptr) - return; - - if (scale > 1) - { - for (int32_t i = 0; i < sprite->width; i++) - for (int32_t j = 0; j < sprite->height; j++) - for (uint32_t is = 0; is < scale; is++) - for (uint32_t js = 0; js < scale; js++) - Draw(x + (i*scale) + is, y + (j*scale) + js, sprite->GetPixel(i, j)); - } - else - { - for (int32_t i = 0; i < sprite->width; i++) - for (int32_t j = 0; j < sprite->height; j++) - Draw(x + i, y + j, sprite->GetPixel(i, j)); - } - } - - void PixelGameEngine::DrawPartialSprite(int32_t x, int32_t y, Sprite *sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale) - { - if (sprite == nullptr) - return; - - if (scale > 1) - { - for (int32_t i = 0; i < w; i++) - for (int32_t j = 0; j < h; j++) - for (uint32_t is = 0; is < scale; is++) - for (uint32_t js = 0; js < scale; js++) - Draw(x + (i*scale) + is, y + (j*scale) + js, sprite->GetPixel(i + ox, j + oy)); - } - else - { - for (int32_t i = 0; i < w; i++) - for (int32_t j = 0; j < h; j++) - Draw(x + i, y + j, sprite->GetPixel(i + ox, j + oy)); - } - } - - void PixelGameEngine::DrawString(int32_t x, int32_t y, std::string sText, Pixel col, uint32_t scale) - { - int32_t sx = 0; - int32_t sy = 0; - Pixel::Mode m = nPixelMode; - if(col.ALPHA != 255) SetPixelMode(Pixel::ALPHA); - else SetPixelMode(Pixel::MASK); - for (auto c : sText) - { - if (c == '\n') - { - sx = 0; sy += 8 * scale; - } - else - { - int32_t ox = (c - 32) % 16; - int32_t oy = (c - 32) / 16; - - if (scale > 1) - { - for (uint32_t i = 0; i < 8; i++) - for (uint32_t j = 0; j < 8; j++) - if (fontSprite->GetPixel(i + ox * 8, j + oy * 8).r > 0) - for (uint32_t is = 0; is < scale; is++) - for (uint32_t js = 0; js < scale; js++) - Draw(x + sx + (i*scale) + is, y + sy + (j*scale) + js, col); - } - else - { - for (uint32_t i = 0; i < 8; i++) - for (uint32_t j = 0; j < 8; j++) - if (fontSprite->GetPixel(i + ox * 8, j + oy * 8).r > 0) - Draw(x + sx + i, y + sy + j, col); - } - sx += 8 * scale; - } - } - SetPixelMode(m); - } - - void PixelGameEngine::SetPixelMode(Pixel::Mode m) - { - nPixelMode = m; - } - - Pixel::Mode PixelGameEngine::GetPixelMode() - { - return nPixelMode; - } - - void PixelGameEngine::SetPixelMode(std::function pixelMode) - { - funcPixelMode = pixelMode; - nPixelMode = Pixel::Mode::CUSTOM; - } - - void PixelGameEngine::SetPixelBlend(float fBlend) - { - fBlendFactor = fBlend; - if (fBlendFactor < 0.0f) fBlendFactor = 0.0f; - if (fBlendFactor > 1.0f) fBlendFactor = 1.0f; - } - - // User must override these functions as required. I have not made - // them abstract because I do need a default behaviour to occur if - // they are not overwritten - bool PixelGameEngine::OnUserCreate() - { return false; } - bool PixelGameEngine::OnUserUpdate(float fElapsedTime) - { return false; } - bool PixelGameEngine::OnUserDestroy() - { return true; } - ////////////////////////////////////////////////////////////////// - - void PixelGameEngine::olc_UpdateViewport() - { - int32_t ww = nScreenWidth * nPixelWidth; - int32_t wh = nScreenHeight * nPixelHeight; - float wasp = (float)ww / (float)wh; - - nViewW = (int32_t)nWindowWidth; - nViewH = (int32_t)((float)nViewW / wasp); - - if (nViewH > nWindowHeight) - { - nViewH = nWindowHeight; - nViewW = (int32_t)((float)nViewH * wasp); - } - - nViewX = (nWindowWidth - nViewW) / 2; - nViewY = (nWindowHeight - nViewH) / 2; - } - - void PixelGameEngine::olc_UpdateWindowSize(int32_t x, int32_t y) - { - nWindowWidth = x; - nWindowHeight = y; - olc_UpdateViewport(); - - } - - void PixelGameEngine::olc_UpdateMouseWheel(int32_t delta) - { - nMouseWheelDeltaCache += delta; - } - - void PixelGameEngine::olc_UpdateMouse(int32_t x, int32_t y) - { - // Mouse coords come in screen space - // But leave in pixel space - - //if (bFullScreen) - { - // Full Screen mode may have a weird viewport we must clamp to - x -= nViewX; - y -= nViewY; - } - - nMousePosXcache = (int32_t)(((float)x / (float)(nWindowWidth - (nViewX * 2)) * (float)nScreenWidth)); - nMousePosYcache = (int32_t)(((float)y / (float)(nWindowHeight - (nViewY * 2)) * (float)nScreenHeight)); - - if (nMousePosXcache >= (int32_t)nScreenWidth) - nMousePosXcache = nScreenWidth - 1; - if (nMousePosYcache >= (int32_t)nScreenHeight) - nMousePosYcache = nScreenHeight - 1; - - if (nMousePosXcache < 0) - nMousePosXcache = 0; - if (nMousePosYcache < 0) - nMousePosYcache = 0; - } - - void PixelGameEngine::EngineThread() - { - // Start OpenGL, the context is owned by the game thread - olc_OpenGLCreate(); - - // Create Screen Texture - disable filtering - glEnable(GL_TEXTURE_2D); - glGenTextures(1, &glBuffer); - glBindTexture(GL_TEXTURE_2D, glBuffer); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nScreenWidth, nScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pDefaultDrawTarget->GetData()); - - - // Create user resources as part of this thread - if (!OnUserCreate()) - bAtomActive = false; - - auto tp1 = std::chrono::system_clock::now(); - auto tp2 = std::chrono::system_clock::now(); - - while (bAtomActive) - { - // Run as fast as possible - while (bAtomActive) - { - // Handle Timing - tp2 = std::chrono::system_clock::now(); - std::chrono::duration elapsedTime = tp2 - tp1; - tp1 = tp2; - - // Our time per frame coefficient - float fElapsedTime = elapsedTime.count(); - -#ifndef _WIN32 - // Handle Xlib Message Loop - we do this in the - // same thread that OpenGL was created so we dont - // need to worry too much about multithreading with X11 - XEvent xev; - while (XPending(olc_Display)) - { - XNextEvent(olc_Display, &xev); - if (xev.type == Expose) - { - XWindowAttributes gwa; - XGetWindowAttributes(olc_Display, olc_Window, &gwa); - nWindowWidth = gwa.width; - nWindowHeight = gwa.height; - olc_UpdateViewport(); - glClear(GL_COLOR_BUFFER_BIT); // Thanks Benedani! - } - else if (xev.type == ConfigureNotify) - { - XConfigureEvent xce = xev.xconfigure; - nWindowWidth = xce.width; - nWindowHeight = xce.height; - } - else if (xev.type == KeyPress) - { - KeySym sym = XLookupKeysym(&xev.xkey, 0); - pKeyNewState[mapKeys[sym]] = true; - XKeyEvent *e = (XKeyEvent *)&xev; // Because DragonEye loves numpads - XLookupString(e, NULL, 0, &sym, NULL); - pKeyNewState[mapKeys[sym]] = true; - } - else if (xev.type == KeyRelease) - { - KeySym sym = XLookupKeysym(&xev.xkey, 0); - pKeyNewState[mapKeys[sym]] = false; - XKeyEvent *e = (XKeyEvent *)&xev; - XLookupString(e, NULL, 0, &sym, NULL); - pKeyNewState[mapKeys[sym]] = false; - } - else if (xev.type == ButtonPress) - { - switch (xev.xbutton.button) - { - case 1: pMouseNewState[0] = true; break; - case 2: pMouseNewState[2] = true; break; - case 3: pMouseNewState[1] = true; break; - case 4: olc_UpdateMouseWheel(120); break; - case 5: olc_UpdateMouseWheel(-120); break; - default: break; - } - } - else if (xev.type == ButtonRelease) - { - switch (xev.xbutton.button) - { - case 1: pMouseNewState[0] = false; break; - case 2: pMouseNewState[2] = false; break; - case 3: pMouseNewState[1] = false; break; - default: break; - } - } - else if (xev.type == MotionNotify) - { - olc_UpdateMouse(xev.xmotion.x, xev.xmotion.y); - } - else if (xev.type == FocusIn) - { - bHasInputFocus = true; - } - else if (xev.type == FocusOut) - { - bHasInputFocus = false; - } - else if (xev.type == ClientMessage) - { - bAtomActive = false; - } - } -#endif - - // Handle User Input - Keyboard - for (int i = 0; i < 256; i++) - { - pKeyboardState[i].bPressed = false; - pKeyboardState[i].bReleased = false; - - if (pKeyNewState[i] != pKeyOldState[i]) - { - if (pKeyNewState[i]) - { - pKeyboardState[i].bPressed = !pKeyboardState[i].bHeld; - pKeyboardState[i].bHeld = true; - } - else - { - pKeyboardState[i].bReleased = true; - pKeyboardState[i].bHeld = false; - } - } - - pKeyOldState[i] = pKeyNewState[i]; - } - - // Handle User Input - Mouse - for (int i = 0; i < 5; i++) - { - pMouseState[i].bPressed = false; - pMouseState[i].bReleased = false; - - if (pMouseNewState[i] != pMouseOldState[i]) - { - if (pMouseNewState[i]) - { - pMouseState[i].bPressed = !pMouseState[i].bHeld; - pMouseState[i].bHeld = true; - } - else - { - pMouseState[i].bReleased = true; - pMouseState[i].bHeld = false; - } - } - - pMouseOldState[i] = pMouseNewState[i]; - } - - // Cache mouse coordinates so they remain - // consistent during frame - nMousePosX = nMousePosXcache; - nMousePosY = nMousePosYcache; - - nMouseWheelDelta = nMouseWheelDeltaCache; - nMouseWheelDeltaCache = 0; - -#ifdef OLC_DBG_OVERDRAW - olc::Sprite::nOverdrawCount = 0; -#endif - - // Handle Frame Update - if (!OnUserUpdate(fElapsedTime)) - bAtomActive = false; - - // Display Graphics - glViewport(nViewX, nViewY, nViewW, nViewH); - - // TODO: This is a bit slow (especially in debug, but 100x faster in release mode???) - // Copy pixel array into texture - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, nScreenWidth, nScreenHeight, GL_RGBA, GL_UNSIGNED_BYTE, pDefaultDrawTarget->GetData()); - - // Display texture on screen - glBegin(GL_QUADS); - glTexCoord2f(0.0, 1.0); glVertex3f(-1.0f + (fSubPixelOffsetX), -1.0f + (fSubPixelOffsetY), 0.0f); - glTexCoord2f(0.0, 0.0); glVertex3f(-1.0f + (fSubPixelOffsetX), 1.0f + (fSubPixelOffsetY), 0.0f); - glTexCoord2f(1.0, 0.0); glVertex3f( 1.0f + (fSubPixelOffsetX), 1.0f + (fSubPixelOffsetY), 0.0f); - glTexCoord2f(1.0, 1.0); glVertex3f( 1.0f + (fSubPixelOffsetX), -1.0f + (fSubPixelOffsetY), 0.0f); - glEnd(); - - // Present Graphics to screen -#ifdef _WIN32 - SwapBuffers(glDeviceContext); -#else - glXSwapBuffers(olc_Display, olc_Window); -#endif - - // Update Title Bar - fFrameTimer += fElapsedTime; - nFrameCount++; - if (fFrameTimer >= 1.0f) - { - fFrameTimer -= 1.0f; - - std::string sTitle = "OneLoneCoder.com - Pixel Game Engine - " + sAppName + " - FPS: " + std::to_string(nFrameCount); -#ifdef _WIN32 -#ifdef UNICODE - SetWindowText(olc_hWnd, ConvertS2W(sTitle).c_str()); -#else - SetWindowText(olc_hWnd, sTitle.c_str()); -#endif -#else - XStoreName(olc_Display, olc_Window, sTitle.c_str()); -#endif - nFrameCount = 0; - } - } - - // Allow the user to free resources if they have overrided the destroy function - if (OnUserDestroy()) - { - // User has permitted destroy, so exit and clean up - } - else - { - // User denied destroy for some reason, so continue running - bAtomActive = true; - } - } - -#ifdef _WIN32 - wglDeleteContext(glRenderContext); - PostMessage(olc_hWnd, WM_DESTROY, 0, 0); -#else - glXMakeCurrent(olc_Display, None, NULL); - glXDestroyContext(olc_Display, glDeviceContext); - XDestroyWindow(olc_Display, olc_Window); - XCloseDisplay(olc_Display); -#endif - - } - -#ifdef _WIN32 - // Thanks @MaGetzUb for this, which allows sprites to be defined - // at construction, by initialising the GDI subsystem - static class GDIPlusStartup - { - public: - GDIPlusStartup() - { - Gdiplus::GdiplusStartupInput startupInput; - ULONG_PTR token; - Gdiplus::GdiplusStartup(&token, &startupInput, NULL); - }; - } gdistartup; -#endif - - - void PixelGameEngine::olc_ConstructFontSheet() - { - std::string data; - data += "?Q`0001oOch0o01o@F40o000000000"; - data += "O000000nOT0063Qo4d8>?7a14Gno94AA4gno94AaOT0>o3`oO400o7QN00000400"; - data += "Of80001oOg<7O7moBGT7O7lABET024@aBEd714AiOdl717a_=TH013Q>00000000"; - data += "720D000V?V5oB3Q_HdUoE7a9@DdDE4A9@DmoE4A;Hg]oM4Aj8S4D84@`00000000"; - data += "OaPT1000Oa`^13P1@AI[?g`1@A=[OdAoHgljA4Ao?WlBA7l1710007l100000000"; - data += "ObM6000oOfMV?3QoBDD`O7a0BDDH@5A0BDD<@5A0BGeVO5ao@CQR?5Po00000000"; - data += "Oc``000?Ogij70PO2D]??0Ph2DUM@7i`2DTg@7lh2GUj?0TO0C1870T?00000000"; - data += "70<4001o?P<7?1QoHg43O;`h@GT0@:@LB@d0>:@hN@L0@?aoN@<0O7ao0000?000"; - data += "OcH0001SOglLA7mg24TnK7ln24US>0PL24U140PnOgl0>7QgOcH0K71S0000A000"; - data += "00H00000@Dm1S007@DUSg00?OdTnH7YhOfTL<7Yh@Cl0700?@Ah0300700000000"; - data += "<008001QL00ZA41a@6HnI<1i@FHLM81M@@0LG81?O`0nC?Y7?`0ZA7Y300080000"; - data += "O`082000Oh0827mo6>Hn?Wmo?6HnMb11MP08@C11H`08@FP0@@0004@000000000"; - data += "00P00001Oab00003OcKP0006@6=PMgl<@440MglH@000000`@000001P00000000"; - data += "Ob@8@@00Ob@8@Ga13R@8Mga172@8?PAo3R@827QoOb@820@0O`0007`0000007P0"; - data += "O`000P08Od400g`<3V=P0G`673IP0`@3>1`00P@6O`P00g`SetPixel(px, py, olc::Pixel(k, k, k, k)); - if (++py == 48) { px++; py = 0; } - } - } - } - -#ifdef _WIN32 - HWND PixelGameEngine::olc_WindowCreate() - { - WNDCLASS wc; - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - wc.hInstance = GetModuleHandle(nullptr); - wc.lpfnWndProc = olc_WindowEvent; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.lpszMenuName = nullptr; - wc.hbrBackground = nullptr; -#ifdef UNICODE - wc.lpszClassName = L"OLC_PIXEL_GAME_ENGINE"; -#else - wc.lpszClassName = "OLC_PIXEL_GAME_ENGINE"; -#endif - - RegisterClass(&wc); - - nWindowWidth = (LONG)nScreenWidth * (LONG)nPixelWidth; - nWindowHeight = (LONG)nScreenHeight * (LONG)nPixelHeight; - - // Define window furniture - DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - DWORD dwStyle = WS_CAPTION | WS_SYSMENU | WS_VISIBLE;// | WS_THICKFRAME; - - int nCosmeticOffset = 30; - nViewW = nWindowWidth; - nViewH = nWindowHeight; - - // Handle Fullscreen - if (bFullScreen) - { - dwExStyle = 0; - dwStyle = WS_VISIBLE | WS_POPUP; - nCosmeticOffset = 0; - HMONITOR hmon = MonitorFromWindow(olc_hWnd, MONITOR_DEFAULTTONEAREST); - MONITORINFO mi = { sizeof(mi) }; - if (!GetMonitorInfo(hmon, &mi)) return NULL; - nWindowWidth = mi.rcMonitor.right; - nWindowHeight = mi.rcMonitor.bottom; - - - } - - olc_UpdateViewport(); - - // Keep client size as requested - RECT rWndRect = { 0, 0, nWindowWidth, nWindowHeight }; - AdjustWindowRectEx(&rWndRect, dwStyle, FALSE, dwExStyle); - int width = rWndRect.right - rWndRect.left; - int height = rWndRect.bottom - rWndRect.top; - -#ifdef UNICODE - olc_hWnd = CreateWindowEx(dwExStyle, L"OLC_PIXEL_GAME_ENGINE", L"", dwStyle, - nCosmeticOffset, nCosmeticOffset, width, height, NULL, NULL, GetModuleHandle(nullptr), this); -#else - olc_hWnd = CreateWindowEx(dwExStyle, "OLC_PIXEL_GAME_ENGINE", "", dwStyle, - nCosmeticOffset, nCosmeticOffset, width, height, NULL, NULL, GetModuleHandle(nullptr), this); -#endif - - // Create Keyboard Mapping - mapKeys[0x00] = Key::NONE; - mapKeys[0x41] = Key::A; mapKeys[0x42] = Key::B; mapKeys[0x43] = Key::C; mapKeys[0x44] = Key::D; mapKeys[0x45] = Key::E; - mapKeys[0x46] = Key::F; mapKeys[0x47] = Key::G; mapKeys[0x48] = Key::H; mapKeys[0x49] = Key::I; mapKeys[0x4A] = Key::J; - mapKeys[0x4B] = Key::K; mapKeys[0x4C] = Key::L; mapKeys[0x4D] = Key::M; mapKeys[0x4E] = Key::N; mapKeys[0x4F] = Key::O; - mapKeys[0x50] = Key::P; mapKeys[0x51] = Key::Q; mapKeys[0x52] = Key::R; mapKeys[0x53] = Key::S; mapKeys[0x54] = Key::T; - mapKeys[0x55] = Key::U; mapKeys[0x56] = Key::V; mapKeys[0x57] = Key::W; mapKeys[0x58] = Key::X; mapKeys[0x59] = Key::Y; - mapKeys[0x5A] = Key::Z; - - mapKeys[VK_F1] = Key::F1; mapKeys[VK_F2] = Key::F2; mapKeys[VK_F3] = Key::F3; mapKeys[VK_F4] = Key::F4; - mapKeys[VK_F5] = Key::F5; mapKeys[VK_F6] = Key::F6; mapKeys[VK_F7] = Key::F7; mapKeys[VK_F8] = Key::F8; - mapKeys[VK_F9] = Key::F9; mapKeys[VK_F10] = Key::F10; mapKeys[VK_F11] = Key::F11; mapKeys[VK_F12] = Key::F12; - - mapKeys[VK_DOWN] = Key::DOWN; mapKeys[VK_LEFT] = Key::LEFT; mapKeys[VK_RIGHT] = Key::RIGHT; mapKeys[VK_UP] = Key::UP; - mapKeys[VK_RETURN] = Key::ENTER; //mapKeys[VK_RETURN] = Key::RETURN; - - mapKeys[VK_BACK] = Key::BACK; mapKeys[VK_ESCAPE] = Key::ESCAPE; mapKeys[VK_RETURN] = Key::ENTER; mapKeys[VK_PAUSE] = Key::PAUSE; - mapKeys[VK_SCROLL] = Key::SCROLL; mapKeys[VK_TAB] = Key::TAB; mapKeys[VK_DELETE] = Key::DEL; mapKeys[VK_HOME] = Key::HOME; - mapKeys[VK_END] = Key::END; mapKeys[VK_PRIOR] = Key::PGUP; mapKeys[VK_NEXT] = Key::PGDN; mapKeys[VK_INSERT] = Key::INS; - mapKeys[VK_SHIFT] = Key::SHIFT; mapKeys[VK_CONTROL] = Key::CTRL; - mapKeys[VK_SPACE] = Key::SPACE; - - mapKeys[0x30] = Key::K0; mapKeys[0x31] = Key::K1; mapKeys[0x32] = Key::K2; mapKeys[0x33] = Key::K3; mapKeys[0x34] = Key::K4; - mapKeys[0x35] = Key::K5; mapKeys[0x36] = Key::K6; mapKeys[0x37] = Key::K7; mapKeys[0x38] = Key::K8; mapKeys[0x39] = Key::K9; - - mapKeys[VK_NUMPAD0] = Key::NP0; mapKeys[VK_NUMPAD1] = Key::NP1; mapKeys[VK_NUMPAD2] = Key::NP2; mapKeys[VK_NUMPAD3] = Key::NP3; mapKeys[VK_NUMPAD4] = Key::NP4; - mapKeys[VK_NUMPAD5] = Key::NP5; mapKeys[VK_NUMPAD6] = Key::NP6; mapKeys[VK_NUMPAD7] = Key::NP7; mapKeys[VK_NUMPAD8] = Key::NP8; mapKeys[VK_NUMPAD9] = Key::NP9; - mapKeys[VK_MULTIPLY] = Key::NP_MUL; mapKeys[VK_ADD] = Key::NP_ADD; mapKeys[VK_DIVIDE] = Key::NP_DIV; mapKeys[VK_SUBTRACT] = Key::NP_SUB; mapKeys[VK_DECIMAL] = Key::NP_DECIMAL; - - return olc_hWnd; - } - - bool PixelGameEngine::olc_OpenGLCreate() - { - // Create Device Context - glDeviceContext = GetDC(olc_hWnd); - PIXELFORMATDESCRIPTOR pfd = - { - sizeof(PIXELFORMATDESCRIPTOR), 1, - PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, - PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - PFD_MAIN_PLANE, 0, 0, 0, 0 - }; - - int pf = 0; - if (!(pf = ChoosePixelFormat(glDeviceContext, &pfd))) return false; - SetPixelFormat(glDeviceContext, pf, &pfd); - - if (!(glRenderContext = wglCreateContext(glDeviceContext))) return false; - wglMakeCurrent(glDeviceContext, glRenderContext); - - glViewport(nViewX, nViewY, nViewW, nViewH); - - // Remove Frame cap - wglSwapInterval = (wglSwapInterval_t*)wglGetProcAddress("wglSwapIntervalEXT"); - if (wglSwapInterval) wglSwapInterval(0); - return true; - } - - // Windows Event Handler - LRESULT CALLBACK PixelGameEngine::olc_WindowEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) - { - static PixelGameEngine *sge; - switch (uMsg) - { - case WM_CREATE: sge = (PixelGameEngine*)((LPCREATESTRUCT)lParam)->lpCreateParams; return 0; - case WM_MOUSEMOVE: - { - uint16_t x = lParam & 0xFFFF; // Thanks @ForAbby (Discord) - uint16_t y = (lParam >> 16) & 0xFFFF; - int16_t ix = *(int16_t*)&x; - int16_t iy = *(int16_t*)&y; - sge->olc_UpdateMouse(ix, iy); - return 0; - } - case WM_SIZE: - { - sge->olc_UpdateWindowSize(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); - return 0; - } - case WM_MOUSEWHEEL: - { - sge->olc_UpdateMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam)); - return 0; - } - case WM_MOUSELEAVE: sge->bHasMouseFocus = false; return 0; - case WM_SETFOCUS: sge->bHasInputFocus = true; return 0; - case WM_KILLFOCUS: sge->bHasInputFocus = false; return 0; - case WM_KEYDOWN: sge->pKeyNewState[mapKeys[wParam]] = true; return 0; - case WM_KEYUP: sge->pKeyNewState[mapKeys[wParam]] = false; return 0; - case WM_LBUTTONDOWN:sge->pMouseNewState[0] = true; return 0; - case WM_LBUTTONUP: sge->pMouseNewState[0] = false; return 0; - case WM_RBUTTONDOWN:sge->pMouseNewState[1] = true; return 0; - case WM_RBUTTONUP: sge->pMouseNewState[1] = false; return 0; - case WM_MBUTTONDOWN:sge->pMouseNewState[2] = true; return 0; - case WM_MBUTTONUP: sge->pMouseNewState[2] = false; return 0; - case WM_CLOSE: bAtomActive = false; return 0; - case WM_DESTROY: PostQuitMessage(0); return 0; - } - return DefWindowProc(hWnd, uMsg, wParam, lParam); - } -#else - // Do the Linux stuff! - Display* PixelGameEngine::olc_WindowCreate() - { - XInitThreads(); - - // Grab the deafult display and window - olc_Display = XOpenDisplay(NULL); - olc_WindowRoot = DefaultRootWindow(olc_Display); - - // Based on the display capabilities, configure the appearance of the window - GLint olc_GLAttribs[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; - olc_VisualInfo = glXChooseVisual(olc_Display, 0, olc_GLAttribs); - olc_ColourMap = XCreateColormap(olc_Display, olc_WindowRoot, olc_VisualInfo->visual, AllocNone); - olc_SetWindowAttribs.colormap = olc_ColourMap; - - // Register which events we are interested in receiving - olc_SetWindowAttribs.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask | StructureNotifyMask; - - // Create the window - olc_Window = XCreateWindow(olc_Display, olc_WindowRoot, 30, 30, nScreenWidth * nPixelWidth, nScreenHeight * nPixelHeight, 0, olc_VisualInfo->depth, InputOutput, olc_VisualInfo->visual, CWColormap | CWEventMask, &olc_SetWindowAttribs); - - Atom wmDelete = XInternAtom(olc_Display, "WM_DELETE_WINDOW", true); - XSetWMProtocols(olc_Display, olc_Window, &wmDelete, 1); - - XMapWindow(olc_Display, olc_Window); - XStoreName(olc_Display, olc_Window, "OneLoneCoder.com - Pixel Game Engine"); - - if (bFullScreen) // Thanks DragonEye, again :D - { - Atom wm_state; - Atom fullscreen; - wm_state = XInternAtom(olc_Display, "_NET_WM_STATE", False); - fullscreen = XInternAtom(olc_Display, "_NET_WM_STATE_FULLSCREEN", False); - XEvent xev{ 0 }; - xev.type = ClientMessage; - xev.xclient.window = olc_Window; - xev.xclient.message_type = wm_state; - xev.xclient.format = 32; - xev.xclient.data.l[0] = (bFullScreen ? 1 : 0); // the action (0: off, 1: on, 2: toggle) - xev.xclient.data.l[1] = fullscreen; // first property to alter - xev.xclient.data.l[2] = 0; // second property to alter - xev.xclient.data.l[3] = 0; // source indication - XMapWindow(olc_Display, olc_Window); - XSendEvent(olc_Display, DefaultRootWindow(olc_Display), False, - SubstructureRedirectMask | SubstructureNotifyMask, &xev); - XFlush(olc_Display); - XWindowAttributes gwa; - XGetWindowAttributes(olc_Display, olc_Window, &gwa); - nWindowWidth = gwa.width; - nWindowHeight = gwa.height; - olc_UpdateViewport(); - } - - // Create Keyboard Mapping - mapKeys[0x00] = Key::NONE; - mapKeys[0x61] = Key::A; mapKeys[0x62] = Key::B; mapKeys[0x63] = Key::C; mapKeys[0x64] = Key::D; mapKeys[0x65] = Key::E; - mapKeys[0x66] = Key::F; mapKeys[0x67] = Key::G; mapKeys[0x68] = Key::H; mapKeys[0x69] = Key::I; mapKeys[0x6A] = Key::J; - mapKeys[0x6B] = Key::K; mapKeys[0x6C] = Key::L; mapKeys[0x6D] = Key::M; mapKeys[0x6E] = Key::N; mapKeys[0x6F] = Key::O; - mapKeys[0x70] = Key::P; mapKeys[0x71] = Key::Q; mapKeys[0x72] = Key::R; mapKeys[0x73] = Key::S; mapKeys[0x74] = Key::T; - mapKeys[0x75] = Key::U; mapKeys[0x76] = Key::V; mapKeys[0x77] = Key::W; mapKeys[0x78] = Key::X; mapKeys[0x79] = Key::Y; - mapKeys[0x7A] = Key::Z; - - mapKeys[XK_F1] = Key::F1; mapKeys[XK_F2] = Key::F2; mapKeys[XK_F3] = Key::F3; mapKeys[XK_F4] = Key::F4; - mapKeys[XK_F5] = Key::F5; mapKeys[XK_F6] = Key::F6; mapKeys[XK_F7] = Key::F7; mapKeys[XK_F8] = Key::F8; - mapKeys[XK_F9] = Key::F9; mapKeys[XK_F10] = Key::F10; mapKeys[XK_F11] = Key::F11; mapKeys[XK_F12] = Key::F12; - - mapKeys[XK_Down] = Key::DOWN; mapKeys[XK_Left] = Key::LEFT; mapKeys[XK_Right] = Key::RIGHT; mapKeys[XK_Up] = Key::UP; - mapKeys[XK_KP_Enter] = Key::ENTER; mapKeys[XK_Return] = Key::ENTER; - - mapKeys[XK_BackSpace] = Key::BACK; mapKeys[XK_Escape] = Key::ESCAPE; mapKeys[XK_Linefeed] = Key::ENTER; mapKeys[XK_Pause] = Key::PAUSE; - mapKeys[XK_Scroll_Lock] = Key::SCROLL; mapKeys[XK_Tab] = Key::TAB; mapKeys[XK_Delete] = Key::DEL; mapKeys[XK_Home] = Key::HOME; - mapKeys[XK_End] = Key::END; mapKeys[XK_Page_Up] = Key::PGUP; mapKeys[XK_Page_Down] = Key::PGDN; mapKeys[XK_Insert] = Key::INS; - mapKeys[XK_Shift_L] = Key::SHIFT; mapKeys[XK_Shift_R] = Key::SHIFT; mapKeys[XK_Control_L] = Key::CTRL; mapKeys[XK_Control_R] = Key::CTRL; - mapKeys[XK_space] = Key::SPACE; - - mapKeys[XK_0] = Key::K0; mapKeys[XK_1] = Key::K1; mapKeys[XK_2] = Key::K2; mapKeys[XK_3] = Key::K3; mapKeys[XK_4] = Key::K4; - mapKeys[XK_5] = Key::K5; mapKeys[XK_6] = Key::K6; mapKeys[XK_7] = Key::K7; mapKeys[XK_8] = Key::K8; mapKeys[XK_9] = Key::K9; - - mapKeys[XK_KP_0] = Key::NP0; mapKeys[XK_KP_1] = Key::NP1; mapKeys[XK_KP_2] = Key::NP2; mapKeys[XK_KP_3] = Key::NP3; mapKeys[XK_KP_4] = Key::NP4; - mapKeys[XK_KP_5] = Key::NP5; mapKeys[XK_KP_6] = Key::NP6; mapKeys[XK_KP_7] = Key::NP7; mapKeys[XK_KP_8] = Key::NP8; mapKeys[XK_KP_9] = Key::NP9; - mapKeys[XK_KP_Multiply] = Key::NP_MUL; mapKeys[XK_KP_Add] = Key::NP_ADD; mapKeys[XK_KP_Divide] = Key::NP_DIV; mapKeys[XK_KP_Subtract] = Key::NP_SUB; mapKeys[XK_KP_Decimal] = Key::NP_DECIMAL; - - return olc_Display; - } - - bool PixelGameEngine::olc_OpenGLCreate() - { - glDeviceContext = glXCreateContext(olc_Display, olc_VisualInfo, nullptr, GL_TRUE); - glXMakeCurrent(olc_Display, olc_Window, glDeviceContext); - - XWindowAttributes gwa; - XGetWindowAttributes(olc_Display, olc_Window, &gwa); - glViewport(0, 0, gwa.width, gwa.height); - - glSwapIntervalEXT = nullptr; - glSwapIntervalEXT = (glSwapInterval_t*)glXGetProcAddress((unsigned char*)"glXSwapIntervalEXT"); - if (glSwapIntervalEXT) - glSwapIntervalEXT(olc_Display, olc_Window, 0); - else - { - printf("NOTE: Could not disable VSYNC, glXSwapIntervalEXT() was not found!\n"); - printf(" Don't worry though, things will still work, it's just the\n"); - printf(" frame rate will be capped to your monitors refresh rate - javidx9\n"); - } - - return true; - } - -#endif - - // Need a couple of statics as these are singleton instances - // read from multiple locations - std::atomic PixelGameEngine::bAtomActive{ false }; - std::map PixelGameEngine::mapKeys; - olc::PixelGameEngine* olc::PGEX::pge = nullptr; -#ifdef OLC_DBG_OVERDRAW - int olc::Sprite::nOverdrawCount = 0; -#endif - //============================================================= -} - -#endif diff --git a/Videos/DemoBinaries/OLC_8BitsImProc.zip b/Videos/DemoBinaries/OLC_8BitsImProc.zip deleted file mode 100644 index cb9f6c5..0000000 Binary files a/Videos/DemoBinaries/OLC_8BitsImProc.zip and /dev/null differ diff --git a/Videos/DemoBinaries/olcPGE_Mandelbrot_x64.exe b/Videos/DemoBinaries/olcPGE_Mandelbrot_x64.exe deleted file mode 100644 index e3763d2..0000000 Binary files a/Videos/DemoBinaries/olcPGE_Mandelbrot_x64.exe and /dev/null differ diff --git a/Videos/DemoBinaries/olcPGE_Mandelbrot_x86.exe b/Videos/DemoBinaries/olcPGE_Mandelbrot_x86.exe deleted file mode 100644 index 77c5894..0000000 Binary files a/Videos/DemoBinaries/olcPGE_Mandelbrot_x86.exe and /dev/null differ diff --git a/Videos/Networking/Parts1&2/SimpleClient.cpp b/Videos/Networking/Parts1&2/SimpleClient.cpp deleted file mode 100644 index 1050752..0000000 --- a/Videos/Networking/Parts1&2/SimpleClient.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* - MMO Client/Server Framework using ASIO - "Happy Birthday Mrs Javidx9!" - javidx9 - - Videos: - Part #1: https://youtu.be/2hNdkYInj4g - Part #2: https://youtu.be/UbjxGvrDrbw - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020 - -*/ - -#include -#include - -enum class CustomMsgTypes : uint32_t -{ - ServerAccept, - ServerDeny, - ServerPing, - MessageAll, - ServerMessage, -}; - - - -class CustomClient : public olc::net::client_interface -{ -public: - void PingServer() - { - olc::net::message msg; - msg.header.id = CustomMsgTypes::ServerPing; - - // Caution with this... - std::chrono::system_clock::time_point timeNow = std::chrono::system_clock::now(); - - msg << timeNow; - Send(msg); - } - - void MessageAll() - { - olc::net::message msg; - msg.header.id = CustomMsgTypes::MessageAll; - Send(msg); - } -}; - -int main() -{ - CustomClient c; - c.Connect("127.0.0.1", 60000); - - bool key[3] = { false, false, false }; - bool old_key[3] = { false, false, false }; - - bool bQuit = false; - while (!bQuit) - { - if (GetForegroundWindow() == GetConsoleWindow()) - { - key[0] = GetAsyncKeyState('1') & 0x8000; - key[1] = GetAsyncKeyState('2') & 0x8000; - key[2] = GetAsyncKeyState('3') & 0x8000; - } - - if (key[0] && !old_key[0]) c.PingServer(); - if (key[1] && !old_key[1]) c.MessageAll(); - if (key[2] && !old_key[2]) bQuit = true; - - for (int i = 0; i < 3; i++) old_key[i] = key[i]; - - if (c.IsConnected()) - { - if (!c.Incoming().empty()) - { - - - auto msg = c.Incoming().pop_front().msg; - - switch (msg.header.id) - { - case CustomMsgTypes::ServerAccept: - { - // Server has responded to a ping request - std::cout << "Server Accepted Connection\n"; - } - break; - - - case CustomMsgTypes::ServerPing: - { - // Server has responded to a ping request - std::chrono::system_clock::time_point timeNow = std::chrono::system_clock::now(); - std::chrono::system_clock::time_point timeThen; - msg >> timeThen; - std::cout << "Ping: " << std::chrono::duration(timeNow - timeThen).count() << "\n"; - } - break; - - case CustomMsgTypes::ServerMessage: - { - // Server has responded to a ping request - uint32_t clientID; - msg >> clientID; - std::cout << "Hello from [" << clientID << "]\n"; - } - break; - } - } - } - else - { - std::cout << "Server Down\n"; - bQuit = true; - } - - } - - return 0; -} \ No newline at end of file diff --git a/Videos/Networking/Parts1&2/SimpleServer.cpp b/Videos/Networking/Parts1&2/SimpleServer.cpp deleted file mode 100644 index 83e524c..0000000 --- a/Videos/Networking/Parts1&2/SimpleServer.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* - MMO Client/Server Framework using ASIO - "Happy Birthday Mrs Javidx9!" - javidx9 - - Videos: - Part #1: https://youtu.be/2hNdkYInj4g - Part #2: https://youtu.be/UbjxGvrDrbw - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020 - -*/ - -#include -#include - -enum class CustomMsgTypes : uint32_t -{ - ServerAccept, - ServerDeny, - ServerPing, - MessageAll, - ServerMessage, -}; - - - -class CustomServer : public olc::net::server_interface -{ -public: - CustomServer(uint16_t nPort) : olc::net::server_interface(nPort) - { - - } - -protected: - virtual bool OnClientConnect(std::shared_ptr> client) - { - olc::net::message msg; - msg.header.id = CustomMsgTypes::ServerAccept; - client->Send(msg); - return true; - } - - // Called when a client appears to have disconnected - virtual void OnClientDisconnect(std::shared_ptr> client) - { - std::cout << "Removing client [" << client->GetID() << "]\n"; - } - - // Called when a message arrives - virtual void OnMessage(std::shared_ptr> client, olc::net::message& msg) - { - switch (msg.header.id) - { - case CustomMsgTypes::ServerPing: - { - std::cout << "[" << client->GetID() << "]: Server Ping\n"; - - // Simply bounce message back to client - client->Send(msg); - } - break; - - case CustomMsgTypes::MessageAll: - { - std::cout << "[" << client->GetID() << "]: Message All\n"; - - // Construct a new message and send it to all clients - olc::net::message msg; - msg.header.id = CustomMsgTypes::ServerMessage; - msg << client->GetID(); - MessageAllClients(msg, client); - - } - break; - } - } -}; - -int main() -{ - CustomServer server(60000); - server.Start(); - - while (1) - { - server.Update(-1, true); - } - - - - return 0; -} \ No newline at end of file diff --git a/Videos/Networking/Parts1&2/net_client.h b/Videos/Networking/Parts1&2/net_client.h deleted file mode 100644 index 5e6c425..0000000 --- a/Videos/Networking/Parts1&2/net_client.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - MMO Client/Server Framework using ASIO - "Happy Birthday Mrs Javidx9!" - javidx9 - - Videos: - Part #1: https://youtu.be/2hNdkYInj4g - Part #2: https://youtu.be/UbjxGvrDrbw - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020 - -*/ - -#pragma once -#include "net_common.h" - -namespace olc -{ - namespace net - { - template - class client_interface - { - public: - client_interface() - {} - - virtual ~client_interface() - { - // If the client is destroyed, always try and disconnect from server - Disconnect(); - } - - public: - // Connect to server with hostname/ip-address and port - bool Connect(const std::string& host, const uint16_t port) - { - try - { - // Resolve hostname/ip-address into tangiable physical address - asio::ip::tcp::resolver resolver(m_context); - asio::ip::tcp::resolver::results_type endpoints = resolver.resolve(host, std::to_string(port)); - - // Create connection - m_connection = std::make_unique>(connection::owner::client, m_context, asio::ip::tcp::socket(m_context), m_qMessagesIn); - - // Tell the connection object to connect to server - m_connection->ConnectToServer(endpoints); - - // Start Context Thread - thrContext = std::thread([this]() { m_context.run(); }); - } - catch (std::exception& e) - { - std::cerr << "Client Exception: " << e.what() << "\n"; - return false; - } - return true; - } - - // Disconnect from server - void Disconnect() - { - // If connection exists, and it's connected then... - if(IsConnected()) - { - // ...disconnect from server gracefully - m_connection->Disconnect(); - } - - // Either way, we're also done with the asio context... - m_context.stop(); - // ...and its thread - if (thrContext.joinable()) - thrContext.join(); - - // Destroy the connection object - m_connection.release(); - } - - // Check if client is actually connected to a server - bool IsConnected() - { - if (m_connection) - return m_connection->IsConnected(); - else - return false; - } - - public: - // Send message to server - void Send(const message& msg) - { - if (IsConnected()) - m_connection->Send(msg); - } - - // Retrieve queue of messages from server - tsqueue>& Incoming() - { - return m_qMessagesIn; - } - - protected: - // asio context handles the data transfer... - asio::io_context m_context; - // ...but needs a thread of its own to execute its work commands - std::thread thrContext; - // The client has a single instance of a "connection" object, which handles data transfer - std::unique_ptr> m_connection; - - private: - // This is the thread safe queue of incoming messages from server - tsqueue> m_qMessagesIn; - }; - } -} \ No newline at end of file diff --git a/Videos/Networking/Parts1&2/net_common.h b/Videos/Networking/Parts1&2/net_common.h deleted file mode 100644 index 002927b..0000000 --- a/Videos/Networking/Parts1&2/net_common.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - MMO Client/Server Framework using ASIO - "Happy Birthday Mrs Javidx9!" - javidx9 - - Videos: - Part #1: https://youtu.be/2hNdkYInj4g - Part #2: https://youtu.be/UbjxGvrDrbw - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020 - -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#define _WIN32_WINNT 0x0A00 -#endif - -#define ASIO_STANDALONE -#include -#include -#include - diff --git a/Videos/Networking/Parts1&2/net_connection.h b/Videos/Networking/Parts1&2/net_connection.h deleted file mode 100644 index 08d3b96..0000000 --- a/Videos/Networking/Parts1&2/net_connection.h +++ /dev/null @@ -1,353 +0,0 @@ -/* - MMO Client/Server Framework using ASIO - "Happy Birthday Mrs Javidx9!" - javidx9 - - Videos: - Part #1: https://youtu.be/2hNdkYInj4g - Part #2: https://youtu.be/UbjxGvrDrbw - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020 - -*/ - -#pragma once - -#include "net_common.h" -#include "net_tsqueue.h" -#include "net_message.h" - - -namespace olc -{ - namespace net - { - template - class connection : public std::enable_shared_from_this> - { - public: - // A connection is "owned" by either a server or a client, and its - // behaviour is slightly different bewteen the two. - enum class owner - { - server, - client - }; - - public: - // Constructor: Specify Owner, connect to context, transfer the socket - // Provide reference to incoming message queue - connection(owner parent, asio::io_context& asioContext, asio::ip::tcp::socket socket, tsqueue>& qIn) - : m_asioContext(asioContext), m_socket(std::move(socket)), m_qMessagesIn(qIn) - { - m_nOwnerType = parent; - } - - virtual ~connection() - {} - - // This ID is used system wide - its how clients will understand other clients - // exist across the whole system. - uint32_t GetID() const - { - return id; - } - - public: - void ConnectToClient(uint32_t uid = 0) - { - if (m_nOwnerType == owner::server) - { - if (m_socket.is_open()) - { - id = uid; - ReadHeader(); - } - } - } - - void ConnectToServer(const asio::ip::tcp::resolver::results_type& endpoints) - { - // Only clients can connect to servers - if (m_nOwnerType == owner::client) - { - // Request asio attempts to connect to an endpoint - asio::async_connect(m_socket, endpoints, - [this](std::error_code ec, asio::ip::tcp::endpoint endpoint) - { - if (!ec) - { - ReadHeader(); - } - }); - } - } - - - void Disconnect() - { - if (IsConnected()) - asio::post(m_asioContext, [this]() { m_socket.close(); }); - } - - bool IsConnected() const - { - return m_socket.is_open(); - } - - // Prime the connection to wait for incoming messages - void StartListening() - { - - } - - public: - // ASYNC - Send a message, connections are one-to-one so no need to specifiy - // the target, for a client, the target is the server and vice versa - void Send(const message& msg) - { - asio::post(m_asioContext, - [this, msg]() - { - // If the queue has a message in it, then we must - // assume that it is in the process of asynchronously being written. - // Either way add the message to the queue to be output. If no messages - // were available to be written, then start the process of writing the - // message at the front of the queue. - bool bWritingMessage = !m_qMessagesOut.empty(); - m_qMessagesOut.push_back(msg); - if (!bWritingMessage) - { - WriteHeader(); - } - }); - } - - - - private: - // ASYNC - Prime context to write a message header - void WriteHeader() - { - // If this function is called, we know the outgoing message queue must have - // at least one message to send. So allocate a transmission buffer to hold - // the message, and issue the work - asio, send these bytes - asio::async_write(m_socket, asio::buffer(&m_qMessagesOut.front().header, sizeof(message_header)), - [this](std::error_code ec, std::size_t length) - { - // asio has now sent the bytes - if there was a problem - // an error would be available... - if (!ec) - { - // ... no error, so check if the message header just sent also - // has a message body... - if (m_qMessagesOut.front().body.size() > 0) - { - // ...it does, so issue the task to write the body bytes - WriteBody(); - } - else - { - // ...it didnt, so we are done with this message. Remove it from - // the outgoing message queue - m_qMessagesOut.pop_front(); - - // If the queue is not empty, there are more messages to send, so - // make this happen by issuing the task to send the next header. - if (!m_qMessagesOut.empty()) - { - WriteHeader(); - } - } - } - else - { - // ...asio failed to write the message, we could analyse why but - // for now simply assume the connection has died by closing the - // socket. When a future attempt to write to this client fails due - // to the closed socket, it will be tidied up. - std::cout << "[" << id << "] Write Header Fail.\n"; - m_socket.close(); - } - }); - } - - // ASYNC - Prime context to write a message body - void WriteBody() - { - // If this function is called, a header has just been sent, and that header - // indicated a body existed for this message. Fill a transmission buffer - // with the body data, and send it! - asio::async_write(m_socket, asio::buffer(m_qMessagesOut.front().body.data(), m_qMessagesOut.front().body.size()), - [this](std::error_code ec, std::size_t length) - { - if (!ec) - { - // Sending was successful, so we are done with the message - // and remove it from the queue - m_qMessagesOut.pop_front(); - - // If the queue still has messages in it, then issue the task to - // send the next messages' header. - if (!m_qMessagesOut.empty()) - { - WriteHeader(); - } - } - else - { - // Sending failed, see WriteHeader() equivalent for description :P - std::cout << "[" << id << "] Write Body Fail.\n"; - m_socket.close(); - } - }); - } - - // ASYNC - Prime context ready to read a message header - void ReadHeader() - { - // If this function is called, we are expecting asio to wait until it receives - // enough bytes to form a header of a message. We know the headers are a fixed - // size, so allocate a transmission buffer large enough to store it. In fact, - // we will construct the message in a "temporary" message object as it's - // convenient to work with. - asio::async_read(m_socket, asio::buffer(&m_msgTemporaryIn.header, sizeof(message_header)), - [this](std::error_code ec, std::size_t length) - { - if (!ec) - { - // A complete message header has been read, check if this message - // has a body to follow... - if (m_msgTemporaryIn.header.size > 0) - { - // ...it does, so allocate enough space in the messages' body - // vector, and issue asio with the task to read the body. - m_msgTemporaryIn.body.resize(m_msgTemporaryIn.header.size); - ReadBody(); - } - else - { - // it doesn't, so add this bodyless message to the connections - // incoming message queue - AddToIncomingMessageQueue(); - } - } - else - { - // Reading form the client went wrong, most likely a disconnect - // has occurred. Close the socket and let the system tidy it up later. - std::cout << "[" << id << "] Read Header Fail.\n"; - m_socket.close(); - } - }); - } - - // ASYNC - Prime context ready to read a message body - void ReadBody() - { - // If this function is called, a header has already been read, and that header - // request we read a body, The space for that body has already been allocated - // in the temporary message object, so just wait for the bytes to arrive... - asio::async_read(m_socket, asio::buffer(m_msgTemporaryIn.body.data(), m_msgTemporaryIn.body.size()), - [this](std::error_code ec, std::size_t length) - { - if (!ec) - { - // ...and they have! The message is now complete, so add - // the whole message to incoming queue - AddToIncomingMessageQueue(); - } - else - { - // As above! - std::cout << "[" << id << "] Read Body Fail.\n"; - m_socket.close(); - } - }); - } - - // Once a full message is received, add it to the incoming queue - void AddToIncomingMessageQueue() - { - // Shove it in queue, converting it to an "owned message", by initialising - // with the a shared pointer from this connection object - if(m_nOwnerType == owner::server) - m_qMessagesIn.push_back({ this->shared_from_this(), m_msgTemporaryIn }); - else - m_qMessagesIn.push_back({ nullptr, m_msgTemporaryIn }); - - // We must now prime the asio context to receive the next message. It - // wil just sit and wait for bytes to arrive, and the message construction - // process repeats itself. Clever huh? - ReadHeader(); - } - - protected: - // Each connection has a unique socket to a remote - asio::ip::tcp::socket m_socket; - - // This context is shared with the whole asio instance - asio::io_context& m_asioContext; - - // This queue holds all messages to be sent to the remote side - // of this connection - tsqueue> m_qMessagesOut; - - // This references the incoming queue of the parent object - tsqueue>& m_qMessagesIn; - - // Incoming messages are constructed asynchronously, so we will - // store the part assembled message here, until it is ready - message m_msgTemporaryIn; - - // The "owner" decides how some of the connection behaves - owner m_nOwnerType = owner::server; - - uint32_t id = 0; - - }; - } -} \ No newline at end of file diff --git a/Videos/Networking/Parts1&2/net_message.h b/Videos/Networking/Parts1&2/net_message.h deleted file mode 100644 index 80e8ef3..0000000 --- a/Videos/Networking/Parts1&2/net_message.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - MMO Client/Server Framework using ASIO - "Happy Birthday Mrs Javidx9!" - javidx9 - - Videos: - Part #1: https://youtu.be/2hNdkYInj4g - Part #2: https://youtu.be/UbjxGvrDrbw - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020 - -*/ - -#pragma once -#include "net_common.h" - -namespace olc -{ - namespace net - { - ///[OLC_HEADERIFYIER] START "MESSAGE" - - // Message Header is sent at start of all messages. The template allows us - // to use "enum class" to ensure that the messages are valid at compile time - template - struct message_header - { - T id{}; - uint32_t size = 0; - }; - - // Message Body contains a header and a std::vector, containing raw bytes - // of infomation. This way the message can be variable length, but the size - // in the header must be updated. - template - struct message - { - // Header & Body vector - message_header header{}; - std::vector body; - - // returns size of entire message packet in bytes - size_t size() const - { - return body.size(); - } - - // Override for std::cout compatibility - produces friendly description of message - friend std::ostream& operator << (std::ostream& os, const message& msg) - { - os << "ID:" << int(msg.header.id) << " Size:" << msg.header.size; - return os; - } - - // Convenience Operator overloads - These allow us to add and remove stuff from - // the body vector as if it were a stack, so First in, Last Out. These are a - // template in itself, because we dont know what data type the user is pushing or - // popping, so lets allow them all. NOTE: It assumes the data type is fundamentally - // Plain Old Data (POD). TLDR: Serialise & Deserialise into/from a vector - - // Pushes any POD-like data into the message buffer - template - friend message& operator << (message& msg, const DataType& data) - { - // Check that the type of the data being pushed is trivially copyable - static_assert(std::is_standard_layout::value, "Data is too complex to be pushed into vector"); - - // Cache current size of vector, as this will be the point we insert the data - size_t i = msg.body.size(); - - // Resize the vector by the size of the data being pushed - msg.body.resize(msg.body.size() + sizeof(DataType)); - - // Physically copy the data into the newly allocated vector space - std::memcpy(msg.body.data() + i, &data, sizeof(DataType)); - - // Recalculate the message size - msg.header.size = msg.size(); - - // Return the target message so it can be "chained" - return msg; - } - - // Pulls any POD-like data form the message buffer - template - friend message& operator >> (message& msg, DataType& data) - { - // Check that the type of the data being pushed is trivially copyable - static_assert(std::is_standard_layout::value, "Data is too complex to be pulled from vector"); - - // Cache the location towards the end of the vector where the pulled data starts - size_t i = msg.body.size() - sizeof(DataType); - - // Physically copy the data from the vector into the user variable - std::memcpy(&data, msg.body.data() + i, sizeof(DataType)); - - // Shrink the vector to remove read bytes, and reset end position - msg.body.resize(i); - - // Recalculate the message size - msg.header.size = msg.size(); - - // Return the target message so it can be "chained" - return msg; - } - }; - - - // An "owned" message is identical to a regular message, but it is associated with - // a connection. On a server, the owner would be the client that sent the message, - // on a client the owner would be the server. - - // Forward declare the connection - template - class connection; - - template - struct owned_message - { - std::shared_ptr> remote = nullptr; - message msg; - - // Again, a friendly string maker - friend std::ostream& operator<<(std::ostream& os, const owned_message& msg) - { - os << msg.msg; - return os; - } - }; - - ///[OLC_HEADERIFYIER] END "MESSAGE" - } -} - diff --git a/Videos/Networking/Parts1&2/net_server.h b/Videos/Networking/Parts1&2/net_server.h deleted file mode 100644 index e43d362..0000000 --- a/Videos/Networking/Parts1&2/net_server.h +++ /dev/null @@ -1,298 +0,0 @@ -/* - MMO Client/Server Framework using ASIO - "Happy Birthday Mrs Javidx9!" - javidx9 - - Videos: - Part #1: https://youtu.be/2hNdkYInj4g - Part #2: https://youtu.be/UbjxGvrDrbw - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020 - -*/ - -#pragma once - -#include "net_common.h" -#include "net_tsqueue.h" -#include "net_message.h" -#include "net_connection.h" - -namespace olc -{ - namespace net - { - template - class server_interface - { - public: - // Create a server, ready to listen on specified port - server_interface(uint16_t port) - : m_asioAcceptor(m_asioContext, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)) - { - - } - - virtual ~server_interface() - { - // May as well try and tidy up - Stop(); - } - - // Starts the server! - bool Start() - { - try - { - // Issue a task to the asio context - This is important - // as it will prime the context with "work", and stop it - // from exiting immediately. Since this is a server, we - // want it primed ready to handle clients trying to - // connect. - WaitForClientConnection(); - - // Launch the asio context in its own thread - m_threadContext = std::thread([this]() { m_asioContext.run(); }); - } - catch (std::exception& e) - { - // Something prohibited the server from listening - std::cerr << "[SERVER] Exception: " << e.what() << "\n"; - return false; - } - - std::cout << "[SERVER] Started!\n"; - return true; - } - - // Stops the server! - void Stop() - { - // Request the context to close - m_asioContext.stop(); - - // Tidy up the context thread - if (m_threadContext.joinable()) m_threadContext.join(); - - // Inform someone, anybody, if they care... - std::cout << "[SERVER] Stopped!\n"; - } - - // ASYNC - Instruct asio to wait for connection - void WaitForClientConnection() - { - // Prime context with an instruction to wait until a socket connects. This - // is the purpose of an "acceptor" object. It will provide a unique socket - // for each incoming connection attempt - m_asioAcceptor.async_accept( - [this](std::error_code ec, asio::ip::tcp::socket socket) - { - // Triggered by incoming connection request - if (!ec) - { - // Display some useful(?) information - std::cout << "[SERVER] New Connection: " << socket.remote_endpoint() << "\n"; - - // Create a new connection to handle this client - std::shared_ptr> newconn = - std::make_shared>(connection::owner::server, - m_asioContext, std::move(socket), m_qMessagesIn); - - - - // Give the user server a chance to deny connection - if (OnClientConnect(newconn)) - { - // Connection allowed, so add to container of new connections - m_deqConnections.push_back(std::move(newconn)); - - // And very important! Issue a task to the connection's - // asio context to sit and wait for bytes to arrive! - m_deqConnections.back()->ConnectToClient(nIDCounter++); - - std::cout << "[" << m_deqConnections.back()->GetID() << "] Connection Approved\n"; - } - else - { - std::cout << "[-----] Connection Denied\n"; - - // Connection will go out of scope with no pending tasks, so will - // get destroyed automagically due to the wonder of smart pointers - } - } - else - { - // Error has occurred during acceptance - std::cout << "[SERVER] New Connection Error: " << ec.message() << "\n"; - } - - // Prime the asio context with more work - again simply wait for - // another connection... - WaitForClientConnection(); - }); - } - - // Send a message to a specific client - void MessageClient(std::shared_ptr> client, const message& msg) - { - // Check client is legitimate... - if (client && client->IsConnected()) - { - // ...and post the message via the connection - client->Send(msg); - } - else - { - // If we cant communicate with client then we may as - // well remove the client - let the server know, it may - // be tracking it somehow - OnClientDisconnect(client); - - // Off you go now, bye bye! - client.reset(); - - // Then physically remove it from the container - m_deqConnections.erase( - std::remove(m_deqConnections.begin(), m_deqConnections.end(), client), m_deqConnections.end()); - } - } - - // Send message to all clients - void MessageAllClients(const message& msg, std::shared_ptr> pIgnoreClient = nullptr) - { - bool bInvalidClientExists = false; - - // Iterate through all clients in container - for (auto& client : m_deqConnections) - { - // Check client is connected... - if (client && client->IsConnected()) - { - // ..it is! - if(client != pIgnoreClient) - client->Send(msg); - } - else - { - // The client couldnt be contacted, so assume it has - // disconnected. - OnClientDisconnect(client); - client.reset(); - - // Set this flag to then remove dead clients from container - bInvalidClientExists = true; - } - } - - // Remove dead clients, all in one go - this way, we dont invalidate the - // container as we iterated through it. - if (bInvalidClientExists) - m_deqConnections.erase( - std::remove(m_deqConnections.begin(), m_deqConnections.end(), nullptr), m_deqConnections.end()); - } - - // Force server to respond to incoming messages - void Update(size_t nMaxMessages = -1, bool bWait = false) - { - if (bWait) m_qMessagesIn.wait(); - - // Process as many messages as you can up to the value - // specified - size_t nMessageCount = 0; - while (nMessageCount < nMaxMessages && !m_qMessagesIn.empty()) - { - // Grab the front message - auto msg = m_qMessagesIn.pop_front(); - - // Pass to message handler - OnMessage(msg.remote, msg.msg); - - nMessageCount++; - } - } - - protected: - // This server class should override thse functions to implement - // customised functionality - - // Called when a client connects, you can veto the connection by returning false - virtual bool OnClientConnect(std::shared_ptr> client) - { - return false; - } - - // Called when a client appears to have disconnected - virtual void OnClientDisconnect(std::shared_ptr> client) - { - - } - - // Called when a message arrives - virtual void OnMessage(std::shared_ptr> client, message& msg) - { - - } - - - protected: - // Thread Safe Queue for incoming message packets - tsqueue> m_qMessagesIn; - - // Container of active validated connections - std::deque>> m_deqConnections; - - // Order of declaration is important - it is also the order of initialisation - asio::io_context m_asioContext; - std::thread m_threadContext; - - // These things need an asio context - asio::ip::tcp::acceptor m_asioAcceptor; // Handles new incoming connection attempts... - - // Clients will be identified in the "wider system" via an ID - uint32_t nIDCounter = 10000; - }; - } -} \ No newline at end of file diff --git a/Videos/Networking/Parts1&2/net_tsqueue.h b/Videos/Networking/Parts1&2/net_tsqueue.h deleted file mode 100644 index 30741a6..0000000 --- a/Videos/Networking/Parts1&2/net_tsqueue.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - MMO Client/Server Framework using ASIO - "Happy Birthday Mrs Javidx9!" - javidx9 - - Videos: - Part #1: https://youtu.be/2hNdkYInj4g - Part #2: https://youtu.be/UbjxGvrDrbw - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020 - -*/ - -#pragma once - -#include "net_common.h" - -namespace olc -{ - namespace net - { - template - class tsqueue - { - public: - tsqueue() = default; - tsqueue(const tsqueue&) = delete; - virtual ~tsqueue() { clear(); } - - public: - // Returns and maintains item at front of Queue - const T& front() - { - std::scoped_lock lock(muxQueue); - return deqQueue.front(); - } - - // Returns and maintains item at back of Queue - const T& back() - { - std::scoped_lock lock(muxQueue); - return deqQueue.back(); - } - - // Removes and returns item from front of Queue - T pop_front() - { - std::scoped_lock lock(muxQueue); - auto t = std::move(deqQueue.front()); - deqQueue.pop_front(); - return t; - } - - // Removes and returns item from back of Queue - T pop_back() - { - std::scoped_lock lock(muxQueue); - auto t = std::move(deqQueue.back()); - deqQueue.pop_back(); - return t; - } - - // Adds an item to back of Queue - void push_back(const T& item) - { - std::scoped_lock lock(muxQueue); - deqQueue.emplace_back(std::move(item)); - - std::unique_lock ul(muxBlocking); - cvBlocking.notify_one(); - } - - // Adds an item to front of Queue - void push_front(const T& item) - { - std::scoped_lock lock(muxQueue); - deqQueue.emplace_front(std::move(item)); - - std::unique_lock ul(muxBlocking); - cvBlocking.notify_one(); - } - - // Returns true if Queue has no items - bool empty() - { - std::scoped_lock lock(muxQueue); - return deqQueue.empty(); - } - - // Returns number of items in Queue - size_t count() - { - std::scoped_lock lock(muxQueue); - return deqQueue.size(); - } - - // Clears Queue - void clear() - { - std::scoped_lock lock(muxQueue); - deqQueue.clear(); - } - - void wait() - { - while (empty()) - { - std::unique_lock ul(muxBlocking); - cvBlocking.wait(ul); - } - } - - protected: - std::mutex muxQueue; - std::deque deqQueue; - std::condition_variable cvBlocking; - std::mutex muxBlocking; - }; - } -} \ No newline at end of file diff --git a/Videos/Networking/Parts1&2/olc_net.h b/Videos/Networking/Parts1&2/olc_net.h deleted file mode 100644 index 1189cbc..0000000 --- a/Videos/Networking/Parts1&2/olc_net.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - MMO Client/Server Framework using ASIO - "Happy Birthday Mrs Javidx9!" - javidx9 - - Videos: - Part #1: https://youtu.be/2hNdkYInj4g - Part #2: https://youtu.be/UbjxGvrDrbw - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020 - -*/ - -#pragma once - -#include "net_common.h" -#include "net_tsqueue.h" -#include "net_message.h" -#include "net_client.h" -#include "net_server.h" -#include "net_connection.h" \ No newline at end of file diff --git a/Videos/Networking/Parts1&2/readme.txt b/Videos/Networking/Parts1&2/readme.txt deleted file mode 100644 index 73dee95..0000000 --- a/Videos/Networking/Parts1&2/readme.txt +++ /dev/null @@ -1,3 +0,0 @@ -Networking Code - -This version is incomplete! Its fine for experimenting, but it will consume whole processor cores, and it has a memory leak. These will be identified and resolved in Part#3 when we look at making it robust. diff --git a/Videos/Networking/Parts3&4/MMO_Client.cpp b/Videos/Networking/Parts3&4/MMO_Client.cpp deleted file mode 100644 index cd47177..0000000 --- a/Videos/Networking/Parts3&4/MMO_Client.cpp +++ /dev/null @@ -1,278 +0,0 @@ - -#include "../MMO_Server/MMO_Common.h" - -#define OLC_PGEX_TRANSFORMEDVIEW -#include "olcPGEX_TransformedView.h" - -#include - -class MMOGame : public olc::PixelGameEngine, olc::net::client_interface -{ -public: - MMOGame() - { - sAppName = "MMO Client"; - } - -private: - olc::TileTransformedView tv; - - std::string sWorldMap = - "################################" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..........####...####.........#" - "#..........#.........#.........#" - "#..........#.........#.........#" - "#..........#.........#.........#" - "#..........##############......#" - "#..............................#" - "#..................#.#.#.#.....#" - "#..............................#" - "#..................#.#.#.#.....#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "#..............................#" - "################################"; - - olc::vi2d vWorldSize = { 32, 32 }; - -private: - std::unordered_map mapObjects; - uint32_t nPlayerID = 0; - sPlayerDescription descPlayer; - - bool bWaitingForConnection = true; - -public: - bool OnUserCreate() override - { - tv = olc::TileTransformedView({ ScreenWidth(), ScreenHeight() }, { 8, 8 }); - - //mapObjects[0].nUniqueID = 0; - //mapObjects[0].vPos = { 3.0f, 3.0f }; - - if (Connect("127.0.0.1", 60000)) - { - return true; - } - - return false; - } - - bool OnUserUpdate(float fElapsedTime) override - { - // Check for incoming network messages - if (IsConnected()) - { - while (!Incoming().empty()) - { - auto msg = Incoming().pop_front().msg; - - switch (msg.header.id) - { - case(GameMsg::Client_Accepted): - { - std::cout << "Server accepted client - you're in!\n"; - olc::net::message msg; - msg.header.id = GameMsg::Client_RegisterWithServer; - descPlayer.vPos = { 3.0f, 3.0f }; - msg << descPlayer; - Send(msg); - break; - } - - case(GameMsg::Client_AssignID): - { - // Server is assigning us OUR id - msg >> nPlayerID; - std::cout << "Assigned Client ID = " << nPlayerID << "\n"; - break; - } - - case(GameMsg::Game_AddPlayer): - { - sPlayerDescription desc; - msg >> desc; - mapObjects.insert_or_assign(desc.nUniqueID, desc); - - if (desc.nUniqueID == nPlayerID) - { - // Now we exist in game world - bWaitingForConnection = false; - } - break; - } - - case(GameMsg::Game_RemovePlayer): - { - uint32_t nRemovalID = 0; - msg >> nRemovalID; - mapObjects.erase(nRemovalID); - break; - } - - case(GameMsg::Game_UpdatePlayer): - { - sPlayerDescription desc; - msg >> desc; - mapObjects.insert_or_assign(desc.nUniqueID, desc); - break; - } - - - } - } - } - - if (bWaitingForConnection) - { - Clear(olc::DARK_BLUE); - DrawString({ 10,10 }, "Waiting To Connect...", olc::WHITE); - return true; - } - - - - - - - // Control of Player Object - mapObjects[nPlayerID].vVel = { 0.0f, 0.0f }; - if (GetKey(olc::Key::W).bHeld) mapObjects[nPlayerID].vVel += { 0.0f, -1.0f }; - if (GetKey(olc::Key::S).bHeld) mapObjects[nPlayerID].vVel += { 0.0f, +1.0f }; - if (GetKey(olc::Key::A).bHeld) mapObjects[nPlayerID].vVel += { -1.0f, 0.0f }; - if (GetKey(olc::Key::D).bHeld) mapObjects[nPlayerID].vVel += { +1.0f, 0.0f }; - - if (mapObjects[nPlayerID].vVel.mag2() > 0) - mapObjects[nPlayerID].vVel = mapObjects[nPlayerID].vVel.norm() * 4.0f; - - // Update objects locally - for (auto& object : mapObjects) - { - // Where will object be worst case? - olc::vf2d vPotentialPosition = object.second.vPos + object.second.vVel * fElapsedTime; - - // Extract region of world cells that could have collision this frame - olc::vi2d vCurrentCell = object.second.vPos.floor(); - olc::vi2d vTargetCell = vPotentialPosition; - olc::vi2d vAreaTL = (vCurrentCell.min(vTargetCell) - olc::vi2d(1, 1)).max({ 0,0 }); - olc::vi2d vAreaBR = (vCurrentCell.max(vTargetCell) + olc::vi2d(1, 1)).min(vWorldSize); - - // Iterate through each cell in test area - olc::vi2d vCell; - for (vCell.y = vAreaTL.y; vCell.y <= vAreaBR.y; vCell.y++) - { - for (vCell.x = vAreaTL.x; vCell.x <= vAreaBR.x; vCell.x++) - { - // Check if the cell is actually solid... - // olc::vf2d vCellMiddle = vCell.floor(); - if (sWorldMap[vCell.y * vWorldSize.x + vCell.x] == '#') - { - // ...it is! So work out nearest point to future player position, around perimeter - // of cell rectangle. We can test the distance to this point to see if we have - // collided. - - olc::vf2d vNearestPoint; - // Inspired by this (very clever btw) - // https://stackoverflow.com/questions/45370692/circle-rectangle-collision-response - vNearestPoint.x = std::max(float(vCell.x), std::min(vPotentialPosition.x, float(vCell.x + 1))); - vNearestPoint.y = std::max(float(vCell.y), std::min(vPotentialPosition.y, float(vCell.y + 1))); - - // But modified to work :P - olc::vf2d vRayToNearest = vNearestPoint - vPotentialPosition; - float fOverlap = object.second.fRadius - vRayToNearest.mag(); - if (std::isnan(fOverlap)) fOverlap = 0;// Thanks Dandistine! - - // If overlap is positive, then a collision has occurred, so we displace backwards by the - // overlap amount. The potential position is then tested against other tiles in the area - // therefore "statically" resolving the collision - if (fOverlap > 0) - { - // Statically resolve the collision - vPotentialPosition = vPotentialPosition - vRayToNearest.norm() * fOverlap; - } - } - } - } - - // Set the objects new position to the allowed potential position - object.second.vPos = vPotentialPosition; - } - - - - - - - // Handle Pan & Zoom - if (GetMouse(2).bPressed) tv.StartPan(GetMousePos()); - if (GetMouse(2).bHeld) tv.UpdatePan(GetMousePos()); - if (GetMouse(2).bReleased) tv.EndPan(GetMousePos()); - if (GetMouseWheel() > 0) tv.ZoomAtScreenPos(1.5f, GetMousePos()); - if (GetMouseWheel() < 0) tv.ZoomAtScreenPos(0.75f, GetMousePos()); - - // Clear World - Clear(olc::BLACK); - - // Draw World - olc::vi2d vTL = tv.GetTopLeftTile().max({ 0,0 }); - olc::vi2d vBR = tv.GetBottomRightTile().min(vWorldSize); - olc::vi2d vTile; - for (vTile.y = vTL.y; vTile.y < vBR.y; vTile.y++) - for (vTile.x = vTL.x; vTile.x < vBR.x; vTile.x++) - { - if (sWorldMap[vTile.y * vWorldSize.x + vTile.x] == '#') - { - tv.DrawRect(vTile, { 1.0f, 1.0f }); - tv.DrawRect(olc::vf2d(vTile) + olc::vf2d(0.1f, 0.1f), { 0.8f, 0.8f }); - } - } - - // Draw World Objects - for (auto& object : mapObjects) - { - // Draw Boundary - tv.DrawCircle(object.second.vPos, object.second.fRadius); - - // Draw Velocity - if (object.second.vVel.mag2() > 0) - tv.DrawLine(object.second.vPos, object.second.vPos + object.second.vVel.norm() * object.second.fRadius, olc::MAGENTA); - - // Draw Name - olc::vi2d vNameSize = GetTextSizeProp("ID: " + std::to_string(object.first)); - tv.DrawStringPropDecal(object.second.vPos - olc::vf2d{ vNameSize.x * 0.5f * 0.25f * 0.125f, -object.second.fRadius * 1.25f }, "ID: " + std::to_string(object.first), olc::BLUE, { 0.25f, 0.25f }); - } - - // Send player description - olc::net::message msg; - msg.header.id = GameMsg::Game_UpdatePlayer; - msg << mapObjects[nPlayerID]; - Send(msg); - return true; - } -}; - -int main() -{ - MMOGame demo; - if (demo.Construct(480, 480, 1, 1)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/Networking/Parts3&4/MMO_Common.h b/Videos/Networking/Parts3&4/MMO_Common.h deleted file mode 100644 index c7c7f2e..0000000 --- a/Videos/Networking/Parts3&4/MMO_Common.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#define OLC_PGEX_NETWORK -#include "olcPGEX_Network.h" - -enum class GameMsg : uint32_t -{ - Server_GetStatus, - Server_GetPing, - - Client_Accepted, - Client_AssignID, - Client_RegisterWithServer, - Client_UnregisterWithServer, - - Game_AddPlayer, - Game_RemovePlayer, - Game_UpdatePlayer, -}; - -struct sPlayerDescription -{ - uint32_t nUniqueID = 0; - uint32_t nAvatarID = 0; - - uint32_t nHealth = 100; - uint32_t nAmmo = 20; - uint32_t nKills = 0; - uint32_t nDeaths = 0; - - float fRadius = 0.5f; - - olc::vf2d vPos; - olc::vf2d vVel; -}; \ No newline at end of file diff --git a/Videos/Networking/Parts3&4/MMO_Server.cpp b/Videos/Networking/Parts3&4/MMO_Server.cpp deleted file mode 100644 index 3390b82..0000000 --- a/Videos/Networking/Parts3&4/MMO_Server.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include -#include - -#include "MMO_Common.h" - -class GameServer : public olc::net::server_interface -{ -public: - GameServer(uint16_t nPort) : olc::net::server_interface(nPort) - { - } - - std::unordered_map m_mapPlayerRoster; - std::vector m_vGarbageIDs; - -protected: - bool OnClientConnect(std::shared_ptr> client) override - { - // For now we will allow all - return true; - } - - void OnClientValidated(std::shared_ptr> client) override - { - // Client passed validation check, so send them a message informing - // them they can continue to communicate - olc::net::message msg; - msg.header.id = GameMsg::Client_Accepted; - client->Send(msg); - } - - void OnClientDisconnect(std::shared_ptr> client) override - { - if (client) - { - if (m_mapPlayerRoster.find(client->GetID()) == m_mapPlayerRoster.end()) - { - // client never added to roster, so just let it disappear - } - else - { - auto& pd = m_mapPlayerRoster[client->GetID()]; - std::cout << "[UNGRACEFUL REMOVAL]:" + std::to_string(pd.nUniqueID) + "\n"; - m_mapPlayerRoster.erase(client->GetID()); - m_vGarbageIDs.push_back(client->GetID()); - } - } - - } - - void OnMessage(std::shared_ptr> client, olc::net::message& msg) override - { - if (!m_vGarbageIDs.empty()) - { - for (auto pid : m_vGarbageIDs) - { - olc::net::message m; - m.header.id = GameMsg::Game_RemovePlayer; - m << pid; - std::cout << "Removing " << pid << "\n"; - MessageAllClients(m); - } - m_vGarbageIDs.clear(); - } - - - - switch (msg.header.id) - { - case GameMsg::Client_RegisterWithServer: - { - sPlayerDescription desc; - msg >> desc; - desc.nUniqueID = client->GetID(); - m_mapPlayerRoster.insert_or_assign(desc.nUniqueID, desc); - - olc::net::message msgSendID; - msgSendID.header.id = GameMsg::Client_AssignID; - msgSendID << desc.nUniqueID; - MessageClient(client, msgSendID); - - olc::net::message msgAddPlayer; - msgAddPlayer.header.id = GameMsg::Game_AddPlayer; - msgAddPlayer << desc; - MessageAllClients(msgAddPlayer); - - for (const auto& player : m_mapPlayerRoster) - { - olc::net::message msgAddOtherPlayers; - msgAddOtherPlayers.header.id = GameMsg::Game_AddPlayer; - msgAddOtherPlayers << player.second; - MessageClient(client, msgAddOtherPlayers); - } - - break; - } - - case GameMsg::Client_UnregisterWithServer: - { - break; - } - - case GameMsg::Game_UpdatePlayer: - { - // Simply bounce update to everyone except incoming client - MessageAllClients(msg, client); - break; - } - - } - - } - -}; - - - -int main() -{ - GameServer server(60000); - server.Start(); - - while (1) - { - server.Update(-1, true); - } - return 0; -} \ No newline at end of file diff --git a/Videos/Networking/Parts3&4/olcPGEX_Network.h b/Videos/Networking/Parts3&4/olcPGEX_Network.h deleted file mode 100644 index 02fd6f0..0000000 --- a/Videos/Networking/Parts3&4/olcPGEX_Network.h +++ /dev/null @@ -1,1038 +0,0 @@ -/* - ASIO Based Networking olcPixelGameEngine Extension v1.0 - - Videos: - Part #1: https://youtu.be/2hNdkYInj4g - Part #2: https://youtu.be/UbjxGvrDrbw - Part #3: https://youtu.be/hHowZ3bWsio - Part #4: https://youtu.be/f_1lt9pfaEo - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2021 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021 - -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0A00 -#endif -#endif - -#define _WINSOCK_DEPRECATED_NO_WARNINGS -#define ASIO_STANDALONE -#include -#include -#include - -namespace olc -{ - namespace net - { - // Message - - // Message Header is sent at start of all messages. The template allows us - // to use "enum class" to ensure that the messages are valid at compile time - template - struct message_header - { - T id{}; - uint32_t size = 0; - }; - - // Message Body contains a header and a std::vector, containing raw bytes - // of infomation. This way the message can be variable length, but the size - // in the header must be updated. - template - struct message - { - // Header & Body vector - message_header header{}; - std::vector body; - - // returns size of entire message packet in bytes - size_t size() const - { - return body.size(); - } - - // Override for std::cout compatibility - produces friendly description of message - friend std::ostream& operator << (std::ostream& os, const message& msg) - { - os << "ID:" << int(msg.header.id) << " Size:" << msg.header.size; - return os; - } - - // Convenience Operator overloads - These allow us to add and remove stuff from - // the body vector as if it were a stack, so First in, Last Out. These are a - // template in itself, because we dont know what data type the user is pushing or - // popping, so lets allow them all. NOTE: It assumes the data type is fundamentally - // Plain Old Data (POD). TLDR: Serialise & Deserialise into/from a vector - - // Pushes any POD-like data into the message buffer - template - friend message& operator << (message& msg, const DataType& data) - { - // Check that the type of the data being pushed is trivially copyable - static_assert(std::is_standard_layout::value, "Data is too complex to be pushed into vector"); - - // Cache current size of vector, as this will be the point we insert the data - size_t i = msg.body.size(); - - // Resize the vector by the size of the data being pushed - msg.body.resize(msg.body.size() + sizeof(DataType)); - - // Physically copy the data into the newly allocated vector space - std::memcpy(msg.body.data() + i, &data, sizeof(DataType)); - - // Recalculate the message size - msg.header.size = msg.size(); - - // Return the target message so it can be "chained" - return msg; - } - - // Pulls any POD-like data form the message buffer - template - friend message& operator >> (message& msg, DataType& data) - { - // Check that the type of the data being pushed is trivially copyable - static_assert(std::is_standard_layout::value, "Data is too complex to be pulled from vector"); - - // Cache the location towards the end of the vector where the pulled data starts - size_t i = msg.body.size() - sizeof(DataType); - - // Physically copy the data from the vector into the user variable - std::memcpy(&data, msg.body.data() + i, sizeof(DataType)); - - // Shrink the vector to remove read bytes, and reset end position - msg.body.resize(i); - - // Recalculate the message size - msg.header.size = msg.size(); - - // Return the target message so it can be "chained" - return msg; - } - }; - - - // An "owned" message is identical to a regular message, but it is associated with - // a connection. On a server, the owner would be the client that sent the message, - // on a client the owner would be the server. - - // Forward declare the connection - template - class connection; - - template - struct owned_message - { - std::shared_ptr> remote = nullptr; - message msg; - - // Again, a friendly string maker - friend std::ostream& operator<<(std::ostream& os, const owned_message& msg) - { - os << msg.msg; - return os; - } - }; - - - // Queue - template - class tsqueue - { - public: - tsqueue() = default; - tsqueue(const tsqueue&) = delete; - virtual ~tsqueue() { clear(); } - - public: - // Returns and maintains item at front of Queue - const T& front() - { - std::scoped_lock lock(muxQueue); - return deqQueue.front(); - } - - // Returns and maintains item at back of Queue - const T& back() - { - std::scoped_lock lock(muxQueue); - return deqQueue.back(); - } - - // Removes and returns item from front of Queue - T pop_front() - { - std::scoped_lock lock(muxQueue); - auto t = std::move(deqQueue.front()); - deqQueue.pop_front(); - return t; - } - - // Removes and returns item from back of Queue - T pop_back() - { - std::scoped_lock lock(muxQueue); - auto t = std::move(deqQueue.back()); - deqQueue.pop_back(); - return t; - } - - // Adds an item to back of Queue - void push_back(const T& item) - { - std::scoped_lock lock(muxQueue); - deqQueue.emplace_back(std::move(item)); - - std::unique_lock ul(muxBlocking); - cvBlocking.notify_one(); - } - - // Adds an item to front of Queue - void push_front(const T& item) - { - std::scoped_lock lock(muxQueue); - deqQueue.emplace_front(std::move(item)); - - std::unique_lock ul(muxBlocking); - cvBlocking.notify_one(); - } - - // Returns true if Queue has no items - bool empty() - { - std::scoped_lock lock(muxQueue); - return deqQueue.empty(); - } - - // Returns number of items in Queue - size_t count() - { - std::scoped_lock lock(muxQueue); - return deqQueue.size(); - } - - // Clears Queue - void clear() - { - std::scoped_lock lock(muxQueue); - deqQueue.clear(); - } - - void wait() - { - while (empty()) - { - std::unique_lock ul(muxBlocking); - cvBlocking.wait(ul); - } - } - - protected: - std::mutex muxQueue; - std::deque deqQueue; - std::condition_variable cvBlocking; - std::mutex muxBlocking; - }; - - // Connection - // Forward declare - template - class server_interface; - - template - class connection : public std::enable_shared_from_this> - { - public: - // A connection is "owned" by either a server or a client, and its - // behaviour is slightly different bewteen the two. - enum class owner - { - server, - client - }; - - public: - // Constructor: Specify Owner, connect to context, transfer the socket - // Provide reference to incoming message queue - connection(owner parent, asio::io_context& asioContext, asio::ip::tcp::socket socket, tsqueue>& qIn) - : m_asioContext(asioContext), m_socket(std::move(socket)), m_qMessagesIn(qIn) - { - m_nOwnerType = parent; - - // Construct validation check data - if (m_nOwnerType == owner::server) - { - // Connection is Server -> Client, construct random data for the client - // to transform and send back for validation - m_nHandshakeOut = uint64_t(std::chrono::system_clock::now().time_since_epoch().count()); - - // Pre-calculate the result for checking when the client responds - m_nHandshakeCheck = scramble(m_nHandshakeOut); - } - else - { - // Connection is Client -> Server, so we have nothing to define, - m_nHandshakeIn = 0; - m_nHandshakeOut = 0; - } - } - - virtual ~connection() - {} - - // This ID is used system wide - its how clients will understand other clients - // exist across the whole system. - uint32_t GetID() const - { - return id; - } - - public: - void ConnectToClient(olc::net::server_interface* server, uint32_t uid = 0) - { - if (m_nOwnerType == owner::server) - { - if (m_socket.is_open()) - { - id = uid; - - // Was: ReadHeader(); - - // A client has attempted to connect to the server, but we wish - // the client to first validate itself, so first write out the - // handshake data to be validated - WriteValidation(); - - // Next, issue a task to sit and wait asynchronously for precisely - // the validation data sent back from the client - ReadValidation(server); - } - } - } - - void ConnectToServer(const asio::ip::tcp::resolver::results_type& endpoints) - { - // Only clients can connect to servers - if (m_nOwnerType == owner::client) - { - // Request asio attempts to connect to an endpoint - asio::async_connect(m_socket, endpoints, - [this](std::error_code ec, asio::ip::tcp::endpoint endpoint) - { - if (!ec) - { - // Was: ReadHeader(); - - // First thing server will do is send packet to be validated - // so wait for that and respond - ReadValidation(); - } - }); - } - } - - - void Disconnect() - { - if (IsConnected()) - asio::post(m_asioContext, [this]() { m_socket.close(); }); - } - - bool IsConnected() const - { - return m_socket.is_open(); - } - - // Prime the connection to wait for incoming messages - void StartListening() - { - - } - - public: - // ASYNC - Send a message, connections are one-to-one so no need to specifiy - // the target, for a client, the target is the server and vice versa - void Send(const message& msg) - { - asio::post(m_asioContext, - [this, msg]() - { - // If the queue has a message in it, then we must - // assume that it is in the process of asynchronously being written. - // Either way add the message to the queue to be output. If no messages - // were available to be written, then start the process of writing the - // message at the front of the queue. - bool bWritingMessage = !m_qMessagesOut.empty(); - m_qMessagesOut.push_back(msg); - if (!bWritingMessage) - { - WriteHeader(); - } - }); - } - - - - private: - // ASYNC - Prime context to write a message header - void WriteHeader() - { - // If this function is called, we know the outgoing message queue must have - // at least one message to send. So allocate a transmission buffer to hold - // the message, and issue the work - asio, send these bytes - asio::async_write(m_socket, asio::buffer(&m_qMessagesOut.front().header, sizeof(message_header)), - [this](std::error_code ec, std::size_t length) - { - // asio has now sent the bytes - if there was a problem - // an error would be available... - if (!ec) - { - // ... no error, so check if the message header just sent also - // has a message body... - if (m_qMessagesOut.front().body.size() > 0) - { - // ...it does, so issue the task to write the body bytes - WriteBody(); - } - else - { - // ...it didnt, so we are done with this message. Remove it from - // the outgoing message queue - m_qMessagesOut.pop_front(); - - // If the queue is not empty, there are more messages to send, so - // make this happen by issuing the task to send the next header. - if (!m_qMessagesOut.empty()) - { - WriteHeader(); - } - } - } - else - { - // ...asio failed to write the message, we could analyse why but - // for now simply assume the connection has died by closing the - // socket. When a future attempt to write to this client fails due - // to the closed socket, it will be tidied up. - std::cout << "[" << id << "] Write Header Fail.\n"; - m_socket.close(); - } - }); - } - - // ASYNC - Prime context to write a message body - void WriteBody() - { - // If this function is called, a header has just been sent, and that header - // indicated a body existed for this message. Fill a transmission buffer - // with the body data, and send it! - asio::async_write(m_socket, asio::buffer(m_qMessagesOut.front().body.data(), m_qMessagesOut.front().body.size()), - [this](std::error_code ec, std::size_t length) - { - if (!ec) - { - // Sending was successful, so we are done with the message - // and remove it from the queue - m_qMessagesOut.pop_front(); - - // If the queue still has messages in it, then issue the task to - // send the next messages' header. - if (!m_qMessagesOut.empty()) - { - WriteHeader(); - } - } - else - { - // Sending failed, see WriteHeader() equivalent for description :P - std::cout << "[" << id << "] Write Body Fail.\n"; - m_socket.close(); - } - }); - } - - // ASYNC - Prime context ready to read a message header - void ReadHeader() - { - // If this function is called, we are expecting asio to wait until it receives - // enough bytes to form a header of a message. We know the headers are a fixed - // size, so allocate a transmission buffer large enough to store it. In fact, - // we will construct the message in a "temporary" message object as it's - // convenient to work with. - asio::async_read(m_socket, asio::buffer(&m_msgTemporaryIn.header, sizeof(message_header)), - [this](std::error_code ec, std::size_t length) - { - if (!ec) - { - // A complete message header has been read, check if this message - // has a body to follow... - if (m_msgTemporaryIn.header.size > 0) - { - // ...it does, so allocate enough space in the messages' body - // vector, and issue asio with the task to read the body. - m_msgTemporaryIn.body.resize(m_msgTemporaryIn.header.size); - ReadBody(); - } - else - { - // it doesn't, so add this bodyless message to the connections - // incoming message queue - AddToIncomingMessageQueue(); - } - } - else - { - // Reading form the client went wrong, most likely a disconnect - // has occurred. Close the socket and let the system tidy it up later. - std::cout << "[" << id << "] Read Header Fail.\n"; - m_socket.close(); - } - }); - } - - // ASYNC - Prime context ready to read a message body - void ReadBody() - { - // If this function is called, a header has already been read, and that header - // request we read a body, The space for that body has already been allocated - // in the temporary message object, so just wait for the bytes to arrive... - asio::async_read(m_socket, asio::buffer(m_msgTemporaryIn.body.data(), m_msgTemporaryIn.body.size()), - [this](std::error_code ec, std::size_t length) - { - if (!ec) - { - // ...and they have! The message is now complete, so add - // the whole message to incoming queue - AddToIncomingMessageQueue(); - } - else - { - // As above! - std::cout << "[" << id << "] Read Body Fail.\n"; - m_socket.close(); - } - }); - } - - // "Encrypt" data - uint64_t scramble(uint64_t nInput) - { - uint64_t out = nInput ^ 0xDEADBEEFC0DECAFE; - out = (out & 0xF0F0F0F0F0F0F0) >> 4 | (out & 0x0F0F0F0F0F0F0F) << 4; - return out ^ 0xC0DEFACE12345678; - } - - // ASYNC - Used by both client and server to write validation packet - void WriteValidation() - { - asio::async_write(m_socket, asio::buffer(&m_nHandshakeOut, sizeof(uint64_t)), - [this](std::error_code ec, std::size_t length) - { - if (!ec) - { - // Validation data sent, clients should sit and wait - // for a response (or a closure) - if (m_nOwnerType == owner::client) - ReadHeader(); - } - else - { - m_socket.close(); - } - }); - } - - void ReadValidation(olc::net::server_interface* server = nullptr) - { - asio::async_read(m_socket, asio::buffer(&m_nHandshakeIn, sizeof(uint64_t)), - [this, server](std::error_code ec, std::size_t length) - { - if (!ec) - { - if (m_nOwnerType == owner::server) - { - // Connection is a server, so check response from client - - // Compare sent data to actual solution - if (m_nHandshakeIn == m_nHandshakeCheck) - { - // Client has provided valid solution, so allow it to connect properly - std::cout << "Client Validated" << std::endl; - server->OnClientValidated(this->shared_from_this()); - - // Sit waiting to receive data now - ReadHeader(); - } - else - { - // Client gave incorrect data, so disconnect - std::cout << "Client Disconnected (Fail Validation)" << std::endl; - m_socket.close(); - } - } - else - { - // Connection is a client, so solve puzzle - m_nHandshakeOut = scramble(m_nHandshakeIn); - - // Write the result - WriteValidation(); - } - } - else - { - // Some biggerfailure occured - std::cout << "Client Disconnected (ReadValidation)" << std::endl; - m_socket.close(); - } - }); - } - - // Once a full message is received, add it to the incoming queue - void AddToIncomingMessageQueue() - { - // Shove it in queue, converting it to an "owned message", by initialising - // with the a shared pointer from this connection object - if(m_nOwnerType == owner::server) - m_qMessagesIn.push_back({ this->shared_from_this(), m_msgTemporaryIn }); - else - m_qMessagesIn.push_back({ nullptr, m_msgTemporaryIn }); - - // We must now prime the asio context to receive the next message. It - // wil just sit and wait for bytes to arrive, and the message construction - // process repeats itself. Clever huh? - ReadHeader(); - } - - protected: - // Each connection has a unique socket to a remote - asio::ip::tcp::socket m_socket; - - // This context is shared with the whole asio instance - asio::io_context& m_asioContext; - - // This queue holds all messages to be sent to the remote side - // of this connection - tsqueue> m_qMessagesOut; - - // This references the incoming queue of the parent object - tsqueue>& m_qMessagesIn; - - // Incoming messages are constructed asynchronously, so we will - // store the part assembled message here, until it is ready - message m_msgTemporaryIn; - - // The "owner" decides how some of the connection behaves - owner m_nOwnerType = owner::server; - - // Handshake Validation - uint64_t m_nHandshakeOut = 0; - uint64_t m_nHandshakeIn = 0; - uint64_t m_nHandshakeCheck = 0; - - - bool m_bValidHandshake = false; - bool m_bConnectionEstablished = false; - - uint32_t id = 0; - - }; - - // Client - template - class client_interface - { - public: - client_interface() - {} - - virtual ~client_interface() - { - // If the client is destroyed, always try and disconnect from server - Disconnect(); - } - - public: - // Connect to server with hostname/ip-address and port - bool Connect(const std::string& host, const uint16_t port) - { - try - { - // Resolve hostname/ip-address into tangiable physical address - asio::ip::tcp::resolver resolver(m_context); - asio::ip::tcp::resolver::results_type endpoints = resolver.resolve(host, std::to_string(port)); - - // Create connection - m_connection = std::make_unique>(connection::owner::client, m_context, asio::ip::tcp::socket(m_context), m_qMessagesIn); - - // Tell the connection object to connect to server - m_connection->ConnectToServer(endpoints); - - // Start Context Thread - thrContext = std::thread([this]() { m_context.run(); }); - } - catch (std::exception& e) - { - std::cerr << "Client Exception: " << e.what() << "\n"; - return false; - } - return true; - } - - // Disconnect from server - void Disconnect() - { - // If connection exists, and it's connected then... - if(IsConnected()) - { - // ...disconnect from server gracefully - m_connection->Disconnect(); - } - - // Either way, we're also done with the asio context... - m_context.stop(); - // ...and its thread - if (thrContext.joinable()) - thrContext.join(); - - // Destroy the connection object - m_connection.release(); - } - - // Check if client is actually connected to a server - bool IsConnected() - { - if (m_connection) - return m_connection->IsConnected(); - else - return false; - } - - public: - // Send message to server - void Send(const message& msg) - { - if (IsConnected()) - m_connection->Send(msg); - } - - // Retrieve queue of messages from server - tsqueue>& Incoming() - { - return m_qMessagesIn; - } - - protected: - // asio context handles the data transfer... - asio::io_context m_context; - // ...but needs a thread of its own to execute its work commands - std::thread thrContext; - // The client has a single instance of a "connection" object, which handles data transfer - std::unique_ptr> m_connection; - - private: - // This is the thread safe queue of incoming messages from server - tsqueue> m_qMessagesIn; - }; - - // Server - template - class server_interface - { - public: - // Create a server, ready to listen on specified port - server_interface(uint16_t port) - : m_asioAcceptor(m_asioContext, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port)) - { - - } - - virtual ~server_interface() - { - // May as well try and tidy up - Stop(); - } - - // Starts the server! - bool Start() - { - try - { - // Issue a task to the asio context - This is important - // as it will prime the context with "work", and stop it - // from exiting immediately. Since this is a server, we - // want it primed ready to handle clients trying to - // connect. - WaitForClientConnection(); - - // Launch the asio context in its own thread - m_threadContext = std::thread([this]() { m_asioContext.run(); }); - } - catch (std::exception& e) - { - // Something prohibited the server from listening - std::cerr << "[SERVER] Exception: " << e.what() << "\n"; - return false; - } - - std::cout << "[SERVER] Started!\n"; - return true; - } - - // Stops the server! - void Stop() - { - // Request the context to close - m_asioContext.stop(); - - // Tidy up the context thread - if (m_threadContext.joinable()) m_threadContext.join(); - - // Inform someone, anybody, if they care... - std::cout << "[SERVER] Stopped!\n"; - } - - // ASYNC - Instruct asio to wait for connection - void WaitForClientConnection() - { - // Prime context with an instruction to wait until a socket connects. This - // is the purpose of an "acceptor" object. It will provide a unique socket - // for each incoming connection attempt - m_asioAcceptor.async_accept( - [this](std::error_code ec, asio::ip::tcp::socket socket) - { - // Triggered by incoming connection request - if (!ec) - { - // Display some useful(?) information - std::cout << "[SERVER] New Connection: " << socket.remote_endpoint() << "\n"; - - // Create a new connection to handle this client - std::shared_ptr> newconn = - std::make_shared>(connection::owner::server, - m_asioContext, std::move(socket), m_qMessagesIn); - - - - // Give the user server a chance to deny connection - if (OnClientConnect(newconn)) - { - // Connection allowed, so add to container of new connections - m_deqConnections.push_back(std::move(newconn)); - - // And very important! Issue a task to the connection's - // asio context to sit and wait for bytes to arrive! - m_deqConnections.back()->ConnectToClient(this, nIDCounter++); - - std::cout << "[" << m_deqConnections.back()->GetID() << "] Connection Approved\n"; - } - else - { - std::cout << "[-----] Connection Denied\n"; - - // Connection will go out of scope with no pending tasks, so will - // get destroyed automagically due to the wonder of smart pointers - } - } - else - { - // Error has occurred during acceptance - std::cout << "[SERVER] New Connection Error: " << ec.message() << "\n"; - } - - // Prime the asio context with more work - again simply wait for - // another connection... - WaitForClientConnection(); - }); - } - - // Send a message to a specific client - void MessageClient(std::shared_ptr> client, const message& msg) - { - // Check client is legitimate... - if (client && client->IsConnected()) - { - // ...and post the message via the connection - client->Send(msg); - } - else - { - // If we cant communicate with client then we may as - // well remove the client - let the server know, it may - // be tracking it somehow - OnClientDisconnect(client); - - // Off you go now, bye bye! - client.reset(); - - // Then physically remove it from the container - m_deqConnections.erase( - std::remove(m_deqConnections.begin(), m_deqConnections.end(), client), m_deqConnections.end()); - } - } - - // Send message to all clients - void MessageAllClients(const message& msg, std::shared_ptr> pIgnoreClient = nullptr) - { - bool bInvalidClientExists = false; - - // Iterate through all clients in container - for (auto& client : m_deqConnections) - { - // Check client is connected... - if (client && client->IsConnected()) - { - // ..it is! - if(client != pIgnoreClient) - client->Send(msg); - } - else - { - // The client couldnt be contacted, so assume it has - // disconnected. - OnClientDisconnect(client); - client.reset(); - - // Set this flag to then remove dead clients from container - bInvalidClientExists = true; - } - } - - // Remove dead clients, all in one go - this way, we dont invalidate the - // container as we iterated through it. - if (bInvalidClientExists) - m_deqConnections.erase( - std::remove(m_deqConnections.begin(), m_deqConnections.end(), nullptr), m_deqConnections.end()); - } - - // Force server to respond to incoming messages - void Update(size_t nMaxMessages = -1, bool bWait = false) - { - if (bWait) m_qMessagesIn.wait(); - - // Process as many messages as you can up to the value - // specified - size_t nMessageCount = 0; - while (nMessageCount < nMaxMessages && !m_qMessagesIn.empty()) - { - // Grab the front message - auto msg = m_qMessagesIn.pop_front(); - - // Pass to message handler - OnMessage(msg.remote, msg.msg); - - nMessageCount++; - } - } - - protected: - // This server class should override thse functions to implement - // customised functionality - - // Called when a client connects, you can veto the connection by returning false - virtual bool OnClientConnect(std::shared_ptr> client) - { - return false; - } - - // Called when a client appears to have disconnected - virtual void OnClientDisconnect(std::shared_ptr> client) - { - - } - - // Called when a message arrives - virtual void OnMessage(std::shared_ptr> client, message& msg) - { - - } - - public: - // Called when a client is validated - virtual void OnClientValidated(std::shared_ptr> client) - { - - } - - - protected: - // Thread Safe Queue for incoming message packets - tsqueue> m_qMessagesIn; - - // Container of active validated connections - std::deque>> m_deqConnections; - - // Order of declaration is important - it is also the order of initialisation - asio::io_context m_asioContext; - std::thread m_threadContext; - - // These things need an asio context - asio::ip::tcp::acceptor m_asioAcceptor; // Handles new incoming connection attempts... - - // Clients will be identified in the "wider system" via an ID - uint32_t nIDCounter = 10000; - }; - } -} - - diff --git a/Videos/Networking/Parts3&4/olcPGEX_TransformedView.h b/Videos/Networking/Parts3&4/olcPGEX_TransformedView.h deleted file mode 100644 index e1e2f17..0000000 --- a/Videos/Networking/Parts3&4/olcPGEX_TransformedView.h +++ /dev/null @@ -1,658 +0,0 @@ -/* - olcPGEX_TransformedView.h - - +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine Extension | - | Transformed View v1.00 | - +-------------------------------------------------------------+ - - NOTE: UNDER ACTIVE DEVELOPMENT - THERE ARE BUGS/GLITCHES - - What is this? - ~~~~~~~~~~~~~ - This extension provides drawing routines that are compatible with - changeable world and screen spaces. For example you can pan and - zoom, and all PGE drawing routines will automatically adopt the current - world scales and offsets. - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2021 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021 - - Revisions: - 1.00: Initial Release -*/ - -#pragma once -#ifndef OLC_PGEX_TRANSFORMEDVIEW_H -#define OLC_PGEX_TRANSFORMEDVIEW_H - -#include "olcPixelGameEngine.h" - - - -namespace olc -{ - class TransformedView : public olc::PGEX - { - public: - TransformedView() = default; - virtual void Initialise(const olc::vi2d& vViewArea, const olc::vf2d& vPixelScale = { 1.0f, 1.0f }); - - public: - void SetWorldOffset(const olc::vf2d& vOffset); - void MoveWorldOffset(const olc::vf2d& vDeltaOffset); - void SetWorldScale(const olc::vf2d& vScale); - void SetViewArea(const olc::vi2d& vViewArea); - olc::vf2d GetWorldTL() const; - olc::vf2d GetWorldBR() const; - olc::vf2d GetWorldVisibleArea() const; - void ZoomAtScreenPos(const float fDeltaZoom, const olc::vi2d& vPos); - void SetZoom(const float fZoom, const olc::vi2d& vPos); - void StartPan(const olc::vi2d& vPos); - void UpdatePan(const olc::vi2d& vPos); - void EndPan(const olc::vi2d& vPos); - const olc::vf2d& GetWorldOffset() const; - const olc::vf2d& GetWorldScale() const; - virtual olc::vi2d WorldToScreen(const olc::vf2d& vWorldPos) const; - virtual olc::vf2d ScreenToWorld(const olc::vi2d& vScreenPos) const; - virtual olc::vf2d ScaleToWorld(const olc::vi2d& vScreenSize) const; - virtual olc::vi2d ScaleToScreen(const olc::vf2d& vWorldSize) const; - virtual bool IsPointVisible(const olc::vf2d& vPos) const; - virtual bool IsRectVisible(const olc::vf2d& vPos, const olc::vf2d& vSize) const; - - protected: - olc::vf2d m_vWorldOffset = { 0.0f, 0.0f }; - olc::vf2d m_vWorldScale = { 1.0f, 1.0f }; - olc::vf2d m_vRecipPixel = { 1.0f, 1.0f }; - olc::vf2d m_vPixelScale = { 1.0f, 1.0f }; - bool m_bPanning = false; - olc::vf2d m_vStartPan = { 0.0f, 0.0f }; - olc::vi2d m_vViewArea; - - public: // Hopefully, these should look familiar! - // Plots a single point - virtual bool Draw(float x, float y, olc::Pixel p = olc::WHITE); - bool Draw(const olc::vf2d& pos, olc::Pixel p = olc::WHITE); - // Draws a line from (x1,y1) to (x2,y2) - void DrawLine(float x1, float y1, float x2, float y2, olc::Pixel p = olc::WHITE, uint32_t pattern = 0xFFFFFFFF); - void DrawLine(const olc::vf2d& pos1, const olc::vf2d& pos2, olc::Pixel p = olc::WHITE, uint32_t pattern = 0xFFFFFFFF); - // Draws a circle located at (x,y) with radius - void DrawCircle(float x, float y, float radius, olc::Pixel p = olc::WHITE, uint8_t mask = 0xFF); - void DrawCircle(const olc::vf2d& pos, float radius, olc::Pixel p = olc::WHITE, uint8_t mask = 0xFF); - // Fills a circle located at (x,y) with radius - void FillCircle(float x, float y, float radius, olc::Pixel p = olc::WHITE); - void FillCircle(const olc::vf2d& pos, float radius, olc::Pixel p = olc::WHITE); - // Draws a rectangle at (x,y) to (x+w,y+h) - void DrawRect(float x, float y, float w, float h, olc::Pixel p = olc::WHITE); - void DrawRect(const olc::vf2d& pos, const olc::vf2d& size, olc::Pixel p = olc::WHITE); - // Fills a rectangle at (x,y) to (x+w,y+h) - void FillRect(float x, float y, float w, float h, olc::Pixel p = olc::WHITE); - void FillRect(const olc::vf2d& pos, const olc::vf2d& size, olc::Pixel p = olc::WHITE); - // Draws a triangle between points (x1,y1), (x2,y2) and (x3,y3) - void DrawTriangle(float x1, float y1, float x2, float y2, float x3, float y3, olc::Pixel p = olc::WHITE); - void DrawTriangle(const olc::vf2d& pos1, const olc::vf2d& pos2, const olc::vf2d& pos3, olc::Pixel p = olc::WHITE); - // Flat fills a triangle between points (x1,y1), (x2,y2) and (x3,y3) - void FillTriangle(float x1, float y1, float x2, float y2, float x3, float y3, olc::Pixel p = olc::WHITE); - void FillTriangle(const olc::vf2d& pos1, const olc::vf2d& pos2, const olc::vf2d& pos3, olc::Pixel p = olc::WHITE); - // Draws an entire sprite at location (x,y) - void DrawSprite(float x, float y, olc::Sprite* sprite, float scalex = 1, float scaley = 1, uint8_t flip = olc::Sprite::NONE); - void DrawSprite(const olc::vf2d& pos, olc::Sprite* sprite, const olc::vf2d& scale = { 1.0f, 1.0f }, uint8_t flip = olc::Sprite::NONE); - // Draws an area of a sprite at location (x,y), where the - // selected area is (ox,oy) to (ox+w,oy+h) - void DrawPartialSprite(float x, float y, Sprite* sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, float scalex = 1, float scaley = 1, uint8_t flip = olc::Sprite::NONE); - void DrawPartialSprite(const olc::vf2d& pos, Sprite* sprite, const olc::vi2d& sourcepos, const olc::vi2d& size, const olc::vf2d& scale = { 1.0f, 1.0f }, uint8_t flip = olc::Sprite::NONE); - void DrawString(float x, float y, const std::string& sText, Pixel col, const olc::vf2d& scale); - void DrawString(const olc::vf2d& pos, const std::string& sText, const Pixel col, const olc::vf2d& scale); - - - // Draws a whole decal, with optional scale and tinting - void DrawDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE); - // Draws a region of a decal, with optional scale and tinting - void DrawPartialDecal(const olc::vf2d& pos, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE); - void DrawPartialDecal(const olc::vf2d& pos, const olc::vf2d& size, olc::Decal* decal, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE); - // Draws fully user controlled 4 vertices, pos(pixels), uv(pixels), colours - void DrawExplicitDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d* uv, const olc::Pixel* col, uint32_t elements = 4); - //// Draws a decal with 4 arbitrary points, warping the texture to look "correct" - void DrawWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::Pixel& tint = olc::WHITE); - void DrawWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::Pixel& tint = olc::WHITE); - void DrawWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::Pixel& tint = olc::WHITE); - //// As above, but you can specify a region of a decal source sprite - void DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE); - void DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE); - void DrawPartialWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint = olc::WHITE); - //// Draws a decal rotated to specified angle, wit point of rotation offset - void DrawRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center = { 0.0f, 0.0f }, const olc::vf2d& scale = { 1.0f,1.0f }, const olc::Pixel& tint = olc::WHITE); - void DrawPartialRotatedDecal(const olc::vf2d& pos, olc::Decal* decal, const float fAngle, const olc::vf2d& center, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::vf2d& scale = { 1.0f, 1.0f }, const olc::Pixel& tint = olc::WHITE); - // Draws a multiline string as a decal, with tiniting and scaling - void DrawStringDecal(const olc::vf2d& pos, const std::string& sText, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); - void DrawStringPropDecal(const olc::vf2d& pos, const std::string& sText, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); - // Draws a single shaded filled rectangle as a decal - void FillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel col = olc::WHITE); - // Draws a corner shaded rectangle as a decal - void GradientFillRectDecal(const olc::vf2d& pos, const olc::vf2d& size, const olc::Pixel colTL, const olc::Pixel colBL, const olc::Pixel colBR, const olc::Pixel colTR); - // Draws an arbitrary convex textured polygon using GPU - void DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const olc::Pixel tint = olc::WHITE); - - }; - - class TileTransformedView : public TransformedView - { - public: - TileTransformedView() = default; - TileTransformedView(const olc::vi2d& vViewArea, const olc::vi2d& vTileSize); - - public: - void SetRangeX(const bool bRanged, const int32_t nMin = 0, const int32_t nMax = 0); - void SetRangeY(const bool bRanged, const int32_t nMin = 0, const int32_t nMax = 0); - olc::vi2d GetTopLeftTile() const; - olc::vi2d GetBottomRightTile() const; - olc::vi2d GetVisibleTiles() const; - olc::vi2d GetTileUnderScreenPos(const olc::vi2d& vPos) const; - const olc::vi2d GetTileOffset() const; - - private: - bool m_bRangedX = false; - int32_t m_nMinRangeX = 0; - int32_t m_nMaxRangeX = 0; - bool m_bRangedY = false; - int32_t m_nMinRangeY = 0; - int32_t m_nMaxRangeY = 0; - }; -} - -#ifdef OLC_PGEX_TRANSFORMEDVIEW -#undef OLC_PGEX_TRANSFORMEDVIEW - -namespace olc -{ - - void TransformedView::Initialise(const olc::vi2d& vViewArea, const olc::vf2d& vPixelScale) - { - SetViewArea(vViewArea); - SetWorldScale(vPixelScale); - m_vPixelScale = vPixelScale; - m_vRecipPixel = 1.0f / m_vPixelScale; - } - - void TransformedView::SetWorldOffset(const olc::vf2d& vOffset) - { - m_vWorldOffset = vOffset; - } - - void TransformedView::MoveWorldOffset(const olc::vf2d& vDeltaOffset) - { - m_vWorldOffset += vDeltaOffset; - } - - void TransformedView::SetWorldScale(const olc::vf2d& vScale) - { - m_vWorldScale = vScale; - } - - void TransformedView::SetViewArea(const olc::vi2d& vViewArea) - { - m_vViewArea = vViewArea; - } - - olc::vf2d TransformedView::GetWorldTL() const - { - return ScreenToWorld({ 0,0 }); - } - - olc::vf2d TransformedView::GetWorldBR() const - { - return TransformedView::ScreenToWorld(m_vViewArea); - } - - olc::vf2d TransformedView::GetWorldVisibleArea() const - { - return GetWorldBR() - GetWorldTL(); - } - - void TransformedView::ZoomAtScreenPos(const float fDeltaZoom, const olc::vi2d& vPos) - { - olc::vf2d vOffsetBeforeZoom = ScreenToWorld(vPos); - m_vWorldScale *= fDeltaZoom; - olc::vf2d vOffsetAfterZoom = ScreenToWorld(vPos); - m_vWorldOffset += vOffsetBeforeZoom - vOffsetAfterZoom; - } - - void TransformedView::SetZoom(const float fZoom, const olc::vi2d& vPos) - { - olc::vf2d vOffsetBeforeZoom = ScreenToWorld(vPos); - m_vWorldScale = { fZoom, fZoom }; - olc::vf2d vOffsetAfterZoom = ScreenToWorld(vPos); - m_vWorldOffset += vOffsetBeforeZoom - vOffsetAfterZoom; - } - - void TransformedView::StartPan(const olc::vi2d& vPos) - { - m_bPanning = true; - m_vStartPan = olc::vf2d(vPos); - } - - void TransformedView::UpdatePan(const olc::vi2d& vPos) - { - if (m_bPanning) - { - m_vWorldOffset -= (olc::vf2d(vPos) - m_vStartPan) / m_vWorldScale; - m_vStartPan = olc::vf2d(vPos); - } - } - - void TransformedView::EndPan(const olc::vi2d& vPos) - { - UpdatePan(vPos); - m_bPanning = false; - } - - const olc::vf2d& TransformedView::GetWorldOffset() const - { - return m_vWorldOffset; - } - - const olc::vf2d& TransformedView::GetWorldScale() const - { - return m_vWorldScale; - } - - olc::vi2d TransformedView::WorldToScreen(const olc::vf2d& vWorldPos) const - { - olc::vf2d vFloat = ((vWorldPos - m_vWorldOffset) * m_vWorldScale); - vFloat = { std::floor(vFloat.x), std::floor(vFloat.y) }; - return vFloat; - } - - olc::vf2d TransformedView::ScreenToWorld(const olc::vi2d& vScreenPos) const - { - return (olc::vf2d(vScreenPos) / m_vWorldScale) + m_vWorldOffset; - } - - olc::vf2d TransformedView::ScaleToWorld(const olc::vi2d& vScreenSize) const - { - return (olc::vf2d(vScreenSize) / m_vWorldScale); - } - - olc::vi2d TransformedView::ScaleToScreen(const olc::vf2d& vWorldSize) const - { - olc::vf2d vFloat = vWorldSize * m_vWorldScale; - return vFloat.floor(); - } - - bool TransformedView::IsPointVisible(const olc::vf2d & vPos) const - { - olc::vi2d vScreen = WorldToScreen(vPos); - return vScreen.x >= 0 && vScreen.x < m_vViewArea.x&& vScreen.y >= 0 && vScreen.y < m_vViewArea.y; - } - - bool TransformedView::IsRectVisible(const olc::vf2d& vPos, const olc::vf2d& vSize) const - { - olc::vi2d vScreenPos = WorldToScreen(vPos); - olc::vi2d vScreenSize = vSize * m_vWorldScale; - return (vScreenPos.x < 0 + m_vViewArea.x && vScreenPos.x + vScreenSize.x > 0 && vScreenPos.y < m_vViewArea.y&& vScreenPos.y + vScreenSize.y > 0); - } - - bool TransformedView::Draw(float x, float y, olc::Pixel p) - { - return Draw({ x, y }, p); - } - - bool TransformedView::Draw(const olc::vf2d & pos, olc::Pixel p) - { - return pge->Draw(WorldToScreen(pos), p); - } - - void TransformedView::DrawLine(float x1, float y1, float x2, float y2, olc::Pixel p, uint32_t pattern) - { - DrawLine({ x1, y2 }, { x2, y2 }, p, pattern); - } - - void TransformedView::DrawLine(const olc::vf2d & pos1, const olc::vf2d & pos2, olc::Pixel p, uint32_t pattern) - { - pge->DrawLine(WorldToScreen(pos1), WorldToScreen(pos2), p, pattern); - } - - void TransformedView::DrawCircle(float x, float y, float radius, olc::Pixel p, uint8_t mask) - { - DrawCircle({ x,y }, radius, p, mask); - } - - void TransformedView::DrawCircle(const olc::vf2d & pos, float radius, olc::Pixel p, uint8_t mask) - { - pge->DrawCircle(WorldToScreen(pos), int32_t(radius * m_vWorldScale.x), p, mask); - } - - void TransformedView::FillCircle(float x, float y, float radius, olc::Pixel p) - { - FillCircle({ x,y }, radius, p); - } - - void TransformedView::FillCircle(const olc::vf2d & pos, float radius, olc::Pixel p) - { - pge->FillCircle(WorldToScreen(pos), int32_t(radius * m_vWorldScale.x), p); - } - - void TransformedView::DrawRect(float x, float y, float w, float h, olc::Pixel p) - { - DrawRect({ x, y }, { w, h }, p); - } - - void TransformedView::DrawRect(const olc::vf2d & pos, const olc::vf2d & size, olc::Pixel p) - { - pge->DrawRect(WorldToScreen(pos), ((size * m_vWorldScale) + olc::vf2d(0.5f, 0.5f)).floor(), p); - } - - void TransformedView::FillRect(float x, float y, float w, float h, olc::Pixel p) - { - FillRect({ x, y }, { w, h }, p); - } - - void TransformedView::FillRect(const olc::vf2d & pos, const olc::vf2d & size, olc::Pixel p) - { - pge->FillRect(WorldToScreen(pos), size * m_vWorldScale, p); - } - - void TransformedView::DrawTriangle(float x1, float y1, float x2, float y2, float x3, float y3, olc::Pixel p) - { - DrawTriangle({ x1, y1 }, { x2, y2 }, { x3, y3 }, p); - } - - void TransformedView::DrawTriangle(const olc::vf2d & pos1, const olc::vf2d & pos2, const olc::vf2d & pos3, olc::Pixel p) - { - pge->DrawTriangle(WorldToScreen(pos1), WorldToScreen(pos2), WorldToScreen(pos3), p); - } - - void TransformedView::FillTriangle(float x1, float y1, float x2, float y2, float x3, float y3, olc::Pixel p) - { - FillTriangle({ x1, y1 }, { x2, y2 }, { x3, y3 }, p); - } - - void TransformedView::FillTriangle(const olc::vf2d & pos1, const olc::vf2d & pos2, const olc::vf2d & pos3, olc::Pixel p) - { - pge->FillTriangle(WorldToScreen(pos1), WorldToScreen(pos2), WorldToScreen(pos3), p); - } - - void TransformedView::DrawSprite(float x, float y, olc::Sprite* sprite, float scalex, float scaley, uint8_t flip) - { - DrawSprite({ x, y }, sprite, { scalex, scaley }, flip); - } - - void TransformedView::DrawSprite(const olc::vf2d & pos, olc::Sprite * sprite, const olc::vf2d & scale, uint8_t flip) - { - olc::vf2d vSpriteSize = olc::vf2d(float(sprite->width), float(sprite->height)); - if (IsRectVisible(pos, vSpriteSize * scale)) - { - olc::vf2d vSpriteScaledSize = vSpriteSize * m_vRecipPixel * m_vWorldScale * scale; - olc::vi2d vPixel, vStart = WorldToScreen(pos), vEnd = vSpriteScaledSize + vStart; - olc::vf2d vPixelStep = 1.0f / vSpriteScaledSize; - for (vPixel.y = vStart.y; vPixel.y < vEnd.y; vPixel.y++) - { - for (vPixel.x = vStart.x; vPixel.x < vEnd.x; vPixel.x++) - { - olc::vf2d vSample = olc::vf2d(vPixel - vStart) * vPixelStep; - pge->Draw(vPixel, sprite->Sample(vSample.x, vSample.y)); - } - } - } - } - - - void TransformedView::DrawPartialSprite(float x, float y, Sprite* sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, float scalex, float scaley, uint8_t flip) - { - DrawPartialSprite({ x,y }, sprite, { ox,oy }, { w, h }, { scalex, scaley }, flip); - } - - void TransformedView::DrawPartialSprite(const olc::vf2d& pos, Sprite* sprite, const olc::vi2d& sourcepos, const olc::vi2d& size, const olc::vf2d& scale, uint8_t flip) - { - olc::vf2d vSpriteSize = size; - if (IsRectVisible(pos, size * scale)) - { - olc::vf2d vSpriteScaledSize = olc::vf2d(size) * m_vRecipPixel * m_vWorldScale * scale; - olc::vf2d vSpritePixelStep = 1.0f / olc::vf2d(float(sprite->width), float(sprite->height)); - olc::vi2d vPixel, vStart = WorldToScreen(pos), vEnd = vSpriteScaledSize + vStart; - olc::vf2d vScreenPixelStep = 1.0f / vSpriteScaledSize; - - for (vPixel.y = vStart.y; vPixel.y < vEnd.y; vPixel.y++) - { - for (vPixel.x = vStart.x; vPixel.x < vEnd.x; vPixel.x++) - { - olc::vf2d vSample = ((olc::vf2d(vPixel - vStart) * vScreenPixelStep) * size * vSpritePixelStep) + olc::vf2d(sourcepos) * vSpritePixelStep; - pge->Draw(vPixel, sprite->Sample(vSample.x, vSample.y)); - } - } - } - } - - void TransformedView::DrawString(float x, float y, const std::string& sText, Pixel col, const olc::vf2d& scale) - { - DrawString({ x, y }, sText, col, scale); - } - - void TransformedView::DrawString(const olc::vf2d& pos, const std::string& sText, const Pixel col, const olc::vf2d& scale) - { - olc::vf2d vOffset = { 0.0f, 0.0f }; - Pixel::Mode m = pge->GetPixelMode(); - - auto StringPlot = [&col](const int x, const int y, const olc::Pixel& pSource, const olc::Pixel& pDest) - { - return pSource.r > 1 ? col : pDest; - }; - - pge->SetPixelMode(StringPlot); - - for (auto c : sText) - { - if (c == '\n') - { - vOffset.x = 0.0f; vOffset.y += 8.0f * m_vRecipPixel.y * scale.y; - } - else - { - int32_t ox = ((c - 32) % 16) * 8; - int32_t oy = ((c - 32) / 16) * 8; - DrawPartialSprite(pos + vOffset, pge->GetFontSprite(), { ox, oy }, { 8, 8 }, scale); - vOffset.x += 8.0f * m_vRecipPixel.x * scale.x; - } - } - pge->SetPixelMode(m); - } - - - void TransformedView::DrawDecal(const olc::vf2d & pos, olc::Decal * decal, const olc::vf2d & scale, const olc::Pixel & tint) - { - pge->DrawDecal(WorldToScreen(pos), decal, scale * m_vWorldScale * m_vRecipPixel, tint); - } - - void TransformedView::DrawPartialDecal(const olc::vf2d & pos, olc::Decal * decal, const olc::vf2d & source_pos, const olc::vf2d & source_size, const olc::vf2d & scale, const olc::Pixel & tint) - { - pge->DrawPartialDecal(WorldToScreen(pos), decal, source_pos, source_size, scale * m_vWorldScale * m_vRecipPixel, tint); - } - - void TransformedView::DrawPartialDecal(const olc::vf2d & pos, const olc::vf2d & size, olc::Decal * decal, const olc::vf2d & source_pos, const olc::vf2d & source_size, const olc::Pixel & tint) - { - pge->DrawPartialDecal(WorldToScreen(pos), size * m_vWorldScale * m_vRecipPixel, decal, source_pos, source_size, tint); - } - - void TransformedView::DrawExplicitDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d* uv, const olc::Pixel* col, uint32_t elements) - { - std::vector vTransformed(elements); - for (uint32_t n = 0; n < elements; n++) - vTransformed[n] = WorldToScreen(pos[n]); - pge->DrawExplicitDecal(decal, vTransformed.data(), uv, col, elements); - } - - void TransformedView::DrawWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::Pixel& tint) - { - std::array vTransformed = - { { - WorldToScreen(pos[0]), WorldToScreen(pos[1]), - WorldToScreen(pos[2]), WorldToScreen(pos[3]), - } }; - - pge->DrawWarpedDecal(decal, vTransformed, tint); - } - - void TransformedView::DrawWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::Pixel& tint) - { - DrawWarpedDecal(decal, &pos[0], tint); - } - - void TransformedView::DrawWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::Pixel& tint) - { - DrawWarpedDecal(decal, pos.data(), tint); - } - - void TransformedView::DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d(&pos)[4], const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint) - { - DrawPartialWarpedDecal(decal, &pos[0], source_pos, source_size, tint); - } - - void TransformedView::DrawPartialWarpedDecal(olc::Decal* decal, const olc::vf2d* pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint) - { - std::array vTransformed = - { { - WorldToScreen(pos[0]), WorldToScreen(pos[1]), - WorldToScreen(pos[2]), WorldToScreen(pos[3]), - } }; - - pge->DrawPartialWarpedDecal(decal, vTransformed, source_pos, source_size, tint); - } - - void TransformedView::DrawPartialWarpedDecal(olc::Decal* decal, const std::array& pos, const olc::vf2d& source_pos, const olc::vf2d& source_size, const olc::Pixel& tint) - { - DrawPartialWarpedDecal(decal, pos.data(), source_pos, source_size, tint); - } - - void TransformedView::DrawRotatedDecal(const olc::vf2d & pos, olc::Decal * decal, const float fAngle, const olc::vf2d & center, const olc::vf2d & scale, const olc::Pixel & tint) - { - pge->DrawRotatedDecal(WorldToScreen(pos), decal, fAngle, center, scale * m_vWorldScale * m_vRecipPixel, tint); - } - - void TransformedView::DrawPartialRotatedDecal(const olc::vf2d & pos, olc::Decal * decal, const float fAngle, const olc::vf2d & center, const olc::vf2d & source_pos, const olc::vf2d & source_size, const olc::vf2d & scale, const olc::Pixel & tint) - { - pge->DrawPartialRotatedDecal(WorldToScreen(pos), decal, fAngle, center, source_pos, source_size, scale * m_vWorldScale * m_vRecipPixel, tint); - } - - void TransformedView::DrawStringDecal(const olc::vf2d & pos, const std::string & sText, const olc::Pixel col, const olc::vf2d & scale) - { - pge->DrawStringDecal(WorldToScreen(pos), sText, col, scale * m_vWorldScale * m_vRecipPixel); - } - - void TransformedView::DrawStringPropDecal(const olc::vf2d & pos, const std::string & sText, const olc::Pixel col, const olc::vf2d & scale ) - { - pge->DrawStringPropDecal(WorldToScreen(pos), sText, col, scale * m_vWorldScale * m_vRecipPixel); - } - - void TransformedView::FillRectDecal(const olc::vf2d & pos, const olc::vf2d & size, const olc::Pixel col) - { - pge->FillRectDecal(WorldToScreen(pos), (size * m_vWorldScale).ceil(), col); - } - - void TransformedView::GradientFillRectDecal(const olc::vf2d & pos, const olc::vf2d & size, const olc::Pixel colTL, const olc::Pixel colBL, const olc::Pixel colBR, const olc::Pixel colTR) - { - pge->GradientFillRectDecal(WorldToScreen(pos), size * m_vWorldScale, colTL, colBL, colBR, colTR); - } - - void TransformedView::DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const olc::Pixel tint) - { - std::vector vTransformed(pos.size()); - for (uint32_t n = 0; n < pos.size(); n++) - vTransformed[n] = WorldToScreen(pos[n]); - pge->DrawPolygonDecal(decal, vTransformed, uv, tint); - } - - ///////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////// - - - TileTransformedView::TileTransformedView(const olc::vi2d& vViewArea, const olc::vi2d& vTileSize) - { - Initialise(vViewArea, vTileSize); - } - - void TileTransformedView::SetRangeX(const bool bRanged, const int32_t nMin, const int32_t nMax) - { - m_bRangedX = bRanged; - m_nMinRangeX = nMin; - m_nMaxRangeX = nMax; - } - - void TileTransformedView::SetRangeY(const bool bRanged, const int32_t nMin, const int32_t nMax) - { - m_bRangedY = bRanged; - m_nMinRangeY = nMin; - m_nMaxRangeY = nMax; - } - - olc::vi2d TileTransformedView::GetTopLeftTile() const - { - return ScreenToWorld({ 0,0 }).floor(); - } - - olc::vi2d TileTransformedView::GetBottomRightTile() const - { - return ScreenToWorld(m_vViewArea).ceil(); - } - - olc::vi2d TileTransformedView::GetVisibleTiles() const - { - return GetBottomRightTile() - GetTopLeftTile(); - } - - olc::vi2d TileTransformedView::GetTileUnderScreenPos(const olc::vi2d& vPos) const - { - return ScreenToWorld(vPos).floor(); - } - - const olc::vi2d TileTransformedView::GetTileOffset() const - { - return { int32_t((m_vWorldOffset.x - std::floor(m_vWorldOffset.x)) * m_vWorldScale.x), - int32_t((m_vWorldOffset.y - std::floor(m_vWorldOffset.y)) * m_vWorldScale.y) }; - } -} - -#endif -#endif diff --git a/Videos/OneLoneCoder_PGE_8BitsImProc.cpp b/Videos/OneLoneCoder_PGE_8BitsImProc.cpp deleted file mode 100644 index 3bd6ea7..0000000 --- a/Videos/OneLoneCoder_PGE_8BitsImProc.cpp +++ /dev/null @@ -1,504 +0,0 @@ -/* - 8-Bits Of Image Processing You Should Know - "Colin, at least you'll always get 700s now..." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Instructions: - ~~~~~~~~~~~~~ - Choose algorithm 1-8, instructions on screen - - - Relevant Video: https://youtu.be/mRM5Js3VLCk - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#include "escapi.h" - -int nFrameWidth = 320; -int nFrameHeight = 240; - -struct frame -{ - float *pixels = nullptr; - - frame() - { - pixels = new float[nFrameWidth * nFrameHeight]; - } - - ~frame() - { - delete[] pixels; - } - - - float get(int x, int y) - { - if (x >= 0 && x < nFrameWidth && y >= 0 && y < nFrameHeight) - { - return pixels[y*nFrameWidth + x]; - } - else - return 0.0f; - } - - void set(int x, int y, float p) - { - if (x >= 0 && x < nFrameWidth && y >= 0 && y < nFrameHeight) - { - pixels[y*nFrameWidth + x] = p; - } - } - - - void operator=(const frame &f) - { - memcpy(this->pixels, f.pixels, nFrameWidth * nFrameHeight * sizeof(float)); - } -}; - - - -class WIP_ImageProcessing : public olc::PixelGameEngine -{ -public: - WIP_ImageProcessing() - { - sAppName = "WIP_ImageProcessing"; - } - - union RGBint - { - int rgb; - unsigned char c[4]; - }; - - int nCameras = 0; - SimpleCapParams capture; - -public: - bool OnUserCreate() override - { - // Initialise webcam to screen dimensions - nCameras = setupESCAPI(); - if (nCameras == 0) return false; - capture.mWidth = nFrameWidth; - capture.mHeight = nFrameHeight; - capture.mTargetBuf = new int[nFrameWidth * nFrameHeight]; - if (initCapture(0, &capture) == 0) return false; - return true; - } - - void DrawFrame(frame &f, int x, int y) - { - for (int i = 0; i < nFrameWidth; i++) - for (int j = 0; j < nFrameHeight; j++) - { - int c = (int)std::min(std::max(0.0f, f.pixels[j*nFrameWidth + i] * 255.0f), 255.0f); - Draw(x + i, y + j, olc::Pixel(c, c, c)); - } - } - - enum ALGORITHM - { - THRESHOLD, MOTION, LOWPASS, CONVOLUTION, - SOBEL, MORPHO, MEDIAN, ADAPTIVE, - }; - - enum MORPHOP - { - DILATION, - EROSION, - EDGE - }; - - frame input, output, prev_input, activity, threshold; - - // Algorithm Currently Running - ALGORITHM algo = THRESHOLD; - MORPHOP morph = DILATION; - int nMorphCount = 1; - - float fThresholdValue = 0.5f; - float fLowPassRC = 0.1f; - float fAdaptiveBias = 1.1f; - - float *pConvoKernel = kernel_blur; - - float kernel_blur[9] = - { - 0.0f, 0.125, 0.0f, - 0.125f, 0.5f, 0.125f, - 0.0f, 0.125f, 0.0f, - }; - - float kernel_sharpen[9] = - { - 0.0f, -1.0f, 0.0f, - -1.0f, 5.0f, -1.0f, - 0.0f, -1.0f, 0.0f, - }; - - float kernel_sobel_v[9] = - { - -1.0f, 0.0f, +1.0f, - -2.0f, 0.0f, +2.0f, - -1.0f, 0.0f, +1.0f, - }; - - float kernel_sobel_h[9] = - { - -1.0f, -2.0f, -1.0f, - 0.0f, 0.0f, 0.0f, - +1.0f, +2.0f, +1.0f, - }; - - bool OnUserUpdate(float fElapsedTime) override - { - // CAPTURING WEBCAM IMAGE - prev_input = input; - doCapture(0); while (isCaptureDone(0) == 0) {} - for (int y = 0; y < capture.mHeight; y++) - for (int x = 0; x < capture.mWidth; x++) - { - RGBint col; - int id = y * capture.mWidth + x; - col.rgb = capture.mTargetBuf[id]; - input.pixels[y*nFrameWidth + x] = (float)col.c[1] / 255.0f; - } - - if (GetKey(olc::Key::K1).bReleased) algo = THRESHOLD; - if (GetKey(olc::Key::K2).bReleased) algo = MOTION; - if (GetKey(olc::Key::K3).bReleased) algo = LOWPASS; - if (GetKey(olc::Key::K4).bReleased) algo = CONVOLUTION; - if (GetKey(olc::Key::K5).bReleased) algo = SOBEL; - if (GetKey(olc::Key::K6).bReleased) algo = MORPHO; - if (GetKey(olc::Key::K7).bReleased) algo = MEDIAN; - if (GetKey(olc::Key::K8).bReleased) algo = ADAPTIVE; - - - switch (algo) - { - case THRESHOLD: - - // Respond to user input - if (GetKey(olc::Key::Z).bHeld) fThresholdValue -= 0.1f * fElapsedTime; - if (GetKey(olc::Key::X).bHeld) fThresholdValue += 0.1f * fElapsedTime; - if (fThresholdValue > 1.0f) fThresholdValue = 1.0f; - if (fThresholdValue < 0.0f) fThresholdValue = 0.0f; - - // Perform threshold per pixel - for (int i = 0; i < nFrameWidth; i++) - for (int j = 0; j < nFrameHeight; j++) - output.set(i, j, input.get(i, j) >= fThresholdValue ? 1.0f : 0.0f); - break; - - case MOTION: - - // Returns the absolute difference between successive frames per pixel - for (int i = 0; i < nFrameWidth; i++) - for (int j = 0; j < nFrameHeight; j++) - output.set(i, j, fabs(input.get(i, j) - prev_input.get(i, j))); - break; - - - case LOWPASS: - - // Respond to user input - if (GetKey(olc::Key::Z).bHeld) fLowPassRC -= 0.1f * fElapsedTime; - if (GetKey(olc::Key::X).bHeld) fLowPassRC += 0.1f * fElapsedTime; - if (fLowPassRC > 1.0f) fLowPassRC = 1.0f; - if (fLowPassRC < 0.0f) fLowPassRC = 0.0f; - - // Pass each pixel through a temporal RC filter - for (int i = 0; i < nFrameWidth; i++) - for (int j = 0; j < nFrameHeight; j++) - { - float dPixel = input.get(i, j) - output.get(i, j); - dPixel *= fLowPassRC; - output.set(i, j, dPixel + output.get(i, j)); - } - break; - - case CONVOLUTION: - // Respond to user input - if (GetKey(olc::Key::Z).bHeld) pConvoKernel = kernel_blur; - if (GetKey(olc::Key::X).bHeld) pConvoKernel = kernel_sharpen; - - for (int i = 0; i < nFrameWidth; i++) - for (int j = 0; j < nFrameHeight; j++) - { - float fSum = 0.0f; - for (int n = -1; n < +2; n++) - for (int m = -1; m < +2; m++) - fSum += input.get(i + n, j + m) * pConvoKernel[(m + 1) * 3 + (n + 1)]; - - output.set(i, j, fSum); - } - break; - - case SOBEL: - for (int i = 0; i < nFrameWidth; i++) - for (int j = 0; j < nFrameHeight; j++) - { - float fKernelSumH = 0.0f; - float fKernelSumV = 0.0f; - - for (int n = -1; n < +2; n++) - for (int m = -1; m < +2; m++) - { - fKernelSumH += input.get(i + n, j + m) * kernel_sobel_h[(m + 1) * 3 + (n + 1)]; - fKernelSumV += input.get(i + n, j + m) * kernel_sobel_v[(m + 1) * 3 + (n + 1)]; - } - - output.set(i, j, fabs((fKernelSumH + fKernelSumV) / 2.0f)); - } - break; - - case MORPHO: - - // Respond to user input - if (GetKey(olc::Key::Z).bHeld) morph = DILATION; - if (GetKey(olc::Key::X).bHeld) morph = EROSION; - if (GetKey(olc::Key::C).bHeld) morph = EDGE; - - if (GetKey(olc::Key::A).bReleased) nMorphCount--; - if (GetKey(olc::Key::S).bReleased) nMorphCount++; - if (nMorphCount > 10.0f) nMorphCount = 10.0f; - if (nMorphCount < 1.0f) nMorphCount = 1.0f; - - // Threshold First to binarise image - for (int i = 0; i < nFrameWidth; i++) - for (int j = 0; j < nFrameHeight; j++) - { - activity.set(i, j, input.get(i, j) > fThresholdValue ? 1.0f : 0.0f); - } - - threshold = activity; - - switch (morph) - { - case DILATION: - for (int n = 0; n < nMorphCount; n++) - { - output = activity; - - for (int i = 0; i < nFrameWidth; i++) - for (int j = 0; j < nFrameHeight; j++) - { - if (activity.get(i, j) == 1.0f) - { - output.set(i, j, 1.0f); - output.set(i - 1, j, 1.0f); - output.set(i + 1, j, 1.0f); - output.set(i, j - 1, 1.0f); - output.set(i, j + 1, 1.0f); - output.set(i - 1, j - 1, 1.0f); - output.set(i + 1, j + 1, 1.0f); - output.set(i + 1, j - 1, 1.0f); - output.set(i - 1, j + 1, 1.0f); - } - } - - activity = output; - } - break; - - case EROSION: - for (int n = 0; n < nMorphCount; n++) - { - output = activity; - for (int i = 0; i < nFrameWidth; i++) - for (int j = 0; j < nFrameHeight; j++) - { - - float sum = activity.get(i - 1, j) + activity.get(i + 1, j) + activity.get(i, j - 1) + activity.get(i, j + 1) + - activity.get(i - 1, j - 1) + activity.get(i + 1, j + 1) + activity.get(i + 1, j - 1) + activity.get(i - 1, j + 1); - - if (activity.get(i, j) == 1.0f && sum < 8.0f) - { - output.set(i, j, 0.0f); - } - } - activity = output; - } - break; - - case EDGE: - output = activity; - for (int i = 0; i < nFrameWidth; i++) - for (int j = 0; j < nFrameHeight; j++) - { - - float sum = activity.get(i - 1, j) + activity.get(i + 1, j) + activity.get(i, j - 1) + activity.get(i, j + 1) + - activity.get(i - 1, j - 1) + activity.get(i + 1, j + 1) + activity.get(i + 1, j - 1) + activity.get(i - 1, j + 1); - - if (activity.get(i, j) == 1.0f && sum == 8.0f) - { - output.set(i, j, 0.0f); - } - } - break; - - } - break; - - case MEDIAN: - for (int i = 0; i < nFrameWidth; i++) - for (int j = 0; j < nFrameHeight; j++) - { - std::vector v; - - for (int n = -2; n < +3; n++) - for (int m = -2; m < +3; m++) - v.push_back(input.get(i + n, j + m)); - - std::sort(v.begin(), v.end(), std::greater()); - output.set(i, j, v[12]); - } - break; - - case ADAPTIVE: - // Respond to user input - if (GetKey(olc::Key::Z).bHeld) fAdaptiveBias -= 0.1f * fElapsedTime; - if (GetKey(olc::Key::X).bHeld) fAdaptiveBias += 0.1f * fElapsedTime; - if (fAdaptiveBias > 1.5f) fAdaptiveBias = 1.5f; - if (fAdaptiveBias < 0.5f) fAdaptiveBias = 0.5f; - - - for (int i = 0; i < nFrameWidth; i++) - for (int j = 0; j < nFrameHeight; j++) - { - float fRegionSum = 0.0f; - - for (int n = -2; n < +3; n++) - for (int m = -2; m < +3; m++) - fRegionSum += input.get(i + n, j + m); - - fRegionSum /= 25.0f; - output.set(i, j, input.get(i, j) > (fRegionSum * fAdaptiveBias) ? 1.0f : 0.0f); - } - break; - } - - // DRAW STUFF ONLY HERE - Clear(olc::DARK_BLUE); - DrawFrame(algo == MORPHO ? threshold : input, 10, 10); - DrawFrame(output, 340, 10); - - DrawString(150, 255, "INPUT"); - DrawString(480, 255, "OUTPUT"); - - DrawString(10, 275, "1) Threshold"); - DrawString(10, 285, "2) Absolute Motion"); - DrawString(10, 295, "3) Low-Pass Temporal Filtering"); - DrawString(10, 305, "4) Convolution (Blurring/Sharpening)"); - DrawString(10, 315, "5) Sobel Edge Detection"); - DrawString(10, 325, "6) Binary Morphological Operations (Erosion/Dilation)"); - DrawString(10, 335, "7) Median Filter"); - DrawString(10, 345, "8) Adaptive Threshold"); - - - switch (algo) - { - case THRESHOLD: - DrawString(10, 375, "Change threshold value with Z and X keys"); - DrawString(10, 385, "Current value = " + std::to_string(fThresholdValue)); - break; - - case LOWPASS: - DrawString(10, 375, "Change RC constant value with Z and X keys"); - DrawString(10, 385, "Current value = " + std::to_string(fLowPassRC)); - break; - - case CONVOLUTION: - DrawString(10, 375, "Change convolution kernel with Z and X keys"); - DrawString(10, 385, "Current kernel = " + std::string((pConvoKernel == kernel_blur) ? "Blur" : "Sharpen")); - break; - - case MORPHO: - DrawString(10, 375, "Change operation with Z and X and C keys"); - if (morph == DILATION) DrawString(10, 385, "Current operation = DILATION"); - if (morph == EROSION) DrawString(10, 385, "Current operation = EROSION"); - if (morph == EDGE) DrawString(10, 385, "Current operation = EDGE"); - DrawString(10, 395, "Change Iterations with A and S keys"); - DrawString(10, 405, "Current iteration count = " + std::to_string(nMorphCount)); - - - break; - - case ADAPTIVE: - DrawString(10, 375, "Change adaptive threshold bias with Z and X keys"); - DrawString(10, 385, "Current value = " + std::to_string(fAdaptiveBias)); - break; - - default: - break; - } - - if (GetKey(olc::Key::ESCAPE).bPressed) return false; - return true; - } -}; - - -int main() -{ - WIP_ImageProcessing demo; - if (demo.Construct(670, 460, 2, 2)) - demo.Start(); - - return 0; -} - - diff --git a/Videos/OneLoneCoder_PGE_Balls2.cpp b/Videos/OneLoneCoder_PGE_Balls2.cpp deleted file mode 100644 index c1e3d6f..0000000 --- a/Videos/OneLoneCoder_PGE_Balls2.cpp +++ /dev/null @@ -1,500 +0,0 @@ -/* -OneLoneCoder.com - Programming Balls! #2 Circle Vs Edge Collisions -"...totally overkill for pong..." - @Javidx9 - - -Background -~~~~~~~~~~ -Collision detection engines can get quite complicated. This program shows the interactions -between circular objects of different sizes and masses. Use Left mouse button to select -and drag a ball to examin static collisions, and use Right mouse button to apply velocity -to the balls as if using a pool/snooker/billiards cue. - -License (OLC-3) -~~~~~~~~~~~~~~~ - -Copyright 2018 OneLoneCoder.com - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions or derivations of source code must retain the above -copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions or derivative works in binary form must reproduce -the above copyright notice. This list of conditions and the following -disclaimer must be reproduced in the documentation and/or other -materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived -from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Links -~~~~~ -YouTube: https://www.youtube.com/javidx9 -Discord: https://discord.gg/WhwHUMV -Twitter: https://www.twitter.com/javidx9 -Twitch: https://www.twitch.tv/javidx9 -GitHub: https://www.github.com/onelonecoder -Homepage: https://www.onelonecoder.com - -Relevant Videos -~~~~~~~~~~~~~~~ -Part #1 https://youtu.be/LPzyNOHY3A4 -Part #2 https://youtu.be/ebq7L2Wtbl4 - -Author -~~~~~~ -David Barr, aka javidx9, ŠOneLoneCoder 2018 -*/ - - -#include -#include -#include -using namespace std; - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -struct sBall -{ - float px, py; - float vx, vy; - float ax, ay; - float ox, oy; - float radius; - float mass; - float friction; - int score; - int id; - float fSimTimeRemaining; - olc::Pixel col; -}; - -struct sLineSegment -{ - float sx, sy; - float ex, ey; - float radius; -}; - - - -class CirclePhysics : public olc::PixelGameEngine -{ -public: - CirclePhysics() - { - sAppName = "Circles V Edges"; - } - -private: - vector vecBalls; - vector vecLines; - vector> modelCircle; - sBall* pSelectedBall = nullptr; - olc::Sprite *spriteBalls = nullptr; - sLineSegment* pSelectedLine = nullptr; - bool bSelectedLineStart = false; - - void AddBall(float x, float y, float r = 5.0f, int s = 0) - { - sBall b; - b.px = x; b.py = y; - b.vx = 0; b.vy = 0; - b.ax = 0; b.ay = 0; - b.ox = 0; b.oy = 0; - b.radius = r; - b.mass = r * 10.0f; - b.friction = 0.0f; - b.score = s; - b.fSimTimeRemaining = 0.0f; - b.id = vecBalls.size(); - b.col = olc::Pixel(rand() % 200 + 55, rand() % 200 + 55, rand() % 200 + 55); - vecBalls.emplace_back(b); - } - - olc::Sprite spr; - -public: - bool OnUserCreate() - { - - float fBallRadius = 4.0f; - for (int i = 0; i <100; i++) - AddBall(((float)rand()/(float)RAND_MAX) * ScreenWidth(), ((float)rand() / (float)RAND_MAX) * ScreenHeight(), fBallRadius); - - AddBall(28.0f, 33.0, fBallRadius * 3); - AddBall(28.0f, 35.0, fBallRadius * 2); - - float fLineRadius = 4.0f; - vecLines.push_back({ 12.0f, 4.0f, 64.0f, 4.0f, fLineRadius }); - vecLines.push_back({ 76.0f, 4.0f, 132.0f, 4.0f, fLineRadius }); - vecLines.push_back({ 12.0f, 68.0f, 64.0f, 68.0f, fLineRadius }); - vecLines.push_back({ 76.0f, 68.0f, 132.0f, 68.0f, fLineRadius }); - vecLines.push_back({ 4.0f, 12.0f, 4.0f, 60.0f, fLineRadius }); - vecLines.push_back({ 140.0f, 12.0f, 140.0f, 60.0f, fLineRadius }); - return true; - } - - bool OnUserUpdate(float fElapsedTime) - { - - auto DoCirclesOverlap = [](float x1, float y1, float r1, float x2, float y2, float r2) - { - return fabs((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)) <= ((r1 + r2) * (r1 + r2)); - }; - - auto IsPointInCircle = [](float x1, float y1, float r1, float px, float py) - { - return fabs((x1 - px)*(x1 - px) + (y1 - py)*(y1 - py)) < (r1 * r1); - }; - - if (GetMouse(0).bPressed) - { - // Check for selected ball - pSelectedBall = nullptr; - for (auto &ball : vecBalls) - { - if (IsPointInCircle(ball.px, ball.py, ball.radius, GetMouseX(), GetMouseY())) - { - pSelectedBall = &ball; - break; - } - } - - // Check for selected line segment end - pSelectedLine = nullptr; - for (auto &line : vecLines) - { - if (IsPointInCircle(line.sx, line.sy, line.radius, GetMouseX(), GetMouseY())) - { - pSelectedLine = &line; - bSelectedLineStart = true; - break; - } - - if (IsPointInCircle(line.ex, line.ey, line.radius, GetMouseX(), GetMouseY())) - { - pSelectedLine = &line; - bSelectedLineStart = false; - break; - } - } - } - - if (GetMouse(0).bHeld) - { - if (pSelectedLine != nullptr) - { - if (bSelectedLineStart) - { - pSelectedLine->sx = GetMouseX(); - pSelectedLine->sy = GetMouseY(); - } - else - { - pSelectedLine->ex = GetMouseX(); - pSelectedLine->ey = GetMouseY(); - } - } - } - - if (GetMouse(0).bReleased) - { - if (pSelectedBall != nullptr) - { - // Apply velocity - pSelectedBall->vx = 5.0f * ((pSelectedBall->px) - GetMouseX()); - pSelectedBall->vy = 5.0f * ((pSelectedBall->py) - GetMouseY()); - } - - pSelectedBall = nullptr; - pSelectedLine = nullptr; - } - - if (GetMouse(1).bHeld) - { - for (auto &ball : vecBalls) - { - ball.vx += (GetMouseX() - ball.px) * 0.01f; - ball.vy += (GetMouseY() - ball.py) * 0.01f; - } - } - - - - vector> vecCollidingPairs; - vector vecFakeBalls; - - // Threshold indicating stability of object - float fStable = 0.005f; - - // Multiple simulation updates with small time steps permit more accurate physics - // and realistic results at the expense of CPU time of course - int nSimulationUpdates = 4; - - // Multiple collision trees require more steps to resolve. Normally we would - // continue simulation until the object has no simulation time left for this - // epoch, however this is risky as the system may never find stability, so we - // can clamp it here - int nMaxSimulationSteps = 15; - - // Break up the frame elapsed time into smaller deltas for each simulation update - float fSimElapsedTime = fElapsedTime / (float)nSimulationUpdates; - - // Main simulation loop - for (int i = 0; i < nSimulationUpdates; i++) - { - // Set all balls time to maximum for this epoch - for (auto &ball : vecBalls) - ball.fSimTimeRemaining = fSimElapsedTime; - - // Erode simulation time on a per objec tbasis, depending upon what happens - // to it during its journey through this epoch - for (int j = 0; j < nMaxSimulationSteps; j++) - { - // Update Ball Positions - for (auto &ball : vecBalls) - { - if (ball.fSimTimeRemaining > 0.0f) - { - ball.ox = ball.px; // Store original position this epoch - ball.oy = ball.py; - - ball.ax = -ball.vx * 0.8f; // Apply drag and gravity - ball.ay = -ball.vy * 0.8f + 100.0f; - - ball.vx += ball.ax * ball.fSimTimeRemaining; // Update Velocity - ball.vy += ball.ay * ball.fSimTimeRemaining; - - ball.px += ball.vx * ball.fSimTimeRemaining; // Update position - ball.py += ball.vy * ball.fSimTimeRemaining; - - // Crudely wrap balls to screen - note this cause issues when collisions occur on screen boundaries - if (ball.px < 0) ball.px += (float)ScreenWidth(); - if (ball.px >= ScreenWidth()) ball.px -= (float)ScreenWidth(); - if (ball.py < 0) ball.py += (float)ScreenHeight(); - if (ball.py >= ScreenHeight()) ball.py -= (float)ScreenHeight(); - - // Stop ball when velocity is neglible - if (fabs(ball.vx*ball.vx + ball.vy*ball.vy) < fStable) - { - ball.vx = 0; - ball.vy = 0; - } - } - } - - - // Work out static collisions with walls and displace balls so no overlaps - for (auto &ball : vecBalls) - { - float fDeltaTime = ball.fSimTimeRemaining; - - // Against Edges - for (auto &edge : vecLines) - { - // Check that line formed by velocity vector, intersects with line segment - float fLineX1 = edge.ex - edge.sx; - float fLineY1 = edge.ey - edge.sy; - - float fLineX2 = ball.px - edge.sx; - float fLineY2 = ball.py - edge.sy; - - float fEdgeLength = fLineX1 * fLineX1 + fLineY1 * fLineY1; - - // This is nifty - It uses the DP of the line segment vs the line to the object, to work out - // how much of the segment is in the "shadow" of the object vector. The min and max clamp - // this to lie between 0 and the line segment length, which is then normalised. We can - // use this to calculate the closest point on the line segment - float t = std::max(0.0f, std::min(fEdgeLength, (fLineX1 * fLineX2 + fLineY1 * fLineY2))) / fEdgeLength; - - // Which we do here - float fClosestPointX = edge.sx + t * fLineX1; - float fClosestPointY = edge.sy + t * fLineY1; - - // And once we know the closest point, we can check if the ball has collided with the segment in the - // same way we check if two balls have collided - float fDistance = sqrtf((ball.px - fClosestPointX)*(ball.px - fClosestPointX) + (ball.py - fClosestPointY)*(ball.py - fClosestPointY)); - - if (fDistance <= (ball.radius + edge.radius)) - { - // Collision has occurred - treat collision point as a ball that cannot move. To make this - // compatible with the dynamic resolution code below, we add a fake ball with an infinite mass - // so it behaves like a solid object when the momentum calculations are performed - sBall *fakeball = new sBall(); - fakeball->radius = edge.radius; - fakeball->mass = ball.mass * 0.8f; - fakeball->px = fClosestPointX; - fakeball->py = fClosestPointY; - fakeball->vx = -ball.vx; // We will use these later to allow the lines to impart energy into ball - fakeball->vy = -ball.vy; // if the lines are moving, i.e. like pinball flippers - - // Store Fake Ball - vecFakeBalls.push_back(fakeball); - - // Add collision to vector of collisions for dynamic resolution - vecCollidingPairs.push_back({ &ball, fakeball }); - - // Calculate displacement required - float fOverlap = 1.0f * (fDistance - ball.radius - fakeball->radius); - - // Displace Current Ball away from collision - ball.px -= fOverlap * (ball.px - fakeball->px) / fDistance; - ball.py -= fOverlap * (ball.py - fakeball->py) / fDistance; - } - } - - // Against other balls - for (auto &target : vecBalls) - { - if (ball.id != target.id) // Do not check against self - { - if (DoCirclesOverlap(ball.px, ball.py, ball.radius, target.px, target.py, target.radius)) - { - // Collision has occured - vecCollidingPairs.push_back({ &ball, &target }); - - // Distance between ball centers - float fDistance = sqrtf((ball.px - target.px)*(ball.px - target.px) + (ball.py - target.py)*(ball.py - target.py)); - - // Calculate displacement required - float fOverlap = 0.5f * (fDistance - ball.radius - target.radius); - - // Displace Current Ball away from collision - ball.px -= fOverlap * (ball.px - target.px) / fDistance; - ball.py -= fOverlap * (ball.py - target.py) / fDistance; - - // Displace Target Ball away from collision - Note, this should affect the timing of the target ball - // and it does, but this is absorbed by the target ball calculating its own time delta later on - target.px += fOverlap * (ball.px - target.px) / fDistance; - target.py += fOverlap * (ball.py - target.py) / fDistance; - } - } - } - - // Time displacement - we knew the velocity of the ball, so we can estimate the distance it should have covered - // however due to collisions it could not do the full distance, so we look at the actual distance to the collision - // point and calculate how much time that journey would have taken using the speed of the object. Therefore - // we can now work out how much time remains in that timestep. - float fIntendedSpeed = sqrtf(ball.vx * ball.vx + ball.vy * ball.vy); - float fIntendedDistance = fIntendedSpeed * ball.fSimTimeRemaining; - float fActualDistance = sqrtf((ball.px - ball.ox)*(ball.px - ball.ox) + (ball.py - ball.oy)*(ball.py - ball.oy)); - float fActualTime = fActualDistance / fIntendedSpeed; - - // After static resolution, there may be some time still left for this epoch, so allow simulation to continue - ball.fSimTimeRemaining = ball.fSimTimeRemaining - fActualTime; - } - - // Now work out dynamic collisions - float fEfficiency = 1.00f; - for (auto c : vecCollidingPairs) - { - sBall *b1 = c.first, *b2 = c.second; - - // Distance between balls - float fDistance = sqrtf((b1->px - b2->px)*(b1->px - b2->px) + (b1->py - b2->py)*(b1->py - b2->py)); - - // Normal - float nx = (b2->px - b1->px) / fDistance; - float ny = (b2->py - b1->py) / fDistance; - - // Tangent - float tx = -ny; - float ty = nx; - - // Dot Product Tangent - float dpTan1 = b1->vx * tx + b1->vy * ty; - float dpTan2 = b2->vx * tx + b2->vy * ty; - - // Dot Product Normal - float dpNorm1 = b1->vx * nx + b1->vy * ny; - float dpNorm2 = b2->vx * nx + b2->vy * ny; - - // Conservation of momentum in 1D - float m1 = fEfficiency * (dpNorm1 * (b1->mass - b2->mass) + 2.0f * b2->mass * dpNorm2) / (b1->mass + b2->mass); - float m2 = fEfficiency * (dpNorm2 * (b2->mass - b1->mass) + 2.0f * b1->mass * dpNorm1) / (b1->mass + b2->mass); - - // Update ball velocities - b1->vx = tx * dpTan1 + nx * m1; - b1->vy = ty * dpTan1 + ny * m1; - b2->vx = tx * dpTan2 + nx * m2; - b2->vy = ty * dpTan2 + ny * m2; - } - - // Remove collisions - vecCollidingPairs.clear(); - - // Remove fake balls - for (auto &b : vecFakeBalls) delete b; - vecFakeBalls.clear(); - } - } - - // Clear Screen - FillRect(0, 0, ScreenWidth(), ScreenHeight(), olc::Pixel(0, 0, 0)); - - // Draw Lines - for (auto line : vecLines) - { - FillCircle(line.sx, line.sy, line.radius, olc::Pixel(255,255,255)); - FillCircle(line.ex, line.ey, line.radius, olc::Pixel(128, 128, 128)); - - float nx = -(line.ey - line.sy); - float ny = (line.ex - line.sx); - float d = sqrt(nx*nx + ny * ny); - nx /= d; - ny /= d; - - DrawLine((line.sx + nx * line.radius), (line.sy + ny * line.radius), (line.ex + nx * line.radius), (line.ey + ny * line.radius), olc::Pixel(255, 255, 255)); - DrawLine((line.sx - nx * line.radius), (line.sy - ny * line.radius), (line.ex - nx * line.radius), (line.ey - ny * line.radius), olc::Pixel(255, 255, 255)); - } - - // Draw Balls - for (auto ball : vecBalls) - { - FillCircle(ball.px, ball.py, ball.radius, ball.col); - - } - - // Draw Cue - if (pSelectedBall != nullptr) - DrawLine(pSelectedBall->px, pSelectedBall->py, GetMouseX(), GetMouseY(), olc::Pixel(0, 0, 255)); - - - - - return true; - } - -}; - - -int main() -{ - - CirclePhysics game; - if (game.Construct(320, 240, 4, 4)) - game.Start(); - else - wcout << L"Could not construct console" << endl; - - return 0; -}; - diff --git a/Videos/OneLoneCoder_PGE_CircleVsRect.cpp b/Videos/OneLoneCoder_PGE_CircleVsRect.cpp deleted file mode 100644 index ee5d923..0000000 --- a/Videos/OneLoneCoder_PGE_CircleVsRect.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - Easy Circle Vs Rectangle Collision Resolution - "Everything's just damp, the walls, the roof, everything!" - javidx9 - - Video: https://youtu.be/D2a5fHX-Qrs - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2021 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#define OLC_PGEX_TRANSFORMEDVIEW -#include "olcPGEX_TransformedView.h" - - -class CircleVsRect : public olc::PixelGameEngine -{ -public: - CircleVsRect() - { - sAppName = "Circle Vs Rectangle"; - } - -private: - olc::TileTransformedView tv; - - struct sWorldObject - { - olc::vf2d vPos; - olc::vf2d vVel; - float fRadius = 0.5f; - }; - - sWorldObject object; - - std::string sWorldMap = - "################################" - "#..............................#" - "#.......#####.#.....#####......#" - "#.......#...#.#.....#..........#" - "#.......#...#.#.....#..........#" - "#.......#####.#####.#####......#" - "#..............................#" - "#.....#####.#####.#####..##....#" - "#.........#.#...#.....#.#.#....#" - "#.....#####.#...#.#####...#....#" - "#.....#.....#...#.#.......#....#" - "#.....#####.#####.#####.#####..#" - "#..............................#" - "#..............................#" - "#..#.#..........#....#.........#" - "#..#.#..........#....#.........#" - "#..#.#.......#####.#######.....#" - "#..#.#..........#....#.........#" - "#..#.#.............###.#.#.....#" - "#..#.##########................#" - "#..#..........#....#.#.#.#.....#" - "#..#.####.###.#................#" - "#..#.#......#.#................#" - "#..#.#.####.#.#....###..###....#" - "#..#.#......#.#....#......#....#" - "#..#.########.#....#......#....#" - "#..#..........#....#......#....#" - "#..############....#......#....#" - "#..................########....#" - "#..............................#" - "#..............................#" - "################################"; - - olc::vi2d vWorldSize = { 32, 32 }; - - bool bFollowObject = false; - -public: - bool OnUserCreate() override - { - // Create "Tiled World", where each tile is 32x32 screen pixels. Coordinates - // for drawing will exist in unit-tile space from now on... - tv = olc::TileTransformedView({ ScreenWidth(), ScreenHeight() }, { 32, 32 }); - object.vPos = { 3.0f, 3.0f }; - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - // Control of Player Object - object.vVel = { 0.0f, 0.0f }; - if (GetKey(olc::Key::W).bHeld) object.vVel += { 0.0f, -1.0f }; - if (GetKey(olc::Key::S).bHeld) object.vVel += { 0.0f, +1.0f }; - if (GetKey(olc::Key::A).bHeld) object.vVel += { -1.0f, 0.0f }; - if (GetKey(olc::Key::D).bHeld) object.vVel += { +1.0f, 0.0f }; - - if (object.vVel.mag2() > 0) - object.vVel = object.vVel.norm() * (GetKey(olc::Key::SHIFT).bHeld ? 5.0f : 2.0f); - - if (GetKey(olc::Key::SPACE).bReleased) bFollowObject = !bFollowObject; - - - // Where will object be worst case? - olc::vf2d vPotentialPosition = object.vPos + object.vVel * fElapsedTime; - - // Extract region of world cells that could have collision this frame - olc::vi2d vCurrentCell = object.vPos.floor(); - olc::vi2d vTargetCell = vPotentialPosition; - olc::vi2d vAreaTL = (vCurrentCell.min(vTargetCell) - olc::vi2d(1, 1)).max({ 0,0 }); - olc::vi2d vAreaBR = (vCurrentCell.max(vTargetCell) + olc::vi2d(1, 1)).min(vWorldSize); - - olc::vf2d vRayToNearest; - - // Iterate through each cell in test area - olc::vi2d vCell; - for (vCell.y = vAreaTL.y; vCell.y <= vAreaBR.y; vCell.y++) - { - for (vCell.x = vAreaTL.x; vCell.x <= vAreaBR.x; vCell.x++) - { - // Check if the cell is actually solid... - if (sWorldMap[vCell.y * vWorldSize.x + vCell.x] == '#') - { - // ...it is! So work out nearest point to future player position, around perimeter - // of cell rectangle. We can test the distance to this point to see if we have - // collided. - - olc::vf2d vNearestPoint; - vNearestPoint.x = std::max(float(vCell.x), std::min(vPotentialPosition.x, float(vCell.x + 1))); - vNearestPoint.y = std::max(float(vCell.y), std::min(vPotentialPosition.y, float(vCell.y + 1))); - - olc::vf2d vRayToNearest = vNearestPoint - vPotentialPosition; - float fOverlap = object.fRadius - vRayToNearest.mag(); - if (std::isnan(fOverlap)) fOverlap = 0; - - // If overlap is positive, then a collision has occurred, so we displace backwards by the - // overlap amount. The potential position is then tested against other tiles in the area - // therefore "statically" resolving the collision - if (fOverlap > 0) - { - // Statically resolve the collision - vPotentialPosition = vPotentialPosition - vRayToNearest.norm() * fOverlap; - } - } - } - } - - // Set the objects new position to the allowed potential position - object.vPos = vPotentialPosition; - - - // Clear World - Clear(olc::VERY_DARK_BLUE); - - if (bFollowObject) - { - tv.SetWorldOffset(object.vPos - tv.ScaleToWorld(olc::vf2d(ScreenWidth()/2.0f, ScreenHeight()/2.0f))); - DrawString({ 10,10 }, "Following Object"); - } - - // Handle Pan & Zoom - if (GetMouse(2).bPressed) tv.StartPan(GetMousePos()); - if (GetMouse(2).bHeld) tv.UpdatePan(GetMousePos()); - if (GetMouse(2).bReleased) tv.EndPan(GetMousePos()); - if (GetMouseWheel() > 0) tv.ZoomAtScreenPos(2.0f, GetMousePos()); - if (GetMouseWheel() < 0) tv.ZoomAtScreenPos(0.5f, GetMousePos()); - - // Draw World - olc::vi2d vTL = tv.GetTopLeftTile().max({ 0,0 }); - olc::vi2d vBR = tv.GetBottomRightTile().min(vWorldSize); - olc::vi2d vTile; - for (vTile.y = vTL.y; vTile.y < vBR.y; vTile.y++) - for (vTile.x = vTL.x; vTile.x < vBR.x; vTile.x++) - { - if (sWorldMap[vTile.y * vWorldSize.x + vTile.x] == '#') - { - tv.DrawRect(vTile, { 1.0f, 1.0f }, olc::WHITE); - tv.DrawLine(vTile, vTile + olc::vf2d(1.0f, 1.0f), olc::WHITE); - tv.DrawLine(vTile + olc::vf2d(0.0f, 1.0f), vTile + olc::vf2d(1.0f, 0.0f), olc::WHITE); - } - } - - tv.FillRectDecal(vAreaTL, vAreaBR - vAreaTL + olc::vi2d(1,1), olc::Pixel(0,255,255,32)); - - // Draw Boundary - tv.DrawCircle(object.vPos, object.fRadius, olc::WHITE); - - // Draw Velocity - if (object.vVel.mag2() > 0) - { - tv.DrawLine(object.vPos, object.vPos + object.vVel.norm() * object.fRadius, olc::MAGENTA); - } - - return true; - } -}; - -int main() -{ - CircleVsRect demo; - if (demo.Construct(640, 480, 2, 2)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_Dithering.cpp b/Videos/OneLoneCoder_PGE_Dithering.cpp deleted file mode 100644 index ae1f688..0000000 --- a/Videos/OneLoneCoder_PGE_Dithering.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - Blithering About Dithering (Floyd-Steinberg) - "2022 lets go!" - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - Copyright 2018 - 2021 OneLoneCoder.com - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Video: - ~~~~~~ - https://youtu.be/lseR6ZguBNY - - Use Q and W keys to view quantised image and dithered image respectively - Use Left mouse button to pan, and mouse wheel to zoom to cursor - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021, 2022 -*/ - - -// Using olc::PixelGameEngine for input and visualisation -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -// Using a transformed view to handle pan and zoom -#define OLC_PGEX_TRANSFORMEDVIEW -#include "olcPGEX_TransformedView.h" - -//#include - -// Override base class with your custom functionality -class Dithering : public olc::PixelGameEngine -{ -public: - Dithering() - { - sAppName = "Floyd Steinberg Dithering"; - } - - olc::TransformedView tv; - std::unique_ptr m_pImage; - std::unique_ptr m_pQuantised; - std::unique_ptr m_pDithered; - -public: - // Called once at start of application - bool OnUserCreate() override - { - // Prepare Pan & Zoom - tv.Initialise({ ScreenWidth(), ScreenHeight() }); - - // Load Test Image - m_pImage = std::make_unique("./assets/Flower_640x480.png"); - - // Create two more images with the same dimensions - m_pQuantised = std::make_unique(m_pImage->width, m_pImage->height); - m_pDithered = std::make_unique(m_pImage->width, m_pImage->height); - - // These lambda functions output a new olc::Pixel based on - // the pixel it is given - auto Convert_RGB_To_Greyscale = [](const olc::Pixel in) - { - uint8_t greyscale = uint8_t(0.2162f * float(in.r) + 0.7152f * float(in.g) + 0.0722f * float(in.b)); - return olc::Pixel(greyscale, greyscale, greyscale); - }; - - - // Quantising functions - auto Quantise_Greyscale_1Bit = [](const olc::Pixel in) - { - return in.r < 128 ? olc::BLACK : olc::WHITE; - }; - - auto Quantise_Greyscale_NBit = [](const olc::Pixel in) - { - constexpr int nBits = 2; - constexpr float fLevels = (1 << nBits) - 1; - uint8_t c = uint8_t(std::clamp(std::round(float(in.r) / 255.0f * fLevels) / fLevels * 255.0f, 0.0f, 255.0f)); - return olc::Pixel(c, c, c); - }; - - auto Quantise_RGB_NBit = [](const olc::Pixel in) - { - constexpr int nBits = 2; - constexpr float fLevels = (1 << nBits) - 1; - uint8_t cr = uint8_t(std::clamp(std::round(float(in.r) / 255.0f * fLevels) / fLevels * 255.0f, 0.0f, 255.0f)); - uint8_t cb = uint8_t(std::clamp(std::round(float(in.g) / 255.0f * fLevels) / fLevels * 255.0f, 0.0f, 255.0f)); - uint8_t cg = uint8_t(std::clamp(std::round(float(in.b) / 255.0f * fLevels) / fLevels * 255.0f, 0.0f, 255.0f)); - return olc::Pixel(cr, cb, cg); - }; - - auto Quantise_RGB_CustomPalette = [](const olc::Pixel in) - { - std::array nShades = { olc::BLACK, olc::WHITE, olc::YELLOW, olc::MAGENTA, olc::CYAN }; - - float fClosest = INFINITY; - olc::Pixel pClosest; - - for (const auto& c : nShades) - { - float fDistance = float( - std::sqrt( - std::pow(float(c.r) - float(in.r), 2) + - std::pow(float(c.g) - float(in.g), 2) + - std::pow(float(c.b) - float(in.b), 2))); - - if (fDistance < fClosest) - { - fClosest = fDistance; - pClosest = c; - } - } - - return pClosest; - }; - - - // We don't need greyscale for the final demonstration, which uses - // RGB, but I've left this here as reference - //std::transform( - // m_pImage->pColData.begin(), - // m_pImage->pColData.end(), - // m_pImage->pColData.begin(), Convert_RGB_To_Greyscale); - - - // Quantise The Image - std::transform( - m_pImage->pColData.begin(), - m_pImage->pColData.end(), - m_pQuantised->pColData.begin(), Quantise_RGB_NBit); - - // Perform Dither - Dither_FloydSteinberg(m_pImage.get(), m_pDithered.get(), Quantise_RGB_NBit); - - return true; - } - - - - void Dither_FloydSteinberg(const olc::Sprite* pSource, olc::Sprite* pDest, - std::function funcQuantise) - { - // The destination image is primed with the source image as the pixel - // values become altered as the algorithm executes - std::copy(pSource->pColData.begin(), pSource->pColData.end(), pDest->pColData.begin()); - - // Iterate through each pixel from top left to bottom right, compare the pixel - // with that on the "allowed" list, and distribute that error to neighbours - // not yet computed - olc::vi2d vPixel; - for (vPixel.y = 0; vPixel.y < pSource->height; vPixel.y++) - { - for (vPixel.x = 0; vPixel.x < pSource->width; vPixel.x++) - { - // Grap and get nearest pixel equivalent from our allowed - // palette - olc::Pixel op = pDest->GetPixel(vPixel); - olc::Pixel qp = funcQuantise(op); - - // olc::Pixels are "inconveniently" clamped to sensible ranges using an unsigned type... - // ...which means they cant be negative. This hampers us a tad here, - // so will resort to manual alteration using a signed type - int32_t error[3] = - { - op.r - qp.r, - op.g - qp.g, - op.b - qp.b - }; - - // Set destination pixel with nearest match from quantisation function - pDest->SetPixel(vPixel, qp); - - // Distribute Error - Using a little utility lambda to keep the messy code - // all in one place. It's important to allow pixels to temporarily become - // negative in order to distribute the error to the neighbours in both - // directions... value directions that is, not spatial! - auto UpdatePixel = [&vPixel, &pDest, &error](const olc::vi2d& vOffset, const float fErrorBias) - { - olc::Pixel p = pDest->GetPixel(vPixel + vOffset); - int32_t k[3] = { p.r, p.g, p.b }; - k[0] += int32_t(float(error[0]) * fErrorBias); - k[1] += int32_t(float(error[1]) * fErrorBias); - k[2] += int32_t(float(error[2]) * fErrorBias); - pDest->SetPixel(vPixel + vOffset, olc::Pixel(std::clamp(k[0], 0, 255), std::clamp(k[1], 0, 255), std::clamp(k[2], 0, 255))); - }; - - UpdatePixel({ +1, 0 }, 7.0f / 16.0f); - UpdatePixel({ -1, +1 }, 3.0f / 16.0f); - UpdatePixel({ 0, +1 }, 5.0f / 16.0f); - UpdatePixel({ +1, +1 }, 1.0f / 16.0f); - } - } - } - - // Called every frame - bool OnUserUpdate(float fElapsedTime) override - { - // Handle Pan & Zoom using defaults middle mouse button - tv.HandlePanAndZoom(0); - - // Erase previous frame - Clear(olc::BLACK); - - // Draw Source Image - if (GetKey(olc::Key::Q).bHeld) - { - tv.DrawSprite({ 0,0 }, m_pQuantised.get()); - } - else if (GetKey(olc::Key::W).bHeld) - { - tv.DrawSprite({ 0,0 }, m_pDithered.get()); - } - else - { - tv.DrawSprite({ 0,0 }, m_pImage.get()); - } - - return true; - } -}; - -int main() -{ - Dithering demo; - if (demo.Construct(1280, 720, 1, 1)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_DungeonWarping.cpp b/Videos/OneLoneCoder_PGE_DungeonWarping.cpp deleted file mode 100644 index 9241612..0000000 --- a/Videos/OneLoneCoder_PGE_DungeonWarping.cpp +++ /dev/null @@ -1,431 +0,0 @@ -/* - Dungeon Warping via Orthographic Projections - "For my Mother-In-Law, you will be missed..." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Relevant Video: https://youtu.be/Ql5VZGkL23o - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Community Blog: https://community.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019, 2020 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -/* - - NOTE! This program requires a tile spritesheet NOT - provided in this github. You only need a few tiles, - see video for details. - -*/ - -class olcDungeon : public olc::PixelGameEngine -{ -public: - olcDungeon() - { - sAppName = "Dungeon Explorer"; - } - - struct Renderable - { - Renderable() {} - - void Load(const std::string& sFile) - { - sprite = new olc::Sprite(sFile); - decal = new olc::Decal(sprite); - } - - ~Renderable() - { - delete decal; - delete sprite; - } - - olc::Sprite* sprite = nullptr; - olc::Decal* decal = nullptr; - }; - - struct vec3d - { - float x, y, z; - }; - - struct sQuad - { - vec3d points[4]; - olc::vf2d tile; - }; - - struct sCell - { - bool wall = false; - olc::vi2d id[6]{ }; - }; - - class World - { - public: - World() - { - - } - - void Create(int w, int h) - { - size = { w, h }; - vCells.resize(w * h); - } - - sCell& GetCell(const olc::vi2d& v) - { - if (v.x >= 0 && v.x < size.x && v.y >= 0 && v.y < size.y) - return vCells[v.y * size.x + v.x]; - else - return NullCell; - } - - public: - olc::vi2d size; - - private: - std::vector vCells; - sCell NullCell; - }; - - World world; - Renderable rendSelect; - Renderable rendAllWalls; - - olc::vf2d vCameraPos = { 0.0f, 0.0f }; - float fCameraAngle = 0.0f; - float fCameraAngleTarget = fCameraAngle; - float fCameraPitch = 5.5f; - float fCameraZoom = 16.0f; - - bool bVisible[6]; - - olc::vi2d vCursor = { 0, 0 }; - olc::vi2d vTileCursor = { 0,0 }; - olc::vi2d vTileSize = { 32, 32 }; - - enum Face - { - Floor = 0, - North = 1, - East = 2, - South = 3, - West = 4, - Top = 5 - }; - -public: - bool OnUserCreate() override - { - rendSelect.Load("./gfx/dng_select.png"); - rendAllWalls.Load("./gfx/oldDungeon.png"); - - world.Create(64, 64); - - for (int y=0; y CreateCube(const olc::vi2d& vCell, const float fAngle, const float fPitch, const float fScale, const vec3d& vCamera) - { - // Unit Cube - std::array unitCube, rotCube, worldCube, projCube; - unitCube[0] = { 0.0f, 0.0f, 0.0f }; - unitCube[1] = { fScale, 0.0f, 0.0f }; - unitCube[2] = { fScale, -fScale, 0.0f }; - unitCube[3] = { 0.0f, -fScale, 0.0f }; - unitCube[4] = { 0.0f, 0.0f, fScale }; - unitCube[5] = { fScale, 0.0f, fScale }; - unitCube[6] = { fScale, -fScale, fScale }; - unitCube[7] = { 0.0f, -fScale, fScale }; - - // Translate Cube in X-Z Plane - for (int i = 0; i < 8; i++) - { - unitCube[i].x += (vCell.x * fScale - vCamera.x); - unitCube[i].y += -vCamera.y; - unitCube[i].z += (vCell.y * fScale - vCamera.z); - } - - // Rotate Cube in Y-Axis around origin - float s = sin(fAngle); - float c = cos(fAngle); - for (int i = 0; i < 8; i++) - { - rotCube[i].x = unitCube[i].x * c + unitCube[i].z * s; - rotCube[i].y = unitCube[i].y; - rotCube[i].z = unitCube[i].x * -s + unitCube[i].z * c; - } - - // Rotate Cube in X-Axis around origin (tilt slighly overhead) - s = sin(fPitch); - c = cos(fPitch); - for (int i = 0; i < 8; i++) - { - worldCube[i].x = rotCube[i].x; - worldCube[i].y = rotCube[i].y * c - rotCube[i].z * s; - worldCube[i].z = rotCube[i].y * s + rotCube[i].z * c; - } - - // Project Cube Orthographically - Unit Cube Viewport - //float fLeft = -ScreenWidth() * 0.5f; - //float fRight = ScreenWidth() * 0.5f; - //float fTop = ScreenHeight() * 0.5f; - //float fBottom = -ScreenHeight() * 0.5f; - //float fNear = 0.1f; - //float fFar = 100.0f;*/ - //for (int i = 0; i < 8; i++) - //{ - // projCube[i].x = (2.0f / (fRight - fLeft)) * worldCube[i].x - ((fRight + fLeft) / (fRight - fLeft)); - // projCube[i].y = (2.0f / (fTop - fBottom)) * worldCube[i].y - ((fTop + fBottom) / (fTop - fBottom)); - // projCube[i].z = (2.0f / (fFar - fNear)) * worldCube[i].z - ((fFar + fNear) / (fFar - fNear)); - // projCube[i].x *= -fRight; - // projCube[i].y *= -fTop; - // projCube[i].x += fRight; - // projCube[i].y += fTop; - //} - - // Project Cube Orthographically - Full Screen Centered - for (int i = 0; i < 8; i++) - { - projCube[i].x = worldCube[i].x + ScreenWidth() * 0.5f; - projCube[i].y = worldCube[i].y + ScreenHeight() * 0.5f; - projCube[i].z = worldCube[i].z; - } - - return projCube; - } - - - - void CalculateVisibleFaces(std::array& cube) - { - auto CheckNormal = [&](int v1, int v2, int v3) - { - olc::vf2d a = { cube[v1].x, cube[v1].y }; - olc::vf2d b = { cube[v2].x, cube[v2].y }; - olc::vf2d c = { cube[v3].x, cube[v3].y }; - return (b - a).cross(c - a) > 0; - }; - - bVisible[Face::Floor] = CheckNormal(4, 0, 1); - bVisible[Face::South] = CheckNormal(3, 0, 1); - bVisible[Face::North] = CheckNormal(6, 5, 4); - bVisible[Face::East] = CheckNormal(7, 4, 0); - bVisible[Face::West] = CheckNormal(2, 1, 5); - bVisible[Face::Top] = CheckNormal(7, 3, 2); - } - - void GetFaceQuads(const olc::vi2d& vCell, const float fAngle, const float fPitch, const float fScale, const vec3d& vCamera, std::vector &render) - { - std::array projCube = CreateCube(vCell, fAngle, fPitch, fScale, vCamera); - - auto& cell = world.GetCell(vCell); - - auto MakeFace = [&](int v1, int v2, int v3, int v4, Face f) - { - render.push_back({ projCube[v1], projCube[v2], projCube[v3], projCube[v4], cell.id[f] }); - }; - - if (!cell.wall) - { - if(bVisible[Face::Floor]) MakeFace(4, 0, 1, 5, Face::Floor); - } - else - { - if (bVisible[Face::South]) MakeFace(3, 0, 1, 2, Face::South); - if (bVisible[Face::North]) MakeFace(6, 5, 4, 7, Face::North); - if (bVisible[Face::East]) MakeFace(7, 4, 0, 3, Face::East); - if (bVisible[Face::West]) MakeFace(2, 1, 5, 6, Face::West); - if (bVisible[Face::Top]) MakeFace(7, 3, 2, 6, Face::Top); - } - } - - - bool OnUserUpdate(float fElapsedTime) override - { - // Grab mouse for convenience - olc::vi2d vMouse = { GetMouseX(), GetMouseY() }; - - // Edit mode - Selection from tile sprite sheet - if (GetKey(olc::Key::TAB).bHeld) - { - DrawSprite({ 0, 0 }, rendAllWalls.sprite); - DrawRect(vTileCursor * vTileSize, vTileSize); - if (GetMouse(0).bPressed) vTileCursor = vMouse / vTileSize; - return true; - } - - // WS keys to tilt camera - if (GetKey(olc::Key::W).bHeld) fCameraPitch += 1.0f * fElapsedTime; - if (GetKey(olc::Key::S).bHeld) fCameraPitch -= 1.0f * fElapsedTime; - - // DA Keys to manually rotate camera - if (GetKey(olc::Key::D).bHeld) fCameraAngleTarget += 1.0f * fElapsedTime; - if (GetKey(olc::Key::A).bHeld) fCameraAngleTarget -= 1.0f * fElapsedTime; - - // QZ Keys to zoom in or out - if (GetKey(olc::Key::Q).bHeld) fCameraZoom += 5.0f * fElapsedTime; - if (GetKey(olc::Key::Z).bHeld) fCameraZoom -= 5.0f * fElapsedTime; - - // Numpad keys used to rotate camera to fixed angles - if (GetKey(olc::Key::NP2).bPressed) fCameraAngleTarget = 3.14159f * 0.0f; - if (GetKey(olc::Key::NP1).bPressed) fCameraAngleTarget = 3.14159f * 0.25f; - if (GetKey(olc::Key::NP4).bPressed) fCameraAngleTarget = 3.14159f * 0.5f; - if (GetKey(olc::Key::NP7).bPressed) fCameraAngleTarget = 3.14159f * 0.75f; - if (GetKey(olc::Key::NP8).bPressed) fCameraAngleTarget = 3.14159f * 1.0f; - if (GetKey(olc::Key::NP9).bPressed) fCameraAngleTarget = 3.14159f * 1.25f; - if (GetKey(olc::Key::NP6).bPressed) fCameraAngleTarget = 3.14159f * 1.5f; - if (GetKey(olc::Key::NP3).bPressed) fCameraAngleTarget = 3.14159f * 1.75f; - - // Numeric keys apply selected tile to specific face - if (GetKey(olc::Key::K1).bPressed) world.GetCell(vCursor).id[Face::North] = vTileCursor * vTileSize; - if (GetKey(olc::Key::K2).bPressed) world.GetCell(vCursor).id[Face::East] = vTileCursor * vTileSize; - if (GetKey(olc::Key::K3).bPressed) world.GetCell(vCursor).id[Face::South] = vTileCursor * vTileSize; - if (GetKey(olc::Key::K4).bPressed) world.GetCell(vCursor).id[Face::West] = vTileCursor * vTileSize; - if (GetKey(olc::Key::K5).bPressed) world.GetCell(vCursor).id[Face::Floor] = vTileCursor * vTileSize; - if (GetKey(olc::Key::K6).bPressed) world.GetCell(vCursor).id[Face::Top] = vTileCursor * vTileSize; - - // Smooth camera - fCameraAngle += (fCameraAngleTarget - fCameraAngle) * 10.0f * fElapsedTime; - - // Arrow keys to move the selection cursor around map (boundary checked) - if (GetKey(olc::Key::LEFT).bPressed) vCursor.x--; - if (GetKey(olc::Key::RIGHT).bPressed) vCursor.x++; - if (GetKey(olc::Key::UP).bPressed) vCursor.y--; - if (GetKey(olc::Key::DOWN).bPressed) vCursor.y++; - if (vCursor.x < 0) vCursor.x = 0; - if (vCursor.y < 0) vCursor.y = 0; - if (vCursor.x >= world.size.x) vCursor.x = world.size.x - 1; - if (vCursor.y >= world.size.y) vCursor.y = world.size.y - 1; - - // Place block with space - if (GetKey(olc::Key::SPACE).bPressed) - { - world.GetCell(vCursor).wall = !world.GetCell(vCursor).wall; - } - - // Position camera in world - vCameraPos = { vCursor.x + 0.5f, vCursor.y + 0.5f }; - vCameraPos *= fCameraZoom; - - // Rendering - - // 1) Create dummy cube to extract visible face information - // Cull faces that cannot be seen - std::array cullCube = CreateCube({ 0, 0 }, fCameraAngle, fCameraPitch, fCameraZoom, { vCameraPos.x, 0.0f, vCameraPos.y }); - CalculateVisibleFaces(cullCube); - - // 2) Get all visible sides of all visible "tile cubes" - std::vector vQuads; - for(int y = 0; y listEvents; - float fTotalTime = 0.0f; - olc::Sprite *spr; - - bool OnUserUpdate(float fElapsedTime) override - { - // Clear Screen - SetPixelMode(olc::Pixel::NORMAL); - Clear(olc::BLUE); - - // Draw Primitives - DrawCircle(32, 32, 30); // Circle - DrawCircle(96, 32, 30); // Circle - - - float mx = (float)GetMouseX(); - float my = (float)GetMouseY(); - - float px1 = mx - 32, px2 = mx - 96; - float py1 = my - 32, py2 = my - 32; - float pr1 = 1.0f / sqrtf(px1*px1 + py1*py1); - float pr2 = 1.0f / sqrtf(px2*px2 + py2*py2); - px1 = 22.0f * (px1 * pr1) + 32.0f; - py1 = 22.0f * (py1 * pr1) + 32.0f; - px2 = 22.0f * (px2 * pr2) + 96.0f; - py2 = 22.0f * (py2 * pr2) + 32.0f; - FillCircle((int32_t)px1, (int32_t)py1, 8, olc::CYAN); - FillCircle((int32_t)px2, (int32_t)py2, 8, olc::CYAN); - - DrawLine(10, 70, 54, 70); // Lines - DrawLine(54, 70, 70, 54); - - DrawRect(10, 80, 54, 30); - FillRect(10, 80, 54, 30); - - // Multiline Text - std::string mpos = "Your Mouse Position is:\nX=" + std::to_string(mx) + "\nY=" + std::to_string(my); - DrawString(10, 130, mpos); - - auto AddEvent = [&](std::string s) - { - listEvents.push_back(s); - listEvents.pop_front(); - }; - - if (GetMouse(0).bPressed) AddEvent("Mouse Button 0 Down"); - if (GetMouse(0).bReleased) AddEvent("Mouse Button 0 Up"); - if (GetMouse(1).bPressed) AddEvent("Mouse Button 1 Down"); - if (GetMouse(1).bReleased) AddEvent("Mouse Button 1 Up"); - if (GetMouse(2).bPressed) AddEvent("Mouse Button 2 Down"); - if (GetMouse(2).bReleased) AddEvent("Mouse Button 2 Up"); - - - // Draw Event Log - int nLog = 0; - for (auto &s : listEvents) - { - DrawString(200, nLog * 8 + 20, s, olc::Pixel(nLog * 16, nLog * 16, nLog * 16)); - nLog++; - } - - std::string notes = "CDEFGAB"; - - - // Test Text scaling and colours - DrawString(0, 360, "Text Scale = 1", olc::WHITE, 1); - DrawString(0, 368, "Text Scale = 2", olc::BLUE, 2); - DrawString(0, 384, "Text Scale = 3", olc::RED, 3); - DrawString(0, 408, "Text Scale = 4", olc::YELLOW, 4); - DrawString(0, 440, "Text Scale = 5", olc::GREEN, 5); - - fTotalTime += fElapsedTime; - - float fAngle = fTotalTime; - - // Draw Sprite using extension, first create a transformation stack - olc::GFX2D::Transform2D t1; - - // Traslate sprite so center of image is at 0,0 - t1.Translate(-250, -35); - // Scale the sprite - t1.Scale(1 * sinf(fAngle) + 1, 1 * sinf(fAngle) + 1); - // Rotate it - t1.Rotate(fAngle*2.0f); - // Translate to 0,100 - t1.Translate(0, 100); - // Rotate different speed - t1.Rotate(fAngle / 3); - // Translate to centre of screen - t1.Translate(320, 240); - - SetPixelMode(olc::Pixel::ALPHA); - - // Use extension to draw sprite with transform applied - olc::GFX2D::DrawSprite(spr, t1); - - DrawSprite((int32_t)mx, (int32_t)my, spr, 4); - - return true; - } -}; - - -int main() -{ - TestExtension demo; - if (demo.Construct(640, 480, 2, 2)) - demo.Start(); - - return 0; -} diff --git a/Videos/OneLoneCoder_PGE_FiveDice.cpp b/Videos/OneLoneCoder_PGE_FiveDice.cpp deleted file mode 100644 index a7c86ff..0000000 --- a/Videos/OneLoneCoder_PGE_FiveDice.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* - Programming Practice: Five Dice - "OK, it's getting a bit serious now..." - javidx9 - - Video: https://youtu.be/D2a5fHX-Qrs - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2021 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Video: - ~~~~~~ - https://youtu.be/DDV_2cWT94U - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#include -#include - -class FiveDice : public olc::PixelGameEngine -{ -public: - FiveDice() - { - sAppName = "Five Dice"; - } - - std::vector vRolled; - -public: - void DrawDie(const olc::vi2d& vPos, - const uint8_t nFace, - const olc::vi2d& vSize = { 64, 64 }, - const olc::Pixel colFace = olc::DARK_RED, - const olc::Pixel colSpot = olc::WHITE) - { - // Draw Background - FillRect(vPos, vSize, colFace); - - int32_t nColL = int32_t(double(vSize.x) * 0.25); - int32_t nColM = int32_t(double(vSize.x) * 0.5); - int32_t nColR = int32_t(double(vSize.x) * 0.75); - int32_t nRowT = int32_t(double(vSize.y) * 0.25); - int32_t nRowM = int32_t(double(vSize.y) * 0.5); - int32_t nRowB = int32_t(double(vSize.y) * 0.75); - int32_t nRad = int32_t(double(nColL) * 0.4); - - /* - switch (nFace) - { - case 1: - FillCircle(vPos + olc::vi2d(nColM, nRowM), nRad, colSpot); - break; - case 2: - FillCircle(vPos + olc::vi2d(nColL, nRowT), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColR, nRowB), nRad, colSpot); - break; - case 3: - FillCircle(vPos + olc::vi2d(nColL, nRowT), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColM, nRowM), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColR, nRowB), nRad, colSpot); - break; - case 4: - FillCircle(vPos + olc::vi2d(nColL, nRowT), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColR, nRowB), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColL, nRowB), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColR, nRowT), nRad, colSpot); - break; - case 5: - FillCircle(vPos + olc::vi2d(nColL, nRowT), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColR, nRowB), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColL, nRowB), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColR, nRowT), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColM, nRowM), nRad, colSpot); - break; - case 6: - FillCircle(vPos + olc::vi2d(nColL, nRowT), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColR, nRowB), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColL, nRowB), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColR, nRowT), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColL, nRowM), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColR, nRowM), nRad, colSpot); - break; - } - */ - - /* - if((std::set{2, 3, 4, 5, 6}).count(nFace) > 0) - FillCircle(vPos + olc::vi2d(nColL, nRowT), nRad, colSpot); - if ((std::set{6}).count(nFace) > 0) - FillCircle(vPos + olc::vi2d(nColL, nRowM), nRad, colSpot); - if ((std::set{4, 5, 6}).count(nFace) > 0) - FillCircle(vPos + olc::vi2d(nColL, nRowB), nRad, colSpot); - - if ((std::set{1, 3, 5}).count(nFace) > 0) - FillCircle(vPos + olc::vi2d(nColM, nRowM), nRad, colSpot); - - if ((std::set{4, 5, 6}).count(nFace) > 0) - FillCircle(vPos + olc::vi2d(nColR, nRowT), nRad, colSpot); - if ((std::set{6}).count(nFace) > 0) - FillCircle(vPos + olc::vi2d(nColR, nRowM), nRad, colSpot); - if ((std::set{2, 3, 4, 5, 6}).count(nFace) > 0) - FillCircle(vPos + olc::vi2d(nColR, nRowB), nRad, colSpot); - */ - - - if (nFace & 1) - { - FillCircle(vPos + olc::vi2d(nColM, nRowM), nRad, colSpot); - } - - if (nFace > 1) - { - FillCircle(vPos + olc::vi2d(nColR, nRowB), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColL, nRowT), nRad, colSpot); - } - - if (nFace > 3) - { - FillCircle(vPos + olc::vi2d(nColR, nRowT), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColL, nRowB), nRad, colSpot); - } - - if (nFace == 6) - { - FillCircle(vPos + olc::vi2d(nColL, nRowM), nRad, colSpot); - FillCircle(vPos + olc::vi2d(nColR, nRowM), nRad, colSpot); - } - - } - - - - - bool OnUserCreate() override - { - vRolled = { 1, 6, 3, 3, 5 }; - - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - - //if (GetKey(olc::Key::SPACE).bReleased) - //{ - // /* - // vRolled = - // { - // uint8_t(rand() % 6 + 1), - // uint8_t(rand() % 6 + 1), - // uint8_t(rand() % 6 + 1), - // uint8_t(rand() % 6 + 1), - // uint8_t(rand() % 6 + 1) - // }; - // */ - - // /* - // std::transform( - // vRolled.begin(), - // vRolled.end(), - // vRolled.begin(), - // [](uint8_t n) { return rand() % 6 + 1; } - // ); - // */ - - // std::generate( - // vRolled.begin(), - // vRolled.end(), - // []() { return rand() % 6 + 1; } - // ); - - // std::sort(vRolled.begin(), vRolled.end()); - //} - - - /* - int nScore_AllDice = std::accumulate(vRolled.begin(), vRolled.end(), 0); - - int nScore_CountOnes = std::count(vRolled.begin(), vRolled.end(), 1) * 1; - int nScore_CountTwos = std::count(vRolled.begin(), vRolled.end(), 2) * 2; - int nScore_CountThrees = std::count(vRolled.begin(), vRolled.end(), 3) * 3; - int nScore_CountFours = std::count(vRolled.begin(), vRolled.end(), 4) * 4; - int nScore_CountFives = std::count(vRolled.begin(), vRolled.end(), 5) * 5; - int nScore_CountSixes = std::count(vRolled.begin(), vRolled.end(), 6) * 6; - - int nScore_ThreeOfAKind = 0; - int nScore_FourOfAKind = 0; - int nScore_FiveOfAKind = 0; - int nScore_SmallStraight = 0; - int nScore_LargeStraight = 0; - int nScore_FullHouse = 0; - */ - - /* - auto PatternMatch = [&](const std::vector vDice, const std::string& sPattern) -> bool - { - // nnnnn - Yahtzee - // nnnn?, ?nnnn - four of a kind - // nnn??, ?nnn?, ??nnn - three of a kind - // 1234?, ?2345, 2345?, ?3456 - Small Straight - // 12345, 23456 - Large Straight - // nnn?? & ???nn, nn??? & ??nnn - Full House - - bool bMatch = true; - uint8_t n = 0; - - for (size_t idx = 0; idx < 5; idx++) - { - if (sPattern[idx] == 'n') - { - if (n == 0) - { - n = vDice[idx]; - } - else - { - bMatch &= (vDice[idx] == n); - } - } - else if (sPattern[idx] == '?') - { - bMatch &= true; - } - else // is Face Value - { - bMatch &= ((sPattern[idx] - '0') == vDice[idx]); - } - - } - return bMatch; - }; - - - // nnnnn - Yahtzee - if (PatternMatch(vRolled, "nnnnn")) - { - nScore_FiveOfAKind = 50; - } - - // nnnn?, ?nnnn - four of a kind - if (PatternMatch(vRolled, "nnnn?") || PatternMatch(vRolled, "?nnnn")) - { - nScore_FourOfAKind = 4 * vRolled[2]; - } - - // nnn??, ?nnn?, ??nnn - three of a kind - if (PatternMatch(vRolled, "nnn??") || PatternMatch(vRolled, "?nnn?") || PatternMatch(vRolled, "??nnn")) - { - nScore_ThreeOfAKind = 3 * vRolled[2]; - } - - // 1234?, ?2345, 2345?, ?3456 - Small Straight - if (PatternMatch(vRolled, "1234?") || PatternMatch(vRolled, "2345?") || PatternMatch(vRolled, "?3456") || PatternMatch(vRolled, "?2345")) - { - nScore_SmallStraight = 30; - } - - // 12345, 23456 - Large Straight - if (PatternMatch(vRolled, "12345") || PatternMatch(vRolled, "23456")) - { - nScore_LargeStraight = 40; - } - - // nnn?? & ???nn, nn??? & ??nnn - Full House - if ((PatternMatch(vRolled, "nnn??") && PatternMatch(vRolled, "???nn")) || (PatternMatch(vRolled, "??nnn") && PatternMatch(vRolled, "nn???"))) - { - nScore_FullHouse = 25; - } - - std::vector> vScores = - { - {"Total Ones : ", std::count(vRolled.begin(), vRolled.end(), 1) * 1}, - {"Total Twos : ", std::count(vRolled.begin(), vRolled.end(), 2) * 2}, - {"Total Threes : ", std::count(vRolled.begin(), vRolled.end(), 3) * 3}, - {"Total Fours : ", std::count(vRolled.begin(), vRolled.end(), 4) * 4}, - {"Total Fives : ", std::count(vRolled.begin(), vRolled.end(), 5) * 5}, - {"Total Sixes : ", std::count(vRolled.begin(), vRolled.end(), 6) * 6}, - {"Chance : ", std::accumulate(vRolled.begin(), vRolled.end(), 0)}, - - {"Three Of A Kind : ", (PatternMatch(vRolled, "nnn??") || PatternMatch(vRolled, "?nnn?") || PatternMatch(vRolled, "??nnn")) ? (std::count(vRolled.begin(), vRolled.end(), vRolled[2]) * vRolled[2]) : 0}, - {"Four Of A Kind : ", (PatternMatch(vRolled, "nnnn?") || PatternMatch(vRolled, "?nnnn")) ? (std::count(vRolled.begin(), vRolled.end(), vRolled[2]) * vRolled[2]) : 0}, - {"Full House : ", ((PatternMatch(vRolled, "nnn??") && PatternMatch(vRolled, "???nn")) || (PatternMatch(vRolled, "??nnn") && PatternMatch(vRolled, "nn???"))) ? 25 : 0}, - {"Small Straight : ", (PatternMatch(vRolled, "1234?") || PatternMatch(vRolled, "2345?") || PatternMatch(vRolled, "?3456") || PatternMatch(vRolled, "?2345")) ? 30 : 0}, - {"Large Straight : ", (PatternMatch(vRolled, "12345") || PatternMatch(vRolled, "23456")) ? 40 : 0}, - {"Five Of A Kind : ", (PatternMatch(vRolled, "nnnnn")) ? 50 : 0}, - }; - - */ - - auto Match = [&vRolled = vRolled](const std::vector& vPatterns) -> bool - { - // nnnnn - Yahtzee - // nnnn?, ?nnnn - four of a kind - // nnn??, ?nnn?, ??nnn - three of a kind - // 1234?, ?2345, 2345?, ?3456 - Small Straight - // 12345, 23456 - Large Straight - // nnn?? & ???nn, nn??? & ??nnn - Full House - - bool bResult = false; - - for (const auto& sPattern : vPatterns) - { - - bool bMatch = true; - uint8_t n = 0; - - for (size_t idx = 0; idx < 5; idx++) - { - if (sPattern[idx] == 'n') - { - if (n == 0) - { - n = vRolled[idx]; - } - else - { - bMatch &= (vRolled[idx] == n); - } - } - else if (sPattern[idx] == '?') - { - bMatch &= true; - } - else // is Face Value - { - bMatch &= ((sPattern[idx] - '0') == vRolled[idx]); - } - - } - - bResult |= bMatch; - } - return bResult; - }; - - /*DrawDie({ 10, 10 }, vRolled[0]); - DrawDie({ 80, 10 }, vRolled[1]); - DrawDie({ 150, 10 }, vRolled[2]); - DrawDie({ 220, 10 }, vRolled[3]); - DrawDie({ 290, 10 }, vRolled[4]); - - int nOffsetY = 100; - DrawString(10, nOffsetY += 10, "Total Ones : " + std::to_string(nScore_CountOnes)); - DrawString(10, nOffsetY += 10, "Total Twos : " + std::to_string(nScore_CountTwos)); - DrawString(10, nOffsetY += 10, "Total Threes : " + std::to_string(nScore_CountThrees)); - DrawString(10, nOffsetY += 10, "Total Fours : " + std::to_string(nScore_CountFours)); - DrawString(10, nOffsetY += 10, "Total Fives : " + std::to_string(nScore_CountFives)); - DrawString(10, nOffsetY += 10, "Total Sixes : " + std::to_string(nScore_CountSixes)); - DrawString(10, nOffsetY += 10, "Three Of A Kind : " + std::to_string(nScore_ThreeOfAKind)); - DrawString(10, nOffsetY += 10, "Four Of A Kind : " + std::to_string(nScore_FourOfAKind)); - DrawString(10, nOffsetY += 10, "Full House : " + std::to_string(nScore_FullHouse)); - DrawString(10, nOffsetY += 10, "Small Straight : " + std::to_string(nScore_SmallStraight)); - DrawString(10, nOffsetY += 10, "Large Straight : " + std::to_string(nScore_LargeStraight)); - DrawString(10, nOffsetY += 10, "Five Of A Kind : " + std::to_string(nScore_FiveOfAKind)); - DrawString(10, nOffsetY += 10, "Chance : " + std::to_string(nScore_AllDice));*/ - - if (GetKey(olc::Key::SPACE).bReleased) - { - std::generate(vRolled.begin(), vRolled.end(), []() { return rand() % 6 + 1; }); - std::sort(vRolled.begin(), vRolled.end()); - } - - std::vector> vScores = - { - {"Total Ones : ", std::count(vRolled.begin(), vRolled.end(), 1) * 1}, - {"Total Twos : ", std::count(vRolled.begin(), vRolled.end(), 2) * 2}, - {"Total Threes : ", std::count(vRolled.begin(), vRolled.end(), 3) * 3}, - {"Total Fours : ", std::count(vRolled.begin(), vRolled.end(), 4) * 4}, - {"Total Fives : ", std::count(vRolled.begin(), vRolled.end(), 5) * 5}, - {"Total Sixes : ", std::count(vRolled.begin(), vRolled.end(), 6) * 6}, - {"Chance : ", std::accumulate(vRolled.begin(), vRolled.end(), 0)}, - - {"Three Of A Kind : ", (Match({"nnn??", "?nnn?", "??nnn"})) ? (3 * vRolled[2]) : 0}, - {"Four Of A Kind : ", (Match({"nnnn?", "?nnnn"})) ? (4 * vRolled[2]) : 0}, - {"Full House : ", ((Match({"nnn??"}) && Match({"???nn"})) || (Match({"??nnn"}) && Match({"nn???"}))) ? 25 : 0}, - {"Small Straight : ", (Match({"1234?", "2345?", "?3456", "?2345"})) ? 30 : 0}, - {"Large Straight : ", (Match({"12345", "23456"})) ? 40 : 0}, - {"Five Of A Kind : ", (Match({"nnnnn"})) ? 50 : 0}, - }; - - - Clear(olc::DARK_GREEN); - olc::vi2d vOffset = { -60, 90 }; - for (int i = 0; i < 5; i++) DrawDie({ vOffset.x += 70, 10 }, vRolled[i]); - for (const auto& score : vScores) DrawString(10, vOffset.y += 10, score.first + std::to_string(score.second)); - - return true; - } -}; - -int main() -{ - FiveDice demo; - if (demo.Construct(640, 480, 2, 2)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_IsometricTiles.cpp b/Videos/OneLoneCoder_PGE_IsometricTiles.cpp deleted file mode 100644 index 4854ef3..0000000 --- a/Videos/OneLoneCoder_PGE_IsometricTiles.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - Coding Quickie: Isometric Tiles - "Owww... My insides hurt :(" - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Relevant Video: https://youtu.be/ukkbNKTgf5U - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -// Override base class with your custom functionality -class IsometricDemo : public olc::PixelGameEngine -{ -public: - IsometricDemo() - { - sAppName = "Coding Quickie: Isometric Tiles"; - } - -private: - // Number of tiles in world - olc::vi2d vWorldSize = { 14, 10 }; - - // Size of single tile graphic - olc::vi2d vTileSize = { 40, 20 }; - - // Where to place tile (0,0) on screen (in tile size steps) - olc::vi2d vOrigin = { 5, 1 }; - - // Sprite that holds all imagery - olc::Sprite *sprIsom = nullptr; - - // Pointer to create 2D world array - int *pWorld = nullptr; - -public: - bool OnUserCreate() override - { - // Load sprites used in demonstration - sprIsom = new olc::Sprite("isometric_demo.png"); - - // Create empty world - pWorld = new int[vWorldSize.x * vWorldSize.y]{ 0 }; - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - Clear(olc::WHITE); - - // Get Mouse in world - olc::vi2d vMouse = { GetMouseX(), GetMouseY() }; - - // Work out active cell - olc::vi2d vCell = { vMouse.x / vTileSize.x, vMouse.y / vTileSize.y }; - - // Work out mouse offset into cell - olc::vi2d vOffset = { vMouse.x % vTileSize.x, vMouse.y % vTileSize.y }; - - // Sample into cell offset colour - olc::Pixel col = sprIsom->GetPixel(3 * vTileSize.x + vOffset.x, vOffset.y); - - // Work out selected cell by transforming screen cell - olc::vi2d vSelected = - { - (vCell.y - vOrigin.y) + (vCell.x - vOrigin.x), - (vCell.y - vOrigin.y) - (vCell.x - vOrigin.x) - }; - - // "Bodge" selected cell by sampling corners - if (col == olc::RED) vSelected += {-1, +0}; - if (col == olc::BLUE) vSelected += {+0, -1}; - if (col == olc::GREEN) vSelected += {+0, +1}; - if (col == olc::YELLOW) vSelected += {+1, +0}; - - // Handle mouse click to toggle if a tile is visible or not - if (GetMouse(0).bPressed) - { - // Guard array boundary - if (vSelected.x >= 0 && vSelected.x < vWorldSize.x && vSelected.y >= 0 && vSelected.y < vWorldSize.y) - ++pWorld[vSelected.y * vWorldSize.x + vSelected.x] %= 6; - } - - // Labmda function to convert "world" coordinate into screen space - auto ToScreen = [&](int x, int y) - { - return olc::vi2d - { - (vOrigin.x * vTileSize.x) + (x - y) * (vTileSize.x / 2), - (vOrigin.y * vTileSize.y) + (x + y) * (vTileSize.y / 2) - }; - }; - - // Draw World - has binary transparancy so enable masking - SetPixelMode(olc::Pixel::MASK); - - // (0,0) is at top, defined by vOrigin, so draw from top to bottom - // to ensure tiles closest to camera are drawn last - for (int y = 0; y < vWorldSize.y; y++) - { - for (int x = 0; x < vWorldSize.x; x++) - { - // Convert cell coordinate to world space - olc::vi2d vWorld = ToScreen(x, y); - - switch(pWorld[y*vWorldSize.x + x]) - { - case 0: - // Invisble Tile - DrawPartialSprite(vWorld.x, vWorld.y, sprIsom, 1 * vTileSize.x, 0, vTileSize.x, vTileSize.y); - break; - case 1: - // Visible Tile - DrawPartialSprite(vWorld.x, vWorld.y, sprIsom, 2 * vTileSize.x, 0, vTileSize.x, vTileSize.y); - break; - case 2: - // Tree - DrawPartialSprite(vWorld.x, vWorld.y - vTileSize.y, sprIsom, 0 * vTileSize.x, 1 * vTileSize.y, vTileSize.x, vTileSize.y * 2); - break; - case 3: - // Spooky Tree - DrawPartialSprite(vWorld.x, vWorld.y - vTileSize.y, sprIsom, 1 * vTileSize.x, 1 * vTileSize.y, vTileSize.x, vTileSize.y * 2); - break; - case 4: - // Beach - DrawPartialSprite(vWorld.x, vWorld.y - vTileSize.y, sprIsom, 2 * vTileSize.x, 1 * vTileSize.y, vTileSize.x, vTileSize.y * 2); - break; - case 5: - // Water - DrawPartialSprite(vWorld.x, vWorld.y - vTileSize.y, sprIsom, 3 * vTileSize.x, 1 * vTileSize.y, vTileSize.x, vTileSize.y * 2); - break; - } - } - } - - // Draw Selected Cell - Has varying alpha components - SetPixelMode(olc::Pixel::ALPHA); - - // Convert selected cell coordinate to world space - olc::vi2d vSelectedWorld = ToScreen(vSelected.x, vSelected.y); - - // Draw "highlight" tile - DrawPartialSprite(vSelectedWorld.x, vSelectedWorld.y, sprIsom, 0 * vTileSize.x, 0, vTileSize.x, vTileSize.y); - - // Go back to normal drawing with no expected transparency - SetPixelMode(olc::Pixel::NORMAL); - - // Draw Hovered Cell Boundary - //DrawRect(vCell.x * vTileSize.x, vCell.y * vTileSize.y, vTileSize.x, vTileSize.y, olc::RED); - - // Draw Debug Info - DrawString(4, 4, "Mouse : " + std::to_string(vMouse.x) + ", " + std::to_string(vMouse.y), olc::BLACK); - DrawString(4, 14, "Cell : " + std::to_string(vCell.x) + ", " + std::to_string(vCell.y), olc::BLACK); - DrawString(4, 24, "Selected: " + std::to_string(vSelected.x) + ", " + std::to_string(vSelected.y), olc::BLACK); - return true; - } -}; - - -int main() -{ - IsometricDemo demo; - if (demo.Construct(512, 480, 2, 2)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_MIDI.cpp b/Videos/OneLoneCoder_PGE_MIDI.cpp deleted file mode 100644 index 9494328..0000000 --- a/Videos/OneLoneCoder_PGE_MIDI.cpp +++ /dev/null @@ -1,626 +0,0 @@ -/* - Programming MIDI: Parsing, Displaying (& Playing) MIDI Files - "Better get these done before im virused..." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Relevant Video: https://youtu.be/040BKtnDdg0 - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Community: https://community.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019, 2020 -*/ - - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#include -#include - -//#pragma comment(lib, "winmm.lib") - - -struct MidiEvent -{ - enum class Type - { - NoteOff, - NoteOn, - Other - } event; - - uint8_t nKey = 0; - uint8_t nVelocity = 0; - uint32_t nDeltaTick = 0; -}; - - -struct MidiNote -{ - uint8_t nKey = 0; - uint8_t nVelocity = 0; - uint32_t nStartTime = 0; - uint32_t nDuration = 0; -}; - -struct MidiTrack -{ - std::string sName; - std::string sInstrument; - std::vector vecEvents; - std::vector vecNotes; - uint8_t nMaxNote = 64; - uint8_t nMinNote = 64; -}; - - -class MidiFile -{ -public: - enum EventName : uint8_t - { - VoiceNoteOff = 0x80, - VoiceNoteOn = 0x90, - VoiceAftertouch = 0xA0, - VoiceControlChange = 0xB0, - VoiceProgramChange = 0xC0, - VoiceChannelPressure = 0xD0, - VoicePitchBend = 0xE0, - SystemExclusive = 0xF0, - }; - - enum MetaEventName : uint8_t - { - MetaSequence = 0x00, - MetaText = 0x01, - MetaCopyright = 0x02, - MetaTrackName = 0x03, - MetaInstrumentName = 0x04, - MetaLyrics = 0x05, - MetaMarker = 0x06, - MetaCuePoint = 0x07, - MetaChannelPrefix = 0x20, - MetaEndOfTrack = 0x2F, - MetaSetTempo = 0x51, - MetaSMPTEOffset = 0x54, - MetaTimeSignature = 0x58, - MetaKeySignature = 0x59, - MetaSequencerSpecific = 0x7F, - }; - -public: - MidiFile() - { - } - - MidiFile(const std::string& sFileName) - { - ParseFile(sFileName); - } - - void Clear() - { - - } - - bool ParseFile(const std::string& sFileName) - { - // Open the MIDI File as a stream - std::ifstream ifs; - ifs.open(sFileName, std::fstream::in | std::ios::binary); - if (!ifs.is_open()) - return false; - - - // Helper Utilities ==================== - - // Swaps byte order of 32-bit integer - auto Swap32 = [](uint32_t n) - { - return (((n >> 24) & 0xff) | ((n << 8) & 0xff0000) | ((n >> 8) & 0xff00) | ((n << 24) & 0xff000000)); - }; - - // Swaps byte order of 16-bit integer - auto Swap16 = [](uint16_t n) - { - return ((n >> 8) | (n << 8)); - }; - - // Reads nLength bytes form file stream, and constructs a text string - auto ReadString = [&ifs](uint32_t nLength) - { - std::string s; - for (uint32_t i = 0; i < nLength; i++) s += ifs.get(); - return s; - }; - - // Reads a compressed MIDI value. This can be up to 32 bits long. Essentially if the first byte, first - // bit is set to 1, that indicates that the next byte is required to construct the full word. Only - // the bottom 7 bits of each byte are used to construct the final word value. Each successive byte - // that has MSB set, indicates a further byte needs to be read. - auto ReadValue = [&ifs]() - { - uint32_t nValue = 0; - uint8_t nByte = 0; - - // Read byte - nValue = ifs.get(); - - // Check MSB, if set, more bytes need reading - if (nValue & 0x80) - { - // Extract bottom 7 bits of read byte - nValue &= 0x7F; - do - { - // Read next byte - nByte = ifs.get(); - - // Construct value by setting bottom 7 bits, then shifting 7 bits - nValue = (nValue << 7) | (nByte & 0x7F); - } - while (nByte & 0x80); // Loop whilst read byte MSB is 1 - } - - // Return final construction (always 32-bit unsigned integer internally) - return nValue; - }; - - uint32_t n32 = 0; - uint16_t n16 = 0; - - // Read MIDI Header (Fixed Size) - ifs.read((char*)&n32, sizeof(uint32_t)); - uint32_t nFileID = Swap32(n32); - ifs.read((char*)&n32, sizeof(uint32_t)); - uint32_t nHeaderLength = Swap32(n32); - ifs.read((char*)&n16, sizeof(uint16_t)); - uint16_t nFormat = Swap16(n16); - ifs.read((char*)&n16, sizeof(uint16_t)); - uint16_t nTrackChunks = Swap16(n16); - ifs.read((char*)&n16, sizeof(uint16_t)); - uint16_t nDivision = Swap16(n16); - - for (uint16_t nChunk = 0; nChunk < nTrackChunks; nChunk++) - { - std::cout << "===== NEW TRACK" << std::endl; - // Read Track Header - ifs.read((char*)&n32, sizeof(uint32_t)); - uint32_t nTrackID = Swap32(n32); - ifs.read((char*)&n32, sizeof(uint32_t)); - uint32_t nTrackLength = Swap32(n32); - - bool bEndOfTrack = false; - - vecTracks.push_back(MidiTrack()); - - uint32_t nWallTime = 0; - - uint8_t nPreviousStatus = 0; - - while (!ifs.eof() && !bEndOfTrack) - { - // Fundamentally all MIDI Events contain a timecode, and a status byte* - uint32_t nStatusTimeDelta = 0; - uint8_t nStatus = 0; - - - // Read Timecode from MIDI stream. This could be variable in length - // and is the delta in "ticks" from the previous event. Of course this value - // could be 0 if two events happen simultaneously. - nStatusTimeDelta = ReadValue(); - - // Read first byte of message, this could be the status byte, or it could not... - nStatus = ifs.get(); - - // All MIDI Status events have the MSB set. The data within a standard MIDI event - // does not. A crude yet utilised form of compression is to omit sending status - // bytes if the following sequence of events all refer to the same MIDI Status. - // This is called MIDI Running Status, and is essential to succesful decoding of - // MIDI streams and files. - // - // If the MSB of the read byte was not set, and on the whole we were expecting a - // status byte, then Running Status is in effect, so we refer to the previous - // confirmed status byte. - if (nStatus < 0x80) - { - // MIDI Running Status is happening, so refer to previous valid MIDI Status byte - nStatus = nPreviousStatus; - - // We had to read the byte to assess if MIDI Running Status is in effect. But! - // that read removed the byte form the stream, and that will desync all of the - // following code because normally we would have read a status byte, but instead - // we have read the data contained within a MIDI message. The simple solution is - // to put the byte back :P - ifs.seekg(-1, std::ios_base::cur); - } - - - - if ((nStatus & 0xF0) == EventName::VoiceNoteOff) - { - nPreviousStatus = nStatus; - uint8_t nChannel = nStatus & 0x0F; - uint8_t nNoteID = ifs.get(); - uint8_t nNoteVelocity = ifs.get(); - vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::NoteOff, nNoteID, nNoteVelocity, nStatusTimeDelta }); - } - - else if ((nStatus & 0xF0) == EventName::VoiceNoteOn) - { - nPreviousStatus = nStatus; - uint8_t nChannel = nStatus & 0x0F; - uint8_t nNoteID = ifs.get(); - uint8_t nNoteVelocity = ifs.get(); - if(nNoteVelocity == 0) - vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::NoteOff, nNoteID, nNoteVelocity, nStatusTimeDelta }); - else - vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::NoteOn, nNoteID, nNoteVelocity, nStatusTimeDelta }); - } - - else if ((nStatus & 0xF0) == EventName::VoiceAftertouch) - { - nPreviousStatus = nStatus; - uint8_t nChannel = nStatus & 0x0F; - uint8_t nNoteID = ifs.get(); - uint8_t nNoteVelocity = ifs.get(); - vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::Other }); - } - - else if ((nStatus & 0xF0) == EventName::VoiceControlChange) - { - nPreviousStatus = nStatus; - uint8_t nChannel = nStatus & 0x0F; - uint8_t nControlID = ifs.get(); - uint8_t nControlValue = ifs.get(); - vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::Other }); - } - - else if ((nStatus & 0xF0) == EventName::VoiceProgramChange) - { - nPreviousStatus = nStatus; - uint8_t nChannel = nStatus & 0x0F; - uint8_t nProgramID = ifs.get(); - vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::Other }); - } - - else if ((nStatus & 0xF0) == EventName::VoiceChannelPressure) - { - nPreviousStatus = nStatus; - uint8_t nChannel = nStatus & 0x0F; - uint8_t nChannelPressure = ifs.get(); - vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::Other }); - } - - else if ((nStatus & 0xF0) == EventName::VoicePitchBend) - { - nPreviousStatus = nStatus; - uint8_t nChannel = nStatus & 0x0F; - uint8_t nLS7B = ifs.get(); - uint8_t nMS7B = ifs.get(); - vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::Other }); - - } - - else if ((nStatus & 0xF0) == EventName::SystemExclusive) - { - nPreviousStatus = 0; - - if (nStatus == 0xFF) - { - // Meta Message - uint8_t nType = ifs.get(); - uint8_t nLength = ReadValue(); - - switch (nType) - { - case MetaSequence: - std::cout << "Sequence Number: " << ifs.get() << ifs.get() << std::endl; - break; - case MetaText: - std::cout << "Text: " << ReadString(nLength) << std::endl; - break; - case MetaCopyright: - std::cout << "Copyright: " << ReadString(nLength) << std::endl; - break; - case MetaTrackName: - vecTracks[nChunk].sName = ReadString(nLength); - std::cout << "Track Name: " << vecTracks[nChunk].sName << std::endl; - break; - case MetaInstrumentName: - vecTracks[nChunk].sInstrument = ReadString(nLength); - std::cout << "Instrument Name: " << vecTracks[nChunk].sInstrument << std::endl; - break; - case MetaLyrics: - std::cout << "Lyrics: " << ReadString(nLength) << std::endl; - break; - case MetaMarker: - std::cout << "Marker: " << ReadString(nLength) << std::endl; - break; - case MetaCuePoint: - std::cout << "Cue: " << ReadString(nLength) << std::endl; - break; - case MetaChannelPrefix: - std::cout << "Prefix: " << ifs.get() << std::endl; - break; - case MetaEndOfTrack: - bEndOfTrack = true; - break; - case MetaSetTempo: - // Tempo is in microseconds per quarter note - if (m_nTempo == 0) - { - (m_nTempo |= (ifs.get() << 16)); - (m_nTempo |= (ifs.get() << 8)); - (m_nTempo |= (ifs.get() << 0)); - m_nBPM = (60000000 / m_nTempo); - std::cout << "Tempo: " << m_nTempo << " (" << m_nBPM << "bpm)" << std::endl; - } - break; - case MetaSMPTEOffset: - std::cout << "SMPTE: H:" << ifs.get() << " M:" << ifs.get() << " S:" << ifs.get() << " FR:" << ifs.get() << " FF:" << ifs.get() << std::endl; - break; - case MetaTimeSignature: - std::cout << "Time Signature: " << ifs.get() << "/" << (2 << ifs.get()) << std::endl; - std::cout << "ClocksPerTick: " << ifs.get() << std::endl; - - // A MIDI "Beat" is 24 ticks, so specify how many 32nd notes constitute a beat - std::cout << "32per24Clocks: " << ifs.get() << std::endl; - break; - case MetaKeySignature: - std::cout << "Key Signature: " << ifs.get() << std::endl; - std::cout << "Minor Key: " << ifs.get() << std::endl; - break; - case MetaSequencerSpecific: - std::cout << "Sequencer Specific: " << ReadString(nLength) << std::endl; - break; - default: - std::cout << "Unrecognised MetaEvent: " << nType << std::endl; - } - } - - if (nStatus == 0xF0) - { - // System Exclusive Message Begin - std::cout << "System Exclusive Begin: " << ReadString(ReadValue()) << std::endl; - } - - if (nStatus == 0xF7) - { - // System Exclusive Message Begin - std::cout << "System Exclusive End: " << ReadString(ReadValue()) << std::endl; - } - } - else - { - std::cout << "Unrecognised Status Byte: " << nStatus << std::endl; - } - } - } - - - // Convert Time Events to Notes - for (auto& track : vecTracks) - { - uint32_t nWallTime = 0; - - std::list listNotesBeingProcessed; - - for (auto& event : track.vecEvents) - { - nWallTime += event.nDeltaTick; - - if (event.event == MidiEvent::Type::NoteOn) - { - // New Note - listNotesBeingProcessed.push_back({ event.nKey, event.nVelocity, nWallTime, 0 }); - } - - if (event.event == MidiEvent::Type::NoteOff) - { - auto note = std::find_if(listNotesBeingProcessed.begin(), listNotesBeingProcessed.end(), [&](const MidiNote& n) { return n.nKey == event.nKey; }); - if (note != listNotesBeingProcessed.end()) - { - note->nDuration = nWallTime - note->nStartTime; - track.vecNotes.push_back(*note); - track.nMinNote = std::min(track.nMinNote, note->nKey); - track.nMaxNote = std::max(track.nMaxNote, note->nKey); - listNotesBeingProcessed.erase(note); - } - } - } - } - - return true; - } - -public: - std::vector vecTracks; - uint32_t m_nTempo = 0; - uint32_t m_nBPM = 0; - -}; - - -class olcMIDIViewer : public olc::PixelGameEngine -{ -public: - olcMIDIViewer() - { - sAppName = "MIDI File Viewer"; - } - - - MidiFile midi; - - //HMIDIOUT hInstrument; - size_t nCurrentNote[16]{ 0 }; - - double dSongTime = 0.0; - double dRunTime = 0.0; - uint32_t nMidiClock = 0; - - -public: - bool OnUserCreate() override - { - - midi.ParseFile("ff7_battle.mid"); - - /* - int nMidiDevices = midiOutGetNumDevs(); - if (nMidiDevices > 0) - { - if (midiOutOpen(&hInstrument, 2, NULL, 0, NULL) == MMSYSERR_NOERROR) - { - std::cout << "Opened midi" << std::endl; - } - } - */ - - - return true; - } - - float nTrackOffset = 1000; - - bool OnUserUpdate(float fElapsedTime) override - { - Clear(olc::BLACK); - uint32_t nTimePerColumn = 50; - uint32_t nNoteHeight = 2; - uint32_t nOffsetY = 0; - - if (GetKey(olc::Key::LEFT).bHeld) nTrackOffset -= 10000.0f * fElapsedTime; - if (GetKey(olc::Key::RIGHT).bHeld) nTrackOffset += 10000.0f * fElapsedTime; - - - for (auto& track : midi.vecTracks) - { - if (!track.vecNotes.empty()) - { - uint32_t nNoteRange = track.nMaxNote - track.nMinNote; - - FillRect(0, nOffsetY, ScreenWidth(), (nNoteRange + 1) * nNoteHeight, olc::DARK_GREY); - DrawString(1, nOffsetY + 1, track.sName); - - for (auto& note : track.vecNotes) - { - FillRect((note.nStartTime - nTrackOffset) / nTimePerColumn, (nNoteRange - (note.nKey - track.nMinNote)) * nNoteHeight + nOffsetY, note.nDuration / nTimePerColumn, nNoteHeight, olc::WHITE); - } - - nOffsetY += (nNoteRange + 1) * nNoteHeight + 4; - } - } - - // BELOW - ABSOLUTELY HORRIBLE BODGE TO PLAY SOUND - // DO NOT USE THIS CODE... - - /* - dRunTime += fElapsedTime; - uint32_t nTempo = 4; - int nTrack = 1; - while (dRunTime >= 1.0 / double(midi.m_nBPM * 8)) - { - dRunTime -= 1.0 / double(midi.m_nBPM * 8); - - // Single MIDI Clock - nMidiClock++; - - int i = 0; - int nTrack = 1; - //for (nTrack = 1; nTrack < 3; nTrack++) - { - if (nCurrentNote[nTrack] < midi.vecTracks[nTrack].vecEvents.size()) - { - if (midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].nDeltaTick == 0) - { - uint32_t nStatus = 0; - uint32_t nNote = midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].nKey; - uint32_t nVelocity = midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].nVelocity; - - if (midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].event == MidiEvent::Type::NoteOn) - nStatus = 0x90; - else - nStatus = 0x80; - - midiOutShortMsg(hInstrument, (nVelocity << 16) | (nNote << 8) | nStatus); - nCurrentNote[nTrack]++; - } - else - midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].nDeltaTick--; - } - } - } - - if (GetKey(olc::Key::SPACE).bPressed) - { - midiOutShortMsg(hInstrument, 0x00403C90); - } - - if (GetKey(olc::Key::SPACE).bReleased) - { - midiOutShortMsg(hInstrument, 0x00003C80); - } - */ - - - return true; - } - - -}; - -int main() -{ - olcMIDIViewer demo; - if (demo.Construct(1280, 960, 1, 1)) - demo.Start(); - return 0; -} - diff --git a/Videos/OneLoneCoder_PGE_Mandelbrot.cpp b/Videos/OneLoneCoder_PGE_Mandelbrot.cpp deleted file mode 100644 index b371263..0000000 --- a/Videos/OneLoneCoder_PGE_Mandelbrot.cpp +++ /dev/null @@ -1,592 +0,0 @@ -/* - Brute Force Processing a Mandelbrot Renderer - "Dammit Moros & Saladin, you guys keep making tools, I'll have nothing left to video..." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Relevant Video: https://youtu.be/PBvLs88hvJ8 - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Community Blog: https://community.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019, 2020 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#include -#include -#include -#include -#include - -constexpr int nMaxThreads = 32; - -class olcFractalExplorer : public olc::PixelGameEngine -{ -public: - olcFractalExplorer() - { - sAppName = "Brute Force Processing"; - } - - int* pFractal = nullptr; - int nMode = 4; - int nIterations = 128; - -public: - bool OnUserCreate() override - { - //pFractal = new int[ScreenWidth() * ScreenHeight()]{ 0 }; - - // Using Vector extensions, align memory (not as necessary as it used to be) - // MS Specific - see std::aligned_alloc for others - pFractal = (int*)_aligned_malloc(size_t(ScreenWidth()) * size_t(ScreenHeight()) * sizeof(int), 64); - - InitialiseThreadPool(); - return true; - } - - bool OnUserDestroy() override - { - // Stop Worker threads - for (int i = 0; i < nMaxThreads; i++) - { - workers[i].alive = false; // Allow thread exit - workers[i].cvStart.notify_one(); // Fake starting gun - } - - // Clean up worker threads - for (int i = 0; i < nMaxThreads; i++) - workers[i].thread.join(); - - // Clean up memory - _aligned_free(pFractal); - return true; - } - - // Method 1) - Super simple, no effort at optimising - void CreateFractalBasic(const olc::vi2d& pix_tl, const olc::vi2d& pix_br, const olc::vd2d& frac_tl, const olc::vd2d& frac_br, const int iterations) - { - double x_scale = (frac_br.x - frac_tl.x) / (double(pix_br.x) - double(pix_tl.x)); - double y_scale = (frac_br.y - frac_tl.y) / (double(pix_br.y) - double(pix_tl.y)); - - for (int y = pix_tl.y; y < pix_br.y; y++) - { - for (int x = pix_tl.x; x < pix_br.x; x++) - { - std::complex c(x * x_scale + frac_tl.x, y * y_scale + frac_tl.y); - std::complex z(0, 0); - - int n = 0; - while (abs(z) < 2.0 && n < iterations) - { - z = (z * z) + c; - n++; - } - - pFractal[y * ScreenWidth() + x] = n; - } - } - } - - // Method 2) - Attempt to pre-calculate as much as possible, and reduce - // repeated multiplications - void CreateFractalPreCalculate(const olc::vi2d& pix_tl, const olc::vi2d& pix_br, const olc::vd2d& frac_tl, const olc::vd2d& frac_br, const int iterations) - { - double x_scale = (frac_br.x - frac_tl.x) / (double(pix_br.x) - double(pix_tl.x)); - double y_scale = (frac_br.y - frac_tl.y) / (double(pix_br.y) - double(pix_tl.y)); - - double x_pos = frac_tl.x; - double y_pos = frac_tl.y; - - int y_offset = 0; - int row_size = pix_br.x - pix_tl.x; - - int x, y, n; - std::complex c, z; - - for (y = pix_tl.y; y < pix_br.y; y++) - { - x_pos = frac_tl.x; - for (x = pix_tl.x; x < pix_br.x; x++) - { - c = { x_pos, y_pos }; - z = { 0,0 }; - - n = 0; - while (abs(z) < 2.0 && n < iterations) - { - z = (z * z) + c; - n++; - } - - pFractal[y_offset + x] = n; - x_pos += x_scale; - } - - y_pos += y_scale; - y_offset += row_size; - } - } - - - // Method 3) - Replace std::complex with just hard coded mathematics - void CreateFractalNoComplex(const olc::vi2d& pix_tl, const olc::vi2d& pix_br, const olc::vd2d& frac_tl, const olc::vd2d& frac_br, const int iterations) - { - double x_scale = (frac_br.x - frac_tl.x) / (double(pix_br.x) - double(pix_tl.x)); - double y_scale = (frac_br.y - frac_tl.y) / (double(pix_br.y) - double(pix_tl.y)); - - double x_pos = frac_tl.x; - double y_pos = frac_tl.y; - - int y_offset = 0; - int row_size = ScreenWidth(); - - int x, y, n; - - double cr = 0; - double ci = 0; - double zr = 0; - double zi = 0; - double re = 0; - double im = 0; - - for (y = pix_tl.y; y < pix_br.y; y++) - { - x_pos = frac_tl.x; - ci = y_pos; - for (x = pix_tl.x; x < pix_br.x; x++) - { - cr = x_pos; - zr = 0; - zi = 0; - - n = 0; - while ((zr * zr + zi * zi) < 4.0 && n < iterations) - { - re = zr * zr - zi * zi + cr; - im = zr * zi * 2.0 + ci; - zr = re; - zi = im; - n++; - } - - pFractal[y_offset + x] = n; - x_pos += x_scale; - } - - y_pos += y_scale; - y_offset += row_size; - } - } - - // Method 4) - Use AVX2 Vector co-processor to handle 4 fractal locations at once - void CreateFractalIntrinsics(const olc::vi2d& pix_tl, const olc::vi2d& pix_br, const olc::vd2d& frac_tl, const olc::vd2d& frac_br, const int iterations) - { - double x_scale = (frac_br.x - frac_tl.x) / (double(pix_br.x) - double(pix_tl.x)); - double y_scale = (frac_br.y - frac_tl.y) / (double(pix_br.y) - double(pix_tl.y)); - - double y_pos = frac_tl.y; - - int y_offset = 0; - int row_size = ScreenWidth(); - - int x, y; - - __m256d _a, _b, _two, _four, _mask1; - __m256d _zr, _zi, _zr2, _zi2, _cr, _ci; - __m256d _x_pos_offsets, _x_pos, _x_scale, _x_jump; - __m256i _one, _c, _n, _iterations, _mask2; - - _one = _mm256_set1_epi64x(1); - _two = _mm256_set1_pd(2.0); - _four = _mm256_set1_pd(4.0); - _iterations = _mm256_set1_epi64x(iterations); - - _x_scale = _mm256_set1_pd(x_scale); - _x_jump = _mm256_set1_pd(x_scale * 4); - _x_pos_offsets = _mm256_set_pd(0, 1, 2, 3); - _x_pos_offsets = _mm256_mul_pd(_x_pos_offsets, _x_scale); - - - for (y = pix_tl.y; y < pix_br.y; y++) - { - // Reset x_position - _a = _mm256_set1_pd(frac_tl.x); - _x_pos = _mm256_add_pd(_a, _x_pos_offsets); - - _ci = _mm256_set1_pd(y_pos); - - for (x = pix_tl.x; x < pix_br.x; x += 4) - { - _cr = _x_pos; - _zr = _mm256_setzero_pd(); - _zi = _mm256_setzero_pd(); - _n = _mm256_setzero_si256(); - - - repeat: - _zr2 = _mm256_mul_pd(_zr, _zr); - _zi2 = _mm256_mul_pd(_zi, _zi); - _a = _mm256_sub_pd(_zr2, _zi2); - _a = _mm256_add_pd(_a, _cr); - _b = _mm256_mul_pd(_zr, _zi); - _b = _mm256_fmadd_pd(_b, _two, _ci); - _zr = _a; - _zi = _b; - _a = _mm256_add_pd(_zr2, _zi2); - _mask1 = _mm256_cmp_pd(_a, _four, _CMP_LT_OQ); - _mask2 = _mm256_cmpgt_epi64(_iterations, _n); - _mask2 = _mm256_and_si256(_mask2, _mm256_castpd_si256(_mask1)); - _c = _mm256_and_si256(_one, _mask2); // Zero out ones where n < iterations - _n = _mm256_add_epi64(_n, _c); // n++ Increase all n - if (_mm256_movemask_pd(_mm256_castsi256_pd(_mask2)) > 0) - goto repeat; - - pFractal[y_offset + x + 0] = int(_n.m256i_i64[3]); - pFractal[y_offset + x + 1] = int(_n.m256i_i64[2]); - pFractal[y_offset + x + 2] = int(_n.m256i_i64[1]); - pFractal[y_offset + x + 3] = int(_n.m256i_i64[0]); - _x_pos = _mm256_add_pd(_x_pos, _x_jump); - } - - y_pos += y_scale; - y_offset += row_size; - } - } - - // Method 5) - Spawn threads that use AVX method above - void CreateFractalThreads(const olc::vi2d& pix_tl, const olc::vi2d& pix_br, const olc::vd2d& frac_tl, const olc::vd2d& frac_br, const int iterations) - { - int nSectionWidth = (pix_br.x - pix_tl.x) / nMaxThreads; - double dFractalWidth = (frac_br.x - frac_tl.x) / double(nMaxThreads); - - std::thread t[nMaxThreads]; - - for (size_t i = 0; i < nMaxThreads; i++) - t[i] = std::thread(&olcFractalExplorer::CreateFractalIntrinsics, this, - olc::vi2d(pix_tl.x + nSectionWidth * (i), pix_tl.y), - olc::vi2d(pix_tl.x + nSectionWidth * (i + 1), pix_br.y), - olc::vd2d(frac_tl.x + dFractalWidth * double(i), frac_tl.y), - olc::vd2d(frac_tl.x + dFractalWidth * double(i + 1), frac_br.y), - iterations); - - for (size_t i = 0; i < nMaxThreads; i++) - t[i].join(); - - } - - - // Method 6) - Threadpool, keep threads alive and reuse them, reducing setup overhead - struct WorkerThread - { - olc::vi2d pix_tl = { 0,0 }; - olc::vi2d pix_br = { 0,0 }; - olc::vd2d frac_tl = { 0,0 }; - olc::vd2d frac_br = { 0,0 }; - int iterations = 0; - std::condition_variable cvStart; - bool alive = true; - std::mutex mux; - int screen_width = 0; - int* fractal = nullptr; - - std::thread thread; - - void Start(const olc::vi2d& ptl, const olc::vi2d& pbr, const olc::vd2d& ftl, const olc::vd2d& fbr, const int it) - { - pix_tl = ptl; - pix_br = pbr; - frac_tl = ftl; - frac_br = fbr; - iterations = it; - std::unique_lock lm(mux); - cvStart.notify_one(); - } - - void CreateFractal() - { - while (alive) - { - std::unique_lock lm(mux); - cvStart.wait(lm); - - double x_scale = (frac_br.x - frac_tl.x) / (double(pix_br.x) - double(pix_tl.x)); - double y_scale = (frac_br.y - frac_tl.y) / (double(pix_br.y) - double(pix_tl.y)); - - double y_pos = frac_tl.y; - - int y_offset = 0; - int row_size = screen_width; - - int x, y; - - __m256d _a, _b, _two, _four, _mask1; - __m256d _zr, _zi, _zr2, _zi2, _cr, _ci; - __m256d _x_pos_offsets, _x_pos, _x_scale, _x_jump; - __m256i _one, _c, _n, _iterations, _mask2; - - _one = _mm256_set1_epi64x(1); - _two = _mm256_set1_pd(2.0); - _four = _mm256_set1_pd(4.0); - _iterations = _mm256_set1_epi64x(iterations); - - _x_scale = _mm256_set1_pd(x_scale); - _x_jump = _mm256_set1_pd(x_scale * 4); - _x_pos_offsets = _mm256_set_pd(0, 1, 2, 3); - _x_pos_offsets = _mm256_mul_pd(_x_pos_offsets, _x_scale); - - - for (y = pix_tl.y; y < pix_br.y; y++) - { - // Reset x_position - _a = _mm256_set1_pd(frac_tl.x); - _x_pos = _mm256_add_pd(_a, _x_pos_offsets); - - _ci = _mm256_set1_pd(y_pos); - - for (x = pix_tl.x; x < pix_br.x; x += 4) - { - _cr = _x_pos; - _zr = _mm256_setzero_pd(); - _zi = _mm256_setzero_pd(); - _n = _mm256_setzero_si256(); - - repeat: - _zr2 = _mm256_mul_pd(_zr, _zr); - _zi2 = _mm256_mul_pd(_zi, _zi); - _a = _mm256_sub_pd(_zr2, _zi2); - _a = _mm256_add_pd(_a, _cr); - _b = _mm256_mul_pd(_zr, _zi); - _b = _mm256_fmadd_pd(_b, _two, _ci); - _zr = _a; - _zi = _b; - _a = _mm256_add_pd(_zr2, _zi2); - _mask1 = _mm256_cmp_pd(_a, _four, _CMP_LT_OQ); - _mask2 = _mm256_cmpgt_epi64(_iterations, _n); - _mask2 = _mm256_and_si256(_mask2, _mm256_castpd_si256(_mask1)); - _c = _mm256_and_si256(_one, _mask2); // Zero out ones where n < iterations - _n = _mm256_add_epi64(_n, _c); // n++ Increase all n - if (_mm256_movemask_pd(_mm256_castsi256_pd(_mask2)) > 0) - goto repeat; - - fractal[y_offset + x + 0] = int(_n.m256i_i64[3]); - fractal[y_offset + x + 1] = int(_n.m256i_i64[2]); - fractal[y_offset + x + 2] = int(_n.m256i_i64[1]); - fractal[y_offset + x + 3] = int(_n.m256i_i64[0]); - _x_pos = _mm256_add_pd(_x_pos, _x_jump); - } - - y_pos += y_scale; - y_offset += row_size; - } - nWorkerComplete++; - } - } - }; - - WorkerThread workers[nMaxThreads]; - static std::atomic nWorkerComplete; - - void InitialiseThreadPool() - { - for (int i = 0; i < nMaxThreads; i++) - { - workers[i].alive = true; - workers[i].fractal = pFractal; - workers[i].screen_width = ScreenWidth(); - workers[i].thread = std::thread(&WorkerThread::CreateFractal, &workers[i]); - } - } - - void CreateFractalThreadPool(const olc::vi2d& pix_tl, const olc::vi2d& pix_br, const olc::vd2d& frac_tl, const olc::vd2d& frac_br, const int iterations) - { - int nSectionWidth = (pix_br.x - pix_tl.x) / nMaxThreads; - double dFractalWidth = (frac_br.x - frac_tl.x) / double(nMaxThreads); - nWorkerComplete = 0; - - for (size_t i = 0; i < nMaxThreads; i++) - workers[i].Start( - olc::vi2d(pix_tl.x + nSectionWidth * i, pix_tl.y), - olc::vi2d(pix_tl.x + nSectionWidth * (i + 1), pix_br.y), - olc::vd2d(frac_tl.x + dFractalWidth * double(i), frac_tl.y), - olc::vd2d(frac_tl.x + dFractalWidth * double(i + 1), frac_br.y), - iterations); - - - while (nWorkerComplete < nMaxThreads) // Wait for all workers to complete - { } - } - - - bool OnUserUpdate(float fElapsedTime) override - { - - // Get mouse location this frame - olc::vd2d vMouse = { (double)GetMouseX(), (double)GetMouseY() }; - - // Handle Pan & Zoom - if (GetMouse(2).bPressed) - { - vStartPan = vMouse; - } - - if (GetMouse(2).bHeld) - { - vOffset -= (vMouse - vStartPan) / vScale; - vStartPan = vMouse; - } - - olc::vd2d vMouseBeforeZoom; - ScreenToWorld(vMouse, vMouseBeforeZoom); - - if (GetKey(olc::Key::Q).bHeld || GetMouseWheel() > 0) vScale *= 1.1; - if (GetKey(olc::Key::A).bHeld || GetMouseWheel() < 0) vScale *= 0.9; - - olc::vd2d vMouseAfterZoom; - ScreenToWorld(vMouse, vMouseAfterZoom); - vOffset += (vMouseBeforeZoom - vMouseAfterZoom); - - olc::vi2d pix_tl = { 0,0 }; - olc::vi2d pix_br = { ScreenWidth(), ScreenHeight() }; - olc::vd2d frac_tl = { -2.0, -1.0 }; - olc::vd2d frac_br = { 1.0, 1.0 }; - - ScreenToWorld(pix_tl, frac_tl); - ScreenToWorld(pix_br, frac_br); - - // Handle User Input - if (GetKey(olc::K1).bPressed) nMode = 0; - if (GetKey(olc::K2).bPressed) nMode = 1; - if (GetKey(olc::K3).bPressed) nMode = 2; - if (GetKey(olc::K4).bPressed) nMode = 3; - if (GetKey(olc::K5).bPressed) nMode = 4; - if (GetKey(olc::K6).bPressed) nMode = 5; - if (GetKey(olc::UP).bPressed) nIterations += 64; - if (GetKey(olc::DOWN).bPressed) nIterations -= 64; - if (nIterations < 64) nIterations = 64; - - - // START TIMING - auto tp1 = std::chrono::high_resolution_clock::now(); - - // Do the computation - switch (nMode) - { - case 0: CreateFractalBasic(pix_tl, pix_br, frac_tl, frac_br, nIterations); break; - case 1: CreateFractalPreCalculate(pix_tl, pix_br, frac_tl, frac_br, nIterations); break; - case 2: CreateFractalNoComplex(pix_tl, pix_br, frac_tl, frac_br, nIterations); break; - case 3: CreateFractalIntrinsics(pix_tl, pix_br, frac_tl, frac_br, nIterations); break; - case 4: CreateFractalThreads(pix_tl, pix_br, frac_tl, frac_br, nIterations); break; - case 5: CreateFractalThreadPool(pix_tl, pix_br, frac_tl, frac_br, nIterations); break; - } - - // STOP TIMING - auto tp2 = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsedTime = tp2 - tp1; - - - // Render result to screen - for (int y = 0; y < ScreenHeight(); y++) - { - for (int x = 0; x < ScreenWidth(); x++) - { - int i = pFractal[y * ScreenWidth() + x]; - float n = (float)i; - float a = 0.1f; - // Thank you @Eriksonn - Wonderful Magic Fractal Oddball Man - Draw(x, y, olc::PixelF(0.5f * sin(a * n) + 0.5f, 0.5f * sin(a * n + 2.094f) + 0.5f, 0.5f * sin(a * n + 4.188f) + 0.5f)); - } - } - - // Render UI - switch (nMode) - { - case 0: DrawString(0, 0, "1) Naive Method", olc::WHITE, 3); break; - case 1: DrawString(0, 0, "2) Precalculate Method", olc::WHITE, 3); break; - case 2: DrawString(0, 0, "3) Hand-code Maths Method", olc::WHITE, 3); break; - case 3: DrawString(0, 0, "4) Vector Extensions (AVX2) Method", olc::WHITE, 3); break; - case 4: DrawString(0, 0, "5) Threads Method", olc::WHITE, 3); break; - case 5: DrawString(0, 0, "6) ThreadPool Method", olc::WHITE, 3); break; - } - - DrawString(0, 30, "Time Taken: " + std::to_string(elapsedTime.count()) + "s", olc::WHITE, 3); - DrawString(0, 60, "Iterations: " + std::to_string(nIterations), olc::WHITE, 3); - return !(GetKey(olc::Key::ESCAPE).bPressed); - } - - // Pan & Zoom variables - olc::vd2d vOffset = { 0.0, 0.0 }; - olc::vd2d vStartPan = { 0.0, 0.0 }; - olc::vd2d vScale = { 1280.0 / 2.0, 720.0 }; - - - // Convert coordinates from World Space --> Screen Space - void WorldToScreen(const olc::vd2d& v, olc::vi2d &n) - { - n.x = (int)((v.x - vOffset.x) * vScale.x); - n.y = (int)((v.y - vOffset.y) * vScale.y); - } - - // Convert coordinates from Screen Space --> World Space - void ScreenToWorld(const olc::vi2d& n, olc::vd2d& v) - { - v.x = (double)(n.x) / vScale.x + vOffset.x; - v.y = (double)(n.y) / vScale.y + vOffset.y; - } -}; - -std::atomic olcFractalExplorer::nWorkerComplete = 0; - -int main() -{ - olcFractalExplorer demo; - if (demo.Construct(1280, 720, 1, 1, false, false)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_PathFinding_WaveProp.cpp b/Videos/OneLoneCoder_PGE_PathFinding_WaveProp.cpp deleted file mode 100644 index 0648983..0000000 --- a/Videos/OneLoneCoder_PGE_PathFinding_WaveProp.cpp +++ /dev/null @@ -1,426 +0,0 @@ -/* - OneLoneCoder.com - Path Finding #2 - Wave Propagation & Potential Fields - "...never get lost again, so long as you know where you are" - @Javidx9 - - - Background - ~~~~~~~~~~ - A nice follow up alternative to the A* Algorithm. Wave propagation is less - applicable to multiple objects with multiple destinations, but fantatsic - for multiple objects all reaching the same destination. - - WARNING! This code is NOT OPTIMAL!! It is however very robust. There - are many ways to optimise this further. - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon/javidx9 - Homepage: https://www.onelonecoder.com - - Relevant Videos - ~~~~~~~~~~~~~~~ - Part #1 https://youtu.be/icZj67PTFhc - Part #2 https://youtu.be/0ihciMKlcP8 - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018 -*/ -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#include -#include -#include -#include - - -// Override base class with your custom functionality -class PathFinding_FlowFields : public olc::PixelGameEngine -{ -public: - PathFinding_FlowFields() - { - sAppName = "PathFinding - Flow Fields"; - } - -private: - int nMapWidth; - int nMapHeight; - int nCellSize; - int nBorderWidth; - - bool *bObstacleMap; - - int *nFlowFieldZ; - float *fFlowFieldY; - float *fFlowFieldX; - - int nStartX; - int nStartY; - int nEndX; - int nEndY; - - int nWave = 1; - -public: - bool OnUserCreate() override - { - nBorderWidth = 4; - nCellSize = 32; - nMapWidth = ScreenWidth() / nCellSize; - nMapHeight = ScreenHeight() / nCellSize; - bObstacleMap = new bool[nMapWidth * nMapHeight]{ false }; - nFlowFieldZ = new int[nMapWidth * nMapHeight]{ 0 }; - fFlowFieldX = new float[nMapWidth * nMapHeight]{ 0 }; - fFlowFieldY = new float[nMapWidth * nMapHeight]{ 0 }; - - nStartX = 3; - nStartY = 7; - nEndX = 12; - nEndY = 7; - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - // Little convenience lambda 2D -> 1D - auto p = [&](int x, int y) { return y * nMapWidth + x; }; - - // User Input - int nSelectedCellX = GetMouseX() / nCellSize; - int nSelectedCellY = GetMouseY() / nCellSize; - - if (GetMouse(0).bReleased) - { - // Toggle Obstacle if mouse left clicked - bObstacleMap[p(nSelectedCellX, nSelectedCellY)] = - !bObstacleMap[p(nSelectedCellX, nSelectedCellY)]; - } - - if (GetMouse(1).bReleased) - { - nStartX = nSelectedCellX; - nStartY = nSelectedCellY; - } - - if (GetKey(olc::Key::Q).bReleased) - { - nWave++; - } - - if (GetKey(olc::Key::A).bReleased) - { - nWave--; - if (nWave == 0) - nWave = 1; - } - - - - // 1) Prepare flow field, add a boundary, and add obstacles - // by setting the flow Field Height (Z) to -1 - for (int x = 0; x < nMapWidth; x++) - { - for (int y = 0; y < nMapHeight; y++) - { - // Set border or obstacles - if (x == 0 || y == 0 || x == (nMapWidth - 1) || y == (nMapHeight - 1) || bObstacleMap[p(x, y)]) - { - nFlowFieldZ[p(x, y)] = -1; - } - else - { - nFlowFieldZ[p(x, y)] = 0; - } - } - } - - // 2) Propagate a wave (i.e. flood-fill) from target location. Here I use - // a tuple, of {x, y, distance} - though you could use a struct or - // similar. - std::list> nodes; - - // Add the first discovered node - the target location, with a distance of 1 - nodes.push_back({ nEndX, nEndY, 1 }); - - while (!nodes.empty()) - { - // Each iteration through the discovered nodes may create newly discovered - // nodes, so I maintain a second list. It's important not to contaminate - // the list being iterated through. - std::list> new_nodes; - - // Now iterate through each discovered node. If it has neighbouring nodes - // that are empty space and undiscovered, add those locations to the - // new nodes list - for (auto &n : nodes) - { - int x = std::get<0>(n); // Map X-Coordinate - int y = std::get<1>(n); // Map Y-Coordinate - int d = std::get<2>(n); // Distance From Target Location - - // Set distance count for this node. NOte that when we add nodes we add 1 - // to this distance. This emulates propagating a wave across the map, where - // the front of that wave increments each iteration. In this way, we can - // propagate distance information 'away from target location' - nFlowFieldZ[p(x, y)] = d; - - // Add neigbour nodes if unmarked, i.e their "height" is 0. Any discovered - // node or obstacle will be non-zero - - // Check East - if ((x + 1) < nMapWidth && nFlowFieldZ[p(x + 1, y)] == 0) - new_nodes.push_back({ x + 1, y, d + 1 }); - - // Check West - if ((x - 1) >= 0 && nFlowFieldZ[p(x - 1, y)] == 0) - new_nodes.push_back({ x - 1, y, d + 1 }); - - // Check South - if ((y + 1) < nMapHeight && nFlowFieldZ[p(x, y + 1)] == 0) - new_nodes.push_back({ x, y + 1, d + 1 }); - - // Check North - if ((y - 1) >= 0 && nFlowFieldZ[p(x, y - 1)] == 0) - new_nodes.push_back({ x, y - 1, d + 1 }); - } - - // We will now have potentially multiple nodes for a single location. This means our - // algorithm will never complete! So we must remove duplicates form our new node list. - // Im doing this with some clever code - but it is not performant(!) - it is merely - // convenient. I'd suggest doing away with overhead structures like linked lists and sorts - // if you are aiming for fastest path finding. - - // Sort the nodes - This will stack up nodes that are similar: A, B, B, B, B, C, D, D, E, F, F - new_nodes.sort([&](const std::tuple &n1, const std::tuple &n2) - { - // In this instance I dont care how the values are sorted, so long as nodes that - // represent the same location are adjacent in the list. I can use the p() lambda - // to generate a unique 1D value for a 2D coordinate, so I'll sort by that. - return p(std::get<0>(n1), std::get<1>(n1)) < p(std::get<0>(n2), std::get<1>(n2)); - }); - - // Use "unique" function to remove adjacent duplicates : A, B, -, -, -, C, D, -, E, F - - // and also erase them : A, B, C, D, E, F - new_nodes.unique([&](const std::tuple &n1, const std::tuple &n2) - { - return p(std::get<0>(n1), std::get<1>(n1)) == p(std::get<0>(n2), std::get<1>(n2)); - }); - - // We've now processed all the discoverd nodes, so clear the list, and add the newly - // discovered nodes for processing on the next iteration - nodes.clear(); - nodes.insert(nodes.begin(), new_nodes.begin(), new_nodes.end()); - - // When there are no more newly discovered nodes, we have "flood filled" the entire - // map. The propagation phase of the algorithm is complete - } - - - // 3) Create Path. Starting a start location, create a path of nodes until you reach target - // location. At each node find the neighbour with the lowest "distance" score. - std::list> path; - path.push_back({ nStartX, nStartY }); - int nLocX = nStartX; - int nLocY = nStartY; - bool bNoPath = false; - - while (!(nLocX == nEndX && nLocY == nEndY) && !bNoPath) - { - std::list> listNeighbours; - - // 4-Way Connectivity - if ((nLocY - 1) >= 0 && nFlowFieldZ[p(nLocX, nLocY - 1)] > 0) - listNeighbours.push_back({ nLocX, nLocY - 1, nFlowFieldZ[p(nLocX, nLocY - 1)] }); - - if ((nLocX + 1) < nMapWidth && nFlowFieldZ[p(nLocX + 1, nLocY)] > 0) - listNeighbours.push_back({ nLocX + 1, nLocY, nFlowFieldZ[p(nLocX + 1, nLocY)] }); - - if ((nLocY + 1) < nMapHeight && nFlowFieldZ[p(nLocX, nLocY + 1)] > 0) - listNeighbours.push_back({ nLocX, nLocY + 1, nFlowFieldZ[p(nLocX, nLocY + 1)] }); - - if ((nLocX - 1) >= 0 && nFlowFieldZ[p(nLocX - 1, nLocY)] > 0) - listNeighbours.push_back({ nLocX - 1, nLocY, nFlowFieldZ[p(nLocX - 1, nLocY)] }); - - // 8-Way Connectivity - if ((nLocY - 1) >= 0 && (nLocX - 1) >= 0 && nFlowFieldZ[p(nLocX - 1, nLocY - 1)] > 0) - listNeighbours.push_back({ nLocX - 1, nLocY - 1, nFlowFieldZ[p(nLocX - 1, nLocY - 1)] }); - - if ((nLocY - 1) >= 0 && (nLocX + 1) < nMapWidth && nFlowFieldZ[p(nLocX + 1, nLocY - 1)] > 0) - listNeighbours.push_back({ nLocX + 1, nLocY - 1, nFlowFieldZ[p(nLocX + 1, nLocY - 1)] }); - - if ((nLocY + 1) < nMapHeight && (nLocX - 1) >= 0 && nFlowFieldZ[p(nLocX - 1, nLocY + 1)] > 0) - listNeighbours.push_back({ nLocX - 1, nLocY + 1, nFlowFieldZ[p(nLocX - 1, nLocY + 1)] }); - - if ((nLocY + 1) < nMapHeight && (nLocX + 1) < nMapWidth && nFlowFieldZ[p(nLocX + 1, nLocY + 1)] > 0) - listNeighbours.push_back({ nLocX + 1, nLocY + 1, nFlowFieldZ[p(nLocX + 1, nLocY + 1)] }); - - // Sprt neigbours based on height, so lowest neighbour is at front - // of list - listNeighbours.sort([&](const std::tuple &n1, const std::tuple &n2) - { - return std::get<2>(n1) < std::get<2>(n2); // Compare distances - }); - - if (listNeighbours.empty()) // Neighbour is invalid or no possible path - bNoPath = true; - else - { - nLocX = std::get<0>(listNeighbours.front()); - nLocY = std::get<1>(listNeighbours.front()); - path.push_back({ nLocX, nLocY }); - } - } - - - // 4) Create Flow "Field" - for (int x = 1; x < nMapWidth - 1; x++) - { - for (int y = 1; y < nMapHeight - 1; y++) - { - float vx = 0.0f; - float vy = 0.0f; - - vy -= (float)((nFlowFieldZ[p(x, y + 1)] <= 0 ? nFlowFieldZ[p(x, y)] : nFlowFieldZ[p(x, y + 1)]) - nFlowFieldZ[p(x, y)]); - vx -= (float)((nFlowFieldZ[p(x + 1, y)] <= 0 ? nFlowFieldZ[p(x, y)] : nFlowFieldZ[p(x + 1, y)]) - nFlowFieldZ[p(x, y)]); - vy += (float)((nFlowFieldZ[p(x, y - 1)] <= 0 ? nFlowFieldZ[p(x, y)] : nFlowFieldZ[p(x, y - 1)]) - nFlowFieldZ[p(x, y)]); - vx += (float)((nFlowFieldZ[p(x - 1, y)] <= 0 ? nFlowFieldZ[p(x, y)] : nFlowFieldZ[p(x - 1, y)]) - nFlowFieldZ[p(x, y)]); - - float r = 1.0f / sqrtf(vx*vx + vy * vy); - fFlowFieldX[p(x, y)] = vx * r; - fFlowFieldY[p(x, y)] = vy * r; - } - } - - - - - // Draw Map - Clear(olc::BLACK); - - for (int x = 0; x < nMapWidth; x++) - { - for (int y = 0; y < nMapHeight; y++) - { - olc::Pixel colour = olc::BLUE; - - if (bObstacleMap[p(x, y)]) - colour = olc::GREY; - - if (nWave == nFlowFieldZ[p(x, y)]) - colour = olc::DARK_CYAN; - - if (x == nStartX && y == nStartY) - colour = olc::GREEN; - - if (x == nEndX && y == nEndY) - colour = olc::RED; - - // Draw Base - FillRect(x * nCellSize, y * nCellSize, nCellSize - nBorderWidth, nCellSize - nBorderWidth, colour); - - // Draw "potential" or "distance" or "height" :D - //DrawString(x * nCellSize, y * nCellSize, std::to_string(nFlowFieldZ[p(x, y)]), olc::WHITE); - - if (nFlowFieldZ[p(x, y)] > 0) - { - float ax[4], ay[4]; - float fAngle = atan2f(fFlowFieldY[p(x, y)], fFlowFieldX[p(x, y)]); - float fRadius = (float)(nCellSize - nBorderWidth) / 2.0f; - int fOffsetX = x * nCellSize + ((nCellSize - nBorderWidth) / 2); - int fOffsetY = y * nCellSize + ((nCellSize - nBorderWidth) / 2); - ax[0] = cosf(fAngle) * fRadius + fOffsetX; - ay[0] = sinf(fAngle) * fRadius + fOffsetY; - ax[1] = cosf(fAngle) * -fRadius + fOffsetX; - ay[1] = sinf(fAngle) * -fRadius + fOffsetY; - ax[2] = cosf(fAngle + 0.1f) * fRadius * 0.7f + fOffsetX; - ay[2] = sinf(fAngle + 0.1f) * fRadius * 0.7f + fOffsetY; - ax[3] = cosf(fAngle - 0.1f) * fRadius * 0.7f + fOffsetX; - ay[3] = sinf(fAngle - 0.1f) * fRadius * 0.7f + fOffsetY; - - DrawLine(ax[0], ay[0], ax[1], ay[1], olc::CYAN); - DrawLine(ax[0], ay[0], ax[2], ay[2], olc::CYAN); - DrawLine(ax[0], ay[0], ax[3], ay[3], olc::CYAN); - - } - } - } - - - bool bFirstPoint = true; - int ox, oy; - for (auto &a : path) - { - if (bFirstPoint) - { - ox = a.first; - oy = a.second; - bFirstPoint = false; - } - else - { - DrawLine( - ox * nCellSize + ((nCellSize - nBorderWidth) / 2), - oy * nCellSize + ((nCellSize - nBorderWidth) / 2), - a.first * nCellSize + ((nCellSize - nBorderWidth) / 2), - a.second * nCellSize + ((nCellSize - nBorderWidth) / 2), olc::YELLOW); - - ox = a.first; - oy = a.second; - - FillCircle(ox * nCellSize + ((nCellSize - nBorderWidth) / 2), oy * nCellSize + ((nCellSize - nBorderWidth) / 2), 10, olc::YELLOW); - } - } - - - return true; - } -}; - - -int main() -{ - PathFinding_FlowFields demo; - if (demo.Construct(512, 480, 2, 2)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_PolygonCollisions1.cpp b/Videos/OneLoneCoder_PGE_PolygonCollisions1.cpp deleted file mode 100644 index e3b95c8..0000000 --- a/Videos/OneLoneCoder_PGE_PolygonCollisions1.cpp +++ /dev/null @@ -1,434 +0,0 @@ -/* - Convex Polygon Collision Detection - "Don't you dare try concave ones..." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Instructions: - ~~~~~~~~~~~~~ - Use arrow keys to control pentagon - Use WASD to control triangle - F1..F4 selects algorithm - - Relevant Video: https://youtu.be/7Ik2vowGcU0 - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#include -#include - -// Override base class with your custom functionality -class PolygonCollisions : public olc::PixelGameEngine -{ -public: - PolygonCollisions() - { - sAppName = "Polygon Collisions"; - } - - struct vec2d - { - float x; - float y; - }; - - struct polygon - { - std::vector p; // Transformed Points - vec2d pos; // Position of shape - float angle; // Direction of shape - std::vector o; // "Model" of shape - bool overlap = false; // Flag to indicate if overlap has occurred - }; - - std::vector vecShapes; - - int nMode = 0; - -public: - bool OnUserCreate() override - { - // Create Pentagon - polygon s1; - float fTheta = 3.14159f * 2.0f / 5.0f; - s1.pos = { 100, 100 }; - s1.angle = 0.0f; - for (int i = 0; i < 5; i++) - { - s1.o.push_back({ 30.0f * cosf(fTheta * i), 30.0f * sinf(fTheta * i) }); - s1.p.push_back({ 30.0f * cosf(fTheta * i), 30.0f * sinf(fTheta * i) }); - } - - // Create Triangle - polygon s2; - fTheta = 3.14159f * 2.0f / 3.0f; - s2.pos = { 200, 150 }; - s2.angle = 0.0f; - for (int i = 0; i < 3; i++) - { - s2.o.push_back({ 20.0f * cosf(fTheta * i), 20.0f * sinf(fTheta * i) }); - s2.p.push_back({ 20.0f * cosf(fTheta * i), 20.0f * sinf(fTheta * i) }); - } - - // Create Quad - polygon s3; - s3.pos = { 50, 200 }; - s3.angle = 0.0f; - s3.o.push_back({ -30, -30 }); - s3.o.push_back({ -30, +30 }); - s3.o.push_back({ +30, +30 }); - s3.o.push_back({ +30, -30 }); - s3.p.resize(4); - - - vecShapes.push_back(s1); - vecShapes.push_back(s2); - vecShapes.push_back(s3); - return true; - } - - - - bool ShapeOverlap_SAT(polygon &r1, polygon &r2) - { - polygon *poly1 = &r1; - polygon *poly2 = &r2; - - for (int shape = 0; shape < 2; shape++) - { - if (shape == 1) - { - poly1 = &r2; - poly2 = &r1; - } - - for (int a = 0; a < poly1->p.size(); a++) - { - int b = (a + 1) % poly1->p.size(); - vec2d axisProj = { -(poly1->p[b].y - poly1->p[a].y), poly1->p[b].x - poly1->p[a].x }; - float d = sqrtf(axisProj.x * axisProj.x + axisProj.y * axisProj.y); - axisProj = { axisProj.x / d, axisProj.y / d }; - - // Work out min and max 1D points for r1 - float min_r1 = INFINITY, max_r1 = -INFINITY; - for (int p = 0; p < poly1->p.size(); p++) - { - float q = (poly1->p[p].x * axisProj.x + poly1->p[p].y * axisProj.y); - min_r1 = std::min(min_r1, q); - max_r1 = std::max(max_r1, q); - } - - // Work out min and max 1D points for r2 - float min_r2 = INFINITY, max_r2 = -INFINITY; - for (int p = 0; p < poly2->p.size(); p++) - { - float q = (poly2->p[p].x * axisProj.x + poly2->p[p].y * axisProj.y); - min_r2 = std::min(min_r2, q); - max_r2 = std::max(max_r2, q); - } - - if (!(max_r2 >= min_r1 && max_r1 >= min_r2)) - return false; - } - } - - return true; - } - - bool ShapeOverlap_SAT_STATIC(polygon &r1, polygon &r2) - { - polygon *poly1 = &r1; - polygon *poly2 = &r2; - - float overlap = INFINITY; - - for (int shape = 0; shape < 2; shape++) - { - if (shape == 1) - { - poly1 = &r2; - poly2 = &r1; - } - - for (int a = 0; a < poly1->p.size(); a++) - { - int b = (a + 1) % poly1->p.size(); - vec2d axisProj = { -(poly1->p[b].y - poly1->p[a].y), poly1->p[b].x - poly1->p[a].x }; - - // Optional normalisation of projection axis enhances stability slightly - //float d = sqrtf(axisProj.x * axisProj.x + axisProj.y * axisProj.y); - //axisProj = { axisProj.x / d, axisProj.y / d }; - - // Work out min and max 1D points for r1 - float min_r1 = INFINITY, max_r1 = -INFINITY; - for (int p = 0; p < poly1->p.size(); p++) - { - float q = (poly1->p[p].x * axisProj.x + poly1->p[p].y * axisProj.y); - min_r1 = std::min(min_r1, q); - max_r1 = std::max(max_r1, q); - } - - // Work out min and max 1D points for r2 - float min_r2 = INFINITY, max_r2 = -INFINITY; - for (int p = 0; p < poly2->p.size(); p++) - { - float q = (poly2->p[p].x * axisProj.x + poly2->p[p].y * axisProj.y); - min_r2 = std::min(min_r2, q); - max_r2 = std::max(max_r2, q); - } - - // Calculate actual overlap along projected axis, and store the minimum - overlap = std::min(std::min(max_r1, max_r2) - std::max(min_r1, min_r2), overlap); - - if (!(max_r2 >= min_r1 && max_r1 >= min_r2)) - return false; - } - } - - // If we got here, the objects have collided, we will displace r1 - // by overlap along the vector between the two object centers - vec2d d = { r2.pos.x - r1.pos.x, r2.pos.y - r1.pos.y }; - float s = sqrtf(d.x*d.x + d.y*d.y); - r1.pos.x -= overlap * d.x / s; - r1.pos.y -= overlap * d.y / s; - return false; - } - - // Use edge/diagonal intersections. - bool ShapeOverlap_DIAGS(polygon &r1, polygon &r2) - { - polygon *poly1 = &r1; - polygon *poly2 = &r2; - - for (int shape = 0; shape < 2; shape++) - { - if (shape == 1) - { - poly1 = &r2; - poly2 = &r1; - } - - // Check diagonals of polygon... - for (int p = 0; p < poly1->p.size(); p++) - { - vec2d line_r1s = poly1->pos; - vec2d line_r1e = poly1->p[p]; - - // ...against edges of the other - for (int q = 0; q < poly2->p.size(); q++) - { - vec2d line_r2s = poly2->p[q]; - vec2d line_r2e = poly2->p[(q + 1) % poly2->p.size()]; - - // Standard "off the shelf" line segment intersection - float h = (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r1e.y) - (line_r1s.x - line_r1e.x) * (line_r2e.y - line_r2s.y); - float t1 = ((line_r2s.y - line_r2e.y) * (line_r1s.x - line_r2s.x) + (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r2s.y)) / h; - float t2 = ((line_r1s.y - line_r1e.y) * (line_r1s.x - line_r2s.x) + (line_r1e.x - line_r1s.x) * (line_r1s.y - line_r2s.y)) / h; - - if (t1 >= 0.0f && t1 < 1.0f && t2 >= 0.0f && t2 < 1.0f) - { - return true; - } - } - } - } - return false; - } - - // Use edge/diagonal intersections. - bool ShapeOverlap_DIAGS_STATIC(polygon &r1, polygon &r2) - { - polygon *poly1 = &r1; - polygon *poly2 = &r2; - - for (int shape = 0; shape < 2; shape++) - { - if (shape == 1) - { - poly1 = &r2; - poly2 = &r1; - } - - // Check diagonals of this polygon... - for (int p = 0; p < poly1->p.size(); p++) - { - vec2d line_r1s = poly1->pos; - vec2d line_r1e = poly1->p[p]; - - vec2d displacement = { 0,0 }; - - // ...against edges of this polygon - for (int q = 0; q < poly2->p.size(); q++) - { - vec2d line_r2s = poly2->p[q]; - vec2d line_r2e = poly2->p[(q + 1) % poly2->p.size()]; - - // Standard "off the shelf" line segment intersection - float h = (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r1e.y) - (line_r1s.x - line_r1e.x) * (line_r2e.y - line_r2s.y); - float t1 = ((line_r2s.y - line_r2e.y) * (line_r1s.x - line_r2s.x) + (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r2s.y)) / h; - float t2 = ((line_r1s.y - line_r1e.y) * (line_r1s.x - line_r2s.x) + (line_r1e.x - line_r1s.x) * (line_r1s.y - line_r2s.y)) / h; - - if (t1 >= 0.0f && t1 < 1.0f && t2 >= 0.0f && t2 < 1.0f) - { - displacement.x += (1.0f - t1) * (line_r1e.x - line_r1s.x); - displacement.y += (1.0f - t1) * (line_r1e.y - line_r1s.y); - } - } - - r1.pos.x += displacement.x * (shape == 0 ? -1 : +1); - r1.pos.y += displacement.y * (shape == 0 ? -1 : +1); - } - } - - // Cant overlap if static collision is resolved - return false; - } - - - - bool OnUserUpdate(float fElapsedTime) override - { - if (GetKey(olc::Key::F1).bReleased) nMode = 0; - if (GetKey(olc::Key::F2).bReleased) nMode = 1; - if (GetKey(olc::Key::F3).bReleased) nMode = 2; - if (GetKey(olc::Key::F4).bReleased) nMode = 3; - - // Shape 1 - if (GetKey(olc::Key::LEFT).bHeld) vecShapes[0].angle -= 2.0f * fElapsedTime; - if (GetKey(olc::Key::RIGHT).bHeld) vecShapes[0].angle += 2.0f * fElapsedTime; - - if (GetKey(olc::Key::UP).bHeld) - { - vecShapes[0].pos.x += cosf(vecShapes[0].angle) * 60.0f * fElapsedTime; - vecShapes[0].pos.y += sinf(vecShapes[0].angle) * 60.0f * fElapsedTime; - } - - if (GetKey(olc::Key::DOWN).bHeld) - { - vecShapes[0].pos.x -= cosf(vecShapes[0].angle) * 60.0f * fElapsedTime; - vecShapes[0].pos.y -= sinf(vecShapes[0].angle) * 60.0f * fElapsedTime; - } - - // Shape 2 - if (GetKey(olc::Key::A).bHeld) vecShapes[1].angle -= 2.0f * fElapsedTime; - if (GetKey(olc::Key::D).bHeld) vecShapes[1].angle += 2.0f * fElapsedTime; - - if (GetKey(olc::Key::W).bHeld) - { - vecShapes[1].pos.x += cosf(vecShapes[1].angle) * 60.0f * fElapsedTime; - vecShapes[1].pos.y += sinf(vecShapes[1].angle) * 60.0f * fElapsedTime; - } - - if (GetKey(olc::Key::S).bHeld) - { - vecShapes[1].pos.x -= cosf(vecShapes[1].angle) * 60.0f * fElapsedTime; - vecShapes[1].pos.y -= sinf(vecShapes[1].angle) * 60.0f * fElapsedTime; - } - - // Update Shapes and reset flags - for (auto &r : vecShapes) - { - for (int i = 0; i < r.o.size(); i++) - r.p[i] = - { // 2D Rotation Transform + 2D Translation - (r.o[i].x * cosf(r.angle)) - (r.o[i].y * sinf(r.angle)) + r.pos.x, - (r.o[i].x * sinf(r.angle)) + (r.o[i].y * cosf(r.angle)) + r.pos.y, - }; - - r.overlap = false; - } - - // Check for overlap - for (int m = 0; m < vecShapes.size(); m++) - for (int n = m + 1; n < vecShapes.size(); n++) - { - switch (nMode) - { - case 0: vecShapes[m].overlap |= ShapeOverlap_SAT(vecShapes[m], vecShapes[n]); break; - case 1: vecShapes[m].overlap |= ShapeOverlap_SAT_STATIC(vecShapes[m], vecShapes[n]); break; - case 2: vecShapes[m].overlap |= ShapeOverlap_DIAGS(vecShapes[m], vecShapes[n]); break; - case 3: vecShapes[m].overlap |= ShapeOverlap_DIAGS_STATIC(vecShapes[m], vecShapes[n]); break; - } - } - - // === Render Display === - Clear(olc::BLUE); - - // Draw Shapes - for (auto &r : vecShapes) - { - // Draw Boundary - for (int i = 0; i < r.p.size(); i++) - DrawLine(r.p[i].x, r.p[i].y, r.p[(i + 1) % r.p.size()].x, r.p[(i + 1) % r.p.size()].y, (r.overlap ? olc::RED : olc::WHITE)); - - // Draw Direction - DrawLine(r.p[0].x, r.p[0].y, r.pos.x, r.pos.y, (r.overlap ? olc::RED : olc::WHITE)); - } - - // Draw HUD - DrawString(8, 10, "F1: SAT", (nMode == 0 ? olc::RED : olc::YELLOW)); - DrawString(8, 20, "F2: SAT/STATIC", (nMode == 1 ? olc::RED : olc::YELLOW)); - DrawString(8, 30, "F3: DIAG", (nMode == 2 ? olc::RED : olc::YELLOW)); - DrawString(8, 40, "F4: DIAG/STATIC", (nMode == 3 ? olc::RED : olc::YELLOW)); - - return true; - } -}; - - - -int main() -{ - PolygonCollisions demo; - if (demo.Construct(256, 240, 4, 4)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_Polymorphism.cpp b/Videos/OneLoneCoder_PGE_Polymorphism.cpp deleted file mode 100644 index 424e2a1..0000000 --- a/Videos/OneLoneCoder_PGE_Polymorphism.cpp +++ /dev/null @@ -1,542 +0,0 @@ -/* - OLC::CAD - A practical example of Polymorphism - "Damn Gorbette, you made us giggle..." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Instructions: - ~~~~~~~~~~~~~ - Press & Hold middle mouse mutton to PAN - Use Scroll wheel (or Q & A) to zoom in & out - Press L to start drawing a line - Press C to start drawing a circle - Press B to start drawing a box - Press S to start drawing a curve - Press M to move node under cursor - - Relevant Video: https://youtu.be/kxKKHKSMGIg - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -// Forward declare shape, since we use it in sNode -struct sShape; - -// Define a node -struct sNode -{ - sShape *parent; - olc::vf2d pos; -}; - -// Our BASE class, defines the interface for all shapes -struct sShape -{ - // Shapes are defined by the placment of nodes - std::vector vecNodes; - uint32_t nMaxNodes = 0; - - // The colour of the shape - olc::Pixel col = olc::GREEN; - - // All shapes share word to screen transformation - // coefficients, so share them staically - static float fWorldScale; - static olc::vf2d vWorldOffset; - - // Convert coordinates from World Space --> Screen Space - void WorldToScreen(const olc::vf2d &v, int &nScreenX, int &nScreenY) - { - nScreenX = (int)((v.x - vWorldOffset.x) * fWorldScale); - nScreenY = (int)((v.y - vWorldOffset.y) * fWorldScale); - } - - // This is a PURE function, which makes this class abstract. A sub-class - // of this class must provide an implementation of this function by - // overriding it - virtual void DrawYourself(olc::PixelGameEngine *pge) = 0; - - // Shapes are defined by nodes, the shape is responsible - // for issuing nodes that get placed by the user. The shape may - // change depending on how many nodes have been placed. Once the - // maximum number of nodes for a shape have been placed, it returns - // nullptr - sNode* GetNextNode(const olc::vf2d &p) - { - if (vecNodes.size() == nMaxNodes) - return nullptr; // Shape is complete so no new nodes to be issued - - // else create new node and add to shapes node vector - sNode n; - n.parent = this; - n.pos = p; - vecNodes.push_back(n); - - // Beware! - This normally is bad! But see sub classes - return &vecNodes[vecNodes.size() - 1]; - } - - // Test to see if supplied coordinate exists at same location - // as any of the nodes for this shape. Return a pointer to that - // node if it does - sNode* HitNode(olc::vf2d &p) - { - for (auto &n : vecNodes) - { - if ((p - n.pos).mag() < 0.01f) - return &n; - } - - return nullptr; - } - - // Draw all of the nodes that define this shape so far - void DrawNodes(olc::PixelGameEngine *pge) - { - for (auto &n : vecNodes) - { - int sx, sy; - WorldToScreen(n.pos, sx, sy); - pge->FillCircle(sx, sy, 2, olc::RED); - } - } -}; - -// We must provide an implementation of our static variables -float sShape::fWorldScale = 1.0f; -olc::vf2d sShape::vWorldOffset = { 0,0 }; - - - -// LINE sub class, inherits from sShape -struct sLine : public sShape -{ - sLine() - { - nMaxNodes = 2; - vecNodes.reserve(nMaxNodes); // We're gonna be getting pointers to vector elements - // though we have defined already how much capacity our vector will have. This makes - // it safe to do this as we know the vector will not be maniupulated as we add nodes - // to it. Is this bad practice? Possibly, but as with all thing programming, if you - // know what you are doing, it's ok :D - } - - // Implements custom DrawYourself Function, meaning the shape - // is no longer abstract - void DrawYourself(olc::PixelGameEngine *pge) override - { - int sx, sy, ex, ey; - WorldToScreen(vecNodes[0].pos, sx, sy); - WorldToScreen(vecNodes[1].pos, ex, ey); - pge->DrawLine(sx, sy, ex, ey, col); - } -}; - - -// BOX -struct sBox : public sShape -{ - sBox() - { - nMaxNodes = 2; - vecNodes.reserve(nMaxNodes); - } - - void DrawYourself(olc::PixelGameEngine *pge) override - { - int sx, sy, ex, ey; - WorldToScreen(vecNodes[0].pos, sx, sy); - WorldToScreen(vecNodes[1].pos, ex, ey); - pge->DrawRect(sx, sy, ex - sx, ey - sy, col); - } -}; - - -// CIRCLE -struct sCircle : public sShape -{ - sCircle() - { - nMaxNodes = 2; - vecNodes.reserve(nMaxNodes); - } - - void DrawYourself(olc::PixelGameEngine *pge) override - { - float fRadius = (vecNodes[0].pos - vecNodes[1].pos).mag(); - int sx, sy, ex, ey; - WorldToScreen(vecNodes[0].pos, sx, sy); - WorldToScreen(vecNodes[1].pos, ex, ey); - pge->DrawLine(sx, sy, ex, ey, col, 0xFF00FF00); - - // Note the radius is also scaled so it is drawn appropriately - pge->DrawCircle(sx, sy, (int32_t)(fRadius * fWorldScale), col); - } -}; - -// BEZIER SPLINE - requires 3 nodes to be defined fully -struct sCurve : public sShape -{ - sCurve() - { - nMaxNodes = 3; - vecNodes.reserve(nMaxNodes); - } - - void DrawYourself(olc::PixelGameEngine *pge) override - { - int sx, sy, ex, ey; - - if (vecNodes.size() < 3) - { - // Can only draw line from first to second - WorldToScreen(vecNodes[0].pos, sx, sy); - WorldToScreen(vecNodes[1].pos, ex, ey); - pge->DrawLine(sx, sy, ex, ey, col, 0xFF00FF00); - } - - if (vecNodes.size() == 3) - { - // Can draw line from first to second - WorldToScreen(vecNodes[0].pos, sx, sy); - WorldToScreen(vecNodes[1].pos, ex, ey); - pge->DrawLine(sx, sy, ex, ey, col, 0xFF00FF00); - - // Can draw second structural line - WorldToScreen(vecNodes[1].pos, sx, sy); - WorldToScreen(vecNodes[2].pos, ex, ey); - pge->DrawLine(sx, sy, ex, ey, col, 0xFF00FF00); - - // And bezier curve - olc::vf2d op = vecNodes[0].pos; - olc::vf2d np = op; - for (float t = 0; t < 1.0f; t += 0.01f) - { - np = (1 - t)*(1 - t)*vecNodes[0].pos + 2 * (1 - t)*t*vecNodes[1].pos + t * t * vecNodes[2].pos; - WorldToScreen(op, sx, sy); - WorldToScreen(np, ex, ey); - pge->DrawLine(sx, sy, ex, ey, col); - op = np; - } - } - - } -}; - - - -// APPLICATION STARTS HERE - -class Polymorphism : public olc::PixelGameEngine -{ -public: - Polymorphism() - { - sAppName = "Polymorphism"; - } - -private: - // Pan & Zoom variables - olc::vf2d vOffset = { 0.0f, 0.0f }; - olc::vf2d vStartPan = { 0.0f, 0.0f }; - float fScale = 10.0f; - float fGrid = 1.0f; - - // Convert coordinates from World Space --> Screen Space - void WorldToScreen(const olc::vf2d &v, int &nScreenX, int &nScreenY) - { - nScreenX = (int)((v.x - vOffset.x) * fScale); - nScreenY = (int)((v.y - vOffset.y) * fScale); - } - - // Convert coordinates from Screen Space --> World Space - void ScreenToWorld(int nScreenX, int nScreenY, olc::vf2d &v) - { - v.x = (float)(nScreenX) / fScale + vOffset.x; - v.y = (float)(nScreenY) / fScale + vOffset.y; - } - - - // A pointer to a shape that is currently being defined - // by the placment of nodes - sShape* tempShape = nullptr; - - // A list of pointers to all shapes which have been drawn - // so far - std::list listShapes; - - // A pointer to a node that is currently selected. Selected - // nodes follow the mouse cursor - sNode *selectedNode = nullptr; - - // "Snapped" mouse location - olc::vf2d vCursor = { 0, 0 }; - - // NOTE! No direct instances of lines, circles, boxes or curves, - // the application is only aware of the existence of shapes! - // THIS IS THE POWER OF POLYMORPHISM! - -public: - bool OnUserCreate() override - { - // Configure world space (0,0) to be middle of screen space - vOffset = { (float)(-ScreenWidth() / 2) / fScale, (float)(-ScreenHeight() / 2) / fScale }; - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - // Get mouse location this frame - olc::vf2d vMouse = { (float)GetMouseX(), (float)GetMouseY() }; - - - // Handle Pan & Zoom - if (GetMouse(2).bPressed) - { - vStartPan = vMouse; - } - - if (GetMouse(2).bHeld) - { - vOffset -= (vMouse - vStartPan) / fScale; - vStartPan = vMouse; - } - - olc::vf2d vMouseBeforeZoom; - ScreenToWorld((int)vMouse.x, (int)vMouse.y, vMouseBeforeZoom); - - if (GetKey(olc::Key::Q).bHeld || GetMouseWheel() > 0) - { - fScale *= 1.1f; - } - - if (GetKey(olc::Key::A).bHeld || GetMouseWheel() < 0) - { - fScale *= 0.9f; - } - - olc::vf2d vMouseAfterZoom; - ScreenToWorld((int)vMouse.x, (int)vMouse.y, vMouseAfterZoom); - vOffset += (vMouseBeforeZoom - vMouseAfterZoom); - - - // Snap mouse cursor to nearest grid interval - vCursor.x = floorf((vMouseAfterZoom.x + 0.5f) * fGrid); - vCursor.y = floorf((vMouseAfterZoom.y + 0.5f) * fGrid); - - - if (GetKey(olc::Key::L).bPressed) - { - tempShape = new sLine(); - - // Place first node at location of keypress - selectedNode = tempShape->GetNextNode(vCursor); - - // Get Second node - selectedNode = tempShape->GetNextNode(vCursor); - } - - - if (GetKey(olc::Key::B).bPressed) - { - tempShape = new sBox(); - - // Place first node at location of keypress - selectedNode = tempShape->GetNextNode(vCursor); - - // Get Second node - selectedNode = tempShape->GetNextNode(vCursor); - } - - if (GetKey(olc::Key::C).bPressed) - { - // Create new shape as a temporary - tempShape = new sCircle(); - - // Place first node at location of keypress - selectedNode = tempShape->GetNextNode(vCursor); - - // Get Second node - selectedNode = tempShape->GetNextNode(vCursor); - } - - if (GetKey(olc::Key::S).bPressed) - { - // Create new shape as a temporary - tempShape = new sCurve(); - - // Place first node at location of keypress - selectedNode = tempShape->GetNextNode(vCursor); - - // Get Second node - selectedNode = tempShape->GetNextNode(vCursor); - } - - // Search for any node that exists under the cursor, if one - // is found then select it - if (GetKey(olc::Key::M).bPressed) - { - selectedNode = nullptr; - for (auto &shape : listShapes) - { - selectedNode = shape->HitNode(vCursor); - if (selectedNode != nullptr) - break; - } - } - - - // If a node is selected, make it follow the mouse cursor - // by updating its position - if (selectedNode != nullptr) - { - selectedNode->pos = vCursor; - } - - - // As the user left clicks to place nodes, the shape can grow - // until it requires no more nodes, at which point it is completed - // and added to the list of completed shapes. - if (GetMouse(0).bReleased) - { - if (tempShape != nullptr) - { - selectedNode = tempShape->GetNextNode(vCursor); - if (selectedNode == nullptr) - { - tempShape->col = olc::WHITE; - listShapes.push_back(tempShape); - tempShape = nullptr; // Thanks @howlevergreen /Disord - } - - } - else - { - selectedNode = nullptr; - } - } - - - - // Clear Screen - Clear(olc::VERY_DARK_BLUE); - - int sx, sy; - int ex, ey; - - // Get visible world - olc::vf2d vWorldTopLeft, vWorldBottomRight; - ScreenToWorld(0, 0, vWorldTopLeft); - ScreenToWorld(ScreenWidth(), ScreenHeight(), vWorldBottomRight); - - // Get values just beyond screen boundaries - vWorldTopLeft.x = floor(vWorldTopLeft.x); - vWorldTopLeft.y = floor(vWorldTopLeft.y); - vWorldBottomRight.x = ceil(vWorldBottomRight.x); - vWorldBottomRight.y = ceil(vWorldBottomRight.y); - - // Draw Grid dots - for (float x = vWorldTopLeft.x; x < vWorldBottomRight.x; x += fGrid) - { - for (float y = vWorldTopLeft.y; y < vWorldBottomRight.y; y += fGrid) - { - WorldToScreen({ x, y }, sx, sy); - Draw(sx, sy, olc::BLUE); - } - } - - // Draw World Axis - WorldToScreen({ 0,vWorldTopLeft.y }, sx, sy); - WorldToScreen({ 0,vWorldBottomRight.y }, ex, ey); - DrawLine(sx, sy, ex, ey, olc::GREY, 0xF0F0F0F0); - WorldToScreen({ vWorldTopLeft.x,0 }, sx, sy); - WorldToScreen({ vWorldBottomRight.x,0 }, ex, ey); - DrawLine(sx, sy, ex, ey, olc::GREY, 0xF0F0F0F0); - - // Update shape translation coefficients - sShape::fWorldScale = fScale; - sShape::vWorldOffset = vOffset; - - // Draw All Existing Shapes - for (auto &shape : listShapes) - { - shape->DrawYourself(this); - shape->DrawNodes(this); - } - - // Draw shape currently being defined - if (tempShape != nullptr) - { - tempShape->DrawYourself(this); - tempShape->DrawNodes(this); - } - - // Draw "Snapped" Cursor - WorldToScreen(vCursor, sx, sy); - DrawCircle(sx, sy, 3, olc::YELLOW); - - // Draw Cursor Position - DrawString(10, 10, "X=" + std::to_string(vCursor.x) + ", Y=" + std::to_string(vCursor.x), olc::YELLOW, 2); - return true; - } -}; - - -int main() -{ - Polymorphism demo; - if (demo.Construct(800, 480, 1, 1, false)) - demo.Start(); - return 0; -} - - - - diff --git a/Videos/OneLoneCoder_PGE_ProcGen_Universe.cpp b/Videos/OneLoneCoder_PGE_ProcGen_Universe.cpp deleted file mode 100644 index 79b4d38..0000000 --- a/Videos/OneLoneCoder_PGE_ProcGen_Universe.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/* - Procedural Generation: Programming The Universe - "Here we go again! Year 4 begins now..." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Relevant Video: https://youtu.be/ZZY9YE7rZJw - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019, 2020 -*/ - - - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#include - -constexpr uint32_t g_starColours[8] = -{ - 0xFFFFFFFF, 0xFFD9FFFF, 0xFFA3FFFF, 0xFFFFC8C8, - 0xFFFFCB9D, 0xFF9F9FFF, 0xFF415EFF, 0xFF28199D -}; - - -struct sPlanet -{ - double distance = 0.0; - double diameter = 0.0; - double foliage = 0.0; - double minerals = 0.0; - double water = 0.0; - double gases = 0.0; - double temperature = 0.0; - double population = 0.0; - bool ring = false; - std::vector vMoons; -}; - -class cStarSystem -{ -public: - cStarSystem(uint32_t x, uint32_t y, bool bGenerateFullSystem = false) - { - // Set seed based on location of star system - nProcGen = (x & 0xFFFF) << 16 | (y & 0xFFFF); - - // Not all locations contain a system - starExists = (rndInt(0, 20) == 1); - if (!starExists) return; - - // Generate Star - starDiameter = rndDouble(10.0, 40.0); - starColour.n = g_starColours[rndInt(0, 8)]; - - // When viewing the galaxy map, we only care about the star - // so abort early - if (!bGenerateFullSystem) return; - - // If we are viewing the system map, we need to generate the - // full system - - // Generate Planets - double dDistanceFromStar = rndDouble(60.0, 200.0); - int nPlanets = rndInt(0, 10); - for (int i = 0; i < nPlanets; i++) - { - sPlanet p; - p.distance = dDistanceFromStar; - dDistanceFromStar += rndDouble(20.0, 200.0); - p.diameter = rndDouble(4.0, 20.0); - - // Could make temeprature a function of distance from star - p.temperature = rndDouble(-200.0, 300.0); - - // Composition of planet - p.foliage = rndDouble(0.0, 1.0); - p.minerals = rndDouble(0.0, 1.0); - p.gases = rndDouble(0.0, 1.0); - p.water = rndDouble(0.0, 1.0); - - // Normalise to 100% - double dSum = 1.0 / (p.foliage + p.minerals + p.gases + p.water); - p.foliage *= dSum; - p.minerals *= dSum; - p.gases *= dSum; - p.water *= dSum; - - // Population could be a function of other habitat encouraging - // properties, such as temperature and water - p.population = std::max(rndInt(-5000000, 20000000), 0); - - // 10% of planets have a ring - p.ring = rndInt(0, 10) == 1; - - // Satellites (Moons) - int nMoons = std::max(rndInt(-5, 5), 0); - for (int n = 0; n < nMoons; n++) - { - // A moon is just a diameter for now, but it could be - // whatever you want! - p.vMoons.push_back(rndDouble(1.0, 5.0)); - } - - // Add planet to vector - vPlanets.push_back(p); - } - } - - ~cStarSystem() - { - - } - -public: - std::vector vPlanets; - -public: - bool starExists = false; - double starDiameter = 0.0f; - olc::Pixel starColour = olc::WHITE; - -private: - uint32_t nProcGen = 0; - - double rndDouble(double min, double max) - { - return ((double)rnd() / (double)(0x7FFFFFFF)) * (max - min) + min; - } - - int rndInt(int min, int max) - { - return (rnd() % (max - min)) + min; - } - - // Modified from this for 64-bit systems: - // https://lemire.me/blog/2019/03/19/the-fastest-conventional-random-number-generator-that-can-pass-big-crush/ - // Now I found the link again - Also, check out his blog, it's a fantastic resource! - uint32_t rnd() - { - nProcGen += 0xe120fc15; - uint64_t tmp; - tmp = (uint64_t)nProcGen * 0x4a39b70d; - uint32_t m1 = (tmp >> 32) ^ tmp; - tmp = (uint64_t)m1 * 0x12fad5c9; - uint32_t m2 = (tmp >> 32) ^ tmp; - return m2; - } -}; - -class olcGalaxy : public olc::PixelGameEngine -{ -public: - olcGalaxy() - { - sAppName = "olcGalaxy"; - } - -public: - bool OnUserCreate() override - { - return true; - } - - olc::vf2d vGalaxyOffset = { 0,0 }; - bool bStarSelected = false; - uint32_t nSelectedStarSeed1 = 0; - uint32_t nSelectedStarSeed2 = 0; - - - /*uint32_t nLehmer = 0; - uint32_t Lehmer32() - { - nLehmer += 0xe120fc15; - uint64_t tmp; - tmp = (uint64_t)nLehmer * 0x4a39b70d; - uint32_t m1 = (tmp >> 32) ^ tmp; - tmp = (uint64_t)m1 * 0x12fad5c9; - uint32_t m2 = (tmp >> 32) ^ tmp; - return m2; - }*/ - - bool OnUserUpdate(float fElapsedTime) override - { - if (fElapsedTime <= 0.0001f) return true; - Clear(olc::BLACK); - - //if (GetKey(olc::SPACE).bReleased) - //{ - - // //srand(1000); - - // std::random_device rd; - // std::mt19937 mt(1000); - // std::uniform_int_distribution dist(0, 256); - - // auto tp1 = std::chrono::system_clock::now(); - // // Ranomness Tests - // for (int x = 0; x < ScreenWidth(); x++) - // { - // for (int y = 0; y < ScreenHeight(); y++) - // { - // bool bIsStar = false; - // int nSeed = y << 16 | x; - // - // // Standard C++ rand() - // //srand(nSeed); - // //bIsStar = rand() % 256 < 32; - - // // std::random - // //mt.seed(nSeed); - // //bIsStar = dist(mt) < 32; - - // // Lehmer32 - // nLehmer = nSeed; - // bIsStar = Lehmer32() % 256 < 32; - - // Draw(x, y, bIsStar ? olc::WHITE : olc::BLACK); - // } - // } - // auto tp2 = std::chrono::system_clock::now(); - // std::chrono::duration elapsedTime = tp2 - tp1; - // DrawString(3, 3, "Time: " + std::to_string(elapsedTime.count()), olc::RED, 2); - //} - - - //return true; - - - if (GetKey(olc::W).bHeld) vGalaxyOffset.y -= 50.0f * fElapsedTime; - if (GetKey(olc::S).bHeld) vGalaxyOffset.y += 50.0f * fElapsedTime; - if (GetKey(olc::A).bHeld) vGalaxyOffset.x -= 50.0f * fElapsedTime; - if (GetKey(olc::D).bHeld) vGalaxyOffset.x += 50.0f * fElapsedTime; - - int nSectorsX = ScreenWidth() / 16; - int nSectorsY = ScreenHeight() / 16; - - olc::vi2d mouse = { GetMouseX() / 16, GetMouseY() / 16 }; - olc::vi2d galaxy_mouse = mouse + vGalaxyOffset; - olc::vi2d screen_sector = { 0,0 }; - - for (screen_sector.x = 0; screen_sector.x < nSectorsX; screen_sector.x++) - for (screen_sector.y = 0; screen_sector.y < nSectorsY; screen_sector.y++) - { - uint32_t seed1 = (uint32_t)vGalaxyOffset.x + (uint32_t)screen_sector.x; - uint32_t seed2 = (uint32_t)vGalaxyOffset.y + (uint32_t)screen_sector.y; - - cStarSystem star(seed1, seed2); - if (star.starExists) - { - FillCircle(screen_sector.x * 16 + 8, screen_sector.y * 16 + 8, - (int)star.starDiameter / 8, star.starColour); - - // For convenience highlight hovered star - if (mouse.x == screen_sector.x && mouse.y == screen_sector.y) - { - DrawCircle(screen_sector.x * 16 + 8, screen_sector.y * 16 + 8, 12, olc::YELLOW); - } - } - } - - // Handle Mouse Click - if (GetMouse(0).bPressed) - { - uint32_t seed1 = (uint32_t)vGalaxyOffset.x + (uint32_t)mouse.x; - uint32_t seed2 = (uint32_t)vGalaxyOffset.y + (uint32_t)mouse.y; - - cStarSystem star(seed1, seed2); - if (star.starExists) - { - bStarSelected = true; - nSelectedStarSeed1 = seed1; - nSelectedStarSeed2 = seed2; - } - else - bStarSelected = false; - } - - // Draw Details of selected star system - if (bStarSelected) - { - // Generate full star system - cStarSystem star(nSelectedStarSeed1, nSelectedStarSeed2, true); - - // Draw Window - FillRect(8, 240, 496, 232, olc::DARK_BLUE); - DrawRect(8, 240, 496, 232, olc::WHITE); - - // Draw Star - olc::vi2d vBody = { 14, 356 }; - - vBody.x += star.starDiameter * 1.375; - FillCircle(vBody, (int)(star.starDiameter * 1.375), star.starColour); - vBody.x += (star.starDiameter * 1.375) + 8; - - - - // Draw Planets - for (auto& planet : star.vPlanets) - { - if (vBody.x + planet.diameter >= 496) break; - - vBody.x += planet.diameter; - FillCircle(vBody, (int)(planet.diameter * 1.0), olc::RED); - - olc::vi2d vMoon = vBody; - vMoon.y += planet.diameter + 10; - - // Draw Moons - for (auto& moon : planet.vMoons) - { - vMoon.y += moon; - FillCircle(vMoon, (int)(moon * 1.0), olc::GREY); - vMoon.y += moon + 10; - } - - vBody.x += planet.diameter + 8; - } - } - - return true; - } -}; - -int main() -{ - olcGalaxy demo; - if (demo.Construct(512, 480, 2, 2, false, false)) - demo.Start(); - return 0; -} diff --git a/Videos/OneLoneCoder_PGE_QuadTree1.cpp b/Videos/OneLoneCoder_PGE_QuadTree1.cpp deleted file mode 100644 index df3786e..0000000 --- a/Videos/OneLoneCoder_PGE_QuadTree1.cpp +++ /dev/null @@ -1,493 +0,0 @@ -/* - Quirky Quad Trees Part #1 - Static Quad Tree Implementation - "War... huh... What is it good for? Absolutely nothin..." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - Copyright 2018 - 2022 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Video: - ~~~~~~ - https://youtu.be/ASAowY6yJII - - Pan & Zoom with middle mouse, TAB to switch between methods - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021, 2022 -*/ - - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#define OLC_PGEX_TRANSFORMEDVIEW -#include "olcPGEX_TransformedView.h" - -namespace olc -{ - struct rect - { - olc::vf2d pos; - olc::vf2d size; - - rect(const olc::vf2d& p = { 0.0f, 0.0f }, const olc::vf2d& s = { 1.0f, 1.0f }) : pos(p), size(s) - { - - } - - constexpr bool contains(const olc::vf2d& p) const - { - return !(p.x < pos.x || p.y < pos.y || p.x >= (pos.x + size.x) || p.y >= (pos.y + size.y)); - } - - constexpr bool contains(const olc::rect& r) const - { - return (r.pos.x >= pos.x) && (r.pos.x + r.size.x < pos.x + size.x) && - (r.pos.y >= pos.y) && (r.pos.y + r.size.y < pos.y + size.y); - } - - constexpr bool overlaps(const olc::rect& r) const - { - return (pos.x < r.pos.x + r.size.x && pos.x + size.x >= r.pos.x && pos.y < r.pos.y + r.size.y && pos.y + size.y >= r.pos.y); - } - }; - -}; - - -// Constrain depth of Quad Tree. Since its floating point, it could in principle sub-divide for -// a very long time, consuming far more time and memory than is sensible -constexpr size_t MAX_DEPTH = 8; - - -template -class StaticQuadTree -{ -public: - StaticQuadTree(const olc::rect& size = { {0.0f, 0.0f}, {100.0f, 100.0f} }, const size_t nDepth = 0) - { - m_depth = nDepth; - resize(size); - } - - // Force area change on Tree, invalidates this and all child layers - void resize(const olc::rect& rArea) - { - // Erase this layer - clear(); - - // Recalculate area of children - m_rect = rArea; - olc::vf2d vChildSize = m_rect.size / 2.0f; - - // Cache child areas local to this layer - m_rChild = - { - // Top Left - olc::rect(m_rect.pos, vChildSize), - // Top Right - olc::rect({m_rect.pos.x + vChildSize.x, m_rect.pos.y}, vChildSize), - // Bottom Left - olc::rect({m_rect.pos.x, m_rect.pos.y + vChildSize.y}, vChildSize), - // Bottom Right - olc::rect(m_rect.pos + vChildSize, vChildSize) - }; - - } - - // Clears the contents of this layer, and all child layers - void clear() - { - // Erase any items stored in this layer - m_pItems.clear(); - - // Iterate through children, erase them too - for (int i = 0; i < 4; i++) - { - if (m_pChild[i]) - m_pChild[i]->clear(); - m_pChild[i].reset(); - } - } - - // Returns a count of how many items are stored in this layer, and all children of this layer - size_t size() const - { - size_t nCount = m_pItems.size(); - for (int i = 0; i < 4; i++) - if (m_pChild[i]) nCount += m_pChild[i]->size(); - return nCount; - } - - // Inserts an object into this layer (or appropriate child layer), given the area the item occupies - void insert(const OBJECT_TYPE& item, const olc::rect& itemsize) - { - // Check each child - for (int i = 0; i < 4; i++) - { - // If the child can wholly contain the item being inserted - if (m_rChild[i].contains(itemsize)) - { - // Have we reached depth limit? - if (m_depth + 1 < MAX_DEPTH) - { - // No, so does child exist? - if (!m_pChild[i]) - { - // No, so create it - m_pChild[i] = std::make_shared>(m_rChild[i], m_depth + 1); - } - - // Yes, so add item to it - m_pChild[i]->insert(item, itemsize); - return; - } - } - } - - // It didnt fit, so item must belong to this quad - m_pItems.push_back({ itemsize, item }); - } - - // Returns a list of objects in the given search area - std::list search(const olc::rect& rArea) const - { - std::list listItems; - search(rArea, listItems); - return listItems; - } - - // Returns the objects in the given search area, by adding to supplied list - void search(const olc::rect& rArea, std::list& listItems) const - { - // First, check for items belonging to this area, add them to the list - // if there is overlap - for (const auto& p : m_pItems) - { - if (rArea.overlaps(p.first)) - listItems.push_back(p.second); - } - - // Second, recurse through children and see if they can - // add to the list - for (int i = 0; i < 4; i++) - { - if (m_pChild[i]) - { - // If child is entirely contained within area, recursively - // add all of its children, no need to check boundaries - if (rArea.contains(m_rChild[i])) - m_pChild[i]->items(listItems); - - // If child overlaps with search area then checks need - // to be made - else if (m_rChild[i].overlaps(rArea)) - m_pChild[i]->search(rArea, listItems); - } - } - } - - void items(std::list& listItems) const - { - // No questions asked, just return child items - for (const auto& p : m_pItems) - listItems.push_back(p.second); - - // Now add children of this layer's items - for (int i = 0; i < 4; i++) - if (m_pChild[i]) m_pChild[i]->items(listItems); - } - - - std::list items() const - { - // No questions asked, just return child items - std::list listItems; - items(listItems); - return listItems; - } - - // Returns area of this layer - const olc::rect& area() - { - return m_rect; - } - - -protected: - // Depth of this StaticQuadTree layer - size_t m_depth = 0; - - // Area of this StaticQuadTree - olc::rect m_rect; - - // 4 child areas of this StaticQuadTree - std::array m_rChild{}; - - // 4 potential children of this StaticQuadTree - std::array>, 4> m_pChild{}; - - // Items which belong to this StaticQuadTree - std::vector> m_pItems; -}; - - -template -class StaticQuadTreeContainer -{ - // Using a std::list as we dont want pointers to be invalidated to objects stored in the - // tree should the contents of the tree change - using QuadTreeContainer = std::list; - -protected: - // The actual container - QuadTreeContainer m_allItems; - - // Use our StaticQuadTree to store "pointers" instead of objects - this reduces - // overheads when moving or copying objects - StaticQuadTree root; - -public: - StaticQuadTreeContainer(const olc::rect& size = { {0.0f, 0.0f}, { 100.0f, 100.0f } }, const size_t nDepth = 0) : root(size, nDepth) - { - - } - - // Sets the spatial coverage area of the quadtree - // Invalidates tree - void resize(const olc::rect& rArea) - { - root.resize(rArea); - } - - // Returns number of items within tree - size_t size() const - { - return m_allItems.size(); - } - - // Returns true if tree is empty - bool empty() const - { - return m_allItems.empty(); - } - - // Removes all items from tree - void clear() - { - root.clear(); - m_allItems.clear(); - } - - - // Convenience functions for ranged for loop - typename QuadTreeContainer::iterator begin() - { - return m_allItems.begin(); - } - - typename QuadTreeContainer::iterator end() - { - return m_allItems.end(); - } - - typename QuadTreeContainer::const_iterator cbegin() - { - return m_allItems.cbegin(); - } - - typename QuadTreeContainer::const_iterator cend() - { - return m_allItems.cend(); - } - - - // Insert item into tree in specified area - void insert(const OBJECT_TYPE& item, const olc::rect& itemsize) - { - // Item is stored in container - m_allItems.push_back(item); - - // Pointer/Area of item is stored in quad tree - root.insert(std::prev(m_allItems.end()), itemsize); - } - - // Returns a std::list of pointers to items within the search area - std::list search(const olc::rect& rArea) const - { - std::list listItemPointers; - root.search(rArea, listItemPointers); - return listItemPointers; - } - -}; - - - - -// The Example! -class Example_StaticQuadTree : public olc::PixelGameEngine -{ -public: - Example_StaticQuadTree() - { - sAppName = "Static QuadTree"; - } - -protected: - olc::TransformedView tv; - - // An example object of something in 2D space - struct SomeObjectWithArea - { - olc::vf2d vPos; - olc::vf2d vVel; - olc::vf2d vSize; - olc::Pixel colour; - }; - - // A regular list of the objects - std::list vecObjects; - - // An equivalent quad tree of the objects - StaticQuadTreeContainer treeObjects; - - // The "length" of one side of the "world" the objects reside in - float fArea = 100000.0f; - - bool bUseQuadTree = true; - -public: - bool OnUserCreate() override - { - // Transform View - enables Pan & Zoom - tv.Initialise({ ScreenWidth(), ScreenHeight() }); - - // Create the tree, and size it to the world - treeObjects.resize(olc::rect({ 0.0f, 0.0f }, { fArea, fArea })); - - - // Dirty random float generator - auto rand_float = [](const float a, const float b) - { - return float(rand()) / float(RAND_MAX) * (b - a) + a; - }; - - - // Create 1,000,000 objects, push into both containers (so 2,000,000 I suppose :P ) - for (int i = 0; i < 1000000; i++) - { - SomeObjectWithArea ob; - ob.vPos = { rand_float(0.0f, fArea), rand_float(0.0f, fArea) }; - ob.vSize = { rand_float(0.1f, 100.0f), rand_float(0.1f, 100.0f) }; - ob.colour = olc::Pixel(rand() % 256, rand() % 256, rand() % 256); - - treeObjects.insert(ob, olc::rect(ob.vPos, ob.vSize)); - vecObjects.push_back(ob); - } - - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - // Tab switches between modes - if (GetKey(olc::Key::TAB).bPressed) - bUseQuadTree = !bUseQuadTree; - - tv.HandlePanAndZoom(); - - // Get rectangle that equates to screen in world space - olc::rect rScreen = { tv.GetWorldTL(), tv.GetWorldBR() - tv.GetWorldTL() }; - size_t nObjectCount = 0; - - if (bUseQuadTree) - { - // QUAD TREE MODE - auto tpStart = std::chrono::system_clock::now(); - - // Use search function to return list of pointers to objects in that area - for (const auto& object : treeObjects.search(rScreen)) - { - tv.FillRectDecal(object->vPos, object->vSize, object->colour); - nObjectCount++; - } - std::chrono::duration duration = std::chrono::system_clock::now() - tpStart; - - - std::string sOutput = "Quadtree " + std::to_string(nObjectCount) + "/" + std::to_string(vecObjects.size()) + " in " + std::to_string(duration.count()); - DrawStringDecal({ 4, 4 }, sOutput, olc::BLACK, { 4.0f, 8.0f }); - DrawStringDecal({ 2, 2 }, sOutput, olc::WHITE, { 4.0f, 8.0f }); - - } - else - { - // LINEAR SEARCH MODE - auto tpStart = std::chrono::system_clock::now(); - - // Blindly check all objects to see if they overlap with screen - for (const auto& object : vecObjects) - { - if (rScreen.overlaps({ object.vPos, object.vSize })) - { - tv.FillRectDecal(object.vPos, object.vSize, object.colour); - nObjectCount++; - } - } - std::chrono::duration duration = std::chrono::system_clock::now() - tpStart; - - std::string sOutput = "Linear " + std::to_string(nObjectCount) + "/" + std::to_string(vecObjects.size()) + " in " + std::to_string(duration.count()); - DrawStringDecal({ 4, 4 }, sOutput, olc::BLACK, { 4.0f, 8.0f }); - DrawStringDecal({ 2, 2 }, sOutput, olc::WHITE, { 4.0f, 8.0f }); - } - - return true; - } -}; - - -int main() -{ - Example_StaticQuadTree demo; - if (demo.Construct(1280, 960, 1, 1, false, false)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_RayCastDDA.cpp b/Videos/OneLoneCoder_PGE_RayCastDDA.cpp deleted file mode 100644 index 0d98060..0000000 --- a/Videos/OneLoneCoder_PGE_RayCastDDA.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/* - Fast Ray Casting Using DDA - "Itchy Eyes... Not blinking enough..." - javidx9 - - Video: https://youtu.be/NbSee-XM7WA - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2021 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -class Example : public olc::PixelGameEngine -{ -public: - Example() - { - sAppName = "RayCast With DDA Algorithm"; - } - - olc::vf2d vPlayer = { 0,0 }; - olc::vi2d vMapSize = { 32, 30 }; - olc::vi2d vCellSize = { 16, 16 }; - std::vector vecMap; - - -public: - bool OnUserCreate() override - { - // Construct Map - vecMap.resize(vMapSize.x * vMapSize.y); - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - olc::vf2d vMouse = { float(GetMouseX()), float(GetMouseY()) }; - olc::vf2d vMouseCell = vMouse / vCellSize; - olc::vi2d vCell = vMouseCell; // implicit cast to integer, rounds down - - // Paint with right mouse button "solid" tiles - if (GetMouse(1).bHeld) vecMap[vCell.y * vMapSize.x + vCell.x] = 1; - - // Move "player" position - if (GetKey(olc::Key::W).bHeld) vPlayer.y -= 25.0f * fElapsedTime; - if (GetKey(olc::Key::S).bHeld) vPlayer.y += 25.0f * fElapsedTime; - if (GetKey(olc::Key::A).bHeld) vPlayer.x -= 25.0f * fElapsedTime; - if (GetKey(olc::Key::D).bHeld) vPlayer.x += 25.0f * fElapsedTime; - - // DDA Algorithm ============================================== - // https://lodev.org/cgtutor/raycasting.html - - - // Form ray cast from player into scene - olc::vf2d vRayStart = vPlayer; - olc::vf2d vRayDir = (vMouseCell - vPlayer).norm(); - - // Lodev.org also explains this additional optimistaion (but it's beyond scope of video) - // olc::vf2d vRayUnitStepSize = { abs(1.0f / vRayDir.x), abs(1.0f / vRayDir.y) }; - - olc::vf2d vRayUnitStepSize = { sqrt(1 + (vRayDir.y / vRayDir.x) * (vRayDir.y / vRayDir.x)), sqrt(1 + (vRayDir.x / vRayDir.y) * (vRayDir.x / vRayDir.y)) }; - olc::vi2d vMapCheck = vRayStart; - olc::vf2d vRayLength1D; - olc::vi2d vStep; - - // Establish Starting Conditions - if (vRayDir.x < 0) - { - vStep.x = -1; - vRayLength1D.x = (vRayStart.x - float(vMapCheck.x)) * vRayUnitStepSize.x; - } - else - { - vStep.x = 1; - vRayLength1D.x = (float(vMapCheck.x + 1) - vRayStart.x) * vRayUnitStepSize.x; - } - - if (vRayDir.y < 0) - { - vStep.y = -1; - vRayLength1D.y = (vRayStart.y - float(vMapCheck.y)) * vRayUnitStepSize.y; - } - else - { - vStep.y = 1; - vRayLength1D.y = (float(vMapCheck.y + 1) - vRayStart.y) * vRayUnitStepSize.y; - } - - // Perform "Walk" until collision or range check - bool bTileFound = false; - float fMaxDistance = 100.0f; - float fDistance = 0.0f; - while (!bTileFound && fDistance < fMaxDistance) - { - // Walk along shortest path - if (vRayLength1D.x < vRayLength1D.y) - { - vMapCheck.x += vStep.x; - fDistance = vRayLength1D.x; - vRayLength1D.x += vRayUnitStepSize.x; - } - else - { - vMapCheck.y += vStep.y; - fDistance = vRayLength1D.y; - vRayLength1D.y += vRayUnitStepSize.y; - } - - // Test tile at new test point - if (vMapCheck.x >= 0 && vMapCheck.x < vMapSize.x && vMapCheck.y >= 0 && vMapCheck.y < vMapSize.y) - { - if (vecMap[vMapCheck.y * vMapSize.x + vMapCheck.x] == 1) - { - bTileFound = true; - } - } - } - - // Calculate intersection location - olc::vf2d vIntersection; - if (bTileFound) - { - vIntersection = vRayStart + vRayDir * fDistance; - } - - - - Clear(olc::BLACK); - - // Draw Map - for (int y = 0; y < vMapSize.y; y++) - { - for (int x = 0; x < vMapSize.x; x++) - { - int cell = vecMap[y * vMapSize.x + x]; - if (cell == 1) - FillRect(olc::vi2d(x, y) * vCellSize, vCellSize, olc::BLUE); - - // Draw Cell border - DrawRect(olc::vi2d(x, y) * vCellSize, vCellSize, olc::DARK_GREY); - } - } - - // Draw ray between player and mouse if left mouse button held - if (GetMouse(0).bHeld) - { - DrawLine(vPlayer * vCellSize, vMouse, olc::WHITE, 0xF0F0F0F0); - - if (bTileFound) - { - DrawCircle(vIntersection * vCellSize, 4.0f, olc::YELLOW); - } - } - - // Draw Player - FillCircle(vPlayer * vCellSize, 4.0f, olc::RED); - - // Draw Mouse - FillCircle(vMouse, 4.0f, olc::GREEN); - return true; - } -}; - -int main() -{ - Example demo; - if (demo.Construct(512, 480, 2, 2)) - demo.Start(); - return 0; -} diff --git a/Videos/OneLoneCoder_PGE_RayCastWorld_Simple.cpp b/Videos/OneLoneCoder_PGE_RayCastWorld_Simple.cpp deleted file mode 100644 index 1c21b96..0000000 --- a/Videos/OneLoneCoder_PGE_RayCastWorld_Simple.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* - Simple example of RayCastWorld Pixel Game Engine Extension - "My Kneeeeeeeees!!!!" - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Relevant Video: https://youtu.be/Vij_obgv9h4 - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Community Blog: https://community.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019, 2020 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#define OLC_PGEX_RAYCASTWORLD -#include "olcPGEX_RayCastWorld.h" - -// ADAPTOR CLASS - Override the RayCastWorld Engine and fill in the blanks! -class ExampleGame : public olc::rcw::Engine -{ -public: - ExampleGame(const int screen_w, const int screen_h, const float fov) - : olc::rcw::Engine(screen_w, screen_h, fov) - { - sMap = - "################################################################" - "#.........#....................##..............................#" - "#.........#....................................................#" - "#.........#....................................................#" - "#.........#....................................................#" - "#.........#############........................................#" - "#...............#..............................................#" - "#...............#..............................................#" - "#...............#..............................................#" - "#.....#..#..#...#..............................................#" - "#...............#..............................................#" - "#...............#..............................................#" - "#.....#..#..#..................................................#" - "#..............................................................#" - "#..............................................................#" - "#..............................................................#" - "#..............................................................#" - "#.....................######..#................................#" - "#.....................#.......#................................#" - "#....................##.###.###.........................#......#" - "#....................##.....#........................##........#" - "#....................##.#####........................##.#......#" - "#....................#.#.......................................#" - "#....................#..#...............................#......#" - "#..............................................................#" - "#..............................................................#" - "#..............................................................#" - "#..............................................................#" - "#..............................##..............................#" - "#..............................##..............................#" - "#..............................##..............................#" - "################################################################"; - - vWorldSize = { 64, 32 }; - } - -protected: - // User implementation to retrieve appropriate graphics for scenery - olc::Pixel SelectSceneryPixel(const int tile_x, const int tile_y, const olc::rcw::Engine::CellSide side, const float sample_x, const float sample_y, const float distance) override - { - olc::Pixel p; - - // Choose appropriate colour - switch (side) - { - case olc::rcw::Engine::CellSide::Top: // Location is "Sky" - p = olc::CYAN; - break; - - case olc::rcw::Engine::CellSide::Bottom: // Location is "Ground" - p = olc::DARK_GREEN; - break; - - default: // Location is "Wall" - p = olc::WHITE; - if (sample_x < 0.05f || sample_x > 0.95f || sample_y < 0.05f || sample_y > 0.95f) - p = olc::BLACK; - break; - } - - // Apply directional lighting, by first creating a shadow scalar... - float fShadow = 1.0f; - switch (side) - { - case olc::rcw::Engine::CellSide::South: fShadow = 0.3f; break; - case olc::rcw::Engine::CellSide::East: fShadow = 0.3f; break; - } - - // ...also shade by distance... - float fDistance = 1.0f - std::min(distance / 32.0f, 1.0f); - - // ...and applying it to sampled pixel - p.r = uint8_t(float(p.r) * fDistance); - p.g = uint8_t(float(p.g) * fDistance); - p.b = uint8_t(float(p.b) * fDistance); - - return p; - } - - // User implementation to retrieve if a particular tile is solid - bool IsLocationSolid(const float tile_x, const float tile_y) override - { - if (int(tile_x) >= 0 && int(tile_x) < vWorldSize.x && int(tile_y) >= 0 && int(tile_y) < vWorldSize.y) - return sMap[int(tile_y) * vWorldSize.x + int(tile_x)] == '#'; - else - return true; - } - - - // NOTE! Objects are not used in this demonstration =================== - - // User implementation to retrieve dimensions of an in game object - float GetObjectWidth(const uint32_t id) override - { return 1; } - - float GetObjectHeight(const uint32_t id) override - { return 1; } - - // User implementation to retrieve appropriate graphics for objects - olc::Pixel SelectObjectPixel(const uint32_t id, const float sample_x, const float sample_y, const float distance, const float angle) override - { return olc::BLACK; } - -private: - std::string sMap; - olc::vi2d vWorldSize; -}; - - - -class RayCastWorldDemo_SIMPLE : public olc::PixelGameEngine -{ -public: - RayCastWorldDemo_SIMPLE() - { - sAppName = "RayCastWorld - SIMPLE"; - } - -public: - bool OnUserCreate() override - { - // Create game object - pGame.reset(new ExampleGame(ScreenWidth(), ScreenHeight(), 3.14159f / 3.333f)); - - // Add an object "player" - std::shared_ptr player = std::make_shared(); - player->pos = { 2.1f, 2.1f }; - player->bVisible = false; - - // Insert into game world - pGame->mapObjects.insert_or_assign(0, player); - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - // Handle User Input ================================================= - auto& player = pGame->mapObjects[0]; - - if (GetKey(olc::Key::A).bHeld) // Turn Left - player->Turn(-fPlayerMoveSpeed * 0.1f * fElapsedTime); - - if (GetKey(olc::Key::D).bHeld) // Turn Right - player->Turn(+fPlayerMoveSpeed * 0.1f * fElapsedTime); - - // Reset speed and velocity so player doesnt move if keys are not pressed - player->Stop(); - - // Walk Forward - if (GetKey(olc::Key::W).bHeld) player->Walk(+fPlayerMoveSpeed); - // Walk Backwards - if (GetKey(olc::Key::S).bHeld) player->Walk(-fPlayerMoveSpeed); - // Strafe Right - if (GetKey(olc::Key::E).bHeld) player->Strafe(+fPlayerMoveSpeed); - // Strafe Left - if (GetKey(olc::Key::Q).bHeld) player->Strafe(-fPlayerMoveSpeed); - - // Update & Render World ================================================== - - // Update ray cast world engine - this will move the player object - pGame->Update(fElapsedTime); - - // Link the camera to the play position - pGame->SetCamera(player->pos, player->fHeading); - - // Render the scene! - pGame->Render(); - - // Draw the players position, cos why not? - DrawString({ 10,10 }, player->pos.str(), olc::BLACK); - return true; - } - -private: - float fPlayerMoveSpeed = 16.0f; - std::unique_ptr pGame = nullptr; -}; - -int main() -{ - RayCastWorldDemo_SIMPLE demo; - if (demo.Construct(320, 240, 4, 4)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_Rectangles.cpp b/Videos/OneLoneCoder_PGE_Rectangles.cpp deleted file mode 100644 index 8767a6c..0000000 --- a/Videos/OneLoneCoder_PGE_Rectangles.cpp +++ /dev/null @@ -1,281 +0,0 @@ -/* - One-Size-Fits-All Rectangle Vs Rectangle Collisions - "Stupid scanners... making me miss at archery..." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Relevant Video: https://www.youtube.com/watch?v=8JJ-4JgR7Dg - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Community Blog: https://community.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019, 2020 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" -#include -#include -#undef min -#undef max - -namespace olc -{ - namespace aabb - { - struct rect - { - olc::vf2d pos; - olc::vf2d size; - olc::vf2d vel; - - std::array contact; - }; - - bool PointVsRect(const olc::vf2d& p, const olc::aabb::rect* r) - { - return (p.x >= r->pos.x && p.y >= r->pos.y && p.x < r->pos.x + r->size.x && p.y < r->pos.y + r->size.y); - } - - bool RectVsRect(const olc::aabb::rect* r1, const olc::aabb::rect* r2) - { - return (r1->pos.x < r2->pos.x + r2->size.x && r1->pos.x + r1->size.x > r2->pos.x && r1->pos.y < r2->pos.y + r2->size.y && r1->pos.y + r1->size.y > r2->pos.y); - } - - bool RayVsRect(const olc::vf2d& ray_origin, const olc::vf2d& ray_dir, const rect* target, olc::vf2d& contact_point, olc::vf2d& contact_normal, float& t_hit_near) - { - contact_normal = { 0,0 }; - contact_point = { 0,0 }; - - // Cache division - olc::vf2d invdir = 1.0f / ray_dir; - - // Calculate intersections with rectangle bounding axes - olc::vf2d t_near = (target->pos - ray_origin) * invdir; - olc::vf2d t_far = (target->pos + target->size - ray_origin) * invdir; - - if (std::isnan(t_far.y) || std::isnan(t_far.x)) return false; - if (std::isnan(t_near.y) || std::isnan(t_near.x)) return false; - - // Sort distances - if (t_near.x > t_far.x) std::swap(t_near.x, t_far.x); - if (t_near.y > t_far.y) std::swap(t_near.y, t_far.y); - - // Early rejection - if (t_near.x > t_far.y || t_near.y > t_far.x) return false; - - // Closest 'time' will be the first contact - t_hit_near = std::max(t_near.x, t_near.y); - - // Furthest 'time' is contact on opposite side of target - float t_hit_far = std::min(t_far.x, t_far.y); - - // Reject if ray direction is pointing away from object - if (t_hit_far < 0) - return false; - - // Contact point of collision from parametric line equation - contact_point = ray_origin + t_hit_near * ray_dir; - - if (t_near.x > t_near.y) - if (invdir.x < 0) - contact_normal = { 1, 0 }; - else - contact_normal = { -1, 0 }; - else if (t_near.x < t_near.y) - if (invdir.y < 0) - contact_normal = { 0, 1 }; - else - contact_normal = { 0, -1 }; - - // Note if t_near == t_far, collision is principly in a diagonal - // so pointless to resolve. By returning a CN={0,0} even though its - // considered a hit, the resolver wont change anything. - return true; - } - - bool DynamicRectVsRect(const olc::aabb::rect* r_dynamic, const float fTimeStep, const olc::aabb::rect& r_static, - olc::vf2d& contact_point, olc::vf2d& contact_normal, float& contact_time) - { - // Check if dynamic rectangle is actually moving - we assume rectangles are NOT in collision to start - if (r_dynamic->vel.x == 0 && r_dynamic->vel.y == 0) - return false; - - // Expand target rectangle by source dimensions - olc::aabb::rect expanded_target; - expanded_target.pos = r_static.pos - r_dynamic->size / 2; - expanded_target.size = r_static.size + r_dynamic->size; - - if (RayVsRect(r_dynamic->pos + r_dynamic->size / 2, r_dynamic->vel * fTimeStep, &expanded_target, contact_point, contact_normal, contact_time)) - return (contact_time >= 0.0f && contact_time < 1.0f); - else - return false; - } - - - - bool ResolveDynamicRectVsRect(olc::aabb::rect* r_dynamic, const float fTimeStep, olc::aabb::rect* r_static) - { - olc::vf2d contact_point, contact_normal; - float contact_time = 0.0f; - if (DynamicRectVsRect(r_dynamic, fTimeStep, *r_static, contact_point, contact_normal, contact_time)) - { - if (contact_normal.y > 0) r_dynamic->contact[0] = r_static; else nullptr; - if (contact_normal.x < 0) r_dynamic->contact[1] = r_static; else nullptr; - if (contact_normal.y < 0) r_dynamic->contact[2] = r_static; else nullptr; - if (contact_normal.x > 0) r_dynamic->contact[3] = r_static; else nullptr; - - r_dynamic->vel += contact_normal * olc::vf2d(std::abs(r_dynamic->vel.x), std::abs(r_dynamic->vel.y)) * (1 - contact_time); - return true; - } - - return false; - } - } -} - - -class RectangleCollisions : public olc::PixelGameEngine -{ -public: - RectangleCollisions() - { - sAppName = "Rectangles!"; - } - - std::vector vRects; - -public: - bool OnUserCreate() override - { - vRects.push_back({ {170.0f, 70.0f}, {10.0f, 40.0f} }); - vRects.push_back({ {150.0f, 50.0f}, {20.0f, 20.0f} }); - vRects.push_back({ {150.0f, 150.0f}, {75.0f, 20.0f} }); - vRects.push_back({ {170.0f, 50.0f}, {20.0f, 20.0f} }); - vRects.push_back({ {190.0f, 50.0f}, {20.0f, 20.0f} }); - vRects.push_back({ {110.0f, 50.0f}, {20.0f, 20.0f} }); - vRects.push_back({ {50.0f, 130.0f}, {20.0f, 20.0f} }); - vRects.push_back({ {50.0f, 150.0f}, {20.0f, 20.0f} }); - vRects.push_back({ {50.0f, 170.0f}, {20.0f, 20.0f} }); - vRects.push_back({ {150.0f, 100.0f}, {10.0f, 1.0f} }); - vRects.push_back({ {200.0f, 100.0f}, {20.0f, 60.0f} }); - - - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - Clear(olc::DARK_BLUE); - - olc::vf2d vMouse = { float(GetMouseX()), float(GetMouseY()) }; - olc::vf2d vPoint = { 128.0f, 120.0f }; - - if (GetKey(olc::Key::W).bHeld) vRects[0].vel.y = -100.0f; - if (GetKey(olc::Key::S).bHeld) vRects[0].vel.y = +100.0f; - if (GetKey(olc::Key::A).bHeld) vRects[0].vel.x = -100.0f; - if (GetKey(olc::Key::D).bHeld) vRects[0].vel.x = +100.0f; - - if (GetMouse(0).bHeld) - vRects[0].vel += (vMouse - vRects[0].pos).norm() * 100.0f * fElapsedTime; - - - // Draw all rectangles - for (const auto& r : vRects) - DrawRect(r.pos, r.size, olc::WHITE); - - - // Sort collisions in order of distance - olc::vf2d cp, cn; - float t = 0, min_t = INFINITY; - std::vector> z; - - // Work out collision point, add it to vector along with rect ID - for (size_t i = 1; i < vRects.size(); i++) - { - if (olc::aabb::DynamicRectVsRect(&vRects[0], fElapsedTime, vRects[i], cp, cn, t)) - { - z.push_back({ i, t }); - } - } - - // Do the sort - std::sort(z.begin(), z.end(), [](const std::pair& a, const std::pair& b) - { - return a.second < b.second; - }); - - // Now resolve the collision in correct order - for (auto j : z) - olc::aabb::ResolveDynamicRectVsRect(&vRects[0], fElapsedTime, &vRects[j.first]); - - // Embellish the "in contact" rectangles in yellow - for (int i = 0; i < 4; i++) - { - if (vRects[0].contact[i]) - DrawRect(vRects[0].contact[i]->pos, vRects[0].contact[i]->size, olc::YELLOW); - vRects[0].contact[i] = nullptr; - } - - // UPdate the player rectangles position, with its modified velocity - vRects[0].pos += vRects[0].vel * fElapsedTime; - - // Draw players velocity vector - if (vRects[0].vel.mag2() > 0) - DrawLine(vRects[0].pos + vRects[0].size / 2, vRects[0].pos + vRects[0].size / 2 + vRects[0].vel.norm() * 20, olc::RED); - - return true; - } -}; - - -int main() -{ - RectangleCollisions demo; - if (demo.Construct(256, 240, 4, 4, false, false)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_RetroMenu.cpp b/Videos/OneLoneCoder_PGE_RetroMenu.cpp deleted file mode 100644 index 34ae4e0..0000000 --- a/Videos/OneLoneCoder_PGE_RetroMenu.cpp +++ /dev/null @@ -1,482 +0,0 @@ -/* - Easy To Use "Retro Pop-Up Menu System" - "There's a storm comin'......" - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Relevant Video: https://youtu.be/jde1Jq5dF0E - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Community Blog: https://community.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019, 2020 -*/ - - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#include - - -constexpr int32_t nPatch = 8; - - -class menuobject -{ -public: - menuobject() - { sName = "root"; } - - menuobject(const std::string& name) - { sName = name; } - - menuobject& SetTable(int nColumns, int nRows) - { vCellTable = { nColumns, nRows }; return *this; } - - menuobject& SetID(int32_t id) - { nID = id; return *this; } - - int32_t GetID() - { return nID; } - - std::string& GetName() - { return sName; } - - menuobject& Enable(bool b) - { bEnabled = b; return *this; } - - bool Enabled() - { return bEnabled; } - - bool HasChildren() - { return !items.empty(); } - - // For now, cells are simply one line strings - olc::vi2d GetSize() - { return { int32_t(sName.size()), 1 }; } - - olc::vi2d& GetCursorPosition() - { return vCursorPos; } - - menuobject& operator[](const std::string& name) - { - if (itemPointer.count(name) == 0) - { - itemPointer[name] = items.size(); - items.push_back(menuobject(name)); - } - - return items[itemPointer[name]]; - } - - void Build() - { - // Recursively build all children, so they can determine their size, use - // that size to indicate cell sizes if this object contains more than - // one item - for (auto& m : items) - { - if (m.HasChildren()) - { - m.Build(); - } - - // Longest child name determines cell width - vCellSize.x = std::max(m.GetSize().x, vCellSize.x); - vCellSize.y = std::max(m.GetSize().y, vCellSize.y); - } - - // Adjust size of this object (in patches) if it were rendered as a panel - vSizeInPatches.x = vCellTable.x * vCellSize.x + (vCellTable.x - 1) * vCellPadding.x + 2; - vSizeInPatches.y = vCellTable.y * vCellSize.y + (vCellTable.y - 1) * vCellPadding.y + 2; - - // Calculate how many rows this item has to hold - nTotalRows = (items.size() / vCellTable.x) + (((items.size() % vCellTable.x) > 0) ? 1 : 0); - } - - void DrawSelf(olc::PixelGameEngine& pge, olc::Sprite* sprGFX, olc::vi2d vScreenOffset) - { - // === Draw Panel - - // Record current pixel mode user is using - olc::Pixel::Mode currentPixelMode = pge.GetPixelMode(); - pge.SetPixelMode(olc::Pixel::MASK); - - // Draw Panel & Border - olc::vi2d vPatchPos = { 0,0 }; - for (vPatchPos.x = 0; vPatchPos.x < vSizeInPatches.x; vPatchPos.x++) - { - for (vPatchPos.y = 0; vPatchPos.y < vSizeInPatches.y; vPatchPos.y++) - { - // Determine position in screen space - olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset; - - // Calculate which patch is needed - olc::vi2d vSourcePatch = { 0, 0 }; - if (vPatchPos.x > 0) vSourcePatch.x = 1; - if (vPatchPos.x == vSizeInPatches.x - 1) vSourcePatch.x = 2; - if (vPatchPos.y > 0) vSourcePatch.y = 1; - if (vPatchPos.y == vSizeInPatches.y - 1) vSourcePatch.y = 2; - - // Draw Actual Patch - pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize); - } - } - - // === Draw Panel Contents - olc::vi2d vCell = { 0,0 }; - vPatchPos = { 1,1 }; - - // Work out visible items - int32_t nTopLeftItem = nTopVisibleRow * vCellTable.x; - int32_t nBottomRightItem = vCellTable.y * vCellTable.x + nTopLeftItem; - - // Clamp to size of child item vector - nBottomRightItem = std::min(int32_t(items.size()), nBottomRightItem); - int32_t nVisibleItems = nBottomRightItem - nTopLeftItem; - - // Draw Scroll Markers (if required) - if (nTopVisibleRow > 0) - { - vPatchPos = { vSizeInPatches.x - 2, 0 }; - olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset; - olc::vi2d vSourcePatch = { 3, 0 }; - pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize); - } - - if ((nTotalRows - nTopVisibleRow) > vCellTable.y) - { - vPatchPos = { vSizeInPatches.x - 2, vSizeInPatches.y - 1 }; - olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset; - olc::vi2d vSourcePatch = { 3, 2 }; - pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize); - } - - // Draw Visible Items - for (int32_t i = 0; i < nVisibleItems; i++) - { - // Cell location - vCell.x = i % vCellTable.x; - vCell.y = i / vCellTable.x; - - // Patch location (including border offset and padding) - vPatchPos.x = vCell.x * (vCellSize.x + vCellPadding.x) + 1; - vPatchPos.y = vCell.y * (vCellSize.y + vCellPadding.y) + 1; - - // Actual screen location in pixels - olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset; - - // Display Item Header - pge.DrawString(vScreenLocation, items[nTopLeftItem + i].sName, items[nTopLeftItem + i].bEnabled ? olc::WHITE : olc::DARK_GREY); - - if (items[nTopLeftItem + i].HasChildren()) - { - // Display Indicator that panel has a sub panel - vPatchPos.x = vCell.x * (vCellSize.x + vCellPadding.x) + 1 + vCellSize.x; - vPatchPos.y = vCell.y * (vCellSize.y + vCellPadding.y) + 1; - olc::vi2d vSourcePatch = { 3, 1 }; - vScreenLocation = vPatchPos * nPatch + vScreenOffset; - pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize); - } - } - - // Calculate cursor position in screen space in case system draws it - vCursorPos.x = (vCellCursor.x * (vCellSize.x + vCellPadding.x)) * nPatch + vScreenOffset.x - nPatch; - vCursorPos.y = ((vCellCursor.y - nTopVisibleRow) * (vCellSize.y + vCellPadding.y)) * nPatch + vScreenOffset.y + nPatch; - } - - void ClampCursor() - { - // Find item in children - nCursorItem = vCellCursor.y * vCellTable.x + vCellCursor.x; - - // Clamp Cursor - if (nCursorItem >= int32_t(items.size())) - { - vCellCursor.y = (items.size() / vCellTable.x); - vCellCursor.x = (items.size() % vCellTable.x) - 1; - nCursorItem = items.size() - 1; - } - } - - void OnUp() - { - vCellCursor.y--; - if (vCellCursor.y < 0) vCellCursor.y = 0; - - if (vCellCursor.y < nTopVisibleRow) - { - nTopVisibleRow--; - if (nTopVisibleRow < 0) nTopVisibleRow = 0; - } - - ClampCursor(); - } - - void OnDown() - { - vCellCursor.y++; - if (vCellCursor.y == nTotalRows) vCellCursor.y = nTotalRows - 1; - - if (vCellCursor.y > (nTopVisibleRow + vCellTable.y - 1)) - { - nTopVisibleRow++; - if (nTopVisibleRow > (nTotalRows - vCellTable.y)) - nTopVisibleRow = nTotalRows - vCellTable.y; - } - - ClampCursor(); - } - - void OnLeft() - { - vCellCursor.x--; - if (vCellCursor.x < 0) vCellCursor.x = 0; - ClampCursor(); - } - - void OnRight() - { - vCellCursor.x++; - if (vCellCursor.x == vCellTable.x) vCellCursor.x = vCellTable.x - 1; - ClampCursor(); - } - - menuobject* OnConfirm() - { - // Check if selected item has children - if (items[nCursorItem].HasChildren()) - { - return &items[nCursorItem]; - } - else - return this; - } - - menuobject* GetSelectedItem() - { - return &items[nCursorItem]; - } - - -protected: - int32_t nID = -1; - olc::vi2d vCellTable = { 1, 0 }; - std::unordered_map itemPointer; - std::vector items; - olc::vi2d vSizeInPatches = { 0, 0 }; - olc::vi2d vCellSize = { 0, 0 }; - olc::vi2d vCellPadding = { 2, 0 }; - olc::vi2d vCellCursor = { 0, 0 }; - int32_t nCursorItem = 0; - int32_t nTopVisibleRow = 0; - int32_t nTotalRows = 0; - const olc::vi2d vPatchSize = { nPatch, nPatch }; - std::string sName; - olc::vi2d vCursorPos = { 0, 0 }; - bool bEnabled = true; -}; - - -class menumanager -{ -public: - menumanager() { } - - void Open(menuobject* mo) { Close(); panels.push_back(mo); } - void Close() { panels.clear(); } - - void OnUp() { if (!panels.empty()) panels.back()->OnUp(); } - void OnDown() { if (!panels.empty()) panels.back()->OnDown(); } - void OnLeft() { if (!panels.empty()) panels.back()->OnLeft(); } - void OnRight() { if (!panels.empty()) panels.back()->OnRight(); } - void OnBack() { if (!panels.empty()) panels.pop_back(); } - - menuobject* OnConfirm() - { - if (panels.empty()) return nullptr; - - menuobject* next = panels.back()->OnConfirm(); - if (next == panels.back()) - { - if(panels.back()->GetSelectedItem()->Enabled()) - return panels.back()->GetSelectedItem(); - } - else - { - if(next->Enabled()) - panels.push_back(next); - } - - return nullptr; - } - - void Draw(olc::PixelGameEngine& pge, olc::Sprite* sprGFX, olc::vi2d vScreenOffset) - { - if (panels.empty()) return; - - // Draw Visible Menu System - for (auto& p : panels) - { - p->DrawSelf(pge, sprGFX, vScreenOffset); - vScreenOffset += {10, 10}; - } - - // Draw Cursor - olc::Pixel::Mode currentPixelMode = pge.GetPixelMode(); - pge.SetPixelMode(olc::Pixel::ALPHA); - pge.DrawPartialSprite(panels.back()->GetCursorPosition(), sprGFX, olc::vi2d(4, 0) * nPatch, { nPatch * 2, nPatch * 2 }); - pge.SetPixelMode(currentPixelMode); - } - -private: - std::list panels; -}; - -// Override base class with your custom functionality -class olcRetroPopUpMenu : public olc::PixelGameEngine -{ -public: - olcRetroPopUpMenu() - { - sAppName = "Retro Pop-Up Menu"; - } - - olc::Sprite* sprGFX = nullptr; - - menuobject mo; - menumanager mm; - -public: - bool OnUserCreate() override - { - sprGFX = new olc::Sprite("./RetroMenu.png"); - - mo["main"].SetTable(1, 4); - mo["main"]["Attack"].SetID(101); - - mo["main"]["Magic"].SetTable(1, 2); - - mo["main"]["Magic"]["White"].SetTable(3, 6); - auto& menuWhiteMagic = mo["main"]["Magic"]["White"]; - menuWhiteMagic["Cure"].SetID(401); - menuWhiteMagic["Cura"].SetID(402); - menuWhiteMagic["Curaga"].SetID(403); - menuWhiteMagic["Esuna"].SetID(404); - - mo["main"]["Magic"]["Black"].SetTable(3, 4); - auto& menuBlackMagic = mo["main"]["Magic"]["Black"]; - menuBlackMagic["Fire"].SetID(201); - menuBlackMagic["Fira"].SetID(202); - menuBlackMagic["Firaga"].SetID(203); - menuBlackMagic["Blizzard"].SetID(204); - menuBlackMagic["Blizzara"].SetID(205).Enable(false); - menuBlackMagic["Blizzaga"].SetID(206).Enable(false); - menuBlackMagic["Thunder"].SetID(207); - menuBlackMagic["Thundara"].SetID(208); - menuBlackMagic["Thundaga"].SetID(209); - menuBlackMagic["Quake"].SetID(210); - menuBlackMagic["Quake2"].SetID(211); - menuBlackMagic["Quake3"].SetID(212); - menuBlackMagic["Bio"].SetID(213); - menuBlackMagic["Bio1"].SetID(214); - menuBlackMagic["Bio2"].SetID(215); - menuBlackMagic["Demi"].SetID(216); - menuBlackMagic["Demi1"].SetID(217); - menuBlackMagic["Demi2"].SetID(218); - - mo["main"]["Defend"].SetID(102); - - mo["main"]["Items"].SetTable(2, 4).Enable(false); - mo["main"]["Items"]["Potion"].SetID(301); - mo["main"]["Items"]["Ether"].SetID(302); - mo["main"]["Items"]["Elixir"].SetID(303); - - mo["main"]["Escape"].SetID(103); - - mo.Build(); - - mm.Open(&mo["main"]); - - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - menuobject* command = nullptr; - - if (GetKey(olc::Key::M).bPressed) mm.Open(&mo["main"]); - - if (GetKey(olc::Key::UP).bPressed) mm.OnUp(); - if (GetKey(olc::Key::DOWN).bPressed) mm.OnDown(); - if (GetKey(olc::Key::LEFT).bPressed) mm.OnLeft(); - if (GetKey(olc::Key::RIGHT).bPressed) mm.OnRight(); - if (GetKey(olc::Key::SPACE).bPressed) command = mm.OnConfirm(); - if (GetKey(olc::Key::Z).bPressed) mm.OnBack(); - - if (command != nullptr) - { - sLastAction = "Selected: " + command->GetName() + " ID: " + std::to_string(command->GetID()); - mm.Close(); - } - - Clear(olc::BLACK); - mm.Draw(*this, sprGFX, { 30,30 }); - DrawString(10, 200, sLastAction); - return true; - } - - std::string sLastAction; -}; - -int main() -{ - olcRetroPopUpMenu demo; - if (demo.Construct(384, 240, 4, 4)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_RobotArm1.cpp b/Videos/OneLoneCoder_PGE_RobotArm1.cpp deleted file mode 100644 index 8c1bcd4..0000000 --- a/Videos/OneLoneCoder_PGE_RobotArm1.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* - Programming a robotic arm - "I told you, put down the screwdriver..." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Instructions: - ~~~~~~~~~~~~~ - Without a robot arm and an mbed there is not much you can do! - Also requires a 3rd Party PGEX UI by ZleapingBear: - https://youtu.be/bfiSjC__MCI - - - Relevant Video: https://youtu.be/ekdQ-aAB36Y - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" -#include "olcPGEX_UI.h" - -class RobotArm1 : public olc::PixelGameEngine -{ -public: - RobotArm1() - { - sAppName = "Robot Arm 1"; - } - - olc::UI_CONTAINER gui; - float fJointAngle[6]; - float fAccumulatedTime = 0.0f; - HANDLE hCom = nullptr; - - -public: - bool OnUserCreate() override - { - gui.addSlider(10, 20, 180); - gui.addSlider(10, 60, 180); - gui.addSlider(10, 100, 180); - gui.addSlider(10, 140, 180); - gui.addSlider(10, 180, 180); - gui.addSlider(10, 220, 180); - gui.setValue(0, 50); - gui.setValue(1, 50); - gui.setValue(2, 50); - gui.setValue(3, 50); - gui.setValue(4, 50); - gui.setValue(5, 50); - - // Open COM Port - hCom = CreateFile("COM3", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - if (hCom == nullptr) return false; - - // Configure Protocol: 9600bps, 8N1 - DCB dcb = { 0 }; - GetCommState(hCom, &dcb); - dcb.BaudRate = CBR_9600; - dcb.ByteSize = 8; - dcb.StopBits = ONESTOPBIT; - dcb.Parity = NOPARITY; - SetCommState(hCom, &dcb); - return true; - } - - bool OnUserDestroy() override - { - if (hCom != nullptr) CloseHandle(hCom); - - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - gui.Update(fElapsedTime); - Clear(olc::GREEN); - gui.drawUIObjects(); - - for (int i = 0; i < 6; i++) - fJointAngle[i] = (gui.getSliderFloat(i) / 100.0f) * 180.0f - 90.0f; - - unsigned char command[12]; - for (int i = 0; i < 6; i++) - { - command[i * 2 + 0] = i; - command[i * 2 + 1] = (int)(128 + fJointAngle[i]); - } - - fAccumulatedTime += fElapsedTime; - if (fAccumulatedTime > 0.05f) - { - fAccumulatedTime -= 0.05f; - DWORD bw = 0; - WriteFile(hCom, command, 12, &bw, 0); - } - - return true; - } -}; - -int main() -{ - RobotArm1 demo; - if (demo.Construct(400, 400, 2, 2)) - demo.Start(); - return 0; -} - -// Below here is the source code compiled on MBED LPC1768, using the BufferedSerial Library - -/* - -#include "mbed.h" -#include "BufferedSerial.h" - -PwmOut pin26(p26); -PwmOut pin25(p25); -PwmOut pin24(p24); -PwmOut pin23(p23); -PwmOut pin22(p22); -PwmOut pin21(p21); - -BufferedSerial uart(p9, p10); - - -class Joint -{ -private: - static const float fDutyMin = 0.03f; // -90 - static const float fDutyMax = 0.11f; // +90 - static const float fDutyRange = fDutyMax - fDutyMin; - - float fTarget; - float fPosition; - float fJointMax; - float fJointMin; - -public: - Joint(float fMin = -90.0f, float fMax = 90.0f, float fDefaultPos = 0.0f) - { - fJointMin = fMin; - fJointMax = fMax; - fPosition = 0.0f; - SetTarget(fDefaultPos); - } - - void SetTarget(float fAngle) - { - fTarget = fAngle; - if(fTarget < fJointMin) fTarget = fJointMin; - if(fTarget > fJointMax) fTarget = fJointMax; - } - - void UpdatePosition() - { - fPosition = fTarget; - } - - float GetTarget() - { - return fTarget; - } - - float GetDutyCycle() - { - float fDutyCycle = fPosition / (fJointMax - fJointMin); - fDutyCycle = (fDutyCycle * fDutyRange) + fDutyMin + (fDutyRange * 0.5f); - return fDutyCycle; - } -}; - - -int main() -{ - // Servos (MG996R) operate on 20ms period, so set - // PWM period for each pin - pin26.period(0.02f); - pin25.period(0.02f); - pin24.period(0.02f); - pin23.period(0.02f); - pin22.period(0.02f); - pin21.period(0.02f); - - Joint joint[6]; - - joint[0].SetTarget(0.0f); - joint[1].SetTarget(0.0f); - joint[2].SetTarget(0.0f); - joint[3].SetTarget(-25.0f); - joint[4].SetTarget(-20.0f); - joint[5].SetTarget(-15.0f); - - int nTargetJoint = 0; - - while(1) - { - // Read from UART - if(uart.readable()) - { - unsigned char c = (unsigned char)uart.getc(); - - if(c < 10) - nTargetJoint = c; - else - joint[nTargetJoint].SetTarget((float)c - 128); - - } - - - // Write Duty Cycles - // Update each joints position - for(int i=0; i<6; i++) - joint[i].UpdatePosition(); - - // Set PWM values for each joint - pin26.write(joint[0].GetDutyCycle()); - pin25.write(joint[1].GetDutyCycle()); - pin24.write(joint[2].GetDutyCycle()); - pin23.write(joint[3].GetDutyCycle()); - pin22.write(joint[4].GetDutyCycle()); - pin21.write(joint[5].GetDutyCycle()); - - } -} - -*/ \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_RobotCar1.cpp b/Videos/OneLoneCoder_PGE_RobotCar1.cpp deleted file mode 100644 index 2eaf14a..0000000 --- a/Videos/OneLoneCoder_PGE_RobotCar1.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* - Controlling Elegoo Robot Smart Car Kit 3.0+ with ASIO and C++ - "Well, it better not leak anymore... stupid window" - javidx9 - - Video: https://youtu.be/nkCP95zLvSQ - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020 - -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#define ASIO_STANDALONE -#define _WINSOCK_DEPRECATED_NO_WARNINGS -#include - -class RobotCar : public olc::PixelGameEngine -{ -public: - RobotCar() - { - sAppName = "Robot Car - Simple Control"; - } - - asio::io_context context; - std::unique_ptr port; - char nIncomingByte; - std::string sIncomingData; - std::thread thrContext; - - struct sButton - { - olc::vi2d vPos; - olc::vi2d vSize; - std::string sText; - - bool clicked(const olc::vi2d& vMousePos) - { - return vMousePos.x >= vPos.x && - vMousePos.x < (vPos.x + vSize.x) && - vMousePos.y >= vPos.y && - vMousePos.y < (vPos.y + vSize.y); - } - - void draw(olc::PixelGameEngine* pge) - { - pge->FillRect(vPos, vSize, olc::BLUE); - pge->DrawRect(vPos, vSize, olc::WHITE); - olc::vi2d vTextSize = pge->GetTextSizeProp(sText); - pge->DrawStringProp(vPos + (vSize - vTextSize) / 2, sText, olc::WHITE); - } - }; - - sButton btnForwards; - sButton btnBackwards; - sButton btnTurnLeft; - sButton btnTurnRight; - -public: - bool OnUserCreate() override - { - // Create serial port object... - port.reset(new asio::serial_port(context)); - - asio::error_code ec; - port->open("COM4", ec); - - if (ec) - { - // Port could not be opened, so abort - std::cout << ec.message() << std::endl; - return false; - } - - // ...it should have opened via creation, but check - if (port->is_open()) - { - // Set the BAUD rate - port->set_option(asio::serial_port::baud_rate(9600)); - - // By default the option arguments configure to 8N1... - port->set_option(asio::serial_port_base::character_size()); - port->set_option(asio::serial_port_base::stop_bits()); - port->set_option(asio::serial_port_base::parity()); - - // ...and flow control off - port->set_option(asio::serial_port_base::flow_control()); - - AsyncReadFromPort(); - thrContext = std::thread([&](){ context.run(); }); - } - - // Create Buttons - btnForwards.vPos = { 78, 10 }; - btnForwards.vSize = { 100, 30 }; - btnForwards.sText = "Forwards"; - - btnTurnLeft.vPos = { 10, 60 }; - btnTurnLeft.vSize = { 100, 30 }; - btnTurnLeft.sText = "Turn Left"; - - btnTurnRight.vPos = { 146, 60 }; - btnTurnRight.vSize = { 100, 30 }; - btnTurnRight.sText = "Turn Right"; - - btnBackwards.vPos = { 78, 110 }; - btnBackwards.vSize = { 100, 30 }; - btnBackwards.sText = "Backwards"; - - return true; - } - - bool OnUserDestroy() override - { - if (port) - { - // Abort any ongoing communications - port->cancel(); - - // Close the port - port->close(); - - // Don't erase the port... - } - - // Wait for thread to expire - if (thrContext.joinable()) - { - thrContext.join(); - } - - // ...until now, as the context may still need it before it expires - port.reset(); - - return true; - } - - void AsyncReadFromPort() - { - port->async_read_some(asio::buffer(&nIncomingByte, 1), [this](std::error_code ec, std::size_t length) - { - if (!ec) - { - sIncomingData.append(1, nIncomingByte); - std::cout << nIncomingByte; - AsyncReadFromPort(); - } - }); - } - - - - - bool OnUserUpdate(float fElapsedTime) override - { - asio::error_code ec; - - // Check input - if (GetMouse(0).bPressed) - { - if (btnForwards.clicked(GetMousePos())) - { - port->write_some(asio::buffer("f", 1), ec); - if (ec) std::cout << "Error Moving Forwards\n"; - } - - if (btnBackwards.clicked(GetMousePos())) - { - port->write_some(asio::buffer("b", 1), ec); - if (ec) std::cout << "Error Moving Backwards\n"; - } - - if (btnTurnLeft.clicked(GetMousePos())) - { - port->write_some(asio::buffer("l", 1), ec); - if (ec) std::cout << "Error Turning Left\n"; - } - - if (btnTurnRight.clicked(GetMousePos())) - { - port->write_some(asio::buffer("r", 1), ec); - if (ec) std::cout << "Error Turning Right\n"; - } - } - - if (GetMouse(0).bReleased) - { - port->write_some(asio::buffer("s", 1), ec); - if (ec) std::cout << "Error Stopping!!\n"; - } - - - Clear(olc::BLACK); - btnForwards.draw(this); - btnTurnLeft.draw(this); - btnTurnRight.draw(this); - btnBackwards.draw(this); - return true; - } -}; - -int main() -{ - RobotCar demo; - if (demo.Construct(256, 240, 4, 4)) - demo.Start(); - return 0; -} diff --git a/Videos/OneLoneCoder_PGE_ShadowCasting2D.cpp b/Videos/OneLoneCoder_PGE_ShadowCasting2D.cpp deleted file mode 100644 index 4399472..0000000 Binary files a/Videos/OneLoneCoder_PGE_ShadowCasting2D.cpp and /dev/null differ diff --git a/Videos/OneLoneCoder_PGE_ShootEmUp.cpp b/Videos/OneLoneCoder_PGE_ShootEmUp.cpp deleted file mode 100644 index cf37353..0000000 --- a/Videos/OneLoneCoder_PGE_ShootEmUp.cpp +++ /dev/null @@ -1,484 +0,0 @@ -/* - Live 100K Code Party! Code-It-Yourself: SHMUP - "It's done... 2019 is done..." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Relevant Video: https://youtu.be/CqDfZEX0Yhc - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Community Blog: http://community.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -// IMPORTANT!! Requires sprites not provided in repo! -// Sprites are 48x48 pixels. - - -#include -#include -#include - -class Example : public olc::PixelGameEngine -{ -public: - Example() - { - sAppName = "100K Live Special - SHMUP"; - } - - olc::Sprite* sprPlayer = nullptr; - olc::Sprite* sprEnemy[3]; - - olc::vf2d vPlayerPos; - float fPlayerSpeed = 100.0f; - float fScrollSpeed = 60.0f; - float fPlayerShipRad = 24 * 24; - float fPlayerHealth = 1000.0f; - float fPlayerGunTemp = 0.0f; - float fPlayerGunReload = 0.2f; - float fPlayerGunReloadTime = 0.0f; - - double dWorldPos = 0.0f; - - std::array aryStars; - - struct sBullet - { - olc::vf2d pos; - olc::vf2d vel; - bool remove = false; - }; - - struct sEnemy; - - struct sEnemyDefinition - { - double dTriggerTime; - uint32_t nSpriteID = 0; - float fHealth = 0.0f; - std::function funcMove; - std::function& bullets)> funcFire; - float offset = 0.0f; - }; - - struct sEnemy - { - olc::vf2d pos; - sEnemyDefinition def; - - std::array dataMove{ 0 }; - std::array dataFire{ 0 }; - - void Update(float fElapsedTime, float fScrollSpeed, std::list& bullets) - { - def.funcMove(*this, fElapsedTime, fScrollSpeed); - def.funcFire(*this, fElapsedTime, fScrollSpeed, bullets); - } - }; - - - olc::vf2d GetMiddle(const olc::Sprite *s) - { - return { (float)s->width / 2.0f, (float)s->height / 2.0f }; - } - - - std::list listSpawns; - std::list listEnemies; - std::list listEnemyBullets; - std::list listPlayerBullets; - std::list listStars; - std::list listFragments; - -public: - bool OnUserCreate() override - { - // Load resources - sprPlayer = new olc::Sprite("gfx//100k_player.png"); - sprEnemy[0] = new olc::Sprite("gfx//100k_enemy1.png"); - sprEnemy[1] = new olc::Sprite("gfx//100k_enemy2.png"); - sprEnemy[2] = new olc::Sprite("gfx//100k_enemy3.png"); - - // Generate Star Map - for (auto& s : aryStars) s = { (float)(rand() % ScreenWidth()), (float)(rand() % ScreenHeight()) }; - - // MOVEMENT PATTERN FUNCTIONS - auto Move_None = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed) - { - e.pos.y += fScrollSpeed * fElapsedTime; - }; - - auto Move_StraightFast = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed) - { - e.pos.y += 3.0f * fScrollSpeed * fElapsedTime; - }; - - auto Move_StraightSlow = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed) - { - e.pos.y += 0.5f * fScrollSpeed * fElapsedTime; - }; - - auto Move_SinusoidNarrow = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed) - { - e.dataMove[0] += fElapsedTime; - e.pos.y += 0.5f * fScrollSpeed * fElapsedTime; - e.pos.x += 50.0f * cosf(e.dataMove[0]) * fElapsedTime; - }; - - auto Move_SinusoidWide = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed) - { - e.dataMove[0] += fElapsedTime; - e.pos.y += 0.5f * fScrollSpeed * fElapsedTime; - e.pos.x += 150.0f * cosf(e.dataMove[0]) * fElapsedTime; - }; - - // FIRING PATTERN FUNCTIONS - auto Fire_None = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed, std::list& bullets) - { - - }; - - auto Fire_StraightDelay2 = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed, std::list& bullets) - { - constexpr float fDelay = 0.2f; - e.dataFire[0] += fElapsedTime; - if (e.dataFire[0] >= fDelay) - { - e.dataFire[0] -= fDelay; - sBullet b; - b.pos = e.pos + olc::vf2d((float)sprEnemy[e.def.nSpriteID]->width / 2.0f, (float)sprEnemy[e.def.nSpriteID]->height); - b.vel = { 0.0f, 180.0f }; - bullets.push_back(b); - } - }; - - auto Fire_CirclePulse2 = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed, std::list& bullets) - { - constexpr float fDelay = 0.2f; - constexpr int nBullets = 10; - constexpr float fTheta = 2.0f * 3.14159f / (float)nBullets; - e.dataFire[0] += fElapsedTime; - if (e.dataFire[0] >= fDelay) - { - e.dataFire[0] -= fDelay; - for (int i = 0; i < nBullets; i++) - { - sBullet b; - b.pos = e.pos + GetMiddle(sprEnemy[e.def.nSpriteID]); - b.vel = { 180.0f * cosf(fTheta * i), 180.0f * sinf(fTheta * i)}; - bullets.push_back(b); - } - } - }; - - auto Fire_DeathSpiral = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed, std::list& bullets) - { - constexpr float fDelay = 0.01f; - e.dataFire[0] += fElapsedTime; - if (e.dataFire[0] >= fDelay) - { - e.dataFire[1] += 0.1f; - e.dataFire[0] -= fDelay; - sBullet b; - b.pos = e.pos + GetMiddle(sprEnemy[e.def.nSpriteID]); - b.vel = { 180.0f * cosf(e.dataFire[1]), 180.0f * sinf(e.dataFire[1]) }; - bullets.push_back(b); - - } - }; - - auto Fire_DeathSpiralCircle = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed, std::list& bullets) - { - constexpr float fDelay = 0.2f; - constexpr int nBullets = 100; - constexpr float fTheta = 2.0f * 3.14159f / (float)nBullets; - e.dataFire[0] += fElapsedTime; - if (e.dataFire[0] >= fDelay) - { - e.dataFire[0] -= fDelay; - e.dataFire[1] += 0.1f; - for (int i = 0; i < nBullets; i++) - { - sBullet b; - b.pos = e.pos + GetMiddle(sprEnemy[e.def.nSpriteID]); - b.vel = { 180.0f * cosf(fTheta * i + e.dataFire[1]), 180.0f * sinf(fTheta * i + e.dataFire[1]) }; - bullets.push_back(b); - } - } - }; - - // Construct level - listSpawns = - { - {100.0, 0, 3.0f, Move_None, Fire_CirclePulse2, 0.25f}, - {100.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.75f}, - {120.0, 1, 3.0f, Move_SinusoidNarrow, Fire_CirclePulse2, 0.50f}, - - {200.0, 2, 3.0f, Move_SinusoidWide, Fire_CirclePulse2, 0.30f}, - {200.0, 2, 3.0f, Move_SinusoidWide, Fire_CirclePulse2, 0.70f}, - - {500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.2f}, - {500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.4f}, - {500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.6f}, - {500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.8f}, - - {550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.1f}, - {550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.3f}, - {550.0, 0, 3.0f, Move_StraightSlow, Fire_DeathSpiralCircle, 0.5f}, - {550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.7f}, - {550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.9f}, - - {600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.2f}, - {600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.4f}, - {600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.6f}, - {600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.8f}, - - {1100.0, 0, 3.0f, Move_None, Fire_CirclePulse2, 0.25f}, - {1100.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.75f}, - {1120.0, 1, 3.0f, Move_SinusoidNarrow, Fire_CirclePulse2, 0.50f}, - - {1200.0, 2, 3.0f, Move_SinusoidWide, Fire_CirclePulse2, 0.30f}, - {1200.0, 2, 3.0f, Move_SinusoidWide, Fire_CirclePulse2, 0.70f}, - - {1500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.2f}, - {1500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.4f}, - {1500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.6f}, - {1500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.8f}, - - {1550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.1f}, - {1550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.3f}, - {1550.0, 0, 3.0f, Move_StraightSlow, Fire_DeathSpiralCircle, 0.5f}, - {1550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.7f}, - {1550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.9f}, - - {1600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.2f}, - {1600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.4f}, - {1600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.6f}, - {1600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.8f}, - }; - - - vPlayerPos = { (float)ScreenWidth() / 2, (float)ScreenHeight() / 2 }; - - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - // AutoScroll World - dWorldPos += fScrollSpeed * fElapsedTime; - - // Scroll Player Object - vPlayerPos.y += fScrollSpeed * fElapsedTime; - - // Handle Player Input - if (GetKey(olc::W).bHeld) vPlayerPos.y -= (fPlayerSpeed + fScrollSpeed) * fElapsedTime; - if (GetKey(olc::S).bHeld) vPlayerPos.y += (fPlayerSpeed - fScrollSpeed) * fElapsedTime; - if (GetKey(olc::A).bHeld) vPlayerPos.x -= fPlayerSpeed * fElapsedTime * 2.0f; - if (GetKey(olc::D).bHeld) vPlayerPos.x += fPlayerSpeed * fElapsedTime * 2.0f; - - // Clamp Player to screen - if (vPlayerPos.x <= 0) vPlayerPos.x = 0; - if (vPlayerPos.x + (float)sprPlayer->width >= ScreenWidth()) vPlayerPos.x = (float)ScreenWidth() - sprPlayer->width; - if (vPlayerPos.y <= 0) vPlayerPos.y = 0; - if (vPlayerPos.y + (float)sprPlayer->height >= ScreenHeight()) vPlayerPos.y = (float)ScreenHeight() - sprPlayer->height; - - // Player Weapon Fire - bool bCanFire = false; - fPlayerGunReloadTime -= fElapsedTime; - if (fPlayerGunReloadTime <= 0.0f) - { - bCanFire = true; - } - - fPlayerGunTemp -= fElapsedTime * 10.0f; - if (fPlayerGunTemp < 0) fPlayerGunTemp = 0; - if (GetMouse(0).bHeld) - { - if (bCanFire && fPlayerGunTemp < 80.0f) - { - fPlayerGunReloadTime = fPlayerGunReload; - fPlayerGunTemp += 5.0f; - if (fPlayerGunTemp > 100.0f) fPlayerGunTemp = 100.0f; - listPlayerBullets.push_back({vPlayerPos + olc::vf2d((float)sprPlayer->width / 2.0f, 0.0f), {0.0f, -200.0f} }); - } - } - - // Update Player Bullets - for (auto& b : listPlayerBullets) - { - // Position Bullet - b.pos += (b.vel + olc::vf2d(0.0f, fScrollSpeed)) * fElapsedTime; - - // Check Enemies Vs Player Bullets - for (auto& e : listEnemies) - { - if ((b.pos - (e.pos + olc::vf2d(24.0f, 24.0f))).mag2() < fPlayerShipRad) - { - // Enemy has been hit - b.remove = true; - e.def.fHealth -= 1.0f; - - // Trigger explosion - if (e.def.fHealth <= 0) - { - for (int i = 0; i < 500; i++) - { - float angle = ((float)rand() / (float)RAND_MAX) * 2.0f * 3.14159f; - float speed = ((float)rand() / (float)RAND_MAX) * 200.0f + 50.0f; - listFragments.push_back({ - e.pos + GetMiddle(sprEnemy[e.def.nSpriteID]), - { cosf(angle)*speed, sinf(angle)*speed }}); - } - } - } - } - } - - - // Perform spawn check - while(!listSpawns.empty() && dWorldPos >= listSpawns.front().dTriggerTime) - { - sEnemy e; - e.def = listSpawns.front(); - e.pos = - { - listSpawns.front().offset * (float)(ScreenWidth() - sprEnemy[e.def.nSpriteID]->width), - 0.0f - sprEnemy[e.def.nSpriteID]->height - }; - listSpawns.pop_front(); - listEnemies.push_back(e); - } - - // Update Enemies - for (auto& e : listEnemies) e.Update(fElapsedTime, fScrollSpeed, listEnemyBullets); - - // Update Enemy Bullets - for (auto& b : listEnemyBullets) - { - // Position Bullet - b.pos += (b.vel + olc::vf2d(0.0f, fScrollSpeed)) * fElapsedTime; - - // Check Player Vs Enemy Bullets - if ((b.pos - (vPlayerPos + olc::vf2d(24.0f, 24.0f))).mag2() < fPlayerShipRad) - { - b.remove = true; - fPlayerHealth -= 10.0f; - } - } - - // Update Fragments - for(auto& f : listFragments) f.pos += (f.vel + olc::vf2d(0.0f, fScrollSpeed)) * fElapsedTime; - - // Remove Offscreen Enemies - listEnemies.remove_if([&](const sEnemy& e) {return (e.pos.y >= (float)ScreenHeight()) || e.def.fHealth <= 0.0f; }); - - // Remove finished enemy bullets - listEnemyBullets.remove_if([&](const sBullet& b) {return b.pos.x<0 || b.pos.x>ScreenWidth() || b.pos.y <0 || b.pos.y>ScreenHeight() || b.remove; }); - - // Remove finished player bullets - listPlayerBullets.remove_if([&](const sBullet& b) {return b.pos.x<0 || b.pos.x>ScreenWidth() || b.pos.y <0 || b.pos.y>ScreenHeight() || b.remove; }); - - // Remove finished fragments - listFragments.remove_if([&](const sBullet& b) {return b.pos.x<0 || b.pos.x>ScreenWidth() || b.pos.y <0 || b.pos.y>ScreenHeight() || b.remove; }); - - // GRAPHICS - Clear(olc::BLACK); - - // Update & Draw Stars - for (size_t i=0; i> 2) ? 0.8f : 1.0f); - if (s.y >= (float)ScreenHeight()) - s = { (float)(rand() % ScreenWidth()), 0.0f }; - - Draw(s, (i < aryStars.size() >> 2) ? olc::DARK_GREY : olc::WHITE); - } - - SetPixelMode(olc::Pixel::MASK); - - // Draw Enemies - for (auto& e : listEnemies) DrawSprite(e.pos, sprEnemy[e.def.nSpriteID]); - - // Draw Player - DrawSprite(vPlayerPos, sprPlayer); - - SetPixelMode(olc::Pixel::NORMAL); - - // Draw Enemy Bullets - for (auto& b : listEnemyBullets) FillCircle(b.pos, 3, olc::RED); - - // Draw Player Bullets - for (auto& b : listPlayerBullets) FillCircle(b.pos, 3, olc::CYAN); - - // Draw Fragments - for (auto& b : listFragments) Draw(b.pos, olc::YELLOW); - - // Draw Player Health Bar - DrawString(4, 4, "HEALTH:"); - FillRect(60, 4, (fPlayerHealth / 1000.0f * 576.0f), 8, olc::GREEN); - - DrawString(4, 14, "WEAPON:"); - FillRect(60, 14, (fPlayerGunTemp / 100.0f * 576.0f), 8, olc::YELLOW); - - return true; - } -}; - - -int main() -{ - Example demo; - if (demo.Construct(640, 480, 2, 2)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_SlidingBlockPuzzle.cpp b/Videos/OneLoneCoder_PGE_SlidingBlockPuzzle.cpp deleted file mode 100644 index 3586372..0000000 --- a/Videos/OneLoneCoder_PGE_SlidingBlockPuzzle.cpp +++ /dev/null @@ -1,431 +0,0 @@ -/* - Mechanics of Sliding Puzzle Game - "Just let me go home... please!!!" - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Relevant Video: https://www.youtube.com/watch?v=l7YEaa2otVE - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Community Blog: https://community.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019, 2020 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - - -constexpr int NORTH = 0; -constexpr int EAST = 1; -constexpr int SOUTH = 2; -constexpr int WEST = 3; - - -class BlockPuzzle : public olc::PixelGameEngine -{ -public: - BlockPuzzle() - { - sAppName = "BlockPuzzle"; - } - - std::string sLevel = - "################" - "#..............#" - "#...+....+.....#" - "#........+..|..#" - "#........+..|..#" - "#....P......|..#" - "#..5....---....#" - "#..............#" - "#..+++....#..@.#" - "#.........#..@.#" - "#..-.........@.#" - "#.....+....|...#" - "#........+.....#" - "#..............#" - "################"; - - olc::vf2d vLevelSize = { 16, 15 }; - olc::vf2d vBlockSize = { 16, 16 }; - - std::vector vGoals; - - olc::Renderable gfxTiles; - - struct block - { - block() - { - - } - - virtual void DrawSelf(olc::PixelGameEngine* pge, const olc::vi2d& pos, const olc::vi2d& size, const olc::Renderable& skin) - { - - } - - virtual bool Push(const int from) - { - return true; - } - - virtual void Move() - { - - } - - }; - - struct block_solid : public block - { - void DrawSelf(olc::PixelGameEngine* pge, const olc::vi2d& pos, const olc::vi2d& size, const olc::Renderable& skin) override - { - //pge->FillRect(pos * size, size, olc::BLUE); - pge->DrawPartialSprite(pos * size, skin.Sprite(), olc::vi2d(0, 0) * size, size); - - } - - bool Push(const int from) override - { - return false; - } - - }; - - - struct block_player : public block - { - void DrawSelf(olc::PixelGameEngine* pge, const olc::vi2d& pos, const olc::vi2d& size, const olc::Renderable& skin) override - { - pge->FillRect(pos * size, size, olc::WHITE); - } - - bool Push(const int from) override - { - return true; - } - }; - - - struct block_simple : public block - { - void DrawSelf(olc::PixelGameEngine* pge, const olc::vi2d& pos, const olc::vi2d& size, const olc::Renderable& skin) override - { - //pge->FillRect(pos * size, size, olc::RED); - pge->DrawPartialSprite(pos * size, skin.Sprite(), olc::vi2d(1, 0) * size, size); - } - - bool Push(const int from) override - { - return true; - } - }; - - - struct block_horizontal : public block - { - void DrawSelf(olc::PixelGameEngine* pge, const olc::vi2d& pos, const olc::vi2d& size, const olc::Renderable& skin) override - { - //pge->FillRect(pos * size, size, olc::GREEN); - pge->DrawPartialSprite(pos * size, skin.Sprite(), olc::vi2d(3, 0) * size, size); - } - - bool Push(const int from) override - { - return from == EAST || from == WEST; - } - }; - - struct block_vertical : public block - { - void DrawSelf(olc::PixelGameEngine* pge, const olc::vi2d& pos, const olc::vi2d& size, const olc::Renderable& skin) override - { - //pge->FillRect(pos * size, size, olc::YELLOW); - pge->DrawPartialSprite(pos * size, skin.Sprite(), olc::vi2d(2, 0) * size, size); - } - - bool Push(const int from) override - { - return from == NORTH || from == SOUTH; - } - }; - - struct block_countdown : public block - { - block_countdown(int m) - { - nMoves = m; - } - - void DrawSelf(olc::PixelGameEngine* pge, const olc::vi2d& pos, const olc::vi2d& size, const olc::Renderable& skin) override - { - //pge->FillRect(pos * size, size, olc::CYAN); - pge->DrawPartialSprite(pos * size, skin.Sprite(), olc::vi2d(4, 0) * size, size); - pge->DrawString(pos * size + olc::vi2d(4, 4), std::to_string(nMoves), olc::BLACK); - } - - bool Push(const int from) override - { - return nMoves > 0; - } - - void Move() override - { - nMoves--; - } - - int nMoves = 0; - }; - - - olc::vi2d vPlayer; - std::vector> vLevel; - - -public: - void LoadLevel(int n) - { - vLevel.clear(); - vGoals.clear(); - - - for (int y = 0; y < vLevelSize.y; y++) - { - for (int x = 0; x < vLevelSize.x; x++) - { - switch (sLevel[y * vLevelSize.x + x]) - { - case '#': - vLevel.emplace_back(std::make_unique()); - break; - - case 'P': - vLevel.emplace_back(std::make_unique()); - vPlayer = { x, y }; - break; - - case '+': - vLevel.emplace_back(std::make_unique()); - break; - - case '-': - vLevel.emplace_back(std::make_unique()); - break; - - case '|': - vLevel.emplace_back(std::make_unique()); - break; - - case '5': - vLevel.emplace_back(std::make_unique(5)); - break; - - case '@': - vGoals.push_back({ x, y }); - vLevel.emplace_back(nullptr); - break; - - - default: - vLevel.emplace_back(nullptr); - } - } - } - } - - bool OnUserCreate() override - { - gfxTiles.Load("./gfx/blocks.png"); - LoadLevel(0); - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - - bool bPushing = false; - int dirPush = 0; - - if (GetKey(olc::Key::W).bPressed) - { - dirPush = NORTH; - bPushing = true; - } - - if (GetKey(olc::Key::S).bPressed) - { - dirPush = SOUTH; - bPushing = true; - } - - if (GetKey(olc::Key::A).bPressed) - { - dirPush = WEST; - bPushing = true; - } - - if (GetKey(olc::Key::D).bPressed) - { - dirPush = EAST; - bPushing = true; - } - - if (GetKey(olc::Key::R).bPressed) - { - LoadLevel(0); - } - - auto id = [&](olc::vi2d& pos) { return pos.y * vLevelSize.x + pos.x; }; - - if (bPushing) - { - olc::vi2d vBlock = vPlayer; - - bool bAllowPush = false; - bool bTest = true; - - while (bTest) - { - if (vLevel[id(vBlock)] != nullptr) - { - if (vLevel[id(vBlock)]->Push((dirPush + 2) % 4)) - { - // Block allows push - switch (dirPush) - { - case NORTH: vBlock.y--; break; - case SOUTH: vBlock.y++; break; - case EAST: vBlock.x++; break; - case WEST: vBlock.x--; break; - } - } - else - bTest = false; - } - else - { - bAllowPush = true; - bTest = false; - } - } - - if (bAllowPush) - { - while (vBlock != vPlayer) - { - olc::vi2d vSource = vBlock; - switch (dirPush) - { - case NORTH: vSource.y++; break; - case SOUTH: vSource.y--; break; - case EAST: vSource.x--; break; - case WEST: vSource.x++; break; - } - - - if (vLevel[id(vSource)] != nullptr) vLevel[id(vSource)]->Move(); - std::swap(vLevel[id(vSource)], vLevel[id(vBlock)]); - - vBlock = vSource; - } - - switch (dirPush) - { - case NORTH: vPlayer.y--; break; - case SOUTH: vPlayer.y++; break; - case EAST: vPlayer.x++; break; - case WEST: vPlayer.x--; break; - } - - } - - } - - - int nGoals = 0; - for (auto& g : vGoals) - if (vLevel[id(g)]) nGoals++; - - - Clear(olc::BLACK); - - - for (auto& g : vGoals) - FillCircle(g * vBlockSize + vBlockSize / 2, vBlockSize.x / 2 - 2, olc::YELLOW); - - - olc::vi2d vTilePos = { 0,0 }; - for (vTilePos.y = 0; vTilePos.y < vLevelSize.y; vTilePos.y++) - { - for (vTilePos.x = 0; vTilePos.x < vLevelSize.x; vTilePos.x++) - { - - auto& b = vLevel[id(vTilePos)]; - - - if (b) - { - b->DrawSelf(this, vTilePos, vBlockSize, gfxTiles); - } - } - } - - DrawString(4, 4, "Goals: " + std::to_string(nGoals) + " / " + std::to_string(vGoals.size()), olc::WHITE); - - - return true; - } -}; - -int main() -{ - BlockPuzzle demo; - if (demo.Construct(256, 240, 4, 4)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_SoundTest.cpp b/Videos/OneLoneCoder_PGE_SoundTest.cpp deleted file mode 100644 index 373d448..0000000 --- a/Videos/OneLoneCoder_PGE_SoundTest.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* - Simple example code for olcPGEX_Sound.h - Mind your speakers! - - You will need SampleA.wav, SampleB.wav and SampleC.wav for this demo. - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - Patreon: https://www.patreon.com/javidx9 - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#define OLC_PGEX_SOUND -#include "olcPGEX_Sound.h" - -#include - -class SoundTest : public olc::PixelGameEngine -{ -public: - SoundTest() - { - sAppName = "Sound Test"; - } - -private: - int sndSampleA; - int sndSampleB; - int sndSampleC; - bool bToggle = false; - static bool bSynthPlaying; - static float fSynthFrequency; - static float fFilterVolume; - - const olc::Key keys[12] = { olc::Key::Z, olc::Key::S, olc::Key::X, olc::Key::D, olc::Key::C, - olc::Key::V, olc::Key::G, olc::Key::B, olc::Key::H, olc::Key::N, olc::Key::J, olc::Key::M}; - - static float fPreviousSamples[128]; - static int nSamplePos; - - -private: - - // This is an optional function that allows the user to generate or synthesize sounds - // in a custom way, it is fed into the output mixer bu the extension - static float MyCustomSynthFunction(int nChannel, float fGlobalTime, float fTimeStep) - { - // Just generate a sine wave of the appropriate frequency - if (bSynthPlaying) - return sin(fSynthFrequency * 2.0f * 3.14159f * fGlobalTime); - else - return 0.0f; - } - - // This is an optional function that allows the user to filter the output from - // the internal mixer of the extension. Here you could add effects or just - // control volume. I also like to use it to extract information about - // the currently playing output waveform - static float MyCustomFilterFunction(int nChannel, float fGlobalTime, float fSample) - { - // Fundamentally just control volume - float fOutput = fSample * fFilterVolume; - - // But also add sample to list of previous samples for visualisation - fPreviousSamples[nSamplePos] = fOutput; - nSamplePos++; - nSamplePos %= 128; - - return fOutput; - } - - - bool OnUserCreate() - { - olc::SOUND::InitialiseAudio(44100, 1, 8, 512); - - sndSampleA = olc::SOUND::LoadAudioSample("SampleA.wav"); - sndSampleB = olc::SOUND::LoadAudioSample("SampleB.wav"); - sndSampleC = olc::SOUND::LoadAudioSample("SampleC.wav"); - - // Give the sound engine a hook to a custom generation function - olc::SOUND::SetUserSynthFunction(MyCustomSynthFunction); - - // Give the sound engine a hook to a custom filtering function - olc::SOUND::SetUserFilterFunction(MyCustomFilterFunction); - - return true; - } - - bool OnUserUpdate(float fElapsedTime) - { - //olc::SOUND::PlaySample(sndTest); - - auto PointInRect = [&](int x, int y, int rx, int ry, int rw, int rh) - { - return x >= rx && x < (rx + rw) && y >= ry && y < (ry + rh); - }; - - int nMouseX = GetMouseX(); - int nMouseY = GetMouseY(); - - if(GetMouse(0).bPressed && PointInRect(nMouseX, nMouseY, 16, 16, 128, 24)) - olc::SOUND::PlaySample(sndSampleA); // Plays the sample once - - if (GetMouse(0).bPressed && PointInRect(nMouseX, nMouseY, 16, 48, 128, 24)) - olc::SOUND::PlaySample(sndSampleB); - - if (GetMouse(0).bPressed && PointInRect(nMouseX, nMouseY, 16, 80, 128, 24)) - { - bToggle = !bToggle; - if (bToggle) - { - olc::SOUND::PlaySample(sndSampleC, true); // Plays the sample in looping mode - } - else - { - olc::SOUND::StopSample(sndSampleC); - } - } - - if (GetMouse(0).bHeld && PointInRect(nMouseX, nMouseY, 160, 16, 90, 24)) - fFilterVolume += 2.0f * fElapsedTime; - - if (GetMouse(0).bHeld && PointInRect(nMouseX, nMouseY, 160, 48, 90, 24)) - fFilterVolume -= 2.0f * fElapsedTime; - - if (fFilterVolume < 0.0f) fFilterVolume = 0.0f; - if (fFilterVolume > 1.0f) fFilterVolume = 1.0f; - - // Detect keyboard - very simple synthesizer - if (IsFocused()) - { - bool bKeyIsPressed = false; - float fFrequency = 0.0f; - for (int i = 0; i < 12; i++) - { - if (GetKey(keys[i]).bHeld) - { - bKeyIsPressed = true; - float fOctaveBaseFrequency = 220.0f; - float f12thRootOf2 = pow(2.0f, 1.0f / 12.0f); - fFrequency = fOctaveBaseFrequency * powf(f12thRootOf2, (float)i); - } - } - - fSynthFrequency = fFrequency; - bSynthPlaying = bKeyIsPressed; - } - - - // Draw Buttons - Clear(olc::BLUE); - - DrawRect(16, 16, 128, 24); - DrawString(20, 20, "Play Sample A"); - - DrawRect(16, 48, 128, 24); - DrawString(20, 52, "Play Sample B"); - - DrawRect(16, 80, 128, 24); - DrawString(20, 84, (bToggle ? "Stop Sample C" : "Loop Sample C")); - - - DrawRect(160, 16, 90, 24); - DrawString(164, 20, "Volume +"); - - DrawRect(160, 48, 90, 24); - DrawString(164, 52, "Volume -"); - - - DrawString(164, 80, "Volume: " + std::to_string((int)(fFilterVolume * 10.0f))); - - // Draw Keyboard - - // White Keys - for (int i = 0; i < 7; i++) - { - FillRect(i * 16 + 8, 160, 16, 64); - DrawRect(i * 16 + 8, 160, 16, 64, olc::BLACK); - DrawString(i * 16 + 12, 212, std::string(1, "ZXCVBNM"[i]), olc::BLACK); - } - - // Black Keys - for (int i = 0; i < 6; i++) - { - if (i != 2) - { - FillRect(i * 16 + 18, 160, 12, 32, olc::BLACK); - DrawString(i * 16 + 20, 180, std::string(1, "SDFGHJ"[i]), olc::WHITE); - } - } - - // Draw visualisation - int nStartPos = (nSamplePos + 127) % 128; - - for (int i = 127; i >= 0; i--) - { - float fSample = fPreviousSamples[(nSamplePos + i) % 128]; - DrawLine(124 + i, 210, 124 + i, 210 + (int)(fSample * 20.0f), olc::RED); - } - - - return true; - } - - - // Note we must shut down the sound system too!! - bool OnUserDestroy() - { - olc::SOUND::DestroyAudio(); - return true; - } -}; - -bool SoundTest::bSynthPlaying = false; -float SoundTest::fSynthFrequency = 0.0f; -float SoundTest::fFilterVolume = 1.0f; -int SoundTest::nSamplePos = 0; -float SoundTest::fPreviousSamples[128]; - -int main() -{ - SoundTest demo; - if(demo.Construct(256, 240, 4, 4)) - demo.Start(); - - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_SpriteTransforms.cpp b/Videos/OneLoneCoder_PGE_SpriteTransforms.cpp deleted file mode 100644 index ed0d9b5..0000000 --- a/Videos/OneLoneCoder_PGE_SpriteTransforms.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - OneLoneCoder.com - 2D Sprite Affine Transformations - "No more 90 degree movements" - @Javidx9 - - - Background - ~~~~~~~~~~ - The sophistication of 2D engines is enhanced when the programmer is - able to rotate and scale sprites in a convenient manner. This program - shows the basics of how affine transformations accomplish this. - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Relevant Videos - ~~~~~~~~~~~~~~~ - https://youtu.be/zxwLN2blwbQ - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018 -*/ - - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" - -#include -#undef min -#undef max - - -class SpriteTransforms : public olc::PixelGameEngine -{ -public: - SpriteTransforms() - { - sAppName = "Sprite Transforms"; - } - -private: - olc::Sprite *sprCar; - - struct matrix3x3 - { - float m[3][3]; - }; - - void Identity(matrix3x3 &mat) - { - mat.m[0][0] = 1.0f; mat.m[1][0] = 0.0f; mat.m[2][0] = 0.0f; - mat.m[0][1] = 0.0f; mat.m[1][1] = 1.0f; mat.m[2][1] = 0.0f; - mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f; - } - - void Translate(matrix3x3 &mat, float ox, float oy) - { - mat.m[0][0] = 1.0f; mat.m[1][0] = 0.0f; mat.m[2][0] = ox; - mat.m[0][1] = 0.0f; mat.m[1][1] = 1.0f; mat.m[2][1] = oy; - mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f; - } - - void Rotate(matrix3x3 &mat, float fTheta) - { - mat.m[0][0] = cosf(fTheta); mat.m[1][0] = sinf(fTheta); mat.m[2][0] = 0.0f; - mat.m[0][1] = -sinf(fTheta); mat.m[1][1] = cosf(fTheta); mat.m[2][1] = 0.0f; - mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f; - } - - void Scale(matrix3x3 &mat, float sx, float sy) - { - mat.m[0][0] = sx; mat.m[1][0] = 0.0f; mat.m[2][0] = 0.0f; - mat.m[0][1] = 0.0f; mat.m[1][1] = sy; mat.m[2][1] = 0.0f; - mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f; - } - - void Shear(matrix3x3 &mat, float sx, float sy) - { - mat.m[0][0] = 1.0f; mat.m[1][0] = sx; mat.m[2][0] = 0.0f; - mat.m[0][1] = sy; mat.m[1][1] = 1.0f; mat.m[2][1] = 0.0f; - mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f; - } - - void MatrixMultiply(matrix3x3 &matResult, matrix3x3 &matA, matrix3x3 &matB) - { - for (int c = 0; c < 3; c++) - { - for (int r = 0; r < 3; r++) - { - matResult.m[c][r] = matA.m[0][r] * matB.m[c][0] + - matA.m[1][r] * matB.m[c][1] + - matA.m[2][r] * matB.m[c][2]; - } - } - } - - void Forward(matrix3x3 &mat, float in_x, float in_y, float &out_x, float &out_y) - { - out_x = in_x * mat.m[0][0] + in_y * mat.m[1][0] + mat.m[2][0]; - out_y = in_x * mat.m[0][1] + in_y * mat.m[1][1] + mat.m[2][1]; - } - - void Invert(matrix3x3 &matIn, matrix3x3 &matOut) - { - float det = matIn.m[0][0] * (matIn.m[1][1] * matIn.m[2][2] - matIn.m[1][2] * matIn.m[2][1]) - - matIn.m[1][0] * (matIn.m[0][1] * matIn.m[2][2] - matIn.m[2][1] * matIn.m[0][2]) + - matIn.m[2][0] * (matIn.m[0][1] * matIn.m[1][2] - matIn.m[1][1] * matIn.m[0][2]); - - float idet = 1.0f / det; - matOut.m[0][0] = (matIn.m[1][1] * matIn.m[2][2] - matIn.m[1][2] * matIn.m[2][1]) * idet; - matOut.m[1][0] = (matIn.m[2][0] * matIn.m[1][2] - matIn.m[1][0] * matIn.m[2][2]) * idet; - matOut.m[2][0] = (matIn.m[1][0] * matIn.m[2][1] - matIn.m[2][0] * matIn.m[1][1]) * idet; - matOut.m[0][1] = (matIn.m[2][1] * matIn.m[0][2] - matIn.m[0][1] * matIn.m[2][2]) * idet; - matOut.m[1][1] = (matIn.m[0][0] * matIn.m[2][2] - matIn.m[2][0] * matIn.m[0][2]) * idet; - matOut.m[2][1] = (matIn.m[0][1] * matIn.m[2][0] - matIn.m[0][0] * matIn.m[2][1]) * idet; - matOut.m[0][2] = (matIn.m[0][1] * matIn.m[1][2] - matIn.m[0][2] * matIn.m[1][1]) * idet; - matOut.m[1][2] = (matIn.m[0][2] * matIn.m[1][0] - matIn.m[0][0] * matIn.m[1][2]) * idet; - matOut.m[2][2] = (matIn.m[0][0] * matIn.m[1][1] - matIn.m[0][1] * matIn.m[1][0]) * idet; - } - - - float fRotate = 0.0f; - -public: - bool OnUserCreate() override - { - sprCar = new olc::Sprite("car_top1.png"); - - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - - if (GetKey(olc::Key::Z).bHeld) fRotate -= 2.0f * fElapsedTime; - if (GetKey(olc::Key::X).bHeld) fRotate += 2.0f * fElapsedTime; - - - Clear(olc::DARK_CYAN); - - SetPixelMode(olc::Pixel::ALPHA); - //DrawSprite(0, 0, sprCar, 3); - - - matrix3x3 matFinal, matA, matB, matC, matFinalInv; - Translate(matA, -100, -50); - Rotate(matB, fRotate); - MatrixMultiply(matC, matB, matA); - - Translate(matA, (float)ScreenWidth()/2, (float)ScreenHeight()/2); - MatrixMultiply(matFinal, matA, matC); - - Invert(matFinal, matFinalInv); - - // Draws the dumb way, but leaves gaps - /*for (int x = 0; x < sprCar->width; x++) - { - for (int y = 0; y < sprCar->height; y++) - { - olc::Pixel p = sprCar->GetPixel(x, y); - - float nx, ny; - Forward(matFinal, (float)x, (float)y, nx, ny); - Draw(nx, ny, p); - } - }*/ - - // Work out bounding box of sprite post-transformation - // by passing through sprite corner locations into - // transformation matrix - float ex, ey; - float sx, sy; - float px, py; - - Forward(matFinal, 0.0f, 0.0f, px, py); - sx = px; sy = py; - ex = px; ey = py; - - Forward(matFinal, (float)sprCar->width, (float)sprCar->height, px, py); - sx = std::min(sx, px); sy = std::min(sy, py); - ex = std::max(ex, px); ey = std::max(ey, py); - - Forward(matFinal, 0.0f, (float)sprCar->height, px, py); - sx = std::min(sx, px); sy = std::min(sy, py); - ex = std::max(ex, px); ey = std::max(ey, py); - - Forward(matFinal, (float)sprCar->width, 0.0f, px, py); - sx = std::min(sx, px); sy = std::min(sy, py); - ex = std::max(ex, px); ey = std::max(ey, py); - - // Use transformed corner locations in screen space to establish - // region of pixels to fill, using inverse transform to sample - // sprite at suitable locations. - for (int x = sx; x < ex; x++) - { - for (int y = sy; y < ey; y++) - { - float nx, ny; - Forward(matFinalInv, (float)x, (float)y, nx, ny); - olc::Pixel p = sprCar->GetPixel((int32_t)(nx + 0.5f), (int32_t)(ny + 0.5f)); - Draw(x, y, p); - } - } - - SetPixelMode(olc::Pixel::NORMAL); - - return true; - } -}; - -int main() -{ - SpriteTransforms demo; - if (demo.Construct(256, 240, 4, 4)) - demo.Start(); - return 0; -} \ No newline at end of file diff --git a/Videos/OneLoneCoder_PGE_olcEngine3D.cpp b/Videos/OneLoneCoder_PGE_olcEngine3D.cpp deleted file mode 100644 index d140a16..0000000 Binary files a/Videos/OneLoneCoder_PGE_olcEngine3D.cpp and /dev/null differ diff --git a/Videos/OneLoneCoder_VIDEO_IntrinsicFunctions.cpp b/Videos/OneLoneCoder_VIDEO_IntrinsicFunctions.cpp deleted file mode 100644 index fcb90c3..0000000 --- a/Videos/OneLoneCoder_VIDEO_IntrinsicFunctions.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* - Vector Extensions - Mandelbrot - "Succesfully programmed the dishwasher and debugged the pump this week..." - javidx9 - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2020 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Relevant Video: https://youtu.be/x9Scb5Mku1g - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Community Blog: https://community.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019, 2020 -*/ - -// NOTE: THIS PROGRAM CANNOT BE EXCUTED - IT IS INTENDED AS A GUIDE -// TO THIS VIDEO: https://youtu.be/x9Scb5Mku1g - - -// Method 4) - Use AVX2 Vector co-processor to handle 4 fractal locations at once -void CreateFractalIntrinsics(const olc::vi2d& pix_tl, const olc::vi2d& pix_br, const olc::vd2d& frac_tl, const olc::vd2d& frac_br, const int iterations) -{ - double x_scale = (frac_br.x - frac_tl.x) / (double(pix_br.x) - double(pix_tl.x)); - double y_scale = (frac_br.y - frac_tl.y) / (double(pix_br.y) - double(pix_tl.y)); - - double y_pos = frac_tl.y; - - int y_offset = 0; - int row_size = ScreenWidth(); - - int x, y; - - // 64-bit "double" registers - __m256d _a, _b, _two, _four, _mask1; - __m256d _zr, _zi, _zr2, _zi2, _cr, _ci; - __m256d _x_pos_offsets, _x_pos, _x_scale, _x_jump; - - // 64-bit "integer" registers - __m256i _one, _c, _n, _iterations, _mask2; - - // Expand constants into vectors of constants - // one = |(int)1|(int)1|(int)1|(int)1| - _one = _mm256_set1_epi64x(1); - - // two = |2.0|2.0|2.0|2.0| - _two = _mm256_set1_pd(2.0); - - // four = |4.0|4.0|4.0|4.0| - _four = _mm256_set1_pd(4.0); - - // iterations = |iterations|iterations|iterations|iterations| - _iterations = _mm256_set1_epi64x(iterations); - - _x_scale = _mm256_set1_pd(x_scale); - _x_jump = _mm256_set1_pd(x_scale * 4); - _x_pos_offsets = _mm256_set_pd(0, 1, 2, 3); - _x_pos_offsets = _mm256_mul_pd(_x_pos_offsets, _x_scale); - - - for (y = pix_tl.y; y < pix_br.y; y++) - { - // Reset x_position - _a = _mm256_set1_pd(frac_tl.x); - _x_pos = _mm256_add_pd(_a, _x_pos_offsets); - - _ci = _mm256_set1_pd(y_pos); - - for (x = pix_tl.x; x < pix_br.x; x += 4) - { - _cr = _x_pos; - - // Zreal = 0 - _zr = _mm256_setzero_pd(); - - // Zimag = 0 - _zi = _mm256_setzero_pd(); - - // nIterations = 0 - _n = _mm256_setzero_si256(); - - - repeat: - // Normal: z = (z * z) + c; - // Manual: a = zr * zr - zi * zi + cr; - // b = zr * zi * 2.0 + ci; - // zr = a; - // zi = b; - - - // zr^2 = zr * zr - _zr2 = _mm256_mul_pd(_zr, _zr); // zr * zr - - // zi^2 = zi * zi - _zi2 = _mm256_mul_pd(_zi, _zi); // zi * zi - - // a = zr^2 - zi^2 - _a = _mm256_sub_pd(_zr2, _zi2); // a = (zr * zr) - (zi * zi) - - // a = a + cr - _a = _mm256_add_pd(_a, _cr); // a = ((zr * zr) - (zi * zi)) + cr - - - - // b = zr * zi - _b = _mm256_mul_pd(_zr, _zi); // b = zr * zi - - // b = b * 2.0 + ci - // b = b * |2.0|2.0|2.0|2.0| + ci - _b = _mm256_fmadd_pd(_b, _two, _ci); // b = (zr * zi) * 2.0 + ci - - // zr = a - _zr = _a; // zr = a - - // zi = b - _zi = _b; // zr = b - - - - // Normal: while (abs(z) < 2.0 && n < iterations) - // Manual: while ((zr * zr + zi * zi) < 4.0 && n < iterations) - - - // a = zr^2 + zi^2 - _a = _mm256_add_pd(_zr2, _zi2); // a = (zr * zr) + (zi * zi) - - // m1 = if (a < 4.0) - // m1 = |if(a[3] < 4.0)|if(a[2] < 4.0)|if(a[1] < 4.0)|if(a[0] < 4.0)| - // m1 = |111111...11111|000000...00000|111111...11111|000000...00000| - // m1 = |11...11|00...00|11...11|00...00| <- Shortened to reduce typing :P - _mask1 = _mm256_cmp_pd(_a, _four, _CMP_LT_OQ); - - // m2 = if (iterations > n) - // m2 = |00...00|11...11|11...11|00...00| - _mask2 = _mm256_cmpgt_epi64(_iterations, _n); - - // m2 = m2 AND m1 = if(a < 4.0 && iterations > n) - // - // m2 = |00...00|11...11|11...11|00...00| - // m1 = AND|11...11|00...00|11...11|00...00| - // m2 = |00...00|00...00|11...11|00...00| - _mask2 = _mm256_and_si256(_mask2, _mm256_castpd_si256(_mask1)); - - // c = |(int)1|(int)1|(int)1|(int)1| AND m2 - // - // c = |00...01|00...01|00...01|00...01| - // m2 = AND|00...00|00...00|11...11|00...00| - // c = |00...00|00...00|00...01|00...00| - // - // c = |(int)0|(int)0|(int)1|(int)0| - _c = _mm256_and_si256(_one, _mask2); - - // n = n + c - // n = |00...24|00...13|00...08|00...21| - // c = +|00...00|00...00|00...01|00...00| - // n = |00...24|00...13|00...09|00...21| (Increment only applied to 'enabled' element) - _n = _mm256_add_epi64(_n, _c); - - // if ((zr * zr + zi * zi) < 4.0 && n < iterations) goto repeat - // i.e. if our mask has any elements that are 1 - // |00...00|00...00|11...11|00...00| - // | 0 | 0 | 1 | 0 | = 0b0010 = 2 - // so... if (2 > 0) goto repeat - if (_mm256_movemask_pd(_mm256_castsi256_pd(_mask2)) > 0) - goto repeat; - - // Tight loop has finished, all 4 pixels have been evaluated. Increment - // fractal space x positions for next 4 pixels - // x_pos = x_pos + x_jump - _x_pos = _mm256_add_pd(_x_pos, _x_jump); - - // Unpack our 4x64-bit Integer Vector into normal 32-bit Integers - // and write into memory at correct location. Note, depending on - // how you structure the memory, and the types you use, this step - // may not be required. If I was working with 64-bit integers I - // could choose to just write the vector entirely, saving this - // truncation at the expense of 2x the memory required - - #if defined(__linux__) - // Intrinsics are not cross platform! - pFractal[y_offset + x + 0] = int(_n[3]); - pFractal[y_offset + x + 1] = int(_n[2]); - pFractal[y_offset + x + 2] = int(_n[1]); - pFractal[y_offset + x + 3] = int(_n[0]); - #endif - - #if defined(_WIN32) - pFractal[y_offset + x + 0] = int(_n.m256i_i64[3]); - pFractal[y_offset + x + 1] = int(_n.m256i_i64[2]); - pFractal[y_offset + x + 2] = int(_n.m256i_i64[1]); - pFractal[y_offset + x + 3] = int(_n.m256i_i64[0]); - #endif - - - } - - y_pos += y_scale; - y_offset += row_size; - } -} \ No newline at end of file diff --git a/Videos/RetroMenu.png b/Videos/RetroMenu.png deleted file mode 100644 index f74213f..0000000 Binary files a/Videos/RetroMenu.png and /dev/null differ diff --git a/Videos/SampleA.wav b/Videos/SampleA.wav deleted file mode 100644 index 9a53e04..0000000 Binary files a/Videos/SampleA.wav and /dev/null differ diff --git a/Videos/SampleB.wav b/Videos/SampleB.wav deleted file mode 100644 index aac72c7..0000000 Binary files a/Videos/SampleB.wav and /dev/null differ diff --git a/Videos/SampleC.wav b/Videos/SampleC.wav deleted file mode 100644 index 111a57b..0000000 Binary files a/Videos/SampleC.wav and /dev/null differ diff --git a/Videos/SavingSedit/OneLoneCoder_PGE_SavingSedit.cpp b/Videos/SavingSedit/OneLoneCoder_PGE_SavingSedit.cpp deleted file mode 100644 index 6bfe4d3..0000000 --- a/Videos/SavingSedit/OneLoneCoder_PGE_SavingSedit.cpp +++ /dev/null @@ -1,1509 +0,0 @@ - -/* - Saving Sedit: An OLC Code Jam 2018 Submission - "At least this is checked off my list now..." - javidx9 - - Download the playable version here: https://onelonecoder.itch.io/saving-sedit - - Note: This was a JAM entry, it is incomplete, has bugs, has features that - dont go anywhere. I've not tidied up the code - it is a record of how - the JAM went. - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Relevant Video: https://youtu.be/Qco5BstCxRM - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - -#define OLC_PGE_APPLICATION -#include "olcPixelGameEngine.h" -#define OLC_PGE_GRAPHICS2D -#include "olcPGEX_Graphics2D.h" - -#include "olcPGEX_TileMaps_new.h" -#define OLC_PGEX_SOUND -#include "olcPGEX_Sound.h" - -#include "Zix_PGE_Controller.h" - -#include -#include -#include -#include -#include -using namespace std; - - -class cAnimator -{ -public: - std::map> mapStates; - -public: - std::string sCurrentState; - int nCurrentFrame = 0; - float fTimeBetweenFrames = 0.1f; - float fTimeCounter = 0.0f; - - - void ChangeState(std::string s) - { - if (s != sCurrentState) - { - sCurrentState = s; - fTimeCounter = 0; - nCurrentFrame = 0; - } - } - - void Update(float fElapsedTime) - { - fTimeCounter += fElapsedTime; - if (fTimeCounter >= fTimeBetweenFrames) - { - fTimeCounter -= fTimeBetweenFrames; - nCurrentFrame++; - if (nCurrentFrame >= mapStates[sCurrentState].size()) - nCurrentFrame = 0; - } - } - - void DrawSelf(olc::PixelGameEngine *pge, olc::GFX2D::Transform2D &t) - { - olc::GFX2D::DrawSprite(mapStates[sCurrentState][nCurrentFrame], t); - } - -}; - -// Override base class with your custom functionality -class Discovery : public olc::PixelGameEngine -{ -public: - Discovery() - { - sAppName = "Discovery - OLC CodeJam 2018"; - } - -private: - - int nTileSizeX = 64; - int nTileSizeY = 64; - olc::TILE::Layer layerWorld; - olc::TILE::Layer layerCollectibles; - olc::TILE::Layer layerJavid; - olc::TILE::Atlas atlasWorldMagetzub; - olc::TILE::Atlas atlasWorldJavid; - olc::TILE::Atlas atlasWorldHopson; - olc::TILE::Atlas atlasCollectibles; - - olc::ResourcePack rpPlayer; - - olc::Sprite *sprBackdropMagetzub; - olc::Sprite *sprBackdropHopson; - - olc::Sprite *sprTitleScreen; - olc::Sprite *sprStoryScreen; - olc::Sprite *sprControlScreen; - olc::Sprite *sprCreditScreen; - olc::Sprite *sprCompleteScreen; - - float fBackdropScaleX = 1.0f; - float fBackdropScaleY = 1.0f; - - olc::Sprite *sprMiniMap = nullptr; - - olc::Sprite *backBuff; - - - - cAnimator animPlayer; - ControllerManager controller; - - float fPlayerPosX = 2.0f; - float fPlayerPosY = 2.0f; - float fPlayerVelX = 0.0f; - float fPlayerVelY = 0.0f; - float fCameraPosX = 0.0f; - float fCameraPosY = 0.0f; - bool bPlayerOnGround = false; - bool bPlayerTouchingWall = false; - bool bPlayerTouchingWallOld = false; - bool bCollisionLeft = false; - float fTimeToJump = 0.0f; - float fTimeToJumpMax = 0.25f; - float fFaceDir = 1.0f; - int nFloppyDisks = 0; - float fGameTime = 0.0f; - float fGameTimeMultiplier = 1.0f; - int nHopsonTokens = 0; - int nJavidTokens = 0; - - int nKeys = 0; - float fEffectTime = 0.0f; - float fModeTime = 0.0f; - - bool bFire = false; - - list> listKeys; - - struct sBullet - { - float bx; - float by; - float vx; - bool bRemove = false; - }; - - enum - { - MODE_MAGETZUB, - MODE_JAVID, - MODE_HOPSON, - MODE_HUHLIG - - } nRenderMode; - - enum - { - EFFECT_NONE, - EFFECT_UGLYSWEDISHFISH, - EFFECT_SEDIT, - EFFECT_BRANK, - EFFECT_GORBIT, - - } nRenderEffect; - - - enum - { - GS_LOADING, - GS_TITLE, - GS_STORY, - GS_CREDITS, - GS_GENERATE, - GS_MAIN, - GS_COMPLETE, - } nGameState = GS_LOADING; - - int nChallengeMapSizeX = 8; - int nChallengeMapSizeY = 8; - int nChallengePathSizeX = 4; - int nChallengePathSizeY = 4; - - void CreateMaze(bool* &pMap, int nCellWidth, int nCellHeight, int nCellsX, int nCellsY, int &nMapWidth, int &nMapHeight) - { - int *pLevel = new int[nCellsX * nCellsY]{ 0 }; - - enum - { - CELL_PATH_N = 0x01, - CELL_PATH_E = 0x02, - CELL_PATH_S = 0x04, - CELL_PATH_W = 0x08, - CELL_VISITED = 0x10, - }; - - std::stack> m_stack; - - - auto offset = [&](int x, int y) - { - return (m_stack.top().second + y) * nCellsX + (m_stack.top().first + x); - }; - - m_stack.push(std::make_pair(0, 0)); - pLevel[0] = CELL_VISITED; - int nVisitedCells = 1; - - // Do Maze Algorithm - while (nVisitedCells < nCellsX * nCellsY) - { - // Step 1: Create a set of the unvisted neighbours - - std::vector neighbours; - - // North Neighbour - if (m_stack.top().second > 0 && (pLevel[offset(0, -1)] & CELL_VISITED) == 0) - neighbours.push_back(0); - // East neighbour - if (m_stack.top().first < nCellsX - 1 && (pLevel[offset(1, 0)] & CELL_VISITED) == 0) - neighbours.push_back(1); - // South neighbour - if (m_stack.top().second < nCellsY - 1 && (pLevel[offset(0, 1)] & CELL_VISITED) == 0) - neighbours.push_back(2); - // West neighbour - if (m_stack.top().first > 0 && (pLevel[offset(-1, 0)] & CELL_VISITED) == 0) - neighbours.push_back(3); - - - // Are there any neighbours available? - if (!neighbours.empty()) - { - // Choose one available neighbour at random - int next_cell_dir = neighbours[rand() % neighbours.size()]; - - // Create a path between the neighbour and the current cell - switch (next_cell_dir) - { - case 0: // North - pLevel[offset(0, -1)] |= CELL_VISITED | CELL_PATH_S; - pLevel[offset(0, 0)] |= CELL_PATH_N; - m_stack.push(std::make_pair((m_stack.top().first + 0), (m_stack.top().second - 1))); - break; - - case 1: // East - pLevel[offset(+1, 0)] |= CELL_VISITED | CELL_PATH_W; - pLevel[offset(0, 0)] |= CELL_PATH_E; - m_stack.push(std::make_pair((m_stack.top().first + 1), (m_stack.top().second + 0))); - break; - - case 2: // South - pLevel[offset(0, +1)] |= CELL_VISITED | CELL_PATH_N; - pLevel[offset(0, 0)] |= CELL_PATH_S; - m_stack.push(std::make_pair((m_stack.top().first + 0), (m_stack.top().second + 1))); - break; - - case 3: // West - pLevel[offset(-1, 0)] |= CELL_VISITED | CELL_PATH_E; - pLevel[offset(0, 0)] |= CELL_PATH_W; - m_stack.push(std::make_pair((m_stack.top().first - 1), (m_stack.top().second + 0))); - break; - - } - - nVisitedCells++; - } - else - { - m_stack.pop(); // Backtrack - } - } - - printf("M1 %d\n", m_stack.size()); - - // Convert Maze into tile map - nMapWidth = (nCellWidth + 1) * nCellsX + 1; - nMapHeight = (nCellHeight + 1) * nCellsY + 1; - pMap = new bool[nMapWidth * nMapHeight]{ 0 }; - printf("M1\n"); - - // Draw Maze - for (int x = 0; x < nCellsX; x++) - { - for (int y = 0; y < nCellsY; y++) - { - for (int py = 0; py < nCellHeight; py++) - for (int px = 0; px < nCellWidth; px++) - { - if (pLevel[y * nCellsX + x] & CELL_VISITED) - pMap[(y* (nCellHeight + 1) + py + 1) * nMapWidth + (x * (nCellWidth + 1) + px) + 1] = true; - else - pMap[(y* (nCellHeight + 1) + py + 1) * nMapWidth + (x * (nCellWidth + 1) + px + 1)] = false; - } - - for (int p = 0; p < nCellWidth; p++) - if (pLevel[y * nCellsX + x] & CELL_PATH_S) - pMap[(y * (nCellHeight + 1) + nCellHeight + 1) * nMapWidth + (x * (nCellWidth + 1) + p + 1)] = true; - - for (int p = 0; p < nCellHeight; p++) - if (pLevel[y * nCellsX + x] & CELL_PATH_E) - pMap[(y * (nCellHeight + 1) + p + 1) * nMapWidth + (x * (nCellWidth + 1) + nCellWidth + 1)] = true; - } - } - - printf("M1\n"); - delete[] pLevel; - printf("M1\n"); - } - - void CalculateFlowMap() - { - // Update Flow map - - int nFlowWidth = layerJavid.nLayerWidth; - int nFlowHeight = layerJavid.nLayerHeight; - - // 1) Prepare it centered on player - for (int x = 0; x < nFlowWidth; x++) - for (int y = 0; y < nFlowHeight; y++) - { - layerJavid.GetTile(x, y)->id = 2; - layerJavid.GetTile(x, y)->edge_id[0] = 0; - - if (x == 0 || x == (nFlowWidth - 1) || y == 0 || y == (nFlowHeight - 1)) - layerJavid.GetTile(x, y)->edge_id[0] = -1; - else - //layerJavid.GetTile(x, y)->exist = layerWorld.GetTile(x, y)->exist; - layerJavid.GetTile(x, y)->edge_id[0] = layerWorld.GetTile(x, y)->exist ? -1 : 0; - - - } - - - - list> nodes; - - nodes.push_back({ listKeys.back().first,listKeys.back().second, 1 }); - - while (!nodes.empty()) - { - list> new_nodes; - - // For each node in processing queue, set its count value, and add unmarked - // neighbour nodes - for (auto &n : nodes) - { - int x = get<0>(n); - int y = get<1>(n); - int d = get<2>(n); - - // Set distance for this node - layerJavid.GetTile(x, y)->edge_id[0] = d; - - // Add neigbour nodes if unmarked - if ((x + 1) < nFlowWidth && layerJavid.GetTile(x+1, y)->edge_id[0] == 0) - new_nodes.push_back({ x + 1, y, d + 1 }); - if ((x - 1) >= 0 && layerJavid.GetTile(x - 1, y)->edge_id[0] == 0) - new_nodes.push_back({ x - 1, y, d + 1}); - if ((y + 1) < nFlowHeight && layerJavid.GetTile(x, y+1)->edge_id[0] == 0) - new_nodes.push_back({ x, y + 1, d + 1 }); - if ((y - 1) >= 0 && layerJavid.GetTile(x, y-1)->edge_id[0] == 0) - new_nodes.push_back({ x, y - 1, d + 1 }); - } - - new_nodes.sort([&](const tuple &n1, const tuple &n2) - { - return (get<1>(n1) * layerJavid.nLayerWidth + get<0>(n1)) < (get<1>(n2) * layerJavid.nLayerWidth + get<0>(n2)); - }); - - new_nodes.unique([&](const tuple &n1, const tuple &n2) - { - return (get<1>(n1) * layerJavid.nLayerWidth + get<0>(n1)) == (get<1>(n2) * layerJavid.nLayerWidth + get<0>(n2)); - }); - - - nodes.clear(); - nodes.insert(nodes.begin(), new_nodes.begin(), new_nodes.end()); - } - - for (int x = 0; x < nFlowWidth; x++) - { - for (int y = 0; y < nFlowHeight; y++) - { - if (layerJavid.GetTile(x, y)->edge_id[0] > 0) - { - int flow_xa, flow_xb, flow_ya, flow_yb; - flow_xa = flow_xb = flow_ya = flow_yb = layerJavid.GetTile(x, y)->edge_id[0]; - - if ((x + 1) < nFlowWidth && layerJavid.GetTile(x+1, y)->edge_id[0] > 0) - flow_xb = layerJavid.GetTile(x + 1, y)->edge_id[0]; - - if ((x - 1) >= 0 && layerJavid.GetTile(x-1, y)->edge_id[0] > 0) - flow_xa = layerJavid.GetTile(x - 1, y)->edge_id[0]; - - if ((y + 1) < nFlowHeight && layerJavid.GetTile(x, y+1)->edge_id[0] > 0) - flow_yb = layerJavid.GetTile(x, y + 1)->edge_id[0]; - - if ((y - 1) >= 0 && layerJavid.GetTile(x, y-1)->edge_id[0] > 0) - flow_ya = layerJavid.GetTile(x, y - 1)->edge_id[0]; - - float fdx = (float)(flow_xa - flow_xb); - float fdy = (float)(flow_ya - flow_yb); - float r = 1.0f / sqrtf(fdx * fdx + fdy * fdy); - - if (fabs(fdx) > fabs(fdy)) - { - if (fdx > 0) - { - layerJavid.GetTile(x, y)->exist = true; - layerJavid.GetTile(x, y)->id = 8; - } - - if (fdx < 0) - { - layerJavid.GetTile(x, y)->exist = true; - layerJavid.GetTile(x, y)->id = 10; - } - } - else - { - if (fdy > 0) - { - layerJavid.GetTile(x, y)->exist = true; - layerJavid.GetTile(x, y)->id = 9; - } - - if (fdy < 0) - { - layerJavid.GetTile(x, y)->exist = true; - layerJavid.GetTile(x, y)->id = 7; - } - } - } - } - } - } - - void CreateBorderMap() - { - // Use OLC Standard Bordered tile atlas - for (int x = 0; x < layerWorld.nLayerWidth; x++) - { - for (int y = 0; y < layerWorld.nLayerHeight; y++) - { - int s = 0; - auto a = [&](int i, int j) - { - return (layerWorld.GetTile(i, j) && layerWorld.GetTile(i, j)->exist); - }; - - if (a(x, y)) - { - s |= a(x - 1, y + 0) ? 1 : 0; s <<= 1; - s |= a(x - 1, y + 1) ? 1 : 0; s <<= 1; - s |= a(x + 0, y + 1) ? 1 : 0; s <<= 1; - s |= a(x + 1, y + 1) ? 1 : 0; s <<= 1; - s |= a(x + 1, y + 0) ? 1 : 0; s <<= 1; - s |= a(x + 1, y - 1) ? 1 : 0; s <<= 1; - s |= a(x - 0, y - 1) ? 1 : 0; s <<= 1; - s |= a(x - 1, y - 1) ? 1 : 0; - - int ix = s % 16; - int iy = s / 16; - layerWorld.GetTile(x, y)->id = (iy * 256 + 64) + (ix * 4) + 1; - } - else - layerWorld.GetTile(x, y)->id = 0; - } - } - } - -public: - - int sndHelperChange; - int sndJump; - int sndWall; - int sndGithubPatch; - int sndKeyCollect; - int sndDiskCollect; - int sndThump; - int sndTheme; - - - - bool OnUserCreate() override - { - controller.Initialize(); - backBuff = new olc::Sprite(ScreenWidth(), ScreenHeight()); - - olc::SOUND::InitialiseAudio(); - - animPlayer.ChangeState("idle"); - return true; - } - - bool OnUserDestroy() - { - olc::SOUND::DestroyAudio(); - return true; - } - - bool bFirstFrameLoading = true; - - bool GameState_Loading(float fElapsedTime) - { - - - - if (bFirstFrameLoading) - { - Clear(olc::BLACK); - DrawString(60, 240, "- Loading, Please Wait - ", olc::WHITE, 2); - bFirstFrameLoading = false; - - return true; - } - - rpPlayer.LoadPack("./discres/savingsedit.olcdat"); - - sndHelperChange = olc::SOUND::LoadAudioSample("E:\\linshare\\olcSimpleGameEngine\\discres\\PP_Negative_Trigger_1_2.wav", &rpPlayer); - sndJump = olc::SOUND::LoadAudioSample("E:\\linshare\\olcSimpleGameEngine\\discres\\PP_Jump_1_5.wav", &rpPlayer); - sndWall = olc::SOUND::LoadAudioSample("E:\\linshare\\olcSimpleGameEngine\\discres\\LQ_Back_Button.wav", &rpPlayer); - sndThump = olc::SOUND::LoadAudioSample("E:\\linshare\\olcSimpleGameEngine\\discres\\PP_Small_Impact_1_1.wav", &rpPlayer); - sndGithubPatch = olc::SOUND::LoadAudioSample("E:\\linshare\\olcSimpleGameEngine\\discres\\PP_Skill_Unlock.wav", &rpPlayer); - sndKeyCollect = olc::SOUND::LoadAudioSample("E:\\linshare\\olcSimpleGameEngine\\discres\\FA_Special_Item_2_1.wav", &rpPlayer); - sndDiskCollect = olc::SOUND::LoadAudioSample("E:\\linshare\\olcSimpleGameEngine\\discres\\FA_Funny_Impact_1_3.wav", &rpPlayer); - sndTheme = olc::SOUND::LoadAudioSample("E:\\linshare\\olcSimpleGameEngine\\discres\\Funky Chill 2 loop.wav", &rpPlayer); - - olc::SOUND::PlaySample(sndHelperChange); - - // Load Game Resources - // Define OLC Standard atlas - //atlasWorldMagetzub.Create(new olc::Sprite());// new olc::Sprite("thruster_landscape_all3_neo.png")); - //atlasWorldMagetzub.sprTileSheet->SaveToPGESprFile("discres\\discovery_magetzub_64x64.olcspr"); - //atlasWorldMagetzub.sprTileSheet->LoadFromPGESprFile("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_magetzub_64x64.olcspr"); - atlasWorldMagetzub.Create(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_magetzub_64x64.olcspr", &rpPlayer)); - - //atlasWorldJavid.Create(new olc::Sprite());//new olc::Sprite("discovery_javid_64x64.png")); - //atlasWorldJavid.sprTileSheet->SaveToPGESprFile("discres\\discovery_javid_64x64.olcspr"); - //atlasWorldJavid.sprTileSheet->LoadFromPGESprFile("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_javid_64x64.olcspr"); - atlasWorldJavid.Create(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_javid_64x64.olcspr", &rpPlayer)); - - //atlasWorldHopson.Create(new olc::Sprite());//new olc::Sprite("discovery_hopson_64x64.png")); - //atlasWorldHopson.sprTileSheet->SaveToPGESprFile("discres\\discovery_hopson_64x64.olcspr"); - atlasWorldHopson.Create(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_hopson_64x64.olcspr", &rpPlayer)); - //atlasWorldHopson.sprTileSheet->LoadFromPGESprFile("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_hopson_64x64.olcspr"); - for (int i = 0; i < 64; i++) - for (int j = 0; j < 64; j++) - { - //atlasWorld.location.emplace_back(j * 16, i * 16, 16, 16); - atlasWorldMagetzub.location.emplace_back(j * 64, i * 64, 64, 64); - atlasWorldJavid.location.emplace_back(j * 64, i * 64, 64, 64); - atlasWorldHopson.location.emplace_back(j * 64, i * 64, 64, 64); - } - - //atlasCollectibles.Create(new olc::Sprite());// "discovery_collect1.png")); - //atlasCollectibles.sprTileSheet->SaveToPGESprFile("discres\\discovery_collectibles.olcspr"); - //atlasCollectibles.sprTileSheet->LoadFromPGESprFile("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_collectibles.olcspr"); - atlasCollectibles.Create(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_collectibles.olcspr", &rpPlayer)); - atlasCollectibles.location.emplace_back(0, 0, 16, 16); // Blank - atlasCollectibles.location.emplace_back(16, 0, 16, 16); // Disk - atlasCollectibles.location.emplace_back(32, 0, 16, 16); // Exit - atlasCollectibles.location.emplace_back(48, 0, 16, 16); // Key - atlasCollectibles.location.emplace_back(64, 0, 16, 16); // Javid - atlasCollectibles.location.emplace_back(80, 0, 16, 16); // Github - atlasCollectibles.location.emplace_back(96, 0, 16, 16); // Hopson - atlasCollectibles.location.emplace_back(112, 0, 16, 16); // Up - atlasCollectibles.location.emplace_back(128, 0, 16, 16); // Right - atlasCollectibles.location.emplace_back(144, 0, 16, 16); // Down - atlasCollectibles.location.emplace_back(160, 0, 16, 16); // Left - - - - - animPlayer.mapStates["idle"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Idle_000.olcspr", &rpPlayer)); - animPlayer.mapStates["idle"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Idle_001.olcspr", &rpPlayer)); - animPlayer.mapStates["idle"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Idle_002.olcspr", &rpPlayer)); - animPlayer.mapStates["idle"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Idle_003.olcspr", &rpPlayer)); - animPlayer.mapStates["idle"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Idle_004.olcspr", &rpPlayer)); - animPlayer.mapStates["idle"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Idle_005.olcspr", &rpPlayer)); - animPlayer.mapStates["idle"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Idle_006.olcspr", &rpPlayer)); - animPlayer.mapStates["idle"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Idle_007.olcspr", &rpPlayer)); - animPlayer.mapStates["idle"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Idle_008.olcspr", &rpPlayer)); - animPlayer.mapStates["idle"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Idle_009.olcspr", &rpPlayer)); - animPlayer.mapStates["idle"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Idle_010.olcspr", &rpPlayer)); - animPlayer.mapStates["idle"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Idle_011.olcspr", &rpPlayer)); - - animPlayer.mapStates["idle_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_IdleFire_000.olcspr", &rpPlayer)); - animPlayer.mapStates["idle_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_IdleFire_001.olcspr", &rpPlayer)); - animPlayer.mapStates["idle_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_IdleFire_002.olcspr", &rpPlayer)); - animPlayer.mapStates["idle_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_IdleFire_003.olcspr", &rpPlayer)); - animPlayer.mapStates["idle_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_IdleFire_004.olcspr", &rpPlayer)); - animPlayer.mapStates["idle_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_IdleFire_005.olcspr", &rpPlayer)); - animPlayer.mapStates["idle_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_IdleFire_006.olcspr", &rpPlayer)); - animPlayer.mapStates["idle_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_IdleFire_007.olcspr", &rpPlayer)); - animPlayer.mapStates["idle_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_IdleFire_008.olcspr", &rpPlayer)); - animPlayer.mapStates["idle_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_IdleFire_009.olcspr", &rpPlayer)); - animPlayer.mapStates["idle_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_IdleFire_010.olcspr", &rpPlayer)); - animPlayer.mapStates["idle_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_IdleFire_011.olcspr", &rpPlayer)); - - animPlayer.mapStates["run"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Run_000.olcspr", &rpPlayer)); - animPlayer.mapStates["run"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Run_001.olcspr", &rpPlayer)); - animPlayer.mapStates["run"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Run_002.olcspr", &rpPlayer)); - animPlayer.mapStates["run"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Run_003.olcspr", &rpPlayer)); - animPlayer.mapStates["run"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Run_004.olcspr", &rpPlayer)); - animPlayer.mapStates["run"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Run_005.olcspr", &rpPlayer)); - animPlayer.mapStates["run"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Run_006.olcspr", &rpPlayer)); - animPlayer.mapStates["run"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Run_007.olcspr", &rpPlayer)); - animPlayer.mapStates["run"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Run_008.olcspr", &rpPlayer)); - animPlayer.mapStates["run"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Run_009.olcspr", &rpPlayer)); - animPlayer.mapStates["run"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Run_010.olcspr", &rpPlayer)); - animPlayer.mapStates["run"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Run_011.olcspr", &rpPlayer)); - - animPlayer.mapStates["run_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_RunFire_000.olcspr", &rpPlayer)); - animPlayer.mapStates["run_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_RunFire_001.olcspr", &rpPlayer)); - animPlayer.mapStates["run_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_RunFire_002.olcspr", &rpPlayer)); - animPlayer.mapStates["run_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_RunFire_003.olcspr", &rpPlayer)); - animPlayer.mapStates["run_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_RunFire_004.olcspr", &rpPlayer)); - animPlayer.mapStates["run_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_RunFire_005.olcspr", &rpPlayer)); - animPlayer.mapStates["run_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_RunFire_006.olcspr", &rpPlayer)); - animPlayer.mapStates["run_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_RunFire_007.olcspr", &rpPlayer)); - animPlayer.mapStates["run_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_RunFire_008.olcspr", &rpPlayer)); - animPlayer.mapStates["run_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_RunFire_009.olcspr", &rpPlayer)); - animPlayer.mapStates["run_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_RunFire_010.olcspr", &rpPlayer)); - animPlayer.mapStates["run_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_RunFire_011.olcspr", &rpPlayer)); - - animPlayer.mapStates["jump"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Jump_000.olcspr", &rpPlayer)); - animPlayer.mapStates["jump"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Jump_001.olcspr", &rpPlayer)); - animPlayer.mapStates["jump"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Jump_002.olcspr", &rpPlayer)); - animPlayer.mapStates["jump"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Jump_003.olcspr", &rpPlayer)); - animPlayer.mapStates["jump"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Jump_004.olcspr", &rpPlayer)); - animPlayer.mapStates["jump"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Jump_005.olcspr", &rpPlayer)); - - animPlayer.mapStates["fall"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Fall_000.olcspr", &rpPlayer)); - animPlayer.mapStates["fall"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Fall_001.olcspr", &rpPlayer)); - animPlayer.mapStates["fall"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Fall_002.olcspr", &rpPlayer)); - animPlayer.mapStates["fall"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Fall_003.olcspr", &rpPlayer)); - animPlayer.mapStates["fall"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Fall_004.olcspr", &rpPlayer)); - animPlayer.mapStates["fall"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_Fall_005.olcspr", &rpPlayer)); - - animPlayer.mapStates["air_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_AirFire_000.olcspr", &rpPlayer)); - animPlayer.mapStates["air_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_AirFire_001.olcspr", &rpPlayer)); - animPlayer.mapStates["air_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_AirFire_002.olcspr", &rpPlayer)); - animPlayer.mapStates["air_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_AirFire_003.olcspr", &rpPlayer)); - animPlayer.mapStates["air_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_AirFire_004.olcspr", &rpPlayer)); - animPlayer.mapStates["air_fire"].push_back(new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\Player_AirFire_005.olcspr", &rpPlayer)); - - //sprBackdropMagetzub = new olc::Sprite("discovery_magetzub_bg.png"); - //sprBackdropHopson = new olc::Sprite("discovery_hopson_bg.png"); - //sprTitleScreen = new olc::Sprite("discovery_titlescreen.png"); - //sprStoryScreen = new olc::Sprite("discovery_story.png"); - //sprCreditScreen = new olc::Sprite("discovery_credits.png"); - //sprControlScreen = new olc::Sprite("discovery_story2.png"); - //sprCompleteScreen = new olc::Sprite("discovery_title_bg.png"); - - //sprBackdropMagetzub->SaveToPGESprFile("discres\\discovery_magetzub_bg.olcspr"); - //sprBackdropHopson->SaveToPGESprFile("discres\\discovery_hopson_bg.olcspr"); - //sprTitleScreen->SaveToPGESprFile("discres\\discovery_titlescreen.olcspr"); - //sprStoryScreen->SaveToPGESprFile("discres\\discovery_story.olcspr"); - //sprCreditScreen->SaveToPGESprFile("discres\\discovery_credits.olcspr"); - //sprControlScreen->SaveToPGESprFile("discres\\discovery_story2.olcspr"); - //sprCompleteScreen->SaveToPGESprFile("discres\\discovery_title_bg.olcspr"); - - sprBackdropMagetzub = new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_magetzub_bg.olcspr", &rpPlayer); - sprBackdropHopson = new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_hopson_bg.olcspr", &rpPlayer); - sprTitleScreen = new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_titlescreen.olcspr", &rpPlayer); - sprStoryScreen = new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_story.olcspr", &rpPlayer); - sprCreditScreen = new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_credits.olcspr", &rpPlayer); - sprControlScreen = new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_story2.olcspr", &rpPlayer); - sprCompleteScreen = new olc::Sprite("E:\\linshare\\olcSimpleGameEngine\\discres\\discovery_title_bg.olcspr", &rpPlayer); - - rpPlayer.ClearPack(); - - nGameState = GS_TITLE; - - return true; - } - - int nTitleSelection = 0; - int nLevelSeed = 1; - int nLevelSize = 2; - - bool GameState_Title(float fElapsedTime) - { - controller.Update(fElapsedTime); - - DrawSprite(0, 0, sprTitleScreen); - - DrawString(300, 280, "Story & Help", nTitleSelection == 0 ? olc::WHITE : olc::YELLOW, 2); - DrawString(300, 310, "Credits", nTitleSelection == 1 ? olc::WHITE : olc::YELLOW, 2); - DrawString(300, 340, "Level: " + to_string(nLevelSeed), nTitleSelection == 2 ? olc::WHITE : olc::YELLOW, 2); - DrawString(300, 370, "Size: " + to_string((int)pow(2, (nLevelSize+2))), nTitleSelection == 3 ? olc::WHITE : olc::YELLOW, 2); - DrawString(300, 400, "Start", nTitleSelection == 4 ? olc::WHITE : olc::YELLOW, 2); - - if (GetKey(olc::Key::UP).bPressed || controller.GetButton(UP).bPressed) - { - nTitleSelection--; - if (nTitleSelection < 0) nTitleSelection = 4; - olc::SOUND::PlaySample(sndThump); - } - - if (GetKey(olc::Key::DOWN).bPressed || controller.GetButton(DOWN).bPressed) - { - nTitleSelection++; - if (nTitleSelection > 4 ) nTitleSelection = 0; - olc::SOUND::PlaySample(sndThump); - } - - if (GetKey(olc::Key::LEFT).bPressed || controller.GetButton(LEFT).bPressed) - { - if (nTitleSelection == 2) - { - nLevelSeed--; - if (nLevelSeed < 0) nLevelSeed = 999; - } - - if (nTitleSelection == 3) - { - nLevelSize--; - if (nLevelSize < 1) nLevelSize = 3; - } - } - - if (GetKey(olc::Key::RIGHT).bPressed || controller.GetButton(RIGHT).bPressed) - { - if (nTitleSelection == 2) - { - nLevelSeed++; - if (nLevelSeed > 999) nLevelSeed = 0; - } - - if (nTitleSelection == 3) - { - nLevelSize++; - if (nLevelSize > 3) nLevelSize = 1; - } - } - - if (GetKey(olc::Key::SPACE).bPressed || controller.GetButton(A).bPressed) - { - if (nTitleSelection == 0) nGameState = GS_STORY; - if (nTitleSelection == 1) nGameState = GS_CREDITS; - - if (nTitleSelection == 4) nGameState = GS_GENERATE; - } - - return true; - } - - bool GameState_Generating(float fElapsedTime) - { - fPlayerPosX = 2.0f; - fPlayerPosY = 2.0f; - fPlayerVelX = 0.0f; - fPlayerVelY = 0.0f; - fCameraPosX = 0.0f; - fCameraPosY = 0.0f; - bPlayerOnGround = false; - bPlayerTouchingWall = false; - bPlayerTouchingWallOld = false; - bCollisionLeft = false; - fTimeToJump = 0.0f; - fTimeToJumpMax = 0.25f; - fFaceDir = 1.0f; - nFloppyDisks = 0; - fGameTime = 0.0f; - fGameTimeMultiplier = 1.0f; - nHopsonTokens = 0; - nJavidTokens = 0; - nKeys = 0; - fEffectTime = 0.0f; - fModeTime = 0.0f; - - nChallengeMapSizeX = (int)pow(2, nLevelSize + 2); - nChallengeMapSizeY = (int)pow(2, nLevelSize + 2); - srand(nLevelSeed); - - - // Generate a boolean maze - bool *bTileMaze = nullptr; - int nMapWidth, nMapHeight; - printf("D\n"); - CreateMaze(bTileMaze, nChallengePathSizeX - 1, nChallengePathSizeY - 1, nChallengeMapSizeX, nChallengeMapSizeY, nMapWidth, nMapHeight); - - if (sprMiniMap != nullptr) delete sprMiniMap; - sprMiniMap = new olc::Sprite(nChallengeMapSizeX, nChallengeMapSizeY); - printf("D\n"); - // Create tilemap to match dimensions of generated maze - layerWorld.Create(nMapWidth, nMapHeight, nTileSizeX, nTileSizeY); - layerCollectibles.Create(nMapWidth, nMapHeight, nTileSizeX, nTileSizeY); - layerJavid.Create(nMapWidth, nMapHeight, nTileSizeX, nTileSizeY); - - printf("D\n"); - // Transfer over boolean maze to tilemap - for (int x = 0; x < layerWorld.nLayerWidth; x++) - for (int y = 0; y < layerWorld.nLayerHeight; y++) - { - layerWorld.GetTile(x, y)->exist = !bTileMaze[y*layerWorld.nLayerWidth + x]; - } - - printf("D\n"); - CreateBorderMap(); - - printf("D\n"); - delete[] bTileMaze; - printf("D\n"); - listKeys.clear(); - printf("D\n"); - // Add 100 Drops - for (int i = 0; i < 136; i++) - { - bool bDone = false; - do - { - int x = rand() % layerWorld.nLayerWidth; - int y = rand() % layerWorld.nLayerHeight; - if (!layerWorld.GetTile(x, y)->exist && !layerCollectibles.GetTile(x, y)->exist) - { - - layerCollectibles.GetTile(x, y)->exist = true; - if (i < 100) layerCollectibles.GetTile(x, y)->id = 1; // Place disks - if (i == 100) // Place Exit - { - layerCollectibles.GetTile(x, y)->id = 2; listKeys.push_back(make_pair(x, y)); - } - if (i > 100 && i <= 104)// Place Keys - { - layerCollectibles.GetTile(x, y)->id = 3; listKeys.push_back(make_pair(x, y)); - } - if (i > 105 && i <= 125) layerCollectibles.GetTile(x, y)->id = 5; // Place Githubs - if (i > 125 && i <= 130) layerCollectibles.GetTile(x, y)->id = 4; // Place Javids - if (i > 130 && i <= 135) layerCollectibles.GetTile(x, y)->id = 6; // Place Hopsons - bDone = true; - } - - } while (!bDone); - } - - olc::SOUND::PlaySample(sndTheme, true); - nGameState = GS_MAIN; - printf("Entering Main\n"); - - return true; - } - - bool GameState_Main(float fElapsedTime) - { - fGameTime += fElapsedTime * fGameTimeMultiplier; - - controller.Update(fElapsedTime); - animPlayer.Update(fElapsedTime); - - bool bStartWallJump = bPlayerTouchingWall & !bPlayerTouchingWallOld; - bPlayerTouchingWallOld = bPlayerTouchingWall; - - if (bStartWallJump) - { - fTimeToJump = fTimeToJumpMax; - olc::SOUND::PlaySample(sndWall); - } - - if (fTimeToJump >= 0.0f) - fTimeToJump -= fElapsedTime; - - bPlayerTouchingWall = false; - - // Handle Input - if (IsFocused()) - { - /*if (GetKey(olc::Key::F1).bReleased) nRenderMode = MODE_MAGETZUB; - if (GetKey(olc::Key::F2).bReleased) { - nRenderMode = MODE_JAVID; fModeTime = 500.0f; CalculateFlowMap(); - } - if (GetKey(olc::Key::F3).bReleased) nRenderMode = MODE_HOPSON; - - - if (GetKey(olc::Key::F5).bReleased) nRenderEffect = EFFECT_NONE; - if (GetKey(olc::Key::F6).bReleased) nRenderEffect = EFFECT_UGLYSWEDISHFISH; - if (GetKey(olc::Key::F7).bReleased) nRenderEffect = EFFECT_GORBIT; - if (GetKey(olc::Key::F8).bReleased) nRenderEffect = EFFECT_SEDIT;*/ - - /*if (GetKey(olc::Key::UP).bHeld || controller.GetButton(UP).bHeld) - { - fPlayerVelY = -2.0f; - } - - if (GetKey(olc::Key::DOWN).bHeld || controller.GetButton(DOWN).bHeld) - { - fPlayerVelY = 2.0f; - }*/ - - if (GetKey(olc::Key::LEFT).bHeld || controller.GetButton(LEFT).bHeld) - { - fPlayerVelX += (bPlayerOnGround ? -25.0f : -15.0f) *fElapsedTime; - fFaceDir = -1.0f; - } - - if (GetKey(olc::Key::RIGHT).bHeld || controller.GetButton(RIGHT).bHeld) - { - fPlayerVelX += (bPlayerOnGround ? 25.0f : 15.0f) *fElapsedTime; - fFaceDir = +1.0f; - } - - if (GetKey(olc::Key::SPACE).bPressed || controller.GetButton(A).bPressed) - { - if (bPlayerOnGround) - { - fPlayerVelY = -12.0f; - olc::SOUND::PlaySample(sndJump); - } - - if (fTimeToJump >= 0.0f) - { - if (fPlayerVelX < 0 && !bCollisionLeft) - { - fPlayerVelY = -12.0f; - olc::SOUND::PlaySample(sndJump); - } - - if (fPlayerVelX > 0 && bCollisionLeft) - { - fPlayerVelY = -12.0f; - olc::SOUND::PlaySample(sndJump); - } - } - } - - - bFire = false; - if (GetKey(olc::Key::A).bPressed || controller.GetButton(X).bPressed) - { - //bFire = true; - - if (nRenderMode == MODE_HOPSON) - { - if (fFaceDir < 0) - { - int bx = fPlayerPosX; - int by = fPlayerPosY + 0.5f; - if (bx > 0 && bx < (layerWorld.nLayerWidth - 1) && by > 0 && by < (layerWorld.nLayerHeight - 1) && layerWorld.GetTile(bx, by)->exist) - { - layerWorld.GetTile(bx, by)->exist = false; - CreateBorderMap(); - } - } - else - { - int bx = fPlayerPosX + 1.0f; - int by = fPlayerPosY + 0.5f; - if (bx > 0 && bx < (layerWorld.nLayerWidth - 1) && by > 0 && by < (layerWorld.nLayerHeight - 1) && layerWorld.GetTile(bx, by)->exist) - { - layerWorld.GetTile(bx, by)->exist = false; - CreateBorderMap(); - } - - } - } - } - - if (GetKey(olc::Key::J).bPressed || controller.GetButton(Y).bPressed) - { - if (nRenderMode != MODE_JAVID && nJavidTokens > 0) - { - nJavidTokens--; - nRenderMode = MODE_JAVID; - fModeTime = 60.0f; - CalculateFlowMap(); - olc::SOUND::PlaySample(sndHelperChange); - } - } - - if (GetKey(olc::Key::H).bPressed || controller.GetButton(B).bPressed) - { - if (nRenderMode != MODE_HOPSON && nHopsonTokens > 0) - { - nHopsonTokens--; - nRenderMode = MODE_HOPSON; - fModeTime = 30.0f; - olc::SOUND::PlaySample(sndHelperChange); - } - } - } - - - fPlayerVelY += 20.0f * fElapsedTime; - - if (bPlayerOnGround) - { - - fPlayerVelX += -3.0f * fPlayerVelX * fElapsedTime; - if (fabs(fPlayerVelX) < 0.01f) - { - fPlayerVelX = 0.0f; - animPlayer.ChangeState(bFire ? "idle_fire" : "idle"); - } - else - { - animPlayer.ChangeState(bFire ? "run_fire" : "run"); - } - - } - else - { - if (!bFire) - { - if (fPlayerVelY < 0) - animPlayer.ChangeState("jump"); - else - animPlayer.ChangeState("fall"); - } - else - animPlayer.ChangeState("air_fire"); - } - - - if (layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->id == 1) // Disk - { - layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->id = 0; - layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->exist = false; - nFloppyDisks++; - olc::SOUND::PlaySample(sndDiskCollect); - } - - if (layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->id == 2) // Exit - { - if (nKeys == 4) - { - // Game Completed - nGameState = GS_COMPLETE; - } - } - - if (layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->id == 3) // Keys - { - layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->id = 0; - layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->exist = false; - nKeys++; - - - // Remove key from list - listKeys.remove_if([&](pair &p) {return p.first == ((int)(fPlayerPosX + 0.5f)) && p.second == ((int)(fPlayerPosY + 0.5f)); }); - CalculateFlowMap(); - olc::SOUND::PlaySample(sndKeyCollect); - } - - if (layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->id == 4) // Javid - { - layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->id = 0; - layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->exist = false; - nJavidTokens++; - - //fModeTime = 30.0f; - //nRenderMode = MODE_JAVID; - - //if (nRenderMode == MODE_JAVID) - //{ - // // Javid is helpful and likes to simplify so help out the user - // CalculateFlowMap(); - //} - olc::SOUND::PlaySample(sndKeyCollect); - } - - if (layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->id == 6) // Hopson - { - layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->id = 0; - layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->exist = false; - nHopsonTokens++; - - /*fModeTime = 30.0f; - nRenderMode = MODE_HOPSON;*/ - olc::SOUND::PlaySample(sndKeyCollect); - } - - if (layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->id == 5) // Github - { - layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->id = 0; - layerCollectibles.GetTile(fPlayerPosX + 0.5f, fPlayerPosY + 0.5f)->exist = false; - fEffectTime = 10.0f; - switch (rand() % 4) - { - case 0: nRenderEffect = EFFECT_UGLYSWEDISHFISH; break; - case 1: nRenderEffect = EFFECT_SEDIT; break; - case 2: nRenderEffect = EFFECT_GORBIT; break; - case 3: nRenderEffect = EFFECT_BRANK; break; - } - fGameTimeMultiplier = 0.75f; - olc::SOUND::PlaySample(sndGithubPatch); - } - - if (fEffectTime > 0.0f) - { - fEffectTime -= fElapsedTime; - } - else - { - nRenderEffect = EFFECT_NONE; - fGameTimeMultiplier = 1.0f; - } - - - if (fModeTime > 0.0f) - { - fModeTime -= fElapsedTime; - } - else - { - nRenderMode = MODE_MAGETZUB; - //olc::SOUND::PlaySample(sndHelperChange); - } - - - if (fPlayerVelX > 10.0f) - fPlayerVelX = 10.0f; - - if (fPlayerVelX < -10.0f) - fPlayerVelX = -10.0f; - - if (fPlayerVelY > 100.0f) - fPlayerVelY = 100.0f; - - if (fPlayerVelY < -100.0f) - fPlayerVelY = -100.0f; - - sprMiniMap->SetPixel(fPlayerPosX / nChallengePathSizeX, fPlayerPosY / nChallengePathSizeY, olc::GREEN); - - float fNewPlayerPosX = fPlayerPosX + fPlayerVelX * fElapsedTime; - float fNewPlayerPosY = fPlayerPosY + fPlayerVelY * fElapsedTime; - - sprMiniMap->SetPixel(fNewPlayerPosX / nChallengePathSizeX, fNewPlayerPosY / nChallengePathSizeY, olc::WHITE); - - // Collision - float fOffset = 0.2f; - if (fPlayerVelX <= 0) - { - if (layerWorld.GetTile(fNewPlayerPosX + 0.0f + fOffset, fPlayerPosY + 0.0f)->exist || layerWorld.GetTile(fNewPlayerPosX + 0.0f + fOffset, fPlayerPosY + 0.9f)->exist) - { - fNewPlayerPosX = (int)fNewPlayerPosX + 1 - fOffset; - fPlayerVelX = 0; - bPlayerTouchingWall = true; - bCollisionLeft = true; - } - } - else - { - if (layerWorld.GetTile(fNewPlayerPosX + 1.0f - fOffset, fPlayerPosY + 0.0f)->exist || layerWorld.GetTile(fNewPlayerPosX + 1.0f - fOffset, fPlayerPosY + 0.9f)->exist) - { - fNewPlayerPosX = (int)fNewPlayerPosX + fOffset; - fPlayerVelX = 0; - bPlayerTouchingWall = true; - bCollisionLeft = false; - } - } - - bPlayerOnGround = false; - if (fPlayerVelY <= 0) - { - if (layerWorld.GetTile(fNewPlayerPosX + 0.0f + fOffset, fNewPlayerPosY)->exist || layerWorld.GetTile(fNewPlayerPosX + 0.9f - fOffset, fNewPlayerPosY)->exist) - { - fNewPlayerPosY = (int)fNewPlayerPosY + 1; - fPlayerVelY = 0; - } - } - else - { - if (layerWorld.GetTile(fNewPlayerPosX + 0.0f + fOffset, fNewPlayerPosY + 1.0f)->exist || layerWorld.GetTile(fNewPlayerPosX + 0.9f - fOffset, fNewPlayerPosY + 1.0f)->exist) - { - fNewPlayerPosY = (int)fNewPlayerPosY; - fPlayerVelY = 0; - bPlayerOnGround = true; - - } - } - - fPlayerPosX = fNewPlayerPosX; - fPlayerPosY = fNewPlayerPosY; - - fCameraPosX = fPlayerPosX; - fCameraPosY = fPlayerPosY; - - int nVisibleTilesX = ScreenWidth() / nTileSizeX; - int nVisibleTilesY = ScreenHeight() / nTileSizeY; - - // Calculate Top-Leftmost visible tile - float fOffsetX = fCameraPosX - (float)nVisibleTilesX / 2.0f; - float fOffsetY = fCameraPosY - (float)nVisibleTilesY / 2.0f; - - - // Clamp camera to game boundaries - if (fOffsetX < 0) fOffsetX = 0; - if (fOffsetY < 0) fOffsetY = 0; - if (fOffsetX > layerWorld.nLayerWidth - nVisibleTilesX) fOffsetX = layerWorld.nLayerWidth - nVisibleTilesX; - if (fOffsetY > layerWorld.nLayerHeight - nVisibleTilesY) fOffsetY = layerWorld.nLayerHeight - nVisibleTilesY; - - - - - - SetDrawTarget(backBuff); - //Clear(olc::VERY_DARK_BLUE); - - - if (nRenderMode == MODE_MAGETZUB) - { - fBackdropScaleX = (float)(sprBackdropMagetzub->width - ScreenWidth()) / (float)((layerWorld.nLayerWidth) + (float)nVisibleTilesX); - fBackdropScaleY = (float)(sprBackdropMagetzub->height - ScreenHeight()) / (float)((layerWorld.nLayerHeight) + (float)nVisibleTilesY); - DrawPartialSprite(0, 0, sprBackdropMagetzub, fOffsetX * fBackdropScaleX, fOffsetY * fBackdropScaleY, ScreenWidth(), ScreenHeight()); - - - SetPixelMode(olc::Pixel::ALPHA); - olc::TILE::DrawLayer(layerWorld, atlasWorldMagetzub, fOffsetX, fOffsetY, nVisibleTilesX + 1, nVisibleTilesY + 1, 1); - olc::TILE::DrawLayer(layerCollectibles, atlasCollectibles, fOffsetX, fOffsetY, nVisibleTilesX + 1, nVisibleTilesY + 1, 3); - SetPixelMode(olc::Pixel::NORMAL); - } - - if (nRenderMode == MODE_HOPSON) - { - fBackdropScaleX = (float)(sprBackdropHopson->width - ScreenWidth()) / (float)((layerWorld.nLayerWidth) + (float)nVisibleTilesX); - fBackdropScaleY = (float)(sprBackdropHopson->height - ScreenHeight()) / (float)((layerWorld.nLayerHeight) + (float)nVisibleTilesY); - DrawPartialSprite(0, 0, sprBackdropHopson, fOffsetX * fBackdropScaleX, fOffsetY * fBackdropScaleY, ScreenWidth(), ScreenHeight()); - - - SetPixelMode(olc::Pixel::ALPHA); - olc::TILE::DrawLayer(layerWorld, atlasWorldHopson, fOffsetX, fOffsetY, nVisibleTilesX + 1, nVisibleTilesY + 1, 1); - olc::TILE::DrawLayer(layerCollectibles, atlasCollectibles, fOffsetX, fOffsetY, nVisibleTilesX + 1, nVisibleTilesY + 1, 3); - SetPixelMode(olc::Pixel::NORMAL); - } - - if (nRenderMode == MODE_JAVID) - { - Clear(olc::BLACK); - SetPixelMode(olc::Pixel::ALPHA); - olc::TILE::DrawLayer(layerWorld, atlasWorldJavid, fOffsetX, fOffsetY, nVisibleTilesX + 1, nVisibleTilesY + 1, 1); - - olc::TILE::DrawLayer(layerJavid, atlasCollectibles, fOffsetX, fOffsetY, nVisibleTilesX + 1, nVisibleTilesY + 1, 3); - - olc::TILE::DrawLayer(layerCollectibles, atlasCollectibles, fOffsetX, fOffsetY, nVisibleTilesX + 1, nVisibleTilesY + 1, 3); - SetPixelMode(olc::Pixel::NORMAL); - } - - // Draw Player - - olc::GFX2D::Transform2D t; - t.Translate(-220.0f, 174.0f); - t.Scale(fFaceDir * 0.25f, 0.25f); - - t.Translate((fPlayerPosX - fOffsetX) * nTileSizeX + 32, (fPlayerPosY - fOffsetY) * nTileSizeY - 48); - - SetPixelMode(olc::Pixel::ALPHA); - animPlayer.DrawSelf(this, t); - SetPixelMode(olc::Pixel::NORMAL); - - - //this_thread::sleep_for(20ms); - - string s = "Disks: " + to_string(nFloppyDisks) + "/100\nJx9: " + to_string(nJavidTokens) + " Hop: " + to_string(nHopsonTokens) + "\nKeys: " + to_string(nKeys) + " /4"; - - - - DrawString(11, 11, s, olc::BLACK, 2); - DrawString(9, 9, s, olc::YELLOW, 2); - - SetPixelBlend(0.5f); - SetPixelMode(olc::Pixel::ALPHA); - DrawSprite(10, ScreenHeight() - (sprMiniMap->height + 4) * 3, sprMiniMap, 3); - SetPixelMode(olc::Pixel::NORMAL); - SetPixelBlend(1.0f); - - //Draw(10 + (fNewPlayerPosX / nChallengePathSizeX), ScreenHeight() - sprMiniMap->height - 8 + (fNewPlayerPosY / nChallengePathSizeY), olc::YELLOW); - - //DrawString(10, ScreenHeight() - (sprMiniMap->height - 16) * 2, "Map", olc::BLACK, 2); - //DrawString(9, ScreenHeight() - (sprMiniMap->height - 17) * 2, "Map", olc::YELLOW, 2); - - // Draw Time Information - int minutes = (int)fGameTime / 60; - int seconds = (int)fGameTime - (minutes * 60); - string sMinutes = (minutes <= 9 ? "0" : "") + to_string(minutes); - string sSeconds = (seconds <= 9 ? "0" : "") + to_string(seconds); - DrawString(ScreenWidth() - 158, 12, sMinutes + ":" + sSeconds, olc::BLACK, 3); - DrawString(ScreenWidth() - 160, 10, sMinutes + ":" + sSeconds, olc::YELLOW, 3); - - if (fGameTimeMultiplier != 1.0f) - { - DrawString(ScreenWidth() - 158, 50, "x0.75", olc::BLACK, 4); - DrawString(ScreenWidth() - 160, 53, "x0.75", olc::YELLOW, 4); - } - - SetDrawTarget(nullptr); - - - // UglySwedishFisk Mode - if (nRenderEffect == EFFECT_UGLYSWEDISHFISH) - { - int sparkles = 100 / fElapsedTime; - for (int i = 0; i < sparkles; i++) - { - int x = rand() % ScreenWidth(); - int y = rand() % ScreenHeight(); - Draw(x, y, backBuff->GetPixel(x, y)); - } - } - - if (nRenderEffect == EFFECT_GORBIT) - { - int sparkles = 10 / fElapsedTime; - for (int i = 0; i < sparkles; i++) - { - int x = rand() % 32; - int y = rand() % 32; - DrawPartialSprite(x * 32, y * 32, backBuff, x * 32, y * 32, 32, 32); - } - } - - - if (nRenderEffect == EFFECT_SEDIT) - { - SetPixelMode([](int x, int y, const olc::Pixel &s, const olc::Pixel &d) - { - olc::Pixel p = s; - if (y % 2) - { - float c = ((float)s.r * 1.5f + (float)s.g * 1.5f + (float)s.b * 1.5f) / 3.0f; - p.r = c; - p.g = c; - p.b = c; - } - return p; - }); - - DrawSprite(0, 0, backBuff); - - SetPixelMode(olc::Pixel::NORMAL); - } - - if (nRenderEffect == EFFECT_BRANK) - { - for (int i = 0; i < 4; i++) - { - int sx = rand() % 2; - int sy = rand() % 2; - int tx = rand() % 2; - int ty = rand() % 2; - DrawPartialSprite(0, 0, backBuff, ScreenWidth()/2,ScreenHeight()/2, ScreenWidth()/2, ScreenHeight()/2); - DrawPartialSprite(ScreenWidth()/2, 0, backBuff, 0, ScreenHeight() / 2, ScreenWidth() / 2, ScreenHeight() / 2); - DrawPartialSprite( 0,ScreenHeight()/2, backBuff, ScreenWidth()/2, 0, ScreenWidth() / 2, ScreenHeight() / 2); - DrawPartialSprite(ScreenWidth() / 2, ScreenHeight()/2, backBuff, 0, 0, ScreenWidth() / 2, ScreenHeight() / 2); - } - } - - - - // No effect mode - if (nRenderEffect == EFFECT_NONE) - DrawSprite(0, 0, backBuff); - - string sHelper = ""; - if (nRenderEffect == EFFECT_UGLYSWEDISHFISH) - sHelper = "UGLYSWEDISHFISH Is Patching Your Code!\nHonestly, It's better like this..."; - if (nRenderEffect == EFFECT_GORBIT) - sHelper = "GORBIT Is Patching Your Code!\nLook how beautiful my gifs are..."; - if (nRenderEffect == EFFECT_SEDIT) - sHelper = "SEDIT Is Patching Your Code!\nI'm only going to change one little thing... oh."; - if (nRenderEffect == EFFECT_BRANK) - sHelper = "BRANKEC Is Patching Your Code!\nNow it'll be at least 7623 FPS..."; - - DrawString(ScreenWidth() - 338, ScreenHeight() - 22, sHelper, olc::BLACK); - DrawString(ScreenWidth() - 339, ScreenHeight() - 23, sHelper, olc::YELLOW); - return true; - } - - bool GameState_Complete(float fElapsedTime) - { - - controller.Update(fElapsedTime); - DrawSprite(0, 0, sprCompleteScreen); - - DrawString(4, 10, "YOU SAVED SEDIT!", olc::YELLOW, 4); - - int minutes = (int)fGameTime / 60; - int seconds = (int)fGameTime - (minutes * 60); - string sMinutes = (minutes <= 9 ? "0" : "") + to_string(minutes); - string sSeconds = (seconds <= 9 ? "0" : "") + to_string(seconds); - string sTime = "Your Time: " + sMinutes + ":" + sSeconds; - DrawString(10, 200, sTime, olc::YELLOW, 2); - DrawString(10, 240, "OS Disks Found: " + to_string(nFloppyDisks) + "/100", olc::YELLOW, 2); - DrawString(10, 260, "Level: " + to_string(nLevelSeed) + " Size: " + to_string((int)pow(2,2+nLevelSize)), olc::YELLOW, 2); - DrawString(10, 300, "Jump to Title Screen?", olc::YELLOW, 2); - - if (GetKey(olc::Key::SPACE).bPressed || controller.GetButton(A).bPressed) - { - nGameState = GS_TITLE; - } - - return true; - } - - int nStoryStage = 0; - - bool GameState_Story(float fElapsedTime) - { - controller.Update(fElapsedTime); - - if(nStoryStage == 0) - DrawSprite(0, 0, sprStoryScreen); - else - DrawSprite(0, 0, sprControlScreen); - - if (GetKey(olc::Key::SPACE).bPressed || controller.GetButton(A).bPressed) - { - nStoryStage++; - if (nStoryStage == 2) - { - nGameState = GS_TITLE; - nStoryStage = 0; - } - } - - return true; - } - - bool GameState_Credits(float fElapsedTime) - { - controller.Update(fElapsedTime); - DrawSprite(0, 0, sprCreditScreen); - if (GetKey(olc::Key::SPACE).bPressed || controller.GetButton(A).bPressed) - { - nGameState = GS_TITLE; - } - return true; - } - - bool OnUserUpdate(float fElapsedTime) override - { - - switch (nGameState) - { - case GS_LOADING: GameState_Loading(fElapsedTime); break; - case GS_TITLE: GameState_Title(fElapsedTime); break; - case GS_GENERATE: GameState_Generating(fElapsedTime); break; - case GS_MAIN: GameState_Main(fElapsedTime); break; - case GS_STORY: GameState_Story(fElapsedTime); break; - case GS_CREDITS: GameState_Credits(fElapsedTime); break; - case GS_COMPLETE: GameState_Complete(fElapsedTime); break; - } - - return true; - } -}; - -int main() -{ - Discovery demo; - if (demo.Construct(512, 448, 2, 2)) - demo.Start(); - return 0; -} diff --git a/Videos/SavingSedit/Zix_PGE_Controller.h b/Videos/SavingSedit/Zix_PGE_Controller.h deleted file mode 100644 index c68dfed..0000000 --- a/Videos/SavingSedit/Zix_PGE_Controller.h +++ /dev/null @@ -1,224 +0,0 @@ -#pragma once - -#ifdef WIN32 -#include -#include - -typedef DWORD(WINAPI XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE* pState); -static XInputGetState_t* XInputStateGet; - -typedef DWORD(WINAPI XInputSetState_t)(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration); -static XInputSetState_t* XInputStateSet; -#endif - -#define C_BUTTON_COUNT 14 -enum CButton -{ - UP, - DOWN, - LEFT, - RIGHT, - START, - BACK, - A, - B, - X, - Y, - LEFT_SHOULDER, - RIGHT_SHOULDER, - LEFT_THUMB, - RIGHT_THUMB -}; - -struct CBState -{ - bool bPressed = false; - bool bReleased = false; - bool bHeld = false; -}; - -class ControllerManager -{ -private: - bool buttonState[C_BUTTON_COUNT]; - bool lastButtonState[C_BUTTON_COUNT]; - - // Trigger values are in the range of 0 to 1, where 0 is fully - // released and 1 is fully pressed. - float triggerLeft = 0; - float triggerRight = 0; - - // Stick values are in the range of -1 to 1. For X values, -1 is - // all the way to the left while +1 is all the way to the right. - float leftStickX = 0; - float leftStickY = 0; - float rightStickX = 0; - float rightStickY = 0; - - // Whether or not the controller is plugged in. - bool pluggedIn = true; - - bool vibrating = false; - float vibrateTime = 0; - float vibrateCounter = 0; - -public: - bool Initialize(); - void Update(float dt); - - void Vibrate(short amt, int timeMs); - - CBState GetButton(CButton button); - - float GetLeftTrigger() { return triggerLeft; } - float GetRightTrigger() { return triggerRight; } - - float GetLeftStickX() { return leftStickX; } - float GetLeftStickY() { return leftStickY; } - - float GetRightStickX() { return rightStickX; } - float GetRightStickY() { return rightStickY; } - - bool IsVibrating() { return vibrating; } - bool IsPluggedIn() { return pluggedIn; } - -private: - float NormalizeStickValue(short value); -}; - -bool ControllerManager::Initialize() -{ -#ifdef WIN32 - // TODO: Should we check for version 9.1.0 if we fail to find 1.4? - HMODULE lib = LoadLibraryA("xinput1_4.dll"); - - if (!lib) return false; - - XInputStateGet = (XInputGetState_t*)GetProcAddress(lib, "XInputGetState"); - XInputStateSet = (XInputSetState_t*)GetProcAddress(lib, "XInputSetState"); -#endif - - return true; -} - -float ControllerManager::NormalizeStickValue(short value) -{ - // The value we are given is in the range -32768 to 32767 with some deadzone around zero. - // We will assume all values in this dead zone to be a reading of zero (the stick is not moved). - if (value > -7000 && value < 7000) return 0; - - // Otherwise, we are going to normalize the value. - return ((value + 32768.0f) / (32768.0f + 32767.0f) * 2) - 1; -} - -void ControllerManager::Vibrate(short amt, int timeMs) -{ - // If we are already vibrating, just ignore this, unless they say zero, in which case we will let them stop it. - if (vibrating && amt != 0) return; - - // Only start the timer if we are actually vibrating. - if (amt != 0) - { - vibrateTime = timeMs / 1000.0f; - vibrating = true; - } -#ifdef WIN32 - XINPUT_VIBRATION info = - { - amt, - amt - }; - XInputStateSet(0, &info); -#endif -} - -CBState ControllerManager::GetButton(CButton button) -{ - return - { - !lastButtonState[button] && buttonState[button], - lastButtonState[button] && !buttonState[button], - lastButtonState[button] && buttonState[button] - }; -} - -void ControllerManager::Update(float dt) -{ -#ifdef WIN32 - if (vibrating) - { - vibrateCounter += dt; - if (vibrateCounter >= vibrateTime) - { - XINPUT_VIBRATION info = - { - 0, 0 - }; - XInputStateSet(0, &info); - - vibrating = false; - vibrateCounter = 0; - vibrateTime = 0; - } - } - - for (int i = 0; i < C_BUTTON_COUNT; i++) - { - lastButtonState[i] = buttonState[i]; - } - - XINPUT_STATE state; - - // Try and get the first controller. For now we will only support a single one. - DWORD res = XInputStateGet(0, &state); - - // If the controller is plugged in, handle input. - if (res == ERROR_SUCCESS) - { - XINPUT_GAMEPAD* pad = &state.Gamepad; - - buttonState[UP] = (pad->wButtons & XINPUT_GAMEPAD_DPAD_UP); - buttonState[DOWN] = (pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN); - buttonState[LEFT] = (pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT); - buttonState[RIGHT] = (pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT); - buttonState[START] = (pad->wButtons & XINPUT_GAMEPAD_START); - buttonState[BACK] = (pad->wButtons & XINPUT_GAMEPAD_BACK); - buttonState[LEFT_SHOULDER] = (pad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER); - buttonState[RIGHT_SHOULDER] = (pad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER); - buttonState[LEFT_THUMB] = (pad->wButtons & XINPUT_GAMEPAD_LEFT_THUMB); - buttonState[RIGHT_THUMB] = (pad->wButtons & XINPUT_GAMEPAD_RIGHT_THUMB); - buttonState[A] = (pad->wButtons & XINPUT_GAMEPAD_A); - buttonState[B] = (pad->wButtons & XINPUT_GAMEPAD_B); - buttonState[X] = (pad->wButtons & XINPUT_GAMEPAD_X); - buttonState[Y] = (pad->wButtons & XINPUT_GAMEPAD_Y); - - triggerLeft = pad->bLeftTrigger / 255.0f; - triggerRight = pad->bRightTrigger / 255.0f; - leftStickX = NormalizeStickValue(pad->sThumbLX); - leftStickY = NormalizeStickValue(pad->sThumbLY); - rightStickX = NormalizeStickValue(pad->sThumbRX); - rightStickY = NormalizeStickValue(pad->sThumbRY); - - if (!pluggedIn) - { - pluggedIn = true; - // Send callback. - // printf("Plugged in.\n"); - } - } - else - { - if (pluggedIn) - { - pluggedIn = false; - // Send callback. - // printf("Unplugged.\n"); - } - } -#else - for (int i = 0; i < C_BUTTON_COUNT; i++) - { - lastButtonState[i] = buttonState[i] = false; - } -#endif -} \ No newline at end of file diff --git a/Videos/SavingSedit/licence.txt b/Videos/SavingSedit/licence.txt deleted file mode 100644 index be2bc61..0000000 --- a/Videos/SavingSedit/licence.txt +++ /dev/null @@ -1,42 +0,0 @@ -License (OLC-3) -~~~~~~~~~~~~~~~ - -Copyright 2018 - 2019 OneLoneCoder.com - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions or derivations of source code must retain the above -copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions or derivative works in binary form must reproduce -the above copyright notice. This list of conditions and the following -disclaimer must be reproduced in the documentation and/or other -materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived -from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Links -~~~~~ -YouTube: https://www.youtube.com/javidx9 -Discord: https://discord.gg/WhwHUMV -Twitter: https://www.twitter.com/javidx9 -Twitch: https://www.twitch.tv/javidx9 -GitHub: https://www.github.com/onelonecoder -Homepage: https://www.onelonecoder.com -Patreon: https://www.patreon.com/javidx9 diff --git a/Videos/SavingSedit/olcPGEX_Graphics2D.h b/Videos/SavingSedit/olcPGEX_Graphics2D.h deleted file mode 100644 index c77be85..0000000 --- a/Videos/SavingSedit/olcPGEX_Graphics2D.h +++ /dev/null @@ -1,313 +0,0 @@ -/* - olcPGEX_Graphics2D.h - - +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine Extension | - | Advanced 2D Rendering - v0.4 | - +-------------------------------------------------------------+ - - What is this? - ~~~~~~~~~~~~~ - This is an extension to the olcPixelGameEngine, which provides - advanced olc::Sprite manipulation and drawing routines. To use - it, simply include this header file. - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - -/* - Matrices stored as [Column][Row] (i.e. x, y) - - |C0R0 C1R0 C2R0| | x | | x'| - |C0R1 C1R1 C2R1| * | y | = | y'| - |C0R2 C1R2 C2R2| |1.0| | - | -*/ - - - -#ifndef OLC_PGEX_GFX2D -#define OLC_PGEX_GFX2D - -#include -#undef min -#undef max - -namespace olc -{ - // Container class for Advanced 2D Drawing functions - class GFX2D : public olc::PGEX - { - // A representation of an affine transform, used to rotate, scale, offset & shear space - public: - class Transform2D - { - public: - Transform2D(); - - public: - // Set this transformation to unity - void Reset(); - // Append a rotation of fTheta radians to this transform - void Rotate(float fTheta); - // Append a translation (ox, oy) to this transform - void Translate(float ox, float oy); - // Append a scaling operation (sx, sy) to this transform - void Scale(float sx, float sy); - // Append a shear operation (sx, sy) to this transform - void Shear(float sx, float sy); - - void Perspective(float ox, float oy); - // Calculate the Forward Transformation of the coordinate (in_x, in_y) -> (out_x, out_y) - void Forward(float in_x, float in_y, float &out_x, float &out_y); - // Calculate the Inverse Transformation of the coordinate (in_x, in_y) -> (out_x, out_y) - void Backward(float in_x, float in_y, float &out_x, float &out_y); - // Regenerate the Inverse Transformation - void Invert(); - - private: - void Multiply(); - float matrix[4][3][3]; - int nTargetMatrix; - int nSourceMatrix; - bool bDirty; - }; - - public: - // Draws a sprite with the transform applied - static void DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform); - }; -} - - -#ifdef OLC_PGE_GRAPHICS2D -#undef OLC_PGE_GRAPHICS2D - -namespace olc -{ - void GFX2D::DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform) - { - if (sprite == nullptr) - return; - - // Work out bounding rectangle of sprite - float ex, ey; - float sx, sy; - float px, py; - - transform.Forward(0.0f, 0.0f, sx, sy); - px = sx; py = sy; - sx = std::min(sx, px); sy = std::min(sy, py); - ex = std::max(ex, px); ey = std::max(ey, py); - - transform.Forward((float)sprite->width, (float)sprite->height, px, py); - sx = std::min(sx, px); sy = std::min(sy, py); - ex = std::max(ex, px); ey = std::max(ey, py); - - transform.Forward(0.0f, (float)sprite->height, px, py); - sx = std::min(sx, px); sy = std::min(sy, py); - ex = std::max(ex, px); ey = std::max(ey, py); - - transform.Forward((float)sprite->width, 0.0f, px, py); - sx = std::min(sx, px); sy = std::min(sy, py); - ex = std::max(ex, px); ey = std::max(ey, py); - - // Perform inversion of transform if required - transform.Invert(); - - if (ex < sx) - std::swap(ex, sx); - if (ey < sy) - std::swap(ey, sy); - - // Iterate through render space, and sample Sprite from suitable texel location - for (float i = sx; i < ex; i++) - { - for (float j = sy; j < ey; j++) - { - float ox, oy; - transform.Backward(i, j, ox, oy); - pge->Draw((int32_t)i, (int32_t)j, sprite->GetPixel((int32_t)(ox+0.5f), (int32_t)(oy+0.5f))); - } - } - } - - olc::GFX2D::Transform2D::Transform2D() - { - Reset(); - } - - void olc::GFX2D::Transform2D::Reset() - { - nTargetMatrix = 0; - nSourceMatrix = 1; - bDirty = true; - - // Columns Then Rows - - // Matrices 0 & 1 are used as swaps in Transform accumulation - matrix[0][0][0] = 1.0f; matrix[0][1][0] = 0.0f; matrix[0][2][0] = 0.0f; - matrix[0][0][1] = 0.0f; matrix[0][1][1] = 1.0f; matrix[0][2][1] = 0.0f; - matrix[0][0][2] = 0.0f; matrix[0][1][2] = 0.0f; matrix[0][2][2] = 1.0f; - - matrix[1][0][0] = 1.0f; matrix[1][1][0] = 0.0f; matrix[1][2][0] = 0.0f; - matrix[1][0][1] = 0.0f; matrix[1][1][1] = 1.0f; matrix[1][2][1] = 0.0f; - matrix[1][0][2] = 0.0f; matrix[1][1][2] = 0.0f; matrix[1][2][2] = 1.0f; - - // Matrix 2 is a cache matrix to hold the immediate transform operation - // Matrix 3 is a cache matrix to hold the inverted transform - } - - void olc::GFX2D::Transform2D::Multiply() - { - for (int c = 0; c < 3; c++) - { - for (int r = 0; r < 3; r++) - { - matrix[nTargetMatrix][c][r] = matrix[2][0][r] * matrix[nSourceMatrix][c][0] + - matrix[2][1][r] * matrix[nSourceMatrix][c][1] + - matrix[2][2][r] * matrix[nSourceMatrix][c][2]; - } - } - - std::swap(nTargetMatrix, nSourceMatrix); - bDirty = true; // Any transform multiply dirties the inversion - } - - void olc::GFX2D::Transform2D::Rotate(float fTheta) - { - // Construct Rotation Matrix - matrix[2][0][0] = cosf(fTheta); matrix[2][1][0] = sinf(fTheta); matrix[2][2][0] = 0.0f; - matrix[2][0][1] = -sinf(fTheta); matrix[2][1][1] = cosf(fTheta); matrix[2][2][1] = 0.0f; - matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f; - Multiply(); - } - - void olc::GFX2D::Transform2D::Scale(float sx, float sy) - { - // Construct Scale Matrix - matrix[2][0][0] = sx; matrix[2][1][0] = 0.0f; matrix[2][2][0] = 0.0f; - matrix[2][0][1] = 0.0f; matrix[2][1][1] = sy; matrix[2][2][1] = 0.0f; - matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f; - Multiply(); - } - - void olc::GFX2D::Transform2D::Shear(float sx, float sy) - { - // Construct Shear Matrix - matrix[2][0][0] = 1.0f; matrix[2][1][0] = sx; matrix[2][2][0] = 0.0f; - matrix[2][0][1] = sy; matrix[2][1][1] = 1.0f; matrix[2][2][1] = 0.0f; - matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f; - Multiply(); - } - - void olc::GFX2D::Transform2D::Translate(float ox, float oy) - { - // Construct Translate Matrix - matrix[2][0][0] = 1.0f; matrix[2][1][0] = 0.0f; matrix[2][2][0] = ox; - matrix[2][0][1] = 0.0f; matrix[2][1][1] = 1.0f; matrix[2][2][1] = oy; - matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f; - Multiply(); - } - - void olc::GFX2D::Transform2D::Perspective(float ox, float oy) - { - // Construct Translate Matrix - matrix[2][0][0] = 1.0f; matrix[2][1][0] = 0.0f; matrix[2][2][0] = 0.0f; - matrix[2][0][1] = 0.0f; matrix[2][1][1] = 1.0f; matrix[2][2][1] = 0.0f; - matrix[2][0][2] = ox; matrix[2][1][2] = oy; matrix[2][2][2] = 1.0f; - Multiply(); - } - - void olc::GFX2D::Transform2D::Forward(float in_x, float in_y, float &out_x, float &out_y) - { - out_x = in_x * matrix[nSourceMatrix][0][0] + in_y * matrix[nSourceMatrix][1][0] + matrix[nSourceMatrix][2][0]; - out_y = in_x * matrix[nSourceMatrix][0][1] + in_y * matrix[nSourceMatrix][1][1] + matrix[nSourceMatrix][2][1]; - float out_z = in_x * matrix[nSourceMatrix][0][2] + in_y * matrix[nSourceMatrix][1][2] + matrix[nSourceMatrix][2][2]; - if (out_z != 0) - { - out_x /= out_z; - out_y /= out_z; - } - } - - void olc::GFX2D::Transform2D::Backward(float in_x, float in_y, float &out_x, float &out_y) - { - out_x = in_x * matrix[3][0][0] + in_y * matrix[3][1][0] + matrix[3][2][0]; - out_y = in_x * matrix[3][0][1] + in_y * matrix[3][1][1] + matrix[3][2][1]; - float out_z = in_x * matrix[3][0][2] + in_y * matrix[3][1][2] + matrix[3][2][2]; - if (out_z != 0) - { - out_x /= out_z; - out_y /= out_z; - } - } - - void olc::GFX2D::Transform2D::Invert() - { - if (bDirty) // Obviously costly so only do if needed - { - float det = matrix[nSourceMatrix][0][0] * (matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][1][2] * matrix[nSourceMatrix][2][1]) - - matrix[nSourceMatrix][1][0] * (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][2][1] * matrix[nSourceMatrix][0][2]) + - matrix[nSourceMatrix][2][0] * (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][0][2]); - - float idet = 1.0f / det; - matrix[3][0][0] = (matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][1][2] * matrix[nSourceMatrix][2][1]) * idet; - matrix[3][1][0] = (matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][1][0] * matrix[nSourceMatrix][2][2]) * idet; - matrix[3][2][0] = (matrix[nSourceMatrix][1][0] * matrix[nSourceMatrix][2][1] - matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][1][1]) * idet; - matrix[3][0][1] = (matrix[nSourceMatrix][2][1] * matrix[nSourceMatrix][0][2] - matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][2]) * idet; - matrix[3][1][1] = (matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][0][2]) * idet; - matrix[3][2][1] = (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][0] - matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][2][1]) * idet; - matrix[3][0][2] = (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][0][2] * matrix[nSourceMatrix][1][1]) * idet; - matrix[3][1][2] = (matrix[nSourceMatrix][0][2] * matrix[nSourceMatrix][1][0] - matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][1][2]) * idet; - matrix[3][2][2] = (matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][1][1] - matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][0]) * idet; - bDirty = false; - } - } -} - -#endif -#endif \ No newline at end of file diff --git a/Videos/SavingSedit/olcPGEX_Sound.h b/Videos/SavingSedit/olcPGEX_Sound.h deleted file mode 100644 index 55094aa..0000000 --- a/Videos/SavingSedit/olcPGEX_Sound.h +++ /dev/null @@ -1,906 +0,0 @@ -/* - olcPGEX_Sound.h - - +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine Extension | - | Sound - v0.4 | - +-------------------------------------------------------------+ - - What is this? - ~~~~~~~~~~~~~ - This is an extension to the olcPixelGameEngine, which provides - sound generation and wave playing routines. - - Special Thanks: - ~~~~~~~~~~~~~~~ - Slavka - For entire non-windows system back end! - Gorbit99 - Testing, Bug Fixes - Cyberdroid - Testing, Bug Fixes - Dragoneye - Testing - Puol - Testing - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - Patreon: https://www.patreon.com/javidx9 - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - - -#ifndef OLC_PGEX_SOUND_H -#define OLC_PGEX_SOUND_H - -#include -#include -#include - -#include -#undef min -#undef max - -// Choose a default sound backend -#if !defined(USE_ALSA) && !defined(USE_OPENAL) && !defined(USE_WINDOWS) -#ifdef __linux__ -#define USE_ALSA -#endif - -#ifdef __EMSCRIPTEN__ -#define USE_OPENAL -#endif - -#ifdef _WIN32 -#define USE_WINDOWS -#endif - -#endif - -#ifdef USE_ALSA -#define ALSA_PCM_NEW_HW_PARAMS_API -#include -#endif - -#ifdef USE_OPENAL -#include -#include -#include -#endif - -#pragma pack(push, 1) -typedef struct { - uint16_t wFormatTag; - uint16_t nChannels; - uint32_t nSamplesPerSec; - uint32_t nAvgBytesPerSec; - uint16_t nBlockAlign; - uint16_t wBitsPerSample; - uint16_t cbSize; -} OLC_WAVEFORMATEX; -#pragma pack(pop) - -namespace olc -{ - // Container class for Advanced 2D Drawing functions - class SOUND : public olc::PGEX - { - // A representation of an affine transform, used to rotate, scale, offset & shear space - public: - class AudioSample - { - public: - AudioSample(); - AudioSample(std::string sWavFile, olc::ResourcePack *pack = nullptr); - olc::rcode LoadFromFile(std::string sWavFile, olc::ResourcePack *pack = nullptr); - - public: - OLC_WAVEFORMATEX wavHeader; - float *fSample = nullptr; - long nSamples = 0; - int nChannels = 0; - bool bSampleValid = false; - }; - - struct sCurrentlyPlayingSample - { - int nAudioSampleID = 0; - long nSamplePosition = 0; - bool bFinished = false; - bool bLoop = false; - bool bFlagForStop = false; - }; - - static std::list listActiveSamples; - - public: - static bool InitialiseAudio(unsigned int nSampleRate = 44100, unsigned int nChannels = 1, unsigned int nBlocks = 8, unsigned int nBlockSamples = 512); - static bool DestroyAudio(); - static void SetUserSynthFunction(std::function func); - static void SetUserFilterFunction(std::function func); - - public: - static int LoadAudioSample(std::string sWavFile, olc::ResourcePack *pack = nullptr); - static void PlaySample(int id, bool bLoop = false); - static void StopSample(int id); - static void StopAll(); - static float GetMixerOutput(int nChannel, float fGlobalTime, float fTimeStep); - - - private: -#ifdef USE_WINDOWS // Windows specific sound management - static void CALLBACK waveOutProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwParam1, DWORD dwParam2); - static unsigned int m_nSampleRate; - static unsigned int m_nChannels; - static unsigned int m_nBlockCount; - static unsigned int m_nBlockSamples; - static unsigned int m_nBlockCurrent; - static short* m_pBlockMemory; - static WAVEHDR *m_pWaveHeaders; - static HWAVEOUT m_hwDevice; - static std::atomic m_nBlockFree; - static std::condition_variable m_cvBlockNotZero; - static std::mutex m_muxBlockNotZero; -#endif - -#ifdef USE_ALSA - static snd_pcm_t *m_pPCM; - static unsigned int m_nSampleRate; - static unsigned int m_nChannels; - static unsigned int m_nBlockSamples; - static short* m_pBlockMemory; -#endif - -#ifdef USE_OPENAL - static std::queue m_qAvailableBuffers; - static ALuint *m_pBuffers; - static ALuint m_nSource; - static ALCdevice *m_pDevice; - static ALCcontext *m_pContext; - static unsigned int m_nSampleRate; - static unsigned int m_nChannels; - static unsigned int m_nBlockCount; - static unsigned int m_nBlockSamples; - static short* m_pBlockMemory; -#endif - - static void AudioThread(); - static std::thread m_AudioThread; - static std::atomic m_bAudioThreadActive; - static std::atomic m_fGlobalTime; - static std::function funcUserSynth; - static std::function funcUserFilter; - }; -} - - -// Implementation, platform-independent - -#ifdef OLC_PGEX_SOUND -#undef OLC_PGEX_SOUND - -namespace olc -{ - SOUND::AudioSample::AudioSample() - { } - - SOUND::AudioSample::AudioSample(std::string sWavFile, olc::ResourcePack *pack) - { - LoadFromFile(sWavFile, pack); - } - - olc::rcode SOUND::AudioSample::LoadFromFile(std::string sWavFile, olc::ResourcePack *pack) - { - auto ReadWave = [&](std::istream &is) - { - char dump[4]; - is.read(dump, sizeof(char) * 4); // Read "RIFF" - if (strncmp(dump, "RIFF", 4) != 0) return olc::FAIL; - is.read(dump, sizeof(char) * 4); // Not Interested - is.read(dump, sizeof(char) * 4); // Read "WAVE" - if (strncmp(dump, "WAVE", 4) != 0) return olc::FAIL; - - // Read Wave description chunk - is.read(dump, sizeof(char) * 4); // Read "fmt " - unsigned int nHeaderSize = 0; - is.read((char*)&nHeaderSize, sizeof(unsigned int)); // Not Interested - is.read((char*)&wavHeader, nHeaderSize);// sizeof(WAVEFORMATEX)); // Read Wave Format Structure chunk - // Note the -2, because the structure has 2 bytes to indicate its own size - // which are not in the wav file - - // Just check if wave format is compatible with olcPGE - if (wavHeader.wBitsPerSample != 16 || wavHeader.nSamplesPerSec != 44100) - return olc::FAIL; - - // Search for audio data chunk - uint32_t nChunksize = 0; - is.read(dump, sizeof(char) * 4); // Read chunk header - is.read((char*)&nChunksize, sizeof(uint32_t)); // Read chunk size - while (strncmp(dump, "data", 4) != 0) - { - // Not audio data, so just skip it - //std::fseek(f, nChunksize, SEEK_CUR); - is.seekg(nChunksize, std::istream::cur); - is.read(dump, sizeof(char) * 4); - is.read((char*)&nChunksize, sizeof(uint32_t)); - } - - // Finally got to data, so read it all in and convert to float samples - nSamples = nChunksize / (wavHeader.nChannels * (wavHeader.wBitsPerSample >> 3)); - nChannels = wavHeader.nChannels; - - // Create floating point buffer to hold audio sample - fSample = new float[nSamples * nChannels]; - float *pSample = fSample; - - // Read in audio data and normalise - for (long i = 0; i < nSamples; i++) - { - for (int c = 0; c < nChannels; c++) - { - short s = 0; - if (!is.eof()) - { - is.read((char*)&s, sizeof(short)); - - *pSample = (float)s / (float)(SHRT_MAX); - pSample++; - } - } - } - - // All done, flag sound as valid - bSampleValid = true; - return olc::OK; - }; - - if (pack != nullptr) - { - olc::ResourcePack::sEntry entry = pack->GetStreamBuffer(sWavFile); - std::istream is(&entry); - return ReadWave(is); - } - else - { - // Read from file - std::ifstream ifs(sWavFile, std::ifstream::binary); - if (ifs.is_open()) - { - return ReadWave(ifs); - } - else - return olc::FAIL; - } - } - - // This vector holds all loaded sound samples in memory - std::vector vecAudioSamples; - - // This structure represents a sound that is currently playing. It only - // holds the sound ID and where this instance of it is up to for its - // current playback - - void SOUND::SetUserSynthFunction(std::function func) - { - funcUserSynth = func; - } - - void SOUND::SetUserFilterFunction(std::function func) - { - funcUserFilter = func; - } - - // Load a 16-bit WAVE file @ 44100Hz ONLY into memory. A sample ID - // number is returned if successful, otherwise -1 - int SOUND::LoadAudioSample(std::string sWavFile, olc::ResourcePack *pack) - { - - olc::SOUND::AudioSample a(sWavFile, pack); - if (a.bSampleValid) - { - vecAudioSamples.push_back(a); - return (unsigned int)vecAudioSamples.size(); - } - else - return -1; - } - - // Add sample 'id' to the mixers sounds to play list - void SOUND::PlaySample(int id, bool bLoop) - { - olc::SOUND::sCurrentlyPlayingSample a; - a.nAudioSampleID = id; - a.nSamplePosition = 0; - a.bFinished = false; - a.bFlagForStop = false; - a.bLoop = bLoop; - SOUND::listActiveSamples.push_back(a); - } - - void SOUND::StopSample(int id) - { - // Find first occurence of sample id - auto s = std::find_if(listActiveSamples.begin(), listActiveSamples.end(), [&](const olc::SOUND::sCurrentlyPlayingSample &s) { return s.nAudioSampleID == id; }); - if (s != listActiveSamples.end()) - s->bFlagForStop = true; - } - - void SOUND::StopAll() - { - for (auto &s : listActiveSamples) - { - s.bFlagForStop = true; - } - } - - float SOUND::GetMixerOutput(int nChannel, float fGlobalTime, float fTimeStep) - { - // Accumulate sample for this channel - float fMixerSample = 0.0f; - - for (auto &s : listActiveSamples) - { - if (m_bAudioThreadActive) - { - if (s.bFlagForStop) - { - s.bLoop = false; - s.bFinished = true; - } - else - { - // Calculate sample position - s.nSamplePosition += roundf((float)vecAudioSamples[s.nAudioSampleID - 1].wavHeader.nSamplesPerSec * fTimeStep); - - // If sample position is valid add to the mix - if (s.nSamplePosition < vecAudioSamples[s.nAudioSampleID - 1].nSamples) - fMixerSample += vecAudioSamples[s.nAudioSampleID - 1].fSample[(s.nSamplePosition * vecAudioSamples[s.nAudioSampleID - 1].nChannels) + nChannel]; - else - { - if (s.bLoop) - { - s.nSamplePosition = 0; - } - else - s.bFinished = true; // Else sound has completed - } - } - } - else - return 0.0f; - } - - // If sounds have completed then remove them - listActiveSamples.remove_if([](const sCurrentlyPlayingSample &s) {return s.bFinished; }); - - // The users application might be generating sound, so grab that if it exists - if (funcUserSynth != nullptr) - fMixerSample += funcUserSynth(nChannel, fGlobalTime, fTimeStep); - - // Return the sample via an optional user override to filter the sound - if (funcUserFilter != nullptr) - return funcUserFilter(nChannel, fGlobalTime, fMixerSample); - else - return fMixerSample; - } - - std::thread SOUND::m_AudioThread; - std::atomic SOUND::m_bAudioThreadActive{ false }; - std::atomic SOUND::m_fGlobalTime{ 0.0f }; - std::list SOUND::listActiveSamples; - std::function SOUND::funcUserSynth = nullptr; - std::function SOUND::funcUserFilter = nullptr; -} - -// Implementation, Windows-specific -#ifdef USE_WINDOWS -#pragma comment(lib, "winmm.lib") - -namespace olc -{ - bool SOUND::InitialiseAudio(unsigned int nSampleRate, unsigned int nChannels, unsigned int nBlocks, unsigned int nBlockSamples) - { - // Initialise Sound Engine - m_bAudioThreadActive = false; - m_nSampleRate = nSampleRate; - m_nChannels = nChannels; - m_nBlockCount = nBlocks; - m_nBlockSamples = nBlockSamples; - m_nBlockFree = m_nBlockCount; - m_nBlockCurrent = 0; - m_pBlockMemory = nullptr; - m_pWaveHeaders = nullptr; - - // Device is available - WAVEFORMATEX waveFormat; - waveFormat.wFormatTag = WAVE_FORMAT_PCM; - waveFormat.nSamplesPerSec = m_nSampleRate; - waveFormat.wBitsPerSample = sizeof(short) * 8; - waveFormat.nChannels = m_nChannels; - waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels; - waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; - waveFormat.cbSize = 0; - - listActiveSamples.clear(); - - // Open Device if valid - if (waveOutOpen(&m_hwDevice, WAVE_MAPPER, &waveFormat, (DWORD_PTR)SOUND::waveOutProc, (DWORD_PTR)0, CALLBACK_FUNCTION) != S_OK) - return DestroyAudio(); - - // Allocate Wave|Block Memory - m_pBlockMemory = new short[m_nBlockCount * m_nBlockSamples]; - if (m_pBlockMemory == nullptr) - return DestroyAudio(); - ZeroMemory(m_pBlockMemory, sizeof(short) * m_nBlockCount * m_nBlockSamples); - - m_pWaveHeaders = new WAVEHDR[m_nBlockCount]; - if (m_pWaveHeaders == nullptr) - return DestroyAudio(); - ZeroMemory(m_pWaveHeaders, sizeof(WAVEHDR) * m_nBlockCount); - - // Link headers to block memory - for (unsigned int n = 0; n < m_nBlockCount; n++) - { - m_pWaveHeaders[n].dwBufferLength = m_nBlockSamples * sizeof(short); - m_pWaveHeaders[n].lpData = (LPSTR)(m_pBlockMemory + (n * m_nBlockSamples)); - } - - m_bAudioThreadActive = true; - m_AudioThread = std::thread(&SOUND::AudioThread); - - // Start the ball rolling with the sound delivery thread - std::unique_lock lm(m_muxBlockNotZero); - m_cvBlockNotZero.notify_one(); - return true; - } - - // Stop and clean up audio system - bool SOUND::DestroyAudio() - { - m_bAudioThreadActive = false; - if(m_AudioThread.joinable()) - m_AudioThread.join(); - return false; - } - - // Handler for soundcard request for more data - void CALLBACK SOUND::waveOutProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwParam1, DWORD dwParam2) - { - if (uMsg != WOM_DONE) return; - m_nBlockFree++; - std::unique_lock lm(m_muxBlockNotZero); - m_cvBlockNotZero.notify_one(); - } - - // Audio thread. This loop responds to requests from the soundcard to fill 'blocks' - // with audio data. If no requests are available it goes dormant until the sound - // card is ready for more data. The block is fille by the "user" in some manner - // and then issued to the soundcard. - void SOUND::AudioThread() - { - m_fGlobalTime = 0.0f; - static float fTimeStep = 1.0f / (float)m_nSampleRate; - - // Goofy hack to get maximum integer for a type at run-time - short nMaxSample = (short)pow(2, (sizeof(short) * 8) - 1) - 1; - float fMaxSample = (float)nMaxSample; - short nPreviousSample = 0; - - auto tp1 = std::chrono::system_clock::now(); - auto tp2 = std::chrono::system_clock::now(); - - while (m_bAudioThreadActive) - { - // Wait for block to become available - if (m_nBlockFree == 0) - { - std::unique_lock lm(m_muxBlockNotZero); - while (m_nBlockFree == 0) // sometimes, Windows signals incorrectly - m_cvBlockNotZero.wait(lm); - } - - // Block is here, so use it - m_nBlockFree--; - - // Prepare block for processing - if (m_pWaveHeaders[m_nBlockCurrent].dwFlags & WHDR_PREPARED) - waveOutUnprepareHeader(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR)); - - short nNewSample = 0; - int nCurrentBlock = m_nBlockCurrent * m_nBlockSamples; - - auto clip = [](float fSample, float fMax) - { - if (fSample >= 0.0) - return fmin(fSample, fMax); - else - return fmax(fSample, -fMax); - }; - - tp2 = std::chrono::system_clock::now(); - std::chrono::duration elapsedTime = tp2 - tp1; - tp1 = tp2; - - // Our time per frame coefficient - float fElapsedTime = elapsedTime.count(); - - for (unsigned int n = 0; n < m_nBlockSamples; n += m_nChannels) - { - // User Process - for (unsigned int c = 0; c < m_nChannels; c++) - { - nNewSample = (short)(clip(GetMixerOutput(c, m_fGlobalTime + fTimeStep * (float)n, fTimeStep), 1.0) * fMaxSample); - m_pBlockMemory[nCurrentBlock + n + c] = nNewSample; - nPreviousSample = nNewSample; - } - } - - m_fGlobalTime = m_fGlobalTime + fTimeStep * (float)m_nBlockSamples; - - // Send block to sound device - waveOutPrepareHeader(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR)); - waveOutWrite(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR)); - m_nBlockCurrent++; - m_nBlockCurrent %= m_nBlockCount; - } - } - - unsigned int SOUND::m_nSampleRate = 0; - unsigned int SOUND::m_nChannels = 0; - unsigned int SOUND::m_nBlockCount = 0; - unsigned int SOUND::m_nBlockSamples = 0; - unsigned int SOUND::m_nBlockCurrent = 0; - short* SOUND::m_pBlockMemory = nullptr; - WAVEHDR *SOUND::m_pWaveHeaders = nullptr; - HWAVEOUT SOUND::m_hwDevice; - std::atomic SOUND::m_nBlockFree = 0; - std::condition_variable SOUND::m_cvBlockNotZero; - std::mutex SOUND::m_muxBlockNotZero; -} - -#elif defined(USE_ALSA) - -namespace olc -{ - bool SOUND::InitialiseAudio(unsigned int nSampleRate, unsigned int nChannels, unsigned int nBlocks, unsigned int nBlockSamples) - { - // Initialise Sound Engine - m_bAudioThreadActive = false; - m_nSampleRate = nSampleRate; - m_nChannels = nChannels; - m_nBlockSamples = nBlockSamples; - m_pBlockMemory = nullptr; - - // Open PCM stream - int rc = snd_pcm_open(&m_pPCM, "default", SND_PCM_STREAM_PLAYBACK, 0); - if (rc < 0) - return DestroyAudio(); - - - // Prepare the parameter structure and set default parameters - snd_pcm_hw_params_t *params; - snd_pcm_hw_params_alloca(¶ms); - snd_pcm_hw_params_any(m_pPCM, params); - - // Set other parameters - snd_pcm_hw_params_set_access(m_pPCM, params, SND_PCM_ACCESS_RW_INTERLEAVED); - snd_pcm_hw_params_set_format(m_pPCM, params, SND_PCM_FORMAT_S16_LE); - snd_pcm_hw_params_set_rate(m_pPCM, params, m_nSampleRate, 0); - snd_pcm_hw_params_set_channels(m_pPCM, params, m_nChannels); - snd_pcm_hw_params_set_period_size(m_pPCM, params, m_nBlockSamples, 0); - snd_pcm_hw_params_set_periods(m_pPCM, params, nBlocks, 0); - - // Save these parameters - rc = snd_pcm_hw_params(m_pPCM, params); - if (rc < 0) - return DestroyAudio(); - - listActiveSamples.clear(); - - // Allocate Wave|Block Memory - m_pBlockMemory = new short[m_nBlockSamples]; - if (m_pBlockMemory == nullptr) - return DestroyAudio(); - std::fill(m_pBlockMemory, m_pBlockMemory + m_nBlockSamples, 0); - - // Unsure if really needed, helped prevent underrun on my setup - snd_pcm_start(m_pPCM); - for (unsigned int i = 0; i < nBlocks; i++) - rc = snd_pcm_writei(m_pPCM, m_pBlockMemory, 512); - - snd_pcm_start(m_pPCM); - m_bAudioThreadActive = true; - m_AudioThread = std::thread(&SOUND::AudioThread); - - return true; - } - - // Stop and clean up audio system - bool SOUND::DestroyAudio() - { - m_bAudioThreadActive = false; - if(m_AudioThread.joinable()) - m_AudioThread.join(); - snd_pcm_drain(m_pPCM); - snd_pcm_close(m_pPCM); - return false; - } - - - // Audio thread. This loop responds to requests from the soundcard to fill 'blocks' - // with audio data. If no requests are available it goes dormant until the sound - // card is ready for more data. The block is fille by the "user" in some manner - // and then issued to the soundcard. - void SOUND::AudioThread() - { - m_fGlobalTime = 0.0f; - static float fTimeStep = 1.0f / (float)m_nSampleRate; - - // Goofy hack to get maximum integer for a type at run-time - short nMaxSample = (short)pow(2, (sizeof(short) * 8) - 1) - 1; - float fMaxSample = (float)nMaxSample; - short nPreviousSample = 0; - - while (m_bAudioThreadActive) - { - short nNewSample = 0; - - auto clip = [](float fSample, float fMax) - { - if (fSample >= 0.0) - return fmin(fSample, fMax); - else - return fmax(fSample, -fMax); - }; - - for (unsigned int n = 0; n < m_nBlockSamples; n += m_nChannels) - { - // User Process - for (unsigned int c = 0; c < m_nChannels; c++) - { - nNewSample = (short)(GetMixerOutput(c, m_fGlobalTime + fTimeStep * (float)n, fTimeStep), 1.0) * fMaxSample; - m_pBlockMemory[n + c] = nNewSample; - nPreviousSample = nNewSample; - } - } - - m_fGlobalTime = m_fGlobalTime + fTimeStep * (float)m_nBlockSamples; - - // Send block to sound device - snd_pcm_uframes_t nLeft = m_nBlockSamples; - short *pBlockPos = m_pBlockMemory; - while (nLeft > 0) - { - int rc = snd_pcm_writei(m_pPCM, pBlockPos, nLeft); - if (rc > 0) - { - pBlockPos += rc * m_nChannels; - nLeft -= rc; - } - if (rc == -EAGAIN) continue; - if (rc == -EPIPE) // an underrun occured, prepare the device for more data - snd_pcm_prepare(m_pPCM); - } - } - } - - snd_pcm_t* SOUND::m_pPCM = nullptr; - unsigned int SOUND::m_nSampleRate = 0; - unsigned int SOUND::m_nChannels = 0; - unsigned int SOUND::m_nBlockSamples = 0; - short* SOUND::m_pBlockMemory = nullptr; -} - -#elif defined(USE_OPENAL) - -namespace olc -{ - bool SOUND::InitialiseAudio(unsigned int nSampleRate, unsigned int nChannels, unsigned int nBlocks, unsigned int nBlockSamples) - { - // Initialise Sound Engine - m_bAudioThreadActive = false; - m_nSampleRate = nSampleRate; - m_nChannels = nChannels; - m_nBlockCount = nBlocks; - m_nBlockSamples = nBlockSamples; - m_pBlockMemory = nullptr; - - // Open the device and create the context - m_pDevice = alcOpenDevice(NULL); - if (m_pDevice) - { - m_pContext = alcCreateContext(m_pDevice, NULL); - alcMakeContextCurrent(m_pContext); - } - else - return DestroyAudio(); - - // Allocate memory for sound data - alGetError(); - m_pBuffers = new ALuint[m_nBlockCount]; - alGenBuffers(m_nBlockCount, m_pBuffers); - alGenSources(1, &m_nSource); - - for (unsigned int i = 0; i < m_nBlockCount; i++) - m_qAvailableBuffers.push(m_pBuffers[i]); - - listActiveSamples.clear(); - - // Allocate Wave|Block Memory - m_pBlockMemory = new short[m_nBlockSamples]; - if (m_pBlockMemory == nullptr) - return DestroyAudio(); - std::fill(m_pBlockMemory, m_pBlockMemory + m_nBlockSamples, 0); - - m_bAudioThreadActive = true; - m_AudioThread = std::thread(&SOUND::AudioThread); - return true; - } - - // Stop and clean up audio system - bool SOUND::DestroyAudio() - { - m_bAudioThreadActive = false; - if(m_AudioThread.joinable()) - m_AudioThread.join(); - - alDeleteBuffers(m_nBlockCount, m_pBuffers); - delete[] m_pBuffers; - alDeleteSources(1, &m_nSource); - - alcMakeContextCurrent(NULL); - alcDestroyContext(m_pContext); - alcCloseDevice(m_pDevice); - return false; - } - - - // Audio thread. This loop responds to requests from the soundcard to fill 'blocks' - // with audio data. If no requests are available it goes dormant until the sound - // card is ready for more data. The block is fille by the "user" in some manner - // and then issued to the soundcard. - void SOUND::AudioThread() - { - m_fGlobalTime = 0.0f; - static float fTimeStep = 1.0f / (float)m_nSampleRate; - - // Goofy hack to get maximum integer for a type at run-time - short nMaxSample = (short)pow(2, (sizeof(short) * 8) - 1) - 1; - float fMaxSample = (float)nMaxSample; - short nPreviousSample = 0; - - std::vector vProcessed; - - while (m_bAudioThreadActive) - { - ALint nState, nProcessed; - alGetSourcei(m_nSource, AL_SOURCE_STATE, &nState); - alGetSourcei(m_nSource, AL_BUFFERS_PROCESSED, &nProcessed); - - // Add processed buffers to our queue - vProcessed.resize(nProcessed); - alSourceUnqueueBuffers(m_nSource, nProcessed, vProcessed.data()); - for (ALint nBuf : vProcessed) m_qAvailableBuffers.push(nBuf); - - // Wait until there is a free buffer (ewww) - if (m_qAvailableBuffers.empty()) continue; - - short nNewSample = 0; - - auto clip = [](float fSample, float fMax) - { - if (fSample >= 0.0) - return fmin(fSample, fMax); - else - return fmax(fSample, -fMax); - }; - - for (unsigned int n = 0; n < m_nBlockSamples; n += m_nChannels) - { - // User Process - for (unsigned int c = 0; c < m_nChannels; c++) - { - nNewSample = (short)(clip(GetMixerOutput(c, m_fGlobalTime, fTimeStep), 1.0) * fMaxSample); - m_pBlockMemory[n + c] = nNewSample; - nPreviousSample = nNewSample; - } - - m_fGlobalTime = m_fGlobalTime + fTimeStep; - } - - // Fill OpenAL data buffer - alBufferData( - m_qAvailableBuffers.front(), - m_nChannels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, - m_pBlockMemory, - 2 * m_nBlockSamples, - m_nSampleRate - ); - // Add it to the OpenAL queue - alSourceQueueBuffers(m_nSource, 1, &m_qAvailableBuffers.front()); - // Remove it from ours - m_qAvailableBuffers.pop(); - - // If it's not playing for some reason, change that - if (nState != AL_PLAYING) - alSourcePlay(m_nSource); - } - } - - std::queue SOUND::m_qAvailableBuffers; - ALuint *SOUND::m_pBuffers = nullptr; - ALuint SOUND::m_nSource = 0; - ALCdevice *SOUND::m_pDevice = nullptr; - ALCcontext *SOUND::m_pContext = nullptr; - unsigned int SOUND::m_nSampleRate = 0; - unsigned int SOUND::m_nChannels = 0; - unsigned int SOUND::m_nBlockCount = 0; - unsigned int SOUND::m_nBlockSamples = 0; - short* SOUND::m_pBlockMemory = nullptr; -} - -#else // Some other platform - -namespace olc -{ - bool SOUND::InitialiseAudio(unsigned int nSampleRate, unsigned int nChannels, unsigned int nBlocks, unsigned int nBlockSamples) - { - return true; - } - - // Stop and clean up audio system - bool SOUND::DestroyAudio() - { - return false; - } - - - // Audio thread. This loop responds to requests from the soundcard to fill 'blocks' - // with audio data. If no requests are available it goes dormant until the sound - // card is ready for more data. The block is fille by the "user" in some manner - // and then issued to the soundcard. - void SOUND::AudioThread() - { } -} - -#endif -#endif -#endif // OLC_PGEX_SOUND \ No newline at end of file diff --git a/Videos/SavingSedit/olcPGEX_TileMaps_new.h b/Videos/SavingSedit/olcPGEX_TileMaps_new.h deleted file mode 100644 index b89a7c2..0000000 --- a/Videos/SavingSedit/olcPGEX_TileMaps_new.h +++ /dev/null @@ -1,381 +0,0 @@ -#pragma once -#include "olcPixelGameEngine.h" - -#include -#undef min -#undef max - -namespace olc -{ - - class TILE : public olc::PGEX - { - - public: - - - struct Edge - { - float sx, sy; - float ex, ey; - }; - - public: - class Atlas - { - public: - Atlas(); - void Create(olc::Sprite *tileSheet); - olc::rcode LoadFromFile(std::string filename); - olc::rcode SaveToFile(std::string filename); - - public: - olc::Sprite *sprTileSheet; - std::vector> location; - }; - - public: - - template - class Layer - { - public: - Layer(); - void Create(int32_t w, int32_t h, int32_t tw, int32_t th); - olc::rcode LoadFromFile(std::string filename); - olc::rcode SaveToFile(std::string filename); - T* GetTile(int32_t x, int32_t y); - - public: - int32_t nLayerWidth; - int32_t nLayerHeight; - int32_t nTileWidth; - int32_t nTileHeight; - - private: - T *pTiles; - - }; - - class BasicTile - { - public: - BasicTile(); - - public: - int32_t id; - bool exist; - - int edge_id[4]; - bool edge_exist[4]; - }; - - public: - template - static void DrawLayer(olc::TILE::Layer &layer, olc::TILE::Atlas &atlas, float cam_x, float cam_y, int tiles_x, int tiles_y, int nScale = 1); - - template - static olc::Pixel GetLayerPixel(olc::TILE::Layer &layer, olc::TILE::Atlas &atlas, float x, float y); - - template - static std::vector ExtractEdgesFromLayer(olc::TILE::Layer &layer, int sx, int sy, int width, int height); - - }; -} - - - - -namespace olc -{ - TILE::BasicTile::BasicTile() - { - exist = false; - id = 0; - - for (int i = 0; i < 4; i++) - { - edge_exist[i] = false; - edge_id[i] = 0; - } - } - - template - TILE::Layer::Layer() - { - - } - - - - template - void TILE::Layer::Create(int32_t w, int32_t h, int32_t tw, int32_t th) - { - nLayerWidth = w; - nLayerHeight = h; - nTileWidth = tw; - nTileHeight = th; - - pTiles = new T[nLayerWidth * nLayerHeight]; - for (int i = 0; i < nLayerWidth*nLayerHeight; i++) - { - pTiles[i].id = 0; - } - } - - template - olc::rcode TILE::Layer::LoadFromFile(std::string filename) - { - return olc::FAIL; - } - - template - olc::rcode TILE::Layer::SaveToFile(std::string filename) - { - return olc::FAIL; - } - - template - T* TILE::Layer::GetTile(int32_t x, int32_t y) - { - if (x < 0 || x >= nLayerWidth || y < 0 || y >= nLayerHeight) - return nullptr; - else - return &pTiles[y*nLayerWidth + x]; - } - - template - void TILE::DrawLayer(olc::TILE::Layer &layer, olc::TILE::Atlas &atlas, float cam_x, float cam_y, int32_t tiles_x, int32_t tiles_y, int nScale) - { - float fOffsetX = cam_x - (int)cam_x; - float fOffsetY = cam_y - (int)cam_y; - - for (int32_t x = 0; x < tiles_x; x++) - { - for (int32_t y = 0; y < tiles_y; y++) - { - olc::TILE::BasicTile *t = layer.GetTile(x + (int)cam_x, y + (int)cam_y); - if (t != nullptr && t->exist) - { - float fx = (int)(((float)x - fOffsetX) * (float)(layer.nTileWidth)); - float fy = (int)(((float)y - fOffsetY) * (float)(layer.nTileHeight)); - - pge->DrawPartialSprite( - fx + 0.5f - (fx < 0.0f), - fy + 0.5f - (fy < 0.0f), - atlas.sprTileSheet, - std::get<0>(atlas.location[t->id]), - std::get<1>(atlas.location[t->id]), - std::get<2>(atlas.location[t->id]), - std::get<3>(atlas.location[t->id]), - nScale); - } - } - } - } - - template - olc::Pixel TILE::GetLayerPixel(olc::TILE::Layer &layer, olc::TILE::Atlas &atlas, float x, float y) - { - olc::TILE::BasicTile *t = layer.GetTile((int32_t)x, (int32_t)y); - if (t != nullptr) - { - float fOffsetX = x - (int)x; - float fOffsetY = y - (int)y; - return atlas.sprTileSheet->GetPixel(std::get<0>(atlas.location[t->id]) + fOffsetX * std::get<2>(atlas.location[t->id]), - std::get<1>(atlas.location[t->id]) + fOffsetX * std::get<3>(atlas.location[t->id])); - } - else - return olc::BLANK; - } - - template - std::vector TILE::ExtractEdgesFromLayer(olc::TILE::Layer &layer, int sx, int sy, int width, int height) - { - enum - { - NORTH = 0, - EAST = 1, - SOUTH = 2, - WEST = 3 - }; - - std::vector vecEdges; - - for (int x = -1; x < width + 1; x++) - for (int y = -1; y < height + 1; y++) - for (int j = 0; j < 4; j++) - { - if ((x + sx) >= 0 && (y + sy) >= 0 && (x + sx) < (layer.nLayerWidth - 1) && (y + sy) < (layer.nLayerHeight - 1)) - { - layer.GetTile(x + sx, y + sy)->edge_exist[j] = false; - layer.GetTile(x + sx, y + sy)->edge_id[j] = 0; - } - } - - // Add boundary edges - vecEdges.push_back({ (float)(sx)* layer.nTileWidth, (float)(sy)*layer.nTileHeight, (float)(sx + width)*layer.nTileWidth, (float)(sy)*layer.nTileHeight }); - vecEdges.push_back({ (float)(sx + width)* layer.nTileWidth, (float)(sy)*layer.nTileHeight, (float)(sx + width)*layer.nTileWidth, (float)(sy + height)*layer.nTileHeight }); - vecEdges.push_back({ (float)(sx + width)* layer.nTileWidth, (float)(sy + height)*layer.nTileHeight, (float)(sx)*layer.nTileWidth, (float)(sy + height)*layer.nTileHeight }); - vecEdges.push_back({ (float)(sx)* layer.nTileWidth, (float)(sy + height)*layer.nTileHeight, (float)(sx)*layer.nTileWidth, (float)(sy)*layer.nTileHeight }); - - - // Iterate through region from top left to bottom right - for (int x = 0; x < width; x++) - for (int y = 0; y < height; y++) - { - T* i = layer.GetTile(x + sx, y + sy); //This - T* n = layer.GetTile(x + sx, y + sy - 1); - T* s = layer.GetTile(x + sx, y + sy + 1); - T* w = layer.GetTile(x + sx - 1, y + sy); - T* e = layer.GetTile(x + sx + 1, y + sy); - - // If this cell exists, check if it needs edges - if (i->exist) - { - // If this cell has no western neighbour, it needs a western edge - if (w && !w->exist) - { - // It can either extend it from its northern neighbour if they have - // one, or It can start a new one. - if (n && n->edge_exist[WEST]) - { - // Northern neighbour has a western edge, so grow it downwards - vecEdges[n->edge_id[WEST]].ey += layer.nTileHeight; - i->edge_id[WEST] = n->edge_id[WEST]; - i->edge_exist[WEST] = true; - } - else - { - // Northern neighbour does not have one, so create one - olc::TILE::Edge edge; - edge.sx = (sx + x) * layer.nTileWidth; edge.sy = (sy + y) * layer.nTileHeight; - edge.ex = edge.sx; edge.ey = edge.sy + layer.nTileHeight; - - // Add edge to Polygon Pool - int edge_id = vecEdges.size(); - vecEdges.push_back(edge); - - // Update tile information with edge information - i->edge_id[WEST] = edge_id; - i->edge_exist[WEST] = true; - } - } - - - // If this cell dont have an eastern neignbour, It needs a eastern edge - if (e && !e->exist) - { - // It can either extend it from its northern neighbour if they have - // one, or It can start a new one. - if (n && n->edge_exist[EAST]) - { - // Northern neighbour has one, so grow it downwards - vecEdges[n->edge_id[EAST]].ey += layer.nTileHeight; - i->edge_id[EAST] = n->edge_id[EAST]; - i->edge_exist[EAST] = true; - } - else - { - // Northern neighbour does not have one, so create one - olc::TILE::Edge edge; - edge.sx = (sx + x + 1) * layer.nTileWidth; edge.sy = (sy + y) * layer.nTileHeight; - edge.ex = edge.sx; edge.ey = edge.sy + layer.nTileHeight; - - // Add edge to Polygon Pool - int edge_id = vecEdges.size(); - vecEdges.push_back(edge); - - // Update tile information with edge information - i->edge_id[EAST] = edge_id; - i->edge_exist[EAST] = true; - } - } - - // If this cell doesnt have a northern neignbour, It needs a northern edge - if (n && !n->exist) - { - // It can either extend it from its western neighbour if they have - // one, or It can start a new one. - if (w && w->edge_exist[NORTH]) - { - // Western neighbour has one, so grow it eastwards - vecEdges[w->edge_id[NORTH]].ex += layer.nTileWidth; - i->edge_id[NORTH] = w->edge_id[NORTH]; - i->edge_exist[NORTH] = true; - } - else - { - // Western neighbour does not have one, so create one - olc::TILE::Edge edge; - edge.sx = (sx + x) * layer.nTileWidth; edge.sy = (sy + y) * layer.nTileHeight; - edge.ex = edge.sx + layer.nTileWidth; edge.ey = edge.sy; - - // Add edge to Polygon Pool - int edge_id = vecEdges.size(); - vecEdges.push_back(edge); - - // Update tile information with edge information - i->edge_id[NORTH] = edge_id; - i->edge_exist[NORTH] = true; - } - } - - // If this cell doesnt have a southern neignbour, It needs a southern edge - if (s && !s->exist) - { - // It can either extend it from its western neighbour if they have - // one, or It can start a new one. - if (w && w->edge_exist[SOUTH]) - { - // Western neighbour has one, so grow it eastwards - vecEdges[w->edge_id[SOUTH]].ex += layer.nTileWidth; - i->edge_id[SOUTH] = w->edge_id[SOUTH]; - i->edge_exist[SOUTH] = true; - } - else - { - // Western neighbour does not have one, so I need to create one - olc::TILE::Edge edge; - edge.sx = (sx + x) * layer.nTileWidth; edge.sy = (sy + y + 1) * layer.nTileHeight; - edge.ex = edge.sx + layer.nTileWidth; edge.ey = edge.sy; - - // Add edge to Polygon Pool - int edge_id = vecEdges.size(); - vecEdges.push_back(edge); - - // Update tile information with edge information - i->edge_id[SOUTH] = edge_id; - i->edge_exist[SOUTH] = true; - } - } - } - } - - return vecEdges; - } - - - - TILE::Atlas::Atlas() - { - } - - void TILE::Atlas::Create(olc::Sprite *tileSheet) - { - sprTileSheet = tileSheet; - location.clear(); - - } - - olc::rcode TILE::Atlas::LoadFromFile(std::string filename) - { - return olc::FAIL; - } - - olc::rcode TILE::Atlas::SaveToFile(std::string filename) - { - return olc::FAIL; - } - -} diff --git a/Videos/SavingSedit/olcPixelGameEngine.h b/Videos/SavingSedit/olcPixelGameEngine.h deleted file mode 100644 index a6f36ed..0000000 --- a/Videos/SavingSedit/olcPixelGameEngine.h +++ /dev/null @@ -1,2317 +0,0 @@ -/* - olcPixelGameEngine.h - - +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine v1.18 | - | "Like the command prompt console one, but not..." - javidx9 | - +-------------------------------------------------------------+ - - What is this? - ~~~~~~~~~~~~~ - The olcConsoleGameEngine has been a surprising and wonderful success for me, - and I'm delighted how people have reacted so positively towards it, so thanks - for that. - - However, there are limitations that I simply cannot avoid. Firstly, I need to - maintain several different versions of it to accommodate users on Windows7, - 8, 10, Linux, Mac, Visual Studio & Code::Blocks. Secondly, this year I've been - pushing the console to the limits of its graphical capabilities and the effect - is becoming underwhelming. The engine itself is not slow at all, but the process - that Windows uses to draw the command prompt to the screen is, and worse still, - it's dynamic based upon the variation of character colours and glyphs. Sadly - I have no control over this, and recent videos that are extremely graphical - (for a command prompt :P ) have been dipping to unacceptable framerates. As - the channel has been popular with aspiring game developers, I'm concerned that - the visual appeal of the command prompt is perhaps limited to us oldies, and I - dont want to alienate younger learners. Finally, I'd like to demonstrate many - more algorithms and image processing that exist in the graphical domain, for - which the console is insufficient. - - For this reason, I have created olcPixelGameEngine! The look and feel to the - programmer is almost identical, so all of my existing code from the videos is - easily portable, and the programmer uses this file in exactly the same way. But - I've decided that rather than just build a command prompt emulator, that I - would at least harness some modern(ish) portable technologies. - - As a result, the olcPixelGameEngine supports 32-bit colour, is written in a - cross-platform style, uses modern(ish) C++ conventions and most importantly, - renders much much faster. I will use this version when my applications are - predominantly graphics based, but use the console version when they are - predominantly text based - Don't worry, loads more command prompt silliness to - come yet, but evolution is important!! - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - 1. Redistributions or derivations of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce the above - copyright notice. This list of conditions and the following disclaimer must be - reproduced in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may - be used to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - https://www.youtube.com/javidx9extra - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - Patreon: https://www.patreon.com/javidx9 - - Relevant Videos - ~~~~~~~~~~~~~~~ - https://youtu.be/kRH6oJLFYxY Introducing olcPixelGameEngine - - Compiling in Linux - ~~~~~~~~~~~~~~~~~~ - You will need a modern C++ compiler, so update yours! - To compile use the command: - - g++ -o YourProgName YourSource.cpp -lX11 -lGL -lpthread -lpng - - On some Linux configurations, the frame rate is locked to the refresh - rate of the monitor. This engine tries to unlock it but may not be - able to, in which case try launching your program like this: - - vblank_mode=0 ./YourProgName - - - Compiling in Code::Blocks on Windows - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Well I wont judge you, but make sure your Code::Blocks installation - is really up to date - you may even consider updating your C++ toolchain - to use MinGW32-W64, so google this. You will also need to enable C++14 - in your build options, and add to your linker the following libraries: - user32 gdi32 opengl32 gdiplus - - Ports - ~~~~~ - olc::PixelGameEngine has been ported and tested with varying degrees of - success to: WinXP, Win7, Win8, Win10, Various Linux, Rapberry Pi, - Chromebook, Playstation Portable (PSP) and Nintendo Switch. If you are - interested in the details of these ports, come and visit the Discord! - - Thanks - ~~~~~~ - I'd like to extend thanks to Eremiell, slavka, gurkanctn, Phantim, - JackOJC, KrossX, Huhlig, Dragoneye, Appa, JustinRichardsMusic, SliceNDice - Ralakus, Gorbit99, raoul, joshinils, benedani & MagetzUb for advice, ideas and - testing, and I'd like to extend my appreciation to the 40K YouTube followers, - 22 Patreons and 2.6K Discord server members who give me the motivation to keep - going with all this :D - - Special thanks to those who bring gifts! - GnarGnarHead.......Domina - Gorbit99...........Bastion, Ori & The Blind Forest - Marti Morta........Gris - - Special thanks to my Patreons too - I wont name you on here, but I've - certainly enjoyed my tea and flapjacks :D - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018, 2019 -*/ - -////////////////////////////////////////////////////////////////////////////////////////// - -/* Example Usage (main.cpp) - #define OLC_PGE_APPLICATION - #include "olcPixelGameEngine.h" - // Override base class with your custom functionality - class Example : public olc::PixelGameEngine - { - public: - Example() - { - sAppName = "Example"; - } - public: - bool OnUserCreate() override - { - // Called once at the start, so create things here - return true; - } - bool OnUserUpdate(float fElapsedTime) override - { - // called once per frame, draws random coloured pixels - for (int x = 0; x < ScreenWidth(); x++) - for (int y = 0; y < ScreenHeight(); y++) - Draw(x, y, olc::Pixel(rand() % 255, rand() % 255, rand()% 255)); - return true; - } - }; - int main() - { - Example demo; - if (demo.Construct(256, 240, 4, 4)) - demo.Start(); - return 0; - } -*/ - -#ifndef OLC_PGE_DEF -#define OLC_PGE_DEF - -#ifdef _WIN32 - // Link to libraries -#ifndef __MINGW32__ - #pragma comment(lib, "user32.lib") // Visual Studio Only - #pragma comment(lib, "gdi32.lib") // For other Windows Compilers please add - #pragma comment(lib, "opengl32.lib") // these libs to your linker input - #pragma comment(lib, "gdiplus.lib") -#else - // In Code::Blocks, Select C++14 in your build options, and add the - // following libs to your linker: user32 gdi32 opengl32 gdiplus - #if !defined _WIN32_WINNT - #ifdef HAVE_MSMF - #define _WIN32_WINNT 0x0600 // Windows Vista - #else - #define _WIN32_WINNT 0x0500 // Windows 2000 - #endif - #endif -#endif - // Include WinAPI - #include - #include - - // OpenGL Extension - #include - typedef BOOL(WINAPI wglSwapInterval_t) (int interval); - static wglSwapInterval_t *wglSwapInterval; -#else - #include - #include - #include - #include - #include - typedef int(glSwapInterval_t) (Display *dpy, GLXDrawable drawable, int interval); - static glSwapInterval_t *glSwapIntervalEXT; -#endif - - -// Standard includes -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef min -#undef max - -namespace olc // All OneLoneCoder stuff will now exist in the "olc" namespace -{ - struct Pixel - { - union - { - uint32_t n = 0xFF000000; - struct - { - uint8_t r; uint8_t g; uint8_t b; uint8_t a; - }; - }; - - Pixel(); - Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255); - Pixel(uint32_t p); - enum Mode { NORMAL, MASK, ALPHA, CUSTOM }; - }; - - // Some constants for symbolic naming of Pixels - static const Pixel - WHITE(255, 255, 255), - GREY(192, 192, 192), DARK_GREY(128, 128, 128), VERY_DARK_GREY(64, 64, 64), - RED(255, 0, 0), DARK_RED(128, 0, 0), VERY_DARK_RED(64, 0, 0), - YELLOW(255, 255, 0), DARK_YELLOW(128, 128, 0), VERY_DARK_YELLOW(64, 64, 0), - GREEN(0, 255, 0), DARK_GREEN(0, 128, 0), VERY_DARK_GREEN(0, 64, 0), - CYAN(0, 255, 255), DARK_CYAN(0, 128, 128), VERY_DARK_CYAN(0, 64, 64), - BLUE(0, 0, 255), DARK_BLUE(0, 0, 128), VERY_DARK_BLUE(0, 0, 64), - MAGENTA(255, 0, 255), DARK_MAGENTA(128, 0, 128), VERY_DARK_MAGENTA(64, 0, 64), - BLACK(0, 0, 0), - BLANK(0, 0, 0, 0); - - enum rcode - { - FAIL = 0, - OK = 1, - NO_FILE = -1, - }; - - //================================================================================== - - template - struct v2d_generic - { - T x = 0; - T y = 0; - - inline v2d_generic() : x(0), y(0) { } - inline v2d_generic(T _x, T _y) : x(_x), y(_y) { } - inline v2d_generic(const v2d_generic& v) : x(v.x), y(v.y){ } - inline T mag() { return sqrt(x * x + y * y); } - inline v2d_generic norm() { T r = 1 / mag(); return v2d_generic(x*r, y*r); } - inline v2d_generic perp() { return v2d_generic(-y, x); } - inline T dot(const v2d_generic& rhs) { return this->x * rhs.x + this->y * rhs.y; } - inline T cross(const v2d_generic& rhs) { return this->x * rhs.y - this->y * rhs.x; } - inline v2d_generic operator + (const v2d_generic& rhs) const { return v2d_generic(this->x + rhs.x, this->y + rhs.y);} - inline v2d_generic operator - (const v2d_generic& rhs) const { return v2d_generic(this->x - rhs.x, this->y - rhs.y);} - inline v2d_generic operator * (const T& rhs) const { return v2d_generic(this->x * rhs, this->y * rhs); } - inline v2d_generic operator / (const T& rhs) const { return v2d_generic(this->x / rhs, this->y / rhs); } - inline v2d_generic& operator += (const v2d_generic& rhs) { this->x += rhs.x; this->y += rhs.y; return *this; } - inline v2d_generic& operator -= (const v2d_generic& rhs) { this->x -= rhs.x; this->y -= rhs.y; return *this; } - inline v2d_generic& operator *= (const T& rhs) { this->x *= rhs; this->y *= rhs; return *this; } - inline v2d_generic& operator /= (const T& rhs) { this->x /= rhs; this->y /= rhs; return *this; } - inline T& operator [] (std::size_t i) { return *((T*)this + i); /* <-- D'oh :( */ } - }; - - template inline v2d_generic operator * (const float& lhs, const v2d_generic& rhs) { return v2d_generic(lhs * rhs.x, lhs * rhs.y); } - template inline v2d_generic operator * (const double& lhs, const v2d_generic& rhs){ return v2d_generic(lhs * rhs.x, lhs * rhs.y); } - template inline v2d_generic operator * (const int& lhs, const v2d_generic& rhs) { return v2d_generic(lhs * rhs.x, lhs * rhs.y); } - template inline v2d_generic operator / (const float& lhs, const v2d_generic& rhs) { return v2d_generic(lhs / rhs.x, lhs / rhs.y); } - template inline v2d_generic operator / (const double& lhs, const v2d_generic& rhs){ return v2d_generic(lhs / rhs.x, lhs / rhs.y); } - template inline v2d_generic operator / (const int& lhs, const v2d_generic& rhs) { return v2d_generic(lhs / rhs.x, lhs / rhs.y); } - - typedef v2d_generic vi2d; - typedef v2d_generic vf2d; - typedef v2d_generic vd2d; - - //============================================================= - - struct HWButton - { - bool bPressed = false; // Set once during the frame the event occurs - bool bReleased = false; // Set once during the frame the event occurs - bool bHeld = false; // Set true for all frames between pressed and released events - }; - - //============================================================= - - - class ResourcePack - { - public: - ResourcePack(); - ~ResourcePack(); - struct sEntry : public std::streambuf { - uint32_t nID, nFileOffset, nFileSize; uint8_t* data; void _config() { this->setg((char*)data, (char*)data, (char*)(data + nFileSize)); } - }; - - public: - olc::rcode AddToPack(std::string sFile); - - public: - olc::rcode SavePack(std::string sFile); - olc::rcode LoadPack(std::string sFile); - olc::rcode ClearPack(); - - public: - olc::ResourcePack::sEntry GetStreamBuffer(std::string sFile); - - private: - - std::map mapFiles; - }; - - //============================================================= - - // A bitmap-like structure that stores a 2D array of Pixels - class Sprite - { - public: - Sprite(); - Sprite(std::string sImageFile); - Sprite(std::string sImageFile, olc::ResourcePack *pack); - Sprite(int32_t w, int32_t h); - ~Sprite(); - - public: - olc::rcode LoadFromFile(std::string sImageFile, olc::ResourcePack *pack = nullptr); - olc::rcode LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack = nullptr); - olc::rcode SaveToPGESprFile(std::string sImageFile); - - public: - int32_t width = 0; - int32_t height = 0; - enum Mode { NORMAL, PERIODIC }; - - public: - void SetSampleMode(olc::Sprite::Mode mode = olc::Sprite::Mode::NORMAL); - Pixel GetPixel(int32_t x, int32_t y); - bool SetPixel(int32_t x, int32_t y, Pixel p); - - Pixel Sample(float x, float y); - Pixel SampleBL(float u, float v); - Pixel* GetData(); - - private: - Pixel *pColData = nullptr; - Mode modeSample = Mode::NORMAL; - -#ifdef OLC_DBG_OVERDRAW - public: - static int nOverdrawCount; -#endif - - }; - - //============================================================= - - enum Key - { - NONE, - A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, - K0, K1, K2, K3, K4, K5, K6, K7, K8, K9, - F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, - UP, DOWN, LEFT, RIGHT, - SPACE, TAB, SHIFT, CTRL, INS, DEL, HOME, END, PGUP, PGDN, - BACK, ESCAPE, RETURN, ENTER, PAUSE, SCROLL, - NP0, NP1, NP2, NP3, NP4, NP5, NP6, NP7, NP8, NP9, - NP_MUL, NP_DIV, NP_ADD, NP_SUB, NP_DECIMAL, - }; - - - //============================================================= - - class PixelGameEngine - { - public: - PixelGameEngine(); - - public: - olc::rcode Construct(uint32_t screen_w, uint32_t screen_h, uint32_t pixel_w, uint32_t pixel_h, bool full_screen = false); - olc::rcode Start(); - - public: // Override Interfaces - // Called once on application startup, use to load your resources - virtual bool OnUserCreate(); - // Called every frame, and provides you with a time per frame value - virtual bool OnUserUpdate(float fElapsedTime); - // Called once on application termination, so you can be a clean coder - virtual bool OnUserDestroy(); - - public: // Hardware Interfaces - // Returns true if window is currently in focus - bool IsFocused(); - // Get the state of a specific keyboard button - HWButton GetKey(Key k); - // Get the state of a specific mouse button - HWButton GetMouse(uint32_t b); - // Get Mouse X coordinate in "pixel" space - int32_t GetMouseX(); - // Get Mouse Y coordinate in "pixel" space - int32_t GetMouseY(); - // Get Mouse Wheel Delta - int32_t GetMouseWheel(); - - public: // Utility - // Returns the width of the screen in "pixels" - int32_t ScreenWidth(); - // Returns the height of the screen in "pixels" - int32_t ScreenHeight(); - // Returns the width of the currently selected drawing target in "pixels" - int32_t GetDrawTargetWidth(); - // Returns the height of the currently selected drawing target in "pixels" - int32_t GetDrawTargetHeight(); - // Returns the currently active draw target - Sprite* GetDrawTarget(); - - public: // Draw Routines - // Specify which Sprite should be the target of drawing functions, use nullptr - // to specify the primary screen - void SetDrawTarget(Sprite *target); - // Change the pixel mode for different optimisations - // olc::Pixel::NORMAL = No transparency - // olc::Pixel::MASK = Transparent if alpha is < 255 - // olc::Pixel::ALPHA = Full transparency - void SetPixelMode(Pixel::Mode m); - Pixel::Mode GetPixelMode(); - // Use a custom blend function - void SetPixelMode(std::function pixelMode); - // Change the blend factor form between 0.0f to 1.0f; - void SetPixelBlend(float fBlend); - // Offset texels by sub-pixel amount (advanced, do not use) - void SetSubPixelOffset(float ox, float oy); - - // Draws a single Pixel - virtual bool Draw(int32_t x, int32_t y, Pixel p = olc::WHITE); - // Draws a line from (x1,y1) to (x2,y2) - void DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p = olc::WHITE, uint32_t pattern = 0xFFFFFFFF); - // Draws a circle located at (x,y) with radius - void DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p = olc::WHITE, uint8_t mask = 0xFF); - // Fills a circle located at (x,y) with radius - void FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p = olc::WHITE); - // Draws a rectangle at (x,y) to (x+w,y+h) - void DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p = olc::WHITE); - // Fills a rectangle at (x,y) to (x+w,y+h) - void FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p = olc::WHITE); - // Draws a triangle between points (x1,y1), (x2,y2) and (x3,y3) - void DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p = olc::WHITE); - // Flat fills a triangle between points (x1,y1), (x2,y2) and (x3,y3) - void FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p = olc::WHITE); - // Draws an entire sprite at location (x,y) - void DrawSprite(int32_t x, int32_t y, Sprite *sprite, uint32_t scale = 1); - // Draws an area of a sprite at location (x,y), where the - // selected area is (ox,oy) to (ox+w,oy+h) - void DrawPartialSprite(int32_t x, int32_t y, Sprite *sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale = 1); - // Draws a single line of text - void DrawString(int32_t x, int32_t y, std::string sText, Pixel col = olc::WHITE, uint32_t scale = 1); - // Clears entire draw target to Pixel - void Clear(Pixel p); - - public: // Branding - std::string sAppName; - - private: // Inner mysterious workings - Sprite *pDefaultDrawTarget = nullptr; - Sprite *pDrawTarget = nullptr; - Pixel::Mode nPixelMode = Pixel::NORMAL; - float fBlendFactor = 1.0f; - uint32_t nScreenWidth = 256; - uint32_t nScreenHeight = 240; - uint32_t nPixelWidth = 4; - uint32_t nPixelHeight = 4; - int32_t nMousePosX = 0; - int32_t nMousePosY = 0; - int32_t nMouseWheelDelta = 0; - int32_t nMousePosXcache = 0; - int32_t nMousePosYcache = 0; - int32_t nMouseWheelDeltaCache = 0; - int32_t nWindowWidth = 0; - int32_t nWindowHeight = 0; - int32_t nViewX = 0; - int32_t nViewY = 0; - int32_t nViewW = 0; - int32_t nViewH = 0; - bool bFullScreen = false; - float fPixelX = 1.0f; - float fPixelY = 1.0f; - float fSubPixelOffsetX = 0.0f; - float fSubPixelOffsetY = 0.0f; - bool bHasInputFocus = false; - bool bHasMouseFocus = false; - float fFrameTimer = 1.0f; - int nFrameCount = 0; - Sprite *fontSprite = nullptr; - std::function funcPixelMode; - - static std::map mapKeys; - bool pKeyNewState[256]{ 0 }; - bool pKeyOldState[256]{ 0 }; - HWButton pKeyboardState[256]; - - bool pMouseNewState[5]{ 0 }; - bool pMouseOldState[5]{ 0 }; - HWButton pMouseState[5]; - -#ifdef _WIN32 - HDC glDeviceContext = nullptr; - HGLRC glRenderContext = nullptr; -#else - GLXContext glDeviceContext = nullptr; - GLXContext glRenderContext = nullptr; -#endif - GLuint glBuffer; - - void EngineThread(); - - // If anything sets this flag to false, the engine - // "should" shut down gracefully - static std::atomic bAtomActive; - - // Common initialisation functions - void olc_UpdateMouse(int32_t x, int32_t y); - void olc_UpdateMouseWheel(int32_t delta); - void olc_UpdateWindowSize(int32_t x, int32_t y); - void olc_UpdateViewport(); - bool olc_OpenGLCreate(); - void olc_ConstructFontSheet(); - - -#ifdef _WIN32 - // Windows specific window handling - HWND olc_hWnd = nullptr; - HWND olc_WindowCreate(); - std::wstring wsAppName; - static LRESULT CALLBACK olc_WindowEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -#else - // Non-Windows specific window handling - Display* olc_Display = nullptr; - Window olc_WindowRoot; - Window olc_Window; - XVisualInfo* olc_VisualInfo; - Colormap olc_ColourMap; - XSetWindowAttributes olc_SetWindowAttribs; - Display* olc_WindowCreate(); -#endif - - }; - - - class PGEX - { - friend class olc::PixelGameEngine; - protected: - static PixelGameEngine* pge; - }; - - //============================================================= -} - -#endif // OLC_PGE_DEF - - - - -/* - Object Oriented Mode - ~~~~~~~~~~~~~~~~~~~~ - - If the olcPixelGameEngine.h is called from several sources it can cause - multiple definitions of objects. To prevent this, ONLY ONE of the pathways - to including this file must have OLC_PGE_APPLICATION defined before it. This prevents - the definitions being duplicated. - - If all else fails, create a file called "olcPixelGameEngine.cpp" with the following - two lines. Then you can just #include "olcPixelGameEngine.h" as normal without worrying - about defining things. Dont forget to include that cpp file as part of your build! - - #define OLC_PGE_APPLICATION - #include "olcPixelGameEngine.h" - -*/ - -#ifdef OLC_PGE_APPLICATION -#undef OLC_PGE_APPLICATION - -namespace olc -{ - Pixel::Pixel() - { - r = 0; g = 0; b = 0; a = 255; - } - - Pixel::Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) - { - r = red; g = green; b = blue; a = alpha; - } - - Pixel::Pixel(uint32_t p) - { - n = p; - } - - //========================================================== - - std::wstring ConvertS2W(std::string s) - { -#ifdef _WIN32 - int count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0); - wchar_t* buffer = new wchar_t[count]; - MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, buffer, count); - std::wstring w(buffer); - delete[] buffer; - return w; -#else - return L"SVN FTW!"; -#endif - } - - Sprite::Sprite() - { - pColData = nullptr; - width = 0; - height = 0; - } - - Sprite::Sprite(std::string sImageFile) - { - LoadFromFile(sImageFile); - } - - Sprite::Sprite(std::string sImageFile, olc::ResourcePack *pack) - { - LoadFromPGESprFile(sImageFile, pack); - } - - Sprite::Sprite(int32_t w, int32_t h) - { - if(pColData) delete[] pColData; - width = w; height = h; - pColData = new Pixel[width * height]; - for (int32_t i = 0; i < width*height; i++) - pColData[i] = Pixel(); - } - - Sprite::~Sprite() - { - if (pColData) delete pColData; - } - - olc::rcode Sprite::LoadFromPGESprFile(std::string sImageFile, olc::ResourcePack *pack) - { - if (pColData) delete[] pColData; - - auto ReadData = [&](std::istream &is) - { - is.read((char*)&width, sizeof(int32_t)); - is.read((char*)&height, sizeof(int32_t)); - pColData = new Pixel[width * height]; - is.read((char*)pColData, width * height * sizeof(uint32_t)); - }; - - // These are essentially Memory Surfaces represented by olc::Sprite - // which load very fast, but are completely uncompressed - if (pack == nullptr) - { - std::ifstream ifs; - ifs.open(sImageFile, std::ifstream::binary); - if (ifs.is_open()) - { - ReadData(ifs); - return olc::OK; - } - else - return olc::FAIL; - } - else - { - auto streamBuffer = pack->GetStreamBuffer(sImageFile); - std::istream is(&streamBuffer); - ReadData(is); - } - - - return olc::FAIL; - } - - olc::rcode Sprite::SaveToPGESprFile(std::string sImageFile) - { - if (pColData == nullptr) return olc::FAIL; - - std::ofstream ofs; - ofs.open(sImageFile, std::ifstream::binary); - if (ofs.is_open()) - { - ofs.write((char*)&width, sizeof(int32_t)); - ofs.write((char*)&height, sizeof(int32_t)); - ofs.write((char*)pColData, width*height*sizeof(uint32_t)); - ofs.close(); - return olc::OK; - } - - return olc::FAIL; - } - - olc::rcode Sprite::LoadFromFile(std::string sImageFile, olc::ResourcePack *pack) - { -#ifdef _WIN32 - // Use GDI+ - std::wstring wsImageFile; -#ifdef __MINGW32__ - wchar_t *buffer = new wchar_t[sImageFile.length() + 1]; - mbstowcs(buffer, sImageFile.c_str(), sImageFile.length()); - buffer[sImageFile.length()] = L'\0'; - wsImageFile = buffer; - delete [] buffer; -#else - wsImageFile = ConvertS2W(sImageFile); -#endif - Gdiplus::Bitmap *bmp = Gdiplus::Bitmap::FromFile(wsImageFile.c_str()); - if (bmp == nullptr) - return olc::NO_FILE; - - width = bmp->GetWidth(); - height = bmp->GetHeight(); - pColData = new Pixel[width * height]; - - for(int x=0; xGetPixel(x, y, &c); - SetPixel(x, y, Pixel(c.GetRed(), c.GetGreen(), c.GetBlue(), c.GetAlpha())); - } - delete bmp; - return olc::OK; -#else - //////////////////////////////////////////////////////////////////////////// - // Use libpng, Thanks to Guillaume Cottenceau - // https://gist.github.com/niw/5963798 - png_structp png; - png_infop info; - - FILE *f = fopen(sImageFile.c_str(), "rb"); - if (!f) return olc::NO_FILE; - - png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png) goto fail_load; - - info = png_create_info_struct(png); - if (!info) goto fail_load; - - if (setjmp(png_jmpbuf(png))) goto fail_load; - - png_init_io(png, f); - png_read_info(png, info); - - png_byte color_type; - png_byte bit_depth; - png_bytep *row_pointers; - width = png_get_image_width(png, info); - height = png_get_image_height(png, info); - color_type = png_get_color_type(png, info); - bit_depth = png_get_bit_depth(png, info); - -#ifdef _DEBUG - std::cout << "Loading PNG: " << sImageFile << "\n"; - std::cout << "W:" << width << " H:" << height << " D:" << (int)bit_depth << "\n"; -#endif - - if (bit_depth == 16) png_set_strip_16(png); - if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png); - if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); - if (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_PALETTE) - png_set_filler(png, 0xFF, PNG_FILLER_AFTER); - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png); - - png_read_update_info(png, info); - row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height); - for (int y = 0; y < height; y++) { - row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info)); - } - png_read_image(png, row_pointers); - //////////////////////////////////////////////////////////////////////////// - - // Create sprite array - pColData = new Pixel[width * height]; - - // Iterate through image rows, converting into sprite format - for (int y = 0; y < height; y++) - { - png_bytep row = row_pointers[y]; - for (int x = 0; x < width; x++) - { - png_bytep px = &(row[x * 4]); - SetPixel(x, y, Pixel(px[0], px[1], px[2], px[3])); - } - } - - fclose(f); - return olc::OK; - - fail_load: - width = 0; - height = 0; - fclose(f); - pColData = nullptr; - return olc::FAIL; -#endif - } - - void Sprite::SetSampleMode(olc::Sprite::Mode mode) - { - modeSample = mode; - } - - - Pixel Sprite::GetPixel(int32_t x, int32_t y) - { - if (modeSample == olc::Sprite::Mode::NORMAL) - { - if (x >= 0 && x < width && y >= 0 && y < height) - return pColData[y*width + x]; - else - return Pixel(0, 0, 0, 0); - } - else - { - return pColData[abs(y%height)*width + abs(x%width)]; - } - } - - bool Sprite::SetPixel(int32_t x, int32_t y, Pixel p) - { - -#ifdef OLC_DBG_OVERDRAW - nOverdrawCount++; -#endif - - if (x >= 0 && x < width && y >= 0 && y < height) - { - pColData[y*width + x] = p; - return true; - } - else - return false; - } - - Pixel Sprite::Sample(float x, float y) - { - int32_t sx = std::min((int32_t)((x * (float)width)), width - 1); - int32_t sy = std::min((int32_t)((y * (float)height)), height - 1); - return GetPixel(sx, sy); - } - - Pixel Sprite::SampleBL(float u, float v) - { - u = u * width - 0.5f; - v = v * height - 0.5f; - int x = (int)floor(u); // cast to int rounds toward zero, not downward - int y = (int)floor(v); // Thanks @joshinils - float u_ratio = u - x; - float v_ratio = v - y; - float u_opposite = 1 - u_ratio; - float v_opposite = 1 - v_ratio; - - olc::Pixel p1 = GetPixel(std::max(x, 0), std::max(y, 0)); - olc::Pixel p2 = GetPixel(std::min(x + 1, (int)width - 1), std::max(y, 0)); - olc::Pixel p3 = GetPixel(std::max(x, 0), std::min(y + 1, (int)height - 1)); - olc::Pixel p4 = GetPixel(std::min(x + 1, (int)width - 1), std::min(y + 1, (int)height - 1)); - - return olc::Pixel( - (uint8_t)((p1.r * u_opposite + p2.r * u_ratio) * v_opposite + (p3.r * u_opposite + p4.r * u_ratio) * v_ratio), - (uint8_t)((p1.g * u_opposite + p2.g * u_ratio) * v_opposite + (p3.g * u_opposite + p4.g * u_ratio) * v_ratio), - (uint8_t)((p1.b * u_opposite + p2.b * u_ratio) * v_opposite + (p3.b * u_opposite + p4.b * u_ratio) * v_ratio)); - } - - Pixel* Sprite::GetData() { return pColData; } - - //========================================================== - - ResourcePack::ResourcePack() - { - - } - - ResourcePack::~ResourcePack() - { - ClearPack(); - } - - olc::rcode ResourcePack::AddToPack(std::string sFile) - { - std::ifstream ifs(sFile, std::ifstream::binary); - if (!ifs.is_open()) return olc::FAIL; - - // Get File Size - std::streampos p = 0; - p = ifs.tellg(); - ifs.seekg(0, std::ios::end); - p = ifs.tellg() - p; - ifs.seekg(0, std::ios::beg); - - // Create entry - sEntry e; - e.data = nullptr; - e.nFileSize = (uint32_t)p; - - // Read file into memory - e.data = new uint8_t[(uint32_t)e.nFileSize]; - ifs.read((char*)e.data, e.nFileSize); - ifs.close(); - - // Add To Map - mapFiles[sFile] = e; - return olc::OK; - } - - olc::rcode ResourcePack::SavePack(std::string sFile) - { - std::ofstream ofs(sFile, std::ofstream::binary); - if (!ofs.is_open()) return olc::FAIL; - - // 1) Write Map - size_t nMapSize = mapFiles.size(); - ofs.write((char*)&nMapSize, sizeof(size_t)); - for (auto &e : mapFiles) - { - size_t nPathSize = e.first.size(); - ofs.write((char*)&nPathSize, sizeof(size_t)); - ofs.write(e.first.c_str(), nPathSize); - ofs.write((char*)&e.second.nID, sizeof(uint32_t)); - ofs.write((char*)&e.second.nFileSize, sizeof(uint32_t)); - ofs.write((char*)&e.second.nFileOffset, sizeof(uint32_t)); - } - - // 2) Write Data - std::streampos offset = ofs.tellp(); - for (auto &e : mapFiles) - { - e.second.nFileOffset = (uint32_t)offset; - ofs.write((char*)e.second.data, e.second.nFileSize); - offset += e.second.nFileSize; - } - - // 3) Rewrite Map (it has been updated with offsets now) - ofs.seekp(std::ios::beg); - ofs.write((char*)&nMapSize, sizeof(size_t)); - for (auto &e : mapFiles) - { - size_t nPathSize = e.first.size(); - ofs.write((char*)&nPathSize, sizeof(size_t)); - ofs.write(e.first.c_str(), nPathSize); - ofs.write((char*)&e.second.nID, sizeof(uint32_t)); - ofs.write((char*)&e.second.nFileSize, sizeof(uint32_t)); - ofs.write((char*)&e.second.nFileOffset, sizeof(uint32_t)); - } - ofs.close(); - - return olc::OK; - } - - olc::rcode ResourcePack::LoadPack(std::string sFile) - { - std::ifstream ifs(sFile, std::ifstream::binary); - if (!ifs.is_open()) return olc::FAIL; - - // 1) Read Map - uint32_t nMapEntries; - ifs.read((char*)&nMapEntries, sizeof(uint32_t)); - for (uint32_t i = 0; i < nMapEntries; i++) - { - uint32_t nFilePathSize = 0; - ifs.read((char*)&nFilePathSize, sizeof(uint32_t)); - - std::string sFileName(nFilePathSize, ' '); - for (uint32_t j = 0; j < nFilePathSize; j++) - sFileName[j] = ifs.get(); - - sEntry e; - e.data = nullptr; - ifs.read((char*)&e.nID, sizeof(uint32_t)); - ifs.read((char*)&e.nFileSize, sizeof(uint32_t)); - ifs.read((char*)&e.nFileOffset, sizeof(uint32_t)); - mapFiles[sFileName] = e; - } - - // 2) Read Data - for (auto &e : mapFiles) - { - e.second.data = new uint8_t[(uint32_t)e.second.nFileSize]; - ifs.seekg(e.second.nFileOffset); - ifs.read((char*)e.second.data, e.second.nFileSize); - e.second._config(); - } - - ifs.close(); - return olc::OK; - } - - olc::ResourcePack::sEntry ResourcePack::GetStreamBuffer(std::string sFile) - { - return mapFiles[sFile]; - } - - olc::rcode ResourcePack::ClearPack() - { - for (auto &e : mapFiles) - { - if (e.second.data != nullptr) - delete[] e.second.data; - } - - mapFiles.clear(); - return olc::OK; - } - - //========================================================== - - PixelGameEngine::PixelGameEngine() - { - sAppName = "Undefined"; - olc::PGEX::pge = this; - } - - olc::rcode PixelGameEngine::Construct(uint32_t screen_w, uint32_t screen_h, uint32_t pixel_w, uint32_t pixel_h, bool full_screen) - { - nScreenWidth = screen_w; - nScreenHeight = screen_h; - nPixelWidth = pixel_w; - nPixelHeight = pixel_h; - bFullScreen = full_screen; - - fPixelX = 2.0f / (float)(nScreenWidth); - fPixelY = 2.0f / (float)(nScreenHeight); - - if (nPixelWidth == 0 || nPixelHeight == 0 || nScreenWidth == 0 || nScreenHeight == 0) - return olc::FAIL; - -#ifdef _WIN32 -#ifdef UNICODE -#ifndef __MINGW32__ - wsAppName = ConvertS2W(sAppName); -#endif -#endif -#endif - // Load the default font sheet - olc_ConstructFontSheet(); - - // Create a sprite that represents the primary drawing target - pDefaultDrawTarget = new Sprite(nScreenWidth, nScreenHeight); - SetDrawTarget(nullptr); - return olc::OK; - } - - olc::rcode PixelGameEngine::Start() - { - // Construct the window - if (!olc_WindowCreate()) - return olc::FAIL; - - // Load libraries required for PNG file interaction -//#ifdef _WIN32 -// // Windows use GDI+ -// Gdiplus::GdiplusStartupInput startupInput; -// ULONG_PTR token; -// Gdiplus::GdiplusStartup(&token, &startupInput, NULL); -//#else -// // Linux use libpng -// -//#endif - // Start the thread - bAtomActive = true; - std::thread t = std::thread(&PixelGameEngine::EngineThread, this); - -#ifdef _WIN32 - // Handle Windows Message Loop - MSG msg; - while (GetMessage(&msg, NULL, 0, 0) > 0) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } -#endif - - // Wait for thread to be exited - t.join(); - return olc::OK; - } - - void PixelGameEngine::SetDrawTarget(Sprite *target) - { - if (target) - pDrawTarget = target; - else - pDrawTarget = pDefaultDrawTarget; - } - - Sprite* PixelGameEngine::GetDrawTarget() - { - return pDrawTarget; - } - - int32_t PixelGameEngine::GetDrawTargetWidth() - { - if (pDrawTarget) - return pDrawTarget->width; - else - return 0; - } - - int32_t PixelGameEngine::GetDrawTargetHeight() - { - if (pDrawTarget) - return pDrawTarget->height; - else - return 0; - } - - bool PixelGameEngine::IsFocused() - { - return bHasInputFocus; - } - - HWButton PixelGameEngine::GetKey(Key k) - { - return pKeyboardState[k]; - } - - HWButton PixelGameEngine::GetMouse(uint32_t b) - { - return pMouseState[b]; - } - - int32_t PixelGameEngine::GetMouseX() - { - return nMousePosX; - } - - int32_t PixelGameEngine::GetMouseY() - { - return nMousePosY; - } - - int32_t PixelGameEngine::GetMouseWheel() - { - return nMouseWheelDelta; - } - - int32_t PixelGameEngine::ScreenWidth() - { - return nScreenWidth; - } - - int32_t PixelGameEngine::ScreenHeight() - { - return nScreenHeight; - } - - bool PixelGameEngine::Draw(int32_t x, int32_t y, Pixel p) - { - if (!pDrawTarget) return false; - - - if (nPixelMode == Pixel::NORMAL) - { - return pDrawTarget->SetPixel(x, y, p); - } - - if (nPixelMode == Pixel::MASK) - { - if(p.a == 255) - return pDrawTarget->SetPixel(x, y, p); - } - - if (nPixelMode == Pixel::ALPHA) - { - Pixel d = pDrawTarget->GetPixel(x, y); - float a = (float)(p.a / 255.0f) * fBlendFactor; - float c = 1.0f - a; - float r = a * (float)p.r + c * (float)d.r; - float g = a * (float)p.g + c * (float)d.g; - float b = a * (float)p.b + c * (float)d.b; - return pDrawTarget->SetPixel(x, y, Pixel((uint8_t)r, (uint8_t)g, (uint8_t)b)); - } - - if (nPixelMode == Pixel::CUSTOM) - { - return pDrawTarget->SetPixel(x, y, funcPixelMode(x, y, p, pDrawTarget->GetPixel(x, y))); - } - - return false; - } - - void PixelGameEngine::SetSubPixelOffset(float ox, float oy) - { - fSubPixelOffsetX = ox * fPixelX; - fSubPixelOffsetY = oy * fPixelY; - } - - void PixelGameEngine::DrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, Pixel p, uint32_t pattern) - { - int x, y, dx, dy, dx1, dy1, px, py, xe, ye, i; - dx = x2 - x1; dy = y2 - y1; - - auto rol = [&](void) - { - pattern = (pattern << 1) | (pattern >> 31); - return pattern & 1; - }; - - // straight lines idea by gurkanctn - if (dx == 0) // Line is vertical - { - if (y2 < y1) std::swap(y1, y2); - for (y = y1; y <= y2; y++) - if (rol()) Draw(x1, y, p); - return; - } - - if (dy == 0) // Line is horizontal - { - if (x2 < x1) std::swap(x1, x2); - for (x = x1; x <= x2; x++) - if (rol()) Draw(x, y1, p); - return; - } - - // Line is Funk-aye - dx1 = abs(dx); dy1 = abs(dy); - px = 2 * dy1 - dx1; py = 2 * dx1 - dy1; - if (dy1 <= dx1) - { - if (dx >= 0) - { - x = x1; y = y1; xe = x2; - } - else - { - x = x2; y = y2; xe = x1; - } - - if (rol()) Draw(x, y, p); - - for (i = 0; x0 && dy>0)) y = y + 1; else y = y - 1; - px = px + 2 * (dy1 - dx1); - } - if (rol()) Draw(x, y, p); - } - } - else - { - if (dy >= 0) - { - x = x1; y = y1; ye = y2; - } - else - { - x = x2; y = y2; ye = y1; - } - - if (rol()) Draw(x, y, p); - - for (i = 0; y0 && dy>0)) x = x + 1; else x = x - 1; - py = py + 2 * (dx1 - dy1); - } - if (rol()) Draw(x, y, p); - } - } - } - - void PixelGameEngine::DrawCircle(int32_t x, int32_t y, int32_t radius, Pixel p, uint8_t mask) - { - int x0 = 0; - int y0 = radius; - int d = 3 - 2 * radius; - if (!radius) return; - - while (y0 >= x0) // only formulate 1/8 of circle - { - if (mask & 0x01) Draw(x + x0, y - y0, p); - if (mask & 0x02) Draw(x + y0, y - x0, p); - if (mask & 0x04) Draw(x + y0, y + x0, p); - if (mask & 0x08) Draw(x + x0, y + y0, p); - if (mask & 0x10) Draw(x - x0, y + y0, p); - if (mask & 0x20) Draw(x - y0, y + x0, p); - if (mask & 0x40) Draw(x - y0, y - x0, p); - if (mask & 0x80) Draw(x - x0, y - y0, p); - if (d < 0) d += 4 * x0++ + 6; - else d += 4 * (x0++ - y0--) + 10; - } - } - - void PixelGameEngine::FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p) - { - // Taken from wikipedia - int x0 = 0; - int y0 = radius; - int d = 3 - 2 * radius; - if (!radius) return; - - auto drawline = [&](int sx, int ex, int ny) - { - for (int i = sx; i <= ex; i++) - Draw(i, ny, p); - }; - - while (y0 >= x0) - { - // Modified to draw scan-lines instead of edges - drawline(x - x0, x + x0, y - y0); - drawline(x - y0, x + y0, y - x0); - drawline(x - x0, x + x0, y + y0); - drawline(x - y0, x + y0, y + x0); - if (d < 0) d += 4 * x0++ + 6; - else d += 4 * (x0++ - y0--) + 10; - } - } - - void PixelGameEngine::DrawRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p) - { - DrawLine(x, y, x+w, y, p); - DrawLine(x+w, y, x+w, y+h, p); - DrawLine(x+w, y+h, x, y+h, p); - DrawLine(x, y+h, x, y, p); - } - - void PixelGameEngine::Clear(Pixel p) - { - int pixels = GetDrawTargetWidth() * GetDrawTargetHeight(); - Pixel* m = GetDrawTarget()->GetData(); - for (int i = 0; i < pixels; i++) - m[i] = p; -#ifdef OLC_DBG_OVERDRAW - olc::Sprite::nOverdrawCount += pixels; -#endif - } - - void PixelGameEngine::FillRect(int32_t x, int32_t y, int32_t w, int32_t h, Pixel p) - { - int32_t x2 = x + w; - int32_t y2 = y + h; - - if (x < 0) x = 0; - if (x >= (int32_t)nScreenWidth) x = (int32_t)nScreenWidth; - if (y < 0) y = 0; - if (y >= (int32_t)nScreenHeight) y = (int32_t)nScreenHeight; - - if (x2 < 0) x2 = 0; - if (x2 >= (int32_t)nScreenWidth) x2 = (int32_t)nScreenWidth; - if (y2 < 0) y2 = 0; - if (y2 >= (int32_t)nScreenHeight) y2 = (int32_t)nScreenHeight; - - for (int i = x; i < x2; i++) - for (int j = y; j < y2; j++) - Draw(i, j, p); - } - - void PixelGameEngine::DrawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p) - { - DrawLine(x1, y1, x2, y2, p); - DrawLine(x2, y2, x3, y3, p); - DrawLine(x3, y3, x1, y1, p); - } - - // https://www.avrfreaks.net/sites/default/files/triangles.c - void PixelGameEngine::FillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, Pixel p) - { - auto SWAP = [](int &x, int &y) { int t = x; x = y; y = t; }; - auto drawline = [&](int sx, int ex, int ny) { for (int i = sx; i <= ex; i++) Draw(i, ny, p); }; - - int t1x, t2x, y, minx, maxx, t1xp, t2xp; - bool changed1 = false; - bool changed2 = false; - int signx1, signx2, dx1, dy1, dx2, dy2; - int e1, e2; - // Sort vertices - if (y1>y2) { SWAP(y1, y2); SWAP(x1, x2); } - if (y1>y3) { SWAP(y1, y3); SWAP(x1, x3); } - if (y2>y3) { SWAP(y2, y3); SWAP(x2, x3); } - - t1x = t2x = x1; y = y1; // Starting points - dx1 = (int)(x2 - x1); if (dx1<0) { dx1 = -dx1; signx1 = -1; } - else signx1 = 1; - dy1 = (int)(y2 - y1); - - dx2 = (int)(x3 - x1); if (dx2<0) { dx2 = -dx2; signx2 = -1; } - else signx2 = 1; - dy2 = (int)(y3 - y1); - - if (dy1 > dx1) { // swap values - SWAP(dx1, dy1); - changed1 = true; - } - if (dy2 > dx2) { // swap values - SWAP(dy2, dx2); - changed2 = true; - } - - e2 = (int)(dx2 >> 1); - // Flat top, just process the second half - if (y1 == y2) goto next; - e1 = (int)(dx1 >> 1); - - for (int i = 0; i < dx1;) { - t1xp = 0; t2xp = 0; - if (t1x= dx1) { - e1 -= dx1; - if (changed1) t1xp = signx1;//t1x += signx1; - else goto next1; - } - if (changed1) break; - else t1x += signx1; - } - // Move line - next1: - // process second line until y value is about to change - while (1) { - e2 += dy2; - while (e2 >= dx2) { - e2 -= dx2; - if (changed2) t2xp = signx2;//t2x += signx2; - else goto next2; - } - if (changed2) break; - else t2x += signx2; - } - next2: - if (minx>t1x) minx = t1x; if (minx>t2x) minx = t2x; - if (maxx dx1) { // swap values - SWAP(dy1, dx1); - changed1 = true; - } - else changed1 = false; - - e1 = (int)(dx1 >> 1); - - for (int i = 0; i <= dx1; i++) { - t1xp = 0; t2xp = 0; - if (t1x= dx1) { - e1 -= dx1; - if (changed1) { t1xp = signx1; break; }//t1x += signx1; - else goto next3; - } - if (changed1) break; - else t1x += signx1; - if (i= dx2) { - e2 -= dx2; - if (changed2) t2xp = signx2; - else goto next4; - } - if (changed2) break; - else t2x += signx2; - } - next4: - - if (minx>t1x) minx = t1x; if (minx>t2x) minx = t2x; - if (maxxy3) return; - } - } - - void PixelGameEngine::DrawSprite(int32_t x, int32_t y, Sprite *sprite, uint32_t scale) - { - if (sprite == nullptr) - return; - - if (scale > 1) - { - for (int32_t i = 0; i < sprite->width; i++) - for (int32_t j = 0; j < sprite->height; j++) - for (uint32_t is = 0; is < scale; is++) - for (uint32_t js = 0; js < scale; js++) - Draw(x + (i*scale) + is, y + (j*scale) + js, sprite->GetPixel(i, j)); - } - else - { - for (int32_t i = 0; i < sprite->width; i++) - for (int32_t j = 0; j < sprite->height; j++) - Draw(x + i, y + j, sprite->GetPixel(i, j)); - } - } - - void PixelGameEngine::DrawPartialSprite(int32_t x, int32_t y, Sprite *sprite, int32_t ox, int32_t oy, int32_t w, int32_t h, uint32_t scale) - { - if (sprite == nullptr) - return; - - if (scale > 1) - { - for (int32_t i = 0; i < w; i++) - for (int32_t j = 0; j < h; j++) - for (uint32_t is = 0; is < scale; is++) - for (uint32_t js = 0; js < scale; js++) - Draw(x + (i*scale) + is, y + (j*scale) + js, sprite->GetPixel(i + ox, j + oy)); - } - else - { - for (int32_t i = 0; i < w; i++) - for (int32_t j = 0; j < h; j++) - Draw(x + i, y + j, sprite->GetPixel(i + ox, j + oy)); - } - } - - void PixelGameEngine::DrawString(int32_t x, int32_t y, std::string sText, Pixel col, uint32_t scale) - { - int32_t sx = 0; - int32_t sy = 0; - Pixel::Mode m = nPixelMode; - if(col.ALPHA != 255) SetPixelMode(Pixel::ALPHA); - else SetPixelMode(Pixel::MASK); - for (auto c : sText) - { - if (c == '\n') - { - sx = 0; sy += 8 * scale; - } - else - { - int32_t ox = (c - 32) % 16; - int32_t oy = (c - 32) / 16; - - if (scale > 1) - { - for (uint32_t i = 0; i < 8; i++) - for (uint32_t j = 0; j < 8; j++) - if (fontSprite->GetPixel(i + ox * 8, j + oy * 8).r > 0) - for (uint32_t is = 0; is < scale; is++) - for (uint32_t js = 0; js < scale; js++) - Draw(x + sx + (i*scale) + is, y + sy + (j*scale) + js, col); - } - else - { - for (uint32_t i = 0; i < 8; i++) - for (uint32_t j = 0; j < 8; j++) - if (fontSprite->GetPixel(i + ox * 8, j + oy * 8).r > 0) - Draw(x + sx + i, y + sy + j, col); - } - sx += 8 * scale; - } - } - SetPixelMode(m); - } - - void PixelGameEngine::SetPixelMode(Pixel::Mode m) - { - nPixelMode = m; - } - - Pixel::Mode PixelGameEngine::GetPixelMode() - { - return nPixelMode; - } - - void PixelGameEngine::SetPixelMode(std::function pixelMode) - { - funcPixelMode = pixelMode; - nPixelMode = Pixel::Mode::CUSTOM; - } - - void PixelGameEngine::SetPixelBlend(float fBlend) - { - fBlendFactor = fBlend; - if (fBlendFactor < 0.0f) fBlendFactor = 0.0f; - if (fBlendFactor > 1.0f) fBlendFactor = 1.0f; - } - - // User must override these functions as required. I have not made - // them abstract because I do need a default behaviour to occur if - // they are not overwritten - bool PixelGameEngine::OnUserCreate() - { return false; } - bool PixelGameEngine::OnUserUpdate(float fElapsedTime) - { return false; } - bool PixelGameEngine::OnUserDestroy() - { return true; } - ////////////////////////////////////////////////////////////////// - - void PixelGameEngine::olc_UpdateViewport() - { - int32_t ww = nScreenWidth * nPixelWidth; - int32_t wh = nScreenHeight * nPixelHeight; - float wasp = (float)ww / (float)wh; - - nViewW = (int32_t)nWindowWidth; - nViewH = (int32_t)((float)nViewW / wasp); - - if (nViewH > nWindowHeight) - { - nViewH = nWindowHeight; - nViewW = (int32_t)((float)nViewH * wasp); - } - - nViewX = (nWindowWidth - nViewW) / 2; - nViewY = (nWindowHeight - nViewH) / 2; - } - - void PixelGameEngine::olc_UpdateWindowSize(int32_t x, int32_t y) - { - nWindowWidth = x; - nWindowHeight = y; - olc_UpdateViewport(); - - } - - void PixelGameEngine::olc_UpdateMouseWheel(int32_t delta) - { - nMouseWheelDeltaCache += delta; - } - - void PixelGameEngine::olc_UpdateMouse(int32_t x, int32_t y) - { - // Mouse coords come in screen space - // But leave in pixel space - - //if (bFullScreen) - { - // Full Screen mode may have a weird viewport we must clamp to - x -= nViewX; - y -= nViewY; - } - - nMousePosXcache = (int32_t)(((float)x / (float)(nWindowWidth - (nViewX * 2)) * (float)nScreenWidth)); - nMousePosYcache = (int32_t)(((float)y / (float)(nWindowHeight - (nViewY * 2)) * (float)nScreenHeight)); - - if (nMousePosXcache >= (int32_t)nScreenWidth) - nMousePosXcache = nScreenWidth - 1; - if (nMousePosYcache >= (int32_t)nScreenHeight) - nMousePosYcache = nScreenHeight - 1; - - if (nMousePosXcache < 0) - nMousePosXcache = 0; - if (nMousePosYcache < 0) - nMousePosYcache = 0; - } - - void PixelGameEngine::EngineThread() - { - // Start OpenGL, the context is owned by the game thread - olc_OpenGLCreate(); - - // Create Screen Texture - disable filtering - glEnable(GL_TEXTURE_2D); - glGenTextures(1, &glBuffer); - glBindTexture(GL_TEXTURE_2D, glBuffer); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nScreenWidth, nScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pDefaultDrawTarget->GetData()); - - - // Create user resources as part of this thread - if (!OnUserCreate()) - bAtomActive = false; - - auto tp1 = std::chrono::system_clock::now(); - auto tp2 = std::chrono::system_clock::now(); - - while (bAtomActive) - { - // Run as fast as possible - while (bAtomActive) - { - // Handle Timing - tp2 = std::chrono::system_clock::now(); - std::chrono::duration elapsedTime = tp2 - tp1; - tp1 = tp2; - - // Our time per frame coefficient - float fElapsedTime = elapsedTime.count(); - -#ifndef _WIN32 - // Handle Xlib Message Loop - we do this in the - // same thread that OpenGL was created so we dont - // need to worry too much about multithreading with X11 - XEvent xev; - while (XPending(olc_Display)) - { - XNextEvent(olc_Display, &xev); - if (xev.type == Expose) - { - XWindowAttributes gwa; - XGetWindowAttributes(olc_Display, olc_Window, &gwa); - nWindowWidth = gwa.width; - nWindowHeight = gwa.height; - olc_UpdateViewport(); - glClear(GL_COLOR_BUFFER_BIT); // Thanks Benedani! - } - else if (xev.type == ConfigureNotify) - { - XConfigureEvent xce = xev.xconfigure; - nWindowWidth = xce.width; - nWindowHeight = xce.height; - } - else if (xev.type == KeyPress) - { - KeySym sym = XLookupKeysym(&xev.xkey, 0); - pKeyNewState[mapKeys[sym]] = true; - XKeyEvent *e = (XKeyEvent *)&xev; // Because DragonEye loves numpads - XLookupString(e, NULL, 0, &sym, NULL); - pKeyNewState[mapKeys[sym]] = true; - } - else if (xev.type == KeyRelease) - { - KeySym sym = XLookupKeysym(&xev.xkey, 0); - pKeyNewState[mapKeys[sym]] = false; - XKeyEvent *e = (XKeyEvent *)&xev; - XLookupString(e, NULL, 0, &sym, NULL); - pKeyNewState[mapKeys[sym]] = false; - } - else if (xev.type == ButtonPress) - { - switch (xev.xbutton.button) - { - case 1: pMouseNewState[0] = true; break; - case 2: pMouseNewState[2] = true; break; - case 3: pMouseNewState[1] = true; break; - case 4: olc_UpdateMouseWheel(120); break; - case 5: olc_UpdateMouseWheel(-120); break; - default: break; - } - } - else if (xev.type == ButtonRelease) - { - switch (xev.xbutton.button) - { - case 1: pMouseNewState[0] = false; break; - case 2: pMouseNewState[2] = false; break; - case 3: pMouseNewState[1] = false; break; - default: break; - } - } - else if (xev.type == MotionNotify) - { - olc_UpdateMouse(xev.xmotion.x, xev.xmotion.y); - } - else if (xev.type == FocusIn) - { - bHasInputFocus = true; - } - else if (xev.type == FocusOut) - { - bHasInputFocus = false; - } - else if (xev.type == ClientMessage) - { - bAtomActive = false; - } - } -#endif - - // Handle User Input - Keyboard - for (int i = 0; i < 256; i++) - { - pKeyboardState[i].bPressed = false; - pKeyboardState[i].bReleased = false; - - if (pKeyNewState[i] != pKeyOldState[i]) - { - if (pKeyNewState[i]) - { - pKeyboardState[i].bPressed = !pKeyboardState[i].bHeld; - pKeyboardState[i].bHeld = true; - } - else - { - pKeyboardState[i].bReleased = true; - pKeyboardState[i].bHeld = false; - } - } - - pKeyOldState[i] = pKeyNewState[i]; - } - - // Handle User Input - Mouse - for (int i = 0; i < 5; i++) - { - pMouseState[i].bPressed = false; - pMouseState[i].bReleased = false; - - if (pMouseNewState[i] != pMouseOldState[i]) - { - if (pMouseNewState[i]) - { - pMouseState[i].bPressed = !pMouseState[i].bHeld; - pMouseState[i].bHeld = true; - } - else - { - pMouseState[i].bReleased = true; - pMouseState[i].bHeld = false; - } - } - - pMouseOldState[i] = pMouseNewState[i]; - } - - // Cache mouse coordinates so they remain - // consistent during frame - nMousePosX = nMousePosXcache; - nMousePosY = nMousePosYcache; - - nMouseWheelDelta = nMouseWheelDeltaCache; - nMouseWheelDeltaCache = 0; - -#ifdef OLC_DBG_OVERDRAW - olc::Sprite::nOverdrawCount = 0; -#endif - - // Handle Frame Update - if (!OnUserUpdate(fElapsedTime)) - bAtomActive = false; - - // Display Graphics - glViewport(nViewX, nViewY, nViewW, nViewH); - - // TODO: This is a bit slow (especially in debug, but 100x faster in release mode???) - // Copy pixel array into texture - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, nScreenWidth, nScreenHeight, GL_RGBA, GL_UNSIGNED_BYTE, pDefaultDrawTarget->GetData()); - - // Display texture on screen - glBegin(GL_QUADS); - glTexCoord2f(0.0, 1.0); glVertex3f(-1.0f + (fSubPixelOffsetX), -1.0f + (fSubPixelOffsetY), 0.0f); - glTexCoord2f(0.0, 0.0); glVertex3f(-1.0f + (fSubPixelOffsetX), 1.0f + (fSubPixelOffsetY), 0.0f); - glTexCoord2f(1.0, 0.0); glVertex3f( 1.0f + (fSubPixelOffsetX), 1.0f + (fSubPixelOffsetY), 0.0f); - glTexCoord2f(1.0, 1.0); glVertex3f( 1.0f + (fSubPixelOffsetX), -1.0f + (fSubPixelOffsetY), 0.0f); - glEnd(); - - // Present Graphics to screen -#ifdef _WIN32 - SwapBuffers(glDeviceContext); -#else - glXSwapBuffers(olc_Display, olc_Window); -#endif - - // Update Title Bar - fFrameTimer += fElapsedTime; - nFrameCount++; - if (fFrameTimer >= 1.0f) - { - fFrameTimer -= 1.0f; - - std::string sTitle = "OneLoneCoder.com - Pixel Game Engine - " + sAppName + " - FPS: " + std::to_string(nFrameCount); -#ifdef _WIN32 -#ifdef UNICODE - SetWindowText(olc_hWnd, ConvertS2W(sTitle).c_str()); -#else - SetWindowText(olc_hWnd, sTitle.c_str()); -#endif -#else - XStoreName(olc_Display, olc_Window, sTitle.c_str()); -#endif - nFrameCount = 0; - } - } - - // Allow the user to free resources if they have overrided the destroy function - if (OnUserDestroy()) - { - // User has permitted destroy, so exit and clean up - } - else - { - // User denied destroy for some reason, so continue running - bAtomActive = true; - } - } - -#ifdef _WIN32 - wglDeleteContext(glRenderContext); - PostMessage(olc_hWnd, WM_DESTROY, 0, 0); -#else - glXMakeCurrent(olc_Display, None, NULL); - glXDestroyContext(olc_Display, glDeviceContext); - XDestroyWindow(olc_Display, olc_Window); - XCloseDisplay(olc_Display); -#endif - - } - -#ifdef _WIN32 - // Thanks @MaGetzUb for this, which allows sprites to be defined - // at construction, by initialising the GDI subsystem - static class GDIPlusStartup - { - public: - GDIPlusStartup() - { - Gdiplus::GdiplusStartupInput startupInput; - ULONG_PTR token; - Gdiplus::GdiplusStartup(&token, &startupInput, NULL); - }; - } gdistartup; -#endif - - - void PixelGameEngine::olc_ConstructFontSheet() - { - std::string data; - data += "?Q`0001oOch0o01o@F40o000000000"; - data += "O000000nOT0063Qo4d8>?7a14Gno94AA4gno94AaOT0>o3`oO400o7QN00000400"; - data += "Of80001oOg<7O7moBGT7O7lABET024@aBEd714AiOdl717a_=TH013Q>00000000"; - data += "720D000V?V5oB3Q_HdUoE7a9@DdDE4A9@DmoE4A;Hg]oM4Aj8S4D84@`00000000"; - data += "OaPT1000Oa`^13P1@AI[?g`1@A=[OdAoHgljA4Ao?WlBA7l1710007l100000000"; - data += "ObM6000oOfMV?3QoBDD`O7a0BDDH@5A0BDD<@5A0BGeVO5ao@CQR?5Po00000000"; - data += "Oc``000?Ogij70PO2D]??0Ph2DUM@7i`2DTg@7lh2GUj?0TO0C1870T?00000000"; - data += "70<4001o?P<7?1QoHg43O;`h@GT0@:@LB@d0>:@hN@L0@?aoN@<0O7ao0000?000"; - data += "OcH0001SOglLA7mg24TnK7ln24US>0PL24U140PnOgl0>7QgOcH0K71S0000A000"; - data += "00H00000@Dm1S007@DUSg00?OdTnH7YhOfTL<7Yh@Cl0700?@Ah0300700000000"; - data += "<008001QL00ZA41a@6HnI<1i@FHLM81M@@0LG81?O`0nC?Y7?`0ZA7Y300080000"; - data += "O`082000Oh0827mo6>Hn?Wmo?6HnMb11MP08@C11H`08@FP0@@0004@000000000"; - data += "00P00001Oab00003OcKP0006@6=PMgl<@440MglH@000000`@000001P00000000"; - data += "Ob@8@@00Ob@8@Ga13R@8Mga172@8?PAo3R@827QoOb@820@0O`0007`0000007P0"; - data += "O`000P08Od400g`<3V=P0G`673IP0`@3>1`00P@6O`P00g`SetPixel(px, py, olc::Pixel(k, k, k, k)); - if (++py == 48) { px++; py = 0; } - } - } - } - -#ifdef _WIN32 - HWND PixelGameEngine::olc_WindowCreate() - { - WNDCLASS wc; - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - wc.hInstance = GetModuleHandle(nullptr); - wc.lpfnWndProc = olc_WindowEvent; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.lpszMenuName = nullptr; - wc.hbrBackground = nullptr; -#ifdef UNICODE - wc.lpszClassName = L"OLC_PIXEL_GAME_ENGINE"; -#else - wc.lpszClassName = "OLC_PIXEL_GAME_ENGINE"; -#endif - - RegisterClass(&wc); - - nWindowWidth = (LONG)nScreenWidth * (LONG)nPixelWidth; - nWindowHeight = (LONG)nScreenHeight * (LONG)nPixelHeight; - - // Define window furniture - DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - DWORD dwStyle = WS_CAPTION | WS_SYSMENU | WS_VISIBLE;// | WS_THICKFRAME; - - int nCosmeticOffset = 30; - nViewW = nWindowWidth; - nViewH = nWindowHeight; - - // Handle Fullscreen - if (bFullScreen) - { - dwExStyle = 0; - dwStyle = WS_VISIBLE | WS_POPUP; - nCosmeticOffset = 0; - HMONITOR hmon = MonitorFromWindow(olc_hWnd, MONITOR_DEFAULTTONEAREST); - MONITORINFO mi = { sizeof(mi) }; - if (!GetMonitorInfo(hmon, &mi)) return NULL; - nWindowWidth = mi.rcMonitor.right; - nWindowHeight = mi.rcMonitor.bottom; - - - } - - olc_UpdateViewport(); - - // Keep client size as requested - RECT rWndRect = { 0, 0, nWindowWidth, nWindowHeight }; - AdjustWindowRectEx(&rWndRect, dwStyle, FALSE, dwExStyle); - int width = rWndRect.right - rWndRect.left; - int height = rWndRect.bottom - rWndRect.top; - -#ifdef UNICODE - olc_hWnd = CreateWindowEx(dwExStyle, L"OLC_PIXEL_GAME_ENGINE", L"", dwStyle, - nCosmeticOffset, nCosmeticOffset, width, height, NULL, NULL, GetModuleHandle(nullptr), this); -#else - olc_hWnd = CreateWindowEx(dwExStyle, "OLC_PIXEL_GAME_ENGINE", "", dwStyle, - nCosmeticOffset, nCosmeticOffset, width, height, NULL, NULL, GetModuleHandle(nullptr), this); -#endif - - // Create Keyboard Mapping - mapKeys[0x00] = Key::NONE; - mapKeys[0x41] = Key::A; mapKeys[0x42] = Key::B; mapKeys[0x43] = Key::C; mapKeys[0x44] = Key::D; mapKeys[0x45] = Key::E; - mapKeys[0x46] = Key::F; mapKeys[0x47] = Key::G; mapKeys[0x48] = Key::H; mapKeys[0x49] = Key::I; mapKeys[0x4A] = Key::J; - mapKeys[0x4B] = Key::K; mapKeys[0x4C] = Key::L; mapKeys[0x4D] = Key::M; mapKeys[0x4E] = Key::N; mapKeys[0x4F] = Key::O; - mapKeys[0x50] = Key::P; mapKeys[0x51] = Key::Q; mapKeys[0x52] = Key::R; mapKeys[0x53] = Key::S; mapKeys[0x54] = Key::T; - mapKeys[0x55] = Key::U; mapKeys[0x56] = Key::V; mapKeys[0x57] = Key::W; mapKeys[0x58] = Key::X; mapKeys[0x59] = Key::Y; - mapKeys[0x5A] = Key::Z; - - mapKeys[VK_F1] = Key::F1; mapKeys[VK_F2] = Key::F2; mapKeys[VK_F3] = Key::F3; mapKeys[VK_F4] = Key::F4; - mapKeys[VK_F5] = Key::F5; mapKeys[VK_F6] = Key::F6; mapKeys[VK_F7] = Key::F7; mapKeys[VK_F8] = Key::F8; - mapKeys[VK_F9] = Key::F9; mapKeys[VK_F10] = Key::F10; mapKeys[VK_F11] = Key::F11; mapKeys[VK_F12] = Key::F12; - - mapKeys[VK_DOWN] = Key::DOWN; mapKeys[VK_LEFT] = Key::LEFT; mapKeys[VK_RIGHT] = Key::RIGHT; mapKeys[VK_UP] = Key::UP; - mapKeys[VK_RETURN] = Key::ENTER; //mapKeys[VK_RETURN] = Key::RETURN; - - mapKeys[VK_BACK] = Key::BACK; mapKeys[VK_ESCAPE] = Key::ESCAPE; mapKeys[VK_RETURN] = Key::ENTER; mapKeys[VK_PAUSE] = Key::PAUSE; - mapKeys[VK_SCROLL] = Key::SCROLL; mapKeys[VK_TAB] = Key::TAB; mapKeys[VK_DELETE] = Key::DEL; mapKeys[VK_HOME] = Key::HOME; - mapKeys[VK_END] = Key::END; mapKeys[VK_PRIOR] = Key::PGUP; mapKeys[VK_NEXT] = Key::PGDN; mapKeys[VK_INSERT] = Key::INS; - mapKeys[VK_SHIFT] = Key::SHIFT; mapKeys[VK_CONTROL] = Key::CTRL; - mapKeys[VK_SPACE] = Key::SPACE; - - mapKeys[0x30] = Key::K0; mapKeys[0x31] = Key::K1; mapKeys[0x32] = Key::K2; mapKeys[0x33] = Key::K3; mapKeys[0x34] = Key::K4; - mapKeys[0x35] = Key::K5; mapKeys[0x36] = Key::K6; mapKeys[0x37] = Key::K7; mapKeys[0x38] = Key::K8; mapKeys[0x39] = Key::K9; - - mapKeys[VK_NUMPAD0] = Key::NP0; mapKeys[VK_NUMPAD1] = Key::NP1; mapKeys[VK_NUMPAD2] = Key::NP2; mapKeys[VK_NUMPAD3] = Key::NP3; mapKeys[VK_NUMPAD4] = Key::NP4; - mapKeys[VK_NUMPAD5] = Key::NP5; mapKeys[VK_NUMPAD6] = Key::NP6; mapKeys[VK_NUMPAD7] = Key::NP7; mapKeys[VK_NUMPAD8] = Key::NP8; mapKeys[VK_NUMPAD9] = Key::NP9; - mapKeys[VK_MULTIPLY] = Key::NP_MUL; mapKeys[VK_ADD] = Key::NP_ADD; mapKeys[VK_DIVIDE] = Key::NP_DIV; mapKeys[VK_SUBTRACT] = Key::NP_SUB; mapKeys[VK_DECIMAL] = Key::NP_DECIMAL; - - return olc_hWnd; - } - - bool PixelGameEngine::olc_OpenGLCreate() - { - // Create Device Context - glDeviceContext = GetDC(olc_hWnd); - PIXELFORMATDESCRIPTOR pfd = - { - sizeof(PIXELFORMATDESCRIPTOR), 1, - PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, - PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - PFD_MAIN_PLANE, 0, 0, 0, 0 - }; - - int pf = 0; - if (!(pf = ChoosePixelFormat(glDeviceContext, &pfd))) return false; - SetPixelFormat(glDeviceContext, pf, &pfd); - - if (!(glRenderContext = wglCreateContext(glDeviceContext))) return false; - wglMakeCurrent(glDeviceContext, glRenderContext); - - glViewport(nViewX, nViewY, nViewW, nViewH); - - // Remove Frame cap - wglSwapInterval = (wglSwapInterval_t*)wglGetProcAddress("wglSwapIntervalEXT"); - if (wglSwapInterval) wglSwapInterval(0); - return true; - } - - // Windows Event Handler - LRESULT CALLBACK PixelGameEngine::olc_WindowEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) - { - static PixelGameEngine *sge; - switch (uMsg) - { - case WM_CREATE: sge = (PixelGameEngine*)((LPCREATESTRUCT)lParam)->lpCreateParams; return 0; - case WM_MOUSEMOVE: - { - uint16_t x = lParam & 0xFFFF; // Thanks @ForAbby (Discord) - uint16_t y = (lParam >> 16) & 0xFFFF; - int16_t ix = *(int16_t*)&x; - int16_t iy = *(int16_t*)&y; - sge->olc_UpdateMouse(ix, iy); - return 0; - } - case WM_SIZE: - { - sge->olc_UpdateWindowSize(lParam & 0xFFFF, (lParam >> 16) & 0xFFFF); - return 0; - } - case WM_MOUSEWHEEL: - { - sge->olc_UpdateMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam)); - return 0; - } - case WM_MOUSELEAVE: sge->bHasMouseFocus = false; return 0; - case WM_SETFOCUS: sge->bHasInputFocus = true; return 0; - case WM_KILLFOCUS: sge->bHasInputFocus = false; return 0; - case WM_KEYDOWN: sge->pKeyNewState[mapKeys[wParam]] = true; return 0; - case WM_KEYUP: sge->pKeyNewState[mapKeys[wParam]] = false; return 0; - case WM_LBUTTONDOWN:sge->pMouseNewState[0] = true; return 0; - case WM_LBUTTONUP: sge->pMouseNewState[0] = false; return 0; - case WM_RBUTTONDOWN:sge->pMouseNewState[1] = true; return 0; - case WM_RBUTTONUP: sge->pMouseNewState[1] = false; return 0; - case WM_MBUTTONDOWN:sge->pMouseNewState[2] = true; return 0; - case WM_MBUTTONUP: sge->pMouseNewState[2] = false; return 0; - case WM_CLOSE: bAtomActive = false; return 0; - case WM_DESTROY: PostQuitMessage(0); return 0; - } - return DefWindowProc(hWnd, uMsg, wParam, lParam); - } -#else - // Do the Linux stuff! - Display* PixelGameEngine::olc_WindowCreate() - { - XInitThreads(); - - // Grab the deafult display and window - olc_Display = XOpenDisplay(NULL); - olc_WindowRoot = DefaultRootWindow(olc_Display); - - // Based on the display capabilities, configure the appearance of the window - GLint olc_GLAttribs[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; - olc_VisualInfo = glXChooseVisual(olc_Display, 0, olc_GLAttribs); - olc_ColourMap = XCreateColormap(olc_Display, olc_WindowRoot, olc_VisualInfo->visual, AllocNone); - olc_SetWindowAttribs.colormap = olc_ColourMap; - - // Register which events we are interested in receiving - olc_SetWindowAttribs.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask | StructureNotifyMask; - - // Create the window - olc_Window = XCreateWindow(olc_Display, olc_WindowRoot, 30, 30, nScreenWidth * nPixelWidth, nScreenHeight * nPixelHeight, 0, olc_VisualInfo->depth, InputOutput, olc_VisualInfo->visual, CWColormap | CWEventMask, &olc_SetWindowAttribs); - - Atom wmDelete = XInternAtom(olc_Display, "WM_DELETE_WINDOW", true); - XSetWMProtocols(olc_Display, olc_Window, &wmDelete, 1); - - XMapWindow(olc_Display, olc_Window); - XStoreName(olc_Display, olc_Window, "OneLoneCoder.com - Pixel Game Engine"); - - if (bFullScreen) // Thanks DragonEye, again :D - { - Atom wm_state; - Atom fullscreen; - wm_state = XInternAtom(olc_Display, "_NET_WM_STATE", False); - fullscreen = XInternAtom(olc_Display, "_NET_WM_STATE_FULLSCREEN", False); - XEvent xev{ 0 }; - xev.type = ClientMessage; - xev.xclient.window = olc_Window; - xev.xclient.message_type = wm_state; - xev.xclient.format = 32; - xev.xclient.data.l[0] = (bFullScreen ? 1 : 0); // the action (0: off, 1: on, 2: toggle) - xev.xclient.data.l[1] = fullscreen; // first property to alter - xev.xclient.data.l[2] = 0; // second property to alter - xev.xclient.data.l[3] = 0; // source indication - XMapWindow(olc_Display, olc_Window); - XSendEvent(olc_Display, DefaultRootWindow(olc_Display), False, - SubstructureRedirectMask | SubstructureNotifyMask, &xev); - XFlush(olc_Display); - XWindowAttributes gwa; - XGetWindowAttributes(olc_Display, olc_Window, &gwa); - nWindowWidth = gwa.width; - nWindowHeight = gwa.height; - olc_UpdateViewport(); - } - - // Create Keyboard Mapping - mapKeys[0x00] = Key::NONE; - mapKeys[0x61] = Key::A; mapKeys[0x62] = Key::B; mapKeys[0x63] = Key::C; mapKeys[0x64] = Key::D; mapKeys[0x65] = Key::E; - mapKeys[0x66] = Key::F; mapKeys[0x67] = Key::G; mapKeys[0x68] = Key::H; mapKeys[0x69] = Key::I; mapKeys[0x6A] = Key::J; - mapKeys[0x6B] = Key::K; mapKeys[0x6C] = Key::L; mapKeys[0x6D] = Key::M; mapKeys[0x6E] = Key::N; mapKeys[0x6F] = Key::O; - mapKeys[0x70] = Key::P; mapKeys[0x71] = Key::Q; mapKeys[0x72] = Key::R; mapKeys[0x73] = Key::S; mapKeys[0x74] = Key::T; - mapKeys[0x75] = Key::U; mapKeys[0x76] = Key::V; mapKeys[0x77] = Key::W; mapKeys[0x78] = Key::X; mapKeys[0x79] = Key::Y; - mapKeys[0x7A] = Key::Z; - - mapKeys[XK_F1] = Key::F1; mapKeys[XK_F2] = Key::F2; mapKeys[XK_F3] = Key::F3; mapKeys[XK_F4] = Key::F4; - mapKeys[XK_F5] = Key::F5; mapKeys[XK_F6] = Key::F6; mapKeys[XK_F7] = Key::F7; mapKeys[XK_F8] = Key::F8; - mapKeys[XK_F9] = Key::F9; mapKeys[XK_F10] = Key::F10; mapKeys[XK_F11] = Key::F11; mapKeys[XK_F12] = Key::F12; - - mapKeys[XK_Down] = Key::DOWN; mapKeys[XK_Left] = Key::LEFT; mapKeys[XK_Right] = Key::RIGHT; mapKeys[XK_Up] = Key::UP; - mapKeys[XK_KP_Enter] = Key::ENTER; mapKeys[XK_Return] = Key::ENTER; - - mapKeys[XK_BackSpace] = Key::BACK; mapKeys[XK_Escape] = Key::ESCAPE; mapKeys[XK_Linefeed] = Key::ENTER; mapKeys[XK_Pause] = Key::PAUSE; - mapKeys[XK_Scroll_Lock] = Key::SCROLL; mapKeys[XK_Tab] = Key::TAB; mapKeys[XK_Delete] = Key::DEL; mapKeys[XK_Home] = Key::HOME; - mapKeys[XK_End] = Key::END; mapKeys[XK_Page_Up] = Key::PGUP; mapKeys[XK_Page_Down] = Key::PGDN; mapKeys[XK_Insert] = Key::INS; - mapKeys[XK_Shift_L] = Key::SHIFT; mapKeys[XK_Shift_R] = Key::SHIFT; mapKeys[XK_Control_L] = Key::CTRL; mapKeys[XK_Control_R] = Key::CTRL; - mapKeys[XK_space] = Key::SPACE; - - mapKeys[XK_0] = Key::K0; mapKeys[XK_1] = Key::K1; mapKeys[XK_2] = Key::K2; mapKeys[XK_3] = Key::K3; mapKeys[XK_4] = Key::K4; - mapKeys[XK_5] = Key::K5; mapKeys[XK_6] = Key::K6; mapKeys[XK_7] = Key::K7; mapKeys[XK_8] = Key::K8; mapKeys[XK_9] = Key::K9; - - mapKeys[XK_KP_0] = Key::NP0; mapKeys[XK_KP_1] = Key::NP1; mapKeys[XK_KP_2] = Key::NP2; mapKeys[XK_KP_3] = Key::NP3; mapKeys[XK_KP_4] = Key::NP4; - mapKeys[XK_KP_5] = Key::NP5; mapKeys[XK_KP_6] = Key::NP6; mapKeys[XK_KP_7] = Key::NP7; mapKeys[XK_KP_8] = Key::NP8; mapKeys[XK_KP_9] = Key::NP9; - mapKeys[XK_KP_Multiply] = Key::NP_MUL; mapKeys[XK_KP_Add] = Key::NP_ADD; mapKeys[XK_KP_Divide] = Key::NP_DIV; mapKeys[XK_KP_Subtract] = Key::NP_SUB; mapKeys[XK_KP_Decimal] = Key::NP_DECIMAL; - - return olc_Display; - } - - bool PixelGameEngine::olc_OpenGLCreate() - { - glDeviceContext = glXCreateContext(olc_Display, olc_VisualInfo, nullptr, GL_TRUE); - glXMakeCurrent(olc_Display, olc_Window, glDeviceContext); - - XWindowAttributes gwa; - XGetWindowAttributes(olc_Display, olc_Window, &gwa); - glViewport(0, 0, gwa.width, gwa.height); - - glSwapIntervalEXT = nullptr; - glSwapIntervalEXT = (glSwapInterval_t*)glXGetProcAddress((unsigned char*)"glXSwapIntervalEXT"); - if (glSwapIntervalEXT) - glSwapIntervalEXT(olc_Display, olc_Window, 0); - else - { - printf("NOTE: Could not disable VSYNC, glXSwapIntervalEXT() was not found!\n"); - printf(" Don't worry though, things will still work, it's just the\n"); - printf(" frame rate will be capped to your monitors refresh rate - javidx9\n"); - } - - return true; - } - -#endif - - // Need a couple of statics as these are singleton instances - // read from multiple locations - std::atomic PixelGameEngine::bAtomActive{ false }; - std::map PixelGameEngine::mapKeys; - olc::PixelGameEngine* olc::PGEX::pge = nullptr; -#ifdef OLC_DBG_OVERDRAW - int olc::Sprite::nOverdrawCount = 0; -#endif - //============================================================= -} - -#endif diff --git a/Videos/blocks.png b/Videos/blocks.png deleted file mode 100644 index b108a2d..0000000 Binary files a/Videos/blocks.png and /dev/null differ diff --git a/Videos/car_top1.png b/Videos/car_top1.png deleted file mode 100644 index 15ceb1d..0000000 Binary files a/Videos/car_top1.png and /dev/null differ diff --git a/Videos/isometric_demo.png b/Videos/isometric_demo.png deleted file mode 100644 index 797ef4c..0000000 Binary files a/Videos/isometric_demo.png and /dev/null differ diff --git a/Videos/light_cast.png b/Videos/light_cast.png deleted file mode 100644 index 4ac2ce8..0000000 Binary files a/Videos/light_cast.png and /dev/null differ diff --git a/Videos/logo_long.png b/Videos/logo_long.png deleted file mode 100644 index e4ca5b3..0000000 Binary files a/Videos/logo_long.png and /dev/null differ diff --git a/Videos/mountains.obj b/Videos/mountains.obj deleted file mode 100644 index 6bb8954..0000000 --- a/Videos/mountains.obj +++ /dev/null @@ -1,7302 +0,0 @@ -# Blender v2.79 (sub 0) OBJ File: '' -# www.blender.org -v -43.592037 7.219297 -21.717901 -v -41.717117 7.750917 -20.780441 -v -42.342102 5.160596 -23.592819 -v -44.217018 9.241996 -21.092922 -v -72.028442 5.974188 -68.903564 -v -73.278381 7.996269 -68.278580 -v -71.090981 6.918389 -66.091179 -v -72.340919 4.623488 -72.965897 -v -74.528343 6.804868 -72.028442 -v -68.591080 4.523389 -68.591080 -v -68.903564 3.463808 -72.965897 -v -73.590881 7.987109 -67.028641 -v -4.218580 10.193540 -2.343662 -v -3.906100 9.939019 -3.281122 -v -6.406000 8.828799 -2.968642 -v -4.843560 6.084661 -0.156241 -v -2.343660 12.701460 -2.656142 -v -6.093520 9.363459 -5.156042 -v -7.343460 10.057420 -2.343662 -v 8.905900 0.877183 15.780640 -v 13.905701 1.795742 12.655760 -v 7.655960 1.314801 9.530880 -v 12.343260 1.345923 21.405420 -v 17.343081 2.610563 16.093121 -v -9.530880 1.044402 11.405801 -v -11.718301 1.406962 12.968240 -v -6.093520 0.700782 13.280740 -v -7.343460 1.823221 7.030980 -v -12.030781 3.174521 6.718480 -v -13.593220 1.449682 8.905900 -v -17.968040 0.566503 15.468140 -v -5.156040 1.385601 8.593420 -v 33.592442 8.749445 33.904919 -v 34.842381 8.469306 35.467361 -v 35.154881 7.396305 32.967461 -v 32.029999 11.430706 32.654980 -v 31.717520 11.993446 35.779858 -v -60.778881 2.869342 10.155860 -v -62.028816 4.524002 9.530879 -v -65.153702 2.476283 16.405600 -v -57.966480 1.941622 11.405801 -v -60.466381 3.129961 9.218379 -v -63.903763 6.527781 6.405999 -v -55.779079 14.997571 -49.841805 -v -54.841599 12.433493 -48.904343 -v -55.154099 11.735271 -51.716740 -v -57.341499 16.631474 -47.966885 -v 17.030581 18.012098 -16.093124 -v 16.405600 18.414919 -16.405603 -v 16.093121 15.788599 -14.218204 -v 18.593021 21.878038 -15.468143 -v 17.968040 18.273939 -16.718103 -v 19.530479 22.064796 -17.655563 -v 17.030581 17.594618 -17.030584 -v 18.593021 20.779415 -17.655563 -v 17.343081 18.992317 -17.968044 -v 18.905521 20.914297 -14.843184 -v 20.155460 25.721397 -15.780643 -v 19.530479 6.872031 70.153519 -v 16.405600 6.930011 68.278580 -v 16.405600 5.008032 73.278381 -v 20.780439 5.459071 66.091179 -v -66.403664 17.698992 64.841217 -v -65.466202 19.049089 64.216240 -v -67.341118 15.830710 62.966274 -v -67.653595 18.986233 65.778679 -v -67.028641 19.922493 67.028641 -v -64.216240 17.682510 65.153702 -v -64.528740 13.321570 62.341312 -v -68.278580 18.541889 63.278774 -v -65.778679 17.654449 62.341312 -v -62.028816 15.018351 65.466202 -v -61.091362 12.651411 62.966274 -v 35.467361 7.717345 30.467558 -v 38.904739 5.250325 30.467560 -v 34.529900 10.136765 28.592638 -v 33.279961 10.330864 30.155077 -v 12.030781 18.377075 -18.905525 -v 12.655760 22.685535 -18.905525 -v 12.655760 24.728355 -19.842983 -v 11.405801 16.412376 -18.280542 -v 12.968240 17.966316 -18.280544 -v 12.655760 15.385757 -16.405602 -v 14.530680 18.734735 -17.968044 -v 12.343260 24.668556 -20.155464 -v 59.216442 8.501028 -70.153519 -v 58.278980 10.758088 -68.903564 -v 60.466381 10.145909 -68.591080 -v 59.216442 7.038008 -72.653419 -v 56.716541 9.945108 -71.090981 -v 20.467960 6.322693 -36.717319 -v 21.092920 8.413754 -37.342300 -v 20.155460 6.730414 -39.217220 -v 21.405420 5.674515 -33.279961 -v 23.280338 7.782654 -35.779861 -v 18.905521 5.764234 -39.217220 -v 22.655361 9.045453 -38.279758 -v -17.030581 13.816570 60.778877 -v -18.593021 12.312671 62.966274 -v -16.093121 15.372951 62.653797 -v -18.593021 12.164350 59.841415 -v 66.716141 8.482108 -75.465797 -v 67.028641 8.554729 -72.028442 -v 68.903564 9.040567 -73.903358 -v 65.466202 6.336107 -76.090782 -v 63.591263 6.982468 -72.028442 -v 9.218380 7.417672 75.153320 -v 10.468340 4.138272 77.028244 -v 11.718301 5.040372 72.340919 -v 8.280920 6.615072 73.903358 -v 8.280920 9.280473 75.465797 -v 39.842201 9.461128 52.966682 -v 40.779663 12.272389 54.841595 -v 42.967079 7.984689 52.341698 -v 38.592239 11.705989 53.279182 -v -78.590683 15.604871 -50.466785 -v -78.590683 15.278332 -52.654202 -v -79.528137 16.494152 -49.216824 -v -77.028244 17.339493 -50.466785 -v -41.717117 10.386397 -15.155662 -v -42.029602 13.994178 -12.343262 -v -39.217220 9.993337 -14.843182 -v -41.717117 7.994437 -18.280542 -v -45.779461 9.309137 -17.968042 -v 42.654579 10.520681 9.218378 -v 43.279564 13.113441 7.968438 -v 41.404640 13.817182 7.655957 -v 42.654579 7.778382 11.718300 -v 45.154480 6.359322 9.843359 -v 43.904537 11.718181 7.343458 -v 41.092140 14.035683 8.905898 -v 40.779663 11.514942 11.093318 -v -78.903160 9.183393 -42.029602 -v -74.215858 11.482574 -43.279564 -v -77.653221 11.314133 -45.154480 -v -79.840637 8.479673 -39.842201 -v -73.903358 10.220373 -38.279758 -v 1.718680 4.506929 56.404041 -v 2.968640 4.825529 54.216644 -v -1.406200 4.593589 56.091560 -v 0.156240 6.091990 59.841419 -v 3.906100 4.851170 59.528919 -v -61.091362 11.665696 -18.593023 -v -62.653801 11.849397 -17.343082 -v -59.528919 13.122598 -17.030582 -v -63.278778 10.545097 -20.155462 -v -20.467960 2.636806 40.154682 -v -18.905521 3.925267 40.467182 -v -18.280540 1.597386 34.842381 -v -20.155460 4.284747 44.217018 -v -16.718100 3.454687 39.842201 -v -17.030581 5.504227 43.592037 -v 77.028244 9.475764 27.655159 -v 79.215660 8.433905 30.155077 -v 79.528137 12.050824 25.780237 -v 75.465797 7.164384 27.030199 -v 77.028244 8.752504 30.467558 -v -21.092920 12.119189 56.404037 -v -22.655361 15.489529 55.466576 -v -22.655361 14.562410 56.716537 -v -21.717899 9.918268 52.341698 -v -22.967861 12.523849 54.216640 -v -72.028442 12.550699 -1.406202 -v -71.715958 16.973280 -2.968643 -v -73.278381 15.647599 -3.281123 -v -72.028442 9.946340 0.468738 -v -69.216042 11.165200 -0.156242 -v -40.467182 0.292464 24.530300 -v -40.154682 0.489005 30.780039 -v -32.654980 0.408424 26.717701 -v -49.841801 0.393784 24.530300 -v -46.091961 0.575665 32.342480 -v 2.031180 3.637149 -66.403664 -v 4.218580 5.840509 -67.028641 -v 3.906100 5.487729 -68.903564 -v 1.406200 3.736029 -65.466202 -v 4.843560 3.941109 -66.091179 -v -0.156240 2.641069 -65.778679 -v -4.218580 2.169889 -66.403664 -v 0.468740 2.264489 -63.903763 -v 2.343660 1.220171 -55.779079 -v 4.843560 2.782670 -63.591263 -v 0.781220 3.949649 -69.216042 -v -3.906100 3.189168 -69.528542 -v -78.590683 11.596707 -74.215858 -v -78.590683 10.324747 -73.903358 -v -76.403259 9.301188 -73.590881 -v -78.903160 6.604668 -75.465797 -v -78.903160 11.970248 -74.215858 -v -25.780239 17.374910 58.591457 -v -26.405220 13.718309 60.466377 -v -22.967861 14.039350 61.403858 -v -26.717701 17.066669 58.278976 -v -23.592819 15.753809 57.966476 -v -21.717899 15.050089 58.278976 -v 17.343081 5.401688 45.779461 -v 15.468140 5.347367 46.404438 -v 17.968040 5.174648 48.591862 -v 21.717899 7.566607 44.217018 -v 18.280540 5.947347 42.029602 -v 15.468140 4.885347 42.654579 -v 15.155660 5.759367 40.154682 -v 11.718301 3.733007 47.029419 -v 12.030781 3.998509 55.466579 -v 11.093320 3.336887 42.029602 -v 5.781020 2.985328 47.966881 -v -7.655960 0.360194 -39.217220 -v -7.343460 0.712375 -33.904919 -v -0.156240 0.479214 -39.842201 -v -8.593420 0.477992 -50.779263 -v -20.467960 0.496913 -42.342102 -v -7.030980 1.775595 -27.655161 -v -7.343460 3.554776 -22.655361 -v -2.031180 2.564776 -26.405220 -v -15.780640 0.896095 -31.405020 -v 0.468740 1.364835 -31.092539 -v -15.155660 0.516454 -36.092342 -v 28.592640 20.960678 -5.781024 -v 27.655161 19.381720 -5.156044 -v 28.280140 19.276741 -3.906103 -v 28.280140 24.053938 -7.343463 -v 27.655161 27.377279 -7.030984 -v 57.966480 15.252089 -67.966095 -v 58.278980 12.750270 -66.716141 -v 59.841419 14.639909 -67.653595 -v 57.029018 17.440788 -67.966095 -v -75.153320 9.173630 -66.716141 -v -74.840820 9.166908 -67.966095 -v -76.715759 12.365149 -67.341118 -v -74.528343 10.196569 -64.841217 -v -75.153320 9.649710 -63.591263 -v -77.340744 10.533489 -65.466202 -v -76.715759 12.352930 -60.153904 -v -72.965897 10.417510 -58.591461 -v -70.778481 7.550710 -62.966278 -v 27.655161 17.446924 25.780237 -v 26.092739 12.785084 24.842777 -v 26.405220 13.947186 28.280138 -v 28.592640 23.253765 26.092735 -v 28.905121 26.212124 24.842775 -v 29.217621 24.425644 27.030197 -v 30.155079 31.552063 25.467754 -v -64.216240 18.429579 -13.905704 -v -65.153702 13.386257 -15.780642 -v -66.716141 16.926899 -14.843183 -v -63.591263 18.576658 -12.968243 -v -62.028816 14.967677 -14.843183 -v -62.966278 20.025019 -11.093323 -v -60.153900 17.860718 -11.718304 -v 32.654980 11.511279 -7.030982 -v 35.154881 8.746398 -8.905901 -v 32.029999 11.583899 -9.218382 -v 31.092539 16.179821 -5.468543 -v 33.592442 11.193899 -3.593602 -v 30.780039 15.104999 -4.531083 -v 29.842579 17.533579 -6.406003 -v 44.529499 14.671669 61.091358 -v 43.592037 14.399451 62.653797 -v 45.154480 17.404810 62.966274 -v 42.654579 14.303009 60.153896 -v 77.028244 9.135191 66.716141 -v 76.403259 10.243591 67.653595 -v 79.528137 8.205631 68.278580 -v 77.965698 10.110531 65.153702 -v 74.528343 8.087231 66.716141 -v 43.279564 5.751409 -68.903564 -v 43.592037 7.511029 -66.716141 -v 48.279362 5.408389 -68.903564 -v 42.342102 4.276808 -74.528343 -v 39.842201 6.200009 -67.966095 -v 45.779461 8.067670 -64.216240 -v 42.029602 9.137010 -62.028816 -v 50.779263 15.336312 -51.091766 -v 51.716736 14.375011 -51.716740 -v 49.529320 17.740473 -52.654202 -v 52.654198 10.756872 -48.904339 -v 53.591660 11.793250 -63.903767 -v 53.904144 14.259049 -64.528740 -v 52.341698 9.935949 -64.216240 -v 53.904144 13.385029 -62.653805 -v 55.154099 18.601070 -63.591267 -v 8.280920 1.303805 27.967661 -v 10.155860 2.186985 30.467560 -v 14.530680 3.302705 28.280140 -v 5.156040 0.692844 23.905319 -v 5.781020 1.267185 29.842579 -v -59.216442 16.986692 -49.216824 -v -58.591461 16.724873 -51.716740 -v -61.403862 14.082671 -51.716740 -v -59.216442 20.266113 -48.591866 -v -57.966480 18.179932 -48.904343 -v -61.091362 16.091932 -49.216824 -v -59.528919 20.107412 -47.341904 -v -57.341499 18.654793 -50.466785 -v -39.217220 9.685129 58.903961 -v -37.654778 9.489809 56.091560 -v -40.154682 7.838809 55.779079 -v -39.842201 11.240891 60.153900 -v -36.404819 11.304990 60.778881 -v -39.842201 12.194271 62.341312 -v -40.467182 15.583530 64.841217 -v -37.654778 15.006751 63.903759 -v -42.967079 11.537530 62.341316 -v -34.842381 9.706490 57.341499 -v -41.717117 13.167771 64.528740 -v -67.028641 7.408514 -31.092541 -v -64.528740 7.367615 -28.592642 -v -64.216240 8.447315 -32.029999 -v -71.090981 7.398735 -31.092541 -v -70.153519 7.038636 -25.780241 -v -46.404438 10.272257 -20.155462 -v -47.341900 8.581597 -20.467962 -v -48.279362 12.420697 -19.218002 -v 19.218000 6.339173 -44.217018 -v 19.530479 8.181813 -42.967079 -v 21.405420 6.087713 -44.841999 -v 17.343081 4.892653 -43.592037 -v 23.905319 9.056451 -56.716541 -v 25.155260 7.972471 -53.904144 -v 27.030201 11.294590 -55.779079 -v 20.467960 5.849671 -56.716541 -v 20.467960 5.612251 -53.904144 -v 17.655560 4.949410 -58.278980 -v 18.280540 4.708931 -55.154099 -v 76.403259 8.015810 59.216442 -v 75.465797 8.505310 57.653999 -v 71.403458 5.561609 59.528919 -v 79.215660 9.561211 62.966278 -v 79.215660 9.929270 57.653999 -v -23.592819 17.117950 55.466576 -v 13.905701 4.732747 40.154682 -v 20.467960 7.685006 39.529701 -v 17.343081 6.783526 37.654778 -v 18.905521 9.513605 35.779861 -v 15.468140 7.235186 35.154881 -v 20.780439 10.828906 36.717319 -v -42.654579 7.238830 -61.403862 -v -42.654579 9.610031 -60.153900 -v -41.404640 6.924490 -59.841419 -v -44.529499 5.880190 -64.216240 -v -44.217018 9.165091 -60.153900 -v -42.654579 10.426071 -59.528919 -v -41.717117 8.107350 -58.903961 -v -42.342102 4.417190 -65.153702 -v -38.592239 5.133730 -59.841419 -v -37.342300 12.326710 66.716141 -v -35.779861 14.638090 66.716141 -v -36.092342 13.681690 65.778679 -v -37.967258 9.736391 68.903564 -v -34.842381 11.491152 68.903564 -v -72.653419 10.199653 73.278381 -v -74.528343 12.541552 72.028442 -v -73.278381 9.138852 74.215858 -v -71.403458 13.668872 72.340919 -v 32.029999 8.912393 -47.654400 -v 32.967461 7.559873 -42.967079 -v 37.654778 10.871613 -47.341900 -v 29.530102 7.300473 -44.841999 -v -15.780640 12.874189 59.841415 -v -16.718100 11.807909 59.216438 -v -14.218201 10.387630 60.778881 -v -14.843180 9.004589 57.966480 -v 22.655361 8.949630 -66.091179 -v 22.655361 9.046069 -62.653801 -v 26.092739 8.988090 -64.216240 -v 22.342880 9.861488 -68.903564 -v 20.155460 8.854409 -66.716141 -v -60.466381 20.878897 -8.905904 -v -60.153900 23.482637 -10.155864 -v -60.778881 22.566519 -9.843364 -v -60.466381 23.118877 -8.280924 -v -58.278980 19.826059 -8.280923 -v 8.280920 3.565761 5.156040 -v 7.655960 2.550741 6.718480 -v 12.968240 3.972241 4.843559 -v 5.781020 4.899981 2.656139 -v 17.343081 5.818550 -60.466381 -v 17.030581 8.568170 -62.341316 -v 14.530680 5.705009 -63.278778 -v 18.593021 7.872970 -61.716343 -v 19.218000 11.044950 -62.653801 -v 11.405801 3.407050 -61.403862 -v -14.530680 12.717331 70.778481 -v -13.280740 13.316092 71.715958 -v -12.030781 10.005551 68.903564 -v -16.405600 14.721711 69.528542 -v -17.030581 13.315471 71.403458 -v 27.655161 11.035188 -78.590683 -v 27.342680 12.077047 -76.403259 -v 30.467560 9.257848 -75.778297 -v 22.967861 17.020267 -79.528137 -v 25.155260 14.803488 -76.715759 -v -31.092539 5.502989 -69.216042 -v -31.405020 5.808168 -71.715958 -v -33.279961 4.650329 -70.465996 -v -29.217621 4.039369 -67.028641 -v -27.342680 5.737969 -68.278580 -v 29.530102 8.375294 -41.404640 -v 30.780039 7.457933 -41.092140 -v 27.967661 7.137513 -40.467182 -v 29.842579 9.171793 -40.154682 -v 25.155260 6.734073 -40.467182 -v 27.967661 7.211354 -38.592239 -v 18.593021 6.376411 -52.029221 -v 11.093320 2.440271 -56.404041 -v 20.155460 5.877132 -50.154301 -v 16.405600 4.265811 -51.716736 -v 18.905521 6.899472 -49.529320 -v 22.967861 6.989812 -51.091763 -v 20.780439 5.742252 -47.966881 -v -31.405020 10.322928 50.466782 -v -30.467560 11.002249 51.716736 -v -30.780039 7.970048 49.216820 -v -33.279961 9.120548 52.654198 -v -53.904144 5.948573 77.965698 -v -56.716541 9.657652 76.715759 -v -57.966480 7.762533 77.653221 -v -51.716736 4.699792 77.340744 -v -56.091560 8.193433 75.465797 -v -58.591461 9.911572 75.153320 -v -57.341499 9.780951 72.653419 -v -60.153900 12.866252 75.465797 -v -60.153900 10.602472 77.028244 -v -60.153900 8.387513 79.215660 -v -51.091763 5.747152 74.215858 -v -54.216644 10.115412 71.090981 -v -60.153900 9.155952 77.965698 -v -77.965698 9.763836 -24.530302 -v -73.903358 8.284976 -23.592821 -v -77.653221 9.142515 -27.655163 -v -79.528137 11.398956 -23.280340 -v -77.653221 12.153357 -20.467962 -v 28.592640 13.139676 -16.405602 -v 29.217621 16.149918 -13.905704 -v 31.405020 10.865519 -14.218203 -v 27.967661 12.766137 -17.968042 -v 26.405220 16.767597 -16.093122 -v 27.030201 6.215275 -34.217419 -v 28.905121 7.020315 -35.467361 -v 25.467760 8.787894 -36.404819 -v 28.280140 5.820994 -31.405020 -v 44.529499 13.845850 -59.841423 -v 45.154480 12.094150 -62.028820 -v 45.779461 12.773471 -60.153904 -v -0.156240 6.471608 -72.653419 -v 18.905521 8.344186 34.217419 -v 19.842979 11.142026 34.529900 -v 20.155460 9.050965 33.592442 -v 16.093121 6.467366 33.904919 -v 20.780439 13.727446 35.467358 -v 18.593021 6.283646 31.717518 -v 77.340744 8.082350 57.341499 -v 76.403259 7.236409 55.154099 -v 4.218580 13.917877 -16.405602 -v 3.593600 15.769677 -17.968042 -v 2.343660 15.466336 -15.468143 -v 5.468540 13.578518 -14.218203 -v 5.781020 13.220237 -17.655561 -v 4.843560 4.939672 68.903564 -v 9.218380 4.902431 70.778481 -v 11.093320 4.691251 66.091179 -v 3.281120 5.732512 71.715958 -v 79.215660 8.988091 -60.153900 -v 79.215660 13.883070 -62.966282 -v 78.590683 9.967690 -60.778881 -v 79.528137 5.850291 -56.404041 -v 79.528137 15.219130 -66.091179 -v 77.340744 8.867850 -59.528919 -v 78.278198 15.047629 -62.966282 -v -2.343660 12.951698 -3.593602 -v -2.656140 13.770780 -6.093523 -v 28.280140 24.132059 -10.780824 -v 27.655161 21.652218 -10.468344 -v 28.280140 26.330538 -10.155864 -v 28.592640 24.611177 -12.343264 -v 27.655161 20.483997 -12.655763 -v -10.780820 12.827191 75.778297 -v -12.655760 15.020793 76.090782 -v -11.093320 12.819873 76.715759 -v -11.718301 12.221732 73.278381 -v 48.904339 3.875199 -3.593601 -v 41.404640 6.200019 -2.968641 -v 42.342102 6.423400 0.468739 -v 48.904339 4.830998 -7.655961 -v 41.717117 6.531439 -6.718481 -v 51.091763 5.044638 -7.968441 -v -46.716919 8.111629 -64.216240 -v -45.466980 5.912529 -64.841217 -v -48.591862 7.343809 -66.403664 -v -47.654400 6.919610 -63.278778 -v -46.091961 8.434489 -63.591263 -v -51.091763 6.134709 -64.216240 -v -49.216820 6.706590 -60.466381 -v -72.340919 11.110874 -37.967258 -v -69.841019 10.758713 -38.279758 -v -71.403458 14.175433 -40.467186 -v -71.403458 8.444274 -33.904919 -v 79.215660 7.639845 33.592442 -v 78.590683 7.091745 35.154881 -v 79.528137 9.898126 36.717319 -v 77.340744 6.298285 33.279961 -v 68.903564 2.612993 -44.217018 -v 67.966095 4.443432 -47.966881 -v 65.153702 3.122633 -44.529499 -v 70.465996 2.064293 -41.092140 -v 74.528343 1.655973 -42.342102 -v 65.153702 4.752872 -48.279362 -v 62.028816 6.785952 -49.529320 -v 67.028641 5.389472 -50.154301 -v 64.528740 10.513351 -56.404041 -v 70.778481 5.246032 -52.341698 -v 67.028641 1.785373 -40.467182 -v -69.528542 9.371400 2.343658 -v -72.965897 9.048521 2.968639 -v -77.028244 8.913640 -0.781221 -v -76.090782 11.988560 -2.031182 -v -76.715759 13.576078 -4.531083 -v -76.715759 7.440240 1.406199 -v -75.465797 9.231620 -0.468742 -v -79.840637 8.336860 0.156239 -v -74.840820 16.898821 -3.281123 -v -41.717117 14.829740 -8.593423 -v -41.092140 16.416037 -9.530883 -v -41.717117 15.814837 -10.780823 -v -42.654579 15.757460 -7.030982 -v -38.904739 14.153480 -7.968442 -v -37.967258 13.473538 -9.530882 -v 42.967079 7.319398 -10.468341 -v 43.279564 9.123578 -11.718303 -v 40.779663 7.877858 -11.718302 -v 47.341900 5.199658 -10.780821 -v 44.529499 7.147278 -12.343261 -v 42.029602 9.410470 66.403664 -v 43.279564 12.760050 65.466202 -v 41.717117 13.776290 62.653797 -v 45.466980 9.069892 69.841019 -v 45.779461 10.738592 67.341118 -v 45.466980 10.387032 70.778481 -v 46.404438 9.646671 71.090981 -v 40.154682 7.488471 67.341118 -v 44.841999 7.695391 71.403458 -v 43.279564 5.393152 73.278381 -v 47.341900 6.215912 74.215858 -v -75.778297 12.500029 -69.216042 -v -1.718680 18.760378 -7.343462 -v -1.718680 22.921120 -7.968444 -v -3.281120 16.817038 -8.593423 -v -1.406200 15.136739 -5.781023 -v -0.156240 15.706800 -6.718482 -v -52.966682 24.631317 -13.905704 -v -53.279182 28.569298 -13.280745 -v -52.341698 25.590178 -13.280744 -v -53.904144 18.328857 -14.843183 -v -71.090981 19.677120 -5.468544 -v -71.715958 22.911980 -4.531084 -v -71.403458 19.544060 -3.906103 -v -70.465996 19.414679 -6.718483 -v -71.715958 20.588980 -5.781024 -v -69.528542 20.386959 -6.718483 -v -68.903564 17.718519 -7.030983 -v -69.528542 22.268057 -7.343463 -v -72.340919 19.006958 -7.343462 -v 55.466579 10.149590 65.778679 -v 56.404041 12.299251 66.716141 -v 57.341499 10.129451 66.091179 -v 53.591660 11.823171 67.653595 -v 33.279961 12.420085 28.280138 -v 32.967461 16.145643 26.405218 -v -21.717899 6.258628 46.404438 -v -26.092739 5.686728 46.404438 -v -24.217800 7.513508 49.216820 -v -26.717701 3.425387 43.279564 -v 25.780239 16.951298 -16.718102 -v 26.405220 17.321177 -17.655561 -v 24.530300 20.330196 -18.905525 -v 24.842779 19.374998 -15.155663 -v -24.217800 4.877399 -2.968641 -v -22.967861 3.377780 0.781219 -v -19.530479 5.251539 -4.531081 -v -25.467760 7.340159 -6.093522 -v -29.217621 5.204539 -3.593601 -v -24.217800 7.005679 -7.030981 -v -21.092920 9.231618 -10.468342 -v -26.092739 8.569398 -8.905901 -v -28.905121 7.365779 -6.406002 -v -73.590881 18.239140 -4.531083 -v -75.465797 14.855979 -3.593602 -v -77.028244 11.596708 -72.965897 -v -78.590683 10.847809 -70.153519 -v -36.717319 4.570387 -78.278198 -v -33.904919 4.482487 -79.528137 -v -40.154682 5.369927 -79.840637 -v -34.217419 5.169127 -76.403259 -v -42.967079 3.327708 -72.028442 -v -41.404640 3.573688 -76.403259 -v -44.841999 3.338087 -77.653221 -v -38.592239 3.872149 -67.341118 -v 17.030581 9.968909 -65.778679 -v 16.718100 9.605748 -67.653595 -v 17.343081 12.895530 -63.591267 -v 20.467960 8.879450 -64.216240 -v 15.468140 10.464510 -65.778679 -v 27.342680 17.966324 22.967857 -v 28.280140 24.077744 21.717896 -v 27.030201 20.870964 22.030376 -v 27.655161 17.275404 24.530298 -v 28.905121 23.849464 24.217796 -v -9.530880 2.020349 -66.403664 -v -9.843360 1.110310 -61.091362 -v -9.530880 3.395468 -70.465996 -v -13.905701 3.737868 -72.028442 -v -73.590881 2.501287 -79.528137 -v -72.965897 3.172688 -77.965698 -v -64.841217 2.206507 -79.528137 -v -79.840637 3.750067 -79.840637 -v -77.965698 4.526427 -77.028244 -v 26.092739 18.790277 -14.843183 -v 27.030201 20.122679 -13.905704 -v 27.967661 20.135498 -14.218204 -v 25.780239 22.582378 -14.218204 -v -79.528137 3.911225 31.092539 -v -78.903160 4.181605 32.654980 -v -77.340744 2.929785 29.530102 -v -79.840637 7.465887 40.154682 -v -60.153900 15.155656 -22.342882 -v -58.278980 15.815455 -22.655363 -v -59.216442 13.685937 -23.592821 -v -58.903961 13.439977 -20.155462 -v 29.530102 27.829544 27.655157 -v 28.280140 22.138664 28.905117 -v 30.155079 26.934784 27.967657 -v 30.155079 28.404505 27.030197 -v -53.279182 8.933155 -27.030203 -v -54.529118 7.822315 -28.905123 -v -54.216644 10.469395 -26.405222 -v -52.029221 6.629096 -25.467762 -v -49.841801 4.980536 -27.030201 -v 43.592037 21.860952 -52.341702 -v 44.217018 28.248854 -52.029224 -v 44.529499 26.598471 -53.279186 -v 42.654579 17.225952 -50.779266 -v 19.842979 18.444836 -18.280544 -v 19.218000 21.818836 -18.280544 -v 21.717899 20.324097 -17.343084 -v 16.718100 4.840772 -47.966881 -v 17.655560 6.396552 -48.591862 -v 12.655760 2.254713 -45.154480 -v -72.965897 29.915113 -48.279366 -v -72.653419 26.174892 -48.904343 -v -74.215858 27.018993 -48.904343 -v -72.965897 24.003872 -47.654404 -v -72.340919 34.482334 -48.279366 -v -73.278381 17.615973 -46.716923 -v -71.403458 18.423452 -46.091965 -v 10.468340 7.036199 -7.343461 -v 7.655960 7.290099 -8.593421 -v 5.156040 6.444159 -4.843561 -v 12.343260 8.526059 -6.718482 -v 12.655760 8.073177 -8.905901 -v -13.905701 3.612140 1.093699 -v -14.530680 5.665959 -3.593601 -v -10.780820 4.774860 0.156239 -v -10.780820 6.710879 -2.031181 -v -78.903160 21.868877 -11.405805 -v -78.278198 18.641977 -9.218383 -v -77.653221 23.494238 -9.530884 -v -79.528137 14.177279 -7.655962 -v -52.654198 29.219318 -12.968245 -v -52.341698 25.795858 -12.030785 -v -52.341698 26.663177 -14.530684 -v -51.091763 19.564219 -13.905704 -v -52.966682 32.327194 -12.030787 -v -6.406000 14.492808 -77.653221 -v -7.968440 8.436328 -75.153320 -v -5.781020 14.740607 -76.090782 -v -9.218380 11.244548 -78.903160 -v 72.965897 1.156714 -37.967258 -v 79.528137 0.442595 -29.530102 -v 79.840637 1.107274 -39.842201 -v 78.278198 3.396072 -50.154301 -v 65.466202 1.191494 -35.154881 -v 53.904144 15.574350 -61.091366 -v 54.529118 18.103630 -62.028820 -v 54.841599 21.437370 -60.153904 -v 55.779079 20.798330 -61.403866 -v 56.404041 23.674891 -62.028820 -v 52.341698 10.894809 -62.341316 -v -30.155079 6.895207 47.341900 -v -31.405020 9.733948 48.591862 -v -29.217621 8.936229 51.716736 -v -27.655161 8.574288 51.716736 -v -2.031180 9.809608 -75.153320 -v -2.656140 13.136627 -76.090782 -v -4.843560 10.250888 -75.465797 -v 0.781220 10.991847 -75.153320 -v -1.406200 13.591947 -77.028244 -v -3.906100 4.718088 -72.028442 -v 22.030380 15.768458 -10.780823 -v 23.280338 16.959238 -9.530883 -v 24.217800 17.996218 -13.905704 -v 20.467960 16.806038 -12.030784 -v 21.092920 14.829118 -9.843363 -v 22.655361 16.997078 -8.280923 -v 25.780239 22.305899 -9.218384 -v 26.405220 19.551998 -11.405804 -v -47.966881 13.599878 -14.530682 -v -49.529320 17.471939 -14.218204 -v -47.966881 15.735498 -12.030784 -v -46.091961 11.410557 -15.155662 -v -48.904339 12.646518 -16.718102 -v -51.091763 20.346678 -10.780823 -v -50.466782 16.321417 -16.718102 -v 2.031180 7.150940 -0.781221 -v 1.093700 9.285939 -3.593601 -v -1.406200 9.085140 -2.343661 -v 2.968640 7.387760 1.406199 -v 5.468540 5.468820 -0.156241 -v -27.342680 7.353568 -75.778297 -v -27.655161 5.673887 -77.965698 -v -28.592640 7.704508 -75.465797 -v -25.155260 7.404227 -75.778297 -v 17.655560 15.318617 -20.780441 -v 17.343081 11.051676 -23.905321 -v 15.780640 14.951797 -20.780441 -v 18.593021 17.890015 -20.467964 -v 20.467960 13.275796 -22.967863 -v 13.905701 4.981766 37.342300 -v 14.843180 6.760945 33.279961 -v -1.406200 12.566573 75.465797 -v -1.093700 8.816592 74.215858 -v -2.968640 14.193152 75.465797 -v -0.156240 9.652772 77.653221 -v 0.468740 8.960032 75.153320 -v -0.156240 7.268153 79.840637 -v 2.343660 7.980412 76.715759 -v -4.531080 12.535439 -7.343462 -v -8.593420 11.833538 -11.093322 -v -3.593600 16.438618 -10.155863 -v 12.343260 4.304875 -27.967661 -v 13.593220 3.494955 -31.092539 -v 5.781020 2.031335 -30.467560 -v 15.155660 6.095036 -27.342682 -v -61.403862 19.744253 -46.091965 -v -60.153900 18.746952 -44.842003 -v -59.841419 23.378271 -46.716923 -v -62.028816 18.097532 -45.466984 -v -30.780039 14.660691 67.028641 -v -32.967461 14.133951 67.653595 -v -30.467560 12.963912 68.278580 -v -29.842579 17.213772 66.403664 -v -32.654980 15.805690 65.466202 -v -60.466381 14.343891 -53.279186 -v -58.278980 14.577652 -52.654202 -v -57.341499 14.082051 -54.529121 -v -60.778881 10.330231 -54.841599 -v -56.091560 15.469992 -52.341702 -v -72.340919 22.585440 -5.468544 -v -69.528542 15.661639 -3.593603 -v -73.278381 27.708700 -5.468544 -v -72.653419 29.211979 -5.156045 -v -28.592640 10.864918 -10.468342 -v -30.467560 13.671898 -11.093322 -v -28.592640 10.684859 -8.593422 -v -26.717701 10.037278 -10.780822 -v -29.530102 10.234419 -12.343262 -v -12.968240 9.126628 -78.903160 -v -16.093121 8.432668 -78.590683 -v -12.968240 7.089288 -77.028244 -v -9.218380 12.412127 -79.528137 -v -17.655560 7.820487 -79.215660 -v -14.218201 0.839931 -57.653999 -v 22.342880 18.746960 -4.531083 -v 19.842979 12.763099 -4.218582 -v 21.717899 16.286640 -2.343663 -v 22.030380 21.019897 -6.093524 -v 20.155460 13.774440 -5.781023 -v -79.215660 12.254691 65.778679 -v -78.278198 13.433890 65.466202 -v -79.528137 17.568390 63.591259 -v -79.528137 9.559391 68.278580 -v -78.590683 10.562192 67.341118 -v 28.905121 23.605938 -9.530884 -v 28.905121 20.695799 -10.780824 -v 29.842579 16.887218 -9.218383 -v -16.405600 6.459419 -6.406001 -v -10.780820 7.856499 -6.093522 -v -25.155260 4.785229 -71.090981 -v -27.342680 8.183028 -71.403458 -v -22.967861 3.842228 -71.090981 -v -25.467760 6.017508 -73.278381 -v -27.342680 10.195968 -74.528343 -v -24.217800 3.156209 -67.341118 -v 65.466202 9.013709 -70.465996 -v 62.966278 9.758948 -68.903564 -v 40.779663 16.953751 -54.529121 -v 42.967079 19.543449 -52.966686 -v 43.592037 22.028170 -54.529121 -v 40.154682 13.469871 -52.654202 -v 27.342680 4.919513 77.653221 -v 22.342880 2.256573 79.215660 -v 32.029999 4.852993 79.528137 -v 27.030201 4.907932 75.153320 -v -54.841599 5.625080 1.406199 -v -55.779079 4.046101 4.531080 -v -49.216820 4.799280 1.406199 -v -55.779079 7.904720 -0.468741 -v -57.966480 5.526801 2.656139 -v -50.154301 1.560762 9.843360 -v -58.591461 3.935021 5.781020 -v 50.154301 2.274257 -20.155460 -v 54.529118 1.561376 -23.905319 -v 46.716919 2.802216 -23.905319 -v 52.966682 2.030118 -14.218201 -v 27.342680 14.765046 38.592236 -v 26.717701 14.311566 37.967255 -v 25.155260 14.816926 40.154678 -v 28.905121 11.005906 39.842201 -v 28.592640 13.983807 37.967255 -v 29.842579 9.119926 42.342102 -v 30.467560 9.743107 38.904739 -v -54.216644 24.249857 -12.030785 -v -56.716541 22.561640 -10.468344 -v -56.404041 24.722258 -11.093324 -v -57.029018 19.567257 -12.030784 -v -56.091560 26.042458 -9.218384 -v -55.779079 23.543678 -10.468344 -v -58.591461 19.326178 -9.530883 -v -55.779079 24.401217 -11.718305 -v -54.529118 23.410017 -10.780824 -v -75.153320 18.981319 -4.218583 -v -75.778297 16.444719 -4.843563 -v 36.717319 9.626524 23.905317 -v 39.217220 6.853704 23.280336 -v 36.092342 10.708064 21.717897 -v 35.154881 12.852824 25.780237 -v 36.717319 8.393004 27.655159 -v 19.842979 10.758716 -25.467762 -v 21.405420 12.648355 -24.530302 -v 23.592819 9.550216 -25.155262 -v 18.593021 10.824017 -26.092741 -v 23.280338 7.607475 -29.842581 -v 36.717319 17.244282 7.030977 -v 37.967258 16.540543 7.343457 -v 37.029800 14.344522 6.093518 -v 36.404819 22.164902 7.655956 -v 37.654778 21.942122 8.280916 -v 57.653999 3.659769 55.779079 -v 58.903961 1.747528 49.216820 -v 52.654198 3.168428 52.966682 -v 58.278980 5.044649 58.591461 -v 62.653801 3.143409 54.529118 -v 3.593600 14.646008 -76.403259 -v 4.218580 13.104888 -76.090782 -v 5.468540 7.910207 -79.528137 -v 2.656140 11.990988 -76.715759 -v 3.593600 15.139788 -76.090782 -v 35.467361 5.938174 -35.154881 -v 34.842381 7.692314 -36.717319 -v 32.967461 6.622375 -36.404819 -v 38.279758 4.575875 -32.342480 -v 38.279758 5.719674 -37.342300 -v 58.278980 2.185760 -0.781220 -v 55.466579 4.533781 2.343659 -v 57.966480 3.058561 5.468540 -v 57.029018 2.166839 -4.531081 -v 53.279182 3.329560 0.156239 -v 54.529118 3.560259 -5.468541 -v 52.029221 3.258140 -3.281121 -v 54.841599 1.954438 -10.468340 -v 51.716736 3.127518 -9.843361 -v 62.028816 0.857638 -12.030781 -v -67.966095 10.704398 -18.593023 -v -71.403458 12.017257 -18.280542 -v -69.841019 18.335577 -15.468143 -v -67.341118 8.756776 -21.092922 -v -70.465996 8.228816 -22.030382 -v -67.966095 14.351837 -16.093122 -v -66.403664 12.095977 -17.030582 -v -67.966095 22.117899 -13.593224 -v -33.904919 3.385690 -58.278980 -v -36.404819 4.296951 -54.216644 -v -30.155079 2.838831 -52.966682 -v -39.842201 6.114571 -56.716541 -v 12.655760 8.854406 -79.215660 -v 15.468140 12.632467 -78.903160 -v 19.530479 13.378306 -79.215660 -v 11.718301 9.762608 -76.715759 -v 13.280740 11.583888 -76.090782 -v 31.717520 7.194274 -38.904739 -v 33.279961 5.310735 -32.967461 -v -68.278580 15.014690 69.216042 -v -68.903564 20.660412 65.466202 -v -64.216240 12.507992 71.715958 -v -63.278778 15.455972 70.153519 -v 45.154480 12.672170 65.466202 -v 74.840820 7.633741 11.405800 -v 75.153320 10.413862 10.468338 -v 74.215858 8.820242 9.843358 -v 77.028244 9.241382 14.530678 -v 77.653221 11.381262 11.405799 -v 76.715759 8.090281 7.655958 -v 72.965897 5.958322 12.655759 -v 74.528343 7.055122 15.155659 -v 4.531080 7.206469 -71.090981 -v 2.031180 6.272028 -71.715958 -v 6.093520 8.890429 -69.528542 -v 7.343460 12.019688 -73.903358 -v 9.530880 10.808148 -74.840820 -v 7.343460 10.425448 -75.465797 -v 7.968440 12.553728 -71.715958 -v 11.093320 13.093287 -74.528343 -v 10.468340 9.794968 -75.778297 -v -11.093320 8.648750 66.403664 -v -14.218201 10.545712 68.278580 -v -66.091179 22.960798 -12.655764 -v -67.028641 25.330778 -13.280744 -v -66.716141 26.137657 -12.030785 -v -64.528740 22.934559 -12.030785 -v 34.529900 7.871149 -67.966095 -v 32.342480 9.057049 -69.216042 -v 30.155079 12.478669 -67.028641 -v 36.717319 6.024848 -71.715958 -v -70.465996 26.733978 -12.968245 -v -70.778481 27.240559 -11.405806 -v -69.528542 30.029858 -11.405806 -v -71.403458 25.696999 -13.280744 -v 57.029018 7.923028 -73.903358 -v -78.278198 22.252178 -12.968244 -v -78.903160 20.910639 -12.343264 -v -77.965698 20.533438 -13.905704 -v -79.528137 22.750837 -13.593224 -v -31.092539 5.781928 -77.028244 -v -29.842579 8.230027 -76.090782 -v -29.842579 8.526048 -73.903358 -v 78.278198 10.802664 23.280336 -v 78.903160 10.193543 21.405418 -v 77.028244 12.513464 21.717897 -v 78.903160 12.149084 24.217798 -v 56.716541 16.401989 -64.841217 -v 56.091560 13.537630 -66.091179 -v 54.841599 12.528110 -65.153702 -v 57.653999 14.334729 -64.216240 -v -74.215858 18.849501 -4.843563 -v -73.903358 24.008760 -5.468544 -v -75.465797 22.853376 -6.093524 -v -63.903763 17.119171 67.341118 -v -60.778881 14.695471 67.341118 -v -65.466202 19.884651 66.716141 -v 61.403862 7.864429 -70.153519 -v -35.779861 5.289997 -20.155460 -v -45.154480 5.820376 -22.655361 -v 41.717117 12.036171 -58.278984 -v 39.842201 13.249531 -55.779083 -v 42.342102 17.308352 -56.404045 -v 41.404640 10.396770 -59.841419 -v 37.342300 11.067551 -56.404041 -v -72.653419 18.938011 65.466202 -v -71.090981 16.665071 66.716141 -v -70.778481 21.163952 65.153702 -v -73.590881 18.433851 65.778679 -v -72.965897 14.646031 67.341118 -v 0.156240 7.193072 73.278381 -v -2.656140 8.482732 72.965897 -v -2.343660 6.652291 70.153519 -v -13.905701 5.163648 46.716919 -v -15.468140 7.450627 46.091961 -v -14.530680 5.946728 47.966881 -v -14.218201 3.714687 41.092140 -v 27.342680 13.308142 13.905699 -v 26.717701 11.623584 15.155658 -v 29.842579 17.561041 14.843177 -v 27.655161 11.157282 11.718299 -v 24.530300 7.143622 11.718300 -v 29.842579 5.338832 70.153519 -v 25.780239 6.668772 71.403458 -v 26.717701 6.308671 65.778679 -v 24.530300 6.320871 68.591080 -v 22.342880 7.919991 71.090981 -v 34.217419 5.526812 68.903564 -v 33.279961 3.759253 77.340744 -v 21.405420 3.319792 75.465797 -v -46.716919 7.202810 -60.466381 -v -46.404438 7.467091 -57.966480 -v 29.842579 27.178303 24.217796 -v 29.217621 26.124844 22.342876 -v -51.404236 15.438259 -6.406003 -v -52.966682 18.609018 -7.655962 -v -53.591660 19.202278 -6.718483 -v -50.154301 17.975479 -6.718483 -v -51.091763 17.944338 -8.280923 -v -52.654198 20.800777 -9.530884 -v -54.529118 19.526358 -7.968443 -v 72.965897 9.696103 19.217999 -v 71.403458 10.289963 19.842978 -v 72.965897 9.370183 20.467958 -v 70.778481 10.178283 18.593019 -v -62.028816 1.228744 25.155260 -v -65.466202 3.040244 23.905319 -v -65.153702 1.979465 29.217621 -v -58.278980 0.731304 26.405220 -v -61.091362 1.129244 21.717899 -v -58.591461 1.063945 32.342480 -v 27.967661 9.830969 -62.966278 -v 29.217621 12.269310 -62.653805 -v 29.530102 11.294589 -63.591263 -v 26.717701 9.604530 -60.778881 -v 29.530102 10.998571 -60.778881 -v 47.029419 6.726762 7.343459 -v 47.029419 5.286941 8.905899 -v 49.841801 5.044641 7.343459 -v 46.404438 9.683901 6.405999 -v 46.091961 7.191841 7.655959 -v 33.279961 12.594049 58.591457 -v 31.092539 11.387989 58.903961 -v 31.717520 9.246290 61.403862 -v 32.029999 11.669969 55.154099 -v 44.529499 31.481873 -52.029224 -v 44.529499 23.231173 -51.091766 -v 3.281120 13.860497 -19.530481 -v 5.468540 12.394437 -20.467962 -v 4.843560 13.022496 -21.092922 -v 2.343660 13.981358 -19.218002 -v 1.406200 15.772117 -17.968042 -v 2.968640 14.711938 -20.467962 -v 1.093700 11.364177 -19.842981 -v 12.655760 9.452559 -11.093322 -v 13.905701 12.506759 -13.280742 -v 11.093320 11.981858 -13.280742 -v 15.468140 10.413858 -10.468342 -v -7.968440 11.164612 78.903160 -v -10.155860 12.786314 79.528137 -v -5.156040 11.546692 76.403259 -v -6.093520 13.122613 74.840820 -v 2.968640 10.956456 -21.092922 -v 2.656140 7.431696 -22.342882 -v -68.591080 25.806854 -48.904343 -v -68.903564 23.610813 -48.279366 -v -67.966095 25.807451 -47.654404 -v -69.528542 24.207130 -50.154305 -v -70.153519 24.416473 -48.279366 -v -67.028641 23.746912 -48.904343 -v 24.530300 10.132504 24.217798 -v 23.592819 9.491645 28.592638 -v 29.217621 20.985718 -8.905904 -v 28.905121 27.628736 -8.593425 -v 29.217621 20.769636 -7.655963 -v 28.592640 30.994200 -9.218385 -v 12.968240 7.931580 0.156239 -v 11.718301 6.561960 0.468739 -v 13.905701 7.542180 -0.468741 -v 12.343260 8.541920 -0.156241 -v 50.154301 6.570489 -67.653595 -v 47.029419 4.392768 -71.715958 -v -58.903961 9.674735 -28.592642 -v -58.591461 11.275676 -31.405022 -v -60.466381 8.746995 -28.905123 -v -58.903961 10.487715 -26.405222 -v -76.715759 2.695403 15.468140 -v -70.778481 2.342623 17.968040 -v -76.403259 3.250201 10.780819 -v -79.528137 2.909644 23.905319 -v -35.779861 4.751667 44.841999 -v -34.529900 7.289508 47.029419 -v -30.780039 5.875328 45.466980 -v -40.467182 3.428427 43.904537 -v -41.092140 7.146068 48.279362 -v -38.592239 7.461008 50.154301 -v -35.154881 10.831969 52.966682 -v 54.841599 4.396441 5.156039 -v 53.591660 6.625441 5.156039 -v 52.341698 4.216382 7.343459 -v 53.904144 5.339420 3.281119 -v 53.279182 3.055502 10.468339 -v 52.654198 4.630820 2.656139 -v -1.406200 14.021019 -4.218583 -v 0.156240 12.586099 -5.781022 -v -1.093700 11.314739 -3.593602 -v -0.468740 16.517958 -7.968443 -v -3.281120 8.258718 -18.280542 -v -1.718680 7.108217 -20.780441 -v -4.531080 5.114817 -21.092920 -v -2.656140 12.937037 -16.718102 -v -0.781220 10.443778 -18.905523 -v -2.343660 15.651257 -14.843183 -v -0.156240 17.927259 -16.093124 -v 72.028442 16.043110 -62.966282 -v 71.090981 14.219991 -61.403866 -v 73.278381 14.201069 -61.716347 -v 72.340919 14.879769 -64.841217 -v 70.153519 16.403809 -64.528740 -v 72.340919 13.051170 -59.841423 -v 69.841019 16.398331 -61.403866 -v 69.528542 11.942770 -59.841423 -v 3.906100 8.405808 -72.340919 -v 4.843560 11.578408 -73.590881 -v 2.968640 11.293967 -73.278381 -v 5.468540 10.019568 -72.653419 -v 48.591862 18.488771 -54.841602 -v 48.279362 16.077291 -56.404045 -v 47.029419 17.859489 -55.154102 -v 51.091763 15.477910 -56.091564 -v 45.466980 20.720209 -53.904148 -v 44.529499 18.242189 -55.466583 -v 47.029419 20.676250 -52.966686 -v 47.341900 19.164431 -56.404045 -v 45.779461 16.534431 -57.341503 -v 47.341900 12.880270 -59.216446 -v 50.154301 12.169210 -60.153904 -v 68.903564 2.107025 28.592640 -v 70.778481 3.861785 29.217621 -v 71.715958 4.734584 25.780239 -v 66.403664 1.600445 27.967661 -v 69.841019 2.136945 30.467560 -v -58.591461 13.864153 -41.404644 -v -60.153900 15.678113 -39.529705 -v -56.404041 11.900675 -37.654781 -v -58.591461 15.500513 -44.529503 -v -61.091362 18.485712 -42.654583 -v 79.528137 3.888632 -52.029221 -v 78.903160 5.672051 -56.091560 -v -73.278381 4.748628 45.466980 -v -76.715759 5.554288 45.779461 -v -74.840820 5.027548 49.216820 -v -72.028442 5.839307 42.654579 -v -75.465797 5.817947 42.342102 -v -70.778481 4.734587 43.279564 -v -64.841217 3.861167 45.779461 -v -68.903564 3.932587 40.779663 -v -71.403458 4.869467 40.467182 -v -71.090981 6.870186 37.967258 -v -74.215858 7.216866 38.279758 -v -52.341698 4.426948 -72.340919 -v -47.654400 3.591388 -71.715958 -v -52.341698 4.065008 -75.778297 -v -55.154099 3.494948 -72.653419 -v -53.591660 4.506289 -67.341118 -v 46.716919 8.812322 4.531079 -v 44.841999 9.842581 6.093519 -v 49.529320 8.958800 4.843558 -v 45.466980 6.807920 3.281119 -v 49.216820 5.410841 2.968639 -v 41.717117 8.002381 3.281119 -v 49.216820 4.318920 1.093699 -v -41.092140 9.819991 -52.029221 -v -42.654579 8.078053 -48.591862 -v -39.217220 7.807671 -51.716736 -v -41.717117 12.532371 -52.341702 -v -43.904537 9.645432 -50.466782 -v 27.967661 6.893376 -27.030203 -v 24.842779 6.514355 -30.155081 -v 35.467361 4.773015 -28.280140 -v -50.154301 1.171366 37.654778 -v -47.966881 1.843367 41.404640 -v -57.341499 2.469587 41.717117 -v -33.904919 0.442003 16.718100 -v -34.842381 1.035262 9.530880 -v -40.467182 0.476782 15.155660 -v 56.716541 22.019032 -60.466385 -v 57.966480 16.580811 -61.716347 -v 56.716541 24.642309 -59.841423 -v 32.029999 9.365906 37.029800 -v 33.592442 7.642286 37.342300 -v 30.780039 13.696325 36.717316 -v -48.279362 7.824751 -52.341698 -v -46.404438 8.351492 -47.966881 -v -51.404236 8.736012 -50.779263 -v 77.653221 9.722343 20.780437 -v 79.528137 10.137981 14.530678 -v 76.715759 9.917663 17.655558 -v 12.968240 8.103701 -2.031181 -v 15.468140 8.922779 -4.218582 -v 11.093320 6.321479 -4.843561 -v 8.593420 5.058060 0.156239 -v -28.592640 18.541891 64.528740 -v -30.780039 17.991350 63.903759 -v -27.030201 16.055332 67.341118 -v -29.530102 20.855110 63.591259 -v -27.967661 15.864291 63.591259 -v -29.217621 19.122931 63.278774 -v -31.092539 14.445830 62.653797 -v -27.967661 21.287851 65.466202 -v 11.093320 15.700096 -21.092922 -v 11.093320 21.047358 -20.155464 -v 13.593220 17.430437 -21.092922 -v 13.280740 11.782876 -22.342882 -v -54.529118 18.194578 -6.718483 -v -53.591660 21.511839 -7.343463 -v -55.779079 21.407459 -6.406003 -v -55.154099 16.170059 -5.156043 -v 58.278980 0.644026 37.342300 -v 52.029221 1.004746 34.529900 -v 50.466782 1.229347 40.779663 -v 59.216442 0.924785 30.780039 -v 73.278381 4.709565 28.280140 -v 75.153320 5.007405 31.717520 -v 67.341118 1.118266 34.842381 -v 71.715958 2.312726 34.529900 -v 68.903564 3.695164 23.592819 -v -42.967079 14.397618 -11.093322 -v 4.218580 6.286713 77.653221 -v 3.593600 9.328073 76.715759 -v 6.406000 3.903893 79.528137 -v 6.093520 5.673312 77.028244 -v 3.906100 11.206113 75.153320 -v 5.156040 8.854432 74.840820 -v -37.654778 5.936952 -49.841801 -v -42.029602 7.046573 -45.154480 -v -34.217419 4.362872 -46.716919 -v -33.904919 2.451253 -42.654579 -v -33.592442 1.962374 -38.904739 -v -32.342480 2.409753 -45.154480 -v -25.467760 1.305632 -46.716919 -v -40.154682 4.553293 -39.842201 -v -32.654980 3.140952 -48.279362 -v -67.966095 8.656054 -34.842381 -v -75.465797 9.959754 -33.904919 -v -59.841419 14.703410 65.466202 -v -58.903961 11.960490 62.966274 -v -61.716343 13.794590 62.028812 -v -60.153900 10.809389 61.403862 -v -56.404041 14.741250 65.466202 -v -56.716541 14.431810 63.591259 -v -44.841999 4.572848 46.716919 -v -49.216820 4.470908 47.654400 -v -46.716919 7.442709 51.716736 -v -43.279564 8.181828 49.216820 -v -43.904537 9.466009 51.716736 -v -42.029602 7.246769 52.966682 -v -74.840820 22.973614 -51.404240 -v -76.090782 17.541512 -52.966686 -v -78.278198 17.821053 -48.904343 -v -73.590881 22.968113 -51.404240 -v -73.278381 15.255752 -54.216648 -v -74.528343 21.914053 -49.841805 -v 48.904339 17.266232 -49.841805 -v 47.966881 22.575672 -50.154305 -v 47.654400 16.094372 -49.216824 -v 48.591862 25.484592 -50.779266 -v 28.280140 23.912336 -13.280744 -v -55.154099 10.551200 -2.031182 -v -58.278980 8.951480 -1.718681 -v -21.405420 7.791198 -12.655761 -v -17.030581 7.828438 -12.655761 -v -18.280540 4.724797 -17.343081 -v -65.778679 4.875562 8.593419 -v -62.341316 6.001040 4.218579 -v -49.216820 20.258179 -8.280923 -v -48.904339 17.855837 -9.530883 -v -47.966881 16.599737 -7.968443 -v -47.654400 20.242918 -8.905903 -v -70.778481 3.440026 32.967461 -v -68.903564 2.835185 28.905121 -v -74.215858 2.359104 26.405220 -v -67.653595 4.909745 33.279961 -v 39.529701 4.325047 42.967079 -v 34.529900 6.071246 41.404640 -v 36.717319 5.797208 46.716919 -v 41.092140 4.981767 43.279564 -v 39.842201 4.126667 40.154682 -v 43.592037 2.755227 40.779663 -v 47.966881 2.387788 46.404438 -v 46.716919 1.812226 37.342300 -v 40.154682 4.059526 37.029800 -v 40.154682 4.511808 46.091961 -v 21.405420 8.440004 31.717518 -v 19.218000 4.807204 25.780239 -v -32.029999 8.037792 76.715759 -v -26.092739 7.335893 78.278198 -v -26.717701 8.519973 75.778297 -v -40.154682 3.917333 79.840637 -v 11.405801 2.231532 -48.591862 -v 7.343460 1.626672 -51.091763 -v 8.593420 2.051472 -46.716919 -v 4.843560 1.276951 -52.029221 -v 6.718480 1.232993 -45.154480 -v 6.406000 2.668531 -54.841599 -v -41.092140 13.314870 66.403664 -v -43.592037 14.246250 63.903759 -v 35.154881 3.820292 74.528343 -v -60.153900 10.532275 -31.717522 -v -56.716541 9.468435 -31.405022 -v -58.591461 14.329255 -33.279964 -v -63.591263 6.757893 79.215660 -v -70.465996 6.396573 79.528137 -v -66.403664 6.943433 77.965698 -v 19.530479 7.495792 -45.779461 -v 25.155260 6.325752 -48.279362 -v 26.717701 7.805831 -51.404236 -v -52.341698 7.325490 -63.278778 -v -49.216820 6.994689 -65.778679 -v 24.217800 6.270814 -32.029999 -v -35.779861 2.957840 2.968640 -v -30.780039 2.518400 2.968640 -v -41.717117 1.862881 5.781020 -v -36.092342 5.212480 -0.468741 -v -32.967461 3.958220 -0.781221 -v -36.404819 8.100039 -5.156042 -v -40.154682 4.432460 0.156239 -v -75.465797 5.122141 6.093519 -v -74.840820 7.142401 4.218579 -v -73.278381 3.738481 8.280919 -v -79.528137 3.821501 10.155859 -v 73.278381 3.511448 48.279362 -v 72.965897 2.758887 42.029602 -v 69.841019 2.949308 49.841801 -v 76.403259 5.058688 47.029419 -v 17.030581 3.476652 75.153320 -v 19.218000 6.028532 72.340919 -v 13.905701 5.356531 68.591080 -v -48.279362 6.422800 -1.718681 -v -47.966881 6.005920 0.156239 -v -46.091961 6.210999 -2.343661 -v -52.029221 8.581600 -1.718681 -v -45.779461 3.958220 1.406199 -v -47.966881 8.986259 -4.218582 -v -56.091560 13.123197 -17.343082 -v -56.404041 13.963657 -18.905523 -v -55.466579 14.996978 -15.468143 -v -53.904144 15.838637 -15.780643 -v -54.216644 12.133218 -20.155462 -v -53.591660 13.387477 -19.842981 -v -53.904144 10.568276 -22.030382 -v -55.466579 12.563517 -18.593023 -v 63.903763 12.325468 -68.278580 -v 64.216240 12.171668 -67.653595 -v 66.091179 15.719608 -67.341118 -v 62.653801 12.847928 -67.966095 -v 66.716141 13.845228 -67.653595 -v 62.653801 10.880169 -67.028641 -v 65.466202 13.380150 -66.091179 -v 67.653595 12.238188 -69.528542 -v 66.403664 16.425789 -66.716141 -v 46.091961 11.400169 -61.716343 -v 48.591862 13.944731 -60.778885 -v 48.904339 8.806190 -63.278778 -v -11.093320 7.608099 -3.906101 -v -11.093320 9.548399 -2.968642 -v 39.842201 7.369440 0.156239 -v 26.405220 10.596351 -58.903961 -v 26.717701 9.672291 -57.029018 -v 27.655161 12.442651 -57.966484 -v 22.967861 9.304251 -60.153900 -v -35.154881 7.360297 -16.718102 -v -34.529900 9.881038 -14.218203 -v -1.093700 22.132557 -10.468344 -v -0.468740 21.882318 -12.655764 -v -2.656140 19.923698 -11.093323 -v 0.468740 14.503199 -9.530882 -v -74.840820 16.355610 62.653797 -v -75.778297 11.622370 61.403862 -v -76.403259 19.559950 63.591259 -v -72.340919 15.537750 62.653797 -v -72.653419 9.336609 60.153900 -v 13.593220 7.099050 -65.466202 -v 11.405801 5.423650 -65.153702 -v 13.905701 11.261028 -68.903564 -v 47.654400 4.097382 11.718300 -v 36.404819 7.925488 50.779263 -v 36.404819 10.459049 52.341698 -v 37.967258 7.877869 51.404236 -v 28.905121 10.249087 49.529320 -v -67.341118 13.867219 -4.218583 -v -64.216240 12.977340 -5.156042 -v -67.653595 15.267360 -6.093523 -v -63.903763 9.436700 -1.093702 -v -58.591461 16.821918 -6.718483 -v -57.341499 17.161879 -6.093523 -v -59.841419 12.941319 -4.843562 -v -57.341499 17.298599 -5.156043 -v -63.278778 19.312733 -47.654404 -v -66.403664 18.484491 -46.091965 -v -63.591263 18.161013 -48.279366 -v -66.091179 21.388533 -47.654404 -v -65.778679 9.571589 59.841419 -v -64.841217 6.722489 57.341499 -v -67.966095 9.146790 59.528919 -v -66.091179 13.513230 60.778877 -v -64.528740 11.662029 61.091362 -v -66.716141 12.518970 61.403858 -v -15.155660 15.025672 77.653221 -v -17.030581 12.051454 79.215660 -v -13.593220 17.228413 79.528137 -v -14.843180 17.355373 76.715759 -v -17.343081 11.997132 77.965698 -v -20.780439 8.951493 79.528137 -v -56.404041 14.169332 -50.779266 -v 22.342880 13.407626 36.717316 -v 23.905319 12.633105 33.904915 -v 23.592819 11.786546 38.592236 -v -5.156040 4.428188 53.904144 -v -6.406000 5.390709 57.029018 -v -2.656140 3.933187 47.341900 -v -7.655960 3.191007 46.091961 -v 37.342300 4.921351 71.403458 -v 27.655161 23.682838 -9.218384 -v 25.155260 26.201139 -7.968444 -v 26.717701 28.945879 -7.968445 -v -13.280740 10.222818 -10.780822 -v -14.218201 8.511418 -12.343261 -v -17.030581 9.362238 -10.780822 -v -10.780820 6.536937 -16.093122 -v -69.216042 8.241010 -64.841217 -v -65.466202 10.451094 -36.717319 -v -66.716141 10.701334 -38.279758 -v -63.903763 12.514673 -35.154884 -v -62.966278 12.499413 -38.592243 -v -67.966095 13.396633 -42.029606 -v -70.153519 16.237192 -43.904541 -v -64.841217 14.046653 -42.654583 -v -0.781220 22.022078 -13.593224 -v -4.218580 14.888938 -12.968243 -v 74.528343 6.535708 -76.403259 -v 77.028244 8.934368 -72.965897 -v 79.840637 5.919868 -79.840637 -v 70.778481 5.058667 -79.215660 -v 70.465996 5.759347 -77.653221 -v 39.842201 11.517982 12.968238 -v 40.779663 10.284482 13.593218 -v 39.842201 12.767982 12.030779 -v 38.279758 10.383963 15.780638 -v 41.717117 7.160723 15.468139 -v 44.841999 3.764123 20.467960 -v 41.404640 5.646443 19.842979 -v -78.278198 12.710588 -68.591080 -v -77.340744 10.157508 -70.465996 -v -79.528137 11.168848 -74.528343 -v -79.215660 12.919330 -65.153702 -v 51.091763 4.402528 -72.965897 -v 52.966682 5.578669 -70.778481 -v 55.154099 5.800228 -74.840820 -v 47.341900 3.601748 -76.715759 -v 23.592819 7.589783 19.217999 -v 21.717899 6.176824 23.592817 -v 25.467760 10.893003 20.155458 -v 20.780439 4.693083 17.655560 -v -0.468740 3.927081 4.531080 -v 3.281120 2.285241 5.781020 -v -1.718680 3.346041 3.906100 -v -4.531080 3.873381 5.156040 -v 1.718680 4.751660 3.281119 -v -0.156240 5.394360 0.156239 -v -3.906100 3.576141 2.968640 -v 6.406000 14.811408 -73.590881 -v -52.341698 23.941639 -10.468344 -v -52.341698 13.583400 -5.156043 -v -49.529320 13.632237 -18.280542 -v -49.841801 9.750417 -19.842981 -v -51.716736 10.021417 -20.155462 -v -52.654198 12.622717 -18.593023 -v -48.591862 6.873237 -21.717901 -v -51.404236 7.306576 -22.655363 -v -35.154881 9.657648 54.216644 -v -61.716343 20.981440 -8.905904 -v 20.155460 17.538456 -19.530481 -v 21.717899 25.654879 -16.405603 -v 22.342880 24.432959 -16.405603 -v 21.717899 5.037302 14.843179 -v 23.592819 7.401803 17.343079 -v 19.218000 3.480922 12.030780 -v -69.841019 18.566910 62.966274 -v -69.528542 11.771289 61.403858 -v -69.216042 18.157370 64.216240 -v 30.467560 7.887634 -38.592239 -v 29.530102 11.010174 -37.029800 -v 30.467560 7.208314 -36.092342 -v -68.278580 6.541190 -63.591263 -v -64.841217 5.478570 -63.903763 -v -67.028641 6.295229 -66.716141 -v -69.216042 8.074390 -59.841419 -v -52.966682 7.051450 -62.028816 -v -54.529118 9.917650 -58.278980 -v -57.341499 6.912890 -62.028816 -v -56.404041 11.403851 -57.966480 -v -58.591461 9.127851 -57.029018 -v -55.466579 13.364891 -56.404045 -v -53.904144 9.431190 -57.341499 -v 79.528137 6.992872 74.215858 -v 75.153320 8.613952 72.965897 -v 73.590881 10.240533 77.340744 -v 25.155260 12.149085 29.530100 -v 27.342680 19.415285 30.467556 -v 26.092739 14.932285 32.654976 -v 22.967861 18.931278 -14.843183 -v 21.717899 21.691877 -15.780643 -v 22.030380 17.280899 -13.593223 -v 23.592819 22.325418 -15.155663 -v 23.280338 19.263918 -16.093124 -v 42.654579 12.258950 -58.903965 -v 37.967258 5.620185 35.779861 -v 37.967258 6.768266 37.342300 -v 31.092539 12.148472 -55.466583 -v 30.780039 10.186811 -54.529118 -v 33.279961 12.489052 -55.154102 -v 30.155079 9.945110 -56.716541 -v 30.155079 13.423491 -55.154102 -v -73.278381 7.515936 -27.655163 -v 22.967861 13.959988 -74.528343 -v 25.780239 13.125628 -74.215858 -v 21.405420 16.911627 -76.403259 -v 19.218000 16.658329 -74.215858 -v -71.090981 20.040911 63.591259 -v -72.340919 23.468012 64.528732 -v 49.841801 3.162918 -12.655761 -v 45.154480 5.124578 -15.155661 -v 46.716919 3.573697 -17.655560 -v -24.530300 6.997728 -75.465797 -v 29.217621 20.963745 18.593018 -v 28.592640 18.485723 19.217997 -v 29.217621 21.970203 19.217997 -v 27.967661 16.334242 17.030579 -v 30.155079 19.656984 17.968037 -v 26.717701 10.171561 7.030979 -v 23.592819 7.204041 7.030979 -v 25.780239 8.183042 9.530879 -v 27.967661 13.569361 6.405998 -v 27.030201 11.374561 3.281118 -v 30.467560 14.246241 7.030978 -v 30.155079 16.406879 5.468537 -v 30.780039 14.484901 8.280918 -v 28.905121 12.887001 4.531078 -v -9.218380 6.072448 -72.965897 -v -11.093320 5.175848 -73.590881 -v -14.843180 1.718829 -64.841217 -v 33.904919 22.139282 11.093316 -v 31.405020 16.970242 10.468337 -v 32.029999 21.330561 12.343256 -v 35.154881 20.007940 11.093317 -v 34.217419 20.073862 8.280917 -v 31.092539 21.549063 13.280736 -v -55.154099 12.367597 -22.967863 -v -57.966480 14.499537 -24.530302 -v -1.718680 2.897427 45.154480 -v 0.468740 3.707368 51.091763 -v -0.156240 2.208346 40.154682 -v -10.468340 2.302346 40.154682 -v -11.093320 4.242028 47.966881 -v 5.781020 3.882529 54.841599 -v 7.968440 4.264610 61.403862 -v 28.905121 12.789340 2.656138 -v 30.467560 14.196200 2.343657 -v 11.093320 1.811613 -42.342102 -v 8.593420 13.309977 -14.843182 -v 9.530880 8.906298 -11.093322 -v 12.030781 14.898098 -14.218204 -v -0.468740 9.234056 -20.780441 -v -4.843560 8.250177 -17.030582 -v -0.468740 11.165188 -78.590683 -v 1.093700 13.927028 -75.778297 -v -41.092140 8.817191 -53.904144 -v -51.716736 6.469795 -32.967461 -v -53.279182 9.660074 -33.592442 -v -54.529118 7.683775 -31.717522 -v -51.716736 6.929374 -36.717319 -v -55.466579 10.516395 -34.529900 -v -65.466202 26.217619 -10.155864 -v -66.716141 26.953077 -10.468345 -v -66.091179 24.560518 -8.905904 -v -64.528740 22.084959 -10.780824 -v -65.778679 25.083597 -11.405805 -v -77.965698 7.368227 43.592037 -v -79.528137 5.475548 47.654400 -v -70.778481 14.950580 -2.656142 -v 44.217018 3.801357 -22.342880 -v 42.029602 3.897175 -29.842579 -v 43.904537 5.040956 -21.092920 -v -39.217220 3.211134 -35.779861 -v -37.967258 3.100675 -29.842579 -v -29.217621 1.392915 -32.967461 -v -40.467182 10.108091 68.591080 -v -39.529701 7.468952 71.715958 -v -72.653419 21.248158 -9.843364 -v -71.715958 27.741659 -9.218385 -v -72.340919 23.561378 -10.468344 -v -73.903358 20.126339 -10.468343 -v -73.903358 19.299938 -7.030983 -v -71.715958 21.041258 -8.280924 -v -70.465996 22.282698 -8.593424 -v -54.841599 13.114039 -3.281122 -v -54.216644 15.980239 -2.968643 -v -54.216644 16.491720 -3.906103 -v -57.029018 12.394439 -3.593602 -v -66.091179 8.603571 -57.029018 -v -64.841217 10.751371 -54.529118 -v -62.341316 7.894950 -57.341499 -v -70.778481 10.346710 -57.029018 -v -20.155460 11.793870 57.029015 -v -23.905319 15.679970 56.404037 -v -72.965897 24.899260 -11.718305 -v -72.965897 21.459339 -13.593224 -v -73.590881 24.222399 -11.718305 -v -71.715958 32.249081 -11.405807 -v 13.593220 18.298336 -19.842983 -v 45.154480 16.568630 61.091358 -v 31.092539 26.709562 25.155256 -v 31.405020 29.204065 24.217796 -v 31.092539 28.275105 26.092735 -v 32.029999 25.592625 24.842775 -v -72.653419 5.175246 37.029800 -v -76.403259 4.696126 35.467361 -v -75.778297 7.569047 40.467182 -v 38.279758 21.433104 9.843356 -v 37.029800 18.899542 10.780817 -v 38.592239 21.441643 10.780816 -v 38.592239 17.624521 9.218377 -v 74.215858 3.198320 2.031179 -v 75.153320 5.253981 4.843559 -v 77.340744 4.940260 1.718679 -v 70.465996 3.523041 5.781020 -v -73.590881 5.051961 5.781019 -v -68.278580 3.444302 10.468339 -v -69.528542 4.862741 6.718479 -v 71.715958 8.817804 21.405418 -v 70.465996 6.046824 22.030378 -v 72.028442 10.878344 22.342878 -v 30.780039 21.947023 27.967657 -v 31.092539 18.685925 28.592636 -v 31.405020 24.397564 27.655157 -v -78.278198 9.988455 -31.405022 -v -13.593220 1.974576 -25.780239 -v -51.716736 10.371133 -46.716919 -v -51.716736 11.853672 -45.779465 -v -50.154301 9.416553 -46.716919 -v -54.529118 13.543112 -46.716923 -v 54.216644 9.065589 -67.653595 -v 27.030201 15.401646 34.842377 -v 7.655960 7.147896 -23.280340 -v -27.030201 2.922452 -48.279362 -v -23.905319 1.400232 -48.591862 -v -25.780239 4.011312 -52.029221 -v 71.403458 11.519832 75.465797 -v 67.653595 12.040451 72.653419 -v 69.528542 14.317053 77.653221 -v 72.653419 11.751773 75.153320 -v 69.841019 8.689032 69.216042 -v -13.905701 0.733744 24.217800 -v -18.280540 0.565284 27.030201 -v -12.968240 1.496064 26.092739 -v -23.905319 9.690008 50.466782 -v -22.030380 7.064888 48.279362 -v -47.966881 7.965151 69.528542 -v -45.779461 5.029992 74.840820 -v -47.029419 11.239071 66.091179 -v 36.404819 10.926551 -60.153900 -v 35.467361 10.720251 -57.966480 -v 33.592442 10.903349 -62.966278 -v 32.967461 13.092071 -59.528923 -v 38.279758 8.965509 -62.341316 -v 65.153702 1.562608 45.779461 -v -79.215660 10.762989 61.403862 -v -79.528137 7.537310 58.903961 -v -78.278198 11.115170 61.403862 -v -31.717520 4.988477 -19.530479 -v -34.217419 3.491896 -24.217800 -v -29.842579 5.916817 -19.218002 -v -32.029999 6.507017 -17.030582 -v -32.967461 14.744279 -11.405804 -v -25.780239 3.424757 -21.092920 -v -43.592037 8.142769 57.653999 -v -30.780039 9.085149 55.154099 -v 14.530680 17.064838 -14.843183 -v 73.903358 0.437117 -16.405600 -v 65.153702 0.576276 -22.030380 -v 79.528137 0.788678 -12.655760 -v 20.467960 12.335239 -1.718682 -v 17.655560 8.843440 -0.156241 -v 18.593021 9.641780 0.781218 -v 30.155079 27.802086 22.030376 -v 31.092539 23.931866 21.405416 -v 29.530102 21.668705 20.467957 -v 31.405020 27.868004 22.655357 -v -75.153320 17.343752 -47.341904 -v -75.778297 13.964872 -46.404442 -v -74.215858 13.432033 -45.466984 -v -73.278381 20.057381 -4.843563 -v -77.028244 19.067379 -15.155663 -v -75.153320 21.245117 -15.780643 -v -76.403259 14.616117 -17.968042 -v -75.778297 20.620117 -13.593224 -v 3.593600 7.175372 73.590881 -v 42.654579 8.579788 55.154099 -v 38.279758 12.191209 55.154095 -v 40.779663 16.704128 57.653996 -v -69.841019 24.671598 -9.530884 -v -69.528542 23.700539 -8.593424 -v -68.278580 21.923199 -9.218384 -v -48.904339 4.667428 -68.903564 -v -44.217018 3.722609 -68.903564 -v -73.590881 12.525671 -56.404045 -v -32.654980 12.824739 -10.780822 -v -33.904919 16.051039 -11.405804 -v -32.654980 11.158498 -9.530882 -v -33.904919 13.352078 -10.468342 -v 74.528343 10.241753 79.528137 -v 79.840637 6.951972 79.840637 -v -68.278580 2.526944 26.092739 -v -69.216042 2.616664 23.592819 -v -65.153702 5.264368 53.904144 -v -61.403862 5.858229 55.154099 -v -71.090981 5.869229 56.091560 -v -59.528919 5.333328 52.654198 -v -61.716343 7.468329 57.966480 -v -57.653999 7.015449 57.029018 -v -46.404438 12.082570 63.903759 -v -47.654400 12.674610 64.216240 -v -46.716919 8.901430 60.153900 -v 7.655960 5.194149 -66.716141 -v 18.280540 12.539087 -78.278198 -v 10.780820 7.740527 -79.528137 -v 20.155460 15.093389 -76.403259 -v 67.028641 10.366271 71.403458 -v 65.153702 13.147012 72.965897 -v 57.653999 12.374931 67.966095 -v 60.153900 9.592952 67.653595 -v 54.529118 8.860531 63.591263 -v 62.028816 6.572351 63.903763 -v 32.029999 10.722089 -61.716343 -v 72.028442 6.831123 16.405598 -v -46.716919 1.917201 6.718480 -v -45.154480 1.035262 10.155860 -v -28.905121 9.221848 -72.965897 -v -35.154881 4.511790 -64.528740 -v -65.778679 2.556244 21.717899 -v -67.028641 3.598103 17.655560 -v -69.841019 3.454064 25.467760 -v -19.842979 6.489327 46.091961 -v -20.780439 8.030468 46.716919 -v -19.842979 7.463448 47.341900 -v -53.591660 9.193770 -55.779079 -v -56.404041 12.437772 -53.591663 -v 27.030201 12.896157 -19.842981 -v 31.405020 8.930717 -17.655561 -v 28.905121 9.359797 -21.092922 -v -73.903358 19.931637 -15.468143 -v -72.340919 23.020618 -14.843184 -v -71.715958 19.647818 -15.468143 -v -74.528343 20.809317 -13.905704 -v 31.717520 21.433105 26.717697 -v 15.155660 3.696373 -41.092140 -v 17.655560 6.450253 -40.467182 -v 14.218201 2.760694 -37.654778 -v 19.218000 8.914233 -40.154682 -v 22.342880 13.684716 -22.967863 -v 22.030380 18.563856 -22.030384 -v 23.592819 14.221836 -22.655363 -v -20.780439 12.742970 58.903957 -v -20.780439 14.364670 60.778877 -v -67.341118 20.828238 -8.905904 -v -67.653595 28.786579 -9.843365 -v -65.778679 20.430292 -49.529324 -v -21.092920 13.229410 63.278774 -v -24.530300 14.885291 65.466202 -v 33.904919 15.263083 23.280336 -v -62.028816 12.874811 72.340919 -v -66.716141 9.927432 73.590881 -v -64.841217 7.847972 76.403259 -v 2.656140 11.454518 -10.468342 -v -75.465797 13.488196 -18.905523 -v -74.840820 16.054096 -18.593023 -v 17.655560 16.165798 -12.343263 -v 18.280540 19.297480 -11.405804 -v 18.593021 18.004778 -13.280743 -v -72.028442 7.292550 58.591461 -v -35.467361 15.524919 -10.468343 -v -36.717319 11.453299 -7.655962 -v -34.529900 11.859779 -7.655962 -v -36.717319 13.977078 -11.405803 -v 44.841999 3.512666 34.217419 -v -65.778679 8.269096 -24.842781 -v -63.278778 11.702316 -24.217802 -v -62.341316 9.432416 -25.467762 -v -64.216240 9.435476 -22.342882 -v -62.341316 12.366977 -23.905321 -v -60.466381 10.242355 -25.155262 -v -17.343081 12.181452 68.591080 -v -19.842979 12.900431 65.778679 -v -20.780439 12.280931 68.278580 -v -15.780640 11.231130 67.028641 -v -16.093121 11.727950 64.216240 -v 13.593220 4.718110 62.653801 -v 15.155660 4.498369 58.903961 -v 10.468340 4.969569 59.841419 -v 15.780640 6.290370 65.153702 -v 16.718100 5.909510 60.153900 -v 2.656140 4.910970 62.653801 -v -63.903763 16.643078 -7.343462 -v -66.091179 16.907978 -7.343462 -v -61.403862 9.381760 -2.031181 -v -65.466202 21.080318 -8.280924 -v -63.591263 24.255959 -9.530884 -v -66.403664 18.009659 -7.968443 -v -51.091763 0.701403 16.093121 -v 18.280540 6.532660 2.968639 -v 18.280540 4.062582 7.655959 -v 21.717899 8.216002 3.593599 -v 21.092920 11.369680 0.156238 -v -0.468740 6.124936 -22.030382 -v -0.156240 3.778756 -24.530300 -v 25.780239 13.340485 23.280336 -v 26.405220 17.171644 22.655359 -v 41.092140 14.122331 -49.841805 -v 37.029800 10.770912 -52.654198 -v 27.655161 10.494431 -57.029018 -v 29.530102 10.808152 -55.466579 -v 29.217621 9.732712 -54.216644 -v 29.842579 7.975512 -49.216820 -v 32.654980 8.501031 -49.841801 -v 32.029999 9.042411 -52.966682 -v 27.967661 9.422651 -51.716736 -v 32.967461 17.578144 20.780436 -v 31.717520 24.177843 21.717896 -v 34.842381 14.995143 18.905519 -v 31.717520 20.141005 18.905518 -v 30.780039 24.857763 19.842976 -v 33.904919 3.621913 79.528137 -v 39.842201 3.015233 79.840637 -v 2.343660 15.885638 -13.593223 -v 0.156240 20.225819 -13.905704 -v 55.779079 11.820108 -69.528542 -v 54.841599 7.536068 -70.465996 -v 56.716541 11.860989 -69.216042 -v 56.091560 11.638209 -70.778481 -v 65.778679 6.308047 -78.590683 -v 60.466381 5.340027 -79.528137 -v -71.090981 17.968132 -52.341702 -v -71.403458 22.466413 -51.404240 -v -69.216042 18.804932 -51.404240 -v 67.653595 7.401168 -75.465797 -v 66.403664 8.308768 -76.715759 -v 74.528343 4.119966 33.904919 -v 76.090782 7.185126 33.904919 -v 75.153320 4.665006 35.779861 -v 32.654980 7.243107 44.841999 -v -60.153900 3.075028 -71.090981 -v -55.779079 4.444028 -75.153320 -v -57.341499 3.163528 -75.153320 -v 27.967661 19.197405 31.717516 -v 64.841217 12.985250 -62.653805 -v 63.591263 13.589490 -63.903767 -v 61.716343 13.439970 -61.091366 -v 65.778679 14.954230 -62.028820 -v 64.841217 12.785069 -63.591267 -v 77.653221 7.503127 48.279362 -v 77.028244 7.527528 50.154301 -v 79.528137 8.678648 47.341900 -v 79.215660 7.835768 46.404438 -v -71.090981 29.918158 -9.530885 -v -46.091961 3.183073 79.528137 -v -50.466782 3.601173 79.528137 -v -50.466782 3.922833 78.903160 -v 64.528740 14.653950 -64.528740 -v 62.966278 13.674331 -58.278984 -v -75.465797 20.017078 -9.843363 -v -76.403259 19.526978 -11.405804 -v -18.280540 9.138247 46.091961 -v -18.593021 10.040349 49.841801 -v -17.030581 9.674748 50.466782 -v 31.717520 11.248211 -59.841419 -v 29.217621 12.240010 -59.528923 -v 28.905121 14.559360 -0.156242 -v 28.280140 17.261360 -3.281123 -v 26.405220 14.520901 -0.156242 -v 29.217621 15.343660 1.093698 -v 30.780039 15.493179 -0.781222 -v 14.843180 4.862145 31.717520 -v -6.718480 3.222741 4.843559 -v -74.528343 3.358845 32.967461 -v -78.590683 7.640446 37.654778 -v -13.280740 7.108849 56.091560 -v -9.530880 7.702709 59.841419 -v -14.843180 9.306088 54.841599 -v -17.030581 9.090029 55.154099 -v -16.718100 11.835990 57.341496 -v 19.842979 25.288057 -14.530684 -v 27.030201 17.332785 21.405418 -v -74.528343 21.072998 -12.968244 -v 18.593021 5.413272 -47.029419 -v -70.153519 13.246491 -54.216648 -v -67.653595 14.652731 -52.654202 -v -36.717319 6.395953 74.840820 -v -33.279961 7.205893 76.090782 -v -35.467361 8.418032 71.715958 -v 33.592442 7.332818 -16.718102 -v 33.592442 8.670718 -13.905702 -v 37.029800 6.772518 -15.468141 -v 62.653801 5.868587 -75.153320 -v 71.403458 7.996868 -73.590881 -v 61.091362 5.210027 -78.278198 -v -15.155660 13.875173 75.153320 -v -9.843360 13.641393 75.778297 -v -51.716736 18.944698 -17.030584 -v -53.279182 14.859636 -17.030582 -v -54.841599 13.258697 -22.655363 -v 70.153519 10.587809 -69.528542 -v -25.467760 2.806481 4.531080 -v -22.655361 1.346521 8.593420 -v 76.403259 10.686084 20.467958 -v 74.528343 9.330503 21.405418 -v 75.465797 9.771784 22.342878 -v -27.655161 10.813653 73.278381 -v -26.405220 13.953892 71.090981 -v -27.342680 12.918752 70.153519 -v -24.530300 11.668151 71.403458 -v -30.155079 10.274712 72.653419 -v -26.092739 16.223171 69.528542 -v 56.716541 15.291772 -54.216648 -v 54.529118 17.191771 -56.091564 -v 55.154099 13.551651 -52.966686 -v 56.716541 16.364752 -57.029022 -v -72.028442 31.873093 -48.279366 -v -56.091560 21.281118 -7.968443 -v -59.528919 12.014199 -2.656142 -v -60.153900 20.184937 -7.655963 -v -62.028816 13.427758 -5.781023 -v 36.717319 8.988700 -0.781221 -v 34.529900 12.440220 2.031178 -v 38.904739 9.200501 2.968639 -v 18.905521 14.248668 -73.278381 -v 17.343081 13.190948 -75.778297 -v -27.342680 3.543180 0.156239 -v 1.406200 10.321689 -74.528343 -v 39.842201 12.587931 62.028812 -v 37.967258 14.484290 60.153896 -v 36.404819 9.186470 63.903763 -v 31.405020 14.392124 30.155077 -v 29.530102 17.888206 32.029995 -v 29.530102 20.787964 29.217617 -v 29.842579 14.972567 33.279957 -v 18.905521 5.154510 58.278980 -v 18.593021 5.264369 61.091362 -v 25.467760 6.229930 62.341316 -v 77.965698 6.936106 36.717319 -v 76.403259 7.540966 36.404819 -v 77.340744 5.681226 38.592239 -v 51.404236 2.743002 14.530680 -v 55.779079 2.353003 17.343081 -v 54.529118 2.352384 21.717899 -v 57.029018 3.399144 23.592819 -v -10.468340 7.642879 -3.593601 -v -70.153519 7.433541 3.906099 -v 23.905319 7.612354 -37.967258 -v -46.091961 15.701319 -8.905903 -v -47.341900 16.099258 -9.530883 -v -47.341900 21.162718 -8.593424 -v -44.217018 14.478778 -9.218382 -v -30.155079 12.299850 60.153896 -v -28.592640 12.151529 58.591457 -v -31.092539 10.585389 58.903961 -v -29.842579 16.481970 61.403858 -v -28.280140 13.895910 61.091358 -v 39.842201 19.472042 7.343456 -v -23.905319 11.179248 52.966682 -v -33.592442 8.097599 -6.093522 -v 27.655161 33.002258 -7.655965 -v 29.217621 18.385620 -3.593603 -v 30.155079 19.900520 -5.468544 -v 58.903961 4.987253 -44.529499 -v 57.029018 6.071833 -44.217018 -v 59.528919 3.436973 -41.404640 -v 57.029018 9.835253 -48.591862 -v -25.780239 15.687892 67.966095 -v -23.280338 13.560230 67.028641 -v 37.029800 7.778989 -65.466202 -v 25.780239 16.384895 -21.092922 -v 26.092739 12.594637 -21.717901 -v 56.404041 12.519571 69.528542 -v 55.779079 9.834051 72.965897 -v 60.778881 12.471372 70.778481 -v 51.404236 10.568292 71.715958 -v 50.154301 6.893393 75.465797 -v 72.340919 5.253982 8.280919 -v 72.028442 7.060001 10.468339 -v 68.591080 4.182202 11.405800 -v 68.903564 4.922562 16.093121 -v 65.153702 3.644502 12.030780 -v 66.091179 4.359822 16.093121 -v 63.591263 3.076861 8.593419 -v -68.591080 12.534231 72.653419 -v -70.778481 9.082092 74.528343 -v -58.278980 12.484171 68.591080 -v -69.216042 13.204391 70.465996 -v 40.467182 6.338574 -35.154881 -v 39.842201 6.055353 -39.842201 -v -52.341698 3.146447 45.154480 -v -60.778881 4.135209 -67.653595 -v -61.403862 6.444770 -65.153702 -v -60.778881 5.828310 -62.653801 -v -64.528740 4.912169 -66.091179 -v -5.781020 14.601447 -78.278198 -v -3.281120 13.486348 -77.965698 -v -5.468540 15.071426 -79.528137 -v -54.216644 11.839051 64.528740 -v -51.716736 9.292049 61.403862 -v -55.466579 9.524590 61.403862 -v -53.904144 11.214650 66.403664 -v -54.216644 7.743609 58.591461 -v -54.529118 6.482008 53.591660 -v -48.904339 7.204669 55.466579 -v 16.405600 14.703387 -74.215858 -v 15.468140 12.584247 -73.278381 -v 52.341698 1.806748 47.654400 -v 56.716541 0.966287 43.592037 -v -8.280920 7.467110 61.403862 -v -11.093320 11.225029 61.091362 -v 57.029018 6.388608 -77.653221 -v 56.716541 7.390807 -79.528137 -v 55.154099 5.327207 -78.903160 -v 22.342880 15.339380 0.156237 -v 22.655361 15.612201 -2.031183 -v 23.905319 14.522739 -1.718682 -v 22.655361 19.482420 -3.593603 -v -18.280540 2.889488 -69.841019 -v -18.905521 5.007388 -74.528343 -v -71.403458 29.501293 -47.966885 -v -62.028816 14.939593 -41.404644 -v 26.405220 15.869159 -3.281123 -v -46.404438 4.362875 -25.780239 -v -48.904339 4.658895 -31.717520 -v 46.091961 13.103070 62.028812 -v 46.404438 13.449149 60.778877 -v 47.654400 15.348551 64.216240 -v 48.904339 11.539351 62.653801 -v 51.091763 10.872251 62.028816 -v 49.841801 7.387149 58.903961 -v 46.091961 11.226250 60.153900 -v -54.841599 13.331352 69.841019 -v 53.279182 7.723453 -46.716919 -v 53.279182 5.994933 -44.217018 -v -48.904339 13.502239 -6.093523 -v -46.716919 11.951940 -5.781022 -v -45.779461 17.243658 -7.030983 -v -44.529499 8.670719 -4.531082 -v -57.029018 14.674697 -21.717901 -v 11.093320 9.634449 -68.903564 -v 67.341118 12.701472 77.965698 -v 64.216240 8.822692 68.591080 -v -12.030781 3.391196 -21.717899 -v 68.903564 9.595990 -57.966480 -v 71.715958 7.925471 -56.716541 -v 19.842979 8.278251 -60.778881 -v 23.280338 10.860646 40.154682 -v 26.092739 11.132247 42.967079 -v 65.153702 5.761183 17.030581 -v 67.341118 4.979323 17.968040 -v 9.218380 6.665716 -23.905321 -v 13.593220 8.374696 -24.217802 -v 8.905900 4.881056 -25.467760 -v 9.530880 10.785556 -22.030382 -v -67.653595 18.408218 -8.280923 -v -68.903564 27.492018 -10.468345 -v -69.841019 29.889479 -10.155865 -v 75.778297 12.414583 18.593019 -v 78.590683 9.997002 14.218199 -v 74.528343 9.967703 17.968039 -v 73.903358 12.002003 18.905519 -v 66.403664 3.408283 21.405420 -v -58.278980 10.066589 59.841419 -v 52.029221 10.673270 65.153702 -v 52.341698 10.363830 61.716343 -v 52.029221 7.634350 60.153900 -v 52.029221 5.160609 57.029018 -v 46.091961 4.891448 52.341698 -v 27.342680 9.217571 -53.904144 -v 27.342680 10.734912 -52.341698 -v -44.529499 3.590167 -79.528137 -v -55.779079 4.714427 -78.590683 -v -52.029221 4.069887 -77.965698 -v 17.655560 10.443769 -69.528542 -v 8.280920 2.126551 -57.341499 -v -3.906100 0.829551 -57.029018 -v 65.153702 5.623870 62.341316 -v 12.655760 5.431606 37.654778 -v -46.091961 8.101851 -53.591660 -v -14.843180 11.727351 62.653797 -v -16.093121 17.105730 61.091358 -v 70.153519 7.511663 19.217999 -v 41.717117 4.661944 27.655161 -v -55.154099 13.818392 -47.341904 -v -55.154099 17.951674 -46.404442 -v -57.653999 20.355831 -47.029423 -v -54.841599 14.118672 -45.154484 -v -53.591660 14.772352 -44.217022 -v -7.968440 9.404371 71.715958 -v -44.217018 10.007371 -58.903961 -v -43.592037 14.340230 -58.903965 -v 6.718480 9.852339 -11.718303 -v 8.280920 13.407618 -17.343082 -v 4.843560 8.309378 -8.905901 -v -27.655161 11.400189 56.404041 -v -24.530300 17.939470 57.341496 -v 20.155460 17.152716 -20.780441 -v -1.718680 21.172480 -8.905904 -v 42.029602 3.817852 76.715759 -v 48.591862 4.699193 79.528137 -v 38.279758 5.048306 38.279758 -v -61.403862 1.514385 32.654980 -v -65.778679 3.090307 39.217220 -v -45.779461 3.451007 -78.903160 -v -55.466579 6.231128 -77.340744 -v -0.156240 11.499667 -79.840637 -v -39.529701 12.246751 66.091179 -v 38.592239 7.720393 -43.592037 -v -68.278580 28.400839 -12.655765 -v 13.905701 11.242088 -71.715958 -v 14.218201 14.346328 -73.590881 -v 12.343260 11.751129 -72.965897 -v 9.843360 8.410687 -77.028244 -v 12.030781 14.313987 -75.465797 -v 15.155660 16.129169 -74.215858 -v -73.903358 12.933376 -18.593023 -v -73.903358 16.156019 -16.718102 -v -73.903358 10.398597 -20.467962 -v 35.154881 5.728207 -78.278198 -v 32.342480 8.507728 -75.465797 -v 32.967461 7.742368 -72.965897 -v 30.780039 7.859547 -79.528137 -v -78.903160 17.933979 -16.093124 -v 10.155860 1.745074 -36.092342 -v 78.278198 9.986021 6.093519 -v 79.215660 9.928022 9.218378 -v 79.528137 9.773621 4.843558 -v -13.905701 1.352025 30.467560 -v -14.843180 2.519006 35.779861 -v -10.155860 0.653784 21.405420 -v -4.218580 0.570784 23.905319 -v 25.155260 7.037415 -34.842381 -v 25.155260 12.548857 -22.342882 -v 21.092920 6.315975 -30.155081 -v 27.030201 8.396656 -24.530302 -v -66.716141 32.933281 -11.093326 -v 20.467960 21.089478 -13.280744 -v 49.216820 13.750650 67.028641 -v 48.591862 9.820612 69.528542 -v 49.841801 12.520810 65.466202 -v 51.716736 13.799491 66.716141 -v 42.029602 11.618710 57.341499 -v 44.217018 8.743349 57.029018 -v 40.467182 6.542428 50.779263 -v -33.904919 14.009430 63.591259 -v -33.279961 17.955351 66.403664 -v 5.468540 2.141206 38.592239 -v 10.468340 3.180626 37.967258 -v 10.468340 3.209926 37.029800 -v 51.404236 7.235781 5.156039 -v 47.029419 2.880335 -29.530102 -v 44.217018 4.246294 -35.467361 -v 45.154480 8.522392 -45.466980 -v 51.091763 8.497373 -47.029419 -v 45.779461 11.629072 -47.966881 -v 43.592037 6.169493 -41.404640 -v 54.529118 3.162314 -36.717319 -v 42.967079 9.115652 -45.779461 -v 27.967661 8.855650 58.903961 -v 29.842579 8.550489 60.778881 -v 27.342680 8.402168 54.216644 -v 22.967861 6.331869 55.154099 -v 25.467760 8.379588 49.841801 -v -55.466579 12.553751 67.653595 -v 75.153320 4.151086 38.279758 -v 76.090782 4.126667 42.654579 -v -2.656140 11.917747 -79.215660 -v 75.778297 6.925128 52.029221 -v 73.590881 4.238988 50.466782 -v 74.840820 8.862369 53.591660 -v 77.028244 7.372508 53.904144 -v 15.155660 13.328268 -75.465797 -v 15.155660 13.188507 -77.340744 -v 53.591660 15.496230 -58.903965 -v 8.905900 6.354440 3.906099 -v 34.529900 14.533110 58.591457 -v 37.654778 17.302271 57.966476 -v 39.529701 14.813270 58.278976 -v 46.091961 16.433731 -49.841805 -v 49.841801 12.672152 -48.904343 -v 54.216644 3.173924 26.092739 -v 49.529320 2.595304 21.717899 -v 54.529118 1.539405 28.905121 -v -16.718100 2.246181 4.531080 -v 76.403259 15.864869 -62.028820 -v -17.343081 8.136647 -78.278198 -v 78.903160 13.885528 49.841797 -v -62.341316 9.713813 75.465797 -v 23.280338 10.853921 3.593598 -v 32.967461 16.339739 5.468537 -v -63.903763 14.078991 -52.029224 -v -65.466202 15.928971 -52.341702 -v -64.216240 16.074232 -50.154305 -v -39.529701 6.967219 -3.593601 -v 73.590881 6.262888 53.904144 -v 16.093121 17.036757 -18.593023 -v -12.343260 8.583449 59.841419 -v -10.780820 3.191001 3.906100 -v 62.341316 11.287869 -64.841217 -v 59.528919 11.555809 -64.841217 -v 67.028641 17.459108 -65.153702 -v 59.841419 11.730989 -66.716141 -v 26.717701 25.424780 -7.343464 -v 24.217800 20.767818 -6.093524 -v 67.341118 15.302129 -63.903767 -v -33.592442 1.140846 35.154881 -v -32.029999 2.652066 39.529701 -v -27.030201 1.292826 34.842381 -v -40.154682 1.876326 40.154682 -v -24.842779 1.970926 39.217220 -v 45.779461 2.929165 27.967661 -v -60.778881 17.427996 -22.967863 -v -61.403862 13.439356 -22.342882 -v 40.154682 11.308641 5.468538 -v -52.029221 22.739239 -16.093124 -v 73.590881 10.576223 22.967859 -v -65.778679 8.853821 5.468539 -v 9.843360 20.986937 -20.467964 -v 23.592819 19.635616 -18.905525 -v 23.592819 22.228374 -20.467964 -v 22.030380 18.485117 -18.280544 -v -20.467960 9.810252 76.090782 -v 59.528919 15.481590 -58.278984 -v 58.591461 15.944831 -54.529121 -v -60.466381 15.955215 -35.154884 -v 79.528137 13.798862 11.093318 -v 79.840637 4.584420 0.156239 -v 78.903160 9.367122 3.593599 -v -70.465996 19.378653 -45.779465 -v -71.715958 14.104033 -43.904541 -v 18.593021 23.836657 -18.280544 -v 15.780640 23.427717 -17.343084 -v 39.842201 4.015567 -79.840637 -v 43.904537 17.885750 -56.404045 -v 44.217018 19.222410 -57.654003 -v 45.466980 34.381031 -51.404240 -v 33.904919 23.066401 13.280736 -v 34.529900 23.834822 12.343256 -v 33.592442 21.639402 12.655756 -v 34.217419 23.786001 15.780636 -v 36.404819 16.810923 13.280737 -v 79.528137 9.814488 -72.653419 -v -62.653801 16.325693 -51.404240 -v -74.215858 5.519468 -74.840820 -v -79.528137 6.539368 -75.778297 -v 16.718100 10.805719 -6.406002 -v 8.905900 15.144676 -20.780441 -v 2.031180 3.406456 -25.780239 -v 17.655560 3.007283 21.092920 -v 32.342480 15.084860 2.031178 -v 32.342480 17.196060 3.906097 -v 5.468540 14.127828 -74.215858 -v 15.780640 18.150627 -74.528343 -v -71.403458 30.317938 -14.530684 -v 16.093121 8.864190 -64.216240 -v -77.965698 18.354498 -8.593423 -v -52.029221 9.411072 68.591080 -v 45.466980 22.233871 -50.779266 -v 44.529499 14.013092 -49.216824 -v 35.154881 17.272362 6.718477 -v -67.341118 19.383533 -50.154305 -v -67.653595 20.620111 -51.091766 -v -70.778481 23.158552 -49.841805 -v -71.403458 28.858593 -48.904343 -v -69.528542 23.385593 -47.029423 -v 28.905121 21.156618 -12.343264 -v -25.155260 5.573197 -16.405600 -v -27.967661 7.832697 -14.218202 -v 19.530479 15.206318 -10.780823 -v 18.905521 14.708279 -10.155863 -v 17.343081 13.801918 -10.468342 -v 17.968040 16.174337 -9.530883 -v -59.216442 20.100693 -46.716923 -v -58.278980 23.922092 -47.654404 -v 30.467560 14.376238 -11.718303 -v 28.592640 26.693077 -12.655765 -v 44.529499 4.917688 50.466782 -v 61.403862 2.301724 23.905319 -v 30.155079 12.866848 -69.841019 -v 27.342680 11.859168 -71.403458 -v 29.530102 11.003448 -72.653419 -v 21.405420 20.666496 -20.780443 -v -43.592037 7.192449 53.591660 -v -7.030980 5.473700 1.093699 -v -7.343460 5.482861 3.593599 -v -1.406200 25.210539 -9.843364 -v 2.031180 9.736999 -7.030982 -v -27.655161 12.455489 53.904140 -v 28.280140 26.141317 -8.905904 -v -74.840820 7.379233 79.215660 -v -76.090782 9.788272 74.215858 -v -79.840637 9.467233 79.840637 -v -24.217800 2.058196 -25.467760 -v -17.343081 2.400596 -23.280338 -v -48.279362 8.579152 -44.529499 -v -52.341698 10.905792 -44.217018 -v 23.592819 16.655300 -3.593603 -v -78.278198 21.859129 63.278774 -v -75.153320 14.543490 66.091179 -v 13.905701 2.283433 79.528137 -v 37.967258 9.055243 19.217999 -v 37.029800 8.020079 -4.843561 -v -2.031180 15.693998 -3.281123 -v -13.280740 9.991510 62.028816 -v 55.466579 19.942011 -57.654003 -v 57.653999 16.403811 -53.279186 -v 53.591660 15.129410 -57.029022 -v 55.466579 17.973631 -59.216446 -v 33.279961 10.897870 -56.716541 -v -32.967461 11.978811 70.153519 -v 57.653999 11.531411 -51.404236 -v 49.841801 19.152832 -51.091766 -v -17.968040 14.835252 73.278381 -v -17.030581 13.178152 74.840820 -v 41.717117 8.653018 -13.593221 -v 43.592037 5.497517 -16.405600 -v -53.904144 6.697468 50.154301 -v -51.091763 8.945369 51.404236 -v -57.653999 6.491768 48.279362 -v -72.340919 23.640112 -49.529324 -v -26.092739 2.459791 -54.529118 -v -21.092920 1.567470 -61.091362 -v -29.530102 2.595290 -59.841419 -v -20.467960 1.140831 -53.279182 -v 79.215660 9.067449 53.591660 -v 79.528137 13.378948 50.154297 -v 78.590683 8.288649 55.154099 -v -59.841419 4.502648 45.779461 -v -61.403862 4.825527 43.904537 -v -57.341499 4.120568 45.779461 -v 70.153519 0.654398 -9.843360 -v 39.217220 14.022249 59.841415 -v 79.840637 7.363967 40.154682 -v 19.530479 7.169853 -40.779663 -v 24.217800 11.339154 -35.779861 -v -73.903358 23.217152 65.153702 -v 31.717520 22.434683 16.093117 -v 4.531080 0.727642 13.593220 -v 30.467560 11.840847 -73.903358 -v -74.215858 24.709448 63.903759 -v -42.654579 7.034973 -43.279564 -v -43.592037 10.971712 -44.529499 -v 66.716141 1.903780 2.031180 -v -73.590881 20.679918 -6.093524 -v -75.465797 25.523039 -7.030984 -v 55.779079 2.057575 -32.029999 -v -79.528137 17.100231 -59.528923 -v 36.092342 12.877850 56.404037 -v -70.465996 26.642418 -14.530684 -v -69.841019 23.166479 -13.593224 -v 39.217220 17.297382 11.718298 -v 38.592239 15.607942 12.030778 -v -50.466782 7.467091 -56.716541 -v -16.093121 5.919887 41.404640 -v 23.280338 23.585176 -7.030984 -v -32.342480 7.498848 47.966881 -v 40.467182 18.027363 9.530877 -v -44.529499 3.650595 -32.654980 -v -47.029419 5.272893 -38.904739 -v 51.091763 3.810487 -78.278198 -v 6.406000 10.517632 74.840820 -v 58.591461 18.918449 -58.591465 -v 40.779663 17.856470 58.591457 -v 24.842779 16.843279 0.156237 -v -26.405220 16.904331 65.778679 -v -25.155260 18.762232 66.091179 -v -26.717701 14.028971 62.653797 -v -21.405420 15.022611 65.153702 -v -44.529499 9.946332 -45.779461 -v -45.154480 7.705753 -43.904537 -v -1.093700 5.742270 64.841217 -v 67.653595 14.776629 -66.091179 -v -44.529499 16.122458 -7.343462 -v -41.404640 7.174139 -3.593601 -v -79.528137 10.358313 -44.841999 -v 61.091362 1.435640 -3.281120 -v -61.403862 13.949614 -36.717323 -v -73.590881 12.022751 69.841019 -v -75.778297 10.872252 68.591080 -v -9.530880 11.923272 77.965698 -v -50.779263 7.995053 -42.029602 -v 73.278381 1.543059 -3.281120 -v 20.780439 13.011489 -61.716347 -v 67.966095 16.373314 79.528137 -v 32.654980 22.449322 14.843176 -v 36.092342 13.722564 16.718098 -v 34.217419 20.729364 17.655556 -v 32.967461 28.552822 13.905696 -v 31.717520 22.039782 14.218197 -v -4.531080 9.792552 73.590881 -v -59.216442 20.259394 -35.467365 -v -57.029018 15.797754 -35.154884 -v -59.528919 18.383795 -36.404823 -v 32.029999 17.558603 27.655159 -v 68.591080 4.325649 56.091560 -v 55.779079 18.980091 -60.153904 -v -78.903160 17.536013 -49.529324 -v 8.280920 14.771756 -19.218002 -v 62.653801 3.776323 18.905521 -v 60.466381 3.061602 15.155659 -v -67.653595 8.510801 3.906099 -v -68.903564 10.949141 2.968638 -v -77.340744 24.241320 -8.905904 -v -54.529118 11.553374 -42.967079 -v 58.903961 3.446742 11.405800 -v -74.840820 23.324560 -13.593224 -v 61.716343 10.495673 74.840820 -v 32.342480 28.280602 13.280735 -v 79.528137 13.284350 64.841217 -v 16.093121 11.403239 -5.156042 -v -76.090782 11.670568 -71.715958 -v 79.528137 2.451259 -3.281121 -v 23.592819 12.656280 1.093698 -v 17.655560 4.381794 -35.154881 -v -42.342102 10.631151 -53.904144 -v -44.217018 9.450110 -57.341499 -v -69.841019 6.665733 78.903160 -v -76.403259 18.236698 -7.030983 -v -77.653221 16.540539 -7.655962 -v -75.778297 21.612537 -7.655963 -v 32.967461 6.423397 -21.405422 -v -79.215660 5.951009 55.779079 -v -43.279564 11.576571 -57.653999 -v -6.093520 16.708387 -78.903160 -v 9.843360 18.503416 -18.593025 -v -20.780439 11.347712 72.340919 -v -55.466579 10.761754 -40.779663 -v 27.342680 11.351988 46.404438 -v 4.218580 9.576459 -6.718482 -v 63.278778 0.839947 39.842201 -v -61.716343 23.092632 -46.716923 -v -70.465996 4.517906 36.092342 -v -70.465996 25.890472 -46.716923 -v -28.592640 11.295232 74.528343 -v 50.779263 4.047307 -79.528137 -v 43.592037 10.226478 -12.968242 -v 40.154682 4.604557 -20.467960 -v 47.341900 23.754253 -51.091766 -v 61.716343 6.143262 11.718300 -v 65.153702 11.439274 79.528137 -v 78.590683 15.463282 11.718298 -v -29.217621 8.496167 46.091961 -v -78.590683 7.388989 58.591461 -v -75.778297 6.478950 57.341499 -v -78.903160 18.748190 63.278774 -v -76.090782 21.032093 -48.591866 -s 1 -f 1 2 3 -f 1 4 2 -f 5 6 7 -f 5 8 9 -f 5 10 11 -f 6 12 7 -f 13 14 15 -f 13 16 17 -f 15 18 19 -f 15 14 18 -f 20 21 22 -f 20 23 24 -f 25 26 27 -f 25 28 29 -f 26 30 31 -f 25 27 32 -f 33 34 35 -f 33 36 37 -f 38 39 40 -f 38 41 42 -f 39 42 43 -f 38 40 41 -f 44 45 46 -f 44 47 45 -f 48 49 50 -f 48 51 52 -f 52 51 53 -f 48 54 49 -f 52 55 56 -f 51 57 58 -f 59 60 61 -f 59 62 60 -f 63 64 65 -f 63 66 67 -f 64 68 69 -f 63 65 70 -f 64 69 71 -f 68 72 73 -f 74 35 75 -f 74 76 77 -f 78 79 80 -f 78 81 82 -f 82 83 84 -f 82 79 78 -f 82 81 83 -f 78 80 85 -f 86 87 88 -f 86 89 90 -f 91 92 93 -f 91 94 95 -f 91 93 96 -f 92 95 97 -f 98 99 100 -f 98 101 99 -f 102 103 104 -f 102 105 106 -f 107 108 109 -f 107 110 111 -f 112 113 114 -f 112 115 113 -f 116 117 118 -f 116 119 117 -f 120 121 122 -f 120 123 124 -f 125 126 127 -f 125 128 129 -f 126 129 130 -f 125 131 132 -f 133 134 135 -f 133 136 137 -f 138 139 140 -f 138 141 142 -f 143 144 145 -f 143 146 144 -f 147 148 149 -f 147 150 148 -f 148 151 149 -f 148 150 152 -f 153 154 155 -f 153 156 157 -f 158 159 160 -f 158 161 162 -f 163 164 165 -f 163 166 167 -f 168 169 170 -f 168 171 172 -f 173 174 175 -f 173 176 177 -f 178 176 173 -f 178 179 180 -f 180 176 178 -f 180 181 182 -f 178 183 184 -f 176 182 177 -f 185 186 187 -f 185 188 189 -f 190 191 192 -f 190 193 191 -f 194 195 160 -f 194 192 195 -f 196 197 198 -f 196 199 200 -f 201 200 202 -f 201 197 196 -f 203 197 201 -f 203 204 198 -f 203 205 206 -f 196 198 199 -f 207 208 209 -f 207 210 211 -f 212 213 214 -f 212 208 215 -f 208 216 209 -f 208 217 215 -f 218 219 220 -f 218 221 222 -f 223 224 225 -f 223 226 224 -f 227 228 229 -f 227 230 12 -f 231 230 232 -f 231 233 234 -f 230 235 7 -f 231 232 233 -f 236 237 238 -f 236 239 240 -f 239 241 242 -f 239 238 241 -f 243 244 245 -f 243 246 247 -f 243 247 244 -f 246 248 249 -f 250 251 252 -f 250 253 254 -f 253 255 254 -f 253 250 256 -f 257 258 259 -f 257 260 258 -f 261 262 263 -f 261 264 265 -f 266 267 268 -f 266 269 270 -f 267 271 268 -f 267 270 272 -f 273 274 275 -f 273 276 274 -f 277 278 279 -f 277 280 281 -f 282 283 284 -f 282 285 286 -f 287 288 289 -f 287 290 291 -f 290 292 293 -f 287 291 294 -f 295 296 297 -f 295 298 299 -f 300 301 302 -f 300 298 303 -f 295 299 304 -f 300 303 305 -f 306 307 308 -f 306 309 310 -f 311 124 4 -f 311 312 313 -f 314 315 316 -f 314 317 315 -f 318 319 320 -f 318 321 322 -f 318 322 319 -f 321 323 324 -f 325 326 327 -f 325 328 329 -f 158 160 195 -f 159 162 330 -f 205 201 331 -f 200 332 333 -f 333 202 200 -f 333 334 335 -f 203 201 205 -f 333 332 336 -f 337 338 339 -f 337 340 341 -f 338 341 342 -f 338 337 341 -f 339 342 343 -f 337 344 340 -f 337 339 345 -f 339 343 345 -f 346 347 348 -f 346 349 347 -f 347 349 350 -f 346 348 302 -f 351 352 353 -f 351 354 352 -f 355 356 357 -f 355 358 356 -f 359 360 98 -f 359 361 362 -f 363 364 365 -f 363 366 367 -f 368 369 370 -f 368 371 372 -f 373 374 375 -f 373 376 374 -f 377 378 379 -f 377 380 378 -f 378 380 381 -f 377 379 382 -f 383 384 385 -f 383 386 387 -f 388 389 390 -f 388 391 392 -f 393 394 395 -f 393 396 397 -f 398 399 358 -f 398 400 401 -f 400 402 403 -f 400 358 402 -f 324 404 322 -f 324 323 405 -f 404 406 322 -f 404 407 408 -f 406 409 322 -f 406 408 410 -f 411 412 413 -f 411 414 412 -f 415 416 417 -f 415 418 419 -f 420 419 421 -f 420 422 423 -f 417 416 420 -f 417 424 415 -f 419 425 426 -f 419 416 415 -f 417 423 427 -f 416 419 420 -f 428 429 430 -f 428 431 432 -f 433 434 435 -f 433 436 437 -f 438 439 440 -f 438 441 439 -f 442 443 272 -f 442 444 443 -f 184 183 445 -f 184 179 178 -f 446 447 448 -f 446 449 334 -f 447 334 450 -f 446 448 451 -f 452 326 325 -f 452 453 326 -f 454 455 456 -f 454 457 458 -f 459 460 461 -f 459 462 460 -f 463 464 465 -f 463 466 467 -f 463 465 468 -f 464 467 469 -f 470 14 17 -f 470 471 14 -f 472 473 474 -f 472 475 476 -f 477 478 479 -f 477 480 478 -f 481 482 483 -f 481 484 485 -f 484 481 486 -f 481 485 482 -f 487 488 489 -f 487 490 491 -f 490 492 493 -f 487 491 488 -f 494 495 496 -f 494 497 495 -f 498 499 500 -f 498 154 501 -f 502 503 504 -f 502 505 506 -f 507 508 504 -f 507 503 509 -f 509 510 508 -f 509 503 511 -f 503 502 506 -f 502 504 512 -f 513 166 514 -f 513 167 166 -f 515 516 517 -f 515 518 519 -f 515 517 520 -f 516 519 521 -f 522 523 524 -f 522 525 526 -f 523 526 527 -f 523 522 526 -f 528 529 530 -f 528 531 532 -f 533 534 535 -f 533 536 537 -f 536 538 539 -f 536 540 541 -f 541 538 536 -f 541 542 543 -f 538 541 539 -f 533 537 534 -f 229 228 544 -f 227 232 230 -f 228 12 6 -f 227 229 232 -f 545 546 547 -f 545 548 549 -f 550 551 552 -f 550 553 551 -f 554 555 556 -f 554 557 558 -f 559 557 554 -f 559 560 561 -f 554 558 555 -f 557 562 558 -f 563 564 565 -f 563 566 564 -f 567 76 568 -f 567 77 76 -f 569 570 571 -f 569 150 572 -f 573 574 575 -f 573 576 437 -f 577 578 579 -f 577 580 581 -f 582 580 577 -f 582 583 584 -f 580 584 585 -f 582 579 583 -f 165 521 519 -f 165 586 521 -f 521 587 516 -f 165 164 556 -f 186 588 187 -f 186 589 588 -f 590 591 592 -f 590 593 591 -f 594 595 596 -f 594 597 395 -f 598 367 599 -f 598 600 601 -f 367 601 363 -f 598 599 602 -f 603 604 605 -f 603 606 607 -f 608 609 179 -f 608 610 611 -f 612 613 614 -f 612 615 616 -f 617 618 619 -f 617 620 618 -f 621 622 623 -f 621 624 622 -f 625 626 627 -f 625 628 626 -f 629 241 630 -f 629 631 632 -f 633 634 635 -f 633 636 637 -f 638 639 640 -f 638 641 639 -f 53 642 643 -f 53 58 644 -f 645 646 407 -f 645 647 317 -f 648 649 650 -f 648 651 652 -f 648 652 649 -f 651 653 654 -f 655 656 657 -f 655 658 659 -f 660 661 579 -f 660 662 663 -f 664 665 666 -f 664 667 665 -f 552 668 669 -f 552 670 550 -f 552 669 671 -f 668 551 672 -f 673 674 675 -f 673 676 674 -f 677 678 679 -f 677 505 512 -f 506 505 677 -f 506 680 511 -f 677 512 681 -f 503 506 511 -f 682 683 280 -f 682 684 685 -f 683 685 686 -f 683 682 685 -f 682 280 687 -f 683 686 281 -f 413 688 689 -f 413 690 691 -f 692 693 694 -f 692 445 695 -f 696 692 695 -f 692 694 697 -f 698 699 700 -f 698 701 702 -f 699 702 703 -f 699 704 705 -f 706 707 708 -f 706 709 710 -f 707 671 711 -f 707 710 712 -f 713 714 715 -f 713 716 717 -f 718 719 720 -f 718 721 719 -f 722 723 724 -f 722 725 726 -f 335 727 333 -f 335 449 728 -f 729 730 731 -f 729 732 733 -f 729 733 730 -f 732 734 735 -f 736 18 471 -f 736 737 18 -f 736 738 737 -f 547 471 545 -f 739 740 741 -f 739 742 740 -f 743 744 745 -f 743 746 744 -f 747 748 749 -f 747 750 751 -f 752 753 754 -f 752 289 288 -f 752 754 755 -f 753 288 756 -f 555 558 757 -f 554 556 758 -f 757 759 760 -f 757 558 562 -f 761 762 763 -f 761 764 765 -f 766 767 768 -f 766 769 770 -f 767 766 770 -f 766 768 676 -f 609 771 210 -f 608 179 184 -f 772 773 774 -f 772 775 776 -f 777 778 779 -f 777 780 781 -f 782 783 474 -f 782 784 783 -f 785 661 786 -f 785 579 661 -f 787 788 397 -f 787 789 790 -f 788 790 791 -f 787 397 792 -f 793 106 794 -f 793 103 106 -f 795 796 797 -f 795 798 796 -f 799 800 801 -f 799 802 800 -f 803 804 805 -f 803 806 807 -f 804 808 805 -f 804 807 809 -f 810 811 812 -f 810 813 811 -f 814 815 816 -f 814 817 818 -f 814 818 815 -f 817 819 820 -f 551 553 821 -f 550 670 553 -f 822 823 824 -f 822 825 826 -f 822 827 825 -f 822 824 827 -f 823 828 824 -f 826 829 828 -f 587 830 831 -f 163 519 166 -f 832 833 834 -f 832 835 836 -f 837 838 839 -f 837 840 723 -f 838 837 726 -f 837 839 841 -f 842 843 844 -f 842 845 846 -f 847 848 849 -f 847 850 851 -f 852 853 854 -f 852 855 856 -f 857 858 859 -f 857 860 861 -f 862 863 864 -f 862 865 866 -f 862 866 863 -f 865 867 868 -f 865 868 866 -f 867 869 486 -f 869 870 486 -f 869 871 813 -f 872 873 874 -f 872 875 876 -f 877 245 878 -f 877 874 879 -f 880 881 882 -f 880 345 883 -f 884 885 886 -f 884 887 888 -f 859 858 889 -f 859 890 857 -f 891 67 892 -f 891 893 894 -f 895 534 537 -f 895 259 534 -f 896 897 898 -f 896 899 900 -f 897 900 901 -f 896 902 903 -f 175 904 905 -f 175 174 906 -f 907 908 909 -f 907 910 908 -f 908 911 912 -f 908 910 911 -f 385 384 480 -f 385 913 914 -f 915 916 917 -f 243 918 246 -f 919 920 921 -f 919 922 920 -f 923 924 925 -f 923 926 924 -f 90 89 927 -f 90 87 86 -f 928 929 664 -f 928 930 931 -f 932 933 719 -f 932 593 934 -f 933 720 719 -f 933 932 934 -f 935 936 937 -f 935 938 936 -f 939 940 941 -f 939 942 224 -f 943 830 521 -f 943 944 945 -f 946 894 947 -f 946 948 894 -f 106 103 102 -f 106 949 794 -f 2 123 950 -f 1 3 951 -f 952 953 954 -f 952 955 956 -f 957 958 959 -f 957 960 961 -f 730 962 963 -f 730 733 962 -f 730 963 731 -f 962 462 964 -f 965 966 967 -f 965 968 966 -f 969 970 971 -f 969 972 973 -f 974 975 802 -f 974 976 977 -f 975 977 978 -f 974 979 976 -f 974 802 980 -f 975 978 981 -f 982 341 491 -f 982 493 983 -f 607 240 984 -f 607 606 240 -f 607 984 985 -f 240 242 984 -f 986 987 988 -f 986 989 990 -f 987 991 992 -f 987 990 991 -f 993 994 995 -f 993 996 994 -f 997 998 999 -f 997 1000 1001 -f 1000 171 1001 -f 1000 1002 171 -f 1003 1004 1005 -f 1003 1006 1007 -f 1008 1009 1010 -f 1008 1011 1012 -f 1013 1014 1015 -f 1013 1016 1014 -f 1017 639 1018 -f 1017 640 639 -f 1019 1020 1021 -f 1019 455 1020 -f 1022 455 1019 -f 1022 1023 455 -f 455 1023 456 -f 1022 1024 1025 -f 1026 1027 1028 -f 1026 659 1029 -f 1030 1031 734 -f 1030 1032 1033 -f 1034 1021 1035 -f 1034 1024 1021 -f 1036 1037 1038 -f 1036 1039 1040 -f 1037 1036 1040 -f 1036 1038 1041 -f 236 238 239 -f 237 1042 1043 -f 1044 1045 1046 -f 1044 1047 1045 -f 1048 1049 375 -f 1048 1050 1051 -f 268 271 1052 -f 266 1053 269 -f 1054 1055 1056 -f 1054 1057 634 -f 1058 1059 1060 -f 1058 1061 1059 -f 1062 1063 1064 -f 1062 1065 1066 -f 1063 1067 1068 -f 1067 1062 1066 -f 1069 1070 1071 -f 1069 863 1072 -f 1069 1071 1073 -f 1070 1072 1074 -f 548 1075 1076 -f 548 471 1075 -f 1076 1075 1077 -f 545 549 1078 -f 1079 1080 1081 -f 1079 1082 1083 -f 1079 1083 1080 -f 1082 1084 1085 -f 339 338 342 -f 340 491 341 -f 1086 1087 1088 -f 1086 1089 1090 -f 1087 1091 1088 -f 1087 1092 1093 -f 1094 1095 1096 -f 1094 904 1097 -f 1098 1099 1100 -f 1098 275 1101 -f 1102 1100 1103 -f 1102 1104 1100 -f 1102 1103 797 -f 1100 1105 1106 -f 1099 1105 1100 -f 1099 1107 1105 -f 1100 1106 1103 -f 1099 1101 1108 -f 1109 1110 1111 -f 1109 1112 1113 -f 1114 1115 1116 -f 1114 1117 1118 -f 1119 680 679 -f 1119 466 1120 -f 1121 1122 1123 -f 1121 1124 1125 -f 1126 1124 1121 -f 1126 1127 1128 -f 1129 1124 1126 -f 1129 1130 1131 -f 1121 1125 1122 -f 1129 1128 1130 -f 1132 1133 1134 -f 1132 1135 1136 -f 1011 1137 1138 -f 1011 1008 1139 -f 1140 1137 1141 -f 1140 483 1142 -f 1138 1140 1142 -f 1140 1141 1143 -f 1144 1145 1146 -f 1144 1147 1148 -f 1149 441 1150 -f 1149 1151 441 -f 1152 1153 172 -f 1152 1002 1154 -f 1155 170 31 -f 1155 1156 1157 -f 1158 1159 686 -f 1158 1160 1159 -f 1161 820 1162 -f 1161 1163 820 -f 1164 1165 1148 -f 1164 1166 1165 -f 936 1167 937 -f 936 1168 1169 -f 1170 1050 1171 -f 1170 1172 1173 -f 750 1174 1175 -f 750 749 1176 -f 1174 1177 1175 -f 1174 1178 1179 -f 1177 1179 1180 -f 1174 1181 1178 -f 85 1182 1183 -f 85 1184 1185 -f 1186 988 1187 -f 1186 1188 1189 -f 1190 1191 1192 -f 1190 1193 1191 -f 1194 156 1111 -f 1194 1195 157 -f 1113 1110 1109 -f 1113 1196 1197 -f 1113 1112 1196 -f 1109 1111 1198 -f 121 709 1199 -f 120 122 123 -f 121 1199 524 -f 709 708 1199 -f 1200 1201 735 -f 1200 1202 1203 -f 1201 1204 735 -f 1201 1203 1205 -f 1206 1207 1208 -f 1206 1146 1145 -f 1209 1208 1207 -f 1209 1210 1211 -f 1211 1210 1212 -f 1211 1208 1209 -f 1209 1207 1213 -f 1206 1214 881 -f 497 309 1215 -f 497 1216 309 -f 73 1217 1218 -f 73 1219 69 -f 73 1218 1220 -f 1217 1221 1222 -f 1223 1224 1225 -f 1223 1153 1224 -f 1223 1066 1065 -f 1226 1227 1228 -f 119 1229 1230 -f 119 116 1231 -f 1229 1232 1233 -f 1229 1234 1232 -f 1235 1236 1237 -f 1235 1238 1236 -f 619 618 1239 -f 619 437 617 -f 803 807 804 -f 806 1240 1241 -f 853 856 1095 -f 852 854 855 -f 583 1242 764 -f 583 579 785 -f 1242 1243 1244 -f 583 764 584 -f 39 43 1245 -f 42 809 1246 -f 804 41 808 -f 42 1246 43 -f 1247 1248 990 -f 1247 1249 1250 -f 1251 1252 1253 -f 1251 1254 1252 -f 1255 1256 1257 -f 1255 1258 1259 -f 1260 1258 1261 -f 1260 1262 1263 -f 1260 1261 1192 -f 1258 1264 1261 -f 1265 451 448 -f 1265 1043 1266 -f 398 358 400 -f 399 356 358 -f 1267 1268 1269 -f 1267 1270 1268 -f 1271 1272 1273 -f 1271 407 405 -f 1272 1274 1275 -f 1272 1276 1274 -f 305 1277 301 -f 305 1278 1277 -f 980 802 799 -f 980 1279 974 -f 1055 1280 1056 -f 1055 1281 1282 -f 1283 1284 424 -f 1283 1285 1284 -f 410 409 406 -f 410 1286 316 -f 409 319 322 -f 409 1287 1288 -f 492 1289 493 -f 492 1290 1136 -f 1150 841 839 -f 1150 441 1291 -f 1292 1156 1293 -f 1292 1294 1156 -f 1295 1296 1297 -f 1292 1298 1294 -f 1299 1300 518 -f 1299 1060 1301 -f 1299 1302 1060 -f 1299 518 520 -f 1303 1304 1305 -f 1303 1306 1304 -f 61 1307 1308 -f 61 1309 109 -f 61 109 1307 -f 1309 461 460 -f 1310 1311 1312 -f 1310 1313 805 -f 1314 1311 805 -f 1314 1298 1312 -f 1310 1312 1315 -f 1314 1294 1298 -f 1316 1317 145 -f 1316 1318 1319 -f 1320 1321 1322 -f 1320 1317 1323 -f 1320 1323 1321 -f 1316 145 1318 -f 1324 1325 1326 -f 1324 794 1327 -f 793 1326 1328 -f 1325 1329 1330 -f 793 1328 1331 -f 1326 1330 1332 -f 1325 1324 1327 -f 793 1331 103 -f 1333 1334 1335 -f 1333 443 444 -f 1336 661 1337 -f 1336 786 661 -f 1137 1140 1138 -f 483 482 1338 -f 1339 1340 1341 -f 1339 1342 318 -f 1343 122 1344 -f 1343 950 122 -f 1345 1346 1347 -f 1345 1348 1346 -f 1349 1350 1351 -f 1349 1352 1353 -f 1354 1355 379 -f 1354 602 1356 -f 1008 1010 1139 -f 1009 1357 1010 -f 1358 1359 1360 -f 1358 1361 1016 -f 1359 1358 1016 -f 1358 1360 1257 -f 1362 1363 1364 -f 1362 1365 1363 -f 1366 1367 372 -f 1366 1368 1369 -f 1370 1371 746 -f 1370 1372 1373 -f 1374 1375 1376 -f 1374 1377 1378 -f 1377 1376 1379 -f 1374 1378 1375 -f 1380 1381 1382 -f 1380 1383 1384 -f 1381 1384 1385 -f 1380 1382 478 -f 1386 46 756 -f 1386 44 46 -f 1387 336 332 -f 1387 1388 450 -f 1387 1389 815 -f 1387 332 1389 -f 1390 1391 140 -f 1390 1392 1393 -f 1394 540 979 -f 1394 542 540 -f 704 1395 473 -f 704 1396 1397 -f 1398 786 737 -f 1398 1399 1400 -f 1399 1401 1244 -f 1399 1398 1401 -f 7 1402 10 -f 7 12 230 -f 1403 1404 1215 -f 1403 1405 1406 -f 1407 1408 496 -f 1407 1409 1371 -f 1404 495 1215 -f 1404 1406 1409 -f 1084 1410 1085 -f 1084 1411 1410 -f 1412 1413 1414 -f 1412 1415 1416 -f 1417 1418 1419 -f 1417 1420 1418 -f 1421 1418 1420 -f 1421 1422 1357 -f 1421 1420 1423 -f 1418 128 132 -f 589 1424 1425 -f 589 1426 1427 -f 1424 589 1427 -f 589 1425 588 -f 1428 1429 1430 -f 1428 1431 1053 -f 1432 1433 1434 -f 1432 1435 1433 -f 1436 32 1437 -f 1436 1438 1439 -f 1438 1440 1441 -f 1436 1439 32 -f 1438 1442 1439 -f 1438 1441 1442 -f 1097 1095 1094 -f 1097 1443 1095 -f 987 1187 988 -f 991 1444 829 -f 991 990 711 -f 986 988 1445 -f 1446 712 710 -f 1446 1447 1448 -f 1446 1448 1449 -f 1447 1450 1451 -f 67 66 892 -f 67 948 63 -f 891 892 958 -f 66 63 70 -f 1452 296 304 -f 1452 1068 296 -f 368 370 1453 -f 369 249 370 -f 53 643 55 -f 642 1454 643 -f 53 55 52 -f 643 1454 725 -f 644 1455 1456 -f 644 642 53 -f 1457 1458 970 -f 1457 1459 24 -f 1460 1461 1352 -f 1460 1462 70 -f 1463 889 401 -f 1463 1464 1465 -f 1466 1402 235 -f 1466 1467 1468 -f 235 1402 7 -f 235 234 1469 -f 1402 1468 10 -f 1466 1469 1467 -f 1470 1471 493 -f 1470 1472 1471 -f 1473 1471 1472 -f 1473 1474 1475 -f 1470 1289 1472 -f 1471 1476 493 -f 1477 1478 1479 -f 1477 263 1478 -f 1480 1481 238 -f 1480 1482 1481 -f 1483 1484 1485 -f 1483 1486 1487 -f 576 1486 700 -f 573 437 574 -f 1483 1487 1456 -f 576 700 620 -f 954 953 795 -f 952 1488 955 -f 34 1489 35 -f 34 1162 1490 -f 33 35 36 -f 1489 75 35 -f 1491 1492 1493 -f 1491 1494 1495 -f 1496 430 429 -f 1496 309 1216 -f 392 1497 1498 -f 392 391 1499 -f 1497 1499 1500 -f 392 1498 389 -f 959 1462 1501 -f 959 958 892 -f 1460 70 1461 -f 1462 892 66 -f 959 1501 1502 -f 70 65 1461 -f 1503 1504 531 -f 1503 813 1505 -f 719 721 770 -f 719 591 932 -f 721 1506 770 -f 791 718 720 -f 1507 1508 1509 -f 1507 1510 1508 -f 1508 1510 1434 -f 1507 1509 1511 -f 1512 1513 1514 -f 1512 1515 1516 -f 1515 1517 1518 -f 1515 1512 1519 -f 1517 1515 1519 -f 1515 1518 1520 -f 610 1521 1522 -f 610 608 184 -f 1521 610 697 -f 610 1522 611 -f 1522 674 768 -f 608 611 1523 -f 1524 1525 1526 -f 1524 1527 1528 -f 1525 972 1529 -f 1525 1519 972 -f 1530 1531 626 -f 1530 635 1531 -f 1532 1392 1533 -f 1532 1534 1535 -f 1533 1392 1390 -f 1533 206 1532 -f 1533 139 206 -f 1390 1393 1536 -f 1537 139 138 -f 1537 204 206 -f 1532 206 1534 -f 1537 142 1538 -f 1539 1520 1540 -f 1539 1516 1520 -f 1275 1273 1272 -f 1275 1541 1273 -f 1028 1542 1543 -f 1028 1544 1542 -f 1080 1083 1545 -f 1082 1079 1546 -f 1141 1137 1139 -f 1140 1143 483 -f 1547 1548 855 -f 1547 696 1548 -f 883 1549 881 -f 883 345 343 -f 1550 1551 1552 -f 1550 1553 1551 -f 1550 1552 634 -f 1551 1553 1554 -f 1555 1556 1557 -f 1555 1558 1559 -f 1122 1560 1561 -f 1122 1125 1560 -f 164 1562 556 -f 163 165 519 -f 1563 812 1564 -f 1563 1565 812 -f 1566 1210 1213 -f 1566 1567 1568 -f 269 1053 1431 -f 269 922 270 -f 349 1569 1570 -f 347 350 748 -f 1571 1572 1573 -f 1571 1574 1575 -f 1572 1576 1577 -f 1571 1573 1574 -f 1578 1579 1580 -f 1578 1581 1240 -f 1579 1313 1445 -f 1579 1240 1313 -f 1582 1583 1584 -f 1582 1469 1585 -f 158 195 1586 -f 160 330 1587 -f 1588 1589 1590 -f 1588 1591 926 -f 1184 1592 724 -f 85 1185 1182 -f 257 259 1593 -f 258 535 534 -f 1594 1595 984 -f 1594 1596 1597 -f 1131 1598 1599 -f 1124 1600 1125 -f 1601 1602 1603 -f 1601 1604 846 -f 1605 1606 1607 -f 1605 1608 1606 -f 1301 1609 1299 -f 1301 1610 1611 -f 1612 994 1613 -f 1612 1614 995 -f 1615 1616 1617 -f 1615 631 1616 -f 472 474 783 -f 473 1395 474 -f 1618 430 1496 -f 1618 136 431 -f 212 215 1619 -f 217 211 1568 -f 1620 1621 1622 -f 1620 45 1623 -f 279 278 1624 -f 279 1335 687 -f 278 941 1624 -f 277 279 687 -f 815 818 1625 -f 815 1389 816 -f 1021 1020 1626 -f 1034 1035 1025 -f 186 189 1426 -f 185 187 188 -f 1211 1627 1214 -f 1212 211 1628 -f 1627 1628 1629 -f 1212 1210 211 -f 1630 1631 1632 -f 1630 1633 1634 -f 1635 1636 1637 -f 1635 31 1636 -f 571 1638 1639 -f 571 570 691 -f 1569 1640 1641 -f 1569 1277 1642 -f 1643 1644 956 -f 1643 1645 1646 -f 1643 1647 1645 -f 1643 956 955 -f 1648 1305 1304 -f 1648 848 851 -f 1649 1650 779 -f 1649 1651 1650 -f 1652 1653 950 -f 1652 1654 1653 -f 765 762 761 -f 765 1655 1344 -f 1655 1654 1652 -f 765 1344 1656 -f 1655 1652 1343 -f 1654 1657 1653 -f 297 296 1067 -f 298 1658 303 -f 1452 304 1659 -f 295 297 1658 -f 83 1544 1660 -f 83 81 1542 -f 1661 678 1662 -f 1661 1663 678 -f 1664 774 773 -f 1664 1665 1666 -f 1667 1668 1669 -f 1667 1670 1668 -f 1671 653 651 -f 1671 1672 1673 -f 1674 759 944 -f 1674 760 759 -f 1675 1676 1677 -f 1675 930 1678 -f 1679 733 1204 -f 1679 462 962 -f 113 1680 114 -f 113 1681 1682 -f 1683 1684 1685 -f 1683 1577 1684 -f 489 1686 1290 -f 489 488 1687 -f 234 233 1688 -f 235 1469 1466 -f 1656 1689 762 -f 1656 1344 1690 -f 1689 1691 762 -f 1689 1656 1692 -f 1693 1479 1632 -f 1693 1694 1477 -f 1695 998 1696 -f 1695 1252 999 -f 1697 1375 1698 -f 1697 1699 1375 -f 1697 1698 1700 -f 1374 1376 1377 -f 1697 1700 1127 -f 1698 1701 1702 -f 1703 1704 1642 -f 1703 1705 1704 -f 177 174 173 -f 177 1706 174 -f 886 885 1707 -f 886 391 1708 -f 886 1707 1709 -f 884 1708 887 -f 831 830 943 -f 831 517 587 -f 1369 1367 1366 -f 1369 1581 1189 -f 1630 1632 1479 -f 1631 1710 1711 -f 1712 565 564 -f 1712 1713 565 -f 565 1714 563 -f 565 1715 850 -f 1007 1004 1003 -f 1007 1716 1004 -f 903 902 1717 -f 903 899 896 -f 1718 1719 1294 -f 1718 805 808 -f 934 720 933 -f 934 394 1720 -f 393 395 1721 -f 394 593 395 -f 1722 998 1001 -f 1722 1723 1059 -f 1695 1696 1724 -f 1722 1001 40 -f 1725 1726 1727 -f 1725 150 569 -f 1386 756 294 -f 46 1166 1728 -f 756 1729 753 -f 46 45 1166 -f 436 1730 574 -f 436 1731 1732 -f 1733 1734 1735 -f 1733 1676 1736 -f 270 922 919 -f 270 267 266 -f 1596 1737 1597 -f 1596 242 632 -f 1738 1739 317 -f 1738 1740 1739 -f 1738 317 647 -f 1739 96 1741 -f 1742 1743 1744 -f 1742 726 1743 -f 446 451 449 -f 1265 1388 1480 -f 1745 1746 101 -f 1745 195 1746 -f 1747 1748 1685 -f 1747 1557 1556 -f 1041 1373 1749 -f 1041 1038 1373 -f 1750 1746 192 -f 1750 99 1746 -f 1746 99 101 -f 1750 192 1751 -f 1595 1670 984 -f 1595 1597 1752 -f 1529 972 971 -f 1529 1526 1525 -f 946 947 72 -f 894 893 1753 -f 893 1754 1755 -f 891 894 948 -f 1347 1411 738 -f 1347 1346 1410 -f 1346 1348 1756 -f 1347 1410 1411 -f 1757 1677 1758 -f 1757 432 1677 -f 1759 1760 1761 -f 1759 50 1029 -f 1762 1376 1699 -f 1762 1353 1461 -f 1763 1764 1765 -f 1763 1766 527 -f 1692 1765 1691 -f 1763 1690 1766 -f 1767 1262 1191 -f 1767 75 1263 -f 1768 1769 1770 -f 1768 310 876 -f 1768 1770 307 -f 1769 1771 1772 -f 1770 1772 1773 -f 1768 307 310 -f 955 1647 1643 -f 955 1488 272 -f 1774 1775 1776 -f 1774 386 1777 -f 1775 1777 1778 -f 1774 1776 387 -f 1779 1780 1781 -f 1779 1782 1783 -f 1538 1781 1537 -f 1538 461 1779 -f 1537 1781 204 -f 142 141 1784 -f 1779 461 1782 -f 1538 1784 459 -f 1363 1785 1786 -f 1363 1365 1787 -f 1785 1788 1786 -f 1785 1789 1788 -f 1786 1788 1790 -f 1786 1364 1363 -f 1786 1790 1364 -f 1788 1789 1555 -f 1719 808 1791 -f 1718 1294 1314 -f 1792 375 1793 -f 1792 1666 1665 -f 1792 1665 1050 -f 1666 1794 1795 -f 1796 1081 1080 -f 1796 1797 214 -f 1798 1799 1434 -f 1798 606 603 -f 1800 798 1801 -f 1800 641 798 -f 1802 1803 1494 -f 1802 320 1803 -f 1803 320 1804 -f 1802 1494 1341 -f 355 1805 358 -f 1806 1807 1805 -f 358 1805 1287 -f 399 401 889 -f 1805 1808 1288 -f 1805 1807 1808 -f 1808 1807 1804 -f 1806 355 357 -f 1809 1810 1752 -f 1809 1811 1812 -f 1810 1668 1670 -f 1813 1809 1812 -f 1668 1813 1669 -f 1810 1670 1752 -f 1667 1669 985 -f 1813 1812 1511 -f 1814 1279 980 -f 1814 1815 1279 -f 1816 456 1817 -f 1816 1756 457 -f 1818 1819 1624 -f 1818 1820 1821 -f 1415 1822 1416 -f 1415 1823 1822 -f 1005 1645 921 -f 1005 1004 1716 -f 1824 1825 1826 -f 1824 1233 1232 -f 1827 104 1416 -f 102 1828 105 -f 1560 1125 1600 -f 1122 1561 1123 -f 1829 1830 1195 -f 1829 1197 1831 -f 1832 1257 1256 -f 1832 1361 1358 -f 1132 1136 1686 -f 1135 1833 1136 -f 1834 1135 1134 -f 1135 1835 1833 -f 1481 1482 1836 -f 1480 238 1043 -f 1837 1838 1839 -f 1837 1840 1841 -f 1842 1306 1843 -f 1842 1844 1845 -f 1572 1577 1846 -f 1576 562 557 -f 1847 1848 1270 -f 1847 1641 1849 -f 1838 1841 1850 -f 1837 1839 1851 -f 212 214 216 -f 213 1081 214 -f 1852 1853 666 -f 1852 1574 1853 -f 1727 1726 1639 -f 1727 1854 1725 -f 1855 1639 161 -f 1855 1856 1854 -f 1170 1171 1172 -f 1050 1665 1171 -f 1482 1388 1625 -f 1482 1480 1388 -f 1857 1858 1494 -f 1857 1716 1007 -f 1859 1860 1861 -f 1859 1862 1863 -f 449 451 1864 -f 446 334 447 -f 1865 1439 1442 -f 1865 28 1439 -f 1599 1598 1866 -f 1131 1867 1600 -f 1451 1448 1447 -f 1451 636 1322 -f 1868 1869 1391 -f 1868 1870 362 -f 1870 1871 1872 -f 1870 1536 967 -f 1379 65 71 -f 1379 1376 1461 -f 58 1455 644 -f 58 57 1873 -f 57 51 50 -f 58 1873 1484 -f 604 1874 605 -f 604 1669 1508 -f 1678 1853 1875 -f 1678 930 928 -f 645 407 1271 -f 646 1876 408 -f 647 1273 1541 -f 645 317 1876 -f 1272 1271 405 -f 647 1541 1738 -f 1582 1877 1878 -f 1585 1688 1233 -f 1879 1880 1881 -f 1879 1270 1880 -f 1882 1883 1884 -f 1882 1731 435 -f 1827 102 104 -f 105 1885 106 -f 1412 1416 1886 -f 1822 1823 1887 -f 478 480 1888 -f 477 479 1889 -f 1449 1890 1446 -f 1449 1321 1323 -f 1449 1323 1891 -f 1320 1322 1892 -f 1886 104 1893 -f 1886 1413 1412 -f 104 103 1893 -f 1827 1416 1828 -f 578 1894 1895 -f 577 579 582 -f 1896 937 1167 -f 1896 1897 1898 -f 1899 1900 1901 -f 1899 1269 1902 -f 1899 1901 1903 -f 1900 1902 1904 -f 1905 1906 1907 -f 1905 1908 1906 -f 649 652 1909 -f 648 650 651 -f 1367 1188 1910 -f 1369 1368 1581 -f 1787 1911 1368 -f 1787 1365 1246 -f 1368 1912 1913 -f 1368 1911 1581 -f 1911 1241 1581 -f 1911 1787 1241 -f 1914 1915 1916 -f 1914 254 1915 -f 1499 1497 392 -f 1499 1709 1500 -f 1497 1500 1917 -f 1709 1707 1918 -f 1919 1894 578 -f 1919 581 1296 -f 695 1548 696 -f 695 445 1920 -f 1921 1922 1923 -f 1921 535 260 -f 1924 1925 36 -f 1924 1616 1926 -f 1927 1625 1163 -f 1927 1925 1836 -f 36 1925 1927 -f 36 35 77 -f 33 37 34 -f 1927 1836 1625 -f 1780 1783 1928 -f 1779 1781 1538 -f 1928 1783 1929 -f 1928 204 1780 -f 1928 1929 1930 -f 1783 1782 1929 -f 1931 1932 1933 -f 1931 500 499 -f 1934 1357 1422 -f 1934 1935 1073 -f 1935 1936 1937 -f 1934 1073 1357 -f 663 1337 661 -f 663 19 1938 -f 163 1562 164 -f 513 514 1939 -f 166 519 514 -f 165 556 555 -f 556 1562 758 -f 521 586 943 -f 1940 440 403 -f 1940 97 95 -f 1941 1942 1943 -f 1941 1944 708 -f 1945 1946 1947 -f 1945 1948 1949 -f 127 131 125 -f 127 1950 131 -f 162 1951 330 -f 162 161 1951 -f 585 1952 581 -f 585 763 1691 -f 222 221 1953 -f 222 219 218 -f 1954 1860 1859 -f 1954 255 1955 -f 632 241 629 -f 632 1737 1596 -f 629 630 1926 -f 236 606 237 -f 1956 1957 1958 -f 1956 508 1959 -f 1960 1904 1961 -f 1960 1176 1904 -f 1647 272 270 -f 952 956 953 -f 1005 921 365 -f 1645 1962 919 -f 436 574 437 -f 1730 1963 575 -f 1730 1732 1964 -f 433 437 619 -f 623 1253 1061 -f 623 622 1866 -f 1533 140 139 -f 1390 1536 1868 -f 1965 1966 1967 -f 1965 564 566 -f 1966 1968 1969 -f 1712 1967 1713 -f 1970 898 901 -f 1970 1971 898 -f 1972 1971 1970 -f 1972 1973 902 -f 1972 1974 1975 -f 1972 1608 1976 -f 1754 1977 1978 -f 894 1753 1979 -f 1754 1978 1285 -f 1977 1980 354 -f 861 1981 1982 -f 861 858 857 -f 1463 401 403 -f 889 356 399 -f 859 1465 890 -f 858 861 356 -f 1983 1153 1152 -f 1983 1224 1153 -f 1984 1136 1833 -f 1984 1985 1472 -f 1986 1985 1467 -f 1986 1472 1985 -f 1987 1985 1984 -f 1987 1468 1467 -f 1986 1467 1584 -f 1987 1833 10 -f 1453 371 368 -f 1453 1789 1785 -f 371 1912 372 -f 371 1453 1913 -f 1920 1096 856 -f 1920 445 905 -f 905 1096 1920 -f 905 183 175 -f 1920 1548 695 -f 1096 1095 856 -f 1988 1989 1990 -f 1988 675 1989 -f 1991 1992 1993 -f 1991 1994 1704 -f 1992 1995 1993 -f 1992 1704 1705 -f 1995 1996 1702 -f 1995 1997 1996 -f 1998 1917 1500 -f 1998 1999 1917 -f 2000 2001 1192 -f 2000 849 848 -f 1869 2002 1391 -f 1869 2003 2002 -f 2004 927 1887 -f 2004 2005 2006 -f 1820 87 90 -f 1820 226 87 -f 774 1795 2007 -f 1664 773 1665 -f 2008 2007 2009 -f 774 2010 772 -f 2011 611 2012 -f 2011 1523 611 -f 1696 1722 1059 -f 1695 1724 1252 -f 1909 651 2013 -f 651 650 1671 -f 2014 1118 1409 -f 2014 1406 1115 -f 1118 744 746 -f 1118 1115 1114 -f 1859 1861 1862 -f 1860 220 2015 -f 637 2016 2017 -f 637 636 1451 -f 2018 2019 1593 -f 2018 2020 2021 -f 2021 2019 2018 -f 2021 2022 2023 -f 2019 2024 1593 -f 2019 2021 2023 -f 420 421 1753 -f 426 2025 421 -f 2026 1959 276 -f 2026 2027 1957 -f 2028 2029 1249 -f 2028 1315 2029 -f 2029 2030 1249 -f 2029 2031 2030 -f 626 2032 1530 -f 626 628 2032 -f 906 1706 2033 -f 906 904 175 -f 1631 1711 2034 -f 1710 2035 1711 -f 1764 526 1297 -f 1763 1765 1692 -f 1619 213 212 -f 213 2036 1401 -f 1093 1091 1087 -f 1093 2037 2038 -f 381 380 2039 -f 381 600 378 -f 2029 1315 2031 -f 2028 1249 1247 -f 2040 199 2041 -f 2040 332 199 -f 1975 2042 2043 -f 1975 1974 2042 -f 2044 2045 2046 -f 2044 2047 1185 -f 1685 1684 2048 -f 1685 1748 2049 -f 1683 2050 1846 -f 1685 2048 1747 -f 1169 2051 1896 -f 1169 1168 2052 -f 2051 2053 2054 -f 2051 1169 2053 -f 1198 1613 2055 -f 1198 1112 1109 -f 1220 1218 2056 -f 1220 1219 73 -f 1995 2056 1993 -f 1702 1700 1698 -f 1702 2056 1995 -f 1220 1701 1219 -f 563 1714 2057 -f 565 1713 1715 -f 1714 2058 2057 -f 1712 564 1965 -f 2058 2059 2022 -f 2058 850 2059 -f 2058 2022 2057 -f 2059 2060 2023 -f 2059 2023 2022 -f 2060 849 2061 -f 2062 320 319 -f 2062 1804 320 -f 320 1340 318 -f 1803 1804 1495 -f 1339 1341 1858 -f 2062 319 2063 -f 2064 2065 2066 -f 2064 614 2065 -f 2067 1917 1999 -f 2067 366 1917 -f 1132 1134 1135 -f 1133 596 1134 -f 2068 382 182 -f 2068 1276 405 -f 181 1276 2068 -f 181 2069 210 -f 1274 210 209 -f 1274 1276 181 -f 2068 405 382 -f 1275 1274 209 -f 1715 2070 850 -f 1715 1713 2035 -f 727 2071 331 -f 335 334 449 -f 1148 1145 1144 -f 1148 2072 1164 -f 1778 100 99 -f 1778 1777 913 -f 100 2073 2074 -f 1778 99 1775 -f 994 2075 1613 -f 993 995 2054 -f 472 783 475 -f 474 1395 1047 -f 833 2076 1422 -f 832 834 1752 -f 677 681 678 -f 512 504 1958 -f 2077 2078 1623 -f 2077 47 2079 -f 1623 1621 1620 -f 1623 2078 2080 -f 1623 2080 2081 -f 2078 2077 2079 -f 480 384 1888 -f 480 2082 385 -f 2083 341 982 -f 2083 2084 341 -f 1542 2085 1543 -f 1542 2086 458 -f 1026 1543 659 -f 2085 2087 656 -f 1587 330 2088 -f 1587 2089 194 -f 158 1586 1871 -f 195 192 1746 -f 2090 725 1454 -f 2090 726 725 -f 2091 546 1078 -f 2091 738 547 -f 207 211 217 -f 210 2069 609 -f 2092 542 1394 -f 2092 2093 543 -f 1282 1281 1554 -f 1282 1280 1055 -f 533 535 540 -f 895 537 2020 -f 970 1458 1510 -f 970 973 1457 -f 970 1510 971 -f 1458 1435 1432 -f 1508 1434 1874 -f 1457 973 1459 -f 284 1864 451 -f 284 23 282 -f 2094 1256 1259 -f 2094 1490 1162 -f 412 414 1659 -f 411 413 689 -f 2095 1002 1000 -f 2095 2096 1154 -f 2064 2066 2097 -f 2065 614 1835 -f 2066 2098 1134 -f 2066 2065 2098 -f 872 876 873 -f 875 1771 1768 -f 616 613 612 -f 616 188 187 -f 769 591 770 -f 769 2099 592 -f 1277 1569 2100 -f 1569 1642 1640 -f 2101 356 1982 -f 2101 357 356 -f 925 2049 2102 -f 925 924 2050 -f 2103 2104 2105 -f 2067 1356 599 -f 908 912 2106 -f 911 2105 2107 -f 2105 2104 2107 -f 2103 2033 1356 -f 2104 1999 2108 -f 2103 2105 2033 -f 2109 1758 2110 -f 2109 2111 1758 -f 1758 1677 2110 -f 1757 2111 432 -f 2112 2113 2114 -f 2112 2115 2113 -f 2112 2114 922 -f 2113 2115 390 -f 1677 432 2116 -f 1677 1676 2110 -f 1677 2116 1675 -f 432 431 2116 -f 1550 634 637 -f 1552 1554 1281 -f 2117 741 740 -f 2117 1541 1275 -f 901 2118 1606 -f 901 2119 2118 -f 2118 2119 2120 -f 901 1606 1970 -f 214 1081 1796 -f 213 1619 2036 -f 2121 1637 1636 -f 2121 2122 1535 -f 2123 1637 2124 -f 2123 27 26 -f 2121 1636 149 -f 2123 2124 27 -f 2043 1973 1975 -f 2043 2075 1973 -f 1291 841 1150 -f 1291 2125 95 -f 839 1744 2126 -f 837 841 2127 -f 1742 839 838 -f 839 2126 2128 -f 837 2127 840 -f 1291 441 438 -f 1320 1892 2032 -f 1322 636 1892 -f 1530 636 635 -f 1322 1448 1451 -f 50 1660 1027 -f 50 1761 57 -f 1555 1557 1788 -f 1556 1748 1747 -f 1683 2049 2050 -f 1748 2129 2049 -f 528 485 484 -f 528 530 485 -f 701 2130 1761 -f 698 702 699 -f 1263 75 1489 -f 1263 1262 1767 -f 1489 1490 1263 -f 1924 77 567 -f 2094 1162 1256 -f 74 75 836 -f 2131 537 2132 -f 2131 2133 2020 -f 2133 2134 2057 -f 2131 2020 537 -f 1680 2135 2136 -f 112 114 2137 -f 751 2138 2139 -f 751 1175 2138 -f 206 205 2140 -f 138 140 141 -f 205 331 2141 -f 203 206 204 -f 331 2071 2141 -f 727 202 333 -f 206 2140 1534 -f 2141 2071 2142 -f 200 201 196 -f 2141 2142 2140 -f 1071 2143 1010 -f 1069 864 863 -f 2144 812 811 -f 2144 2145 1564 -f 2146 2147 2148 -f 2146 2149 2027 -f 860 1981 861 -f 860 1151 1564 -f 2149 2145 2150 -f 2149 2151 2101 -f 2145 1981 1564 -f 2149 2150 2027 -f 2144 1564 812 -f 860 890 1151 -f 2152 1930 2153 -f 2152 2154 2155 -f 2154 2156 2155 -f 2154 1016 1361 -f 2157 1221 1979 -f 2157 1994 1221 -f 501 1830 499 -f 501 157 1195 -f 1830 1831 1932 -f 1829 1195 1197 -f 1831 1830 1829 -f 1830 1932 499 -f 2158 1932 1831 -f 2158 1304 2159 -f 1931 1933 500 -f 2158 1197 1304 -f 1989 694 693 -f 1989 2160 1990 -f 262 1478 263 -f 262 265 1478 -f 2161 1843 2162 -f 2161 2163 2164 -f 888 2165 2166 -f 888 2107 2104 -f 1108 1334 1107 -f 1108 2167 682 -f 1107 1106 1105 -f 1107 1334 444 -f 1333 1335 271 -f 1108 1101 2167 -f 11 8 5 -f 11 614 613 -f 1049 2168 375 -f 1049 1173 2168 -f 1923 979 540 -f 1923 1922 2169 -f 1921 1923 540 -f 1923 1015 979 -f 1681 2170 2171 -f 1681 115 1359 -f 2148 1237 2172 -f 2146 2151 2149 -f 1237 2173 1235 -f 1237 2148 2147 -f 2174 1936 2175 -f 2174 2176 1937 -f 2174 1937 1936 -f 2176 1191 1193 -f 1945 1949 1946 -f 1948 1180 1179 -f 1895 1894 1156 -f 1895 2177 578 -f 1894 1293 1156 -f 578 2177 660 -f 1819 1821 1430 -f 1820 1818 226 -f 1288 2063 319 -f 358 1287 402 -f 1076 1077 714 -f 1075 471 470 -f 465 469 2178 -f 464 463 467 -f 463 468 466 -f 465 2178 468 -f 2012 2179 770 -f 2012 611 768 -f 767 2012 768 -f 2012 789 2011 -f 1306 2159 1304 -f 1842 1843 2180 -f 2181 1755 1283 -f 2181 1753 893 -f 1520 1518 1540 -f 1512 1516 2182 -f 1539 1540 1862 -f 1518 1517 2183 -f 1046 1045 221 -f 1046 256 252 -f 1611 1939 1609 -f 1611 1610 1245 -f 2184 2185 2186 -f 2184 1583 2185 -f 1875 1590 1589 -f 1875 1853 1590 -f 1875 1589 1736 -f 1588 1574 1573 -f 1952 1765 1297 -f 585 581 580 -f 1952 1297 1296 -f 1764 527 526 -f 1297 526 2187 -f 1692 1691 1689 -f 1296 1293 1919 -f 1295 2187 1298 -f 1951 1638 691 -f 159 330 160 -f 571 1639 569 -f 1638 161 1639 -f 1930 1929 62 -f 2152 2153 1014 -f 656 1543 2085 -f 655 1172 658 -f 851 850 2070 -f 851 848 847 -f 325 265 264 -f 327 2070 1634 -f 326 453 2188 -f 328 325 264 -f 928 664 1853 -f 664 931 667 -f 722 724 2189 -f 723 2045 1185 -f 2190 2003 1869 -f 2190 362 361 -f 1390 140 1533 -f 1391 2002 141 -f 1007 1006 1858 -f 1003 365 1006 -f 30 29 2177 -f 26 31 2123 -f 30 2177 1895 -f 29 28 2191 -f 489 1687 1686 -f 488 344 1687 -f 735 1204 733 -f 1200 734 1202 -f 2192 1850 1329 -f 2192 2193 1839 -f 1330 1850 2194 -f 1330 1329 1850 -f 2192 1329 2195 -f 1326 1332 1328 -f 219 2015 220 -f 219 2196 2197 -f 2198 2194 1841 -f 2198 1092 1090 -f 2198 1840 1092 -f 2198 1841 1840 -f 173 183 178 -f 174 1706 906 -f 1421 1357 128 -f 1422 2175 1934 -f 2199 170 169 -f 2199 2200 2201 -f 2199 169 2202 -f 170 1155 168 -f 170 1636 31 -f 2201 2200 2203 -f 2201 2203 149 -f 1062 2202 1065 -f 1767 1191 2204 -f 1262 1192 1191 -f 627 626 1531 -f 625 2205 2206 -f 1916 2207 1142 -f 1916 844 2207 -f 312 1450 313 -f 312 311 951 -f 1890 1891 2208 -f 1449 1448 1321 -f 1898 2209 156 -f 1898 937 1896 -f 43 1246 2210 -f 42 41 809 -f 532 531 1504 -f 532 529 528 -f 1183 1182 2211 -f 85 1183 78 -f 1182 1185 2047 -f 85 80 1184 -f 134 1673 135 -f 134 137 496 -f 1938 1337 663 -f 1938 786 1336 -f 1336 1337 1938 -f 661 660 663 -f 785 786 1398 -f 663 662 19 -f 966 152 1854 -f 966 968 152 -f 968 1535 2122 -f 968 965 1535 -f 575 2212 1487 -f 575 1963 2213 -f 573 1487 576 -f 2212 2213 2214 -f 1267 1880 1270 -f 1268 1385 2215 -f 1851 2216 2217 -f 1851 1839 2216 -f 2218 1280 1282 -f 2218 1405 308 -f 2120 2119 2219 -f 2120 2220 2221 -f 2222 1408 1371 -f 2222 654 2223 -f 722 56 2224 -f 2189 2225 56 -f 1428 1053 268 -f 1431 2226 269 -f 2227 954 797 -f 954 2228 1488 -f 638 640 796 -f 1017 1018 2229 -f 2230 2231 2232 -f 2230 2233 2234 -f 2195 2193 2192 -f 2195 225 224 -f 2235 1413 467 -f 2235 1414 1413 -f 289 2236 292 -f 289 752 2184 -f 613 2237 8 -f 616 615 2238 -f 612 614 615 -f 613 8 11 -f 659 658 2239 -f 655 1543 656 -f 658 1172 1171 -f 655 659 1543 -f 1408 1407 1371 -f 1408 2223 496 -f 713 657 714 -f 717 1173 657 -f 1626 1020 2240 -f 1626 2046 2241 -f 1433 2242 1266 -f 1433 1042 1434 -f 1433 1266 1043 -f 2242 23 284 -f 984 1670 1667 -f 1594 242 1596 -f 2243 1915 1863 -f 2243 1540 2244 -f 2245 853 1095 -f 2245 909 853 -f 2104 2165 888 -f 2108 1999 2246 -f 1734 1589 2247 -f 1733 2110 1676 -f 2248 602 379 -f 2248 600 598 -f 664 666 1853 -f 665 667 2249 -f 2206 146 143 -f 2206 1771 146 -f 1217 1222 1218 -f 1221 1994 1991 -f 1979 947 894 -f 2157 2025 2250 -f 1979 421 2025 -f 946 72 68 -f 2001 848 1648 -f 2000 1192 1261 -f 1018 2251 2229 -f 1018 641 2252 -f 2183 1528 2253 -f 2183 1519 1528 -f 1041 1749 2254 -f 1373 1372 1749 -f 2184 2186 2236 -f 2185 1878 2255 -f 2184 2236 289 -f 2186 1372 292 -f 289 292 287 -f 2186 1749 1372 -f 2256 1039 1825 -f 2256 2257 1040 -f 1036 2254 1039 -f 2255 2254 2185 -f 1037 1040 2258 -f 1039 1826 1825 -f 1373 1038 1371 -f 1039 2255 1826 -f 475 783 2259 -f 472 476 473 -f 282 286 283 -f 285 2124 286 -f 2260 1244 1657 -f 2260 2261 764 -f 701 2262 702 -f 701 1761 1760 -f 2262 1760 2263 -f 2130 1485 1873 -f 941 940 1624 -f 941 281 939 -f 2264 2265 2263 -f 2264 1029 2265 -f 2266 745 744 -f 2266 2079 2267 -f 2259 783 2268 -f 475 2269 476 -f 2270 114 2061 -f 2270 1264 2137 -f 1264 1257 2137 -f 1264 1258 1255 -f 2271 1112 2055 -f 2271 1937 1193 -f 305 301 300 -f 2100 346 302 -f 300 302 299 -f 2100 1569 349 -f 2272 2273 921 -f 2272 920 2114 -f 2273 2274 1498 -f 2272 921 920 -f 1354 2033 1355 -f 2103 1999 2104 -f 2090 1454 2275 -f 56 722 2189 -f 1824 1232 1825 -f 1233 1688 1230 -f 1339 1858 1006 -f 1802 1341 1340 -f 1007 1858 1857 -f 318 1342 321 -f 2276 1228 1227 -f 2276 1658 297 -f 2270 2061 1261 -f 114 1680 2061 -f 2277 2278 1442 -f 2277 19 662 -f 560 1364 2048 -f 559 561 557 -f 1248 711 990 -f 1248 1250 1942 -f 2091 1078 2279 -f 545 471 548 -f 1078 549 2280 -f 2091 2279 738 -f 1639 1726 569 -f 1855 161 1856 -f 569 1726 1725 -f 1951 691 2281 -f 570 569 572 -f 1727 1639 1855 -f 790 1506 721 -f 790 789 1506 -f 967 1856 1870 -f 967 1854 1856 -f 1715 2035 2070 -f 1713 1967 2035 -f 1046 221 256 -f 1045 2282 221 -f 2282 1395 1953 -f 2282 1047 1395 -f 2283 2284 2285 -f 2283 1284 353 -f 22 374 1437 -f 22 21 375 -f 2238 188 616 -f 2238 1426 188 -f 243 245 915 -f 244 144 878 -f 988 1189 1445 -f 1186 992 1910 -f 2038 1120 468 -f 2038 511 1120 -f 1091 468 1088 -f 2038 2037 511 -f 1088 468 2178 -f 1093 1092 1840 -f 2286 2287 215 -f 2286 1657 2287 -f 1622 1165 1166 -f 1622 1621 2288 -f 1621 2289 2288 -f 1620 1166 45 -f 1180 2138 1175 -f 1180 1947 2138 -f 518 514 519 -f 1299 520 1302 -f 1560 1600 624 -f 1131 1600 1129 -f 1129 1600 1124 -f 1126 1121 1127 -f 2290 2197 772 -f 2290 2015 2197 -f 1196 1112 1193 -f 1113 1197 1195 -f 1253 1724 1696 -f 1253 1866 1251 -f 1251 1866 1598 -f 1252 1724 1253 -f 1253 1059 1061 -f 997 999 2095 -f 1292 1293 1296 -f 1156 1155 1895 -f 778 1351 2291 -f 778 781 2292 -f 24 21 20 -f 24 1435 1457 -f 744 1118 1117 -f 1118 746 1409 -f 61 1308 59 -f 1307 2293 800 -f 61 60 1309 -f 1308 981 978 -f 2076 836 75 -f 833 1423 2294 -f 482 485 2295 -f 486 481 868 -f 815 1625 1388 -f 818 820 1163 -f 818 1163 1625 -f 1161 1162 37 -f 820 818 817 -f 1927 37 36 -f 17 14 13 -f 17 715 2296 -f 1954 1955 218 -f 250 254 2295 -f 1954 220 1860 -f 1955 256 218 -f 2297 2073 913 -f 2297 2003 2190 -f 435 1883 1882 -f 435 434 2268 -f 943 586 944 -f 830 587 521 -f 2053 1717 2054 -f 2053 1169 903 -f 1906 1908 2298 -f 1905 1907 2299 -f 2300 2298 2167 -f 1906 1101 1907 -f 2300 2167 1101 -f 2298 1908 2301 -f 1669 1509 1508 -f 1809 1668 1810 -f 1491 1493 2302 -f 1492 1807 1493 -f 748 2303 749 -f 748 2139 347 -f 1903 2303 1881 -f 1903 1901 749 -f 1903 1881 1880 -f 747 749 750 -f 1964 1732 2128 -f 1964 1963 1730 -f 2304 2299 1907 -f 2304 508 2217 -f 273 2305 2173 -f 274 1907 1101 -f 273 275 2305 -f 1905 2299 2217 -f 2304 1959 508 -f 2304 1907 1959 -f 244 247 144 -f 245 916 915 -f 243 915 918 -f 916 879 2102 -f 387 1888 383 -f 387 2306 2307 -f 1539 1862 1516 -f 2243 2244 1915 -f 1859 1863 1954 -f 1862 1540 1863 -f 1194 157 156 -f 1831 1197 2158 -f 157 154 153 -f 501 1195 1830 -f 2308 2309 1884 -f 2308 530 529 -f 1743 726 2275 -f 1743 2213 1744 -f 1946 1949 191 -f 1945 1947 1180 -f 2310 1996 2311 -f 2310 2312 1700 -f 1659 414 1452 -f 1659 2088 2281 -f 414 1068 1452 -f 412 690 413 -f 2018 1593 259 -f 2024 2136 260 -f 257 2024 260 -f 2024 2023 2136 -f 1355 382 379 -f 1355 2033 1706 -f 2257 2313 649 -f 2256 1040 1039 -f 1881 350 349 -f 1903 1880 1267 -f 2314 2315 2316 -f 2314 1629 2317 -f 2315 2317 771 -f 2315 792 2316 -f 2318 329 2319 -f 2318 2320 329 -f 1569 1641 1570 -f 1640 2250 425 -f 1721 2316 396 -f 1721 597 345 -f 603 605 1799 -f 1874 1434 1799 -f 2321 2322 1127 -f 2321 2312 2323 -f 1517 1519 2183 -f 1514 972 1519 -f 1929 1782 62 -f 1780 204 1781 -f 1782 461 1309 -f 1779 1783 1780 -f 604 985 1669 -f 603 1799 1798 -f 871 2324 1661 -f 869 813 870 -f 1922 2170 2169 -f 2325 1921 260 -f 2227 797 1103 -f 953 956 1801 -f 794 1324 793 -f 1325 1327 1329 -f 594 395 595 -f 1721 345 880 -f 1844 2319 2326 -f 1842 1845 1306 -f 1547 855 2099 -f 905 445 183 -f 97 93 92 -f 97 402 2327 -f 1940 95 2328 -f 93 1741 96 -f 1910 1188 1186 -f 1910 372 1367 -f 2062 2063 1804 -f 324 322 321 -f 1288 319 409 -f 1802 1340 320 -f 957 961 958 -f 960 2329 2292 -f 1511 2330 971 -f 1511 1509 1813 -f 1436 1437 1440 -f 32 27 2331 -f 1865 1442 2278 -f 1438 1436 1440 -f 1023 1025 1083 -f 454 456 457 -f 1080 1545 1796 -f 1083 1085 1023 -f 1023 1085 456 -f 1025 1545 1083 -f 1796 1545 1025 -f 1079 1081 1546 -f 212 216 208 -f 1797 1796 1035 -f 1797 1035 2241 -f 1082 1546 1084 -f 390 389 2332 -f 390 2115 388 -f 2329 1502 2333 -f 960 2292 961 -f 88 1327 794 -f 88 225 1329 -f 793 1324 1326 -f 1326 1325 1330 -f 2152 1014 1016 -f 2153 976 1015 -f 1013 1015 2169 -f 1930 2155 1928 -f 2334 1207 2335 -f 2334 1213 1207 -f 1864 283 728 -f 284 1266 2242 -f 299 302 2138 -f 298 295 1658 -f 862 864 2336 -f 863 866 1072 -f 1069 1072 1070 -f 866 868 1143 -f 1465 1464 439 -f 1465 859 889 -f 439 1464 403 -f 439 441 890 -f 857 890 860 -f 439 403 440 -f 438 440 2125 -f 403 402 1940 -f 438 2125 1291 -f 1940 402 97 -f 831 945 517 -f 944 2337 945 -f 1575 2337 562 -f 1575 2338 945 -f 2146 2027 2147 -f 2150 2339 681 -f 2109 873 2111 -f 1589 1733 1736 -f 824 828 1318 -f 824 249 827 -f 1057 1531 635 -f 1057 1056 1773 -f 1424 1427 232 -f 1426 615 2340 -f 2341 2170 1681 -f 2341 1016 1013 -f 1681 2171 1682 -f 1923 2169 1015 -f 1601 1603 1604 -f 1602 1527 2234 -f 721 791 790 -f 934 593 394 -f 874 2342 2343 -f 874 873 1735 -f 874 2343 879 -f 2342 1735 2247 -f 1419 2344 2345 -f 1419 1418 132 -f 2346 2072 983 -f 2346 1728 1166 -f 2146 2148 2151 -f 2147 2173 1237 -f 144 247 145 -f 244 878 245 -f 148 2347 151 -f 965 967 1536 -f 995 1614 2209 -f 994 996 2075 -f 1241 1787 807 -f 1188 1369 1189 -f 792 397 396 -f 792 2315 2011 -f 792 396 2316 -f 393 788 394 -f 1933 2158 2159 -f 1932 1931 499 -f 1933 2159 2326 -f 1843 1303 2162 -f 2348 703 775 -f 2348 2197 1396 -f 2237 9 8 -f 186 185 189 -f 995 994 1612 -f 2075 2055 1613 -f 1063 2349 1064 -f 1063 1068 414 -f 132 2344 1419 -f 132 2350 1603 -f 1417 2345 2234 -f 2344 132 1603 -f 2351 2352 2017 -f 2351 1567 1566 -f 1250 1248 1247 -f 1248 1942 708 -f 1187 987 992 -f 1247 989 2028 -f 1187 992 1186 -f 991 829 992 -f 2006 1430 2004 -f 2006 2353 1430 -f 2323 2310 1983 -f 2323 2312 2310 -f 40 1723 1722 -f 39 38 42 -f 1559 918 915 -f 1559 1558 918 -f 808 1719 1718 -f 1719 1791 1157 -f 1791 171 1157 -f 1791 41 1001 -f 315 2327 402 -f 315 317 1739 -f 316 402 1287 -f 314 1286 317 -f 191 193 1946 -f 190 192 194 -f 1205 1204 1201 -f 1205 2354 1679 -f 718 791 721 -f 788 1720 394 -f 2176 1193 1937 -f 1190 1192 2001 -f 2216 2355 1908 -f 2216 1839 2355 -f 330 2281 2088 -f 1951 161 1638 -f 459 461 1538 -f 460 110 109 -f 460 109 1309 -f 110 2354 111 -f 2148 2252 2151 -f 2172 2251 2252 -f 1235 2173 2305 -f 1236 2172 1237 -f 113 1682 2135 -f 1682 2171 2356 -f 113 2135 1680 -f 1680 2136 2061 -f 551 668 552 -f 669 711 671 -f 1289 1136 1472 -f 490 493 982 -f 2150 1957 2027 -f 1958 681 512 -f 1956 1958 504 -f 1958 1957 2150 -f 1954 1863 255 -f 1861 2357 1516 -f 2358 2359 1751 -f 2358 1181 1176 -f 1751 2359 1961 -f 1751 192 2360 -f 1751 1961 2361 -f 2359 2358 1176 -f 930 2116 931 -f 1675 1678 1676 -f 1455 1484 1456 -f 58 53 51 -f 644 1456 2214 -f 1483 1485 700 -f 201 202 331 -f 1392 1532 1393 -f 360 1872 101 -f 359 2074 361 -f 1871 1586 1872 -f 1871 1856 161 -f 1870 1872 362 -f 190 2089 193 -f 1868 362 2190 -f 360 101 98 -f 2191 2278 2277 -f 2191 2177 29 -f 1165 2362 1145 -f 1622 1166 1620 -f 1165 1145 1148 -f 2362 2363 2335 -f 927 1430 1821 -f 2004 1887 1823 -f 2364 2002 913 -f 2364 141 2002 -f 2365 1090 1893 -f 2194 1332 1330 -f 2366 2031 525 -f 2030 1943 1249 -f 2031 1312 2367 -f 2031 1315 1312 -f 2031 2367 525 -f 1314 805 1718 -f 912 2107 887 -f 907 909 1443 -f 1795 1794 2007 -f 1795 1664 1666 -f 2368 118 136 -f 2368 135 1231 -f 1071 1070 2143 -f 862 2369 865 -f 864 1976 2336 -f 1070 1074 2143 -f 840 2127 742 -f 838 726 1742 -f 979 1279 1394 -f 979 1015 976 -f 1008 1012 1009 -f 1138 1142 130 -f 1012 130 129 -f 1137 1011 1139 -f 707 712 671 -f 710 124 313 -f 210 2317 211 -f 2315 1523 2011 -f 811 813 871 -f 811 2339 2144 -f 2370 1405 2218 -f 2370 1406 1405 -f 1136 1290 1686 -f 1473 1472 1474 -f 1132 1686 1133 -f 1290 492 490 -f 2371 352 354 -f 2371 961 2372 -f 1653 1567 3 -f 1653 1568 1567 -f 1031 2373 479 -f 1030 734 1032 -f 1622 2288 1165 -f 2289 2374 2288 -f 867 486 868 -f 870 813 1503 -f 866 1074 1072 -f 484 486 870 -f 866 1143 1074 -f 484 531 528 -f 2258 1038 1037 -f 2258 1371 1038 -f 1878 1583 1582 -f 2186 2185 1749 -f 1772 1770 1769 -f 1770 1773 1056 -f 1174 1179 1177 -f 1178 2360 1949 -f 1071 1010 1073 -f 2143 1074 1141 -f 2336 2375 2369 -f 2336 1608 1605 -f 836 835 76 -f 836 2076 833 -f 835 1752 568 -f 835 832 1752 -f 2039 380 377 -f 2039 2376 381 -f 1630 1479 1633 -f 1632 2034 2377 -f 1200 1203 1201 -f 1202 2293 108 -f 821 828 829 -f 821 553 1318 -f 821 829 672 -f 822 826 823 -f 2233 2378 2330 -f 2233 2379 2234 -f 2233 2330 2380 -f 2378 2381 2382 -f 1030 2373 1031 -f 1032 731 2383 -f 723 1185 724 -f 2044 2046 1626 -f 479 478 1382 -f 477 1889 480 -f 752 755 2184 -f 754 1474 755 -f 754 753 1729 -f 755 1583 2184 -f 2384 2385 2386 -f 2384 2218 1282 -f 1280 308 1056 -f 2218 2384 2386 -f 1737 568 1597 -f 1737 1617 2387 -f 2080 2079 1117 -f 2077 45 47 -f 1644 1493 956 -f 2302 1646 1857 -f 1493 1807 1801 -f 1491 2302 1494 -f 1354 379 602 -f 382 405 323 -f 2188 1305 2388 -f 2188 2163 2162 -f 2389 1158 685 -f 2389 1160 1158 -f 278 281 941 -f 685 684 2389 -f 118 2390 116 -f 2368 136 133 -f 2284 352 2372 -f 2283 2285 1284 -f 351 353 1978 -f 2284 780 2285 -f 1626 2240 2047 -f 1020 2391 2240 -f 1626 2047 2044 -f 2240 2391 2211 -f 2392 2042 2393 -f 2392 1937 2271 -f 2394 2210 1246 -f 2394 2395 1939 -f 1246 807 1787 -f 43 2210 1245 -f 1611 2394 1939 -f 2394 1365 167 -f 928 1853 1678 -f 666 2249 2396 -f 2200 1062 1064 -f 1063 1062 1067 -f 2132 1968 2134 -f 2132 539 543 -f 2397 1117 1114 -f 2397 2081 2080 -f 2176 2174 2204 -f 1935 2393 2398 -f 314 316 1286 -f 315 402 316 -f 155 154 500 -f 155 1168 936 -f 1685 2049 1683 -f 925 2102 2343 -f 2379 2380 1811 -f 2230 2234 2231 -f 151 2347 968 -f 147 2203 150 -f 2203 572 150 -f 2200 2199 2202 -f 1537 138 142 -f 1868 1536 1870 -f 142 1784 1538 -f 141 140 1391 -f 494 496 137 -f 496 495 1407 -f 2299 2304 2217 -f 1959 2026 1957 -f 1459 21 24 -f 1459 1793 21 -f 1800 1801 357 -f 954 795 797 -f 1397 1396 2196 -f 1397 1395 704 -f 1766 1344 122 -f 1763 527 1764 -f 1734 1733 1589 -f 1675 2116 930 -f 2110 1735 873 -f 1736 2399 1875 -f 1969 1968 543 -f 1969 2093 1966 -f 1968 566 2134 -f 1966 2400 1967 -f 2131 2134 2133 -f 1712 1965 1967 -f 1529 2401 1526 -f 2382 2330 2378 -f 328 2402 329 -f 328 264 2402 -f 563 2057 566 -f 2019 2023 2024 -f 935 156 938 -f 2209 1111 156 -f 1544 1028 1027 -f 1544 83 1542 -f 83 1660 84 -f 1759 1029 2264 -f 1026 1028 1543 -f 1660 49 2225 -f 271 443 1333 -f 266 268 1053 -f 1333 444 1334 -f 442 272 1488 -f 2239 2265 1029 -f 2239 776 2265 -f 2264 2263 1760 -f 2239 2403 773 -f 1466 1468 1402 -f 1984 1472 1136 -f 7 10 5 -f 1987 1467 1985 -f 1641 425 1849 -f 349 1570 1881 -f 645 1271 647 -f 1271 1273 647 -f 321 1342 2039 -f 410 408 1876 -f 410 1876 1286 -f 407 404 324 -f 515 519 516 -f 513 1939 2395 -f 2325 2171 2170 -f 2325 260 2356 -f 273 2173 276 -f 2305 275 1238 -f 1476 1475 1728 -f 1470 493 1289 -f 453 2163 2188 -f 453 452 2320 -f 327 2388 2070 -f 2188 2162 1305 -f 9 2404 544 -f 187 9 2237 -f 2404 1425 544 -f 2404 187 588 -f 619 1239 434 -f 618 620 705 -f 619 434 433 -f 1239 476 2269 -f 1076 714 2280 -f 1077 2296 715 -f 1707 2166 1918 -f 1707 885 2166 -f 951 4 1 -f 951 1450 312 -f 108 111 1203 -f 107 109 110 -f 108 1203 1202 -f 111 108 107 -f 916 2102 917 -f 879 2343 2102 -f 1087 1086 1092 -f 1089 467 1413 -f 2405 2375 1607 -f 2405 1663 2375 -f 498 500 154 -f 1933 1932 2158 -f 501 154 157 -f 500 2326 155 -f 1461 1353 1352 -f 1461 1376 1762 -f 70 1462 66 -f 1501 1352 1502 -f 2406 2182 1516 -f 2406 2007 1794 -f 1513 2182 1794 -f 1514 973 972 -f 2406 1516 2357 -f 2182 1513 1512 -f 91 2407 94 -f 96 1740 2407 -f 1256 1162 820 -f 1255 1257 1264 -f 105 1828 1822 -f 103 1331 1893 -f 88 949 86 -f 1886 1893 1413 -f 2408 2409 2072 -f 2408 1549 883 -f 1284 2410 1978 -f 1283 424 427 -f 1848 424 1284 -f 1847 1270 1641 -f 415 1848 1849 -f 418 415 1849 -f 517 667 520 -f 517 945 2411 -f 517 2411 2412 -f 944 586 1674 -f 2411 2338 2413 -f 943 945 831 -f 574 1730 575 -f 1732 2414 2128 -f 1732 1730 436 -f 1963 2126 2213 -f 1121 1123 1127 -f 1561 2415 1123 -f 2322 2096 1127 -f 2322 1154 2096 -f 1106 444 442 -f 1107 1099 1108 -f 2294 1420 2379 -f 2294 1423 1420 -f 2416 2408 883 -f 2416 2409 2408 -f 576 620 617 -f 700 705 620 -f 306 308 1215 -f 1772 1771 2206 -f 2256 1825 2313 -f 1826 1877 1824 -f 1610 1060 1059 -f 1611 1245 2210 -f 1604 1603 2350 -f 1601 846 1602 -f 1419 2345 1417 -f 2345 1603 1602 -f 1602 846 845 -f 1604 2350 1950 -f 478 1888 1383 -f 383 914 386 -f 914 383 385 -f 387 386 1774 -f 2160 696 1547 -f 1988 1990 2417 -f 1504 1505 2309 -f 1503 531 870 -f 582 584 580 -f 764 2261 765 -f 900 899 2052 -f 896 898 1971 -f 926 923 2342 -f 926 1591 924 -f 81 2418 2086 -f 79 82 1592 -f 2086 2418 2391 -f 1542 457 2085 -f 2086 2391 458 -f 78 1183 81 -f 852 856 853 -f 692 696 693 -f 2245 1095 1443 -f 1920 855 1548 -f 1920 856 855 -f 2245 1443 909 -f 2345 1602 2234 -f 846 843 842 -f 1527 2231 2234 -f 1527 845 1528 -f 2231 1527 1524 -f 1417 2234 1420 -f 277 687 280 -f 1107 444 1106 -f 2187 526 525 -f 1952 1296 581 -f 523 527 524 -f 2187 2367 1298 -f 2274 2273 2272 -f 2273 1498 366 -f 2256 2313 2257 -f 1824 1877 1233 -f 392 389 388 -f 2273 366 365 -f 252 2268 784 -f 252 251 1883 -f 1116 2385 1554 -f 1116 2386 2385 -f 1594 1597 1595 -f 568 76 835 -f 568 1752 1597 -f 2076 75 1767 -f 2387 1617 1616 -f 2387 568 1737 -f 567 1616 1924 -f 241 632 242 -f 1777 386 914 -f 1778 2073 100 -f 478 1383 1380 -f 1888 384 383 -f 1888 387 2307 -f 387 1776 2419 -f 1553 2352 2374 -f 1551 1554 1552 -f 1356 602 599 -f 1355 1706 382 -f 1354 1356 2033 -f 2103 1356 2067 -f 105 1887 1885 -f 1823 2005 2004 -f 1369 1188 1367 -f 1189 1580 1445 -f 1946 193 2088 -f 1949 1179 1178 -f 191 2360 192 -f 1946 2088 1659 -f 1403 1215 1405 -f 497 494 1216 -f 963 964 2383 -f 962 733 1679 -f 168 172 169 -f 997 1001 998 -f 1440 1437 376 -f 1865 2278 2191 -f 2277 16 19 -f 32 28 25 -f 1381 1385 1382 -f 1384 1383 2307 -f 1384 2307 2215 -f 480 1889 2082 -f 363 365 366 -f 364 2376 1342 -f 121 524 1766 -f 1199 708 1944 -f 1891 1323 1316 -f 1891 1890 1449 -f 1891 1319 2208 -f 1891 1316 1319 -f 1890 2208 712 -f 1319 1318 553 -f 298 300 299 -f 303 1278 305 -f 2249 667 2412 -f 2249 666 665 -f 1978 2410 1285 -f 1978 354 351 -f 2114 920 922 -f 2114 2332 2274 -f 1358 1257 1832 -f 1360 115 112 -f 728 283 2142 -f 284 451 1266 -f 1411 1546 737 -f 1347 738 2279 -f 884 2166 885 -f 887 2107 888 -f 2165 2246 1918 -f 2108 2165 2104 -f 1709 1918 1500 -f 887 1708 2106 -f 483 1143 481 -f 1138 130 1012 -f 55 2224 56 -f 1455 58 1484 -f 428 430 431 -f 429 310 1496 -f 1573 1846 1591 -f 1576 1571 562 -f 27 2124 2331 -f 30 26 25 -f 1949 2360 191 -f 750 1175 751 -f 1553 2374 2420 -f 2352 1213 2334 -f 1474 1472 1986 -f 1473 1475 1471 -f 1362 1364 758 -f 1790 1557 1747 -f 560 2048 1684 -f 1785 1913 1453 -f 2127 94 2407 -f 1744 839 1742 -f 1756 1348 2280 -f 1816 457 456 -f 2216 1908 2217 -f 2355 1160 1908 -f 151 968 2122 -f 152 150 1854 -f 151 2122 149 -f 2121 1534 2124 -f 69 1219 1378 -f 69 68 73 -f 1217 73 72 -f 1218 1222 1993 -f 1217 72 947 -f 1219 1701 1378 -f 2156 198 2155 -f 2156 2421 199 -f 1319 670 2208 -f 668 672 669 -f 1025 1023 1022 -f 1085 1083 1082 -f 1025 1024 1034 -f 455 458 1020 -f 1054 1281 1055 -f 1550 2017 1553 -f 2287 1657 1244 -f 2286 215 1568 -f 871 1662 811 -f 2324 2375 1663 -f 509 508 507 -f 510 2217 508 -f 2280 549 1076 -f 2280 1348 1078 -f 657 2422 714 -f 657 1173 1172 -f 717 657 713 -f 2280 2087 1756 -f 1751 2361 1750 -f 1961 1776 2361 -f 1524 1526 2232 -f 969 973 970 -f 1616 631 1926 -f 1615 1617 632 -f 1595 1752 1670 -f 568 2387 567 -f 1592 80 79 -f 1184 724 1185 -f 233 232 1427 -f 234 1688 1585 -f 123 122 950 -f 123 4 124 -f 2 4 123 -f 3 1567 2016 -f 120 124 709 -f 951 2016 1450 -f 2419 2306 387 -f 2419 1902 2215 -f 1064 2349 688 -f 1062 2200 2202 -f 1359 115 1360 -f 1682 2356 2135 -f 1922 2325 2170 -f 1360 2137 1257 -f 1621 2081 2289 -f 2080 1117 2397 -f 1305 1648 851 -f 1648 2423 2001 -f 2061 2136 2023 -f 2270 1261 1264 -f 295 304 296 -f 302 348 2138 -f 745 293 2424 -f 2266 1117 2079 -f 290 2267 291 -f 743 2424 746 -f 1627 1629 882 -f 1628 211 2317 -f 534 259 258 -f 537 536 2132 -f 543 539 541 -f 543 1968 2132 -f 2131 2132 2134 -f 1966 2093 2400 -f 1598 1130 2425 -f 1600 1867 624 -f 1997 1225 2311 -f 1997 1705 1658 -f 1094 905 904 -f 693 696 1989 -f 1097 904 906 -f 180 179 2069 -f 800 981 1307 -f 799 801 980 -f 2041 199 2421 -f 2041 816 2040 -f 1864 728 449 -f 283 286 2142 -f 361 2297 2190 -f 361 2074 2073 -f 2002 2003 913 -f 2190 1869 1868 -f 359 362 360 -f 459 964 462 -f 2152 2155 1930 -f 198 204 1928 -f 667 931 520 -f 2249 2412 2396 -f 1684 1577 561 -f 2050 924 1846 -f 248 1789 1453 -f 248 918 1558 -f 143 145 628 -f 246 918 248 -f 248 1558 1789 -f 916 245 879 -f 622 1867 1599 -f 621 1061 624 -f 623 1866 1253 -f 1131 1599 1867 -f 843 1950 2207 -f 1602 845 1527 -f 2254 1036 1041 -f 1040 2013 2426 -f 1901 1904 1176 -f 1899 2427 1269 -f 2195 1329 225 -f 1850 2192 1838 -f 694 675 674 -f 1989 696 2160 -f 1661 1662 871 -f 677 679 506 -f 513 2395 167 -f 2394 1611 2210 -f 2425 1254 1251 -f 2425 1130 2096 -f 57 1761 1873 -f 49 1660 50 -f 701 1760 2262 -f 49 54 2225 -f 2201 170 2199 -f 1155 31 1895 -f 1890 712 1446 -f 2208 670 671 -f 2183 2253 1915 -f 2230 2232 2381 -f 2183 2244 1518 -f 2253 845 842 -f 915 917 1559 -f 2049 925 2050 -f 2028 989 986 -f 1250 1943 1942 -f 2428 2353 2006 -f 2428 2226 1431 -f 2263 776 702 -f 2264 1760 1759 -f 287 292 290 -f 755 1584 1583 -f 2185 1583 1878 -f 288 294 756 -f 643 2224 55 -f 2090 2275 726 -f 2275 2214 2213 -f 722 726 723 -f 511 2037 510 -f 511 680 1120 -f 509 511 510 -f 1091 2038 468 -f 649 1909 2257 -f 653 1673 654 -f 2292 1351 778 -f 2292 2333 1351 -f 2295 254 1914 -f 2295 485 251 -f 530 1884 251 -f 2308 2429 2309 -f 153 155 938 -f 155 2326 1168 -f 854 1708 2099 -f 854 909 2106 -f 907 1443 910 -f 855 854 2099 -f 2330 1812 2380 -f 1511 971 1510 -f 296 1068 1067 -f 304 299 1947 -f 2349 414 411 -f 1659 304 1947 -f 1063 414 2349 -f 690 2281 691 -f 1659 2281 690 -f 2088 2089 1587 -f 1948 1945 1180 -f 413 691 688 -f 1610 1723 40 -f 623 1061 621 -f 1058 1060 1302 -f 40 1001 41 -f 629 1926 631 -f 630 1481 1926 -f 632 631 1615 -f 1926 1925 1924 -f 238 630 241 -f 1480 1043 1265 -f 74 77 35 -f 1926 1836 1925 -f 2414 2430 1151 -f 2414 1731 1882 -f 925 2343 923 -f 879 245 877 -f 393 397 788 -f 2314 2316 882 -f 2413 1575 1852 -f 2413 2338 1575 -f 1998 1500 1918 -f 1497 366 1498 -f 1811 2294 2379 -f 2294 834 833 -f 936 938 155 -f 935 937 1898 -f 1184 80 1592 -f 1182 2047 2211 -f 1592 84 2189 -f 2418 2211 2391 -f 1789 1558 1555 -f 248 370 249 -f 873 876 2111 -f 874 1735 2342 -f 876 310 429 -f 875 878 146 -f 167 2395 2394 -f 167 1562 163 -f 2097 2066 1134 -f 2064 592 614 -f 131 1950 2350 -f 127 130 2207 -f 1843 2164 2318 -f 2161 2162 2163 -f 229 1424 232 -f 589 186 1426 -f 1425 1424 544 -f 1427 2340 233 -f 2392 2393 1935 -f 1975 1973 1972 -f 1631 1630 1634 -f 1479 1693 1477 -f 2313 1232 1234 -f 1826 2255 1878 -f 649 2313 650 -f 2257 2013 1040 -f 2431 1238 275 -f 2431 2229 2251 -f 2034 1711 2400 -f 2034 1632 1631 -f 1572 1846 1573 -f 1684 561 560 -f 557 561 1577 -f 559 758 1364 -f 757 562 2337 -f 1747 2048 1790 -f 2167 684 682 -f 1906 2300 1101 -f 2095 999 1254 -f 1002 172 171 -f 2319 329 2402 -f 1844 2326 1845 -f 717 716 376 -f 548 1076 549 -f 713 715 1441 -f 1078 1348 2279 -f 1526 2401 2232 -f 2401 1529 2382 -f 2417 769 676 -f 1990 2099 769 -f 797 796 640 -f 952 954 1488 -f 1578 1580 1189 -f 1579 1445 1580 -f 1704 1994 2250 -f 1992 1705 1997 -f 1782 60 62 -f 459 1784 2364 -f 1930 62 976 -f 1307 109 108 -f 673 675 1988 -f 674 1522 1521 -f 692 697 445 -f 674 676 768 -f 118 117 2340 -f 1231 118 2368 -f 1244 1243 1399 -f 2260 1657 1654 -f 2430 1565 1563 -f 2430 1884 2309 -f 1563 1564 2430 -f 2144 2339 2150 -f 2309 2429 1504 -f 2308 1884 530 -f 812 1565 1505 -f 861 1982 356 -f 810 1505 813 -f 2414 1151 1149 -f 1934 2175 1935 -f 1357 129 128 -f 2042 2392 2055 -f 2393 2432 2398 -f 1935 1937 2392 -f 2175 1422 2204 -f 2271 1193 1112 -f 2176 2204 1191 -f 2093 2433 2400 -f 2093 1815 2433 -f 1171 1665 773 -f 1048 1051 1049 -f 1478 1633 1479 -f 261 263 264 -f 1631 1634 1710 -f 1477 1694 263 -f 1378 71 69 -f 64 71 65 -f 2307 2306 2215 -f 479 1382 1031 -f 882 1629 2314 -f 882 881 1214 -f 609 2069 179 -f 2317 1629 1628 -f 882 2316 880 -f 771 2317 210 -f 2290 2010 2008 -f 2348 1396 703 -f 699 1396 704 -f 2348 775 2197 -f 703 702 776 -f 1397 2196 1953 -f 1005 1716 1645 -f 1857 1494 2302 -f 223 225 87 -f 224 942 2193 -f 153 938 156 -f 1168 2219 2434 -f 2222 1371 2258 -f 1118 2014 1115 -f 336 450 334 -f 814 816 817 -f 2207 1950 127 -f 1916 1338 1914 -f 842 844 2253 -f 2207 130 1142 -f 1766 524 527 -f 121 120 709 -f 815 1388 1387 -f 1927 1163 37 -f 1161 37 1163 -f 1263 1259 1260 -f 1256 819 1832 -f 1924 36 77 -f 2116 431 931 -f 432 2111 429 -f 688 2435 1064 -f 688 691 570 -f 90 1821 1820 -f 89 1885 1887 -f 376 716 1440 -f 376 2168 1173 -f 494 137 1216 -f 137 136 1216 -f 2082 1033 2383 -f 2082 1889 1033 -f 143 628 2206 -f 145 249 824 -f 2365 1893 1331 -f 1089 2178 469 -f 255 1863 254 -f 1860 2015 1861 -f 497 1215 495 -f 306 310 307 -f 1837 1841 1838 -f 1840 2037 1093 -f 2193 2195 224 -f 1328 1332 2365 -f 1850 1841 2194 -f 2193 942 1159 -f 88 1329 1327 -f 2365 2194 2198 -f 740 742 2127 -f 739 741 2046 -f 116 2390 1231 -f 118 2340 136 -f 891 958 1980 -f 1461 65 1379 -f 2416 343 2084 -f 883 881 880 -f 1846 1577 1683 -f 1577 1576 557 -f 923 2343 2342 -f 2102 2129 917 -f 9 187 2404 -f 2238 615 1426 -f 1981 860 1564 -f 1464 1463 403 -f 1313 1315 1445 -f 1312 1311 1314 -f 1240 1579 1578 -f 1310 805 1311 -f 1487 1486 576 -f 1483 1456 1484 -f 476 618 705 -f 1239 2269 434 -f 575 1487 573 -f 476 705 473 -f 1361 2421 2156 -f 1359 1016 2341 -f 1717 996 993 -f 1717 902 1973 -f 2075 996 1973 -f 1612 1613 1614 -f 1973 996 1717 -f 2042 1974 2393 -f 1198 2055 1112 -f 1972 902 1971 -f 1287 410 316 -f 646 408 407 -f 2070 2388 851 -f 2070 2035 1634 -f 404 408 406 -f 2063 1288 1808 -f 1915 254 1863 -f 1914 1338 482 -f 1169 1896 1167 -f 2209 1614 1111 -f 1110 1113 1195 -f 1196 1193 1190 -f 1111 1614 1613 -f 1194 1110 1195 -f 1897 2209 1898 -f 2271 2055 2392 -f 932 591 593 -f 719 770 591 -f 1399 1243 1400 -f 1401 2036 1244 -f 112 2137 1360 -f 1260 1192 1262 -f 1941 1943 2030 -f 1248 708 711 -f 447 450 448 -f 334 333 336 -f 2130 701 1485 -f 2239 1029 659 -f 2038 1091 1093 -f 1088 2178 1089 -f 712 2208 671 -f 1321 1448 1322 -f 762 1691 763 -f 765 2261 1655 -f 764 763 584 -f 1691 1952 585 -f 2187 525 2367 -f 522 524 1199 -f 2398 2432 1976 -f 2398 1073 1935 -f 2337 1575 945 -f 1575 562 1571 -f 2337 759 757 -f 517 2412 667 -f 2313 1234 650 -f 119 1230 117 -f 1234 1229 119 -f 1233 1877 1585 -f 1804 2063 1808 -f 318 1340 1339 -f 567 2387 1616 -f 1617 1737 632 -f 802 975 981 -f 974 1279 979 -f 1889 2373 1033 -f 385 2082 913 -f 2082 2383 964 -f 1033 2373 1030 -f 1882 1884 2430 -f 1883 2268 252 -f 2143 1139 1010 -f 867 865 869 -f 2362 2335 1207 -f 2363 2352 2334 -f 1366 372 1912 -f 1910 992 825 -f 1366 1912 1368 -f 372 825 827 -f 1243 583 1400 -f 584 763 585 -f 1242 583 1243 -f 660 2177 2191 -f 785 1400 583 -f 1398 737 1401 -f 660 579 578 -f 1894 1919 1293 -f 2105 910 2033 -f 908 2106 909 -f 2181 1283 427 -f 1284 2285 1848 -f 1044 784 782 -f 1044 1046 784 -f 1871 161 158 -f 965 1536 1535 -f 156 935 1898 -f 903 1169 899 -f 374 22 375 -f 22 2331 20 -f 1048 375 1792 -f 22 1437 2331 -f 2319 2402 2326 -f 453 2320 2164 -f 709 124 710 -f 1343 1344 1655 -f 891 1980 1977 -f 957 1502 2329 -f 1524 2232 2231 -f 2382 971 2330 -f 368 827 369 -f 1189 1581 1578 -f 1453 370 248 -f 826 825 829 -f 570 2435 688 -f 1064 572 2200 -f 2347 148 152 -f 688 2349 689 -f 297 1067 1228 -f 1065 2202 1153 -f 411 689 2349 -f 1067 1066 1228 -f 1128 1129 1126 -f 1131 1130 1598 -f 1606 1608 1970 -f 1606 2221 1607 -f 791 720 1720 -f 590 592 595 -f 98 2074 359 -f 1775 2361 1776 -f 327 326 2188 -f 329 452 325 -f 1751 2360 2358 -f 190 194 2089 -f 195 1745 1586 -f 1777 1775 1774 -f 375 21 1793 -f 1049 1051 1173 -f 1792 1793 1794 -f 24 23 2242 -f 1102 640 2229 -f 954 2227 2228 -f 1098 1100 1104 -f 638 796 641 -f 1211 1212 1627 -f 1210 1568 211 -f 279 1624 1052 -f 940 226 1624 -f 1900 1904 1901 -f 2419 2215 2306 -f 1961 1904 1902 -f 1176 1181 750 -f 1166 1164 2346 -f 2081 1621 1623 -f 492 1136 1289 -f 1834 1134 2098 -f 1134 596 2097 -f 1133 1686 1687 -f 987 986 990 -f 1445 1315 2028 -f 1444 991 711 -f 988 1186 1189 -f 806 1313 1240 -f 1444 711 669 -f 2366 2030 2031 -f 1240 1581 1241 -f 676 769 766 -f 673 2417 676 -f 1835 2098 2065 -f 1984 1833 1987 -f 2280 2422 2087 -f 713 1441 716 -f 2410 1284 1285 -f 1849 1848 1847 -f 1754 1285 1755 -f 427 424 417 -f 285 23 20 -f 728 2142 2071 -f 595 593 590 -f 594 1687 597 -f 364 601 2376 -f 365 921 2273 -f 1983 1154 2323 -f 1152 172 1002 -f 2379 1420 2234 -f 1668 1809 1813 -f 216 2241 741 -f 1619 215 2287 -f 1818 1821 1819 -f 86 949 89 -f 1521 697 674 -f 180 2069 181 -f 81 2086 1542 -f 1542 458 457 -f 257 1593 2024 -f 2021 2020 2133 -f 2018 259 2020 -f 541 540 542 -f 2222 2426 654 -f 1039 2254 2255 -f 1664 1795 774 -f 1792 1050 1048 -f 2008 2009 2290 -f 2406 1794 2182 -f 2009 2357 1861 -f 774 2008 2010 -f 2222 2258 2426 -f 1370 746 2424 -f 388 2115 391 -f 2113 2332 2114 -f 1300 1299 1609 -f 1302 1061 1058 -f 2085 457 1756 -f 50 1027 1029 -f 454 458 455 -f 81 1183 2418 -f 754 1475 1474 -f 44 294 291 -f 1042 1798 1434 -f 237 1043 238 -f 985 603 607 -f 1042 1433 1043 -f 1554 2385 1282 -f 1116 1553 2420 -f 1552 1281 634 -f 2218 2386 2370 -f 6 5 9 -f 11 1833 614 -f 722 2224 725 -f 56 2225 54 -f 681 1662 678 -f 1956 504 508 -f 1902 1900 1899 -f 1903 749 2303 -f 1317 2032 628 -f 1447 313 1450 -f 1530 1892 636 -f 1317 628 145 -f 144 146 878 -f 628 625 2206 -f 2095 1254 2096 -f 1696 998 1722 -f 1002 2095 1154 -f 2425 1251 1598 -f 347 2139 348 -f 350 1881 2303 -f 1879 1570 1270 -f 1903 2427 1899 -f 1267 2427 1903 -f 1269 1268 2215 -f 1776 1961 1902 -f 1269 2427 1267 -f 1086 1088 1089 -f 1090 1089 1893 -f 1651 2436 1650 -f 1651 1350 2436 -f 744 1117 2266 -f 1114 2420 2397 -f 1009 1012 129 -f 1141 1139 2143 -f 2305 1238 1235 -f 1098 1101 1099 -f 2011 789 792 -f 2179 2012 767 -f 2378 2233 2381 -f 1421 1423 1422 -f 2250 2025 426 -f 2250 1642 1704 -f 2157 1979 2025 -f 426 425 2250 -f 417 420 423 -f 1217 1979 1221 -f 1413 1893 1089 -f 1412 1414 1415 -f 2118 2120 2221 -f 2120 2219 2220 -f 1607 2375 1605 -f 1605 2375 2336 -f 2221 1606 2118 -f 2119 901 900 -f 880 2316 1721 -f 881 1146 1206 -f 293 292 2424 -f 287 294 288 -f 955 272 1647 -f 442 2228 1106 -f 2124 1637 2121 -f 32 2331 1437 -f 147 149 2203 -f 1635 1637 2123 -f 1486 1483 700 -f 642 644 2214 -f 1454 2214 2275 -f 48 52 54 -f 642 2214 1454 -f 2275 2213 1743 -f 1446 313 1447 -f 3 950 1653 -f 522 1199 1944 -f 1451 1450 637 -f 1119 1120 680 -f 469 467 1089 -f 774 2007 2008 -f 2007 2357 2009 -f 1306 1303 1843 -f 1304 1197 1196 -f 1714 565 850 -f 327 1634 265 -f 1404 1403 1406 -f 1496 1216 1618 -f 1405 1215 308 -f 1407 1404 1409 -f 1496 310 309 -f 429 428 432 -f 1215 309 306 -f 430 1618 431 -f 1225 1997 2276 -f 1997 2311 1996 -f 824 1318 145 -f 821 672 551 -f 723 840 742 -f 1744 2213 2126 -f 1013 2169 2341 -f 2325 1922 1921 -f 1878 1877 1826 -f 1582 1584 1467 -f 2313 1825 1232 -f 292 1372 1370 -f 102 1827 1828 -f 1415 1414 1823 -f 1822 1828 1416 -f 927 2004 1430 -f 106 1885 89 -f 105 1822 1887 -f 1408 2222 2223 -f 2426 2013 654 -f 1003 1005 365 -f 1644 1646 2302 -f 1864 284 283 -f 2242 1435 24 -f 1645 919 921 -f 267 272 271 -f 2016 1567 2351 -f 311 4 951 -f 474 1047 782 -f 2282 1953 221 -f 927 1821 90 -f 1430 2353 1428 -f 1819 1429 1624 -f 927 89 1887 -f 1158 686 685 -f 1159 1839 2193 -f 1710 1634 2035 -f 1632 2377 1693 -f 892 1462 959 -f 1377 71 1378 -f 1377 1379 71 -f 1762 1699 2437 -f 68 63 948 -f 958 961 2371 -f 1460 1501 1462 -f 2329 2333 2292 -f 1349 1353 1350 -f 1375 1701 1698 -f 1162 34 37 -f 2076 2204 1422 -f 1223 1226 1066 -f 1638 571 691 -f 303 1658 1705 -f 2276 1227 1225 -f 471 18 14 -f 547 546 2091 -f 736 547 738 -f 15 19 16 -f 982 491 490 -f 340 344 488 -f 32 1439 28 -f 1440 716 1441 -f 655 657 1172 -f 376 1437 374 -f 633 635 636 -f 1282 2385 2384 -f 634 633 637 -f 635 634 1057 -f 552 671 670 -f 706 708 709 -f 2274 2272 2114 -f 1645 1716 1646 -f 535 258 260 -f 2023 2060 2061 -f 603 985 604 -f 1809 1752 834 -f 1928 2155 198 -f 62 978 977 -f 1835 614 1833 -f 2064 596 595 -f 596 1133 594 -f 1834 2098 1835 -f 1373 1371 1370 -f 495 1404 1407 -f 1471 1475 1476 -f 1474 1584 755 -f 487 489 1290 -f 1476 1728 2346 -f 487 1290 490 -f 493 1476 2346 -f 786 1938 18 -f 1865 2191 28 -f 470 2296 1075 -f 1075 2296 1077 -f 2191 662 660 -f 1400 785 1398 -f 1905 2217 1908 -f 510 2037 1840 -f 2300 1906 2298 -f 1851 510 1840 -f 2056 1218 1993 -f 891 948 67 -f 1702 1996 1700 -f 1995 1992 1997 -f 1378 1701 1375 -f 1992 1991 1704 -f 2364 1784 141 -f 963 2383 731 -f 891 1977 1754 -f 1977 354 1978 -f 1431 2353 2428 -f 1428 268 1429 -f 2310 2311 1224 -f 1991 1993 1222 -f 2276 1997 1658 -f 2056 1702 1701 -f 1220 2056 1701 -f 1697 1127 1123 -f 1800 2252 641 -f 2147 2027 2026 -f 263 2402 264 -f 263 1694 2402 -f 1611 1609 1301 -f 167 1365 1362 -f 1363 1913 1785 -f 1241 807 806 -f 1128 1127 2096 -f 1123 1699 1697 -f 1940 2328 440 -f 95 92 91 -f 2297 913 2003 -f 1775 99 1750 -f 1585 1469 234 -f 1749 2185 2254 -f 231 234 235 -f 1986 1584 1474 -f 1148 1147 2408 -f 1145 2362 1207 -f 1206 1208 1214 -f 2334 2335 2363 -f 1549 2408 1147 -f 2409 2416 2083 -f 847 849 2060 -f 2001 2423 1190 -f 2259 2268 434 -f 782 1047 1044 -f 2096 1130 1128 -f 1252 1254 999 -f 1599 1866 622 -f 2321 1127 1700 -f 1709 1499 886 -f 389 1498 2274 -f 1345 1347 2279 -f 1084 1546 1411 -f 277 281 278 -f 940 939 224 -f 1285 1283 1755 -f 415 424 1848 -f 893 1755 2181 -f 419 418 425 -f 1974 2432 2393 -f 1971 902 896 -f 1231 135 1672 -f 1231 2390 118 -f 646 645 1876 -f 2117 209 741 -f 839 2128 1149 -f 1150 839 1149 -f 780 779 2285 -f 777 781 778 -f 1651 1649 2438 -f 1650 624 2285 -f 1650 2415 1561 -f 352 2284 353 -f 2327 1741 93 -f 1739 1740 96 -f 682 687 1108 -f 279 1052 1335 -f 119 2439 1234 -f 134 133 137 -f 2439 1672 1671 -f 2439 1231 1672 -f 2270 2137 114 -f 1361 1832 2421 -f 1557 1790 1788 -f 1790 2048 1364 -f 1976 2432 1974 -f 865 2369 871 -f 1976 1608 2336 -f 2043 2042 2055 -f 452 329 2320 -f 1843 2318 2180 -f 348 2139 2138 -f 346 2100 349 -f 751 2139 747 -f 1881 1570 1879 -f 1180 1175 1177 -f 2100 302 301 -f 381 2376 601 -f 2039 323 321 -f 906 910 1097 -f 2248 379 378 -f 1011 1138 1012 -f 1009 129 1357 -f 1465 889 1463 -f 1806 357 1801 -f 2125 2328 95 -f 403 401 400 -f 94 1291 95 -f 723 742 2045 -f 1465 439 890 -f 2127 2407 740 -f 398 401 399 -f 2407 91 96 -f 2328 2125 440 -f 441 1151 890 -f 410 1287 409 -f 2101 1982 2149 -f 262 261 265 -f 2320 2318 2164 -f 1679 1204 1205 -f 732 731 1032 -f 1766 122 121 -f 2 950 3 -f 214 2241 216 -f 1035 1626 2241 -f 533 540 536 -f 2152 1016 2154 -f 964 913 2082 -f 197 203 198 -f 2362 2288 2363 -f 756 46 1729 -f 2346 983 493 -f 1549 1146 881 -f 2411 945 2338 -f 514 1609 1939 -f 1236 1238 2431 -f 2173 2147 276 -f 2172 2431 2251 -f 2431 1104 2229 -f 2148 2172 2252 -f 1017 2229 640 -f 803 805 1313 -f 1312 1298 2367 -f 605 1874 1799 -f 1507 1511 1510 -f 617 437 576 -f 433 1731 436 -f 1351 2333 1349 -f 2292 781 2372 -f 2366 525 1944 -f 1297 2187 1295 -f 2030 2366 1941 -f 1766 1690 1344 -f 1549 1147 1144 -f 2416 2084 2083 -f 788 787 790 -f 1211 1214 1208 -f 1274 181 210 -f 382 323 377 -f 1169 1167 936 -f 1168 2326 2220 -f 2371 354 1980 -f 353 1284 1978 -f 958 2371 1980 -f 960 957 2329 -f 893 891 1754 -f 353 2284 2283 -f 6 544 228 -f 233 2340 1230 -f 1467 1469 1582 -f 1229 1233 1230 -f 588 1425 2404 -f 231 235 230 -f 627 1531 1773 -f 1553 2017 2352 -f 627 1773 2205 -f 1530 2032 1892 -f 1770 1056 307 -f 637 1450 2016 -f 325 327 265 -f 2402 1694 2326 -f 1807 1806 1801 -f 1805 1288 1287 -f 355 1806 1805 -f 1493 1801 956 -f 1678 2399 1736 -f 1852 2396 2413 -f 2156 199 198 -f 2041 819 817 -f 2117 1740 1541 -f 739 2046 2045 -f 1169 2052 899 -f 1607 2220 2405 -f 1110 1194 1111 -f 2052 2434 900 -f 1528 845 2253 -f 2230 2381 2233 -f 1144 1146 1549 -f 2315 2314 2317 -f 882 1214 1627 -f 1566 1213 2352 -f 1342 2376 2039 -f 1858 1341 1494 -f 381 601 600 -f 1006 365 364 -f 1173 1051 1170 -f 373 2168 376 -f 1666 1792 1794 -f 376 1173 717 -f 2324 1663 1661 -f 2405 2220 1663 -f 1734 2247 1735 -f 1589 1588 926 -f 874 877 872 -f 1559 2129 1556 -f 2342 2247 926 -f 2109 2110 873 -f 1875 2399 1678 -f 872 877 878 -f 853 909 854 -f 854 2106 1708 -f 184 697 610 -f 911 910 2105 -f 1861 2015 2009 -f 1955 255 253 -f 1514 1513 973 -f 2406 2357 2007 -f 2243 1863 1540 -f 1513 1794 1793 -f 168 1157 171 -f 2121 149 2122 -f 1921 540 535 -f 1814 801 1815 -f 981 800 802 -f 800 2293 801 -f 59 978 62 -f 1279 1815 2092 -f 1205 1203 2354 -f 1200 735 734 -f 1644 1643 1646 -f 2274 2332 389 -f 919 1962 270 -f 1492 1491 1495 -f 2315 771 1523 -f 177 182 1706 -f 1165 2288 2362 -f 44 1386 294 -f 215 217 1568 -f 217 208 207 -f 759 2337 944 -f 1852 1575 1574 -f 1679 2354 462 -f 108 2293 1307 -f 1895 31 30 -f 1155 1157 168 -f 2196 1396 2197 -f 1397 1953 1395 -f 1787 1913 1363 -f 368 372 827 -f 84 2225 2189 -f 1544 1027 1660 -f 1588 1590 1574 -f 664 929 931 -f 281 280 683 -f 1108 1335 1334 -f 2389 2301 1160 -f 1108 687 1335 -f 2295 251 250 -f 529 532 2429 -f 247 246 249 -f 1556 2129 1748 -f 1387 450 336 -f 1481 1836 1926 -f 448 450 1388 -f 282 23 285 -f 727 728 2071 -f 451 1265 1266 -f 746 1371 1409 -f 1370 2424 292 -f 745 2424 743 -f 2236 2186 292 -f 1443 1097 910 -f 445 697 184 -f 870 531 484 -f 811 1662 2339 -f 801 2293 1815 -f 1930 976 2153 -f 836 833 832 -f 132 128 125 -f 530 251 485 -f 435 1731 433 -f 2428 2005 2226 -f 1430 1429 1819 -f 1416 104 1886 -f 2006 2005 2428 -f 794 949 88 -f 269 2226 2112 -f 1006 364 1342 -f 378 600 2248 -f 363 601 364 -f 1492 1495 1804 -f 772 2010 2290 -f 1513 1793 1459 -f 773 776 2239 -f 2197 2015 219 -f 1171 2403 658 -f 776 775 703 -f 658 2403 2239 -f 1442 1441 16 -f 1171 773 2403 -f 714 2422 2280 -f 2134 566 2057 -f 543 542 2092 -f 1965 566 1968 -f 895 2020 259 -f 2194 2365 1332 -f 1823 1414 2226 -f 1086 1090 1092 -f 225 88 87 -f 488 491 340 -f 1687 594 1133 -f 1468 1987 10 -f 1687 344 597 -f 1106 2228 2227 -f 271 1335 1052 -f 888 2166 884 -f 884 886 1708 -f 1845 2159 1306 -f 1933 2326 500 -f 2060 850 847 -f 1967 2400 1711 -f 475 2259 2269 -f 2268 1883 435 -f 434 2269 2259 -f 1487 2212 2214 -f 252 784 1046 -f 473 705 704 -f 1045 1047 2282 -f 1732 1731 2414 -f 253 256 1955 -f 699 705 700 -f 662 2191 2277 -f 375 2168 373 -f 1556 1555 1559 -f 247 249 145 -f 1217 947 1979 -f 1753 422 420 -f 501 499 498 -f 993 2054 1717 -f 911 2107 912 -f 2166 2165 1918 -f 570 572 2435 -f 1064 2435 572 -f 1719 1157 1294 -f 172 2202 169 -f 1867 622 624 -f 998 1695 999 -f 788 791 1720 -f 595 592 2064 -f 1505 810 812 -f 678 1663 679 -f 1671 650 2439 -f 1231 2439 119 -f 1807 1492 1804 -f 798 641 796 -f 2302 1493 1644 -f 1018 2252 2251 -f 2080 2078 2079 -f 754 1729 1475 -f 1301 1060 1610 -f 1562 167 758 -f 1065 1153 1223 -f 2321 1154 2322 -f 1225 1227 1226 -f 690 412 1659 -f 303 1705 1703 -f 1153 2202 172 -f 1135 1834 1835 -f 2237 613 616 -f 2415 1650 2436 -f 2291 1651 2438 -f 2415 2436 2437 -f 777 779 780 -f 200 199 332 -f 1681 1359 2341 -f 2043 2055 2075 -f 1196 2423 1304 -f 545 1078 546 -f 1756 2087 2085 -f 1345 2279 1348 -f 547 736 471 -f 18 737 786 -f 1410 1817 1085 -f 1872 1586 101 -f 1725 1854 150 -f 1652 950 1343 -f 637 2017 1550 -f 914 913 1777 -f 2364 964 459 -f 1703 1642 1278 -f 1994 2157 2250 -f 901 898 897 -f 2398 1976 864 -f 1970 1608 1972 -f 1607 2221 2220 -f 939 281 942 -f 2389 684 2301 -f 747 2139 748 -f 1268 1270 1385 -f 1604 843 846 -f 844 1915 2253 -f 111 2354 1203 -f 1309 60 1782 -f 963 962 964 -f 1308 1307 981 -f 2286 1568 1653 -f 787 792 789 -f 809 807 1246 -f 1294 1157 1156 -f 761 763 764 -f 577 581 1919 -f 1915 2244 2183 -f 218 256 221 -f 377 323 2039 -f 2068 182 181 -f 1190 2423 1196 -f 2000 1261 2061 -f 2301 2167 2298 -f 268 1052 1429 -f 1727 1855 1854 -f 2364 913 964 -f 2049 2129 2102 -f 371 1913 1912 -f 1846 924 1591 -f 917 2129 1559 -f 1143 1141 1074 -f 481 1143 868 -f 869 865 871 -f 864 1073 2398 -f 1778 913 2073 -f 1384 2215 1385 -f 969 971 972 -f 1667 985 984 -f 1958 2150 681 -f 2145 1982 1981 -f 973 1513 1459 -f 1529 971 2382 -f 1540 1518 2244 -f 2401 2381 2232 -f 1528 1519 1525 -f 1516 1862 1861 -f 1478 1634 1633 -f 1714 850 2058 -f 555 1674 165 -f 587 517 516 -f 1277 1278 1642 -f 2310 1224 1983 -f 297 1228 2276 -f 1640 1642 2250 -f 2130 1873 1761 -f 1456 1487 2214 -f 1485 698 700 -f 2197 775 772 -f 1759 1761 50 -f 1239 618 476 -f 1623 45 2077 -f 2266 2267 293 -f 1206 1145 1207 -f 2289 2081 2397 -f 2363 2288 2352 -f 2408 2072 1148 -f 2351 2017 2016 -f 2374 2289 2397 -f 1554 1553 1116 -f 1729 1728 1475 -f 2365 2198 1090 -f 468 1120 466 -f 464 469 465 -f 2217 510 1851 -f 2382 2381 2401 -f 1603 2345 2344 -f 285 2331 2124 -f 1457 1435 1458 -f 1941 2366 1944 -f 1656 1690 1692 -f 1444 672 829 -f 1247 990 989 -f 1942 1941 708 -f 1310 1315 1313 -f 1115 2386 1116 -f 134 2223 1673 -f 934 1720 720 -f 597 344 345 -f 1506 789 2012 -f 1721 396 393 -f 2391 1020 458 -f 1021 1626 1035 -f 2227 1103 1106 -f 1102 2229 1104 -f 640 1102 797 -f 1098 1104 275 -f 442 1488 2228 -f 2112 922 269 -f 684 2167 2301 -f 798 953 1801 -f 126 130 127 -f 125 129 126 -f 1154 2321 2323 -f 1375 1699 1376 -f 1996 2310 1700 -f 1152 1154 1983 -f 1700 2312 2321 -f 1991 1222 1221 -f 1352 1501 1460 -f 1254 2425 2096 -f 1902 1269 2215 -f 1384 1381 1380 -f 1353 1762 2437 -f 68 948 946 -f 1033 1032 2383 -f 1031 1382 734 -f 1401 737 1546 -f 1656 762 765 -f 670 1319 553 -f 872 878 875 -f 2040 816 1389 -f 1361 2156 2154 -f 110 462 2354 -f 2141 2140 205 -f 817 816 2041 -f 139 1537 206 -f 820 819 1256 -f 2140 2142 286 -f 1511 1812 2330 -f 240 606 236 -f 1484 1873 1485 -f 1660 2225 84 -f 2416 883 343 -f 767 770 2179 -f 1522 768 611 -f 395 593 595 -f 1750 2361 1775 -f 1960 2359 1176 -f 1546 213 1401 -f 207 209 210 -f 2241 2046 741 -f 1019 1024 1022 -f 1546 1081 213 -f 1816 1817 1346 -f 1818 1624 226 -f 1838 2192 1839 -f 1965 1968 1966 -f 2433 2377 2034 -f 1242 2260 764 -f 1657 2286 1653 -f 1969 543 2093 -f 2092 1815 2093 -f 2113 390 2332 -f 1499 391 886 -f 1512 1514 1519 -f 844 1916 1915 -f 887 2106 912 -f 1547 2099 2160 -f 1739 1741 2327 -f 1149 2128 2414 -f 740 1740 2117 -f 2189 724 1592 -f 1350 1651 1351 -f 1350 2437 2436 -f 17 16 715 -f 25 29 30 -f 1339 1006 1342 -f 270 1962 1647 -f 367 366 2067 -f 2115 2226 391 -f 507 504 503 -f 2026 276 2147 -f 1478 265 1634 -f 1842 2180 1844 -f 2034 2400 2433 -f 2161 2164 1843 -f 342 2084 343 -f 1164 2072 2346 -f 1115 1406 2370 -f 290 293 2267 -f 1897 2054 995 -f 900 2434 2219 -f 1769 1768 1771 -f 134 496 2223 -f 1054 1056 1057 -f 1757 1758 2111 -f 2439 650 1234 -f 1672 135 1673 -f 1772 2205 1773 -f 875 1768 876 -f 710 707 706 -f 821 1318 828 -f 2206 2205 1772 -f 669 672 1444 -f 875 146 1771 -f 926 2247 1589 -f 307 1056 308 -f 823 826 828 -f 1198 1111 1613 -f 2219 1168 2220 -f 1803 1495 1494 -f 357 2101 2151 -f 317 1286 1876 -f 1962 1645 1647 -f 966 1854 967 -f 1951 2281 330 -f 170 2201 1636 -f 968 2347 152 -f 159 158 162 -f 1228 1066 1226 -f 529 2429 2308 -f 871 2369 2324 -f 837 723 726 -f 56 54 52 -f 2240 2211 2047 -f 2045 742 739 -f 2284 2372 780 -f 2181 422 1753 -f 772 776 773 -f 2263 702 2262 -f 1649 779 2438 -f 2292 2372 961 -f 39 1245 40 -f 1696 1059 1253 -f 2022 2021 2133 -f 2136 2135 260 -f 299 2138 1947 -f 1659 1947 1946 -f 423 422 2181 -f 418 1849 425 -f 1230 1688 233 -f 2013 651 654 -f 1183 2211 2418 -f 656 2087 2422 -f 1640 425 1641 -f 427 423 2181 -f 2067 599 367 -f 1706 182 382 -f 59 1308 978 -f 980 801 1814 -f 1574 1590 1853 -f 1573 1591 1588 -f 928 931 929 -f 431 136 520 -f 2413 2396 2412 -f 515 520 518 -f 367 598 601 -f 2033 910 906 -f 2327 315 1739 -f 1185 2045 2044 -f 602 2248 598 -f 93 97 2327 -f 1999 2103 2067 -f 1857 1646 1716 -f 407 324 405 -f 1800 357 2151 -f 250 252 256 -f 1565 2309 1505 -f 1504 2429 532 -f 2145 2144 2150 -f 2414 1882 2430 -f 1505 1504 1503 -f 1151 2430 1564 -f 2309 1565 2430 -f 1300 1609 514 -f 1245 1610 40 -f 673 1988 2417 -f 175 183 173 -f 1990 769 2417 -f 694 674 697 -f 609 1523 771 -f 2012 770 1506 -f 223 87 226 -f 2005 1823 2226 -f 224 226 940 -f 1428 2353 1431 -f 1840 1837 1851 -f 686 942 281 -f 1651 2291 1351 -f 779 1650 2285 -f 1123 2437 1699 -f 781 780 2372 -f 1426 189 188 -f 11 10 1833 -f 616 187 2237 -f 229 544 1424 -f 1767 2204 2076 -f 1896 2054 1897 -f 1976 1974 1972 -f 1896 2051 2054 -f 630 238 1481 -f 1432 1434 1458 -f 1872 360 362 -f 193 2089 2088 -f 1673 653 1671 -f 2257 1909 2013 -f 1116 2420 1114 -f 1209 1213 1210 -f 681 2339 1662 -f 1957 1956 1959 -f 2261 1654 1655 -f 2287 1244 2036 -f 666 2396 1852 -f 555 760 1674 -f 803 1313 806 -f 986 1445 2028 -f 555 757 760 -f 2411 2413 2412 -f 554 758 559 -f 369 827 249 -f 586 165 1674 -f 560 559 1364 -f 41 804 809 -f 1302 520 1061 -f 977 976 62 -f 2135 2356 260 -f 100 2074 98 -f 460 462 110 -f 1856 1871 1870 -f 729 731 732 -f 2072 2409 983 -f 608 1523 609 -f 342 341 2084 -f 2064 2097 596 -f 982 983 2083 -f 1721 395 597 -f 2336 2369 862 -f 506 679 680 -f 350 2303 748 -f 1889 479 2373 -f 1277 2100 301 -f 1178 1181 2358 -f 1708 391 2099 -f 1998 2246 1999 -f 1998 1918 2246 -f 2160 2099 1990 -f 2001 2000 848 -f 113 115 1681 -f 291 2267 47 -f 652 651 1909 -f 2165 2108 2246 -f 795 953 798 -f 1832 819 2421 -f 1265 448 1388 -f 2041 2421 819 -f 1489 34 1490 -f 1693 2377 1694 -f 2433 1815 1694 -f 536 539 2132 -f 2164 2163 453 -f 1797 2241 214 -f 1568 1210 1566 -f 2355 1839 1159 -f 2235 467 1414 -f 1868 1391 1390 -f 1745 101 1586 -f 2419 1776 1902 -f 1179 1949 1948 -f 2358 2360 1178 -f 2311 1225 1224 -f 1349 2333 1352 -f 2372 352 2371 -f 2437 1350 1353 -f 778 2291 2438 -f 2415 2437 1123 -f 1848 2285 1270 -f 752 288 753 -f 1427 1426 2340 -f 2233 2380 2379 -f 1813 1509 1669 -f 2370 2386 1115 -f 625 627 2205 -f 2397 2420 2374 -f 1733 1735 2110 -f 20 2331 285 -f 222 2196 219 -f 2095 1000 997 -f 41 1791 808 -f 1421 128 1418 -f 843 1604 1950 -f 836 76 74 -f 1263 1490 2094 -f 1304 2423 1648 -f 1809 834 1811 -f 2133 2057 2022 -f 2188 2388 327 -f 2059 850 2060 -f 851 2388 1305 -f 1303 1305 2162 -f 2159 1845 2326 -f 959 1502 957 -f 1641 1270 1570 -f 1883 251 1884 -f 483 1338 1142 -f 48 50 51 -f 725 2224 643 -f 13 15 16 -f 1938 19 18 -f 1907 276 1959 -f 2149 1982 2145 -f 82 84 1592 -f 1021 1024 1019 -f 776 2263 2265 -f 17 2296 470 -f 1032 734 732 -f 1382 1385 734 -f 335 728 727 -f 2277 1442 16 -f 1061 520 624 -f 1610 1059 1723 -f 1368 1913 1787 -f 1296 1295 1292 -f 1362 758 167 -f 1910 825 372 -f 429 2111 876 -f 514 518 1300 -f 1964 2128 2126 -f 841 1291 2127 -f 2119 900 2219 -f 2209 1897 995 -f 1389 332 2040 -f 727 331 202 -f 975 974 977 -f 1798 1042 237 -f 1014 2153 1015 -f 735 733 732 -f 2297 361 2073 -f 1901 1176 749 -f 2359 1960 1961 -f 1535 1536 1393 -f 522 1944 525 -f 1250 1249 1943 -f 6 9 544 -f 133 135 2368 -f 227 12 228 -f 2258 1040 2426 -f 2009 2015 2290 -f 1524 1528 1525 -f 714 1077 715 -f 2123 31 1635 -f 1919 578 577 -f 2287 2036 1619 -f 715 16 1441 -f 1764 1297 1765 -f 2294 1811 834 -f 1874 604 1508 -f 180 182 176 -f 1094 1096 905 -f 366 1497 1917 -f 1276 1272 405 -f 2324 2369 2375 -f 274 276 1907 -f 1422 1423 833 -f 903 1717 2053 -f 1765 1952 1691 -f 1050 1170 1051 -f 2014 1409 1406 -f 2288 2374 2352 -f 1331 1328 2365 -f 466 679 1414 -f 1908 1160 2301 -f 89 949 106 -f 942 686 1159 -f 2112 2226 2115 -f 274 1101 275 -f 1052 1624 1429 -f 1763 1692 1690 -f 2351 1566 2352 -f 1654 2261 2260 -f 1292 1295 1298 -f 2079 47 2267 -f 2083 983 2409 -f 2127 1291 94 -f 1756 1816 1346 -f 575 2213 2212 -f 222 1953 2196 -f 1964 2126 1963 -f 1346 1817 1410 -f 843 2207 844 -f 1119 679 466 -f 2218 308 1280 -f 1585 1877 1582 -f 239 242 240 -f 2174 2175 2204 -f 131 2350 132 -f 900 897 896 -f 2295 1914 482 -f 1936 1935 2175 -f 1357 1073 1010 -f 1069 1073 864 -f 1320 2032 1317 -f 1791 1001 171 -f 1561 624 1650 -f 829 825 992 -f 1510 1458 1434 -f 1594 984 242 -f 421 1979 1753 -f 779 778 2438 -f 286 1534 2140 -f 2341 2169 2170 -f 1174 750 1181 -f 64 63 68 -f 2061 849 2000 -f 2035 1967 1711 -f 2325 2356 2171 -f 2094 1259 1263 -f 1836 1482 1625 -f 2318 2319 2180 -f 1054 634 1281 -f 2223 654 1673 -f 3 2016 951 -f 1316 1323 1317 -f 337 345 344 -f 591 769 592 -f 419 426 421 -f 1226 1223 1225 -f 641 1018 639 -f 505 502 512 -f 311 313 124 -f 456 1085 1817 -f 1275 209 2117 -f 698 1485 701 -f 699 703 1396 -f 1433 1435 2242 -f 293 745 2266 -f 2340 615 136 -f 1618 1216 136 -f 614 592 615 -f 275 1104 2431 -f 272 443 271 -f 675 694 1989 -f 2172 1236 2431 -f 391 2226 2099 -f 1159 1160 2355 -f 218 220 1954 -f 1796 1025 1035 -f 1678 1736 1676 -f 1531 1057 1773 -f 1026 1029 1027 -f 1740 740 2407 -f 711 708 707 -f 931 431 520 -f 1703 1278 303 -f 160 1587 194 -f 1534 2121 1535 -f 1811 2380 1812 -f 237 606 1798 -f 1515 1520 1516 -f 1571 1576 1572 -f 1212 1628 1627 -f 889 858 356 -f 741 209 216 -f 1729 46 1728 -f 117 1230 2340 -f 783 784 2268 -f 2422 657 656 -f 1446 710 313 -f 1246 1365 2394 -f 1255 1259 1256 -f 1393 1532 1535 -f 2201 149 1636 -f 1560 624 1561 -f 2377 2433 1694 -f 2293 734 1815 -f 2307 1383 1888 -f 1502 1352 2333 -f 467 466 1414 -f 2252 1800 2151 -f 1738 1541 1740 -f 44 291 47 -f 1663 2220 679 -f 1142 1338 1916 -f 1411 737 738 -f 2260 1242 1244 -f 2434 2052 1168 -f 1260 1259 1258 -f 286 2124 1534 -f 572 2203 2200 -f 1844 2180 2319 -f 1394 1279 2092 -f 1202 734 2293 -f 1385 1270 734 diff --git a/Videos/olcPGEX_Graphics2D.h b/Videos/olcPGEX_Graphics2D.h deleted file mode 100644 index de8c0f3..0000000 --- a/Videos/olcPGEX_Graphics2D.h +++ /dev/null @@ -1,313 +0,0 @@ -/* - olcPGEX_Graphics2D.h - - +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine Extension | - | Advanced 2D Rendering - v0.4 | - +-------------------------------------------------------------+ - - What is this? - ~~~~~~~~~~~~~ - This is an extension to the olcPixelGameEngine, which provides - advanced olc::Sprite manipulation and drawing routines. To use - it, simply include this header file. - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - -/* - Matrices stored as [Column][Row] (i.e. x, y) - - |C0R0 C1R0 C2R0| | x | | x'| - |C0R1 C1R1 C2R1| * | y | = | y'| - |C0R2 C1R2 C2R2| |1.0| | - | -*/ - - - -#ifndef OLC_PGEX_GFX2D -#define OLC_PGEX_GFX2D - -#include -#undef min -#undef max - -namespace olc -{ - // Container class for Advanced 2D Drawing functions - class GFX2D : public olc::PGEX - { - // A representation of an affine transform, used to rotate, scale, offset & shear space - public: - class Transform2D - { - public: - inline Transform2D(); - - public: - // Set this transformation to unity - inline void Reset(); - // Append a rotation of fTheta radians to this transform - inline void Rotate(float fTheta); - // Append a translation (ox, oy) to this transform - inline void Translate(float ox, float oy); - // Append a scaling operation (sx, sy) to this transform - inline void Scale(float sx, float sy); - // Append a shear operation (sx, sy) to this transform - inline void Shear(float sx, float sy); - - inline void Perspective(float ox, float oy); - // Calculate the Forward Transformation of the coordinate (in_x, in_y) -> (out_x, out_y) - inline void Forward(float in_x, float in_y, float &out_x, float &out_y); - // Calculate the Inverse Transformation of the coordinate (in_x, in_y) -> (out_x, out_y) - inline void Backward(float in_x, float in_y, float &out_x, float &out_y); - // Regenerate the Inverse Transformation - inline void Invert(); - - private: - inline void Multiply(); - float matrix[4][3][3]; - int nTargetMatrix; - int nSourceMatrix; - bool bDirty; - }; - - public: - // Draws a sprite with the transform applied - inline static void DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform); - }; -} - - -#ifdef OLC_PGE_GRAPHICS2D -#undef OLC_PGE_GRAPHICS2D - -namespace olc -{ - void GFX2D::DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform) - { - if (sprite == nullptr) - return; - - // Work out bounding rectangle of sprite - float ex, ey; - float sx, sy; - float px, py; - - transform.Forward(0.0f, 0.0f, sx, sy); - px = sx; py = sy; - sx = std::min(sx, px); sy = std::min(sy, py); - ex = std::max(ex, px); ey = std::max(ey, py); - - transform.Forward((float)sprite->width, (float)sprite->height, px, py); - sx = std::min(sx, px); sy = std::min(sy, py); - ex = std::max(ex, px); ey = std::max(ey, py); - - transform.Forward(0.0f, (float)sprite->height, px, py); - sx = std::min(sx, px); sy = std::min(sy, py); - ex = std::max(ex, px); ey = std::max(ey, py); - - transform.Forward((float)sprite->width, 0.0f, px, py); - sx = std::min(sx, px); sy = std::min(sy, py); - ex = std::max(ex, px); ey = std::max(ey, py); - - // Perform inversion of transform if required - transform.Invert(); - - if (ex < sx) - std::swap(ex, sx); - if (ey < sy) - std::swap(ey, sy); - - // Iterate through render space, and sample Sprite from suitable texel location - for (float i = sx; i < ex; i++) - { - for (float j = sy; j < ey; j++) - { - float ox, oy; - transform.Backward(i, j, ox, oy); - pge->Draw((int32_t)i, (int32_t)j, sprite->GetPixel((int32_t)(ox+0.5f), (int32_t)(oy+0.5f))); - } - } - } - - olc::GFX2D::Transform2D::Transform2D() - { - Reset(); - } - - void olc::GFX2D::Transform2D::Reset() - { - nTargetMatrix = 0; - nSourceMatrix = 1; - bDirty = true; - - // Columns Then Rows - - // Matrices 0 & 1 are used as swaps in Transform accumulation - matrix[0][0][0] = 1.0f; matrix[0][1][0] = 0.0f; matrix[0][2][0] = 0.0f; - matrix[0][0][1] = 0.0f; matrix[0][1][1] = 1.0f; matrix[0][2][1] = 0.0f; - matrix[0][0][2] = 0.0f; matrix[0][1][2] = 0.0f; matrix[0][2][2] = 1.0f; - - matrix[1][0][0] = 1.0f; matrix[1][1][0] = 0.0f; matrix[1][2][0] = 0.0f; - matrix[1][0][1] = 0.0f; matrix[1][1][1] = 1.0f; matrix[1][2][1] = 0.0f; - matrix[1][0][2] = 0.0f; matrix[1][1][2] = 0.0f; matrix[1][2][2] = 1.0f; - - // Matrix 2 is a cache matrix to hold the immediate transform operation - // Matrix 3 is a cache matrix to hold the inverted transform - } - - void olc::GFX2D::Transform2D::Multiply() - { - for (int c = 0; c < 3; c++) - { - for (int r = 0; r < 3; r++) - { - matrix[nTargetMatrix][c][r] = matrix[2][0][r] * matrix[nSourceMatrix][c][0] + - matrix[2][1][r] * matrix[nSourceMatrix][c][1] + - matrix[2][2][r] * matrix[nSourceMatrix][c][2]; - } - } - - std::swap(nTargetMatrix, nSourceMatrix); - bDirty = true; // Any transform multiply dirties the inversion - } - - void olc::GFX2D::Transform2D::Rotate(float fTheta) - { - // Construct Rotation Matrix - matrix[2][0][0] = cosf(fTheta); matrix[2][1][0] = sinf(fTheta); matrix[2][2][0] = 0.0f; - matrix[2][0][1] = -sinf(fTheta); matrix[2][1][1] = cosf(fTheta); matrix[2][2][1] = 0.0f; - matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f; - Multiply(); - } - - void olc::GFX2D::Transform2D::Scale(float sx, float sy) - { - // Construct Scale Matrix - matrix[2][0][0] = sx; matrix[2][1][0] = 0.0f; matrix[2][2][0] = 0.0f; - matrix[2][0][1] = 0.0f; matrix[2][1][1] = sy; matrix[2][2][1] = 0.0f; - matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f; - Multiply(); - } - - void olc::GFX2D::Transform2D::Shear(float sx, float sy) - { - // Construct Shear Matrix - matrix[2][0][0] = 1.0f; matrix[2][1][0] = sx; matrix[2][2][0] = 0.0f; - matrix[2][0][1] = sy; matrix[2][1][1] = 1.0f; matrix[2][2][1] = 0.0f; - matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f; - Multiply(); - } - - void olc::GFX2D::Transform2D::Translate(float ox, float oy) - { - // Construct Translate Matrix - matrix[2][0][0] = 1.0f; matrix[2][1][0] = 0.0f; matrix[2][2][0] = ox; - matrix[2][0][1] = 0.0f; matrix[2][1][1] = 1.0f; matrix[2][2][1] = oy; - matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f; - Multiply(); - } - - void olc::GFX2D::Transform2D::Perspective(float ox, float oy) - { - // Construct Translate Matrix - matrix[2][0][0] = 1.0f; matrix[2][1][0] = 0.0f; matrix[2][2][0] = 0.0f; - matrix[2][0][1] = 0.0f; matrix[2][1][1] = 1.0f; matrix[2][2][1] = 0.0f; - matrix[2][0][2] = ox; matrix[2][1][2] = oy; matrix[2][2][2] = 1.0f; - Multiply(); - } - - void olc::GFX2D::Transform2D::Forward(float in_x, float in_y, float &out_x, float &out_y) - { - out_x = in_x * matrix[nSourceMatrix][0][0] + in_y * matrix[nSourceMatrix][1][0] + matrix[nSourceMatrix][2][0]; - out_y = in_x * matrix[nSourceMatrix][0][1] + in_y * matrix[nSourceMatrix][1][1] + matrix[nSourceMatrix][2][1]; - float out_z = in_x * matrix[nSourceMatrix][0][2] + in_y * matrix[nSourceMatrix][1][2] + matrix[nSourceMatrix][2][2]; - if (out_z != 0) - { - out_x /= out_z; - out_y /= out_z; - } - } - - void olc::GFX2D::Transform2D::Backward(float in_x, float in_y, float &out_x, float &out_y) - { - out_x = in_x * matrix[3][0][0] + in_y * matrix[3][1][0] + matrix[3][2][0]; - out_y = in_x * matrix[3][0][1] + in_y * matrix[3][1][1] + matrix[3][2][1]; - float out_z = in_x * matrix[3][0][2] + in_y * matrix[3][1][2] + matrix[3][2][2]; - if (out_z != 0) - { - out_x /= out_z; - out_y /= out_z; - } - } - - void olc::GFX2D::Transform2D::Invert() - { - if (bDirty) // Obviously costly so only do if needed - { - float det = matrix[nSourceMatrix][0][0] * (matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][1][2] * matrix[nSourceMatrix][2][1]) - - matrix[nSourceMatrix][1][0] * (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][2][1] * matrix[nSourceMatrix][0][2]) + - matrix[nSourceMatrix][2][0] * (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][0][2]); - - float idet = 1.0f / det; - matrix[3][0][0] = (matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][1][2] * matrix[nSourceMatrix][2][1]) * idet; - matrix[3][1][0] = (matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][1][0] * matrix[nSourceMatrix][2][2]) * idet; - matrix[3][2][0] = (matrix[nSourceMatrix][1][0] * matrix[nSourceMatrix][2][1] - matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][1][1]) * idet; - matrix[3][0][1] = (matrix[nSourceMatrix][2][1] * matrix[nSourceMatrix][0][2] - matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][2]) * idet; - matrix[3][1][1] = (matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][0][2]) * idet; - matrix[3][2][1] = (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][0] - matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][2][1]) * idet; - matrix[3][0][2] = (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][0][2] * matrix[nSourceMatrix][1][1]) * idet; - matrix[3][1][2] = (matrix[nSourceMatrix][0][2] * matrix[nSourceMatrix][1][0] - matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][1][2]) * idet; - matrix[3][2][2] = (matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][1][1] - matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][0]) * idet; - bDirty = false; - } - } -} - -#endif -#endif \ No newline at end of file diff --git a/Videos/olcPGEX_Graphics3D.h b/Videos/olcPGEX_Graphics3D.h deleted file mode 100644 index 9c6dd80..0000000 --- a/Videos/olcPGEX_Graphics3D.h +++ /dev/null @@ -1,1174 +0,0 @@ -/* - olcPGEX_Graphics3D.h - - +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine Extension | - | 3D Rendering - v0.1 | - +-------------------------------------------------------------+ - - What is this? - ~~~~~~~~~~~~~ - This is an extension to the olcPixelGameEngine, which provides - support for software rendering 3D graphics. - - NOTE!!! This file is under development and may change! - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018-2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Patreon: https://www.patreon.com/javidx9 - Homepage: https://www.onelonecoder.com - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2018 -*/ - - -#ifndef OLC_PGEX_GFX3D -#define OLC_PGEX_GFX3D - -#include -#include -#include -#undef min -#undef max - -namespace olc -{ - // Container class for Advanced 2D Drawing functions - class GFX3D : public olc::PGEX - { - - public: - - struct vec2d - { - float x = 0; - float y = 0; - float z = 0; - }; - - struct vec3d - { - float x = 0; - float y = 0; - float z = 0; - float w = 1; // Need a 4th term to perform sensible matrix vector multiplication - }; - - struct triangle - { - vec3d p[3]; - vec2d t[3]; - olc::Pixel col; - }; - - struct mat4x4 - { - float m[4][4] = { 0 }; - }; - - struct mesh - { - std::vector tris; - }; - - class Math - { - public: - inline Math(); - public: - inline static vec3d Mat_MultiplyVector(mat4x4 &m, vec3d &i); - inline static mat4x4 Mat_MultiplyMatrix(mat4x4 &m1, mat4x4 &m2); - inline static mat4x4 Mat_MakeIdentity(); - inline static mat4x4 Mat_MakeRotationX(float fAngleRad); - inline static mat4x4 Mat_MakeRotationY(float fAngleRad); - inline static mat4x4 Mat_MakeRotationZ(float fAngleRad); - inline static mat4x4 Mat_MakeScale(float x, float y, float z); - inline static mat4x4 Mat_MakeTranslation(float x, float y, float z); - inline static mat4x4 Mat_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar); - inline static mat4x4 Mat_PointAt(vec3d &pos, vec3d &target, vec3d &up); - inline static mat4x4 Mat_QuickInverse(mat4x4 &m); // Only for Rotation/Translation Matrices - inline static mat4x4 Mat_Inverse(olc::GFX3D::mat4x4 &m); - - inline static vec3d Vec_Add(vec3d &v1, vec3d &v2); - inline static vec3d Vec_Sub(vec3d &v1, vec3d &v2); - inline static vec3d Vec_Mul(vec3d &v1, float k); - inline static vec3d Vec_Div(vec3d &v1, float k); - inline static float Vec_DotProduct(vec3d &v1, vec3d &v2); - inline static float Vec_Length(vec3d &v); - inline static vec3d Vec_Normalise(vec3d &v); - inline static vec3d Vec_CrossProduct(vec3d &v1, vec3d &v2); - inline static vec3d Vec_IntersectPlane(vec3d &plane_p, vec3d &plane_n, vec3d &lineStart, vec3d &lineEnd, float &t); - - inline static int Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2); - }; - - enum RENDERFLAGS - { - RENDER_WIRE = 0x01, - RENDER_FLAT = 0x02, - RENDER_TEXTURED = 0x04, - RENDER_CULL_CW = 0x08, - RENDER_CULL_CCW = 0x10, - RENDER_DEPTH = 0x20, - }; - - - class PipeLine - { - public: - PipeLine(); - - public: - void SetProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar, float fLeft, float fTop, float fWidth, float fHeight); - void SetCamera(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &lookat, olc::GFX3D::vec3d &up); - void SetTransform(olc::GFX3D::mat4x4 &transform); - void SetTexture(olc::Sprite *texture); - void SetLightSource(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &dir, olc::Pixel &col); - uint32_t Render(std::vector &triangles, uint32_t flags = RENDER_CULL_CW | RENDER_TEXTURED | RENDER_DEPTH); - - private: - olc::GFX3D::mat4x4 matProj; - olc::GFX3D::mat4x4 matView; - olc::GFX3D::mat4x4 matWorld; - olc::Sprite *sprTexture; - float fViewX; - float fViewY; - float fViewW; - float fViewH; - }; - - - - public: - //static const int RF_TEXTURE = 0x00000001; - //static const int RF_ = 0x00000002; - - inline static void ConfigureDisplay(); - inline static void ClearDepth(); - inline static void AddTriangleToScene(olc::GFX3D::triangle &tri); - inline static void RenderScene(); - - inline static void DrawTriangleFlat(olc::GFX3D::triangle &tri); - inline static void DrawTriangleWire(olc::GFX3D::triangle &tri, olc::Pixel col = olc::WHITE); - inline static void DrawTriangleTex(olc::GFX3D::triangle &tri, olc::Sprite* spr); - inline static void TexturedTriangle(int x1, int y1, float u1, float v1, float w1, - int x2, int y2, float u2, float v2, float w2, - int x3, int y3, float u3, float v3, float w3, olc::Sprite* spr); - - // Draws a sprite with the transform applied - //inline static void DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform); - - private: - static float* m_DepthBuffer; - }; -} - - - - -namespace olc -{ - olc::GFX3D::Math::Math() - { - - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Mat_MultiplyVector(olc::GFX3D::mat4x4 &m, olc::GFX3D::vec3d &i) - { - vec3d v; - v.x = i.x * m.m[0][0] + i.y * m.m[1][0] + i.z * m.m[2][0] + i.w * m.m[3][0]; - v.y = i.x * m.m[0][1] + i.y * m.m[1][1] + i.z * m.m[2][1] + i.w * m.m[3][1]; - v.z = i.x * m.m[0][2] + i.y * m.m[1][2] + i.z * m.m[2][2] + i.w * m.m[3][2]; - v.w = i.x * m.m[0][3] + i.y * m.m[1][3] + i.z * m.m[2][3] + i.w * m.m[3][3]; - return v; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeIdentity() - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = 1.0f; - matrix.m[1][1] = 1.0f; - matrix.m[2][2] = 1.0f; - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeRotationX(float fAngleRad) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = 1.0f; - matrix.m[1][1] = cosf(fAngleRad); - matrix.m[1][2] = sinf(fAngleRad); - matrix.m[2][1] = -sinf(fAngleRad); - matrix.m[2][2] = cosf(fAngleRad); - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeRotationY(float fAngleRad) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = cosf(fAngleRad); - matrix.m[0][2] = sinf(fAngleRad); - matrix.m[2][0] = -sinf(fAngleRad); - matrix.m[1][1] = 1.0f; - matrix.m[2][2] = cosf(fAngleRad); - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeRotationZ(float fAngleRad) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = cosf(fAngleRad); - matrix.m[0][1] = sinf(fAngleRad); - matrix.m[1][0] = -sinf(fAngleRad); - matrix.m[1][1] = cosf(fAngleRad); - matrix.m[2][2] = 1.0f; - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeScale(float x, float y, float z) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = x; - matrix.m[1][1] = y; - matrix.m[2][2] = z; - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeTranslation(float x, float y, float z) - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = 1.0f; - matrix.m[1][1] = 1.0f; - matrix.m[2][2] = 1.0f; - matrix.m[3][3] = 1.0f; - matrix.m[3][0] = x; - matrix.m[3][1] = y; - matrix.m[3][2] = z; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MakeProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar) - { - float fFovRad = 1.0f / tanf(fFovDegrees * 0.5f / 180.0f * 3.14159f); - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = fAspectRatio * fFovRad; - matrix.m[1][1] = fFovRad; - matrix.m[2][2] = fFar / (fFar - fNear); - matrix.m[3][2] = (-fFar * fNear) / (fFar - fNear); - matrix.m[2][3] = 1.0f; - matrix.m[3][3] = 0.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_MultiplyMatrix(olc::GFX3D::mat4x4 &m1, olc::GFX3D::mat4x4 &m2) - { - olc::GFX3D::mat4x4 matrix; - for (int c = 0; c < 4; c++) - for (int r = 0; r < 4; r++) - matrix.m[r][c] = m1.m[r][0] * m2.m[0][c] + m1.m[r][1] * m2.m[1][c] + m1.m[r][2] * m2.m[2][c] + m1.m[r][3] * m2.m[3][c]; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_PointAt(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &target, olc::GFX3D::vec3d &up) - { - // Calculate new forward direction - olc::GFX3D::vec3d newForward = Vec_Sub(target, pos); - newForward = Vec_Normalise(newForward); - - // Calculate new Up direction - olc::GFX3D::vec3d a = Vec_Mul(newForward, Vec_DotProduct(up, newForward)); - olc::GFX3D::vec3d newUp = Vec_Sub(up, a); - newUp = Vec_Normalise(newUp); - - // New Right direction is easy, its just cross product - olc::GFX3D::vec3d newRight = Vec_CrossProduct(newUp, newForward); - - // Construct Dimensioning and Translation Matrix - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = newRight.x; matrix.m[0][1] = newRight.y; matrix.m[0][2] = newRight.z; matrix.m[0][3] = 0.0f; - matrix.m[1][0] = newUp.x; matrix.m[1][1] = newUp.y; matrix.m[1][2] = newUp.z; matrix.m[1][3] = 0.0f; - matrix.m[2][0] = newForward.x; matrix.m[2][1] = newForward.y; matrix.m[2][2] = newForward.z; matrix.m[2][3] = 0.0f; - matrix.m[3][0] = pos.x; matrix.m[3][1] = pos.y; matrix.m[3][2] = pos.z; matrix.m[3][3] = 1.0f; - return matrix; - - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_QuickInverse(olc::GFX3D::mat4x4 &m) // Only for Rotation/Translation Matrices - { - olc::GFX3D::mat4x4 matrix; - matrix.m[0][0] = m.m[0][0]; matrix.m[0][1] = m.m[1][0]; matrix.m[0][2] = m.m[2][0]; matrix.m[0][3] = 0.0f; - matrix.m[1][0] = m.m[0][1]; matrix.m[1][1] = m.m[1][1]; matrix.m[1][2] = m.m[2][1]; matrix.m[1][3] = 0.0f; - matrix.m[2][0] = m.m[0][2]; matrix.m[2][1] = m.m[1][2]; matrix.m[2][2] = m.m[2][2]; matrix.m[2][3] = 0.0f; - matrix.m[3][0] = -(m.m[3][0] * matrix.m[0][0] + m.m[3][1] * matrix.m[1][0] + m.m[3][2] * matrix.m[2][0]); - matrix.m[3][1] = -(m.m[3][0] * matrix.m[0][1] + m.m[3][1] * matrix.m[1][1] + m.m[3][2] * matrix.m[2][1]); - matrix.m[3][2] = -(m.m[3][0] * matrix.m[0][2] + m.m[3][1] * matrix.m[1][2] + m.m[3][2] * matrix.m[2][2]); - matrix.m[3][3] = 1.0f; - return matrix; - } - - olc::GFX3D::mat4x4 olc::GFX3D::Math::Mat_Inverse(olc::GFX3D::mat4x4 &m) - { - double det; - - - mat4x4 matInv; - - matInv.m[0][0] = m.m[1][1] * m.m[2][2] * m.m[3][3] - m.m[1][1] * m.m[2][3] * m.m[3][2] - m.m[2][1] * m.m[1][2] * m.m[3][3] + m.m[2][1] * m.m[1][3] * m.m[3][2] + m.m[3][1] * m.m[1][2] * m.m[2][3] - m.m[3][1] * m.m[1][3] * m.m[2][2]; - matInv.m[1][0] = -m.m[1][0] * m.m[2][2] * m.m[3][3] + m.m[1][0] * m.m[2][3] * m.m[3][2] + m.m[2][0] * m.m[1][2] * m.m[3][3] - m.m[2][0] * m.m[1][3] * m.m[3][2] - m.m[3][0] * m.m[1][2] * m.m[2][3] + m.m[3][0] * m.m[1][3] * m.m[2][2]; - matInv.m[2][0] = m.m[1][0] * m.m[2][1] * m.m[3][3] - m.m[1][0] * m.m[2][3] * m.m[3][1] - m.m[2][0] * m.m[1][1] * m.m[3][3] + m.m[2][0] * m.m[1][3] * m.m[3][1] + m.m[3][0] * m.m[1][1] * m.m[2][3] - m.m[3][0] * m.m[1][3] * m.m[2][1]; - matInv.m[3][0] = -m.m[1][0] * m.m[2][1] * m.m[3][2] + m.m[1][0] * m.m[2][2] * m.m[3][1] + m.m[2][0] * m.m[1][1] * m.m[3][2] - m.m[2][0] * m.m[1][2] * m.m[3][1] - m.m[3][0] * m.m[1][1] * m.m[2][2] + m.m[3][0] * m.m[1][2] * m.m[2][1]; - matInv.m[0][1] = -m.m[0][1] * m.m[2][2] * m.m[3][3] + m.m[0][1] * m.m[2][3] * m.m[3][2] + m.m[2][1] * m.m[0][2] * m.m[3][3] - m.m[2][1] * m.m[0][3] * m.m[3][2] - m.m[3][1] * m.m[0][2] * m.m[2][3] + m.m[3][1] * m.m[0][3] * m.m[2][2]; - matInv.m[1][1] = m.m[0][0] * m.m[2][2] * m.m[3][3] - m.m[0][0] * m.m[2][3] * m.m[3][2] - m.m[2][0] * m.m[0][2] * m.m[3][3] + m.m[2][0] * m.m[0][3] * m.m[3][2] + m.m[3][0] * m.m[0][2] * m.m[2][3] - m.m[3][0] * m.m[0][3] * m.m[2][2]; - matInv.m[2][1] = -m.m[0][0] * m.m[2][1] * m.m[3][3] + m.m[0][0] * m.m[2][3] * m.m[3][1] + m.m[2][0] * m.m[0][1] * m.m[3][3] - m.m[2][0] * m.m[0][3] * m.m[3][1] - m.m[3][0] * m.m[0][1] * m.m[2][3] + m.m[3][0] * m.m[0][3] * m.m[2][1]; - matInv.m[3][1] = m.m[0][0] * m.m[2][1] * m.m[3][2] - m.m[0][0] * m.m[2][2] * m.m[3][1] - m.m[2][0] * m.m[0][1] * m.m[3][2] + m.m[2][0] * m.m[0][2] * m.m[3][1] + m.m[3][0] * m.m[0][1] * m.m[2][2] - m.m[3][0] * m.m[0][2] * m.m[2][1]; - matInv.m[0][2] = m.m[0][1] * m.m[1][2] * m.m[3][3] - m.m[0][1] * m.m[1][3] * m.m[3][2] - m.m[1][1] * m.m[0][2] * m.m[3][3] + m.m[1][1] * m.m[0][3] * m.m[3][2] + m.m[3][1] * m.m[0][2] * m.m[1][3] - m.m[3][1] * m.m[0][3] * m.m[1][2]; - matInv.m[1][2] = -m.m[0][0] * m.m[1][2] * m.m[3][3] + m.m[0][0] * m.m[1][3] * m.m[3][2] + m.m[1][0] * m.m[0][2] * m.m[3][3] - m.m[1][0] * m.m[0][3] * m.m[3][2] - m.m[3][0] * m.m[0][2] * m.m[1][3] + m.m[3][0] * m.m[0][3] * m.m[1][2]; - matInv.m[2][2] = m.m[0][0] * m.m[1][1] * m.m[3][3] - m.m[0][0] * m.m[1][3] * m.m[3][1] - m.m[1][0] * m.m[0][1] * m.m[3][3] + m.m[1][0] * m.m[0][3] * m.m[3][1] + m.m[3][0] * m.m[0][1] * m.m[1][3] - m.m[3][0] * m.m[0][3] * m.m[1][1]; - matInv.m[3][2] = -m.m[0][0] * m.m[1][1] * m.m[3][2] + m.m[0][0] * m.m[1][2] * m.m[3][1] + m.m[1][0] * m.m[0][1] * m.m[3][2] - m.m[1][0] * m.m[0][2] * m.m[3][1] - m.m[3][0] * m.m[0][1] * m.m[1][2] + m.m[3][0] * m.m[0][2] * m.m[1][1]; - matInv.m[0][3] = -m.m[0][1] * m.m[1][2] * m.m[2][3] + m.m[0][1] * m.m[1][3] * m.m[2][2] + m.m[1][1] * m.m[0][2] * m.m[2][3] - m.m[1][1] * m.m[0][3] * m.m[2][2] - m.m[2][1] * m.m[0][2] * m.m[1][3] + m.m[2][1] * m.m[0][3] * m.m[1][2]; - matInv.m[1][3] = m.m[0][0] * m.m[1][2] * m.m[2][3] - m.m[0][0] * m.m[1][3] * m.m[2][2] - m.m[1][0] * m.m[0][2] * m.m[2][3] + m.m[1][0] * m.m[0][3] * m.m[2][2] + m.m[2][0] * m.m[0][2] * m.m[1][3] - m.m[2][0] * m.m[0][3] * m.m[1][2]; - matInv.m[2][3] = -m.m[0][0] * m.m[1][1] * m.m[2][3] + m.m[0][0] * m.m[1][3] * m.m[2][1] + m.m[1][0] * m.m[0][1] * m.m[2][3] - m.m[1][0] * m.m[0][3] * m.m[2][1] - m.m[2][0] * m.m[0][1] * m.m[1][3] + m.m[2][0] * m.m[0][3] * m.m[1][1]; - matInv.m[3][3] = m.m[0][0] * m.m[1][1] * m.m[2][2] - m.m[0][0] * m.m[1][2] * m.m[2][1] - m.m[1][0] * m.m[0][1] * m.m[2][2] + m.m[1][0] * m.m[0][2] * m.m[2][1] + m.m[2][0] * m.m[0][1] * m.m[1][2] - m.m[2][0] * m.m[0][2] * m.m[1][1]; - - det = m.m[0][0] * matInv.m[0][0] + m.m[0][1] * matInv.m[1][0] + m.m[0][2] * matInv.m[2][0] + m.m[0][3] * matInv.m[3][0]; - // if (det == 0) return false; - - det = 1.0 / det; - - for (int i = 0; i < 4; i++) - for (int j = 0; j < 4; j++) - matInv.m[i][j] *= (float)det; - - return matInv; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Add(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) - { - return { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Sub(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) - { - return { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Mul(olc::GFX3D::vec3d &v1, float k) - { - return { v1.x * k, v1.y * k, v1.z * k }; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Div(olc::GFX3D::vec3d &v1, float k) - { - return { v1.x / k, v1.y / k, v1.z / k }; - } - - float olc::GFX3D::Math::Vec_DotProduct(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) - { - return v1.x*v2.x + v1.y*v2.y + v1.z * v2.z; - } - - float olc::GFX3D::Math::Vec_Length(olc::GFX3D::vec3d &v) - { - return sqrtf(Vec_DotProduct(v, v)); - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_Normalise(olc::GFX3D::vec3d &v) - { - float l = Vec_Length(v); - return { v.x / l, v.y / l, v.z / l }; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_CrossProduct(olc::GFX3D::vec3d &v1, olc::GFX3D::vec3d &v2) - { - vec3d v; - v.x = v1.y * v2.z - v1.z * v2.y; - v.y = v1.z * v2.x - v1.x * v2.z; - v.z = v1.x * v2.y - v1.y * v2.x; - return v; - } - - olc::GFX3D::vec3d olc::GFX3D::Math::Vec_IntersectPlane(olc::GFX3D::vec3d &plane_p, olc::GFX3D::vec3d &plane_n, olc::GFX3D::vec3d &lineStart, olc::GFX3D::vec3d &lineEnd, float &t) - { - plane_n = Vec_Normalise(plane_n); - float plane_d = -Vec_DotProduct(plane_n, plane_p); - float ad = Vec_DotProduct(lineStart, plane_n); - float bd = Vec_DotProduct(lineEnd, plane_n); - t = (-plane_d - ad) / (bd - ad); - olc::GFX3D::vec3d lineStartToEnd = Vec_Sub(lineEnd, lineStart); - olc::GFX3D::vec3d lineToIntersect = Vec_Mul(lineStartToEnd, t); - return Vec_Add(lineStart, lineToIntersect); - } - - - int olc::GFX3D::Math::Triangle_ClipAgainstPlane(vec3d plane_p, vec3d plane_n, triangle &in_tri, triangle &out_tri1, triangle &out_tri2) - { - // Make sure plane normal is indeed normal - plane_n = Math::Vec_Normalise(plane_n); - - out_tri1.t[0] = in_tri.t[0]; - out_tri2.t[0] = in_tri.t[0]; - out_tri1.t[1] = in_tri.t[1]; - out_tri2.t[1] = in_tri.t[1]; - out_tri1.t[2] = in_tri.t[2]; - out_tri2.t[2] = in_tri.t[2]; - - // Return signed shortest distance from point to plane, plane normal must be normalised - auto dist = [&](vec3d &p) - { - vec3d n = Math::Vec_Normalise(p); - return (plane_n.x * p.x + plane_n.y * p.y + plane_n.z * p.z - Math::Vec_DotProduct(plane_n, plane_p)); - }; - - // Create two temporary storage arrays to classify points either side of plane - // If distance sign is positive, point lies on "inside" of plane - vec3d* inside_points[3]; int nInsidePointCount = 0; - vec3d* outside_points[3]; int nOutsidePointCount = 0; - vec2d* inside_tex[3]; int nInsideTexCount = 0; - vec2d* outside_tex[3]; int nOutsideTexCount = 0; - - - // Get signed distance of each point in triangle to plane - float d0 = dist(in_tri.p[0]); - float d1 = dist(in_tri.p[1]); - float d2 = dist(in_tri.p[2]); - - if (d0 >= 0) { inside_points[nInsidePointCount++] = &in_tri.p[0]; inside_tex[nInsideTexCount++] = &in_tri.t[0]; } - else { - outside_points[nOutsidePointCount++] = &in_tri.p[0]; outside_tex[nOutsideTexCount++] = &in_tri.t[0]; - } - if (d1 >= 0) { - inside_points[nInsidePointCount++] = &in_tri.p[1]; inside_tex[nInsideTexCount++] = &in_tri.t[1]; - } - else { - outside_points[nOutsidePointCount++] = &in_tri.p[1]; outside_tex[nOutsideTexCount++] = &in_tri.t[1]; - } - if (d2 >= 0) { - inside_points[nInsidePointCount++] = &in_tri.p[2]; inside_tex[nInsideTexCount++] = &in_tri.t[2]; - } - else { - outside_points[nOutsidePointCount++] = &in_tri.p[2]; outside_tex[nOutsideTexCount++] = &in_tri.t[2]; - } - - // Now classify triangle points, and break the input triangle into - // smaller output triangles if required. There are four possible - // outcomes... - - if (nInsidePointCount == 0) - { - // All points lie on the outside of plane, so clip whole triangle - // It ceases to exist - - return 0; // No returned triangles are valid - } - - if (nInsidePointCount == 3) - { - // All points lie on the inside of plane, so do nothing - // and allow the triangle to simply pass through - out_tri1 = in_tri; - - return 1; // Just the one returned original triangle is valid - } - - if (nInsidePointCount == 1 && nOutsidePointCount == 2) - { - // Triangle should be clipped. As two points lie outside - // the plane, the triangle simply becomes a smaller triangle - - // Copy appearance info to new triangle - out_tri1.col = olc::MAGENTA;// in_tri.col; - - // The inside point is valid, so keep that... - out_tri1.p[0] = *inside_points[0]; - out_tri1.t[0] = *inside_tex[0]; - - // but the two new points are at the locations where the - // original sides of the triangle (lines) intersect with the plane - float t; - out_tri1.p[1] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); - out_tri1.t[1].x = t * (outside_tex[0]->x - inside_tex[0]->x) + inside_tex[0]->x; - out_tri1.t[1].y = t * (outside_tex[0]->y - inside_tex[0]->y) + inside_tex[0]->y; - out_tri1.t[1].z = t * (outside_tex[0]->z - inside_tex[0]->z) + inside_tex[0]->z; - - out_tri1.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[1], t); - out_tri1.t[2].x = t * (outside_tex[1]->x - inside_tex[0]->x) + inside_tex[0]->x; - out_tri1.t[2].y = t * (outside_tex[1]->y - inside_tex[0]->y) + inside_tex[0]->y; - out_tri1.t[2].z = t * (outside_tex[1]->z - inside_tex[0]->z) + inside_tex[0]->z; - - return 1; // Return the newly formed single triangle - } - - if (nInsidePointCount == 2 && nOutsidePointCount == 1) - { - // Triangle should be clipped. As two points lie inside the plane, - // the clipped triangle becomes a "quad". Fortunately, we can - // represent a quad with two new triangles - - // Copy appearance info to new triangles - out_tri1.col = olc::GREEN;// in_tri.col; - out_tri2.col = olc::RED;// in_tri.col; - - // The first triangle consists of the two inside points and a new - // point determined by the location where one side of the triangle - // intersects with the plane - out_tri1.p[0] = *inside_points[0]; - out_tri1.t[0] = *inside_tex[0]; - - out_tri1.p[1] = *inside_points[1]; - out_tri1.t[1] = *inside_tex[1]; - - float t; - out_tri1.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[0], *outside_points[0], t); - out_tri1.t[2].x = t * (outside_tex[0]->x - inside_tex[0]->x) + inside_tex[0]->x; - out_tri1.t[2].y = t * (outside_tex[0]->y - inside_tex[0]->y) + inside_tex[0]->y; - out_tri1.t[2].z = t * (outside_tex[0]->z - inside_tex[0]->z) + inside_tex[0]->z; - - // The second triangle is composed of one of he inside points, a - // new point determined by the intersection of the other side of the - // triangle and the plane, and the newly created point above - out_tri2.p[1] = *inside_points[1]; - out_tri2.t[1] = *inside_tex[1]; - out_tri2.p[0] = out_tri1.p[2]; - out_tri2.t[0] = out_tri1.t[2]; - out_tri2.p[2] = Math::Vec_IntersectPlane(plane_p, plane_n, *inside_points[1], *outside_points[0], t); - out_tri2.t[2].x = t * (outside_tex[0]->x - inside_tex[1]->x) + inside_tex[1]->x; - out_tri2.t[2].y = t * (outside_tex[0]->y - inside_tex[1]->y) + inside_tex[1]->y; - out_tri2.t[2].z = t * (outside_tex[0]->z - inside_tex[1]->z) + inside_tex[1]->z; - return 2; // Return two newly formed triangles which form a quad - } - - return 0; - } - - void GFX3D::DrawTriangleFlat(olc::GFX3D::triangle &tri) - { - pge->FillTriangle(tri.p[0].x, tri.p[0].y, tri.p[1].x, tri.p[1].y, tri.p[2].x, tri.p[2].y, tri.col); - } - - void GFX3D::DrawTriangleWire(olc::GFX3D::triangle &tri, olc::Pixel col) - { - pge->DrawTriangle(tri.p[0].x, tri.p[0].y, tri.p[1].x, tri.p[1].y, tri.p[2].x, tri.p[2].y, col); - } - - void GFX3D::TexturedTriangle(int x1, int y1, float u1, float v1, float w1, - int x2, int y2, float u2, float v2, float w2, - int x3, int y3, float u3, float v3, float w3, olc::Sprite* spr) - - { - if (y2 < y1) - { - std::swap(y1, y2); - std::swap(x1, x2); - std::swap(u1, u2); - std::swap(v1, v2); - std::swap(w1, w2); - } - - if (y3 < y1) - { - std::swap(y1, y3); - std::swap(x1, x3); - std::swap(u1, u3); - std::swap(v1, v3); - std::swap(w1, w3); - } - - if (y3 < y2) - { - std::swap(y2, y3); - std::swap(x2, x3); - std::swap(u2, u3); - std::swap(v2, v3); - std::swap(w2, w3); - } - - int dy1 = y2 - y1; - int dx1 = x2 - x1; - float dv1 = v2 - v1; - float du1 = u2 - u1; - float dw1 = w2 - w1; - - int dy2 = y3 - y1; - int dx2 = x3 - x1; - float dv2 = v3 - v1; - float du2 = u3 - u1; - float dw2 = w3 - w1; - - float tex_u, tex_v, tex_w; - - float dax_step = 0, dbx_step = 0, - du1_step = 0, dv1_step = 0, - du2_step = 0, dv2_step = 0, - dw1_step = 0, dw2_step = 0; - - if (dy1) dax_step = dx1 / (float)abs(dy1); - if (dy2) dbx_step = dx2 / (float)abs(dy2); - - if (dy1) du1_step = du1 / (float)abs(dy1); - if (dy1) dv1_step = dv1 / (float)abs(dy1); - if (dy1) dw1_step = dw1 / (float)abs(dy1); - - if (dy2) du2_step = du2 / (float)abs(dy2); - if (dy2) dv2_step = dv2 / (float)abs(dy2); - if (dy2) dw2_step = dw2 / (float)abs(dy2); - - if (dy1) - { - for (int i = y1; i <= y2; i++) - { - int ax = x1 + (float)(i - y1) * dax_step; - int bx = x1 + (float)(i - y1) * dbx_step; - - float tex_su = u1 + (float)(i - y1) * du1_step; - float tex_sv = v1 + (float)(i - y1) * dv1_step; - float tex_sw = w1 + (float)(i - y1) * dw1_step; - - float tex_eu = u1 + (float)(i - y1) * du2_step; - float tex_ev = v1 + (float)(i - y1) * dv2_step; - float tex_ew = w1 + (float)(i - y1) * dw2_step; - - if (ax > bx) - { - std::swap(ax, bx); - std::swap(tex_su, tex_eu); - std::swap(tex_sv, tex_ev); - std::swap(tex_sw, tex_ew); - } - - tex_u = tex_su; - tex_v = tex_sv; - tex_w = tex_sw; - - float tstep = 1.0f / ((float)(bx - ax)); - float t = 0.0f; - - for (int j = ax; j < bx; j++) - { - tex_u = (1.0f - t) * tex_su + t * tex_eu; - tex_v = (1.0f - t) * tex_sv + t * tex_ev; - tex_w = (1.0f - t) * tex_sw + t * tex_ew; - if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j]) - { - pge->Draw(j, i, spr->Sample(tex_u / tex_w, tex_v / tex_w)); - m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w; - } - t += tstep; - } - - } - } - - dy1 = y3 - y2; - dx1 = x3 - x2; - dv1 = v3 - v2; - du1 = u3 - u2; - dw1 = w3 - w2; - - if (dy1) dax_step = dx1 / (float)abs(dy1); - if (dy2) dbx_step = dx2 / (float)abs(dy2); - - du1_step = 0, dv1_step = 0; - if (dy1) du1_step = du1 / (float)abs(dy1); - if (dy1) dv1_step = dv1 / (float)abs(dy1); - if (dy1) dw1_step = dw1 / (float)abs(dy1); - - if (dy1) - { - for (int i = y2; i <= y3; i++) - { - int ax = x2 + (float)(i - y2) * dax_step; - int bx = x1 + (float)(i - y1) * dbx_step; - - float tex_su = u2 + (float)(i - y2) * du1_step; - float tex_sv = v2 + (float)(i - y2) * dv1_step; - float tex_sw = w2 + (float)(i - y2) * dw1_step; - - float tex_eu = u1 + (float)(i - y1) * du2_step; - float tex_ev = v1 + (float)(i - y1) * dv2_step; - float tex_ew = w1 + (float)(i - y1) * dw2_step; - - if (ax > bx) - { - std::swap(ax, bx); - std::swap(tex_su, tex_eu); - std::swap(tex_sv, tex_ev); - std::swap(tex_sw, tex_ew); - } - - tex_u = tex_su; - tex_v = tex_sv; - tex_w = tex_sw; - - float tstep = 1.0f / ((float)(bx - ax)); - float t = 0.0f; - - for (int j = ax; j < bx; j++) - { - tex_u = (1.0f - t) * tex_su + t * tex_eu; - tex_v = (1.0f - t) * tex_sv + t * tex_ev; - tex_w = (1.0f - t) * tex_sw + t * tex_ew; - - if (tex_w > m_DepthBuffer[i*pge->ScreenWidth() + j]) - { - pge->Draw(j, i, spr->Sample(tex_u / tex_w, tex_v / tex_w)); - m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_w; - } - t += tstep; - } - } - } - } - - - void GFX3D::DrawTriangleTex(olc::GFX3D::triangle &tri, olc::Sprite* spr) - { - if (tri.p[1].y < tri.p[0].y) - { - std::swap(tri.p[0].y, tri.p[1].y); - std::swap(tri.p[0].x, tri.p[1].x); - std::swap(tri.t[0].x, tri.t[1].x); - std::swap(tri.t[0].y, tri.t[1].y); - std::swap(tri.t[0].z, tri.t[1].z); - } - - if (tri.p[2].y < tri.p[0].y) - { - std::swap(tri.p[0].y, tri.p[2].y); - std::swap(tri.p[0].x, tri.p[2].x); - std::swap(tri.t[0].x, tri.t[2].x); - std::swap(tri.t[0].y, tri.t[2].y); - std::swap(tri.t[0].z, tri.t[2].z); - } - - if (tri.p[2].y < tri.p[1].y) - { - std::swap(tri.p[1].y, tri.p[2].y); - std::swap(tri.p[1].x, tri.p[2].x); - std::swap(tri.t[1].x, tri.t[2].x); - std::swap(tri.t[1].y, tri.t[2].y); - std::swap(tri.t[1].z, tri.t[2].z); - } - - int dy1 = tri.p[1].y - tri.p[0].y; - int dx1 = tri.p[1].x - tri.p[0].x; - float dv1 = tri.t[1].y - tri.t[0].y; - float du1 = tri.t[1].x - tri.t[0].x; - float dz1 = tri.t[1].z - tri.t[0].z; - - int dy2 = tri.p[2].y - tri.p[0].y; - int dx2 = tri.p[2].x - tri.p[0].x; - float dv2 = tri.t[2].y - tri.t[0].y; - float du2 = tri.t[2].x - tri.t[0].x; - float dz2 = tri.t[2].z - tri.t[0].z; - - float tex_x, tex_y, tex_z; - - float du1_step = 0, dv1_step = 0, du2_step = 0, dv2_step = 0, dz1_step = 0, dz2_step = 0; - float dax_step = 0, dbx_step = 0; - - if (dy1) dax_step = dx1 / (float)abs(dy1); - if (dy2) dbx_step = dx2 / (float)abs(dy2); - - if (dy1) du1_step = du1 / (float)abs(dy1); - if (dy1) dv1_step = dv1 / (float)abs(dy1); - if (dy1) dz1_step = dz1 / (float)abs(dy1); - - if (dy2) du2_step = du2 / (float)abs(dy2); - if (dy2) dv2_step = dv2 / (float)abs(dy2); - if (dy2) dz2_step = dz2 / (float)abs(dy2); - - - - if (dy1) - { - for (int i = tri.p[0].y; i <= tri.p[1].y; i++) - { - int ax = tri.p[0].x + (i - tri.p[0].y) * dax_step; - int bx = tri.p[0].x + (i - tri.p[0].y) * dbx_step; - - // Start and end points in texture space - float tex_su = tri.t[0].x + (float)(i - tri.p[0].y) * du1_step; - float tex_sv = tri.t[0].y + (float)(i - tri.p[0].y) * dv1_step; - float tex_sz = tri.t[0].z + (float)(i - tri.p[0].y) * dz1_step; - - float tex_eu = tri.t[0].x + (float)(i - tri.p[0].y) * du2_step; - float tex_ev = tri.t[0].y + (float)(i - tri.p[0].y) * dv2_step; - float tex_ez = tri.t[0].z + (float)(i - tri.p[0].y) * dz2_step; - - if (ax > bx) - { - std::swap(ax, bx); - std::swap(tex_su, tex_eu); - std::swap(tex_sv, tex_ev); - std::swap(tex_sz, tex_ez); - } - - tex_x = tex_su; - tex_y = tex_sv; - tex_z = tex_sz; - - - float tstep = 1.0f / ((float)(bx - ax)); - float t = 0; - - for (int j = ax; j < bx; j++) - { - tex_x = (1.0f - t) * tex_su + t * tex_eu; - tex_y = (1.0f - t) * tex_sv + t * tex_ev; - tex_z = (1.0f - t) * tex_sz + t * tex_ez; - - if (tex_z > m_DepthBuffer[i*pge->ScreenWidth() + j]) - { - pge->Draw(j, i, spr->Sample(tex_x / tex_z, tex_y / tex_z)); - m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_z; - } - t += tstep; - } - - - } - } - - dy1 = tri.p[2].y - tri.p[1].y; - dx1 = tri.p[2].x - tri.p[1].x; - dv1 = tri.t[2].y - tri.t[1].y; - du1 = tri.t[2].x - tri.t[1].x; - dz1 = tri.t[2].z - tri.t[1].z; - - if (dy1) dax_step = dx1 / (float)abs(dy1); - if (dy2) dbx_step = dx2 / (float)abs(dy2); - - - du1_step = 0, dv1_step = 0;// , dz1_step = 0;// , du2_step = 0, dv2_step = 0; - if (dy1) du1_step = du1 / (float)abs(dy1); - if (dy1) dv1_step = dv1 / (float)abs(dy1); - if (dy1) dz1_step = dz1 / (float)abs(dy1); - - if (dy1) - { - for (int i = tri.p[1].y; i <= tri.p[2].y; i++) - { - int ax = tri.p[1].x + (i - tri.p[1].y) * dax_step; - int bx = tri.p[0].x + (i - tri.p[0].y) * dbx_step; - - // Start and end points in texture space - float tex_su = tri.t[1].x + (float)(i - tri.p[1].y) * du1_step; - float tex_sv = tri.t[1].y + (float)(i - tri.p[1].y) * dv1_step; - float tex_sz = tri.t[1].z + (float)(i - tri.p[1].y) * dz1_step; - - float tex_eu = tri.t[0].x + (float)(i - tri.p[0].y) * du2_step; - float tex_ev = tri.t[0].y + (float)(i - tri.p[0].y) * dv2_step; - float tex_ez = tri.t[0].z + (float)(i - tri.p[0].y) * dz2_step; - - if (ax > bx) - { - std::swap(ax, bx); - std::swap(tex_su, tex_eu); - std::swap(tex_sv, tex_ev); - std::swap(tex_sz, tex_ez); - } - - tex_x = tex_su; - tex_y = tex_sv; - tex_z = tex_sz; - - - float tstep = 1.0f / ((float)(bx - ax)); - float t = 0; - - for (int j = ax; j < bx; j++) - { - tex_x = (1.0f - t) * tex_su + t * tex_eu; - tex_y = (1.0f - t) * tex_sv + t * tex_ev; - tex_z = (1.0f - t) * tex_sz + t * tex_ez; - - if (tex_z > m_DepthBuffer[i*pge->ScreenWidth() + j]) - { - pge->Draw(j, i, spr->Sample(tex_x / tex_z, tex_y / tex_z)); - m_DepthBuffer[i*pge->ScreenWidth() + j] = tex_z; - } - - t += tstep; - } - } - } - - } - - float* GFX3D::m_DepthBuffer = nullptr; - - void GFX3D::ConfigureDisplay() - { - m_DepthBuffer = new float[pge->ScreenWidth() * pge->ScreenHeight()]{ 0 }; - } - - - void GFX3D::ClearDepth() - { - memset(m_DepthBuffer, 0, pge->ScreenWidth() * pge->ScreenHeight() * sizeof(float)); - } - - - - - GFX3D::PipeLine::PipeLine() - { - - } - - void GFX3D::PipeLine::SetProjection(float fFovDegrees, float fAspectRatio, float fNear, float fFar, float fLeft, float fTop, float fWidth, float fHeight) - { - matProj = GFX3D::Math::Mat_MakeProjection(fFovDegrees, fAspectRatio, fNear, fFar); - fViewX = fLeft; - fViewY = fTop; - fViewW = fWidth; - fViewH = fHeight; - } - - void GFX3D::PipeLine::SetCamera(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &lookat, olc::GFX3D::vec3d &up) - { - matView = GFX3D::Math::Mat_PointAt(pos, lookat, up); - matView = GFX3D::Math::Mat_QuickInverse(matView); - } - - void GFX3D::PipeLine::SetTransform(olc::GFX3D::mat4x4 &transform) - { - matWorld = transform; - } - - void GFX3D::PipeLine::SetTexture(olc::Sprite *texture) - { - sprTexture = texture; - } - - void GFX3D::PipeLine::SetLightSource(olc::GFX3D::vec3d &pos, olc::GFX3D::vec3d &dir, olc::Pixel &col) - { - - } - - uint32_t GFX3D::PipeLine::Render(std::vector &triangles, uint32_t flags) - { - // Calculate Transformation Matrix - mat4x4 matWorldView = Math::Mat_MultiplyMatrix(matWorld, matView); - //matWorldViewProj = Math::Mat_MultiplyMatrix(matWorldView, matProj); - - // Store triangles for rastering later - std::vector vecTrianglesToRaster; - - int nTriangleDrawnCount = 0; - - // Process Triangles - for (auto &tri : triangles) - { - GFX3D::triangle triTransformed; - - // Just copy through texture coordinates - triTransformed.t[0] = { tri.t[0].x, tri.t[0].y, tri.t[0].z }; - triTransformed.t[1] = { tri.t[1].x, tri.t[1].y, tri.t[1].z }; - triTransformed.t[2] = { tri.t[2].x, tri.t[2].y, tri.t[2].z }; // Think! - - // Transform Triangle from object into projected space - triTransformed.p[0] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[0]); - triTransformed.p[1] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[1]); - triTransformed.p[2] = GFX3D::Math::Mat_MultiplyVector(matWorldView, tri.p[2]); - - // Calculate Triangle Normal in WorldView Space - GFX3D::vec3d normal, line1, line2; - line1 = GFX3D::Math::Vec_Sub(triTransformed.p[1], triTransformed.p[0]); - line2 = GFX3D::Math::Vec_Sub(triTransformed.p[2], triTransformed.p[0]); - normal = GFX3D::Math::Vec_CrossProduct(line1, line2); - normal = GFX3D::Math::Vec_Normalise(normal); - - // Cull triangles that face away from viewer - if (flags & RENDER_CULL_CW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) > 0.0f) continue; - if (flags & RENDER_CULL_CCW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) < 0.0f) continue; - - // If Lighting, calculate shading - triTransformed.col = olc::WHITE; - - // Clip triangle against near plane - int nClippedTriangles = 0; - triangle clipped[2]; - nClippedTriangles = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.1f }, { 0.0f, 0.0f, 1.0f }, triTransformed, clipped[0], clipped[1]); - - // This may yield two new triangles - for (int n = 0; n < nClippedTriangles; n++) - { - triangle triProjected = clipped[n]; - - // Project new triangle - triProjected.p[0] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[0]); - triProjected.p[1] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[1]); - triProjected.p[2] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[2]); - - // Apply Projection to Verts - triProjected.p[0].x = triProjected.p[0].x / triProjected.p[0].w; - triProjected.p[1].x = triProjected.p[1].x / triProjected.p[1].w; - triProjected.p[2].x = triProjected.p[2].x / triProjected.p[2].w; - - triProjected.p[0].y = triProjected.p[0].y / triProjected.p[0].w; - triProjected.p[1].y = triProjected.p[1].y / triProjected.p[1].w; - triProjected.p[2].y = triProjected.p[2].y / triProjected.p[2].w; - - triProjected.p[0].z = triProjected.p[0].z / triProjected.p[0].w; - triProjected.p[1].z = triProjected.p[1].z / triProjected.p[1].w; - triProjected.p[2].z = triProjected.p[2].z / triProjected.p[2].w; - - // Apply Projection to Tex coords - triProjected.t[0].x = triProjected.t[0].x / triProjected.p[0].w; - triProjected.t[1].x = triProjected.t[1].x / triProjected.p[1].w; - triProjected.t[2].x = triProjected.t[2].x / triProjected.p[2].w; - - triProjected.t[0].y = triProjected.t[0].y / triProjected.p[0].w; - triProjected.t[1].y = triProjected.t[1].y / triProjected.p[1].w; - triProjected.t[2].y = triProjected.t[2].y / triProjected.p[2].w; - - triProjected.t[0].z = 1.0f / triProjected.p[0].w; - triProjected.t[1].z = 1.0f / triProjected.p[1].w; - triProjected.t[2].z = 1.0f / triProjected.p[2].w; - - // Clip against viewport in screen space - // Clip triangles against all four screen edges, this could yield - // a bunch of triangles, so create a queue that we traverse to - // ensure we only test new triangles generated against planes - triangle sclipped[2]; - std::list listTriangles; - - - // Add initial triangle - listTriangles.push_back(triProjected); - int nNewTriangles = 1; - - for (int p = 0; p < 4; p++) - { - int nTrisToAdd = 0; - while (nNewTriangles > 0) - { - // Take triangle from front of queue - triangle test = listTriangles.front(); - listTriangles.pop_front(); - nNewTriangles--; - - // Clip it against a plane. We only need to test each - // subsequent plane, against subsequent new triangles - // as all triangles after a plane clip are guaranteed - // to lie on the inside of the plane. I like how this - // comment is almost completely and utterly justified - switch (p) - { - case 0: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, -1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - case 1: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, +1.0f, 0.0f }, { 0.0f, -1.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - case 2: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ -1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - case 3: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ +1.0f, 0.0f, 0.0f }, { -1.0f, 0.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - } - - - // Clipping may yield a variable number of triangles, so - // add these new ones to the back of the queue for subsequent - // clipping against next planes - for (int w = 0; w < nTrisToAdd; w++) - listTriangles.push_back(sclipped[w]); - } - nNewTriangles = listTriangles.size(); - } - - for (auto &triRaster : listTriangles) - { - // Scale to viewport - /*triRaster.p[0].x *= -1.0f; - triRaster.p[1].x *= -1.0f; - triRaster.p[2].x *= -1.0f; - triRaster.p[0].y *= -1.0f; - triRaster.p[1].y *= -1.0f; - triRaster.p[2].y *= -1.0f;*/ - vec3d vOffsetView = { 1,1,0 }; - triRaster.p[0] = Math::Vec_Add(triRaster.p[0], vOffsetView); - triRaster.p[1] = Math::Vec_Add(triRaster.p[1], vOffsetView); - triRaster.p[2] = Math::Vec_Add(triRaster.p[2], vOffsetView); - triRaster.p[0].x *= 0.5f * fViewW; - triRaster.p[0].y *= 0.5f * fViewH; - triRaster.p[1].x *= 0.5f * fViewW; - triRaster.p[1].y *= 0.5f * fViewH; - triRaster.p[2].x *= 0.5f * fViewW; - triRaster.p[2].y *= 0.5f * fViewH; - vOffsetView = { fViewX,fViewY,0 }; - triRaster.p[0] = Math::Vec_Add(triRaster.p[0], vOffsetView); - triRaster.p[1] = Math::Vec_Add(triRaster.p[1], vOffsetView); - triRaster.p[2] = Math::Vec_Add(triRaster.p[2], vOffsetView); - - // For now, just draw triangle - - if (flags & RENDER_TEXTURED) - { - TexturedTriangle( - triRaster.p[0].x, triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, - triRaster.p[1].x, triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, - triRaster.p[2].x, triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, - sprTexture); - } - - if (flags & RENDER_WIRE) - { - DrawTriangleWire(triRaster, olc::RED); - } - - if (flags & RENDER_FLAT) - { - DrawTriangleFlat(triRaster); - } - - nTriangleDrawnCount++; - } - } - } - - return nTriangleDrawnCount; - } -} - -#endif \ No newline at end of file diff --git a/Videos/olcPGEX_Sound.h b/Videos/olcPGEX_Sound.h deleted file mode 100644 index 41e47c3..0000000 --- a/Videos/olcPGEX_Sound.h +++ /dev/null @@ -1,892 +0,0 @@ -/* - olcPGEX_Sound.h - - +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine Extension | - | Sound - v0.3 | - +-------------------------------------------------------------+ - - What is this? - ~~~~~~~~~~~~~ - This is an extension to the olcPixelGameEngine, which provides - sound generation and wave playing routines. - - Special Thanks: - ~~~~~~~~~~~~~~~ - Slavka - For entire non-windows system back end! - Gorbit99 - Testing, Bug Fixes - Cyberdroid - Testing, Bug Fixes - Dragoneye - Testing - Puol - Testing - - License (OLC-3) - ~~~~~~~~~~~~~~~ - - Copyright 2018 - 2019 OneLoneCoder.com - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions or derivations of source code must retain the above - copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions or derivative works in binary form must reproduce - the above copyright notice. This list of conditions and the following - disclaimer must be reproduced in the documentation and/or other - materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Links - ~~~~~ - YouTube: https://www.youtube.com/javidx9 - Discord: https://discord.gg/WhwHUMV - Twitter: https://www.twitter.com/javidx9 - Twitch: https://www.twitch.tv/javidx9 - GitHub: https://www.github.com/onelonecoder - Homepage: https://www.onelonecoder.com - Patreon: https://www.patreon.com/javidx9 - - Author - ~~~~~~ - David Barr, aka javidx9, ŠOneLoneCoder 2019 -*/ - - -#ifndef OLC_PGEX_SOUND_H -#define OLC_PGEX_SOUND_H - -#include -#include -#include - -#include -#undef min -#undef max - -// Choose a default sound backend -#if !defined(USE_ALSA) && !defined(USE_OPENAL) && !defined(USE_WINDOWS) -#ifdef __linux__ -#define USE_ALSA -#endif - -#ifdef __EMSCRIPTEN__ -#define USE_OPENAL -#endif - -#ifdef _WIN32 -#define USE_WINDOWS -#endif - -#endif - -#ifdef USE_ALSA -#define ALSA_PCM_NEW_HW_PARAMS_API -#include -#endif - -#ifdef USE_OPENAL -#include -#include -#include -#endif - -#pragma pack(push, 1) -typedef struct { - uint16_t wFormatTag; - uint16_t nChannels; - uint32_t nSamplesPerSec; - uint32_t nAvgBytesPerSec; - uint16_t nBlockAlign; - uint16_t wBitsPerSample; - uint16_t cbSize; -} OLC_WAVEFORMATEX; -#pragma pack(pop) - -namespace olc -{ - // Container class for Advanced 2D Drawing functions - class SOUND : public olc::PGEX - { - // A representation of an affine transform, used to rotate, scale, offset & shear space - public: - class AudioSample - { - public: - AudioSample(); - AudioSample(std::string sWavFile, olc::ResourcePack *pack = nullptr); - olc::rcode LoadFromFile(std::string sWavFile, olc::ResourcePack *pack = nullptr); - - public: - OLC_WAVEFORMATEX wavHeader; - float *fSample = nullptr; - long nSamples = 0; - int nChannels = 0; - bool bSampleValid = false; - }; - - struct sCurrentlyPlayingSample - { - int nAudioSampleID = 0; - long nSamplePosition = 0; - bool bFinished = false; - bool bLoop = false; - bool bFlagForStop = false; - }; - - static std::list listActiveSamples; - - public: - static bool InitialiseAudio(unsigned int nSampleRate = 44100, unsigned int nChannels = 1, unsigned int nBlocks = 8, unsigned int nBlockSamples = 512); - static bool DestroyAudio(); - static void SetUserSynthFunction(std::function func); - static void SetUserFilterFunction(std::function func); - - public: - static int LoadAudioSample(std::string sWavFile, olc::ResourcePack *pack = nullptr); - static void PlaySample(int id, bool bLoop = false); - static void StopSample(int id); - static void StopAll(); - static float GetMixerOutput(int nChannel, float fGlobalTime, float fTimeStep); - - - private: -#ifdef USE_WINDOWS // Windows specific sound management - static void CALLBACK waveOutProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwParam1, DWORD dwParam2); - static unsigned int m_nSampleRate; - static unsigned int m_nChannels; - static unsigned int m_nBlockCount; - static unsigned int m_nBlockSamples; - static unsigned int m_nBlockCurrent; - static short* m_pBlockMemory; - static WAVEHDR *m_pWaveHeaders; - static HWAVEOUT m_hwDevice; - static std::atomic m_nBlockFree; - static std::condition_variable m_cvBlockNotZero; - static std::mutex m_muxBlockNotZero; -#endif - -#ifdef USE_ALSA - static snd_pcm_t *m_pPCM; - static unsigned int m_nSampleRate; - static unsigned int m_nChannels; - static unsigned int m_nBlockSamples; - static short* m_pBlockMemory; -#endif - -#ifdef USE_OPENAL - static std::queue m_qAvailableBuffers; - static ALuint *m_pBuffers; - static ALuint m_nSource; - static ALCdevice *m_pDevice; - static ALCcontext *m_pContext; - static unsigned int m_nSampleRate; - static unsigned int m_nChannels; - static unsigned int m_nBlockCount; - static unsigned int m_nBlockSamples; - static short* m_pBlockMemory; -#endif - - static void AudioThread(); - static std::thread m_AudioThread; - static std::atomic m_bAudioThreadActive; - static std::atomic m_fGlobalTime; - static std::function funcUserSynth; - static std::function funcUserFilter; - }; -} - - -// Implementation, platform-independent - -#ifdef OLC_PGEX_SOUND -#undef OLC_PGEX_SOUND - -namespace olc -{ - SOUND::AudioSample::AudioSample() - { } - - SOUND::AudioSample::AudioSample(std::string sWavFile, olc::ResourcePack *pack) - { - LoadFromFile(sWavFile, pack); - } - - olc::rcode SOUND::AudioSample::LoadFromFile(std::string sWavFile, olc::ResourcePack *pack) - { - auto ReadWave = [&](std::istream &is) - { - char dump[4]; - is.read(dump, sizeof(char) * 4); // Read "RIFF" - if (strncmp(dump, "RIFF", 4) != 0) return olc::FAIL; - is.read(dump, sizeof(char) * 4); // Not Interested - is.read(dump, sizeof(char) * 4); // Read "WAVE" - if (strncmp(dump, "WAVE", 4) != 0) return olc::FAIL; - - // Read Wave description chunk - is.read(dump, sizeof(char) * 4); // Read "fmt " - unsigned int nHeaderSize = 0; - is.read((char*)&nHeaderSize, sizeof(unsigned int)); // Not Interested - is.read((char*)&wavHeader, nHeaderSize);// sizeof(WAVEFORMATEX)); // Read Wave Format Structure chunk - // Note the -2, because the structure has 2 bytes to indicate its own size - // which are not in the wav file - - // Just check if wave format is compatible with olcPGE - if (wavHeader.wBitsPerSample != 16 || wavHeader.nSamplesPerSec != 44100) - return olc::FAIL; - - // Search for audio data chunk - uint32_t nChunksize = 0; - is.read(dump, sizeof(char) * 4); // Read chunk header - is.read((char*)&nChunksize, sizeof(uint32_t)); // Read chunk size - while (strncmp(dump, "data", 4) != 0) - { - // Not audio data, so just skip it - //std::fseek(f, nChunksize, SEEK_CUR); - is.seekg(nChunksize, std::istream::cur); - is.read(dump, sizeof(char) * 4); - is.read((char*)&nChunksize, sizeof(uint32_t)); - } - - // Finally got to data, so read it all in and convert to float samples - nSamples = nChunksize / (wavHeader.nChannels * (wavHeader.wBitsPerSample >> 3)); - nChannels = wavHeader.nChannels; - - // Create floating point buffer to hold audio sample - fSample = new float[nSamples * nChannels]; - float *pSample = fSample; - - // Read in audio data and normalise - for (long i = 0; i < nSamples; i++) - { - for (int c = 0; c < nChannels; c++) - { - short s = 0; - if (!is.eof()) - { - is.read((char*)&s, sizeof(short)); - - *pSample = (float)s / (float)(SHRT_MAX); - pSample++; - } - } - } - - // All done, flag sound as valid - bSampleValid = true; - return olc::OK; - }; - - if (pack != nullptr) - { - olc::ResourcePack::sEntry entry = pack->GetStreamBuffer(sWavFile); - std::istream is(&entry); - return ReadWave(is); - } - else - { - // Read from file - std::ifstream ifs(sWavFile, std::ifstream::binary); - if (ifs.is_open()) - { - return ReadWave(ifs); - } - else - return olc::FAIL; - } - } - - // This vector holds all loaded sound samples in memory - std::vector vecAudioSamples; - - // This structure represents a sound that is currently playing. It only - // holds the sound ID and where this instance of it is up to for its - // current playback - - void SOUND::SetUserSynthFunction(std::function func) - { - funcUserSynth = func; - } - - void SOUND::SetUserFilterFunction(std::function func) - { - funcUserFilter = func; - } - - // Load a 16-bit WAVE file @ 44100Hz ONLY into memory. A sample ID - // number is returned if successful, otherwise -1 - int SOUND::LoadAudioSample(std::string sWavFile, olc::ResourcePack *pack) - { - - olc::SOUND::AudioSample a(sWavFile, pack); - if (a.bSampleValid) - { - vecAudioSamples.push_back(a); - return (unsigned int)vecAudioSamples.size(); - } - else - return -1; - } - - // Add sample 'id' to the mixers sounds to play list - void SOUND::PlaySample(int id, bool bLoop) - { - olc::SOUND::sCurrentlyPlayingSample a; - a.nAudioSampleID = id; - a.nSamplePosition = 0; - a.bFinished = false; - a.bFlagForStop = false; - a.bLoop = bLoop; - SOUND::listActiveSamples.push_back(a); - } - - void SOUND::StopSample(int id) - { - // Find first occurence of sample id - auto s = std::find_if(listActiveSamples.begin(), listActiveSamples.end(), [&](const olc::SOUND::sCurrentlyPlayingSample &s) { return s.nAudioSampleID == id; }); - if (s != listActiveSamples.end()) - s->bFlagForStop = true; - } - - void SOUND::StopAll() - { - for (auto &s : listActiveSamples) - { - s.bFlagForStop = true; - } - } - - float SOUND::GetMixerOutput(int nChannel, float fGlobalTime, float fTimeStep) - { - // Accumulate sample for this channel - float fMixerSample = 0.0f; - - for (auto &s : listActiveSamples) - { - if (m_bAudioThreadActive) - { - if (s.bFlagForStop) - { - s.bLoop = false; - s.bFinished = true; - } - else - { - // Calculate sample position - s.nSamplePosition += roundf((float)vecAudioSamples[s.nAudioSampleID - 1].wavHeader.nSamplesPerSec * fTimeStep); - - // If sample position is valid add to the mix - if (s.nSamplePosition < vecAudioSamples[s.nAudioSampleID - 1].nSamples) - fMixerSample += vecAudioSamples[s.nAudioSampleID - 1].fSample[(s.nSamplePosition * vecAudioSamples[s.nAudioSampleID - 1].nChannels) + nChannel]; - else - { - if (s.bLoop) - { - s.nSamplePosition = 0; - } - else - s.bFinished = true; // Else sound has completed - } - } - } - else - return 0.0f; - } - - // If sounds have completed then remove them - listActiveSamples.remove_if([](const sCurrentlyPlayingSample &s) {return s.bFinished; }); - - // The users application might be generating sound, so grab that if it exists - if (funcUserSynth != nullptr) - fMixerSample += funcUserSynth(nChannel, fGlobalTime, fTimeStep); - - // Return the sample via an optional user override to filter the sound - if (funcUserFilter != nullptr) - return funcUserFilter(nChannel, fGlobalTime, fMixerSample); - else - return fMixerSample; - } - - std::thread SOUND::m_AudioThread; - std::atomic SOUND::m_bAudioThreadActive{ false }; - std::atomic SOUND::m_fGlobalTime{ 0.0f }; - std::list SOUND::listActiveSamples; - std::function SOUND::funcUserSynth = nullptr; - std::function SOUND::funcUserFilter = nullptr; -} - -// Implementation, Windows-specific -#ifdef USE_WINDOWS -#pragma comment(lib, "winmm.lib") - -namespace olc -{ - bool SOUND::InitialiseAudio(unsigned int nSampleRate, unsigned int nChannels, unsigned int nBlocks, unsigned int nBlockSamples) - { - // Initialise Sound Engine - m_bAudioThreadActive = false; - m_nSampleRate = nSampleRate; - m_nChannels = nChannels; - m_nBlockCount = nBlocks; - m_nBlockSamples = nBlockSamples; - m_nBlockFree = m_nBlockCount; - m_nBlockCurrent = 0; - m_pBlockMemory = nullptr; - m_pWaveHeaders = nullptr; - - // Device is available - WAVEFORMATEX waveFormat; - waveFormat.wFormatTag = WAVE_FORMAT_PCM; - waveFormat.nSamplesPerSec = m_nSampleRate; - waveFormat.wBitsPerSample = sizeof(short) * 8; - waveFormat.nChannels = m_nChannels; - waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels; - waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; - waveFormat.cbSize = 0; - - listActiveSamples.clear(); - - // Open Device if valid - if (waveOutOpen(&m_hwDevice, WAVE_MAPPER, &waveFormat, (DWORD_PTR)SOUND::waveOutProc, (DWORD_PTR)0, CALLBACK_FUNCTION) != S_OK) - return DestroyAudio(); - - // Allocate Wave|Block Memory - m_pBlockMemory = new short[m_nBlockCount * m_nBlockSamples]; - if (m_pBlockMemory == nullptr) - return DestroyAudio(); - ZeroMemory(m_pBlockMemory, sizeof(short) * m_nBlockCount * m_nBlockSamples); - - m_pWaveHeaders = new WAVEHDR[m_nBlockCount]; - if (m_pWaveHeaders == nullptr) - return DestroyAudio(); - ZeroMemory(m_pWaveHeaders, sizeof(WAVEHDR) * m_nBlockCount); - - // Link headers to block memory - for (unsigned int n = 0; n < m_nBlockCount; n++) - { - m_pWaveHeaders[n].dwBufferLength = m_nBlockSamples * sizeof(short); - m_pWaveHeaders[n].lpData = (LPSTR)(m_pBlockMemory + (n * m_nBlockSamples)); - } - - m_bAudioThreadActive = true; - m_AudioThread = std::thread(&SOUND::AudioThread); - - // Start the ball rolling with the sound delivery thread - std::unique_lock lm(m_muxBlockNotZero); - m_cvBlockNotZero.notify_one(); - return true; - } - - // Stop and clean up audio system - bool SOUND::DestroyAudio() - { - m_bAudioThreadActive = false; - m_AudioThread.join(); - return false; - } - - // Handler for soundcard request for more data - void CALLBACK SOUND::waveOutProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwParam1, DWORD dwParam2) - { - if (uMsg != WOM_DONE) return; - m_nBlockFree++; - std::unique_lock lm(m_muxBlockNotZero); - m_cvBlockNotZero.notify_one(); - } - - // Audio thread. This loop responds to requests from the soundcard to fill 'blocks' - // with audio data. If no requests are available it goes dormant until the sound - // card is ready for more data. The block is fille by the "user" in some manner - // and then issued to the soundcard. - void SOUND::AudioThread() - { - m_fGlobalTime = 0.0f; - static float fTimeStep = 1.0f / (float)m_nSampleRate; - - // Goofy hack to get maximum integer for a type at run-time - short nMaxSample = (short)pow(2, (sizeof(short) * 8) - 1) - 1; - float fMaxSample = (float)nMaxSample; - short nPreviousSample = 0; - - while (m_bAudioThreadActive) - { - // Wait for block to become available - if (m_nBlockFree == 0) - { - std::unique_lock lm(m_muxBlockNotZero); - while (m_nBlockFree == 0) // sometimes, Windows signals incorrectly - m_cvBlockNotZero.wait(lm); - } - - // Block is here, so use it - m_nBlockFree--; - - // Prepare block for processing - if (m_pWaveHeaders[m_nBlockCurrent].dwFlags & WHDR_PREPARED) - waveOutUnprepareHeader(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR)); - - short nNewSample = 0; - int nCurrentBlock = m_nBlockCurrent * m_nBlockSamples; - - auto clip = [](float fSample, float fMax) - { - if (fSample >= 0.0) - return fmin(fSample, fMax); - else - return fmax(fSample, -fMax); - }; - - for (unsigned int n = 0; n < m_nBlockSamples; n += m_nChannels) - { - // User Process - for (unsigned int c = 0; c < m_nChannels; c++) - { - nNewSample = (short)(clip(GetMixerOutput(c, m_fGlobalTime, fTimeStep), 1.0) * fMaxSample); - m_pBlockMemory[nCurrentBlock + n + c] = nNewSample; - nPreviousSample = nNewSample; - } - - m_fGlobalTime = m_fGlobalTime + fTimeStep; - } - - // Send block to sound device - waveOutPrepareHeader(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR)); - waveOutWrite(m_hwDevice, &m_pWaveHeaders[m_nBlockCurrent], sizeof(WAVEHDR)); - m_nBlockCurrent++; - m_nBlockCurrent %= m_nBlockCount; - } - } - - unsigned int SOUND::m_nSampleRate = 0; - unsigned int SOUND::m_nChannels = 0; - unsigned int SOUND::m_nBlockCount = 0; - unsigned int SOUND::m_nBlockSamples = 0; - unsigned int SOUND::m_nBlockCurrent = 0; - short* SOUND::m_pBlockMemory = nullptr; - WAVEHDR *SOUND::m_pWaveHeaders = nullptr; - HWAVEOUT SOUND::m_hwDevice; - std::atomic SOUND::m_nBlockFree = 0; - std::condition_variable SOUND::m_cvBlockNotZero; - std::mutex SOUND::m_muxBlockNotZero; -} - -#elif defined(USE_ALSA) - -namespace olc -{ - bool SOUND::InitialiseAudio(unsigned int nSampleRate, unsigned int nChannels, unsigned int nBlocks, unsigned int nBlockSamples) - { - // Initialise Sound Engine - m_bAudioThreadActive = false; - m_nSampleRate = nSampleRate; - m_nChannels = nChannels; - m_nBlockSamples = nBlockSamples; - m_pBlockMemory = nullptr; - - // Open PCM stream - int rc = snd_pcm_open(&m_pPCM, "default", SND_PCM_STREAM_PLAYBACK, 0); - if (rc < 0) - return DestroyAudio(); - - - // Prepare the parameter structure and set default parameters - snd_pcm_hw_params_t *params; - snd_pcm_hw_params_alloca(¶ms); - snd_pcm_hw_params_any(m_pPCM, params); - - // Set other parameters - snd_pcm_hw_params_set_format(m_pPCM, params, SND_PCM_FORMAT_S16_LE); - snd_pcm_hw_params_set_rate(m_pPCM, params, m_nSampleRate, 0); - snd_pcm_hw_params_set_channels(m_pPCM, params, m_nChannels); - snd_pcm_hw_params_set_period_size(m_pPCM, params, m_nBlockSamples, 0); - snd_pcm_hw_params_set_periods(m_pPCM, params, nBlocks, 0); - - // Save these parameters - rc = snd_pcm_hw_params(m_pPCM, params); - if (rc < 0) - return DestroyAudio(); - - listActiveSamples.clear(); - - // Allocate Wave|Block Memory - m_pBlockMemory = new short[m_nBlockSamples]; - if (m_pBlockMemory == nullptr) - return DestroyAudio(); - std::fill(m_pBlockMemory, m_pBlockMemory + m_nBlockSamples, 0); - - // Unsure if really needed, helped prevent underrun on my setup - snd_pcm_start(m_pPCM); - for (unsigned int i = 0; i < nBlocks; i++) - rc = snd_pcm_writei(m_pPCM, m_pBlockMemory, 512); - - snd_pcm_start(m_pPCM); - m_bAudioThreadActive = true; - m_AudioThread = std::thread(&SOUND::AudioThread); - - return true; - } - - // Stop and clean up audio system - bool SOUND::DestroyAudio() - { - m_bAudioThreadActive = false; - m_AudioThread.join(); - snd_pcm_drain(m_pPCM); - snd_pcm_close(m_pPCM); - return false; - } - - - // Audio thread. This loop responds to requests from the soundcard to fill 'blocks' - // with audio data. If no requests are available it goes dormant until the sound - // card is ready for more data. The block is fille by the "user" in some manner - // and then issued to the soundcard. - void SOUND::AudioThread() - { - m_fGlobalTime = 0.0f; - static float fTimeStep = 1.0f / (float)m_nSampleRate; - - // Goofy hack to get maximum integer for a type at run-time - short nMaxSample = (short)pow(2, (sizeof(short) * 8) - 1) - 1; - float fMaxSample = (float)nMaxSample; - short nPreviousSample = 0; - - while (m_bAudioThreadActive) - { - short nNewSample = 0; - - auto clip = [](float fSample, float fMax) - { - if (fSample >= 0.0) - return fmin(fSample, fMax); - else - return fmax(fSample, -fMax); - }; - - for (unsigned int n = 0; n < m_nBlockSamples; n += m_nChannels) - { - // User Process - for (unsigned int c = 0; c < m_nChannels; c++) - { - nNewSample = (short)(clip(GetMixerOutput(c, m_fGlobalTime, fTimeStep), 1.0) * fMaxSample); - m_pBlockMemory[n + c] = nNewSample; - nPreviousSample = nNewSample; - } - - m_fGlobalTime = m_fGlobalTime + fTimeStep; - } - - // Send block to sound device - snd_pcm_uframes_t nLeft = m_nBlockSamples; - short *pBlockPos = m_pBlockMemory; - while (nLeft > 0) - { - int rc = snd_pcm_writei(m_pPCM, pBlockPos, nLeft); - if (rc > 0) - { - pBlockPos += rc * m_nChannels; - nLeft -= rc; - } - if (rc == -EAGAIN) continue; - if (rc == -EPIPE) // an underrun occured, prepare the device for more data - snd_pcm_prepare(m_pPCM); - } - } - } - - snd_pcm_t* SOUND::m_pPCM = nullptr; - unsigned int SOUND::m_nSampleRate = 0; - unsigned int SOUND::m_nChannels = 0; - unsigned int SOUND::m_nBlockSamples = 0; - short* SOUND::m_pBlockMemory = nullptr; -} - -#elif defined(USE_OPENAL) - -namespace olc -{ - bool SOUND::InitialiseAudio(unsigned int nSampleRate, unsigned int nChannels, unsigned int nBlocks, unsigned int nBlockSamples) - { - // Initialise Sound Engine - m_bAudioThreadActive = false; - m_nSampleRate = nSampleRate; - m_nChannels = nChannels; - m_nBlockCount = nBlocks; - m_nBlockSamples = nBlockSamples; - m_pBlockMemory = nullptr; - - // Open the device and create the context - m_pDevice = alcOpenDevice(NULL); - if (m_pDevice) - { - m_pContext = alcCreateContext(m_pDevice, NULL); - alcMakeContextCurrent(m_pContext); - } - else - return DestroyAudio(); - - // Allocate memory for sound data - alGetError(); - m_pBuffers = new ALuint[m_nBlockCount]; - alGenBuffers(m_nBlockCount, m_pBuffers); - alGenSources(1, &m_nSource); - - for (unsigned int i = 0; i < m_nBlockCount; i++) - m_qAvailableBuffers.push(m_pBuffers[i]); - - listActiveSamples.clear(); - - // Allocate Wave|Block Memory - m_pBlockMemory = new short[m_nBlockSamples]; - if (m_pBlockMemory == nullptr) - return DestroyAudio(); - std::fill(m_pBlockMemory, m_pBlockMemory + m_nBlockSamples, 0); - - m_bAudioThreadActive = true; - m_AudioThread = std::thread(&SOUND::AudioThread); - return true; - } - - // Stop and clean up audio system - bool SOUND::DestroyAudio() - { - m_bAudioThreadActive = false; - m_AudioThread.join(); - - alDeleteBuffers(m_nBlockCount, m_pBuffers); - delete[] m_pBuffers; - alDeleteSources(1, &m_nSource); - - alcMakeContextCurrent(NULL); - alcDestroyContext(m_pContext); - alcCloseDevice(m_pDevice); - return false; - } - - - // Audio thread. This loop responds to requests from the soundcard to fill 'blocks' - // with audio data. If no requests are available it goes dormant until the sound - // card is ready for more data. The block is fille by the "user" in some manner - // and then issued to the soundcard. - void SOUND::AudioThread() - { - m_fGlobalTime = 0.0f; - static float fTimeStep = 1.0f / (float)m_nSampleRate; - - // Goofy hack to get maximum integer for a type at run-time - short nMaxSample = (short)pow(2, (sizeof(short) * 8) - 1) - 1; - float fMaxSample = (float)nMaxSample; - short nPreviousSample = 0; - - std::vector vProcessed; - - while (m_bAudioThreadActive) - { - ALint nState, nProcessed; - alGetSourcei(m_nSource, AL_SOURCE_STATE, &nState); - alGetSourcei(m_nSource, AL_BUFFERS_PROCESSED, &nProcessed); - - // Add processed buffers to our queue - vProcessed.resize(nProcessed); - alSourceUnqueueBuffers(m_nSource, nProcessed, vProcessed.data()); - for (ALint nBuf : vProcessed) m_qAvailableBuffers.push(nBuf); - - // Wait until there is a free buffer (ewww) - if (m_qAvailableBuffers.empty()) continue; - - short nNewSample = 0; - - auto clip = [](float fSample, float fMax) - { - if (fSample >= 0.0) - return fmin(fSample, fMax); - else - return fmax(fSample, -fMax); - }; - - for (unsigned int n = 0; n < m_nBlockSamples; n += m_nChannels) - { - // User Process - for (unsigned int c = 0; c < m_nChannels; c++) - { - nNewSample = (short)(clip(GetMixerOutput(c, m_fGlobalTime, fTimeStep), 1.0) * fMaxSample); - m_pBlockMemory[n + c] = nNewSample; - nPreviousSample = nNewSample; - } - - m_fGlobalTime = m_fGlobalTime + fTimeStep; - } - - // Fill OpenAL data buffer - alBufferData( - m_qAvailableBuffers.front(), - m_nChannels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, - m_pBlockMemory, - 2 * m_nBlockSamples, - m_nSampleRate - ); - // Add it to the OpenAL queue - alSourceQueueBuffers(m_nSource, 1, &m_qAvailableBuffers.front()); - // Remove it from ours - m_qAvailableBuffers.pop(); - - // If it's not playing for some reason, change that - if (nState != AL_PLAYING) - alSourcePlay(m_nSource); - } - } - - std::queue SOUND::m_qAvailableBuffers; - ALuint *SOUND::m_pBuffers = nullptr; - ALuint SOUND::m_nSource = 0; - ALCdevice *SOUND::m_pDevice = nullptr; - ALCcontext *SOUND::m_pContext = nullptr; - unsigned int SOUND::m_nSampleRate = 0; - unsigned int SOUND::m_nChannels = 0; - unsigned int SOUND::m_nBlockCount = 0; - unsigned int SOUND::m_nBlockSamples = 0; - short* SOUND::m_pBlockMemory = nullptr; -} - -#else // Some other platform - -namespace olc -{ - bool SOUND::InitialiseAudio(unsigned int nSampleRate, unsigned int nChannels, unsigned int nBlocks, unsigned int nBlockSamples) - { - return true; - } - - // Stop and clean up audio system - bool SOUND::DestroyAudio() - { - return false; - } - - - // Audio thread. This loop responds to requests from the soundcard to fill 'blocks' - // with audio data. If no requests are available it goes dormant until the sound - // card is ready for more data. The block is fille by the "user" in some manner - // and then issued to the soundcard. - void SOUND::AudioThread() - { } -} - -#endif -#endif -#endif // OLC_PGEX_SOUND \ No newline at end of file diff --git a/Videos/zombie.png b/Videos/zombie.png deleted file mode 100644 index 8c2e502..0000000 Binary files a/Videos/zombie.png and /dev/null differ diff --git a/WASM/README.md b/WASM/README.md deleted file mode 100644 index 676d206..0000000 --- a/WASM/README.md +++ /dev/null @@ -1 +0,0 @@ -Coing Soon, information on using olc::PixelGameEngine in web browsers diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_01_001.png b/WikiPics/BreakOutTutorialPics/Tutorial_01_001.png deleted file mode 100644 index 45a766b..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_01_001.png and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_01_002.png b/WikiPics/BreakOutTutorialPics/Tutorial_01_002.png deleted file mode 100644 index 070c7d8..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_01_002.png and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_01_003.png b/WikiPics/BreakOutTutorialPics/Tutorial_01_003.png deleted file mode 100644 index ac611d8..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_01_003.png and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_01_004.png b/WikiPics/BreakOutTutorialPics/Tutorial_01_004.png deleted file mode 100644 index 7ddcf7c..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_01_004.png and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_01_005.png b/WikiPics/BreakOutTutorialPics/Tutorial_01_005.png deleted file mode 100644 index 04e462a..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_01_005.png and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_01_006.png b/WikiPics/BreakOutTutorialPics/Tutorial_01_006.png deleted file mode 100644 index 96fb452..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_01_006.png and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_02_001.gif b/WikiPics/BreakOutTutorialPics/Tutorial_02_001.gif deleted file mode 100644 index 14c1631..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_02_001.gif and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_02_002.gif b/WikiPics/BreakOutTutorialPics/Tutorial_02_002.gif deleted file mode 100644 index fc9f434..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_02_002.gif and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_02_003.gif b/WikiPics/BreakOutTutorialPics/Tutorial_02_003.gif deleted file mode 100644 index 25f4d2c..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_02_003.gif and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_02_004.gif b/WikiPics/BreakOutTutorialPics/Tutorial_02_004.gif deleted file mode 100644 index 4265130..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_02_004.gif and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_03_001.gif b/WikiPics/BreakOutTutorialPics/Tutorial_03_001.gif deleted file mode 100644 index a7db763..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_03_001.gif and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_03_002.gif b/WikiPics/BreakOutTutorialPics/Tutorial_03_002.gif deleted file mode 100644 index d07346f..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_03_002.gif and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_04_001.png b/WikiPics/BreakOutTutorialPics/Tutorial_04_001.png deleted file mode 100644 index 3919e1c..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_04_001.png and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_04_002.png b/WikiPics/BreakOutTutorialPics/Tutorial_04_002.png deleted file mode 100644 index 16f3bb7..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_04_002.png and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_04_003.png b/WikiPics/BreakOutTutorialPics/Tutorial_04_003.png deleted file mode 100644 index 4093e02..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_04_003.png and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_04_004.png b/WikiPics/BreakOutTutorialPics/Tutorial_04_004.png deleted file mode 100644 index 1e60a8b..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_04_004.png and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_05_001.gif b/WikiPics/BreakOutTutorialPics/Tutorial_05_001.gif deleted file mode 100644 index 7976404..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_05_001.gif and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/Tutorial_06_001.gif b/WikiPics/BreakOutTutorialPics/Tutorial_06_001.gif deleted file mode 100644 index b603236..0000000 Binary files a/WikiPics/BreakOutTutorialPics/Tutorial_06_001.gif and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/tut_fragment.png b/WikiPics/BreakOutTutorialPics/tut_fragment.png deleted file mode 100644 index 6e71006..0000000 Binary files a/WikiPics/BreakOutTutorialPics/tut_fragment.png and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/tut_tile.png b/WikiPics/BreakOutTutorialPics/tut_tile.png deleted file mode 100644 index 359630a..0000000 Binary files a/WikiPics/BreakOutTutorialPics/tut_tile.png and /dev/null differ diff --git a/WikiPics/BreakOutTutorialPics/tut_tiles.png b/WikiPics/BreakOutTutorialPics/tut_tiles.png deleted file mode 100644 index 8604c45..0000000 Binary files a/WikiPics/BreakOutTutorialPics/tut_tiles.png and /dev/null differ diff --git a/WikiPics/Drawing1.png b/WikiPics/Drawing1.png deleted file mode 100644 index 098a081..0000000 Binary files a/WikiPics/Drawing1.png and /dev/null differ diff --git a/WikiPics/Drawing10.png b/WikiPics/Drawing10.png deleted file mode 100644 index 5ec89da..0000000 Binary files a/WikiPics/Drawing10.png and /dev/null differ diff --git a/WikiPics/Drawing11.png b/WikiPics/Drawing11.png deleted file mode 100644 index eb33623..0000000 Binary files a/WikiPics/Drawing11.png and /dev/null differ diff --git a/WikiPics/Drawing12.png b/WikiPics/Drawing12.png deleted file mode 100644 index ee643cf..0000000 Binary files a/WikiPics/Drawing12.png and /dev/null differ diff --git a/WikiPics/Drawing13.png b/WikiPics/Drawing13.png deleted file mode 100644 index 5521b5b..0000000 Binary files a/WikiPics/Drawing13.png and /dev/null differ diff --git a/WikiPics/Drawing2.png b/WikiPics/Drawing2.png deleted file mode 100644 index 8c6252c..0000000 Binary files a/WikiPics/Drawing2.png and /dev/null differ diff --git a/WikiPics/Drawing3.png b/WikiPics/Drawing3.png deleted file mode 100644 index f3bb0cd..0000000 Binary files a/WikiPics/Drawing3.png and /dev/null differ diff --git a/WikiPics/Drawing4.png b/WikiPics/Drawing4.png deleted file mode 100644 index 0fccbd6..0000000 Binary files a/WikiPics/Drawing4.png and /dev/null differ diff --git a/WikiPics/Drawing5.png b/WikiPics/Drawing5.png deleted file mode 100644 index 72728fc..0000000 Binary files a/WikiPics/Drawing5.png and /dev/null differ diff --git a/WikiPics/Drawing6.png b/WikiPics/Drawing6.png deleted file mode 100644 index f86e413..0000000 Binary files a/WikiPics/Drawing6.png and /dev/null differ diff --git a/WikiPics/Drawing7.png b/WikiPics/Drawing7.png deleted file mode 100644 index 496e612..0000000 Binary files a/WikiPics/Drawing7.png and /dev/null differ diff --git a/WikiPics/Drawing8.png b/WikiPics/Drawing8.png deleted file mode 100644 index e962fea..0000000 Binary files a/WikiPics/Drawing8.png and /dev/null differ diff --git a/WikiPics/Drawing9.png b/WikiPics/Drawing9.png deleted file mode 100644 index ea9e7d2..0000000 Binary files a/WikiPics/Drawing9.png and /dev/null differ diff --git a/WikiPics/Stub.txt b/WikiPics/Stub.txt deleted file mode 100644 index 8b13789..0000000 --- a/WikiPics/Stub.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/extensions/olcPGEX_QuickGUI.h b/extensions/olcPGEX_QuickGUI.h new file mode 100644 index 0000000..664d0c2 --- /dev/null +++ b/extensions/olcPGEX_QuickGUI.h @@ -0,0 +1,786 @@ +/* + OneLoneCoder - QuickGUI v1.00 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + A semi-immediate mode GUI for very simple GUI stuff. + Includes: + Label - Displays a single-line string + TextBox - Click to enter/edit single-line text + Button - A clickable labelled rectangle + CheckBox - A clickable labelled rectangle that retains state + Slider - An omnidirectional draggable handle between two values + + License (OLC-3) + ~~~~~~~~~~~~~~~ + + Copyright 2018 - 2021 OneLoneCoder.com + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions or derivations of source code must retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions or derivative works in binary form must reproduce + the above copyright notice. This list of conditions and the following + disclaimer must be reproduced in the documentation and/or other + materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Links + ~~~~~ + YouTube: https://www.youtube.com/javidx9 + Discord: https://discord.gg/WhwHUMV + Twitter: https://www.twitter.com/javidx9 + Twitch: https://www.twitch.tv/javidx9 + GitHub: https://www.github.com/onelonecoder + Homepage: https://www.onelonecoder.com + + Author + ~~~~~~ + David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021, 2022 + +*/ + +#ifndef OLC_PGEX_QUICKGUI_H +#define OLC_PGEX_QUICKGUI_H + +#include "olcPixelGameEngine.h" + + +namespace olc::QuickGUI +{ + class Manager; + + // Virtual base class for all controls + class BaseControl + { + public: + BaseControl(olc::QuickGUI::Manager& manager); + virtual ~BaseControl(); + + public: + // Switches the control on/off + void Enable(const bool bEnable); + // Sets whether or not the control is interactive/displayed + bool bVisible = true; + + // True on single frame control begins being manipulated + bool bPressed = false; + // True on all frames control is under user manipulation + bool bHeld = false; + // True on single frame control ceases being manipulated + bool bReleased = false; + + public: + // Updates the controls behvaiour + virtual void Update(olc::PixelGameEngine* pge) = 0; + // Draws the control using "sprite" based CPU operations + virtual void Draw(olc::PixelGameEngine* pge) = 0; + // Draws the control using "decal" based GPU operations + virtual void DrawDecal(olc::PixelGameEngine* pge) = 0; + + protected: + // Controls are related to a manager, where the theme resides + // and control groups can be implemented + olc::QuickGUI::Manager& m_manager; + + // All controls exists in one of four states + // Disabled - Greyed out and not interactive + // Normal - interactive and operational + // Hover - currently under the users mouse focus + // Click - user is interacting with the control + enum class State { Disabled, Normal, Hover, Click } m_state = State::Normal; + + // To add a "swish" to things, controls can fade between states + float m_fTransition = 0.0; + }; + + + // A QuickGUI::Manager acts as a convenient grouping of controls + class Manager + { + public: + // Construct Manager, bCleanUpForMe will automatically DELETE any controls + // given to this manager via AddControl() if true + Manager(const bool bCleanUpForMe = true); + virtual ~Manager(); + + public: + // Add a gui element derived form BaseControl to this manager + void AddControl(BaseControl* control); + // Updates all controls this manager operates + void Update(olc::PixelGameEngine* pge); + // Draws as "sprite" all controls this manager operates + void Draw(olc::PixelGameEngine* pge); + // Draws as "decal" all controls this manager operates + void DrawDecal(olc::PixelGameEngine* pge); + + public: // This managers "Theme" can be set here + // Various element colours + olc::Pixel colNormal = olc::DARK_BLUE; + olc::Pixel colHover = olc::BLUE; + olc::Pixel colClick = olc::CYAN; + olc::Pixel colDisable = olc::DARK_GREY; + olc::Pixel colBorder = olc::WHITE; + olc::Pixel colText = olc::WHITE; + // Speed to transiton from Normal -> Hover + float fHoverSpeedOn = 10.0f; + // Speed to transiton from Hover -> Normal + float fHoverSpeedOff = 4.0f; + + private: + // Should this manager call delete on the controls it opeerates? + bool m_bEraseControlsOnDestroy = true; + // Container of controls + std::vector m_vControls; + }; + + + // Creates a Label Control - it's just text! + class Label : public BaseControl + { + public: + Label(olc::QuickGUI::Manager& manager, // Associate with a Manager + const std::string& text, // Text to display + const olc::vf2d& pos, // Location of label top-left + const olc::vf2d& size); // Size of label + + public: + // Position of button + olc::vf2d vPos; + // Size of button + olc::vf2d vSize; + // Text displayed on button + std::string sText; + // Show a border? + bool bHasBorder = false; + // Show a background? + bool bHasBackground = false; + // Where should the text be positioned? + enum class Alignment + {Left, Centre, Right} nAlign = Alignment::Centre; + + public: // BaseControl overrides + void Update(olc::PixelGameEngine* pge) override; + void Draw(olc::PixelGameEngine* pge) override; + void DrawDecal(olc::PixelGameEngine* pge) override; + }; + + class TextBox : public Label + { + public: + TextBox(olc::QuickGUI::Manager& manager, // Associate with a Manager + const std::string& text, // Text to display + const olc::vf2d& pos, // Location of text box top-left + const olc::vf2d& size); // Size of text box + + public: // BaseControl overrides + void Update(olc::PixelGameEngine* pge) override; + void Draw(olc::PixelGameEngine* pge) override; + void DrawDecal(olc::PixelGameEngine* pge) override; + + protected: + bool m_bTextEdit = false; + + }; + + // Creates a Button Control - a clickable, labelled rectangle + class Button : public BaseControl + { + public: + Button(olc::QuickGUI::Manager& manager, // Associate with a Manager + const std::string& text, // Text to display + const olc::vf2d& pos, // Location of button top-left + const olc::vf2d& size); // Size of button + + public: + // Position of button + olc::vf2d vPos; + // Size of button + olc::vf2d vSize; + // Text displayed on button + std::string sText; + + public: // BaseControl overrides + void Update(olc::PixelGameEngine* pge) override; + void Draw(olc::PixelGameEngine* pge) override; + void DrawDecal(olc::PixelGameEngine* pge) override; + }; + + // Creates a Button Control - a clickable, labelled rectangle + class CheckBox : public Button + { + public: + CheckBox(olc::QuickGUI::Manager& manager, // Associate with a Manager + const std::string& text, // Text to display + const bool check, // Is checked or not? + const olc::vf2d& pos, // Location of button top-left + const olc::vf2d& size); // Size of button + + public: + bool bChecked = false; + + public: // BaseControl overrides + void Update(olc::PixelGameEngine* pge) override; + void Draw(olc::PixelGameEngine* pge) override; + void DrawDecal(olc::PixelGameEngine* pge) override; + }; + + + // Creates a Slider Control - a grabbable handle that slides between two locations + class Slider : public BaseControl + { + public: + Slider(olc::QuickGUI::Manager& manager, // Associate with a Manager + const olc::vf2d& posmin, // Screen location of "minimum" + const olc::vf2d& posmax, // Screen location of "maximum" + const float valmin, // Value of minimum + const float valmax, // Value of maximum + const float value); // Starting value + + public: + // Minium value + float fMin = -100.0f; + // Maximum value + float fMax = +100.0f; + // Current value + float fValue = 0.0f; + // Size of grab handle + float fGrabRad = 8.0f; + // Location of minimum/start + olc::vf2d vPosMin; + // Location of maximum/end + olc::vf2d vPosMax; + + public: // BaseControl overrides + void Update(olc::PixelGameEngine* pge) override; + void Draw(olc::PixelGameEngine* pge) override; + void DrawDecal(olc::PixelGameEngine* pge) override; + }; + +} + + +#ifdef OLC_PGEX_QUICKGUI +#undef OLC_PGEX_QUICKGUI +namespace olc::QuickGUI +{ + +#pragma region BaseControl + BaseControl::BaseControl(olc::QuickGUI::Manager& manager) : m_manager(manager) + { + m_manager.AddControl(this); + } + + BaseControl::~BaseControl() + { + + } + + void BaseControl::Enable(const bool bEnable) + { + m_state = bEnable ? State::Normal : State::Disabled; + } +#pragma endregion + +#pragma region Manager + Manager::Manager(const bool bCleanUpForMe) + { + m_bEraseControlsOnDestroy = bCleanUpForMe; + } + + Manager::~Manager() + { + if (m_bEraseControlsOnDestroy) + for (auto& p : m_vControls) + delete p; + + m_vControls.clear(); + } + + void Manager::AddControl(BaseControl* control) + { + m_vControls.push_back(control); + } + + void Manager::Update(olc::PixelGameEngine* pge) + { + for (auto& p : m_vControls) p->Update(pge); + } + + void Manager::Draw(olc::PixelGameEngine* pge) + { + for (auto& p : m_vControls) p->Draw(pge); + } + + void Manager::DrawDecal(olc::PixelGameEngine* pge) + { + for (auto& p : m_vControls) p->DrawDecal(pge); + } +#pragma endregion + +#pragma region Label + Label::Label(olc::QuickGUI::Manager& manager, const std::string& text, const olc::vf2d& pos, const olc::vf2d& size) + : BaseControl(manager) + { + vPos = pos; vSize = size; sText = text; + } + + void Label::Update(olc::PixelGameEngine* pge) + { + + } + + void Label::Draw(olc::PixelGameEngine* pge) + { + if (!bVisible) + return; + + if (bHasBackground) + { + pge->FillRect(vPos + olc::vf2d(1, 1), vSize - olc::vf2d(2, 2), m_manager.colNormal); + } + + if(bHasBorder) + pge->DrawRect(vPos, vSize - olc::vf2d(1, 1), m_manager.colBorder); + + olc::vf2d vText = pge->GetTextSizeProp(sText); + switch (nAlign) + { + case Alignment::Left: + pge->DrawStringProp(olc::vf2d( vPos.x + 2.0f, vPos.y + (vSize.y - vText.y) * 0.5f ), sText, m_manager.colText); + break; + case Alignment::Centre: + pge->DrawStringProp(vPos + (vSize - vText) * 0.5f, sText, m_manager.colText); + break; + case Alignment::Right: + pge->DrawStringProp(olc::vf2d{ vPos.x + vSize.x - vText.x - 2.0f, vPos.y + (vSize.y - vText.y) * 0.5f }, sText, m_manager.colText); + break; + } + } + + void Label::DrawDecal(olc::PixelGameEngine* pge) + { + if (!bVisible) + return; + + if (bHasBackground) + { + pge->FillRectDecal(vPos + olc::vf2d(1, 1), vSize - olc::vf2d(2, 2), m_manager.colNormal); + } + + if (bHasBorder) + { + pge->SetDecalMode(olc::DecalMode::WIREFRAME); + pge->FillRectDecal(vPos + olc::vf2d(1, 1), vSize - olc::vf2d(2,2), m_manager.colBorder); + pge->SetDecalMode(olc::DecalMode::NORMAL); + } + + olc::vf2d vText = pge->GetTextSizeProp(sText); + switch (nAlign) + { + case Alignment::Left: + pge->DrawStringPropDecal({ vPos.x + 2.0f, vPos.y + (vSize.y - vText.y) * 0.5f }, sText, m_manager.colText); + break; + case Alignment::Centre: + pge->DrawStringPropDecal(vPos + (vSize - vText) * 0.5f, sText, m_manager.colText); + break; + case Alignment::Right: + pge->DrawStringPropDecal({ vPos.x + vSize.x - vText.x - 2.0f, vPos.y + (vSize.y - vText.y) * 0.5f }, sText, m_manager.colText); + break; + } + } +#pragma endregion + + +#pragma region TextBox + TextBox::TextBox(olc::QuickGUI::Manager& manager, const std::string& text, const olc::vf2d& pos, const olc::vf2d& size) + : Label(manager, text, pos, size) + { + nAlign = Alignment::Left; + bHasBorder = true; + bHasBackground = false; + } + + void TextBox::Update(olc::PixelGameEngine* pge) + { + if (m_state == State::Disabled || !bVisible) + return; + + bPressed = false; + bReleased = false; + + olc::vf2d vMouse = pge->GetMousePos(); + + if (vMouse.x >= vPos.x && vMouse.x < vPos.x + vSize.x && + vMouse.y >= vPos.y && vMouse.y < vPos.y + vSize.y) + { + // Released inside box does nothing to me, but i may have + // to finish off the neighbours... oo err + bReleased = pge->GetMouse(olc::Mouse::LEFT).bReleased; + if (bReleased && pge->IsTextEntryEnabled() && !m_bTextEdit) + { + pge->TextEntryEnable(false); + } + + bPressed = pge->GetMouse(olc::Mouse::LEFT).bPressed; + if (bPressed && !pge->IsTextEntryEnabled() && !m_bTextEdit) + { + pge->TextEntryEnable(true, sText); + m_bTextEdit = true; + } + + bHeld = pge->GetMouse(olc::Mouse::LEFT).bHeld; + + + } + else + { + // Released outside box + bReleased = pge->GetMouse(olc::Mouse::LEFT).bReleased; + if (bReleased && m_bTextEdit) + { + sText = pge->TextEntryGetString(); + pge->TextEntryEnable(false); + m_bTextEdit = false; + } + } + + if (m_bTextEdit && pge->IsTextEntryEnabled()) + sText = pge->TextEntryGetString(); + } + + void TextBox::Draw(olc::PixelGameEngine* pge) + { + if (!bVisible) + return; + + if (bHasBackground) + { + pge->FillRect(vPos + olc::vf2d(1, 1), vSize - olc::vf2d(2, 2), m_manager.colNormal); + } + + if (bHasBorder) + pge->DrawRect(vPos, vSize - olc::vf2d(1, 1), m_manager.colBorder); + + if (m_bTextEdit && pge->IsTextEntryEnabled()) + { + // Draw Cursor + int32_t i = pge->TextEntryGetCursor(); + olc::vf2d vCursorPos = pge->GetTextSizeProp(sText.substr(0, i)); + pge->FillRect(olc::vf2d(vPos.x + 2.0f + vCursorPos.x, (vPos.y + (vSize.y - 10.0f) * 0.5f)), { 2, 10 }, m_manager.colText); + } + + // Draw Text + olc::vf2d vText = pge->GetTextSizeProp(sText); + pge->DrawStringProp(olc::vf2d(vPos.x + 2.0f, vPos.y + (vSize.y - vText.y) * 0.5f), sText, m_manager.colText); + + } + + void TextBox::DrawDecal(olc::PixelGameEngine* pge) + { + if (!bVisible) + return; + + if (bHasBackground) + { + pge->FillRectDecal(vPos + olc::vf2d(1, 1), vSize - olc::vf2d(2, 2), m_manager.colNormal); + } + + if (bHasBorder) + { + pge->SetDecalMode(olc::DecalMode::WIREFRAME); + pge->FillRectDecal(vPos + olc::vf2d(1, 1), vSize - olc::vf2d(2, 2), m_manager.colBorder); + pge->SetDecalMode(olc::DecalMode::NORMAL); + } + + if (m_bTextEdit && pge->IsTextEntryEnabled()) + { + // Draw Cursor + int32_t i = pge->TextEntryGetCursor(); + olc::vf2d vCursorPos = pge->GetTextSizeProp(sText.substr(0, i)); + pge->FillRectDecal(olc::vf2d(vPos.x + 2.0f + vCursorPos.x, (vPos.y + (vSize.y - 10.0f) * 0.5f)), { 2, 10 }, m_manager.colText); + } + + // Draw Text + olc::vf2d vText = pge->GetTextSizeProp(sText); + pge->DrawStringPropDecal(olc::vf2d(vPos.x + 2.0f, vPos.y + (vSize.y - vText.y) * 0.5f), sText, m_manager.colText); + } +#pragma endregion + +#pragma region Button + Button::Button(olc::QuickGUI::Manager& manager, const std::string& text, const olc::vf2d& pos, const olc::vf2d& size) + : BaseControl(manager) + { + vPos = pos; vSize = size; sText = text; + } + + void Button::Update(olc::PixelGameEngine* pge) + { + if (m_state == State::Disabled || !bVisible) + return; + + bPressed = false; + bReleased = false; + float fElapsedTime = pge->GetElapsedTime(); + + olc::vf2d vMouse = pge->GetMousePos(); + if (m_state != State::Click) + { + if (vMouse.x >= vPos.x && vMouse.x < vPos.x + vSize.x && + vMouse.y >= vPos.y && vMouse.y < vPos.y + vSize.y) + { + m_fTransition += fElapsedTime * m_manager.fHoverSpeedOn; + m_state = State::Hover; + + bPressed = pge->GetMouse(olc::Mouse::LEFT).bPressed; + if (bPressed) + { + m_state = State::Click; + } + + bHeld = pge->GetMouse(olc::Mouse::LEFT).bHeld; + } + else + { + m_fTransition -= fElapsedTime * m_manager.fHoverSpeedOff; + m_state = State::Normal; + } + } + else + { + bHeld = pge->GetMouse(olc::Mouse::LEFT).bHeld; + bReleased = pge->GetMouse(olc::Mouse::LEFT).bReleased; + if (bReleased) m_state = State::Normal; + } + + m_fTransition = std::clamp(m_fTransition, 0.0f, 1.0f); + } + + void Button::Draw(olc::PixelGameEngine* pge) + { + if (!bVisible) + return; + + switch (m_state) + { + case State::Disabled: + pge->FillRect(vPos, vSize, m_manager.colDisable); + break; + case State::Normal: + case State::Hover: + pge->FillRect(vPos, vSize, olc::PixelLerp(m_manager.colNormal, m_manager.colHover, m_fTransition)); + break; + case State::Click: + pge->FillRect(vPos, vSize, m_manager.colClick); + break; + } + + pge->DrawRect(vPos, vSize - olc::vf2d(1, 1), m_manager.colBorder); + olc::vf2d vText = pge->GetTextSizeProp(sText); + pge->DrawStringProp(vPos + (vSize - vText) * 0.5f, sText, m_manager.colText); + } + + void Button::DrawDecal(olc::PixelGameEngine* pge) + { + if (!bVisible) + return; + + switch (m_state) + { + case State::Disabled: + pge->FillRectDecal(vPos + olc::vf2d(1, 1), vSize - olc::vf2d(2, 2), m_manager.colDisable); + break; + case State::Normal: + case State::Hover: + pge->FillRectDecal(vPos + olc::vf2d(1, 1), vSize - olc::vf2d(2, 2), olc::PixelLerp(m_manager.colNormal, m_manager.colHover, m_fTransition)); + break; + case State::Click: + pge->FillRectDecal(vPos + olc::vf2d(1, 1), vSize - olc::vf2d(2, 2), m_manager.colClick); + break; + } + pge->SetDecalMode(olc::DecalMode::WIREFRAME); + pge->FillRectDecal(vPos + olc::vf2d(1, 1), vSize - olc::vf2d(2, 2), m_manager.colBorder); + pge->SetDecalMode(olc::DecalMode::NORMAL); + + olc::vf2d vText = pge->GetTextSizeProp(sText); + pge->DrawStringPropDecal(vPos + (vSize - vText) * 0.5f, sText, m_manager.colText); + } +#pragma endregion + + +#pragma region CheckBox + CheckBox::CheckBox(olc::QuickGUI::Manager& manager, const std::string& text, const bool check, const olc::vf2d& pos, const olc::vf2d& size) + : Button(manager, text, pos, size) + { + bChecked = check; + } + + void CheckBox::Update(olc::PixelGameEngine* pge) + { + if (m_state == State::Disabled || !bVisible) + return; + + Button::Update(pge); + if (bPressed) bChecked = !bChecked; + } + + void CheckBox::Draw(olc::PixelGameEngine* pge) + { + if (!bVisible) + return; + + Button::Draw(pge); + + if (bChecked) + pge->DrawRect(vPos + olc::vf2d(2, 2), vSize - olc::vi2d(4, 4), m_manager.colBorder); + } + + void CheckBox::DrawDecal(olc::PixelGameEngine* pge) + { + if (!bVisible) + return; + + Button::DrawDecal(pge); + + pge->SetDecalMode(olc::DecalMode::WIREFRAME); + pge->FillRectDecal(vPos + olc::vf2d(2,2), vSize - olc::vf2d(4, 4), m_manager.colBorder); + pge->SetDecalMode(olc::DecalMode::NORMAL); + + olc::vf2d vText = pge->GetTextSizeProp(sText); + pge->DrawStringPropDecal(vPos + (vSize - vText) * 0.5f, sText, m_manager.colText); + } +#pragma endregion + +#pragma region Slider + Slider::Slider(olc::QuickGUI::Manager& manager, const olc::vf2d& posmin, const olc::vf2d& posmax, const float valmin, const float valmax, const float value) + : BaseControl(manager) + { + vPosMin = posmin; vPosMax = posmax; fMin = valmin; fMax = valmax; fValue = value; + } + + void Slider::Update(olc::PixelGameEngine* pge) + { + if (m_state == State::Disabled || !bVisible) + return; + + float fElapsedTime = pge->GetElapsedTime(); + + olc::vf2d vMouse = pge->GetMousePos(); + bHeld = false; + if (m_state == State::Click) + { + olc::vf2d d = vPosMax - vPosMin; + float u = d.dot(vMouse - vPosMin) / d.mag2(); + fValue = u * (fMax - fMin) + fMin; + bHeld = true; + } + else + { + olc::vf2d vSliderPos = vPosMin + (vPosMax - vPosMin) * ((fValue - fMin) / (fMax - fMin)); + if ((vMouse - vSliderPos).mag2() <= int32_t(fGrabRad) * int32_t(fGrabRad)) + { + m_fTransition += fElapsedTime * m_manager.fHoverSpeedOn; + m_state = State::Hover; + if (pge->GetMouse(olc::Mouse::LEFT).bPressed) + { + m_state = State::Click; + bPressed = true; + } + } + else + m_state = State::Normal; + } + + if (pge->GetMouse(olc::Mouse::LEFT).bReleased) + { + m_state = State::Normal; + bReleased = true; + } + + if (m_state == State::Normal) + { + m_fTransition -= fElapsedTime * m_manager.fHoverSpeedOff; + m_state = State::Normal; + bHeld = false; + } + + fValue = std::clamp(fValue, fMin, fMax); + m_fTransition = std::clamp(m_fTransition, 0.0f, 1.0f); + } + + void Slider::Draw(olc::PixelGameEngine* pge) + { + if (!bVisible) + return; + + pge->DrawLine(vPosMin, vPosMax, m_manager.colBorder); + olc::vf2d vSliderPos = vPosMin + (vPosMax - vPosMin) * ((fValue - fMin) / (fMax - fMin)); + + switch (m_state) + { + case State::Disabled: + pge->FillCircle(vSliderPos, int32_t(fGrabRad), m_manager.colDisable); + break; + case State::Normal: + case State::Hover: + pge->FillCircle(vSliderPos, int32_t(fGrabRad), olc::PixelLerp(m_manager.colNormal, m_manager.colHover, m_fTransition)); + break; + case State::Click: + pge->FillCircle(vSliderPos, int32_t(fGrabRad), m_manager.colClick); + break; + } + + + pge->DrawCircle(vSliderPos, int32_t(fGrabRad), m_manager.colBorder); + } + + void Slider::DrawDecal(olc::PixelGameEngine* pge) + { + if (!bVisible) + return; + + pge->DrawLineDecal(vPosMin, vPosMax, m_manager.colBorder); + olc::vf2d vSliderPos = vPosMin + (vPosMax - vPosMin) * ((fValue - fMin) / (fMax - fMin)); + + switch (m_state) + { + case State::Disabled: + pge->FillRectDecal(vSliderPos - olc::vf2d(fGrabRad, fGrabRad), olc::vf2d(fGrabRad, fGrabRad) * 2.0f, m_manager.colDisable); + break; + case State::Normal: + case State::Hover: + pge->FillRectDecal(vSliderPos - olc::vf2d(fGrabRad, fGrabRad), olc::vf2d(fGrabRad, fGrabRad) * 2.0f, olc::PixelLerp(m_manager.colNormal, m_manager.colHover, m_fTransition)); + break; + case State::Click: + pge->FillRectDecal(vSliderPos - olc::vf2d(fGrabRad, fGrabRad), olc::vf2d(fGrabRad, fGrabRad) * 2.0f, m_manager.colClick); + break; + } + + pge->SetDecalMode(olc::DecalMode::WIREFRAME); + pge->FillRectDecal(vSliderPos - olc::vf2d(fGrabRad, fGrabRad), olc::vf2d(fGrabRad, fGrabRad) * 2.0f, m_manager.colBorder); + pge->SetDecalMode(olc::DecalMode::NORMAL); + } + + +#pragma endregion + +} +#endif // OLC_PGEX_QUICKGUI +#endif // OLC_PGEX_QUICKGUI_H \ No newline at end of file diff --git a/extensions/olcPGEX_SplashScreen.h b/extensions/olcPGEX_SplashScreen.h new file mode 100644 index 0000000..2759970 --- /dev/null +++ b/extensions/olcPGEX_SplashScreen.h @@ -0,0 +1,220 @@ +/* + olcPGEX_SplashScreen.h + + +-------------------------------------------------------------+ + | OneLoneCoder Pixel Game Engine Extension | + | Splash Screen v1.0 | + +-------------------------------------------------------------+ + + NOTE: UNDER ACTIVE DEVELOPMENT - THERE ARE BUGS/GLITCHES + + What is this? + ~~~~~~~~~~~~~ + This extension produces an animated splashscreen and copyright notice + at the beginning of a PGE application, for the purposes of remaining + OLC-3 compliant should it be ambiguous in your deployment. + + License (OLC-3) + ~~~~~~~~~~~~~~~ + + Copyright 2018 - 2022 OneLoneCoder.com + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions or derivations of source code must retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions or derivative works in binary form must reproduce + the above copyright notice. This list of conditions and the following + disclaimer must be reproduced in the documentation and/or other + materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Links + ~~~~~ + YouTube: https://www.youtube.com/javidx9 + Discord: https://discord.gg/WhwHUMV + Twitter: https://www.twitter.com/javidx9 + Twitch: https://www.twitch.tv/javidx9 + GitHub: https://www.github.com/onelonecoder + Homepage: https://www.onelonecoder.com + + Author + ~~~~~~ + David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021, 2022 + + Revisions: + 1.00: Initial Release +*/ + +#pragma once + +#include "olcPixelGameEngine.h" + +namespace olc +{ + class SplashScreen : public olc::PGEX + { + public: + SplashScreen(); + + protected: + virtual void OnAfterUserCreate() override; + virtual bool OnBeforeUserUpdate(float& fElapsedTime) override; + + private: + olc::Renderable spr; + std::vector> vBoom; + olc::vf2d vScale; + olc::vf2d vPosition; + float fParticleTime = 0.0f; + float fAspect = 0.0f; + bool bComplete = false; + }; + + +} + +#ifdef OLC_PGEX_SPLASHSCREEN +#undef OLC_PGEX_SPLASHSCREEN + +namespace olc +{ + SplashScreen::SplashScreen() : olc::PGEX(true) + { + } + + void SplashScreen::OnAfterUserCreate() + { + const char logo[] = + "000000000000000000000000000000000000000000000000000000000000000000005" + "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED1EE" + "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED5EEE" + "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE@E@000" + "0000000000000000000000000000000000000000000000000000000000001E1D:ZZZZ" + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ1D5BZZZZZZ" + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ5@E:P0002Z0" + "02ZZX000000000000ZP0000000000000000000000000000ZX000Z002XE1DX?o`o:Poo" + "800SooaE5@E1ED5BX?ol5E@E0E1ED?oo5@E1ED5DE1D5E@ZQEEBPEE2QD5BSooclZ?olQ" + "AB?oo5DEEDEEDE:SooaEEAE5DEEDoolEADEEDEAE5AEEBZ5EE:5EE:5@E:?oo?bXoob55" + "8o3lEAEEAD5ADZ?oo5@E5EEAD5Cl01E5AD5AE5DE5@E:X01DXEEDXE1DXo3lo:Sl0800S" + "ooaE1ED5EE5BXo00EEDEEE5EE?oo5EE5EE5DEEDEEDZQEEBQD5BQD5BSl?cl0?`0ZZZ?o" + "o5D5E@EEDE03loaEEAEEDEEDoolEED5EDEAEEAEEBZ5EE:5@E:5@E:?oo?oloob008o00" + "EAEEAD01EE?co5EE5EEAD03l01DE@05AE5AE5@0:XE000EEDXE1DXooloocoo8DDSlZQE" + "5EE5EE5EDoolE1DE4E5EE?oo5AE5EE5DE5DEEDZQEEAAEEBQD5BPoo3oo3olQAB?bZ5DE" + "1D5EDEE@ooaD5AD1D5EDoolE1DEE@EAD5@EEBZ5EE51ED:5@E:P000000020080:X0000" + "00000000000000000000000000000000000:X0000002XE1DZZZZZZZZZZZZZZZZZZZZZ" + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZQD5@ZZZZZZZZZZZZZZZZZZZZZZ" + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZX5@E@00000000000000000000000" + "00000000000000000000000000000000000000001E1EEEEEEEEEEEEEEEEEEEEEEEEEE" + "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED5EEEEEEEEEEEEEEEEEEEEEEEEEEE" + "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE@5EEEEEEEEEEEEEEEEEEEEEEEEEEEE" + "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED0000000000000000000000000000000" + "0000000000000000000000000000000000000"; + + spr.Create(203, 24); + int px = 0, py = 0; + for (size_t b = 0; b < 1624; b += 4) + { + uint32_t sym1 = (uint32_t)logo[b + 0] - 48; + uint32_t sym2 = (uint32_t)logo[b + 1] - 48; + uint32_t sym3 = (uint32_t)logo[b + 2] - 48; + uint32_t sym4 = (uint32_t)logo[b + 3] - 48; + uint32_t r = sym1 << 18 | sym2 << 12 | sym3 << 6 | sym4; + + for (int i = 0; i < 12; i++) + { + olc::Pixel p = olc::RED; + switch ((r & 0xC00000) >> 22) + { + case 0: p = olc::Pixel(0, 0, 0, 255); break; + case 1: p = olc::Pixel(255, 255, 255, 255); break; + case 2: p = olc::Pixel(255, 120, 26, 255); break; + case 3: p = olc::Pixel(79, 193, 255, 255); break; + } + spr.Sprite()->SetPixel(px, py, p); + if (++px == 203) { py++; px = 0; } + r <<= 2; + } + } + + spr.Decal()->Update(); + vBoom.resize(spr.Sprite()->width * spr.Sprite()->height); + vScale = { float(pge->ScreenWidth()) / 500.0f, float(pge->ScreenWidth()) / 500.0f }; + fAspect = float(pge->ScreenWidth()) / float(pge->ScreenHeight()); + vPosition = olc::vf2d( + (250 - spr.Sprite()->width) / 2.0f, + (250 - spr.Sprite()->height) / 2.0f / fAspect); + for (int y = 0; y < spr.Sprite()->height; y++) + for (int x = 0; x < spr.Sprite()->width; x++) + vBoom[y * spr.Sprite()->width + x] = std::make_pair( + vPosition + olc::vf2d(x, y), + olc::vf2d( + (float(rand()) / float(RAND_MAX)) * 10.0f - 5.0f, + (float(rand()) / float(RAND_MAX)) * 10.0f - 5.0f) + ); + } + + bool SplashScreen::OnBeforeUserUpdate(float& fElapsedTime) + { + if (bComplete) return false; + + fParticleTime += fElapsedTime; + + for (int y = 0; y < spr.Sprite()->height; y++) + for (int x = 0; x < spr.Sprite()->width; x++) + { + + + if (fParticleTime < 1.0f) + { + + } + else if (fParticleTime < 2.0f) + { + vBoom[y * spr.Sprite()->width + x].first = + olc::vf2d( + (250 - spr.Sprite()->width) / 2.0f + float(x), + (250 - spr.Sprite()->height) / 2.0f / fAspect + float(y) + ) + + olc::vf2d( + (float(rand()) / float(RAND_MAX)) * 0.5f - 0.25f, + (float(rand()) / float(RAND_MAX)) * 0.5f - 0.25f); + } + else if(fParticleTime < 5.0f) + { + vBoom[y * spr.Sprite()->width + x].first += vBoom[y * spr.Sprite()->width + x].second * fElapsedTime * 20.0f; + } + else + { + bComplete = true; + } + + pge->DrawPartialDecal(vScale * vBoom[y * spr.Sprite()->width + x].first * 2.0f, spr.Decal(), olc::vf2d(x, y), { 1, 1 }, vScale * 2.0f, olc::PixelF(1.0f, 1.0f, 1.0f, std::min(1.0f, std::max(4.0f - fParticleTime, 0.0f)))); + } + + olc::vi2d vSize = pge->GetTextSizeProp("Copyright OneLoneCoder.com 2022"); + pge->DrawStringPropDecal(olc::vf2d(float(pge->ScreenWidth()/2) - vSize.x/2, float(pge->ScreenHeight()) - vSize.y * 3.0f), "Copyright OneLoneCoder.com 2022", olc::PixelF(1.0f, 1.0f, 1.0f, 0.5f), olc::vf2d(1.0, 2.0f)); + return true; + } + +} + +#endif \ No newline at end of file diff --git a/extensions/olcPGEX_Wireframe.h b/extensions/olcPGEX_Wireframe.h new file mode 100644 index 0000000..cd4f843 --- /dev/null +++ b/extensions/olcPGEX_Wireframe.h @@ -0,0 +1,287 @@ +/* + olcPGEX_Wireframe.h + + +-------------------------------------------------------------+ + | OneLoneCoder Pixel Game Engine Extension | + | Wireframe v1.0 | + +-------------------------------------------------------------+ + + NOTE: UNDER ACTIVE DEVELOPMENT - THERE ARE BUGS/GLITCHES + + What is this? + ~~~~~~~~~~~~~ + This extension provides drawing routines giving simple wireframe + shapes and models constructed in a transform hierachy + + License (OLC-3) + ~~~~~~~~~~~~~~~ + + Copyright 2018 - 2022 OneLoneCoder.com + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions or derivations of source code must retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions or derivative works in binary form must reproduce + the above copyright notice. This list of conditions and the following + disclaimer must be reproduced in the documentation and/or other + materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Links + ~~~~~ + YouTube: https://www.youtube.com/javidx9 + Discord: https://discord.gg/WhwHUMV + Twitter: https://www.twitter.com/javidx9 + Twitch: https://www.twitch.tv/javidx9 + GitHub: https://www.github.com/onelonecoder + Homepage: https://www.onelonecoder.com + + Author + ~~~~~~ + David Barr, aka javidx9, ŠOneLoneCoder 2019, 2020, 2021, 2022 + + Revisions: + 1.00: Initial Release + +*/ + +#pragma once +#ifndef OLC_PGEX_WIREFRAME_H +#define OLC_PGEX_WIREFRAME_H + +#include "olcPixelGameEngine.h" + +namespace olc +{ +#ifndef OLC_MAT3_DESC +#define OLC_MAT3_DESC + template + struct mat3_generic + { + std::array m{ 0 }; + constexpr size_t idx(size_t r, size_t c) const { return r * 3 + c; } + T& operator()(size_t row, size_t col) { return m[idx(row, col)]; } + const T& operator()(size_t row, size_t col) const { return m[idx(row, col)]; } + mat3_generic() { identity(); } + mat3_generic(const mat3_generic& m) = default; + mat3_generic& operator=(const mat3_generic& m) = default; + + void clear() { std::fill(m.begin(), m.end(), T(0)); } + void identity() { clear(); (*this)(0, 0) = 1; (*this)(1, 1) = 1; (*this)(2, 2) = 1; } + + void translate(float x, float y) { identity(); auto& m = (*this); m(2, 0) = x; m(2, 1) = y; } + void translate(const olc::v2d_generic& v) { translate(v.x, v.y); } + void scale(float x, float y) { identity(); auto& m = (*this); m(0, 0) = x; m(1, 1) = y; } + void scale(const olc::v2d_generic& v) { return scale(v.x, v.y); } + void rotate(float a) { identity(); auto& m = (*this); m(0, 0) = cos(a); m(0, 1) = sin(a); m(1, 0) = -m(0, 1); m(1, 1) = m(0, 0); } + + olc::v2d_generic operator * (const olc::v2d_generic& v) const + { + auto& m = *this; + olc::v2d_generic vOut; + vOut.x = m(0, 0) * v.x + m(1, 0) * v.y + m(2, 0) * T(1); + vOut.y = m(0, 1) * v.x + m(1, 1) * v.y + m(2, 1) * T(1); + T z = m(0, 2) * v.x + m(1, 2) * v.y + m(2, 2) * T(1); + return (vOut / z); + } + + mat3_generic operator * (const mat3_generic& rhs) const + { + auto& m = *this; + mat3_generic out; + for (size_t c = 0; c < 3; c++) + for (size_t r = 0; r < 3; r++) + out(r, c) = m(r, 0) * rhs(0, c) + m(r, 1) * rhs(1, c) + m(r, 2) * rhs(2, c); + return out; + } + }; + + typedef mat3_generic Matrix2D; +#endif + + namespace wire + { + typedef std::vector Mesh; + //Mesh NullMesh; + + class Model + { + public: + static constexpr uint8_t DRAW_ORIGIN = 0x01; + static constexpr uint8_t DRAW_NODES = 0x02; + static constexpr uint8_t DRAW_MEASURES = 0x04; + public: + Model() = default; + + public: + void Attach(Model* child, const olc::vf2d& position = { 0.0f, 0.0f }, const float angle = 0.0f); + void SetRotation(const float angle); + void SetPosition(const olc::vf2d& position); + void UpdateInWorld(const Matrix2D& matParent); + olc::vf2d LocalToWorld(const olc::vf2d& local); + void SetMesh(const Mesh& mesh); + const Mesh& GetWorldPoints() const; + const std::vector& GetChildren() const; + + protected: + Mesh vLocalPoints;; + Mesh vWorldPoints; + olc::Matrix2D matLocalTranslation; + olc::Matrix2D matLocalRotation; + olc::Matrix2D matLocal; + olc::Matrix2D matWorld; + + protected: + std::vector vChildren; + }; + + + + inline const Mesh MeshCircle(const float fRadius, const int nPoints = 100) + { + Mesh m; + for (int i = 0; i < nPoints; i++) + { + float fTheta = (float(i) / float(nPoints)) * 2.0f * 3.14159f; + m.push_back(olc::vf2d{ cos(fTheta), sin(fTheta) } *fRadius); + } + return m; + } + + inline const Mesh MeshRectangle(const olc::vf2d& size, const olc::vf2d& offset = { 0.0f, 0.0f }) + { + return { -offset, {-offset.x + size.x, -offset.y}, -offset + size, {-offset.x, -offset.y + size.y} }; + } + + inline const Mesh MeshGear(const int nTeeth, const float fOuterRadius, const float fInnerRadius) + { + Mesh m; + for (int i = 0; i < nTeeth * 4; i++) + { + float fTheta = (float(i) / float(nTeeth * 4)) * 2.0f * 3.14159f; + m.push_back(olc::vf2d{ cos(fTheta), sin(fTheta) } * 2.0f * (float((i / 2) % 2) ? fOuterRadius : fInnerRadius)); + } + return m; + } + + template + void DrawModel(T& render, Model& m, const olc::Pixel col = olc::BLACK, const uint8_t flags = -1) + { + const auto& points = m.GetWorldPoints(); + for(size_t i = 0; i < points.size(); i++) + render.DrawLine(points[i], points[(i+1)%points.size()], col); + + // Draw Nodes + if (flags & Model::DRAW_NODES) + for (size_t i = 0; i < points.size(); i++) + render.FillCircle(points[i], render.ScaleToWorld({ 3,3 }).x, olc::RED); + + if (flags & Model::DRAW_ORIGIN) + { + render.FillCircle(m.LocalToWorld({ 0,0 }), render.ScaleToWorld({ 3,3 }).x, olc::BLUE); + render.DrawLine( + m.LocalToWorld({ 0,0 }), + m.LocalToWorld(render.ScaleToWorld({ 10, 0 })), + olc::BLUE); + } + + // Draw Children + for (auto& child : m.GetChildren()) + DrawModel(render, *child, col, flags); + } + + + } +} + +#ifdef OLC_PGEX_WIREFRAME +#undef OLC_PGEX_WIREFRAME + +namespace olc +{ + namespace wire + { + void Model::SetMesh(const Mesh& mesh) + { + vLocalPoints = mesh; + vWorldPoints.clear(); + vWorldPoints.resize(vLocalPoints.size()); + } + + void Model::SetRotation(const float angle) + { + matLocalRotation.rotate(angle); + matLocal = matLocalRotation * matLocalTranslation; + } + + void Model::SetPosition(const olc::vf2d& position) + { + matLocalTranslation.translate(position); + matLocal = matLocalRotation * matLocalTranslation; + } + + void Model::Attach(Model* child, const olc::vf2d& position, const float angle) + { + if (child != nullptr) + { + child->SetPosition(position); + child->SetRotation(angle); + vChildren.push_back(child); + } + } + + olc::vf2d Model::LocalToWorld(const olc::vf2d& local) + { + return matWorld * local; + } + + const Mesh& Model::GetWorldPoints() const + { + return vWorldPoints; + } + + const std::vector& Model::GetChildren() const + { + return vChildren; + } + + void Model::UpdateInWorld(const Matrix2D& matParent) + { + // Propagate matrix transform + matWorld = matLocal * matParent; + + // Transform vertices + for (size_t i = 0; i < vLocalPoints.size(); i++) + { + vWorldPoints[i] = matWorld * vLocalPoints[i]; + } + + // Transform Children + for (auto& child : vChildren) + child->UpdateInWorld(matWorld); + } + } +} + +#endif // OLC_PGEX_WIREFRAME +#endif // OLC_PGEX_WIREFRAME_H + diff --git a/tools/wasm/README.md b/tools/wasm/README.md new file mode 100644 index 0000000..3678e88 --- /dev/null +++ b/tools/wasm/README.md @@ -0,0 +1 @@ +Coming Soon, information on using olc::PixelGameEngine in web browsers diff --git a/WASM/basic_template.html b/tools/wasm/basic_template.html similarity index 97% rename from WASM/basic_template.html rename to tools/wasm/basic_template.html index 1b2f8dd..e15b7ab 100644 --- a/WASM/basic_template.html +++ b/tools/wasm/basic_template.html @@ -1,77 +1,77 @@ - - - - - - - - Emscripten-Generated Code - - - - - - - - - - - - + + + + + + + + Emscripten-Generated Code + + + + + + + + + + + + diff --git a/WASM/pge2wasm.bat b/tools/wasm/pge2wasm.bat similarity index 95% rename from WASM/pge2wasm.bat rename to tools/wasm/pge2wasm.bat index 6b77424..74ed561 100644 --- a/WASM/pge2wasm.bat +++ b/tools/wasm/pge2wasm.bat @@ -1,108 +1,108 @@ -@echo off -:: Convenience Utility to build projects using olc::PixelGameEngine, using -:: Emscripten, producing WASM based output. -:: -:: OneLoneCoder.com 2021 - Released under OLC-3 license -:: -:: v1.00: Initial Release - -setlocal enabledelayedexpansion enableextensions - -:: Customize here =========================================== - -:: Location of Emscripten SDK -set EMSDK="e:\pge_ems\emsdk\" - -:: Location of olc::PixelGameEngine header file -set OLCPGE=".\" -set OLCPGE="e:\pge_dev\olcPixelGameEngine_dev\Deploy" - -:: ========================================================== - -set WORKINGDIR=%CD% - -if not exist %EMSDK% ( - echo Error: No Emscripten SDK folder found! - goto :fail -) - -if not exist %OLCPGE% ( - echo Error: Invalid PGE Location! - goto :fail -) - -if "%1"=="build" goto :build -if "%1"=="run" goto :run -if "%1"=="clean" goto :clean -goto :error - -:build - :: Configure path variables - cd %EMSDK% - call emsdk_env.bat - - :: Create working folder - cd %WORKINGDIR% - if not exist ".\WASM" ( - echo Creating .\WASM output folder - mkdir ".\WASM" - ) - - :: Grab all cpp files if no specific file is given - if "%~2"=="" goto :graball - set CPP=%~2 - goto :embuild - -:graball - echo Gathering *.cpp files from - echo %CD% - set CPP= - for %%x in (%CD%\*.cpp) do set CPP=!CPP! %%x - set CPP=%CPP:~1% - -:embuild - -echo %CPP% - if exist "./assets" ( - echo Starting Build with assets... - call em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_LIBPNG=1 %CPP% -o .\WASM\pge.html -I %OLCPGE% --preload-file .\assets - ) else ( - echo Starting Build without assets... - call em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_LIBPNG=1 %CPP% -o .\WASM\pge.html -I %OLCPGE% - ) - - echo Build Completed - goto :success - -:run - :: Configure path variables - cd %EMSDK% - call emsdk_env.bat - cd %WORKINGDIR% - emrun .\WASM\pge.html - goto :success - -:clean - if exist ".\WASM" ( - rmdir /s /q .\WASM - ) - goto :success - -:error - echo Error: Incorrect Input - goto :fail - -:success - echo Exit With Success - goto :leave - -:fail - echo Exit with Failure - goto :leave - -:leave - exit - - - - +@echo off +:: Convenience Utility to build projects using olc::PixelGameEngine, using +:: Emscripten, producing WASM based output. +:: +:: OneLoneCoder.com 2021 - Released under OLC-3 license +:: +:: v1.00: Initial Release + +setlocal enabledelayedexpansion enableextensions + +:: Customize here =========================================== + +:: Location of Emscripten SDK +set EMSDK="e:\pge_ems\emsdk\" + +:: Location of olc::PixelGameEngine header file +set OLCPGE=".\" +set OLCPGE="e:\pge_dev\olcPixelGameEngine_dev\Deploy" + +:: ========================================================== + +set WORKINGDIR=%CD% + +if not exist %EMSDK% ( + echo Error: No Emscripten SDK folder found! + goto :fail +) + +if not exist %OLCPGE% ( + echo Error: Invalid PGE Location! + goto :fail +) + +if "%1"=="build" goto :build +if "%1"=="run" goto :run +if "%1"=="clean" goto :clean +goto :error + +:build + :: Configure path variables + cd %EMSDK% + call emsdk_env.bat + + :: Create working folder + cd %WORKINGDIR% + if not exist ".\WASM" ( + echo Creating .\WASM output folder + mkdir ".\WASM" + ) + + :: Grab all cpp files if no specific file is given + if "%~2"=="" goto :graball + set CPP=%~2 + goto :embuild + +:graball + echo Gathering *.cpp files from + echo %CD% + set CPP= + for %%x in (%CD%\*.cpp) do set CPP=!CPP! %%x + set CPP=%CPP:~1% + +:embuild + +echo %CPP% + if exist "./assets" ( + echo Starting Build with assets... + call em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_LIBPNG=1 %CPP% -o .\WASM\pge.html -I %OLCPGE% --preload-file .\assets + ) else ( + echo Starting Build without assets... + call em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_LIBPNG=1 %CPP% -o .\WASM\pge.html -I %OLCPGE% + ) + + echo Build Completed + goto :success + +:run + :: Configure path variables + cd %EMSDK% + call emsdk_env.bat + cd %WORKINGDIR% + emrun .\WASM\pge.html + goto :success + +:clean + if exist ".\WASM" ( + rmdir /s /q .\WASM + ) + goto :success + +:error + echo Error: Incorrect Input + goto :fail + +:success + echo Exit With Success + goto :leave + +:fail + echo Exit with Failure + goto :leave + +:leave + exit + + + + diff --git a/utilities/coming_soon.txt b/utilities/coming_soon.txt new file mode 100644 index 0000000..e69de29