diff --git a/C++/scripts/build.sh b/C++/scripts/build.sh index bbdb7f6..0088e5b 100755 --- a/C++/scripts/build.sh +++ b/C++/scripts/build.sh @@ -1,4 +1,4 @@ -#Compiles the entire program then runs it, producing an executable. If the "test" argument is included, will try and run tests too (in the test folder) +#Compiles the entire program then runs it, producing an executable. If the "test" argument is included, will try and run tests too (in the test folder). If the "full" argument is included, it will recopmile the PixelGameEngine (should it change) #C++ printf "Running program...\n\n\n" output=$(dpkg -l | grep libx11-dev) @@ -6,16 +6,28 @@ if [[ -z $output ]] then sudo apt install libx11-dev libpulse-dev mesa-common-dev libpng-dev fi +if [ ! -f "pixelGameEngine.o" ] +then + printf "Pixel Game Engine compile object missing. Compiling for the first time..." + g++ -c pixelGameEngine.cpp +fi if [ "$1" = "test" ] then printf "Running tests...\n" echo "#define TEST_SUITE" > ./test/test.h - if g++ $(find . -type f -name "*.cpp") ${CUSTOM_PARAMS} -o ${PROJECT_NAME}; then + if g++ $(find . -type f -name "*.cpp" -not -name "pixelGameEngine.cpp") pixelGameEngine.o ${CUSTOM_PARAMS} -o ${PROJECT_NAME}; then + ./${PROJECT_NAME} "$@" + fi +elif [ "$1" = "full" ] +then + echo "" > ./test/test.h + g++ -c pixelGameEngine.cpp + if g++ $(find . -type f -name "*.cpp" -not -path "./test/*" -not -name "pixelGameEngine.cpp") pixelGameEngine.o ${CUSTOM_PARAMS} -o ${PROJECT_NAME}; then ./${PROJECT_NAME} "$@" fi else echo "" > ./test/test.h - if g++ $(find . -type f -name "*.cpp" -not -path "./test/*") ${CUSTOM_PARAMS} -o ${PROJECT_NAME}; then + if g++ $(find . -type f -name "*.cpp" -not -path "./test/*" -not -name "pixelGameEngine.cpp") pixelGameEngine.o ${CUSTOM_PARAMS} -o ${PROJECT_NAME}; then ./${PROJECT_NAME} "$@" fi fi diff --git a/C++/scripts/md5 b/C++/scripts/md5 index 45f0dae..a8438a6 100644 --- a/C++/scripts/md5 +++ b/C++/scripts/md5 @@ -1,7 +1,7 @@ -build.sh:d5e4e98a6f677aa0a9759ba0afb2fb77 - +build.sh:f7da5b6f54c56658f5410e0df797b5a7 - commit.sh:d03a46e721060c22ccb146e19d27e70a - debug.sh:849488515cab075948653c15eec4177b - lines.sh:3b907786f7fc9204025993016c9080de - -release.sh:6a96fb84ba64ed60d31be436ec069f05 - +release.sh:0ab321c3fa2f1a1b2f03b1aec3bce816 - temp:d41d8cd98f00b204e9800998ecf8427e - -web.sh:b982212b88b80a59ad607b47d2ff3e94 - +web.sh:e317e1d492d00517a0ac0e460239daa0 - diff --git a/C++/scripts/release.sh b/C++/scripts/release.sh index 2f84395..c1a95a6 100755 --- a/C++/scripts/release.sh +++ b/C++/scripts/release.sh @@ -1,4 +1,4 @@ -#Creates a release build that focuses on high runtime performance. +#Creates a release build that focuses on high runtime performance. Use "full" argument to completely rebuild PGE. #C++ printf "Running program...\n\n\n" output=$(dpkg -l | grep libx11-dev) @@ -6,7 +6,15 @@ if [[ -z $output ]] then sudo apt install libx11-dev libpulse-dev mesa-common-dev libpng-dev fi -if g++ $(find . -type f -name "*.cpp" -not -path "./test/*") ${CUSTOM_PARAMS} -O3 -s -DNDEBUG -o ${PROJECT_NAME}; then +if [ "$1" == "full" ]; then + rm "pixelGameEngine.o" +fi +if [ ! -f "pixelGameEngine.o" ] +then + printf "Pixel Game Engine compile object missing. Compiling for the first time..." + g++ -c pixelGameEngine.cpp +fi +if g++ $(find . -type f -name "*.cpp" -not -path "./test/*" -not -name "pixelGameEngine.cpp") pixelGameEngine.o ${CUSTOM_PARAMS} -o ${PROJECT_NAME}; then ./${PROJECT_NAME} "$@" fi printf "\n\n" diff --git a/C++/scripts/web.sh b/C++/scripts/web.sh index c46d605..2ae0a7c 100755 --- a/C++/scripts/web.sh +++ b/C++/scripts/web.sh @@ -1,23 +1,30 @@ -#Compiles emscripten instance of this project for the web. +#Compiles emscripten instance of this project for the web. Use "full" argument if your PGE has to be completely rebuilt. Use "headless" argument for a headless version. #C++ output=$(dpkg -l | grep libx11-dev) if [[ -z $output ]] then sudo apt install libx11-dev libpulse-dev mesa-common-dev libpng-dev fi +if [[ "$1" == "full" || "$2" == "full" ]]; then + rm "pixelGameEngine_wasm.o" +fi +if [ ! -f "pixelGameEngine_wasm.o" ] +then + printf "Pixel Game Engine compile object missing. Compiling for the first time..." + em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 -c pixelGameEngine.cpp -o pixelGameEngine_wasm.o +fi if [ -d "assets" ]; then - em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 $(find . -type f -name "*.cpp" -not -path "./test/*") -o ${PROJECT_NAME}.html -I pixelGameEngine.h --preload-file ./assets + em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 $(find . -type f -name "*.cpp" -not -path "./test/*" -not -name "pixelGameEngine.cpp") pixelGameEngine_wasm.o -o ${PROJECT_NAME}.html --preload-file ./assets else - em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 $(find . -type f -name "*.cpp" -not -path "./test/*") -o ${PROJECT_NAME}.html -I pixelGameEngine.h + em++ -std=c++17 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 $(find . -type f -name "*.cpp" -not -path "./test/*" -not -name "pixelGameEngine.cpp") pixelGameEngine_wasm.o -o ${PROJECT_NAME}.html fi cp buildtemplate.html ${PROJECT_NAME}.html sed -i "s/_REPLACEME_/$PROJECT_NAME.js/" ${PROJECT_NAME}.html -if [ "$1" == "headless" ]; then +if [[ "$1" == "headless" || "$2" == "headless" ]]; then echo "Running as headless web server" emrun --no_browser ${PROJECT_NAME}.html else emrun --serve_after_close ${PROJECT_NAME}.html -fi - +fi \ No newline at end of file diff --git a/C++ProjectTemplate b/C++ProjectTemplate index 4135a10..d02c258 100755 Binary files a/C++ProjectTemplate and b/C++ProjectTemplate differ diff --git a/Meteos.h b/Meteos.h index a14b312..c6c87d0 100644 --- a/Meteos.h +++ b/Meteos.h @@ -4,6 +4,7 @@ #include "Board.h" #include #include "ComboOverlay.h" +#include "Star.h" class Meteos : public olc::PixelGameEngine{ public: @@ -28,6 +29,7 @@ class Meteos : public olc::PixelGameEngine{ bool gameCanRun=true; std::map SPRITES; std::vectorcomboDisplayList; + std::vectorstarField; int score=0; int displayTargetScore=0; //While technically the displayed score should be what the score actually is, if we're showing how many points we earn for a combo we want to delay adding it to our actual score display for flair and show a side bonus counter. int displayScore=0; @@ -46,5 +48,6 @@ class Meteos : public olc::PixelGameEngine{ void handleWarningLevels(float fElapsedTime); void validateSelectedBlock(); void handleComboAnimations(); + void updateScoreDisplay(float fElapsedTime); }; #endif \ No newline at end of file diff --git a/Star.cpp b/Star.cpp new file mode 100644 index 0000000..3256eaa --- /dev/null +++ b/Star.cpp @@ -0,0 +1,29 @@ +#include "pixelGameEngine.h" +#include "Meteos.h" + +extern Meteos*game; + +void Star::Update(){ + pos+=spd; + if (pos.x<0){ + pos.x+=game->ScreenWidth(); + } + if (pos.x>game->ScreenWidth()){ + pos.x-=game->ScreenWidth(); + } + if (pos.y<0){ + pos.y+=game->ScreenHeight(); + } + if (pos.y>game->ScreenHeight()){ + pos.y-=game->ScreenHeight(); + } + + if (flickerTimer++>=flickerRate){ + flickerTimer=0; + brightness={redDistribution(game->gen),greenDistribution(game->gen),blueDistribution(game->gen)}; + } +}; + +void Star::Draw(){ + game->FillRectDecal(pos,size,brightness); +}; \ No newline at end of file diff --git a/Star.h b/Star.h new file mode 100644 index 0000000..2f62d24 --- /dev/null +++ b/Star.h @@ -0,0 +1,23 @@ +#include "pixelGameEngine.h" +#include + +class Star{ + vf2d pos; + vf2d spd; + vf2d size={1,1}; + Pixel minBrightness; + Pixel maxBrightness; + Pixel brightness=minBrightness; + int flickerRate=10; //Number of frames between each flicker. + int flickerTimer=0; + std::uniform_int_distributionredDistribution,greenDistribution,blueDistribution; + public: + Star(vf2d pos,vf2d spd,Pixel minBrightness,Pixel maxBrightness) + :pos(pos),spd(spd),minBrightness(minBrightness),maxBrightness(maxBrightness){ + redDistribution=std::uniform_int_distribution(minBrightness.r,maxBrightness.r); + greenDistribution=std::uniform_int_distribution(minBrightness.g,maxBrightness.g); + blueDistribution=std::uniform_int_distribution(minBrightness.b,maxBrightness.b); + } + void Update(); + void Draw(); +}; \ No newline at end of file diff --git a/main.cpp b/main.cpp index cc6a32d..4d82f2c 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,3 @@ -#define OLC_PGE_APPLICATION -#include "pixelGameEngine.h" #include #include "gameDefines.h" #include @@ -889,14 +887,7 @@ void Meteos::handleComboAnimations(){ } } -void Meteos::updateGame(float fElapsedTime){ - spawnBlocks(fElapsedTime); - handleBlockGravity(fElapsedTime); - matchBlocks(); - cleanupBlocks(); - handleWarningLevels(fElapsedTime); - validateSelectedBlock(); - handleComboAnimations(); +void Meteos::updateScoreDisplay(float fElapsedTime){ if (blocksInAttackQueue){ lastBlockLaunched+=fElapsedTime; if (lastBlockLaunched>=blockLaunchWaitPeriod){ @@ -941,8 +932,25 @@ void Meteos::updateGame(float fElapsedTime){ } } +void Meteos::updateGame(float fElapsedTime){ + spawnBlocks(fElapsedTime); + handleBlockGravity(fElapsedTime); + matchBlocks(); + cleanupBlocks(); + handleWarningLevels(fElapsedTime); + validateSelectedBlock(); + handleComboAnimations(); + updateScoreDisplay(fElapsedTime); + for (Star s:starField){ + s.Update(); + } +} + void Meteos::drawGame(float fElapsedTime,bool debugView){ - Clear(Pixel(32,32,255)); + Clear(VERY_DARK_BLUE); + for (Star s:starField){ + s.Draw(); + } for (int x=-1;x<=gameBoard.boardSize.x;x++){ for (int y=0;y<=gameBoard.boardSize.y;y++){ if (x==-1||x==10||y==14){ diff --git a/pixelGameEngine.cpp b/pixelGameEngine.cpp new file mode 100644 index 0000000..35c8ee7 --- /dev/null +++ b/pixelGameEngine.cpp @@ -0,0 +1,3 @@ +#define OLC_PGE_HEADLESS +#define OLC_PGE_APPLICATION +#include "pixelGameEngine.h" \ No newline at end of file diff --git a/pixelGameEngine.h b/pixelGameEngine.h index 76f1c27..6a0d01e 100644 --- a/pixelGameEngine.h +++ b/pixelGameEngine.h @@ -3,7 +3,7 @@ olcPixelGameEngine.h +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine v2.20 | + | OneLoneCoder Pixel Game Engine v2.21 | | "What do you need? Pixels... Lots of Pixels..." - javidx9 | +-------------------------------------------------------------+ @@ -197,7 +197,7 @@ Author ~~~~~~ - David Barr, aka javidx9, �OneLoneCoder 2018, 2019, 2020, 2021, 2022 + David Barr, aka javidx9, OneLoneCoder 2018, 2019, 2020, 2021, 2022 */ #pragma endregion @@ -303,12 +303,19 @@ 2.20: +DrawRectDecal() - Keeps OneSketchyGuy quiet +GetScreenSize() +olc::Sprite::Size() - returns size of sprite in vector format + 2.21: Emscripten Overhaul - Thanks Moros! + +DrawPolygonDecal() tint overload, can now tint a polygon accounting for vertex colours + +Multiplicative Pixel overload + +v2d_generic clamp() + +v2d_generic lerp() + +GetDroppedFiles() - returns files dropped onto engine window for that frame (MSW only) + +GetDroppedFilesPoint() - returns location of dropped files (MSW only) + +Exposed OpenGL33 Loader interface so the typedefs can be shared with PGEX & user + +Fix OGL33 DecalStructure types - wow, how did that one get missed?? lol + +FillTexturedTriangle() - Software rasterizes a textured, coloured, triangle + +FillTexturedPolygon() - Hijacks DecalStructure for configuration + +olc::vf2d arguments for Sprite::Sample() functions - SIG Updates: - The following additions are included in Sig's version of the PGE header (this is a sig version) - +GetAnyKey() - Returns when a key is activated - +GetAnyKeyPress() - Returns when a key is pressed down (and if a keyboard key, which key it was) - !! Apple Platforms will not see these updates immediately - Sorry, I dont have a mac to test... !! !! Volunteers willing to help appreciated, though PRs are manually integrated with credit !! */ @@ -387,7 +394,7 @@ int main() #include #pragma endregion -#define PGE_VER 220 +#define PGE_VER 221 // O------------------------------------------------------------------------------O // | COMPILER CONFIGURATION ODDITIES | @@ -433,8 +440,16 @@ int main() // | PLATFORM SELECTION CODE, Thanks slavka! | // O------------------------------------------------------------------------------O +#if defined(OLC_PGE_HEADLESS) + #define OLC_PLATFORM_HEADLESS + #define OLC_GFX_HEADLESS + #if !defined(OLC_IMAGE_STB) && !defined(OLC_IMAGE_GDI) && !defined(OLC_IMAGE_LIBPNG) + #define OLC_IMAGE_HEADLESS + #endif +#endif + // Platform -#if !defined(OLC_PLATFORM_WINAPI) && !defined(OLC_PLATFORM_X11) && !defined(OLC_PLATFORM_GLUT) && !defined(OLC_PLATFORM_EMSCRIPTEN) +#if !defined(OLC_PLATFORM_WINAPI) && !defined(OLC_PLATFORM_X11) && !defined(OLC_PLATFORM_GLUT) && !defined(OLC_PLATFORM_EMSCRIPTEN) && !defined(OLC_PLATFORM_HEADLESS) #if !defined(OLC_PLATFORM_CUSTOM_EX) #if defined(_WIN32) #define OLC_PLATFORM_WINAPI @@ -457,8 +472,10 @@ int main() #define PGE_USE_CUSTOM_START #endif + + // Renderer -#if !defined(OLC_GFX_OPENGL10) && !defined(OLC_GFX_OPENGL33) && !defined(OLC_GFX_DIRECTX10) +#if !defined(OLC_GFX_OPENGL10) && !defined(OLC_GFX_OPENGL33) && !defined(OLC_GFX_DIRECTX10) && !defined(OLC_GFX_HEADLESS) #if !defined(OLC_GFX_CUSTOM_EX) #if defined(OLC_PLATFORM_EMSCRIPTEN) #define OLC_GFX_OPENGL33 @@ -469,7 +486,7 @@ int main() #endif // Image loader -#if !defined(OLC_IMAGE_STB) && !defined(OLC_IMAGE_GDI) && !defined(OLC_IMAGE_LIBPNG) +#if !defined(OLC_IMAGE_STB) && !defined(OLC_IMAGE_GDI) && !defined(OLC_IMAGE_LIBPNG) && !defined(OLC_IMAGE_HEADLESS) #if !defined(OLC_IMAGE_CUSTOM_EX) #if defined(_WIN32) #define OLC_IMAGE_GDI @@ -527,6 +544,15 @@ int main() #endif #endif #endif + +#if defined(OLC_PGE_HEADLESS) +#if defined max +#undef max +#endif +#if defined min +#undef min +#endif +#endif #pragma endregion // O------------------------------------------------------------------------------O @@ -543,6 +569,7 @@ namespace olc constexpr uint8_t nDefaultAlpha = 0xFF; constexpr uint32_t nDefaultPixel = (nDefaultAlpha << 24); constexpr uint8_t nTabSizeInSpaces = 4; + constexpr size_t OLC_MAX_VERTS = 128; enum rcode { FAIL = 0, OK = 1, NO_FILE = -1 }; // O------------------------------------------------------------------------------O @@ -572,6 +599,8 @@ namespace olc Pixel operator - (const Pixel& p) const; Pixel& operator +=(const Pixel& p); Pixel& operator -=(const Pixel& p); + Pixel operator * (const Pixel& p) const; + Pixel& operator *=(const Pixel& p); Pixel inv() const; }; @@ -653,6 +682,8 @@ namespace olc v2d_generic min(const v2d_generic& v) const { return v2d_generic(std::min(x, v.x), std::min(y, v.y)); } v2d_generic cart() { return { std::cos(y) * x, std::sin(y) * x }; } v2d_generic polar() { return { mag(), std::atan2(y, x) }; } + v2d_generic clamp(const v2d_generic& v1, const v2d_generic& v2) const { return this->max(v1)->min(v2); } + v2d_generic lerp(const v2d_generic& v1, const double t) { return this->operator*(T(1.0 - t)) + (v1 * T(t)); } T dot(const v2d_generic& rhs) const { return this->x * rhs.x + this->y * rhs.y; } T cross(const v2d_generic& rhs) const { return this->x * rhs.y - this->y * rhs.x; } v2d_generic operator + (const v2d_generic& rhs) const { return v2d_generic(this->x + rhs.x, this->y + rhs.y); } @@ -776,7 +807,9 @@ namespace olc Pixel GetPixel(const olc::vi2d& a) const; bool SetPixel(const olc::vi2d& a, Pixel p); Pixel Sample(float x, float y) const; + Pixel Sample(const olc::vf2d& uv) const; Pixel SampleBL(float u, float v) const; + Pixel SampleBL(const olc::vf2d& uv) const; Pixel* GetData(); olc::Sprite* Duplicate(); olc::Sprite* Duplicate(const olc::vi2d& vPos, const olc::vi2d& vSize); @@ -938,14 +971,13 @@ namespace olc virtual bool OnUserUpdate(float fElapsedTime); // Called once on application termination, so you can be one clean coder virtual bool OnUserDestroy(); - virtual void GetAnyKey(); - virtual void GetAnyKeyPress(olc::Key pressedKey); // Called when a text entry is confirmed with "enter" key virtual void OnTextEntryComplete(const std::string& sText); // Called when a console command is executed virtual bool OnConsoleCommand(const std::string& sCommand); + public: // Hardware Interfaces // Returns true if window is currently in focus bool IsFocused() const; @@ -994,6 +1026,9 @@ namespace olc const olc::vi2d& GetScreenPixelSize() const; // Gets "screen" size const olc::vi2d& GetScreenSize() const; + // Gets any files dropped this frame + const std::vector& GetDroppedFiles() const; + const olc::vi2d& GetDroppedFilesPoint() const; public: // CONFIGURATION ROUTINES // Layer targeting functions @@ -1047,6 +1082,9 @@ namespace olc // 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); void FillTriangle(const olc::vi2d& pos1, const olc::vi2d& pos2, const olc::vi2d& pos3, Pixel p = olc::WHITE); + // Fill a textured and coloured triangle + void FillTexturedTriangle(const std::vector& vPoints, std::vector vTex, std::vector vColour, olc::Sprite* sprTex); + void FillTexturedPolygon(const std::vector& vPoints, const std::vector& vTex, const std::vector& vColour, olc::Sprite* sprTex, olc::DecalStructure structure = olc::DecalStructure::LIST); // Draws an entire sprite at location (x,y) void DrawSprite(int32_t x, int32_t y, Sprite* sprite, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE); void DrawSprite(const olc::vi2d& pos, Sprite* sprite, uint32_t scale = 1, uint8_t flip = olc::Sprite::NONE); @@ -1096,7 +1134,7 @@ namespace olc void DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const olc::Pixel tint = olc::WHITE); void DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& depth, const std::vector& uv, const olc::Pixel tint = olc::WHITE); void DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const std::vector& tint); - + void DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const std::vector& colours, const olc::Pixel tint); // Draws a line in Decal Space void DrawLineDecal(const olc::vf2d& pos1, const olc::vf2d& pos2, Pixel p = olc::WHITE); void DrawRotatedStringDecal(const olc::vf2d& pos, const std::string& sText, const float fAngle, const olc::vf2d& center = { 0.0f, 0.0f }, const olc::Pixel col = olc::WHITE, const olc::vf2d& scale = { 1.0f, 1.0f }); @@ -1199,6 +1237,10 @@ namespace olc std::function funcPixelMode; std::chrono::time_point m_tp1, m_tp2; std::vector vFontSpacing; + std::vector vDroppedFiles; + std::vector vDroppedFilesCache; + olc::vi2d vDroppedFilesPoint; + olc::vi2d vDroppedFilesPointCache; // Command Console Specific bool bConsoleShow = false; @@ -1253,6 +1295,7 @@ namespace olc void olc_UpdateMouseFocus(bool state); void olc_UpdateKeyFocus(bool state); void olc_Terminate(); + void olc_DropFiles(int32_t x, int32_t y, const std::vector& vFiles); void olc_Reanimate(); bool olc_IsRunning(); @@ -1296,6 +1339,100 @@ namespace olc #pragma endregion + +#pragma region opengl33_iface +// In order to facilitate more advanced graphics features, some PGEX +// will rely on shaders. Instead of having each PGEX responsible for +// managing this, for convenience, this interface exists. + +#if defined(OLC_GFX_OPENGL33) + + #if defined(OLC_PLATFORM_WINAPI) + #include + #define CALLSTYLE __stdcall + #endif + + #if defined(__linux__) || defined(__FreeBSD__) + #include + #endif + + #if defined(OLC_PLATFORM_X11) + namespace X11 + {#include } + #define CALLSTYLE + #endif + + #if defined(__APPLE__) + #define GL_SILENCE_DEPRECATION + #include + #include + #include + #endif + + #if defined(OLC_PLATFORM_EMSCRIPTEN) + #include + #include + #define GL_GLEXT_PROTOTYPES + #include + #include + #define CALLSTYLE + #define GL_CLAMP GL_CLAMP_TO_EDGE + #endif + +namespace olc +{ + typedef char GLchar; + typedef ptrdiff_t GLsizeiptr; + + typedef GLuint CALLSTYLE locCreateShader_t(GLenum type); + typedef GLuint CALLSTYLE locCreateProgram_t(void); + typedef void CALLSTYLE locDeleteShader_t(GLuint shader); + typedef void CALLSTYLE locCompileShader_t(GLuint shader); + typedef void CALLSTYLE locLinkProgram_t(GLuint program); + typedef void CALLSTYLE locDeleteProgram_t(GLuint program); + typedef void CALLSTYLE locAttachShader_t(GLuint program, GLuint shader); + typedef void CALLSTYLE locBindBuffer_t(GLenum target, GLuint buffer); + typedef void CALLSTYLE locBufferData_t(GLenum target, GLsizeiptr size, const void* data, GLenum usage); + typedef void CALLSTYLE locGenBuffers_t(GLsizei n, GLuint* buffers); + typedef void CALLSTYLE locVertexAttribPointer_t(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); + typedef void CALLSTYLE locEnableVertexAttribArray_t(GLuint index); + typedef void CALLSTYLE locUseProgram_t(GLuint program); + typedef void CALLSTYLE locBindVertexArray_t(GLuint array); + typedef void CALLSTYLE locGenVertexArrays_t(GLsizei n, GLuint* arrays); + typedef void CALLSTYLE locGetShaderInfoLog_t(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); + typedef GLint CALLSTYLE locGetUniformLocation_t(GLuint program, const GLchar* name); + typedef void CALLSTYLE locUniform1f_t(GLint location, GLfloat v0); + typedef void CALLSTYLE locUniform1i_t(GLint location, GLint v0); + typedef void CALLSTYLE locUniform2fv_t(GLint location, GLsizei count, const GLfloat* value); + typedef void CALLSTYLE locActiveTexture_t(GLenum texture); + typedef void CALLSTYLE locGenFrameBuffers_t(GLsizei n, GLuint* ids); + typedef void CALLSTYLE locBindFrameBuffer_t(GLenum target, GLuint fb); + typedef GLenum CALLSTYLE locCheckFrameBufferStatus_t(GLenum target); + typedef void CALLSTYLE locDeleteFrameBuffers_t(GLsizei n, const GLuint* fbs); + typedef void CALLSTYLE locFrameBufferTexture2D_t(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + typedef void CALLSTYLE locDrawBuffers_t(GLsizei n, const GLenum* bufs); + typedef void CALLSTYLE locBlendFuncSeparate_t(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); + +#if defined(OLC_PLATFORM_WINAPI) + typedef void __stdcall locSwapInterval_t(GLsizei n); +#endif + +#if defined(OLC_PLATFORM_X11) + typedef int(locSwapInterval_t)(X11::Display* dpy, X11::GLXDrawable drawable, int interval); +#endif + +#if defined(OLC_PLATFORM_EMSCRIPTEN) + typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length); + typedef EGLBoolean(locSwapInterval_t)(EGLDisplay display, EGLint interval); +#else + typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar** string, const GLint* length); +#endif + +} // olc namespace +#endif // OpenGL33 Definitions +#pragma endregion + + #endif // OLC_PGE_DEF @@ -1394,6 +1531,24 @@ namespace olc return *this; } + Pixel Pixel::operator * (const Pixel& p) const + { + uint8_t nR = uint8_t(std::min(255.0f, std::max(0.0f, float(r) * float(p.r) / 255.0f))); + uint8_t nG = uint8_t(std::min(255.0f, std::max(0.0f, float(g) * float(p.g) / 255.0f))); + uint8_t nB = uint8_t(std::min(255.0f, std::max(0.0f, float(b) * float(p.b) / 255.0f))); + uint8_t nA = uint8_t(std::min(255.0f, std::max(0.0f, float(a) * float(p.a) / 255.0f))); + return Pixel(nR, nG, nB, nA); + } + + Pixel& Pixel::operator *=(const Pixel& p) + { + this->r = uint8_t(std::min(255.0f, std::max(0.0f, float(r) * float(p.r) / 255.0f))); + this->g = uint8_t(std::min(255.0f, std::max(0.0f, float(g) * float(p.g) / 255.0f))); + this->b = uint8_t(std::min(255.0f, std::max(0.0f, float(b) * float(p.b) / 255.0f))); + this->a = uint8_t(std::min(255.0f, std::max(0.0f, float(a) * float(p.a) / 255.0f))); + return *this; + } + Pixel Pixel::inv() const { uint8_t nR = uint8_t(std::min(255, std::max(0, 255 - int(r)))); @@ -1472,6 +1627,11 @@ namespace olc return GetPixel(sx, sy); } + Pixel Sprite::Sample(const olc::vf2d& uv) const + { + return Sample(uv.x, uv.y); + } + Pixel Sprite::SampleBL(float u, float v) const { u = u * width - 0.5f; @@ -1494,6 +1654,11 @@ namespace olc (uint8_t)((p1.b * u_opposite + p2.b * u_ratio) * v_opposite + (p3.b * u_opposite + p4.b * u_ratio) * v_ratio)); } + Pixel Sprite::SampleBL(const olc::vf2d& uv) const + { + return SampleBL(uv.x, uv.y); + } + Pixel* Sprite::GetData() { return pColData.data(); } @@ -2411,6 +2576,168 @@ namespace olc } } + void PixelGameEngine::FillTexturedTriangle(const std::vector& vPoints, std::vector vTex, std::vector vColour, olc::Sprite* sprTex) + { + olc::vi2d p1 = vPoints[0]; + olc::vi2d p2 = vPoints[1]; + olc::vi2d p3 = vPoints[2]; + + if (p2.y < p1.y){std::swap(p1.y, p2.y); std::swap(p1.x, p2.x); std::swap(vTex[0].x, vTex[1].x); std::swap(vTex[0].y, vTex[1].y); std::swap(vColour[0], vColour[1]);} + if (p3.y < p1.y){std::swap(p1.y, p3.y); std::swap(p1.x, p3.x); std::swap(vTex[0].x, vTex[2].x); std::swap(vTex[0].y, vTex[2].y); std::swap(vColour[0], vColour[2]);} + if (p3.y < p2.y){std::swap(p2.y, p3.y); std::swap(p2.x, p3.x); std::swap(vTex[1].x, vTex[2].x); std::swap(vTex[1].y, vTex[2].y); std::swap(vColour[1], vColour[2]);} + + olc::vi2d dPos1 = p2 - p1; + olc::vf2d dTex1 = vTex[1] - vTex[0]; + int dcr1 = vColour[1].r - vColour[0].r; + int dcg1 = vColour[1].g - vColour[0].g; + int dcb1 = vColour[1].b - vColour[0].b; + int dca1 = vColour[1].a - vColour[0].a; + + olc::vi2d dPos2 = p3 - p1; + olc::vf2d dTex2 = vTex[2] - vTex[0]; + int dcr2 = vColour[2].r - vColour[0].r; + int dcg2 = vColour[2].g - vColour[0].g; + int dcb2 = vColour[2].b - vColour[0].b; + int dca2 = vColour[2].a - vColour[0].a; + + float dax_step = 0, dbx_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; + olc::vf2d vTex1Step, vTex2Step; + + if (dPos1.y) + { + dax_step = dPos1.x / (float)abs(dPos1.y); + vTex1Step = dTex1 / (float)abs(dPos1.y); + dcr1_step = dcr1 / (float)abs(dPos1.y); + dcg1_step = dcg1 / (float)abs(dPos1.y); + dcb1_step = dcb1 / (float)abs(dPos1.y); + dca1_step = dca1 / (float)abs(dPos1.y); + } + + if (dPos2.y) + { + dbx_step = dPos2.x / (float)abs(dPos2.y); + vTex2Step = dTex2 / (float)abs(dPos2.y); + dcr2_step = dcr2 / (float)abs(dPos2.y); + dcg2_step = dcg2 / (float)abs(dPos2.y); + dcb2_step = dcb2 / (float)abs(dPos2.y); + dca2_step = dca2 / (float)abs(dPos2.y); + } + + olc::vi2d vStart; + olc::vi2d vEnd; + int vStartIdx; + + for (int pass = 0; pass < 2; pass++) + { + if (pass == 0) + { + vStart = p1; vEnd = p2; vStartIdx = 0; + } + else + { + dPos1 = p3 - p2; + dTex1 = vTex[2] - vTex[1]; + dcr1 = vColour[2].r - vColour[1].r; + dcg1 = vColour[2].g - vColour[1].g; + dcb1 = vColour[2].b - vColour[1].b; + dca1 = vColour[2].a - vColour[1].a; + dcr1_step = 0; dcg1_step = 0; dcb1_step = 0; dca1_step = 0; + + if (dPos2.y) dbx_step = dPos2.x / (float)abs(dPos2.y); + if (dPos1.y) + { + dax_step = dPos1.x / (float)abs(dPos1.y); + vTex1Step = dTex1 / (float)abs(dPos1.y); + dcr1_step = dcr1 / (float)abs(dPos1.y); + dcg1_step = dcg1 / (float)abs(dPos1.y); + dcb1_step = dcb1 / (float)abs(dPos1.y); + dca1_step = dca1 / (float)abs(dPos1.y); + } + + vStart = p2; vEnd = p3; vStartIdx = 1; + } + + if (dPos1.y) + { + for (int i = vStart.y; i <= vEnd.y; i++) + { + int ax = int(vStart.x + (float)(i - vStart.y) * dax_step); + int bx = int(p1.x + (float)(i - p1.y) * dbx_step); + + olc::vf2d tex_s(vTex[vStartIdx].x + (float)(i - vStart.y) * vTex1Step.x, vTex[vStartIdx].y + (float)(i - vStart.y) * vTex1Step.y); + olc::vf2d tex_e(vTex[0].x + (float)(i - p1.y) * vTex2Step.x, vTex[0].y + (float)(i - p1.y) * vTex2Step.y); + + olc::Pixel col_s(vColour[vStartIdx].r + uint8_t((float)(i - vStart.y) * dcr1_step), vColour[vStartIdx].g + uint8_t((float)(i - vStart.y) * dcg1_step), + vColour[vStartIdx].b + uint8_t((float)(i - vStart.y) * dcb1_step), vColour[vStartIdx].a + uint8_t((float)(i - vStart.y) * dca1_step)); + + olc::Pixel col_e(vColour[0].r + uint8_t((float)(i - p1.y) * dcr2_step), vColour[0].g + uint8_t((float)(i - p1.y) * dcg2_step), + vColour[0].b + uint8_t((float)(i - p1.y) * dcb2_step), vColour[0].a + uint8_t((float)(i - p1.y) * dca2_step)); + + if (ax > bx) { std::swap(ax, bx); std::swap(tex_s, tex_e); std::swap(col_s, col_e); } + + float tstep = 1.0f / ((float)(bx - ax)); + float t = 0.0f; + + for (int j = ax; j < bx; j++) + { + olc::Pixel pixel = PixelLerp(col_s, col_e, t); + if (sprTex != nullptr) pixel *= sprTex->Sample(tex_s.lerp(tex_e, t)); + Draw(j, i, pixel); + t += tstep; + } + } + } + } + } + + void PixelGameEngine::FillTexturedPolygon(const std::vector& vPoints, const std::vector& vTex, const std::vector& vColour, olc::Sprite* sprTex, olc::DecalStructure structure) + { + if (structure == olc::DecalStructure::LINE) + { + return; // Meaningless, so do nothing + } + + if (vPoints.size() < 3 || vTex.size() < 3 || vColour.size() < 3) + return; + + if (structure == olc::DecalStructure::LIST) + { + for (int tri = 0; tri < vPoints.size() / 3; tri++) + { + std::vector vP = { vPoints[tri * 3 + 0], vPoints[tri * 3 + 1], vPoints[tri * 3 + 2] }; + std::vector vT = { vTex[tri * 3 + 0], vTex[tri * 3 + 1], vTex[tri * 3 + 2] }; + std::vector vC = { vColour[tri * 3 + 0], vColour[tri * 3 + 1], vColour[tri * 3 + 2] }; + FillTexturedTriangle(vP, vT, vC, sprTex); + } + return; + } + + if (structure == olc::DecalStructure::STRIP) + { + for (int tri = 2; tri < vPoints.size(); tri++) + { + std::vector vP = { vPoints[tri - 2], vPoints[tri-1], vPoints[tri] }; + std::vector vT = { vTex[tri - 2], vTex[tri - 1], vTex[tri] }; + std::vector vC = { vColour[tri - 2], vColour[tri - 1], vColour[tri] }; + FillTexturedTriangle(vP, vT, vC, sprTex); + } + return; + } + + if (structure == olc::DecalStructure::FAN) + { + for (int tri = 2; tri < vPoints.size(); tri++) + { + std::vector vP = { vPoints[0], vPoints[tri - 1], vPoints[tri] }; + std::vector vT = { vTex[0], vTex[tri - 1], vTex[tri] }; + std::vector vC = { vColour[0], vColour[tri - 1], vColour[tri] }; + FillTexturedTriangle(vP, vT, vC, sprTex); + } + return; + } + } + + void PixelGameEngine::DrawSprite(const olc::vi2d& pos, Sprite* sprite, uint32_t scale, uint8_t flip) { DrawSprite(pos.x, pos.y, sprite, scale, flip); } @@ -2642,6 +2969,15 @@ namespace olc vLayers[nTargetLayer].vecDecalInstance.push_back(di); } + void PixelGameEngine::DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& uv, const std::vector& colours, const olc::Pixel tint) + { + std::vector newColours(colours.size(), olc::WHITE); + std::transform(colours.begin(), colours.end(), newColours.begin(), + [&tint](const olc::Pixel pin) { return pin * tint; }); + DrawPolygonDecal(decal, pos, uv, newColours); + } + + void PixelGameEngine::DrawPolygonDecal(olc::Decal* decal, const std::vector& pos, const std::vector& depth, const std::vector& uv, const olc::Pixel tint) { DecalInstance di; @@ -3217,6 +3553,12 @@ namespace olc } + const std::vector& PixelGameEngine::GetDroppedFiles() const + { return vDroppedFiles; } + + const olc::vi2d& PixelGameEngine::GetDroppedFilesPoint() const + { return vDroppedFilesPoint; } + void PixelGameEngine::TextEntryEnable(const bool bEnable, const std::string& sText) { @@ -3332,13 +3674,9 @@ namespace olc bool PixelGameEngine::OnUserDestroy() { return true; } - void PixelGameEngine::GetAnyKey(){}; - void PixelGameEngine::GetAnyKeyPress(olc::Key pressedKey){}; - void PixelGameEngine::OnTextEntryComplete(const std::string& sText) { UNUSED(sText); } bool PixelGameEngine::OnConsoleCommand(const std::string& sCommand) { UNUSED(sCommand); return false; } - // Externalised API void PixelGameEngine::olc_UpdateViewport() { @@ -3404,6 +3742,19 @@ namespace olc void PixelGameEngine::olc_UpdateKeyFocus(bool state) { bHasInputFocus = state; } + void PixelGameEngine::olc_DropFiles(int32_t x, int32_t y, const std::vector& vFiles) + { + x -= vViewPos.x; + y -= vViewPos.y; + vDroppedFilesPointCache.x = (int32_t)(((float)x / (float)(vWindowSize.x - (vViewPos.x * 2)) * (float)vScreenSize.x)); + vDroppedFilesPointCache.y = (int32_t)(((float)y / (float)(vWindowSize.y - (vViewPos.y * 2)) * (float)vScreenSize.y)); + if (vDroppedFilesPointCache.x >= (int32_t)vScreenSize.x) vDroppedFilesPointCache.x = vScreenSize.x - 1; + if (vDroppedFilesPointCache.y >= (int32_t)vScreenSize.y) vDroppedFilesPointCache.y = vScreenSize.y - 1; + if (vDroppedFilesPointCache.x < 0) vDroppedFilesPointCache.x = 0; + if (vDroppedFilesPointCache.y < 0) vDroppedFilesPointCache.y = 0; + vDroppedFilesCache = vFiles; + } + void PixelGameEngine::olc_Reanimate() { bAtomActive = true; } @@ -3480,10 +3831,8 @@ namespace olc platform->HandleSystemEvent(); // Compare hardware input states from previous frame - auto ScanHardware = [&](HWButton* pKeys, bool* pStateOld, bool* pStateNew, uint32_t nKeyCount,bool keyboard=true) + auto ScanHardware = [&](HWButton* pKeys, bool* pStateOld, bool* pStateNew, uint32_t nKeyCount) { - bool pressed=false; - int key; for (uint32_t i = 0; i < nKeyCount; i++) { pKeys[i].bPressed = false; @@ -3492,8 +3841,6 @@ namespace olc { if (pStateNew[i]) { - pressed=true; - key=i; pKeys[i].bPressed = !pKeys[i].bHeld; pKeys[i].bHeld = true; } @@ -3502,35 +3849,35 @@ namespace olc pKeys[i].bReleased = true; pKeys[i].bHeld = false; } - GetAnyKey(); } pStateOld[i] = pStateNew[i]; } - if (pressed) { - if (keyboard) {GetAnyKeyPress((olc::Key)key);} - else {GetAnyKeyPress(olc::Key::NONE);} - } }; ScanHardware(pKeyboardState, pKeyOldState, pKeyNewState, 256); - ScanHardware(pMouseState, pMouseOldState, pMouseNewState, nMouseButtons, false); + ScanHardware(pMouseState, pMouseOldState, pMouseNewState, nMouseButtons); // Cache mouse coordinates so they remain consistent during frame vMousePos = vMousePosCache; nMouseWheelDelta = nMouseWheelDeltaCache; nMouseWheelDeltaCache = 0; + vDroppedFiles = vDroppedFilesCache; + vDroppedFilesPoint = vDroppedFilesPointCache; + vDroppedFilesCache.clear(); + if (bTextEntryEnable) { UpdateTextEntry(); } // Handle Frame Update - bool bExtensionBlockFrame = false; + bool bExtensionBlockFrame = false; for (auto& ext : vExtensions) bExtensionBlockFrame |= ext->OnBeforeUserUpdate(fElapsedTime); if (!bExtensionBlockFrame) { if (!OnUserUpdate(fElapsedTime)) bAtomActive = false; + } for (auto& ext : vExtensions) ext->OnAfterUserUpdate(fElapsedTime); @@ -3540,6 +3887,8 @@ namespace olc UpdateConsole(); } + + // Display Frame renderer->UpdateViewport(vViewPos, vViewSize); renderer->ClearBuffer(olc::BLACK, true); @@ -3698,10 +4047,118 @@ namespace olc }; #pragma endregion + +#pragma region platform_headless +namespace olc +{ +#if defined(OLC_GFX_HEADLESS) + class Renderer_Headless : public olc::Renderer + { + public: + virtual void PrepareDevice() {}; + virtual olc::rcode CreateDevice(std::vector params, bool bFullScreen, bool bVSYNC) { return olc::rcode::OK; } + virtual olc::rcode DestroyDevice() { return olc::rcode::OK; } + virtual void DisplayFrame() {} + virtual void PrepareDrawing() {} + virtual void SetDecalMode(const olc::DecalMode& mode) {} + virtual void DrawLayerQuad(const olc::vf2d& offset, const olc::vf2d& scale, const olc::Pixel tint) {} + virtual void DrawDecal(const olc::DecalInstance& decal) {} + virtual uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered = false, const bool clamp = true) {return 1;}; + virtual void UpdateTexture(uint32_t id, olc::Sprite* spr) {} + virtual void ReadTexture(uint32_t id, olc::Sprite* spr) {} + virtual uint32_t DeleteTexture(const uint32_t id) {return 1;} + virtual void ApplyTexture(uint32_t id) {} + virtual void UpdateViewport(const olc::vi2d& pos, const olc::vi2d& size) {} + virtual void ClearBuffer(olc::Pixel p, bool bDepth) {} + }; +#endif +#if defined(OLC_PLATFORM_HEADLESS) + class Platform_Headless : public olc::Platform + { + public: + virtual olc::rcode ApplicationStartUp() { return olc::rcode::OK; } + virtual olc::rcode ApplicationCleanUp() { return olc::rcode::OK; } + virtual olc::rcode ThreadStartUp() { return olc::rcode::OK; } + virtual olc::rcode ThreadCleanUp() { return olc::rcode::OK; } + virtual olc::rcode CreateGraphics(bool bFullScreen, bool bEnableVSYNC, const olc::vi2d& vViewPos, const olc::vi2d& vViewSize) { return olc::rcode::OK; } + virtual olc::rcode CreateWindowPane(const olc::vi2d& vWindowPos, olc::vi2d& vWindowSize, bool bFullScreen) { return olc::rcode::OK; } + virtual olc::rcode SetWindowTitle(const std::string& s) { return olc::rcode::OK; } + virtual olc::rcode StartSystemEventLoop() { return olc::rcode::OK; } + virtual olc::rcode HandleSystemEvent() { return olc::rcode::OK; } + }; +#endif +} +#pragma endregion + // O------------------------------------------------------------------------------O // | olcPixelGameEngine Renderers - the draw-y bits | // O------------------------------------------------------------------------------O +#pragma region image_stb +// O------------------------------------------------------------------------------O +// | START IMAGE LOADER: stb_image.h, all systems, very fast | +// O------------------------------------------------------------------------------O +// Thanks to Sean Barrett - https://github.com/nothings/stb/blob/master/stb_image.h +// MIT License - Copyright(c) 2017 Sean Barrett + +// Note you need to download the above file into your project folder, and +// #define OLC_IMAGE_STB +// #define OLC_PGE_APPLICATION +// #include "olcPixelGameEngine.h" + +#if defined(OLC_IMAGE_STB) +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" +namespace olc +{ + class ImageLoader_STB : public olc::ImageLoader + { + public: + ImageLoader_STB() : ImageLoader() + {} + + olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) override + { + UNUSED(pack); + // clear out existing sprite + spr->pColData.clear(); + // Open file + stbi_uc* bytes = nullptr; + int w = 0, h = 0, cmp = 0; + if (pack != nullptr) + { + ResourceBuffer rb = pack->GetFileBuffer(sImageFile); + bytes = stbi_load_from_memory((unsigned char*)rb.vMemory.data(), rb.vMemory.size(), &w, &h, &cmp, 4); + } + else + { + // Check file exists + if (!_gfs::exists(sImageFile)) return olc::rcode::NO_FILE; + bytes = stbi_load(sImageFile.c_str(), &w, &h, &cmp, 4); + } + + if (!bytes) return olc::rcode::FAIL; + spr->width = w; spr->height = h; + spr->pColData.resize(spr->width * spr->height); + std::memcpy(spr->pColData.data(), bytes, spr->width * spr->height * 4); + delete[] bytes; + return olc::rcode::OK; + } + + olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) override + { + return olc::rcode::OK; + } + }; +} +#endif +// O------------------------------------------------------------------------------O +// | START IMAGE LOADER: stb_image.h | +// O------------------------------------------------------------------------------O +#pragma endregion + + + #if !defined(OLC_PGE_HEADLESS) #pragma region renderer_ogl10 @@ -4103,79 +4560,91 @@ namespace olc #if defined(OLC_PLATFORM_WINAPI) #include - #include + //#include #if !defined(__MINGW32__) #pragma comment(lib, "Dwmapi.lib") #endif - typedef void __stdcall locSwapInterval_t(GLsizei n); + //typedef void __stdcall locSwapInterval_t(GLsizei n); typedef HDC glDeviceContext_t; typedef HGLRC glRenderContext_t; - #define CALLSTYLE __stdcall + //#define CALLSTYLE __stdcall #define OGL_LOAD(t, n) (t*)wglGetProcAddress(#n) #endif - -#if defined(__linux__) || defined(__FreeBSD__) - #include -#endif +// +//#if defined(__linux__) || defined(__FreeBSD__) +// #include +//#endif #if defined(OLC_PLATFORM_X11) - namespace X11 + /*namespace X11 { #include } - typedef int(locSwapInterval_t)(X11::Display* dpy, X11::GLXDrawable drawable, int interval); + typedef int(locSwapInterval_t)(X11::Display* dpy, X11::GLXDrawable drawable, int interval);*/ typedef X11::GLXContext glDeviceContext_t; typedef X11::GLXContext glRenderContext_t; - #define CALLSTYLE + //#define CALLSTYLE #define OGL_LOAD(t, n) (t*)glXGetProcAddress((unsigned char*)#n); #endif -#if defined(__APPLE__) - #define GL_SILENCE_DEPRECATION - #include - #include - #include -#endif - -#if defined(OLC_PLATFORM_EMSCRIPTEN) - #include - #include - #define GL_GLEXT_PROTOTYPES - #include - #include - #define CALLSTYLE - typedef EGLBoolean(locSwapInterval_t)(EGLDisplay display, EGLint interval); - #define GL_CLAMP GL_CLAMP_TO_EDGE - #define OGL_LOAD(t, n) n; -#endif +//#if defined(__APPLE__) +// #define GL_SILENCE_DEPRECATION +// #include +// #include +// #include +//#endif + +//#if defined(OLC_PLATFORM_EMSCRIPTEN) +// #include +// #include +// #define GL_GLEXT_PROTOTYPES +// #include +// #include +// #define CALLSTYLE +// typedef EGLBoolean(locSwapInterval_t)(EGLDisplay display, EGLint interval); +// #define GL_CLAMP GL_CLAMP_TO_EDGE +// #define OGL_LOAD(t, n) n; +//#endif namespace olc { - typedef char GLchar; - typedef ptrdiff_t GLsizeiptr; - typedef GLuint CALLSTYLE locCreateShader_t(GLenum type); - typedef GLuint CALLSTYLE locCreateProgram_t(void); - typedef void CALLSTYLE locDeleteShader_t(GLuint shader); -#if defined(OLC_PLATFORM_EMSCRIPTEN) - typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length); -#else - typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar** string, const GLint* length); -#endif - typedef void CALLSTYLE locCompileShader_t(GLuint shader); - typedef void CALLSTYLE locLinkProgram_t(GLuint program); - typedef void CALLSTYLE locDeleteProgram_t(GLuint program); - typedef void CALLSTYLE locAttachShader_t(GLuint program, GLuint shader); - typedef void CALLSTYLE locBindBuffer_t(GLenum target, GLuint buffer); - typedef void CALLSTYLE locBufferData_t(GLenum target, GLsizeiptr size, const void* data, GLenum usage); - typedef void CALLSTYLE locGenBuffers_t(GLsizei n, GLuint* buffers); - typedef void CALLSTYLE locVertexAttribPointer_t(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); - typedef void CALLSTYLE locEnableVertexAttribArray_t(GLuint index); - typedef void CALLSTYLE locUseProgram_t(GLuint program); - typedef void CALLSTYLE locBindVertexArray_t(GLuint array); - typedef void CALLSTYLE locGenVertexArrays_t(GLsizei n, GLuint* arrays); - typedef void CALLSTYLE locGetShaderInfoLog_t(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); +// typedef char GLchar; +// typedef ptrdiff_t GLsizeiptr; +// typedef GLuint CALLSTYLE locCreateShader_t(GLenum type); +// typedef GLuint CALLSTYLE locCreateProgram_t(void); +// typedef void CALLSTYLE locDeleteShader_t(GLuint shader); +//#if defined(OLC_PLATFORM_EMSCRIPTEN) +// typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length); +//#else +// typedef void CALLSTYLE locShaderSource_t(GLuint shader, GLsizei count, const GLchar** string, const GLint* length); +//#endif +// typedef void CALLSTYLE locCompileShader_t(GLuint shader); +// typedef void CALLSTYLE locLinkProgram_t(GLuint program); +// typedef void CALLSTYLE locDeleteProgram_t(GLuint program); +// typedef void CALLSTYLE locAttachShader_t(GLuint program, GLuint shader); +// typedef void CALLSTYLE locBindBuffer_t(GLenum target, GLuint buffer); +// typedef void CALLSTYLE locBufferData_t(GLenum target, GLsizeiptr size, const void* data, GLenum usage); +// typedef void CALLSTYLE locGenBuffers_t(GLsizei n, GLuint* buffers); +// typedef void CALLSTYLE locVertexAttribPointer_t(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); +// typedef void CALLSTYLE locEnableVertexAttribArray_t(GLuint index); +// typedef void CALLSTYLE locUseProgram_t(GLuint program); +// typedef void CALLSTYLE locBindVertexArray_t(GLuint array); +// typedef void CALLSTYLE locGenVertexArrays_t(GLsizei n, GLuint* arrays); +// typedef void CALLSTYLE locGetShaderInfoLog_t(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); +// typedef GLint CALLSTYLE locGetUniformLocation_t(GLuint program, const GLchar* name); +// typedef void CALLSTYLE locUniform1f_t(GLint location, GLfloat v0); +// typedef void CALLSTYLE locUniform1i_t(GLint location, GLint v0); +// typedef void CALLSTYLE locUniform2fv_t(GLint location, GLsizei count, const GLfloat* value); +// typedef void CALLSTYLE locActiveTexture_t(GLenum texture); +// typedef void CALLSTYLE locGenFrameBuffers_t(GLsizei n, GLuint* ids); +// typedef void CALLSTYLE locBindFrameBuffer_t(GLenum target, GLuint fb); +// typedef GLenum CALLSTYLE locCheckFrameBufferStatus_t(GLenum target); +// typedef void CALLSTYLE locDeleteFrameBuffers_t(GLsizei n, const GLuint* fbs); +// typedef void CALLSTYLE locFrameBufferTexture2D_t(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +// typedef void CALLSTYLE locDrawBuffers_t(GLsizei n, const GLenum* bufs); +// typedef void CALLSTYLE locBlendFuncSeparate_t(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); - constexpr size_t OLC_MAX_VERTS = 128; + class Renderer_OGL33 : public olc::Renderer { @@ -4280,7 +4749,7 @@ namespace olc wglMakeCurrent(glDeviceContext, glRenderContext); // Set Vertical Sync - locSwapInterval = OGL_LOAD(locSwapInterval_t, "wglSwapIntervalEXT"); + locSwapInterval = OGL_LOAD(locSwapInterval_t, wglSwapIntervalEXT); if (locSwapInterval && !bVSYNC) locSwapInterval(0); bSync = bVSYNC; #endif @@ -4300,7 +4769,7 @@ namespace olc XGetWindowAttributes(olc_Display, *olc_Window, &gwa); glViewport(0, 0, gwa.width, gwa.height); - locSwapInterval = OGL_LOAD(locSwapInterval_t, "glXSwapIntervalEXT"); + locSwapInterval = OGL_LOAD(locSwapInterval_t, glXSwapIntervalEXT); if (locSwapInterval == nullptr && !bVSYNC) { @@ -4537,7 +5006,14 @@ namespace olc if (nDecalMode == DecalMode::WIREFRAME) glDrawArrays(GL_LINE_LOOP, 0, decal.points); else - glDrawArrays(GL_TRIANGLE_FAN, 0, decal.points); + { + if (decal.structure == olc::DecalStructure::FAN) + glDrawArrays(GL_TRIANGLE_FAN, 0, decal.points); + else if (decal.structure == olc::DecalStructure::STRIP) + glDrawArrays(GL_TRIANGLE_STRIP, 0, decal.points); + else if (decal.structure == olc::DecalStructure::LIST) + glDrawArrays(GL_TRIANGLES, 0, decal.points); + } } uint32_t CreateTexture(const uint32_t width, const uint32_t height, const bool filtered, const bool clamp) override @@ -4865,68 +5341,6 @@ namespace olc // O------------------------------------------------------------------------------O #pragma endregion -#pragma region image_stb -// O------------------------------------------------------------------------------O -// | START IMAGE LOADER: stb_image.h, all systems, very fast | -// O------------------------------------------------------------------------------O -// Thanks to Sean Barrett - https://github.com/nothings/stb/blob/master/stb_image.h -// MIT License - Copyright(c) 2017 Sean Barrett - -// Note you need to download the above file into your project folder, and -// #define OLC_IMAGE_STB -// #define OLC_PGE_APPLICATION -// #include "olcPixelGameEngine.h" - -#if defined(OLC_IMAGE_STB) -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" -namespace olc -{ - class ImageLoader_STB : public olc::ImageLoader - { - public: - ImageLoader_STB() : ImageLoader() - {} - - olc::rcode LoadImageResource(olc::Sprite* spr, const std::string& sImageFile, olc::ResourcePack* pack) override - { - UNUSED(pack); - // clear out existing sprite - spr->pColData.clear(); - // Open file - stbi_uc* bytes = nullptr; - int w = 0, h = 0, cmp = 0; - if (pack != nullptr) - { - ResourceBuffer rb = pack->GetFileBuffer(sImageFile); - bytes = stbi_load_from_memory((unsigned char*)rb.vMemory.data(), rb.vMemory.size(), &w, &h, &cmp, 4); - } - else - { - // Check file exists - if (!_gfs::exists(sImageFile)) return olc::rcode::NO_FILE; - bytes = stbi_load(sImageFile.c_str(), &w, &h, &cmp, 4); - } - - if (!bytes) return olc::rcode::FAIL; - spr->width = w; spr->height = h; - spr->pColData.resize(spr->width * spr->height); - std::memcpy(spr->pColData.data(), bytes, spr->width * spr->height * 4); - delete[] bytes; - return olc::rcode::OK; - } - - olc::rcode SaveImageResource(olc::Sprite* spr, const std::string& sImageFile) override - { - return olc::rcode::OK; - } - }; -} -#endif -// O------------------------------------------------------------------------------O -// | START IMAGE LOADER: stb_image.h | -// O------------------------------------------------------------------------------O -#pragma endregion // O------------------------------------------------------------------------------O // | olcPixelGameEngine Platforms | @@ -4968,6 +5382,8 @@ namespace olc return w; } + + public: virtual olc::rcode ApplicationStartUp() override { return olc::rcode::OK; } virtual olc::rcode ApplicationCleanUp() override { return olc::rcode::OK; } @@ -5034,6 +5450,8 @@ namespace olc olc_hWnd = CreateWindowEx(dwExStyle, olcT("OLC_PIXEL_GAME_ENGINE"), olcT(""), dwStyle, vTopLeft.x, vTopLeft.y, width, height, NULL, NULL, GetModuleHandle(nullptr), this); + DragAcceptFiles(olc_hWnd, true); + // 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; @@ -5131,6 +5549,44 @@ namespace olc case WM_RBUTTONUP: ptrPGE->olc_UpdateMouseState(1, false); return 0; case WM_MBUTTONDOWN:ptrPGE->olc_UpdateMouseState(2, true); return 0; case WM_MBUTTONUP: ptrPGE->olc_UpdateMouseState(2, false); return 0; + case WM_DROPFILES: + { + // This is all eww... + HDROP drop = (HDROP)wParam; + + uint32_t nFiles = DragQueryFile(drop, 0xFFFFFFFF, nullptr, 0); + std::vector vFiles; + for (uint32_t i = 0; i < nFiles; i++) + { + TCHAR dfbuffer[256]{}; + uint32_t len = DragQueryFile(drop, i, nullptr, 0); + DragQueryFile(drop, i, dfbuffer, 256); +#ifdef UNICODE + #ifdef __MINGW32__ + char* buffer = new char[len + 1]; + wcstombs(buffer, dfbuffer, len); + buffer[len] = '\0'; + #else + int count = WideCharToMultiByte(CP_UTF8, 0, dfbuffer, -1, NULL, 0, NULL, NULL); + char* buffer = new char[count]; + WideCharToMultiByte(CP_UTF8, 0, dfbuffer, -1, buffer, count, NULL, NULL); + #endif + vFiles.push_back(std::string(buffer)); + delete[] buffer; +#else + vFiles.push_back(std::string(dbuffer)); +#endif + } + + // Even more eww... + POINT p; DragQueryPoint(drop, &p); + ptrPGE->olc_DropFiles(p.x, p.y, vFiles); + DragFinish(drop); + return 0; + } + break; + + case WM_CLOSE: ptrPGE->olc_Terminate(); return 0; case WM_DESTROY: PostQuitMessage(0); DestroyWindow(hWnd); return 0; } @@ -5700,6 +6156,9 @@ namespace olc { #pragma endregion + + + #pragma region platform_emscripten // O------------------------------------------------------------------------------O // | START PLATFORM: Emscripten - Totally Game Changing... | @@ -5836,118 +6295,100 @@ namespace olc // the giant web baby. - // Fullscreen and Resize Observers EM_ASM({ - // cache for reuse - Module._olc_EmscriptenShellCss = "width: 100%; height: 70vh; margin-left: auto; margin-right: auto;"; + // olc_ApsectRatio + // + // Used by olc_ResizeHandler to calculate the viewport from the + // dimensions of the canvas container's element. + Module.olc_AspectRatio = $0 / $1; + + // HACK ALERT! + // + // Here we assume any html shell that uses 3 or more instance of the class "emscripten" + // is using one of the default or minimal emscripten page layouts + Module.olc_AssumeDefaultShells = (document.querySelectorAll('.emscripten').length >= 3) ? true : false; + + // olc_ResizeHandler + // + // Used by olc_Init, and is called when a resize observer and fullscreenchange event is triggered. + var olc_ResizeHandler = function() + { + // are we in fullscreen mode? + let isFullscreen = (document.fullscreenElement != null); - // width / height = aspect ratio - Module._olc_WindowAspectRatio = $0 / $1; - Module.canvas.parentNode.addEventListener("resize", function(e) { - - if (e.defaultPrevented) { e.stopPropagation(); return; } - var viewWidth = e.detail.width; - var viewHeight = e.detail.width / Module._olc_WindowAspectRatio; - if (viewHeight > e.detail.height) + // get the width of the containing element + let width = (isFullscreen || !Module.olc_AssumeDefaultShells) ? window.innerWidth : Module.canvas.parentNode.clientWidth; + let height = (isFullscreen || !Module.olc_AssumeDefaultShells) ? window.innerHeight : Module.canvas.parentNode.clientHeight; + + // calculate the expected viewport size + let viewWidth = width; + let viewHeight = width / Module.olc_AspectRatio; + + // if we're taller than the containing element, recalculate based on height + if(viewHeight > height) { - viewHeight = e.detail.height; - viewWidth = e.detail.height * Module._olc_WindowAspectRatio; - } - - if (Module.canvas.parentNode.className == 'emscripten_border') - Module.canvas.parentNode.style.cssText = Module._olc_EmscriptenShellCss + " width: " + viewWidth.toString() + "px; height: " + viewHeight.toString() + "px;"; - - Module.canvas.setAttribute("width", viewWidth); - Module.canvas.setAttribute("height", viewHeight); - - if (document.fullscreenElement != null) - { - var top = (e.detail.height - viewHeight) / 2; - var left = (e.detail.width - viewWidth) / 2; - Module.canvas.style.position = "fixed"; - Module.canvas.style.top = top.toString() + "px"; - Module.canvas.style.left = left.toString() + "px"; - Module.canvas.style.width = ""; - Module.canvas.style.height = ""; + viewWidth = height * Module.olc_AspectRatio; + viewHeight = height; } + + // ensure resulting viewport is in integer space + viewWidth = parseInt(viewWidth); + viewHeight = parseInt(viewHeight); - // trigger PGE update - Module._olc_PGE_UpdateWindowSize(viewWidth, viewHeight); - // this is really only needed when enter/exiting fullscreen - Module.canvas.focus(); - // prevent this event from ever affecting the document beyond this element - e.stopPropagation(); - }); - - // helper function to prevent repeating the same code everywhere - Module._olc_ResizeCanvas = function() - { - // yes, we still have to wait, sigh.. setTimeout(function() { - // if default template, stretch width as well - if (Module.canvas.parentNode.className == 'emscripten_border') - Module.canvas.parentNode.style.cssText = Module._olc_EmscriptenShellCss; - - // override it's styling so we can get it's stretched size - Module.canvas.style.cssText = "width: 100%; height: 100%; outline: none;"; - - // setup custom resize event - var resizeEvent = new CustomEvent('resize', - { - detail: { - width: Module.canvas.clientWidth, - height : Module.canvas.clientHeight - }, - bubbles : true, - cancelable : true - }); - - // trigger custom resize event on canvas element - Module.canvas.dispatchEvent(resizeEvent); - }, 50); + // if default shells, apply default styles + if(Module.olc_AssumeDefaultShells) + Module.canvas.parentNode.setAttribute('style', 'width: 100%; height: 70vh; margin-left: auto; margin-right: auto;'); + + // apply viewport dimensions to teh canvas + Module.canvas.setAttribute('width', viewWidth); + Module.canvas.setAttribute('height', viewHeight); + Module.canvas.setAttribute('style', `width: ${viewWidth}px; height: ${viewHeight}px;`); + + // update the PGE window size + Module._olc_PGE_UpdateWindowSize(viewWidth, viewHeight); + + // force focus on our PGE canvas + Module.canvas.focus(); + }, 200); }; - - // Disable Refresh Gesture on mobile - document.body.style.cssText += " overscroll-behavior-y: contain;"; - - if (Module.canvas.parentNode.className == 'emscripten_border') + + // olc_Init + // + // set up resize observer and fullscreenchange event handler + var olc_Init = function() { - // force body to have no margin in emscripten's minimal shell - document.body.style.margin = "0"; - Module.canvas.parentNode.style.cssText = Module._olc_EmscriptenShellCss; - } - - Module._olc_ResizeCanvas(); + if(Module.olc_AspectRatio === undefined) + { + setTimeout(function() { Module.olc_Init(); }, 50); + return; + } + + let resizeObserver = new ResizeObserver(function(entries) + { + Module.olc_ResizeHandler(); + }).observe(Module.canvas.parentNode); - // observe and react to resizing of the container element - var resizeObserver = new ResizeObserver(function(entries) {Module._olc_ResizeCanvas();}).observe(Module.canvas.parentNode); + let mutationObserver = new MutationObserver(function(mutationsList, observer) + { + setTimeout(function() { Module.olc_ResizeHandler(); }, 200); + }).observe(Module.canvas.parentNode, { attributes: false, childList: true, subtree: false }); - // observe and react to changes that occur when entering/exiting fullscreen - var mutationObserver = new MutationObserver(function(mutationsList, observer) - { - // a change has occurred, let's check them out! - for (var i = 0; i < mutationsList.length; i++) + window.addEventListener('fullscreenchange', function(e) { - // cycle through all of the newly added elements - for (var j = 0; j < mutationsList[i].addedNodes.length; j++) - { - // if this element is a our canvas, trigger resize - if (mutationsList[i].addedNodes[j].id == 'canvas') - Module._olc_ResizeCanvas(); - } - } - }).observe(Module.canvas.parentNode, - { - attributes: false, - childList : true, - subtree : false - }); + setTimeout(function() { Module.olc_ResizeHandler();}, 200); + }); + }; + + // set up hooks + Module.olc_ResizeHandler = (Module.olc_ResizeHandler != undefined) ? Module.olc_ResizeHandler : olc_ResizeHandler; + Module.olc_Init = (Module.olc_Init != undefined) ? Module.olc_Init : olc_Init; - // add resize listener on window - window.addEventListener("resize", function(e) { Module._olc_ResizeCanvas(); }); + // run everything! + Module.olc_Init(); }, vWindowSize.x, vWindowSize.y); // Fullscreen and Resize Observers #pragma warning restore format @@ -6157,7 +6598,9 @@ namespace olc void PixelGameEngine::olc_ConfigureSystem() { -#if !defined(OLC_PGE_HEADLESS) +//#if !defined(OLC_PGE_HEADLESS) + + olc::Sprite::loader = nullptr; #if defined(OLC_IMAGE_GDI) olc::Sprite::loader = std::make_unique(); @@ -6176,7 +6619,9 @@ namespace olc #endif - +#if defined(OLC_PLATFORM_HEADLESS) + platform = std::make_unique(); +#endif #if defined(OLC_PLATFORM_WINAPI) platform = std::make_unique(); @@ -6198,7 +6643,9 @@ namespace olc platform = std::make_unique(); #endif - +#if defined(OLC_GFX_HEADLESS) + renderer = std::make_unique(); +#endif #if defined(OLC_GFX_OPENGL10) renderer = std::make_unique(); @@ -6227,11 +6674,11 @@ namespace olc // Associate components with PGE instance platform->ptrPGE = this; renderer->ptrPGE = this; -#else - olc::Sprite::loader = nullptr; - platform = nullptr; - renderer = nullptr; -#endif +//#else +// olc::Sprite::loader = nullptr; +// platform = nullptr; +// renderer = nullptr; +//#endif } } @@ -6243,5 +6690,4 @@ namespace olc // | END OF OLC_PGE_APPLICATION | // O------------------------------------------------------------------------------O - -using namespace olc; +using namespace olc; \ No newline at end of file diff --git a/pixelGameEngine.o b/pixelGameEngine.o new file mode 100644 index 0000000..d47711d Binary files /dev/null and b/pixelGameEngine.o differ diff --git a/sig b/sig index b30e9ff..947a600 100755 --- a/sig +++ b/sig @@ -3,7 +3,7 @@ export AUTO_UPDATE=true source utils/define.sh define PROJECT_NAME "C++ProjectTemplate" -define CUSTOM_PARAMS "-std=c++17 -lX11 -lGL -lpthread -lpng -lstdc++fs -lpulse -lpulse-simple -I/usr/include/lua5.3" +define CUSTOM_PARAMS "-std=c++17 -lX11 -lpthread -lpng -lstdc++fs -lGL -lpulse -lpulse-simple -I/usr/include/lua5.3" define LANGUAGE "C++" source utils/main.sh