From f5424bf29d75339c51bf98895f8eda6a33945a26 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 12 May 2020 22:12:09 +0100 Subject: [PATCH] CMake Update --- .gitignore | 4 + CMakeCache.txt | 367 +++++++++++++ CMakeLists.txt | 51 +- olcPGEX_Graphics2D.h | 313 ----------- olcPGEX_Graphics3D.h | 1174 ------------------------------------------ olcPGEX_Sound.h | 892 -------------------------------- 6 files changed, 388 insertions(+), 2413 deletions(-) create mode 100644 .gitignore create mode 100644 CMakeCache.txt delete mode 100644 olcPGEX_Graphics2D.h delete mode 100644 olcPGEX_Graphics3D.h delete mode 100644 olcPGEX_Sound.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5fdbf45 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vs/ +CMakeFiles/ +out/ +CMakeCache/ diff --git a/CMakeCache.txt b/CMakeCache.txt new file mode 100644 index 0000000..e1a19a6 --- /dev/null +++ b/CMakeCache.txt @@ -0,0 +1,367 @@ +# This is the CMakeCache file. +# For build in directory: /mnt/e/Not-Mine/plane000_olcPixelGameEngine +# It was generated by CMake: /usr/bin/cmake +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//Path to a program. +CMAKE_AR:FILEPATH=/usr/bin/ar + +//Choose the type of build, options are: None(CMAKE_CXX_FLAGS or +// CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel. +CMAKE_BUILD_TYPE:STRING= + +//Enable/Disable color output during build. +CMAKE_COLOR_MAKEFILE:BOOL=ON + +//CXX compiler +CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++ + +//A wrapper around 'ar' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_CXX_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-7 + +//A wrapper around 'ranlib' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_CXX_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-7 + +//Flags used by the compiler during all build types. +CMAKE_CXX_FLAGS:STRING= + +//Flags used by the compiler during debug builds. +CMAKE_CXX_FLAGS_DEBUG:STRING=-g + +//Flags used by the compiler during release builds for minimum +// size. +CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the compiler during release builds. +CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the compiler during release builds with debug info. +CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//C compiler +CMAKE_C_COMPILER:FILEPATH=/usr/bin/cc + +//A wrapper around 'ar' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_C_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-7 + +//A wrapper around 'ranlib' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_C_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-7 + +//Flags used by the compiler during all build types. +CMAKE_C_FLAGS:STRING= + +//Flags used by the compiler during debug builds. +CMAKE_C_FLAGS_DEBUG:STRING=-g + +//Flags used by the compiler during release builds for minimum +// size. +CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the compiler during release builds. +CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the compiler during release builds with debug info. +CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//Flags used by the linker. +CMAKE_EXE_LINKER_FLAGS:STRING= + +//Flags used by the linker during debug builds. +CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Enable/Disable output of compile commands during generation. +CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=OFF + +//Install path prefix, prepended onto install directories. +CMAKE_INSTALL_PREFIX:PATH=/usr/local + +//Path to a program. +CMAKE_LINKER:FILEPATH=/usr/bin/ld + +//Path to a program. +CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/make + +//Flags used by the linker during the creation of modules. +CMAKE_MODULE_LINKER_FLAGS:STRING= + +//Flags used by the linker during debug builds. +CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_NM:FILEPATH=/usr/bin/nm + +//Path to a program. +CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy + +//Path to a program. +CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump + +//Value Computed by CMake +CMAKE_PROJECT_NAME:STATIC=olcPixelGameEngine + +//Path to a program. +CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib + +//Flags used by the linker during the creation of dll's. +CMAKE_SHARED_LINKER_FLAGS:STRING= + +//Flags used by the linker during debug builds. +CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//If set, runtime paths are not added when installing shared libraries, +// but are added when building. +CMAKE_SKIP_INSTALL_RPATH:BOOL=NO + +//If set, runtime paths are not added when using shared libraries. +CMAKE_SKIP_RPATH:BOOL=NO + +//Flags used by the linker during the creation of static libraries. +CMAKE_STATIC_LINKER_FLAGS:STRING= + +//Flags used by the linker during debug builds. +CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during release minsize builds. +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during release builds. +CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during Release with Debug Info builds. +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_STRIP:FILEPATH=/usr/bin/strip + +//If this value is on, makefiles will be generated without the +// .SILENT directive, and all commands will be echoed to the console +// during the make. This is useful for debugging only. With Visual +// Studio IDE projects all commands are done without /nologo. +CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE + +//Path to a file. +OPENGL_EGL_INCLUDE_DIR:PATH=OPENGL_EGL_INCLUDE_DIR-NOTFOUND + +//Path to a file. +OPENGL_GLX_INCLUDE_DIR:PATH=OPENGL_GLX_INCLUDE_DIR-NOTFOUND + +//Path to a file. +OPENGL_INCLUDE_DIR:PATH=OPENGL_INCLUDE_DIR-NOTFOUND + +//Path to a library. +OPENGL_egl_LIBRARY:FILEPATH=OPENGL_egl_LIBRARY-NOTFOUND + +//Path to a library. +OPENGL_gl_LIBRARY:FILEPATH=OPENGL_gl_LIBRARY-NOTFOUND + +//Path to a library. +OPENGL_glu_LIBRARY:FILEPATH=OPENGL_glu_LIBRARY-NOTFOUND + +//Path to a library. +OPENGL_glx_LIBRARY:FILEPATH=OPENGL_glx_LIBRARY-NOTFOUND + +//Path to a library. +OPENGL_opengl_LIBRARY:FILEPATH=OPENGL_opengl_LIBRARY-NOTFOUND + +//Path to a file. +OPENGL_xmesa_INCLUDE_DIR:PATH=OPENGL_xmesa_INCLUDE_DIR-NOTFOUND + +//Value Computed by CMake +olcPixelGameEngine_BINARY_DIR:STATIC=/mnt/e/Not-Mine/plane000_olcPixelGameEngine + +//Value Computed by CMake +olcPixelGameEngine_SOURCE_DIR:STATIC=/mnt/e/Not-Mine/plane000_olcPixelGameEngine + + +######################## +# INTERNAL cache entries +######################## + +//ADVANCED property for variable: CMAKE_AR +CMAKE_AR-ADVANCED:INTERNAL=1 +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=/mnt/e/Not-Mine/plane000_olcPixelGameEngine +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=10 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=2 +//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE +CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=/usr/bin/cmake +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest +//ADVANCED property for variable: CMAKE_CXX_COMPILER +CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_COMPILER_AR +CMAKE_CXX_COMPILER_AR-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_COMPILER_RANLIB +CMAKE_CXX_COMPILER_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS +CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG +CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL +CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE +CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO +CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER +CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER_AR +CMAKE_C_COMPILER_AR-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER_RANLIB +CMAKE_C_COMPILER_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS +CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG +CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL +CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE +CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO +CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Executable file format +CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS +CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG +CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE +CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS +CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1 +//Name of external makefile project generator. +CMAKE_EXTRA_GENERATOR:INTERNAL= +//Name of generator. +CMAKE_GENERATOR:INTERNAL=Unix Makefiles +//Name of generator platform. +CMAKE_GENERATOR_PLATFORM:INTERNAL= +//Name of generator toolset. +CMAKE_GENERATOR_TOOLSET:INTERNAL= +//Have symbol pthread_create +CMAKE_HAVE_LIBC_CREATE:INTERNAL= +//Have library pthreads +CMAKE_HAVE_PTHREADS_CREATE:INTERNAL= +//Have library pthread +CMAKE_HAVE_PTHREAD_CREATE:INTERNAL=1 +//Have include pthread.h +CMAKE_HAVE_PTHREAD_H:INTERNAL=1 +//Source directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=/mnt/e/Not-Mine/plane000_olcPixelGameEngine +//Install .so files without execute permission. +CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1 +//ADVANCED property for variable: CMAKE_LINKER +CMAKE_LINKER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MAKE_PROGRAM +CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS +CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG +CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE +CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_NM +CMAKE_NM-ADVANCED:INTERNAL=1 +//number of local generators +CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJCOPY +CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJDUMP +CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 +//Platform information initialized +CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RANLIB +CMAKE_RANLIB-ADVANCED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=/usr/share/cmake-3.10 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS +CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG +CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE +CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH +CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_RPATH +CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS +CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG +CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE +CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STRIP +CMAKE_STRIP-ADVANCED:INTERNAL=1 +//uname command +CMAKE_UNAME:INTERNAL=/bin/uname +//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE +CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 +//Details about finding Threads +FIND_PACKAGE_MESSAGE_DETAILS_Threads:INTERNAL=[TRUE][v()] + diff --git a/CMakeLists.txt b/CMakeLists.txt index 5153f69..7563154 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,69 +1,52 @@ # This CMakeList.txt currently only supports compilation of -#a program on windows or linux, but only with the dependancies -#for oclPixelGameEngine.h +# a program on windows or linux, but only with the dependancies +# for oclPixelGameEngine.h # NOTE: THIS CMAKELIST WILL NOT INSTALL DEPENDANCIES, IT WILL JUST FIND THEM AND -#COMPILE / LINK THEM RESPECTIVELY, YOU NEED TO INSTALL THEM YOURSELF +# COMPILE / LINK THEM RESPECTIVELY, YOU NEED TO INSTALL THEM YOURSELF -# Any issues, submit an issue, or contact the author, "Ben (plane000)#8618" on Discord +# Any problems? submit an issue, or contact the author, "Ben (plane000)#8618" on Discord # Currently linked / compiled by default is: -#Threads (pthread), OpenGL, GLX, libPNG, X11 +# Threads (pthread), OpenGL, GLX, libPNG, X11 cmake_minimum_required(VERSION 3.7) project(olcPixelGameEngine) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} CMakeFiles/) # Don't worry what this does, it just gives more compatability options with libraries! -cmake_policy(SET CMP0037 OLD) # This just allows the / charicter in path names +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} CMakeFiles/) -set(ExecutableName output) # You can change this to whatever you wish the executable outputed to be, don't worry about a .exe, i'll do that! -set(SourceDir src) # Change src/ to wherever your code is +set(Executable output) +set(SourceDir src) # Change src/ to your source directory -# You can uncomment these 2 lines if you wish to have some headers included -# set(IncludeDir include/) # Change include/ to your include directory -# include_directories(${IncludeDir}) +set(IncludeDir include/) # Change include/ to your include directory +include_directories(${IncludeDir}) -# Uncomment this if you have your source in a folder called src/ -# file(GLOB_RECURSE SourceFiles -# ${SourceDir}/*.cpp -# ) +file(GLOB_RECURSE SourceFiles + ${SourceDir}/*.cpp + olcExampleProgram.cpp # Remove this +) -# Comment this line if you wish to compile your own programs source code -set(SourceFiles OneLoneCoder_PGE_SpriteTransforms.cpp) - -# From this point on, you don't need to worry about what the code does, it just manages dependancies, linking and compilation -#enjoy tinkering! - -# Find thread package set(THREADS_PREFER_PTHREAD_FLAD ON) find_package(Threads REQUIRED) -# Find GL and GLX package find_package(OpenGL REQUIRED) - if (UNIX) find_package(X11 REQUIRED) find_package(PNG REQUIRED) include_directories(${PNG_INCLUDE_DIR}) - - # Set platform spesific output names - set(Executable ${ExecutableName}.o) endif (UNIX) -if (WIN32) - target_include_directories(${WinSDK}) - # Set platform spesific output names - set(Executable ${ExecutableName}.exe) +if (WIN32) + include_directories(${WinSDK}) endif (WIN32) add_executable(${Executable} ${SourceFiles} - # Add more directories, files or CMake variables here to have them compile too! ) -target_link_libraries(${Executable} +link_libraries(${Executable} Threads::Threads OpenGL::OpenGL OpenGL::GL diff --git a/olcPGEX_Graphics2D.h b/olcPGEX_Graphics2D.h deleted file mode 100644 index 261a5c0..0000000 --- a/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/olcPGEX_Graphics3D.h b/olcPGEX_Graphics3D.h deleted file mode 100644 index 954e776..0000000 --- a/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/olcPGEX_Sound.h b/olcPGEX_Sound.h deleted file mode 100644 index 0b4dcf3..0000000 --- a/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