diff --git a/CMakeLists.txt b/CMakeLists.txt index 16f2c53..560c7ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,28 +9,26 @@ add_library(blah src/core/app.cpp src/core/filesystem.cpp - src/core/log.cpp + src/core/common.cpp src/core/time.cpp - + + src/graphics/batch.cpp src/graphics/blend.cpp src/graphics/framebuffer.cpp src/graphics/material.cpp src/graphics/mesh.cpp src/graphics/renderpass.cpp src/graphics/shader.cpp + src/graphics/spritefont.cpp + src/graphics/subtexture.cpp src/graphics/texture.cpp src/input/input.cpp - src/input/virtual_stick.cpp - src/input/virtual_button.cpp - src/input/virtual_axis.cpp - + src/input/binding.cpp + src/input/binding_registry.cpp + src/containers/str.cpp - src/drawing/batch.cpp - src/drawing/spritefont.cpp - src/drawing/subtexture.cpp - src/images/aseprite.cpp src/images/font.cpp src/images/image.cpp @@ -54,11 +52,11 @@ add_library(blah src/streams/memorystream.cpp src/streams/stream.cpp - src/internal/graphics_backend_gl.cpp src/internal/graphics_backend_d3d11.cpp src/internal/graphics_backend_dummy.cpp src/internal/platform_backend_sdl2.cpp + src/internal/platform_backend_win32.cpp ) target_include_directories(blah @@ -69,34 +67,49 @@ target_include_directories(blah ) # Platform Variables -set(SDL2_ENABLED true CACHE BOOL "Use SDL2 as the System implementation") -set(OPENGL_ENABLED true CACHE BOOL "Use OpenGL graphics implementation") -set(D3D11_ENABLED false CACHE BOOL "Use D3D11 graphics implementation") +set(PLATFORM_SDL2 true CACHE BOOL "Use SDL2 Platform Backend") +set(PLATFORM_WIN32 false CACHE BOOL "Use Win32 Platform Backend") +set(GRAPHICS_OPENGL true CACHE BOOL "Use OpenGL Graphics Backend") +set(GRAPHICS_D3D11 false CACHE BOOL "Use D3D11 Graphics Backend") set(LIBS "") -# add OpenGL definition if we're using it -if (OPENGL_ENABLED) - add_compile_definitions(BLAH_USE_OPENGL) -endif() +# use the OpenGL Graphics Backend +if (GRAPHICS_OPENGL) -# add D3D11 definition if we're using it -if (D3D11_ENABLED) - add_compile_definitions(BLAH_USE_D3D11) + add_compile_definitions(BLAH_GRAPHICS_OPENGL) + +# use the D3D11 Graphics Backend +elseif (GRAPHICS_D3D11) + + add_compile_definitions(BLAH_GRAPHICS_D3D11) set(LIBS ${LIBS} d3d11.lib dxguid.lib D3Dcompiler.lib) + endif() -# Link and create SDL2 Definition if we're using it -if (SDL2_ENABLED) - add_compile_definitions(BLAH_USE_SDL2) - if (EMSCRIPTEN) - set_target_properties(blah PROPERTIES COMPILE_FLAGS "-s USE_SDL=2") - else() - # Attempt to find SDL2 - find_package(SDL2 QUIET) +# use the SDL2 Platform Backend +# Link and create SDL2 Definition +if (PLATFORM_SDL2) + add_compile_definitions(BLAH_PLATFORM_SDL2) + # Emscripten can import SDL2 directly + if (EMSCRIPTEN) + + set_target_properties(blah PROPERTIES COMPILE_FLAGS "-s USE_SDL=2") + + # Load SDL2 Normally + else() + + # Try to find SDL2 + if (DEFINED SDL2_LIBRARIES AND DEFINED SDL2_INCLUDE_DIRS) + set(SDL2_FOUND true) + else() + find_package(SDL2 QUIET) + endif() + # If CMake cannot find SDL2 library, then it gets downloaded and compiled that way if (NOT ${SDL2_FOUND}) + include(FetchContent) FetchContent_Declare( SDL2 @@ -108,11 +121,20 @@ if (SDL2_ENABLED) FetchContent_Populate(SDL2) add_subdirectory(${sdl2_SOURCE_DIR} ${sdl2_BINARY_DIR}) endif() + endif() - # Either way we are linking to SDL2 - set(LIBS ${LIBS} SDL2) - endif() + # Add Library and Include Dirs + set(LIBS ${LIBS} ${SDL2_LIBRARIES}) + target_include_directories(blah PUBLIC ${SDL2_INCLUDE_DIRS}) + + endif() + +# use the Win32 Platform Backend +elseif (PLATFORM_WIN32) + + add_compile_definitions(BLAH_PLATFORM_WIN32) + endif() target_link_libraries(blah PUBLIC ${LIBS}) diff --git a/README.md b/README.md index 9326014..a4d4cf7 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,18 @@ ## blah -A small C++ game framework for 2D games. -Goal is to be simple and use as few dependencies as possible, to maintain easy building and portability. +A small 2D C++ Game Framework, using few dependencies and simple code to mainain easy building and portability. **☆ This will likely see breaking changes! Use at your own risk! ☆** #### building - Requires C++17 and CMake 3.12+ - - Platform Backend - - [SDL2](https://github.com/NoelFB/blah/blob/master/src/internal/platform_backend_sdl2.cpp) can be enabled in CMake with `SDL2_ENABLED`, and setting `SDL2_INCLUDE_DIRS` and `SDL2_LIBRARIES` - - Graphics Backend - - [OpenGL](https://github.com/NoelFB/blah/blob/master/src/internal/graphics_backend_gl.cpp) can be enabled in CMake with `OPENGL_ENABLED`. - - [D3D11](https://github.com/NoelFB/blah/blob/master/src/internal/graphics_backend_d3d11.cpp) (unfinished) can be enabled in CMake with `D3D11_ENABLED`. - - Other backends can be added by implementing the [Platform Backend](https://github.com/NoelFB/blah/blob/master/src/internal/platform_backend.h) or [Graphics Backend](https://github.com/NoelFB/blah/blob/master/src/internal/graphics_backend.h). + - A single *Platform* backend must be enabled: + - [SDL2](https://github.com/NoelFB/blah/blob/master/src/internal/platform_backend_sdl2.cpp) can be enabled in CMake with `PLATFORM_SDL2`, and setting `SDL2_INCLUDE_DIRS` and `SDL2_LIBRARIES` + - [WIN32](https://github.com/NoelFB/blah/blob/master/src/internal/platform_backend_win32.cpp) (UNFINISHED) can be enabled in CMake with `PLATFORM_WIN32`. + - Additional backends can be added by implementing the [Platform Backend](https://github.com/NoelFB/blah/blob/master/src/internal/platform_backend.h) + - A single *Graphics* backend must be enabled: + - [OpenGL](https://github.com/NoelFB/blah/blob/master/src/internal/graphics_backend_gl.cpp) can be enabled in CMake with `GRAPHICS_OPENGL`. + - [D3D11](https://github.com/NoelFB/blah/blob/master/src/internal/graphics_backend_d3d11.cpp) can be enabled in CMake with `GRAPHICS_D3D11`. + - Additional backends can be added by implementing the [Graphics Backend](https://github.com/NoelFB/blah/blob/master/src/internal/graphics_backend.h). #### notes - There's no Shader abstraction, so the [Sprite Batcher](https://github.com/NoelFB/blah/blob/master/include/blah/drawing/batch.h) has hard-coded GLSL/HLSL. This will need to change. @@ -38,7 +39,7 @@ void render() App::backbuffer->clear(Color::black); auto center = Vec2(App::backbuffer->width(), App::backbuffer->height()) / 2; - auto rotation = Time::elapsed * Calc::TAU; + auto rotation = Time::seconds * Calc::TAU; auto transform = Mat3x2::create_transform(center, Vec2::zero, Vec2::one, rotation); batch.push_matrix(transform); diff --git a/include/blah.h b/include/blah.h index 8cd72da..49adfad 100644 --- a/include/blah.h +++ b/include/blah.h @@ -2,16 +2,16 @@ #include "blah/core/app.h" #include "blah/core/filesystem.h" -#include "blah/core/log.h" +#include "blah/core/common.h" #include "blah/core/time.h" #include "blah/containers/vector.h" #include "blah/containers/stackvector.h" #include "blah/containers/str.h" -#include "blah/drawing/batch.h" -#include "blah/drawing/spritefont.h" -#include "blah/drawing/subtexture.h" +#include "blah/graphics/batch.h" +#include "blah/graphics/spritefont.h" +#include "blah/graphics/subtexture.h" #include "blah/graphics/blend.h" #include "blah/graphics/framebuffer.h" @@ -28,9 +28,8 @@ #include "blah/images/packer.h" #include "blah/input/input.h" -#include "blah/input/virtual_stick.h" -#include "blah/input/virtual_button.h" -#include "blah/input/virtual_axis.h" +#include "blah/input/binding.h" +#include "blah/input/binding_registry.h" #include "blah/math/calc.h" #include "blah/math/circle.h" diff --git a/include/blah/containers/stackvector.h b/include/blah/containers/stackvector.h index e7e7130..84e6d60 100644 --- a/include/blah/containers/stackvector.h +++ b/include/blah/containers/stackvector.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include diff --git a/include/blah/containers/str.h b/include/blah/containers/str.h index f372b24..48d02e8 100644 --- a/include/blah/containers/str.h +++ b/include/blah/containers/str.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include @@ -10,6 +10,7 @@ namespace Blah class StrOf; using String = StrOf<64>; + // A simple String implementation class Str { public: @@ -78,7 +79,7 @@ namespace Blah // Returns the unicode value at the given index. // Assumes the index is a valid utf8 starting point. - uint32_t utf8_at(int index) const; + u32 utf8_at(int index) const; // Returns the byte-length of the utf8 character. // Assumes the index is a valid utf8 starting point. @@ -88,7 +89,7 @@ namespace Blah Str& append(char c); // appends the given unicode character - Str& append(uint32_t c); + Str& append(u32 c); // appends the given c string Str& append(const char* start, const char* end = nullptr); @@ -100,7 +101,7 @@ namespace Blah Str& append_fmt(const char* fmt, ...); // appends a utf16 string - Str& append_utf16(const uint16_t* start, const uint16_t* end = nullptr, bool swapEndian = false); + Str& append_utf16(const u16* start, const u16* end = nullptr, bool swapEndian = false); // trims whitespace Str& trim(); @@ -138,8 +139,10 @@ namespace Blah // returns a substring of the string String substr(int start, int end) const; + // Splits the string into a vector of strings Vector split(char ch) const; + // replaces all occurances of old string with the new string Str& replace(const Str& old_str, const Str& new_str); // replaces all occurances of the given character in the string @@ -171,9 +174,14 @@ namespace Blah // returns a pointer to the heap buffer or to our stack allocation char* data() { return (m_buffer != nullptr ? m_buffer : ((char*)(this) + sizeof(Str))); } + + // returns a pointer to the heap buffer or to our stack allocation const char* data() const { return (m_buffer != nullptr ? m_buffer : ((char*)(this) + sizeof(Str))); } + // assigns the contents of the string void set(const Str& str) { set(str.cstr(), str.cstr() + str.m_length); } + + // assigns the contents of the string void set(const char* start, const char* end = nullptr); private: @@ -187,6 +195,7 @@ namespace Blah // combine string inline Str operator+(const Str& lhs, const Str& rhs) { Str str; str.append(lhs).append(rhs); return str; } + // A string with a local stack buffer of size T template class StrOf : public Str { diff --git a/include/blah/containers/vector.h b/include/blah/containers/vector.h index ebd57ec..7c28599 100644 --- a/include/blah/containers/vector.h +++ b/include/blah/containers/vector.h @@ -1,10 +1,12 @@ #pragma once -#include +#include #include +#include #include namespace Blah { + // A lightweight Vector implementation template class Vector { @@ -19,6 +21,7 @@ namespace Blah Vector(int capacity); Vector(const Vector& src); Vector(Vector&& src) noexcept; + Vector(std::initializer_list list); ~Vector(); Vector& operator=(const Vector& src); @@ -95,6 +98,17 @@ namespace Blah src.m_count = 0; } + + template + inline Vector::Vector(std::initializer_list list) + { + m_buffer = nullptr; + m_count = m_capacity = 0; + reserve(list.size()); + for (auto& it : list) + push_back(std::move(it)); + } + template inline Vector::~Vector() { diff --git a/include/blah/core/app.h b/include/blah/core/app.h index e8dd74b..18e0049 100644 --- a/include/blah/core/app.h +++ b/include/blah/core/app.h @@ -1,31 +1,72 @@ #pragma once #include #include -#include +#include namespace Blah { + // Application Event Functions using AppEventFn = std::function; + + // Application Logging Functions using AppLogFn = std::function; + // Application Configuration struct Config { + // Application name. + // This has no default and must be set. const char* name; + + // Starting width, in pixels. + // Depending on the OS DPI, the true window size may be a multiple of this. + // This has no default and must be set. int width; + + // Starting height, in pixels. + // Depending on the OS DPI, the true window size may be a multiple of this. + // This has no default and must be set. int height; + + // maximum updates to run before "giving up" and reducing frame rate. + // this avoids the 'spiral of death'. + // defaults to 5. int max_updates; + + // target framerate. + // defaults to 60. int target_framerate; + // Callback on application startup + // Defaults to nothing. AppEventFn on_startup; + + // Callback on application shutdown + // Defaults to nothing. AppEventFn on_shutdown; + + // Callback on application update + // Defaults to nothing. AppEventFn on_update; + + // Callback on application render + // Defaults to nothing. AppEventFn on_render; + + // Callback when the user has requested the application close. + // For example, pressing the Close button + // By default this calls `App::exit()` AppEventFn on_exit_request; + + // Callback when the application logs info/warning/errors + // Defaults to printf. AppLogFn on_log; + // Default config setup Config(); }; + // Renderer the Application is using enum class Renderer { None = -1, @@ -35,16 +76,24 @@ namespace Blah Count }; + // Features available on the current Renderer struct RendererFeatures { + // Whether Mesh Instancing is available bool instancing = false; + + // Whether the Texture origin is the bottom left. + // This is true for OpenGL. bool origin_bottom_left = false; + + // Maximum Texture Size available int max_texture_size = 0; }; class FrameBuffer; using FrameBufferRef = std::shared_ptr; + // Application namespace App { // Runs the application @@ -53,7 +102,9 @@ namespace Blah // Returns whether the application is running bool is_running(); - // Exits the application + // Exits the application. + // This only signals for the application to close, it will not stop + // until the current update and render calls are finished. void exit(); // Gets the config data used to run the application @@ -71,16 +122,20 @@ namespace Blah // Gets the height of the window int height(); - // Gets the drawable width of the window + // Gets the drawable width of the window, in pixels. + // This may differ from the width when on platforms with High DPI Displays. int draw_width(); - // Gets the drawable height of the window + // Gets the drawable height of the window, in pixels. + // This may differ from the height when on platforms with High DPI Displays. int draw_height(); - // Gets the content scale based on the OS + // Gets the content scale based on the platform. + // macOS is usually 2.0, other platforms vary. float content_scale(); - // Toggles fullscreen + // Toggles fullscreen if supported on the platform. + // Otherwise this function does nothing. void fullscreen(bool enabled); // Returns the Rendering API in use diff --git a/include/blah/core/log.h b/include/blah/core/common.h similarity index 65% rename from include/blah/core/log.h rename to include/blah/core/common.h index 36266dd..71fd98e 100644 --- a/include/blah/core/log.h +++ b/include/blah/core/common.h @@ -1,21 +1,22 @@ #pragma once +#include // error / abort #if defined(DEBUG) || defined(_DEBUG) - #include - #define BLAH_ERROR(message) \ +#include +#define BLAH_ERROR(message) \ do { Blah::Log::error(message "\n\tin file: %s:%d", __FILE__, __LINE__); abort(); } while(0) - #define BLAH_ERROR_FMT(message, ...) \ +#define BLAH_ERROR_FMT(message, ...) \ do { Blah::Log::error(message "\n\tin file: %s:%d", __VA_ARGS__, __FILE__, __LINE__); abort(); } while(0) #else - #define BLAH_ERROR(message) \ +#define BLAH_ERROR(message) \ Blah::Log::error(message "\n\tin file: %s:%d", __FILE__, __LINE__) - #define BLAH_ERROR_FMT(message, ...) \ +#define BLAH_ERROR_FMT(message, ...) \ Blah::Log::error(message "\n\tin file: %s:%d", __VA_ARGS__, __FILE__, __LINE__) #endif @@ -33,6 +34,16 @@ namespace Blah { + using i8 = int8_t; + using i16 = int16_t; + using i32 = int32_t; + using i64 = int64_t; + + using u8 = uint8_t; + using u16 = uint16_t; + using u32 = uint32_t; + using u64 = uint64_t; + namespace Log { enum class Category @@ -42,8 +53,8 @@ namespace Blah Error }; - void print(const char* info, ...); - void warn(const char* info, ...); - void error(const char* info, ...); + void info(const char* message, ...); + void warn(const char* message, ...); + void error(const char* message, ...); } } \ No newline at end of file diff --git a/include/blah/core/filesystem.h b/include/blah/core/filesystem.h index e7a572a..87cca2b 100644 --- a/include/blah/core/filesystem.h +++ b/include/blah/core/filesystem.h @@ -5,40 +5,71 @@ namespace Blah { using FilePath = StrOf<265>; + class FileStream; enum class FileMode { - None = 0, - Read = 1 << 1, - Write = 1 << 2, - ReadWrite = Read | Write, + None = 0, + Read = 1 << 0, + Write = 1 << 1, + ReadWrite = Read | Write, }; namespace Directory { + // Creates a new directory at the given location. + // Returns false if unable to create the directory. bool create(const FilePath& path); + + // Returns whether the given directory exists bool exists(const FilePath& path); + + // Tries to delete a path and returns whether it was successful bool remove(const FilePath& path); - Vector enumerate(const FilePath& str, bool recursive = true); + + // Enumerates over a directory and returns a list of files & directories + Vector enumerate(const FilePath& path, bool recursive = true); + + // Opens the path in the File Explorer / Finder void explore(const FilePath& path); } namespace File { + // Checks if the given file exists bool exists(const FilePath& path); + + // Tries to delete a file and returns whether it was successful bool remove(const FilePath& path); + + // Opens the given file and returns a stream + FileStream open(const FilePath& path, FileMode mode = FileMode::ReadWrite); } namespace Path { + // Returns the file name of the path FilePath get_file_name(const FilePath& path); + + // Returns the file name of the path, without the file extension FilePath get_file_name_no_ext(const FilePath& path); + + // Returns the path without any file extensions FilePath get_path_no_ext(const FilePath& path); + + // Returns relative path FilePath get_path_after(const FilePath& path, const FilePath& after); + + // Gets the top directory name from the path FilePath get_directory_name(const FilePath& path); + + // Normalizes a path (removes ../, changes \\ to /, removes redundant slashes, etc) FilePath normalize(const FilePath& path); + + // Joins two paths together FilePath join(const FilePath& a, const FilePath& b); + // Joins two paths together template FilePath join(const FilePath& a, const FilePath& b, const Args&... args) { diff --git a/include/blah/core/time.h b/include/blah/core/time.h index 1d69adc..a2ce64a 100644 --- a/include/blah/core/time.h +++ b/include/blah/core/time.h @@ -1,21 +1,21 @@ #pragma once -#include +#include namespace Blah { struct Time { // ticks per second (microseconds, in this case) - static constexpr uint64_t ticks_per_second = 1000000; + static constexpr u64 ticks_per_second = 1000000; // uptime, in ticks - static uint64_t ticks; + static u64 ticks; // uptime, in seconds static double seconds; // previous frame uptime, in ticks - static uint64_t previous_ticks; + static u64 previous_ticks; // previous frame uptime, in seconds static double previous_seconds; diff --git a/include/blah/drawing/spritefont.h b/include/blah/drawing/spritefont.h deleted file mode 100644 index b8c8488..0000000 --- a/include/blah/drawing/spritefont.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -namespace Blah -{ - class Font; - - class SpriteFont - { - public: - struct Character - { - Subtexture subtexture; - float advance = 0; - Vec2 offset; - }; - private: - // charset & kerning maps - std::unordered_map m_characters; - std::unordered_map m_kerning; - - // built texture - Vector m_atlas; - - public: - static const uint32_t* ASCII; - - String name; - float size; - float ascent; - float descent; - float line_gap; - - // Note: - // charset is a list of range pairs, until a 0 terminator (ex. 32,128,0) - - SpriteFont(); - SpriteFont(const char* file, float size); - SpriteFont(const char* file, float size, const uint32_t* charset); - SpriteFont(const Font& font, float size); - SpriteFont(const Font& font, float size, const uint32_t* charset); - SpriteFont(const SpriteFont&) = delete; - SpriteFont(SpriteFont&& src) noexcept; - ~SpriteFont(); - - void dispose(); - - SpriteFont& operator=(const SpriteFont&) = delete; - SpriteFont& operator=(SpriteFont&& src) noexcept; - - float height() const { return ascent - descent; } - float line_height() const { return ascent - descent + line_gap; } - - const Vector& textures() { return m_atlas; } - - float width_of(const String& text) const; - float width_of_line(const String& text, int start = 0) const; - float height_of(const String& text) const; - - void build(const char* file, float size, const uint32_t* charset); - void build(const Font& font, float size, const uint32_t* charset); - - float get_kerning(uint32_t codepoint0, uint32_t codepoint1) const; - void set_kerning(uint32_t codepoint0, uint32_t codepoint1, float kerning); - - Character& get_character(uint32_t codepoint) { return m_characters[codepoint]; } - const Character& get_character(uint32_t codepoint) const; - Character& operator[](uint32_t codepoint) { return m_characters[codepoint]; } - const Character& operator[](uint32_t codepoint) const; - }; -} \ No newline at end of file diff --git a/include/blah/drawing/batch.h b/include/blah/graphics/batch.h similarity index 90% rename from include/blah/drawing/batch.h rename to include/blah/graphics/batch.h index 30be4c3..f2a62ec 100644 --- a/include/blah/drawing/batch.h +++ b/include/blah/graphics/batch.h @@ -5,8 +5,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -15,9 +15,14 @@ namespace Blah { + // Spritebatcher Color Mode enum class ColorMode { + // Draws textures and shapes normally Normal, + + // Ignores the texture color but still uses transparency, essentially + // drawing the "shape" of the texture a solid color Wash }; @@ -38,7 +43,7 @@ namespace Blah inline TextAlign operator|(TextAlign lhs, TextAlign rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } inline TextAlign operator&(TextAlign lhs, TextAlign rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); } - // A simple 2D sprite batcher, used for drawing shapes and textures + // A 2D sprite batcher, used for drawing shapes and textures class Batch { public: @@ -187,10 +192,10 @@ namespace Blah Vec2 tex; Color col; - uint8_t mult; - uint8_t wash; - uint8_t fill; - uint8_t pad; + u8 mult; + u8 wash; + u8 fill; + u8 pad; }; struct DrawBatch @@ -214,23 +219,23 @@ namespace Blah scissor(0, 0, -1, -1) {} }; - static ShaderRef m_default_shader; - MaterialRef m_default_material; - MeshRef m_mesh; - Mat3x2 m_matrix; - ColorMode m_color_mode; - uint8_t m_tex_mult; - uint8_t m_tex_wash; - DrawBatch m_batch; - Vector m_vertices; - Vector m_indices; - Vector m_matrix_stack; - Vector m_scissor_stack; - Vector m_blend_stack; - Vector m_material_stack; - Vector m_color_mode_stack; - Vector m_layer_stack; - Vector m_batches; + static ShaderRef m_default_shader; + MaterialRef m_default_material; + MeshRef m_mesh; + Mat3x2 m_matrix; + ColorMode m_color_mode; + u8 m_tex_mult; + u8 m_tex_wash; + DrawBatch m_batch; + Vector m_vertices; + Vector m_indices; + Vector m_matrix_stack; + Vector m_scissor_stack; + Vector m_blend_stack; + Vector m_material_stack; + Vector m_color_mode_stack; + Vector m_layer_stack; + Vector m_batches; void render_single_batch(RenderPass& pass, const DrawBatch& b, const Mat4x4& matrix); }; diff --git a/include/blah/graphics/blend.h b/include/blah/graphics/blend.h index 654ee29..87b82ea 100644 --- a/include/blah/graphics/blend.h +++ b/include/blah/graphics/blend.h @@ -1,5 +1,5 @@ #pragma once -#include +#include namespace Blah { @@ -46,6 +46,7 @@ namespace Blah RGBA = Red | Green | Blue | Alpha, }; + // BlendMode using for rendering struct BlendMode { // Normal, pre-multiplied, Blend Mode @@ -61,7 +62,7 @@ namespace Blah BlendFactor alpha_src; BlendFactor alpha_dst; BlendMask mask; - uint32_t rgba; + u32 rgba; BlendMode() = default; @@ -78,7 +79,7 @@ namespace Blah BlendMode( BlendOp color_op, BlendFactor color_src, BlendFactor color_dst, BlendOp alpha_op, BlendFactor alpha_src, BlendFactor alpha_dst, - BlendMask blend_mask, uint32_t blend_rgba) : + BlendMask blend_mask, u32 blend_rgba) : color_op(color_op), color_src(color_src), color_dst(color_dst), diff --git a/include/blah/graphics/framebuffer.h b/include/blah/graphics/framebuffer.h index 6cad044..963fbf9 100644 --- a/include/blah/graphics/framebuffer.h +++ b/include/blah/graphics/framebuffer.h @@ -4,16 +4,8 @@ #include #include -// 4 color attachments + 1 depth/stencil -#define BLAH_ATTACHMENTS 5 - namespace Blah { - typedef StackVector Attachments; - - class FrameBuffer; - typedef std::shared_ptr FrameBufferRef; - enum class ClearMask { None = 0, @@ -23,6 +15,14 @@ namespace Blah All = (int)Color | (int)Depth | (int)Stencil }; + // Up to 4 color attachments + 1 depth/stencil + using Attachments = StackVector; + + class FrameBuffer; + using FrameBufferRef = std::shared_ptr; + + // FrameBuffer is a 2D Buffer that can be drawn to. + // It can hold up to 4 color Textures, and 1 Depth/Stencil Texture. class FrameBuffer { protected: @@ -65,7 +65,7 @@ namespace Blah virtual int height() const = 0; // Clears the FrameBuffer - virtual void clear(Color color = Color::black, float depth = 1.0f, uint8_t stencil = 0, ClearMask mask = ClearMask::All) = 0; + virtual void clear(Color color = Color::black, float depth = 1.0f, u8 stencil = 0, ClearMask mask = ClearMask::All) = 0; }; } diff --git a/include/blah/graphics/material.h b/include/blah/graphics/material.h index 7347d2d..da098e7 100644 --- a/include/blah/graphics/material.h +++ b/include/blah/graphics/material.h @@ -10,6 +10,7 @@ namespace Blah class Material; typedef std::shared_ptr MaterialRef; + // Materials hold values that can be assigned to a shader during rendering class Material final { private: @@ -59,10 +60,10 @@ namespace Blah // Sets the value. `length` is the total number of floats to set // For example if the uniform is a float2[4], a total of 8 float values // can be set. - void set_value(const char* name, const float* value, int64_t length); + void set_value(const char* name, const float* value, i64 length); // Gets a pointer to the values of the given Uniform, or nullptr if it doesn't exist. - const float* get_value(const char* name, int64_t* length = nullptr) const; + const float* get_value(const char* name, i64* length = nullptr) const; // Returns the internal Texture buffer const Vector& textures() const; diff --git a/include/blah/graphics/mesh.h b/include/blah/graphics/mesh.h index 343d5f5..15beeb4 100644 --- a/include/blah/graphics/mesh.h +++ b/include/blah/graphics/mesh.h @@ -1,10 +1,11 @@ #pragma once -#include +#include #include #include namespace Blah { + // Supported Vertex value types enum class VertexType { None, @@ -20,6 +21,7 @@ namespace Blah UShort4 }; + // Vertex Attribute information struct VertexAttribute { // Location / Attribute Index @@ -32,6 +34,8 @@ namespace Blah bool normalized = false; }; + // Vertex Format information. + // Holds a list of attributes and total stride per-vertex. struct VertexFormat { // List of Attributes @@ -44,15 +48,20 @@ namespace Blah VertexFormat(std::initializer_list attributes, int stride = 0); }; + // Supported Vertex Index formats enum class IndexFormat { + // Indices are 16 bit unsigned integers UInt16, + + // Indices are 32 bit unsigned integers UInt32 }; class Mesh; typedef std::shared_ptr MeshRef; + // A Mesh is a set of Indices and Vertices which are used for drawing class Mesh { protected: @@ -73,21 +82,21 @@ namespace Blah static MeshRef create(); // Uploads the given index buffer to the Mesh - virtual void index_data(IndexFormat format, const void* indices, int64_t count) = 0; + virtual void index_data(IndexFormat format, const void* indices, i64 count) = 0; // Uploads the given vertex buffer to the Mesh - virtual void vertex_data(const VertexFormat& format, const void* vertices, int64_t count) = 0; + virtual void vertex_data(const VertexFormat& format, const void* vertices, i64 count) = 0; // Uploads the given instance buffer to the Mesh - virtual void instance_data(const VertexFormat& format, const void* instances, int64_t count) = 0; + virtual void instance_data(const VertexFormat& format, const void* instances, i64 count) = 0; // Gets the index count of the Mesh - virtual int64_t index_count() const = 0; + virtual i64 index_count() const = 0; // Gets the vertex count of the Mesh - virtual int64_t vertex_count() const = 0; + virtual i64 vertex_count() const = 0; // Gets the instance count of the Mesh - virtual int64_t instance_count() const = 0; + virtual i64 instance_count() const = 0; }; } \ No newline at end of file diff --git a/include/blah/graphics/renderpass.h b/include/blah/graphics/renderpass.h index d1d6aa4..df3d962 100644 --- a/include/blah/graphics/renderpass.h +++ b/include/blah/graphics/renderpass.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include @@ -11,6 +11,7 @@ namespace Blah { + // Depth comparison function to use during a draw call enum class Compare { None, @@ -24,13 +25,20 @@ namespace Blah GreatorOrEqual }; + // Cull mode during a draw call enum class Cull { + // No Culling enabled None = 0, + + // Cull front faces Front = 1, + + // Cull back faces Back = 2, }; + // A single draw call struct RenderPass { // Framebuffer to draw to @@ -55,13 +63,13 @@ namespace Blah Rect scissor; // First index in the Mesh to draw from - int64_t index_start; + i64 index_start; // Total amount of indices to draw from the Mesh - int64_t index_count; + i64 index_count; // Total amount of instances to draw from the Mesh - int64_t instance_count; + i64 instance_count; // Depth Compare Function Compare depth; diff --git a/include/blah/graphics/sampler.h b/include/blah/graphics/sampler.h index 432c8f8..c75fb94 100644 --- a/include/blah/graphics/sampler.h +++ b/include/blah/graphics/sampler.h @@ -2,24 +2,42 @@ namespace Blah { + // Texture filter enum class TextureFilter { + // None will fallback to whatever default the driver sets None, + + // Linear interpolation Linear, + + // Nearest Neighbour interpolation Nearest }; + // Texture Wrap Mode enum class TextureWrap { + // None will fallback to whatever default the driver sets None, + + // Clamps the texture to the edges Clamp, + + // Repeats the texture Repeat }; + // Texture Sampler State, applied during rendering struct TextureSampler { + // Filter Mode TextureFilter filter; + + // Wrap X Mode TextureWrap wrap_x; + + // Wrap Y Mode TextureWrap wrap_y; TextureSampler() : diff --git a/include/blah/graphics/shader.h b/include/blah/graphics/shader.h index adec92e..c7d18af 100644 --- a/include/blah/graphics/shader.h +++ b/include/blah/graphics/shader.h @@ -72,6 +72,7 @@ namespace Blah class Shader; typedef std::shared_ptr ShaderRef; + // A shader used during Rendering class Shader { protected: diff --git a/include/blah/graphics/spritefont.h b/include/blah/graphics/spritefont.h new file mode 100644 index 0000000..e0e1096 --- /dev/null +++ b/include/blah/graphics/spritefont.h @@ -0,0 +1,132 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +namespace Blah +{ + class Font; + + // Sprite Font is a bitmap font implementation for font rendering. + // It can be constructed from a Font (ttf) and will automatically create + // texture atlases for rendering. You can add your own characters + // and textures to it. + class SpriteFont + { + public: + + // Spritefont uses u32 codepoints + using Codepoint = u32; + + // CharSet is a Vector of Character Ranges + struct CharRange; + using CharSet = Vector; + + // Character range, used for building the Sprite Font + struct CharRange + { + Codepoint from; + Codepoint to; + + CharRange(); + CharRange(Codepoint single); + CharRange(Codepoint from, Codepoint to); + + static const CharSet ASCII; + }; + + // Character Entry + struct Character + { + Subtexture subtexture; + float advance = 0; + Vec2 offset; + }; + + // SpriteFont name + String name; + + // Height, in pixels + float size; + + // Ascent, in pixels + float ascent; + + // Descent, in pixels + float descent; + + // Line Gap, in pixels + float line_gap; + + SpriteFont(); + SpriteFont(const FilePath& file, float size); + SpriteFont(const FilePath& file, float size, const CharSet& charset); + SpriteFont(const Font& font, float size); + SpriteFont(const Font& font, float size, const CharSet& charset); + SpriteFont(const SpriteFont&) = delete; + SpriteFont& operator=(const SpriteFont&) = delete; + SpriteFont(SpriteFont&& src) noexcept; + SpriteFont& operator=(SpriteFont&& src) noexcept; + ~SpriteFont(); + + // releases all assets used by the spritefont + void dispose(); + + // gets the height of the sprite font + float height() const { return ascent - descent; } + + // gets the line height of the sprite font (height + line gap) + float line_height() const { return ascent - descent + line_gap; } + + // returns a list of all texture atlases + const Vector& textures() { return m_atlas; } + + // calculates the width of the given string + float width_of(const String& text) const; + + // calculates the width of the next line + float width_of_line(const String& text, int start = 0) const; + + // calculates the height of the given string + float height_of(const String& text) const; + + // disposes the existing spritefont data and rebuilds from the given font file + void rebuild(const FilePath& file, float size, const CharSet& charset); + + // disposes the existing spritefont data and rebuilds from the given font + void rebuild(const Font& font, float size, const CharSet& charset); + + // gets the kerning between two characters + float get_kerning(Codepoint codepoint0, Codepoint codepoint1) const; + + // sets the kerning between two characters + void set_kerning(Codepoint codepoint0, Codepoint codepoint1, float kerning); + + // gets the character at the given codepoint + Character& get_character(Codepoint codepoint); + + // gets the character at the given codepoint + const Character& get_character(Codepoint codepoint) const; + + // gets the character at the given codepoint + Character& operator[](Codepoint codepoint); + + // gets the character at the given codepoint + const Character& operator[](Codepoint codepoint) const; + + private: + // character set + std::unordered_map m_characters; + + // kerning + // key is 2 codepoints combined ((first << 32) | second) + std::unordered_map m_kerning; + + // built texture + Vector m_atlas; + }; +} \ No newline at end of file diff --git a/include/blah/drawing/subtexture.h b/include/blah/graphics/subtexture.h similarity index 100% rename from include/blah/drawing/subtexture.h rename to include/blah/graphics/subtexture.h diff --git a/include/blah/graphics/texture.h b/include/blah/graphics/texture.h index 38cecf5..61e4ba6 100644 --- a/include/blah/graphics/texture.h +++ b/include/blah/graphics/texture.h @@ -5,11 +5,22 @@ namespace Blah { enum class TextureFormat { + // Invalid Format None, + + // Single 8-bit channe; R, + + // 2 8-bit channels RG, + + // 4 8-bit channels RGBA, + + // Depth 24, Stencil 8 DepthStencil, + + // Total Formats Count }; @@ -18,6 +29,7 @@ namespace Blah class Texture; typedef std::shared_ptr TextureRef; + // A 2D Texture held by the GPU to be used during rendering class Texture { protected: diff --git a/include/blah/images/aseprite.h b/include/blah/images/aseprite.h index 594136a..db35aa0 100644 --- a/include/blah/images/aseprite.h +++ b/include/blah/images/aseprite.h @@ -3,12 +3,13 @@ #include #include #include +#include namespace Blah { // A simple Aseprite file parser. // This implementation does not support Aseprite blendmodes, - // besides the default blend mode. + // aside from the default blend mode. class Aseprite { public: @@ -125,12 +126,12 @@ namespace Blah Vector layers; Vector frames; - Vector tags; + Vector tags; Vector slices; Vector palette; Aseprite(); - Aseprite(const char* path); + Aseprite(const FilePath& path); Aseprite(Stream& stream); Aseprite(const Aseprite& src); Aseprite(Aseprite&& src) noexcept; diff --git a/include/blah/images/font.h b/include/blah/images/font.h index 15c7097..6958276 100644 --- a/include/blah/images/font.h +++ b/include/blah/images/font.h @@ -2,50 +2,102 @@ #include #include #include +#include namespace Blah { - typedef uint32_t Codepoint; - + // Loads fonts from file and can blit individual characters to images class Font { public: - struct Char + + // Font uses u32 Codepoints + using Codepoint = u32; + + // Information provided for a single Character + struct Character { + // character's glyph index int glyph = 0; + + // width of the character, in pixels int width = 0; + + // height of the character, in pixels int height = 0; + + // advance (how much to move horizontally) float advance = 0; + + // render x-offset float offset_x = 0; + + // render y-offset float offset_y = 0; + + // scale the character was created at float scale = 0; + + // whether the character has a visible glyph bool has_glyph = false; }; Font(); Font(Stream& stream); - Font(const char* path); + Font(const FilePath& path); Font(const Font&) = delete; Font& operator=(const Font&) = delete; Font(Font&& src) noexcept; Font& operator=(Font&& src) noexcept; ~Font(); + // Releases all Font resources + // Note that after doing this various properties may become invalid (ex. font name) void dispose(); - const char* family_name() const; - const char* style_name() const; + // returns the font family name + const String& family_name() const; + + // returns the font style name + const String& style_name() const; + + // the font ascent int ascent() const; + + // the font descent int descent() const; + + // the font line gap (space between lines) int line_gap() const; + + // the height of the font int height() const; + + // the height of the line, including line gap int line_height() const; + // gets the glyph index for the given codepoint int get_glyph(Codepoint codepoint) const; + + // gets the font scale for the given font size in pixels float get_scale(float size) const; + + // gets the font kerning between 2 glyphs float get_kerning(int glyph1, int glyph2, float scale) const; - Char get_character(int glyph, float scale) const; - bool get_image(const Char& ch, Color* pixels) const; + + // gets character data for the given glyph, at the provided scale + Character get_character(int glyph, float scale) const; + + // Blits a character to the provided pixel array. + // The pixel array must be at least ch.width * ch.height in size! + // If the character doesn't exist, this will do nothing and return false. + bool get_image(const Character& ch, Color* pixels) const; + + // Returns an image of the provided character. + // If the character doesn't exist, this will return an empty image. + Image get_image(const Character& ch) const; + + // checks if the Font is valid bool is_valid() const; private: diff --git a/include/blah/images/image.h b/include/blah/images/image.h index 03000c7..7d681b2 100644 --- a/include/blah/images/image.h +++ b/include/blah/images/image.h @@ -2,21 +2,31 @@ #include #include #include +#include namespace Blah { class Stream; + // A 2D Bitmap stored on the CPU. + // For drawing images to the screen, use a Texture. class Image { public: + + // width of the image, in pixels. int width = 0; + + // height of the image, in pixels. int height = 0; + + // pixel data of the image. + // this can be nullptr if the image is never assigned to anything. Color* pixels = nullptr; Image(); Image(Stream& stream); - Image(const char* file); + Image(const FilePath& file); Image(int width, int height); Image(const Image& src); Image& operator=(const Image& src); @@ -24,19 +34,41 @@ namespace Blah Image& operator=(Image&& src) noexcept; ~Image(); + // disposes the existing image and recreates it from a stream void from_stream(Stream& stream); + + // disposes the image and resets its values to defaults void dispose(); + // applies alpha premultiplication to the image data void premultiply(); + + // sets the pixels at the provided rectangle to the given data + // data must be at least rect.w * rect.h in size! void set_pixels(const RectI& rect, Color* data); - bool save_png(const char* file) const; + + // saves the image to a png file + bool save_png(const FilePath& file) const; + + // saves the image to a png file bool save_png(Stream& stream) const; - bool save_jpg(const char* file, int quality) const; + + // saves the image to a jpg file + bool save_jpg(const FilePath& file, int quality) const; + + // saves the image to a jpg file bool save_jpg(Stream& stream, int quality) const; - void get_pixels(Color* dest, const Point& destPos, const Point& destSize, RectI sourceRect); - Image get_sub_image(const RectI& sourceRect); + + // gets the pixels from the given source rectangle + void get_pixels(Color* dest, const Point& dest_pos, const Point& dest_size, RectI source_rect); + + // gets a sub image from this image + Image get_sub_image(const RectI& source_rect); private: + + // whether the stbi library owns the image data. + // we should let it free the data if it created it. bool m_stbi_ownership; }; } \ No newline at end of file diff --git a/include/blah/images/packer.h b/include/blah/images/packer.h index da0a8f9..faa451e 100644 --- a/include/blah/images/packer.h +++ b/include/blah/images/packer.h @@ -6,37 +6,67 @@ #include #include #include +#include namespace Blah { // Texture Packer, which takes source images and combines - // them into a single large texture. + // them into a single large texture. Useful for 2D sprite batching. class Packer { public: + + // Packer Entry, which stores information about the resulting packed texture class Entry { friend class Packer; private: - int64_t memory_index; + i64 memory_index; + public: - uint64_t id; + + // entry ID + u64 id; + + // Texture Page that it was packed into. + // This won't be set until after the packer has run. int page; + + // Whether the entry is empty bool empty; + + // Packed frame rectangle. + // This won't be set until after the packer has run. RectI frame; + + // Packed position and size. + // This won't be set until after the packer has run. RectI packed; - Entry(uint64_t id, const RectI& frame) - : memory_index(0), id(id), page(0), empty(true), frame(frame), packed(0, 0, 0, 0) {} + Entry(u64 id, const RectI& frame) + : memory_index(0) + , id(id) + , page(0) + , empty(true) + , frame(frame) + , packed(0, 0, 0, 0) {} }; + // maximum width / height of the generated texture int max_size; + + // whether the generated texture must be a power of 2 bool power_of_two; + + // spacing between each packed subtexture int spacing; + + // padding on each subtexture (extrudes their borders outwards) int padding; + // generated textures. There can be more than one if the packer was + // unable to fit all of the provided subtextures into the max_size. Vector pages; - Vector entries; Packer(); Packer(int max_size, int spacing, bool power_of_two); @@ -46,12 +76,25 @@ namespace Blah Packer& operator=(Packer&& src) noexcept; ~Packer(); - void add(uint64_t id, int width, int height, const Color* pixels); - void add(uint64_t id, const Image& bitmap); - void add(uint64_t id, const String& path); + // add a new entry + void add(u64 id, int width, int height, const Color* pixels); + // add a new entry + void add(u64 id, const Image& bitmap); + + // add a new entry + void add(u64 id, const FilePath& path); + + // returns a vector of all the resulting entries + const Vector& entries() const; + + // perform the packing void pack(); + + // clear the current packer data void clear(); + + // dispose all resources used by the packer void dispose(); private: @@ -67,9 +110,16 @@ namespace Blah Node* Reset(const RectI& rect); }; + // whether the packer has any changes that require it to run again bool m_dirty; + + // buffer of all the image data we will be packing BufferStream m_buffer; - void add_entry(uint64_t id, int w, int h, const Color* pixels); + // Entries to pack & their resulting data + Vector m_entries; + + // adds a new entry + void add_entry(u64 id, int w, int h, const Color* pixels); }; } \ No newline at end of file diff --git a/include/blah/input/binding.h b/include/blah/input/binding.h new file mode 100644 index 0000000..2d93f28 --- /dev/null +++ b/include/blah/input/binding.h @@ -0,0 +1,299 @@ +#pragma once +#include +#include +#include +#include + +namespace Blah +{ + // Single input Binding + // You must call Binding::update() every frame to poll the input state. + // Alternatively, bindings can be registered to BindingRegistry which will + // automatically update them. + class Binding + { + public: + + // Represents a Controller Trigger or a single direction of a Controller Axis. + struct TriggerBind + { + // Controller Index we're bound to + int controller = 0; + + // The Axis we're bound to + Axis axis = Axis::None; + + // Minimum value of the axis + float threshold = 0.01f; + + // requires a positive value + // otherwise requires a negative value + bool positive = true; + + TriggerBind() = default; + TriggerBind(Axis axis); + TriggerBind(int controller, Axis axis, float threshold, bool positive); + + bool is_down(float axis_value) const; + }; + + // Represents a Controller Button. + struct ButtonBind + { + // Controller Index we're bound to + int controller = 0; + + // Button we're bound to + Button button = Button::None; + + ButtonBind() = default; + ButtonBind(Button button); + ButtonBind(int controller, Button button); + }; + + // Input Buffer for press events + float press_buffer = 0; + + // Input Buffer for release events + float release_buffer = 0; + + // List of bound Keys + StackVector keys; + + // List of bound Buttons + StackVector buttons; + + // List of bound Triggers / Axis + StackVector triggers; + + // List of bound Mouse buttons + StackVector mouse; + + Binding() = default; + + Binding(float press_buffer) + : press_buffer(press_buffer) + { + + } + + template + Binding(float press_buffer, const Args&... args) + : press_buffer(press_buffer) + { + add(args...); + } + + // if the binding has been pressed + bool pressed() const; + + // if the binding has been released + bool released() const; + + // if the binding is currently held + bool down() const; + + // returns the binding's value from 0-1 + float value() const; + + // returns the bindings signed value (0 or 1) + int sign() const; + + // returns the timestamp of the last time the binding was pressed + double timestamp() const; + + // updates the binding state + void update(); + + // consumes the current press, and pressed() will return false until the next press + void consume_press(); + + // consumes the current release, and released() will return false until the next release + void consume_release(); + + // adds a key to the binding + Binding& add(Key key); + + // adds a button to the binding + Binding& add(ButtonBind button); + + // adds an trigger to the binding + Binding& add(TriggerBind trigger); + + // adds a mouse button to the binding + Binding& add(MouseButton mouse); + + // adds an input to the binding + template + Binding& add(T first, T2 second, const Args&... args) + { + add(first); + add(second, args...); + return *this; + } + + // adds the left trigger to the binding + Binding& add_left_trigger(int controller, float threshold); + + // adds the right trigger to the binding + Binding& add_right_trigger(int controller, float threshold); + + // assigns all the bindings to the specific controller + Binding& set_controller(int index); + + // removes all bindings + void clear(); + + private: + double m_last_timestamp = 0; + double m_last_press_time = -1; + double m_last_release_time = -1; + float m_value = 0.0f; + bool m_pressed = false; + bool m_released = false; + bool m_down = false; + bool m_press_consumed = false; + bool m_release_consumed = false; + + bool get_pressed() const; + bool get_released() const; + bool get_down() const; + float get_value() const; + }; + + // Axis Binding (ex. Left/Right movement, or a Trigger) + // You must call AxisBinding::update() every frame to poll the input state. + // Alternatively, bindings can be registered to BindingRegistry which will + // automatically update them. + class AxisBinding + { + public: + + enum class Overlap + { + Newer, + Older, + Cancel + }; + + // Negative Value Binding + Binding negative; + + // Positive Value Binding + Binding positive; + + // How to handle overlaps (ex. Left and Right are both held) + Overlap overlap = Overlap::Newer; + + AxisBinding() = default; + + AxisBinding(const Binding& negative, const Binding& positive, Overlap overlap = Overlap::Newer) + : negative(negative) + , positive(positive) + , overlap(overlap) + {} + + // Current Value from -1 to 1 + float value() const; + + // Current value, either -1, 0, or 1 + int sign() const; + + // updates the Binding + void update(); + + // consumes the press buffer + void consume_press(); + + // consumes the release buffer + void consume_release(); + + // Adds a negative & positive binding pair + template + AxisBinding& add(NegativeT negative, PositiveT positive) + { + this->negative.add(negative); + this->positive.add(positive); + return *this; + } + + // Adds a Stick binding + AxisBinding& add_left_stick_x(int controller, float threshold); + AxisBinding& add_left_stick_y(int controller, float threshold); + AxisBinding& add_right_stick_x(int controller, float threshold); + AxisBinding& add_right_stick_y(int controller, float threshold); + + // assigns all the bindings to the specific controller + AxisBinding& set_controller(int index); + + // Clears all Bindings + void clear(); + }; + + // Stick Binding (ex. Joystick, Dpad, Arrow Keys, WASD, etc) + // You must call StickBinding::update() every frame to poll the input state. + // Alternatively, bindings can be registered to BindingRegistry which will + // automatically update them. + class StickBinding + { + public: + + // X Axis Binding + AxisBinding x; + + // Y Axis Binding + AxisBinding y; + + // An optional threshold for circular thresholds + float round_threshold = 0.0f; + + StickBinding() = default; + + StickBinding(const AxisBinding& x, const AxisBinding& y, float round_threshold = 0) + : x(x) + , y(y) + , round_threshold(round_threshold) + {} + + // Current Value, -1 to 1 + Vec2 value() const; + + // Current value, either -1, 0, or 1 + Point sign() const; + + // Updates the Binding + void update(); + + // Consumes the Press Buffer + void consume_press(); + + // Consumes the Release Buffer + void consume_release(); + + // Adds directional bindings + template + StickBinding& add(LeftT left, RightT right, UpT up, DownT down) + { + x.negative.add(left); + x.positive.add(right); + y.negative.add(up); + y.positive.add(down); + return *this; + } + + // Adds the dpad binding + StickBinding& add_dpad(int controller); + + // Adds the left stick binding + StickBinding& add_left_stick(int controller, float threshold); + + // Adds the right stick binding + StickBinding& add_right_stick(int controller, float threshold); + + // assigns all the bindings to the specific controller + StickBinding& set_controller(int index); + + // Clears all the bindings + void clear(); + }; +} \ No newline at end of file diff --git a/include/blah/input/binding_registry.h b/include/blah/input/binding_registry.h new file mode 100644 index 0000000..4ec1b16 --- /dev/null +++ b/include/blah/input/binding_registry.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include +#include + +namespace Blah +{ + using BindingRef = std::shared_ptr; + using AxisBindingRef = std::shared_ptr; + using StickBindingRef = std::shared_ptr; + + // An Optional registry to automatically update Input Bindings. + // Once registered here, you do not need to explicitely call their update methods. + class BindingRegistry + { + public: + // registers a new binding + static BindingRef register_binding(const Binding& binding = Binding()); + + // registers a new axis binding + static AxisBindingRef register_axis(const AxisBinding& binding = AxisBinding()); + + // registers a new stick binding + static StickBindingRef register_stick(const StickBinding& binding = StickBinding()); + + // updates all the bindings. This is called + // automatically by the App loop. + static void update(); + + private: + static Vector> bindings; + static Vector> axes; + static Vector> sticks; + }; +} \ No newline at end of file diff --git a/include/blah/input/input.h b/include/blah/input/input.h index f227a3d..9fdb3df 100644 --- a/include/blah/input/input.h +++ b/include/blah/input/input.h @@ -1,223 +1,193 @@ #pragma once -#include +#include #include +#include -// These are generally copied from the SDL2 Scancode Keys +// These are generally copied from the SDL2 Scancode Keys, +// which are in turn based on the USB standards: +// https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf #define BLAH_KEY_DEFINITIONS \ DEFINE_KEY(Unknown, 0) \ - DEFINE_KEY(A, 4) \ - DEFINE_KEY(B, 5) \ - DEFINE_KEY(C, 6) \ - DEFINE_KEY(D, 7) \ - DEFINE_KEY(E, 8) \ - DEFINE_KEY(F, 9) \ - DEFINE_KEY(G, 10) \ - DEFINE_KEY(H, 11) \ - DEFINE_KEY(I, 12) \ - DEFINE_KEY(J, 13) \ - DEFINE_KEY(K, 14) \ - DEFINE_KEY(L, 15) \ - DEFINE_KEY(M, 16) \ - DEFINE_KEY(N, 17) \ - DEFINE_KEY(O, 18) \ - DEFINE_KEY(P, 19) \ - DEFINE_KEY(Q, 20) \ - DEFINE_KEY(R, 21) \ - DEFINE_KEY(S, 22) \ - DEFINE_KEY(T, 23) \ - DEFINE_KEY(U, 24) \ - DEFINE_KEY(V, 25) \ - DEFINE_KEY(W, 26) \ - DEFINE_KEY(X, 27) \ - DEFINE_KEY(Y, 28) \ - DEFINE_KEY(Z, 29) \ - DEFINE_KEY(D1, 30) \ - DEFINE_KEY(D2, 31) \ - DEFINE_KEY(D3, 32) \ - DEFINE_KEY(D4, 33) \ - DEFINE_KEY(D5, 34) \ - DEFINE_KEY(D6, 35) \ - DEFINE_KEY(D7, 36) \ - DEFINE_KEY(D8, 37) \ - DEFINE_KEY(D9, 38) \ - DEFINE_KEY(D0, 39) \ + \ + DEFINE_KEY(A, 4) \ + DEFINE_KEY(B, 5) \ + DEFINE_KEY(C, 6) \ + DEFINE_KEY(D, 7) \ + DEFINE_KEY(E, 8) \ + DEFINE_KEY(F, 9) \ + DEFINE_KEY(G, 10) \ + DEFINE_KEY(H, 11) \ + DEFINE_KEY(I, 12) \ + DEFINE_KEY(J, 13) \ + DEFINE_KEY(K, 14) \ + DEFINE_KEY(L, 15) \ + DEFINE_KEY(M, 16) \ + DEFINE_KEY(N, 17) \ + DEFINE_KEY(O, 18) \ + DEFINE_KEY(P, 19) \ + DEFINE_KEY(Q, 20) \ + DEFINE_KEY(R, 21) \ + DEFINE_KEY(S, 22) \ + DEFINE_KEY(T, 23) \ + DEFINE_KEY(U, 24) \ + DEFINE_KEY(V, 25) \ + DEFINE_KEY(W, 26) \ + DEFINE_KEY(X, 27) \ + DEFINE_KEY(Y, 28) \ + DEFINE_KEY(Z, 29) \ + \ + DEFINE_KEY(D1, 30) \ + DEFINE_KEY(D2, 31) \ + DEFINE_KEY(D3, 32) \ + DEFINE_KEY(D4, 33) \ + DEFINE_KEY(D5, 34) \ + DEFINE_KEY(D6, 35) \ + DEFINE_KEY(D7, 36) \ + DEFINE_KEY(D8, 37) \ + DEFINE_KEY(D9, 38) \ + DEFINE_KEY(D0, 39) \ + \ DEFINE_KEY(Enter, 40) \ DEFINE_KEY(Escape, 41) \ DEFINE_KEY(Backspace, 42) \ DEFINE_KEY(Tab, 43) \ DEFINE_KEY(Space, 44) \ + \ DEFINE_KEY(Minus, 45) \ DEFINE_KEY(Equals, 46) \ DEFINE_KEY(LeftBracket, 47) \ DEFINE_KEY(RightBracket, 48) \ - DEFINE_KEY(BackSlash, 49) \ - DEFINE_KEY(NonUSHash, 50) \ + DEFINE_KEY(Backslash, 49) \ DEFINE_KEY(Semicolon, 51) \ DEFINE_KEY(Apostrophe, 52) \ - DEFINE_KEY(Grave, 53) \ + DEFINE_KEY(Tilde, 53) \ DEFINE_KEY(Comma, 54) \ DEFINE_KEY(Period, 55) \ DEFINE_KEY(Slash, 56) \ + \ DEFINE_KEY(Capslock, 57) \ - DEFINE_KEY(F1, 58) \ - DEFINE_KEY(F2, 59) \ - DEFINE_KEY(F3, 60) \ - DEFINE_KEY(F4, 61) \ - DEFINE_KEY(F5, 62) \ - DEFINE_KEY(F6, 63) \ - DEFINE_KEY(F7, 64) \ - DEFINE_KEY(F8, 65) \ - DEFINE_KEY(F9, 66) \ - DEFINE_KEY(F10, 67) \ - DEFINE_KEY(F11, 68) \ - DEFINE_KEY(F12, 69) \ - DEFINE_KEY(PrintScreen, 70) \ - DEFINE_KEY(ScrollLock, 71) \ - DEFINE_KEY(Pause, 72) \ - DEFINE_KEY(Insert, 73) \ - DEFINE_KEY(Home, 74) \ - DEFINE_KEY(PageUp, 75) \ - DEFINE_KEY(Delete, 76) \ - DEFINE_KEY(End, 77) \ - DEFINE_KEY(PageDown, 78) \ - DEFINE_KEY(Right, 79) \ - DEFINE_KEY(Left, 80) \ - DEFINE_KEY(Down, 81) \ - DEFINE_KEY(Up, 82) \ - DEFINE_KEY(NumlockClear, 83) \ - DEFINE_KEY(KP_Divide, 84) \ - DEFINE_KEY(KP_Multiply, 85) \ - DEFINE_KEY(KP_Minus, 86) \ - DEFINE_KEY(KP_Plus, 87) \ - DEFINE_KEY(KP_Enter, 88) \ - DEFINE_KEY(KP_1, 89) \ - DEFINE_KEY(KP_2, 90) \ - DEFINE_KEY(KP_3, 91) \ - DEFINE_KEY(KP_4, 92) \ - DEFINE_KEY(KP_5, 93) \ - DEFINE_KEY(KP_6, 94) \ - DEFINE_KEY(KP_7, 95) \ - DEFINE_KEY(KP_8, 96) \ - DEFINE_KEY(KP_9, 97) \ - DEFINE_KEY(KP_0, 98) \ - DEFINE_KEY(KP_Period, 99) \ - DEFINE_KEY(NonUSBackSlash, 100) \ - DEFINE_KEY(Application, 101) \ - DEFINE_KEY(Power, 102) \ - DEFINE_KEY(KP_Equals, 103) \ - DEFINE_KEY(F13, 104) \ - DEFINE_KEY(F14, 105) \ - DEFINE_KEY(F15, 106) \ - DEFINE_KEY(F16, 107) \ - DEFINE_KEY(F17, 108) \ - DEFINE_KEY(F18, 109) \ - DEFINE_KEY(F19, 110) \ - DEFINE_KEY(F20, 111) \ - DEFINE_KEY(F21, 112) \ - DEFINE_KEY(F22, 113) \ - DEFINE_KEY(F23, 114) \ - DEFINE_KEY(F24, 115) \ - DEFINE_KEY(Execute, 116) \ - DEFINE_KEY(Help, 117) \ - DEFINE_KEY(Menu, 118) \ - DEFINE_KEY(Select, 119) \ - DEFINE_KEY(Stop, 120) \ - DEFINE_KEY(Again, 121) \ - DEFINE_KEY(Undo, 122) \ - DEFINE_KEY(Cut, 123) \ - DEFINE_KEY(Copy, 124) \ - DEFINE_KEY(Paste, 125) \ - DEFINE_KEY(Find, 126) \ - DEFINE_KEY(Mute, 127) \ - DEFINE_KEY(VolumeUp, 128) \ - DEFINE_KEY(VolumeDown, 129) \ - DEFINE_KEY(KP_Comma, 133) \ - DEFINE_KEY(KP_EqualsAs400, 134) \ - DEFINE_KEY(International1, 135) \ - DEFINE_KEY(International2, 136) \ - DEFINE_KEY(International3, 137) \ - DEFINE_KEY(International4, 138) \ - DEFINE_KEY(International5, 139) \ - DEFINE_KEY(International6, 140) \ - DEFINE_KEY(International7, 141) \ - DEFINE_KEY(International8, 142) \ - DEFINE_KEY(International9, 143) \ - DEFINE_KEY(Language1, 144) \ - DEFINE_KEY(Language2, 145) \ - DEFINE_KEY(Language3, 146) \ - DEFINE_KEY(Language4, 147) \ - DEFINE_KEY(Language5, 148) \ - DEFINE_KEY(Language6, 149) \ - DEFINE_KEY(Language7, 150) \ - DEFINE_KEY(Language8, 151) \ - DEFINE_KEY(Language9, 152) \ - DEFINE_KEY(AltErase, 153) \ - DEFINE_KEY(SysReq, 154) \ - DEFINE_KEY(Cancel, 155) \ - DEFINE_KEY(clear, 156) \ - DEFINE_KEY(Prior, 157) \ - DEFINE_KEY(Return2, 158) \ - DEFINE_KEY(Separator, 159) \ - DEFINE_KEY(Out, 160) \ - DEFINE_KEY(Oper, 161) \ - DEFINE_KEY(ClearAgain, 162) \ - DEFINE_KEY(CRSEL, 163) \ - DEFINE_KEY(EXSEL, 164) \ - DEFINE_KEY(KP_00, 176) \ - DEFINE_KEY(KP_000, 177) \ - DEFINE_KEY(ThousandsSeparator, 178) \ - DEFINE_KEY(DecimalSeparator, 179) \ - DEFINE_KEY(CurrencyUnit, 180) \ - DEFINE_KEY(CurrencySubUnit, 181) \ - DEFINE_KEY(KP_LeftParen, 182) \ - DEFINE_KEY(KP_RightParent, 183) \ - DEFINE_KEY(KP_LeftBrace, 184) \ - DEFINE_KEY(KP_RightBrace, 185) \ - DEFINE_KEY(KP_Tab, 186) \ - DEFINE_KEY(KP_BackSpace, 187) \ - DEFINE_KEY(KP_A, 188) \ - DEFINE_KEY(KP_B, 189) \ - DEFINE_KEY(KP_C, 190) \ - DEFINE_KEY(KP_D, 191) \ - DEFINE_KEY(KP_E, 192) \ - DEFINE_KEY(KP_F, 193) \ - DEFINE_KEY(KP_XOR, 194) \ - DEFINE_KEY(KP_Power, 195) \ - DEFINE_KEY(KP_Percent, 196) \ - DEFINE_KEY(KP_Less, 197) \ - DEFINE_KEY(KP_Greater, 198) \ - DEFINE_KEY(KP_Ampersand, 199) \ - DEFINE_KEY(KP_DoubleAmpersand, 200) \ - DEFINE_KEY(KP_VerticalBar, 201) \ - DEFINE_KEY(KP_DoubleVerticalBar, 202) \ - DEFINE_KEY(KP_Colon, 203) \ - DEFINE_KEY(KP_Hash, 204) \ - DEFINE_KEY(KP_Space, 205) \ - DEFINE_KEY(KP_At, 206) \ - DEFINE_KEY(KP_EXCLAM, 207) \ - DEFINE_KEY(KP_MemStore, 208) \ - DEFINE_KEY(KP_MemRecall, 209) \ - DEFINE_KEY(KP_MemClear, 210) \ - DEFINE_KEY(KP_MemAdd, 211) \ - DEFINE_KEY(KP_MemSubstract, 212) \ - DEFINE_KEY(KP_MemMultiply, 213) \ - DEFINE_KEY(KP_MemDivide, 214) \ - DEFINE_KEY(KP_PlusMinus, 215) \ - DEFINE_KEY(KP_Clear, 216) \ - DEFINE_KEY(KP_ClearEntry, 217) \ - DEFINE_KEY(KP_Binary, 218) \ - DEFINE_KEY(KP_Octal, 219) \ - DEFINE_KEY(KP_Decimal, 220) \ - DEFINE_KEY(KP_Hexadecimal, 221) \ - DEFINE_KEY(LeftControl, 224) \ - DEFINE_KEY(LeftShift, 225) \ - DEFINE_KEY(LeftAlt, 226) \ - DEFINE_KEY(LeftGui, 227) \ - DEFINE_KEY(RightControl, 228) \ - DEFINE_KEY(RightShift, 229) \ - DEFINE_KEY(RightAlt, 230) \ - DEFINE_KEY(RightGui, 231) + \ + DEFINE_KEY(F1, 58) \ + DEFINE_KEY(F2, 59) \ + DEFINE_KEY(F3, 60) \ + DEFINE_KEY(F4, 61) \ + DEFINE_KEY(F5, 62) \ + DEFINE_KEY(F6, 63) \ + DEFINE_KEY(F7, 64) \ + DEFINE_KEY(F8, 65) \ + DEFINE_KEY(F9, 66) \ + DEFINE_KEY(F10, 67) \ + DEFINE_KEY(F11, 68) \ + DEFINE_KEY(F12, 69) \ + DEFINE_KEY(F13, 104) \ + DEFINE_KEY(F14, 105) \ + DEFINE_KEY(F15, 106) \ + DEFINE_KEY(F16, 107) \ + DEFINE_KEY(F17, 108) \ + DEFINE_KEY(F18, 109) \ + DEFINE_KEY(F19, 110) \ + DEFINE_KEY(F20, 111) \ + DEFINE_KEY(F21, 112) \ + DEFINE_KEY(F22, 113) \ + DEFINE_KEY(F23, 114) \ + DEFINE_KEY(F24, 115) \ + \ + DEFINE_KEY(PrintScreen, 70) \ + DEFINE_KEY(ScrollLock, 71) \ + DEFINE_KEY(Pause, 72) \ + DEFINE_KEY(Insert, 73) \ + DEFINE_KEY(Home, 74) \ + DEFINE_KEY(PageUp, 75) \ + DEFINE_KEY(Delete, 76) \ + DEFINE_KEY(End, 77) \ + DEFINE_KEY(PageDown, 78) \ + DEFINE_KEY(Right, 79) \ + DEFINE_KEY(Left, 80) \ + DEFINE_KEY(Down, 81) \ + DEFINE_KEY(Up, 82) \ + \ + DEFINE_KEY(Numlock, 83) \ + \ + DEFINE_KEY(Application, 101) \ + \ + DEFINE_KEY(Execute, 116) \ + DEFINE_KEY(Help, 117) \ + DEFINE_KEY(Menu, 118) \ + DEFINE_KEY(Select, 119) \ + DEFINE_KEY(Stop, 120) \ + DEFINE_KEY(Redo, 121) \ + DEFINE_KEY(Undo, 122) \ + DEFINE_KEY(Cut, 123) \ + DEFINE_KEY(Copy, 124) \ + DEFINE_KEY(Paste, 125) \ + DEFINE_KEY(Find, 126) \ + DEFINE_KEY(Mute, 127) \ + DEFINE_KEY(VolumeUp, 128) \ + DEFINE_KEY(VolumeDown, 129) \ + \ + DEFINE_KEY(AltErase, 153) \ + DEFINE_KEY(SysReq, 154) \ + DEFINE_KEY(Cancel, 155) \ + DEFINE_KEY(Clear, 156) \ + DEFINE_KEY(Prior, 157) \ + DEFINE_KEY(Enter2, 158) \ + DEFINE_KEY(Separator, 159) \ + DEFINE_KEY(Out, 160) \ + DEFINE_KEY(Oper, 161) \ + DEFINE_KEY(ClearAgain, 162) \ + \ + DEFINE_KEY(KeypadA, 188) \ + DEFINE_KEY(KeypadB, 189) \ + DEFINE_KEY(KeypadC, 190) \ + DEFINE_KEY(KeypadD, 191) \ + DEFINE_KEY(KeypadE, 192) \ + DEFINE_KEY(KeypadF, 193) \ + DEFINE_KEY(Keypad0, 98) \ + DEFINE_KEY(Keypad00, 176) \ + DEFINE_KEY(Keypad000, 177) \ + DEFINE_KEY(Keypad1, 89) \ + DEFINE_KEY(Keypad2, 90) \ + DEFINE_KEY(Keypad3, 91) \ + DEFINE_KEY(Keypad4, 92) \ + DEFINE_KEY(Keypad5, 93) \ + DEFINE_KEY(Keypad6, 94) \ + DEFINE_KEY(Keypad7, 95) \ + DEFINE_KEY(Keypad8, 96) \ + DEFINE_KEY(Keypad9, 97) \ + DEFINE_KEY(KeypadDivide, 84) \ + DEFINE_KEY(KeypadMultiply, 85) \ + DEFINE_KEY(KeypadMinus, 86) \ + DEFINE_KEY(KeypadPlus, 87) \ + DEFINE_KEY(KeypadEnter, 88) \ + DEFINE_KEY(KeypadPeroid, 99) \ + DEFINE_KEY(KeypadEquals, 103) \ + DEFINE_KEY(KeypadComma, 133) \ + DEFINE_KEY(KeypadLeftParen, 182) \ + DEFINE_KEY(KeypadRightParen, 183) \ + DEFINE_KEY(KeypadLeftBrace, 184) \ + DEFINE_KEY(KeypadRightBrace, 185) \ + DEFINE_KEY(KeypadTab, 186) \ + DEFINE_KEY(KeypadBackspace, 187) \ + DEFINE_KEY(KeypadXor, 194) \ + DEFINE_KEY(KeypadPower, 195) \ + DEFINE_KEY(KeypadPercent, 196) \ + DEFINE_KEY(KeypadLess, 197) \ + DEFINE_KEY(KeypadGreater, 198) \ + DEFINE_KEY(KeypadAmpersand, 199) \ + DEFINE_KEY(KeypadColon, 203) \ + DEFINE_KEY(KeypadHash, 204) \ + DEFINE_KEY(KeypadSpace, 205) \ + DEFINE_KEY(KeypadClear, 216) \ + \ + DEFINE_KEY(LeftControl, 224) \ + DEFINE_KEY(LeftShift, 225) \ + DEFINE_KEY(LeftAlt, 226) \ + DEFINE_KEY(LeftOS, 227) \ + DEFINE_KEY(RightControl, 228) \ + DEFINE_KEY(RightShift, 229) \ + DEFINE_KEY(RightAlt, 230) \ + DEFINE_KEY(RightOS, 231) #define BLAH_BUTTON_DEFINITIONS \ DEFINE_BTN(None, -1) \ @@ -255,12 +225,6 @@ namespace Blah // maximum number of keys the input will track constexpr int max_keyboard_keys = 512; - - // maximum length of text input that can be received per-frame - constexpr int max_text_input = 256; - - // maximum number of nodes within a virtual input device - constexpr int max_virtual_nodes = 32; } struct ControllerState @@ -293,19 +257,19 @@ namespace Blah float axis[Input::max_controller_axis]; // Timestamp, in milliseconds, since each button was last pressed - uint64_t button_timestamp[Input::max_controller_buttons]; + u64 button_timestamp[Input::max_controller_buttons]; // Timestamp, in milliseconds, since each axis last had a value set - uint64_t axis_timestamp[Input::max_controller_axis]; + u64 axis_timestamp[Input::max_controller_axis]; // The USB Vendor ID - uint16_t vendor; + u16 vendor; // The USB Product ID - uint16_t product; + u16 product; // the Product Version - uint16_t version; + u16 version; }; struct KeyboardState @@ -313,8 +277,8 @@ namespace Blah bool pressed[Input::max_keyboard_keys]; bool down[Input::max_keyboard_keys]; bool released[Input::max_keyboard_keys]; - uint64_t timestamp[Input::max_keyboard_keys]; - char text[Input::max_text_input]; + u64 timestamp[Input::max_keyboard_keys]; + String text; }; struct MouseState @@ -322,7 +286,7 @@ namespace Blah bool pressed[Input::max_mouse_buttons]; bool down[Input::max_mouse_buttons]; bool released[Input::max_mouse_buttons]; - uint64_t timestamp[Input::max_mouse_buttons]; + u64 timestamp[Input::max_mouse_buttons]; Vec2 screen_position; Vec2 draw_position; Vec2 position; diff --git a/include/blah/input/virtual_axis.h b/include/blah/input/virtual_axis.h deleted file mode 100644 index 4a026ae..0000000 --- a/include/blah/input/virtual_axis.h +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once -#include - -namespace Blah -{ - // A virtual controller axis, which can be used to map multiple - // inputs to an axis. Note that you must call `update` every frame! - class VirtualAxis - { - private: - struct KeysNode - { - Key positive = Key::Unknown; - Key negative = Key::Unknown; - - int value = 0; - - void init(Key negative, Key positive); - void update(); - }; - - struct ButtonsNode - { - int gamepad_id = 0; - Button positive = Button::None; - Button negative = Button::None; - - int value = 0; - - void init(int gamepad_id, Button negative, Button positive); - void update(); - }; - - struct AxisNode - { - int gamepad_id = 0; - Axis axis = Axis::None; - float deadzone = 0; - - float value = 0; - - void init(int gamepad_id, Axis axis, float deadzone); - void update(); - }; - - KeysNode m_keys[Input::max_virtual_nodes]; - ButtonsNode m_buttons[Input::max_virtual_nodes]; - AxisNode m_axes[Input::max_virtual_nodes]; - int m_keys_len = 0; - int m_buttons_len = 0; - int m_axes_len = 0; - - float m_press_buffer = 0; - float m_release_buffer = 0; - float m_repeat_delay = 0; - float m_repeat_interval = 0; - - float m_value = 0; - int m_value_i = 0; - float m_last_value = 0; - int m_last_value_i = 0; - bool m_pressed = false; - bool m_released = false; - double m_last_press_time = -1; - double m_last_release_time = -1; - double m_repeat_press_time = -1; - - public: - VirtualAxis& add_keys(Key negative, Key positive); - VirtualAxis& add_buttons(int gamepad_id, Button negative, Button positive); - VirtualAxis& add_axis(int gamepad_id, Axis axis, float deadzone); - VirtualAxis& repeat(float m_repeat_delay, float m_repeat_interval); - VirtualAxis& press_buffer(float duration); - VirtualAxis& release_buffer(float duration); - - void update(); - float value() const { return m_value; } - int value_i() const { return m_value_i; } - float last_value() const { return m_last_value; } - int last_value_i() const { return m_last_value_i; } - bool pressed() const { return m_pressed; } - bool released() const { return m_released; } - void clear_press_buffer() { m_last_press_time = -1; m_pressed = false; } - void clear_release_buffer() { m_last_release_time = -1; m_released = false; } - }; -} \ No newline at end of file diff --git a/include/blah/input/virtual_button.h b/include/blah/input/virtual_button.h deleted file mode 100644 index f0f8ac0..0000000 --- a/include/blah/input/virtual_button.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once -#include - -namespace Blah -{ - class VirtualButton - { - private: - struct KeyNode - { - Key key = Key::Unknown; - - bool down = false; - bool pressed = false; - bool released = false; - - void init(Key key); - void update(); - }; - - struct ButtonNode - { - int gamepad_id = 0; - Button button = Button::None; - - bool down = false; - bool pressed = false; - bool released = false; - - void init(int gamepad_id, Button button); - void update(); - }; - - struct AxisNode - { - int gamepad_id = 0; - Axis axis = Axis::None; - float threshold = 0; - bool greater_than = false; - - bool down = false; - bool pressed = false; - bool released = false; - - void init(int gamepad_id, Axis axis, float threshold, bool greater_than); - void update(); - }; - - KeyNode m_keys[Input::max_virtual_nodes]; - ButtonNode m_buttons[Input::max_virtual_nodes]; - AxisNode m_axes[Input::max_virtual_nodes]; - int m_keys_len = 0; - int m_buttons_len = 0; - int m_axes_len = 0; - - float m_press_buffer = 0; - float m_release_buffer = 0; - float m_repeat_delay = 0; - float m_repeat_interval = 0; - - bool m_down = false; - bool m_pressed = false; - bool m_released = false; - double m_last_press_time = -1; - double m_last_release_time = -1; - double m_repeat_press_time = -1; - - public: - VirtualButton& add_key(Key key); - VirtualButton& add_button(int gamepad_id, Button button); - VirtualButton& add_axis(int gamepad_id, Axis axis, float threshold, bool greater_than); - VirtualButton& repeat(float m_repeat_delay, float m_repeat_interval); - VirtualButton& press_buffer(float duration); - VirtualButton& release_buffer(float duration); - - void update(); - bool down() const { return m_down; } - bool pressed() const { return m_pressed; } - bool released() const { return m_released; } - void clear_press_buffer() { m_last_press_time = -1; m_pressed = false; } - void clear_release_buffer() { m_last_release_time = -1; m_released = false; } - }; -} \ No newline at end of file diff --git a/include/blah/input/virtual_stick.h b/include/blah/input/virtual_stick.h deleted file mode 100644 index a0bb0a8..0000000 --- a/include/blah/input/virtual_stick.h +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once -#include -#include -#include - -namespace Blah -{ - // A virtual controller stick, which can be used to map multiple - // inputs to a stick. Note that you must call `update` every frame! - class VirtualStick - { - private: - struct KeysNode - { - Key left; - Key right; - Key up; - Key down; - - Point value; - - void init(Key left, Key right, Key up, Key down); - void update(); - }; - - struct ButtonsNode - { - int gamepad_id; - Button left; - Button right; - Button up; - Button down; - - Point value; - - void init(int gamepad_id, Button left, Button right, Button up, Button down); - void update(); - }; - - struct AxesNode - { - int gamepad_id; - Axis horizontal; - Axis vertical; - float deadzone; - - Vec2 value; - - void init(int gamepad_id, Axis horizontal, Axis vertical, float deadzone); - void update(); - }; - - KeysNode m_keys[Input::max_virtual_nodes]; - ButtonsNode m_buttons[Input::max_virtual_nodes]; - AxesNode m_axes[Input::max_virtual_nodes]; - int m_keys_len = 0; - int m_buttons_len = 0; - int m_axes_len = 0; - - float m_press_buffer = 0; - float m_release_buffer = 0; - float m_repeat_delay = 0; - float m_repeat_interval = 0; - - Vec2 m_value = Vec2(); - Point m_value_i = Point(); - Vec2 m_last_value = Vec2(); - Point m_last_value_i = Point(); - bool m_pressed = false; - bool m_released = false; - - float m_i_deadzone; - double m_last_press_time = -1; - double m_last_release_time = -1; - double m_repeat_press_time = -1; - - public: - VirtualStick(); - VirtualStick(float iDeadzone); - VirtualStick& add_keys(Key left, Key right, Key up, Key down); - VirtualStick& add_buttons(int gamepad_id, Button left, Button right, Button up, Button down); - VirtualStick& add_axes(int gamepad_id, Axis horizontal, Axis vertical, float deadzone); - VirtualStick& repeat(float m_repeat_delay, float m_repeat_interval); - VirtualStick& press_buffer(float duration); - VirtualStick& release_buffer(float duration); - - void update(); - const Vec2& value() const { return m_value; } - const Point& value_i() const { return m_value_i; } - const Vec2& last_value() const { return m_last_value; } - const Point& last_value_i() const { return m_last_value_i; } - bool pressed() const { return m_pressed; } - bool released() const { return m_released; } - void clear_press_buffer() { m_last_press_time = 0; } - void clear_release_buffer() { m_last_release_time = 0; } - }; -} \ No newline at end of file diff --git a/include/blah/math/calc.h b/include/blah/math/calc.h index 252ed39..68f6c0f 100644 --- a/include/blah/math/calc.h +++ b/include/blah/math/calc.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include namespace Blah @@ -27,10 +27,6 @@ namespace Blah Vec2 approach(const Vec2& t, const Vec2& target, float delta); - float clamp(float t, float min, float max); - - int clamp_int(int t, int min, int max); - float map(float t, float old_min, float old_max, float new_min, float new_max); float clamped_map(float t, float old_min, float old_max, float new_min, float new_max); @@ -43,6 +39,9 @@ namespace Blah float abs(float x); + template + T clamp(T value, T min, T max) { return value < min ? min : (value > max ? max : value); } + template T min(T a, U b) { return (T)(a < b ? a : b); } diff --git a/include/blah/math/color.h b/include/blah/math/color.h index 3d057d3..e5a8e37 100644 --- a/include/blah/math/color.h +++ b/include/blah/math/color.h @@ -1,38 +1,41 @@ #pragma once -#include +#include #include namespace Blah { + struct Vec3; struct Vec4; struct Color { - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; + u8 r; + u8 g; + u8 b; + u8 a; Color(); Color(int rgb); Color(int rgb, float alpha); - Color(uint8_t r, uint8_t g, uint8_t b); - Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a); + Color(u8 r, u8 g, u8 b); + Color(u8 r, u8 g, u8 b, u8 a); + Color(const Vec3& vec3); + Color(const Vec3& vec3, float alpha); Color(const Vec4& vec4); // Parses a Hex string in the format of "#00000000" or "0x00000000" or "00000000" - Color(const char* hexCstr); + Color(const String& hex_string); // Premultiplies the Color void premultiply(); + // Returns an RGBA hex string of the color + String to_hex_rgba() const; + // Sets a Hex string to the given buffer, in the format of RRGGBBAA // The buffer must be at least 8 bytes long void to_hex_rgba(char* buffer) const; - // Returns an RGBA hex string of the color - String to_hex_rgba() const; - // Sets a Hex string to the given buffer, in the format of RRGGBB // The buffer must be at least 6 bytes long void to_hex_rgb(char* buffer) const; @@ -40,17 +43,17 @@ namespace Blah // Returns an RGB hex string of the color String to_hex_rgb() const; - // Convers the Color to a uint32_t - uint32_t to_rgba() const; + // Convers the Color to a u32 + u32 to_rgba() const; // Converts the Color to a Vec4 Vec4 to_vec4() const; // Returns a RGBA Color representation of the integer value - static Color from_rgba(uint32_t value); + static Color from_rgba(u32 value); // Returns a RGB Color representation of the integer value, with Alpha = 255 - static Color from_rgb(uint32_t value); + static Color from_rgb(u32 value); // Lerps between two colors static Color lerp(Color a, Color b, float amount); diff --git a/include/blah/math/ease.h b/include/blah/math/ease.h index f2cdf24..5af1a0c 100644 --- a/include/blah/math/ease.h +++ b/include/blah/math/ease.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include namespace Blah { @@ -8,6 +8,7 @@ namespace Blah enum class Easers { + Linear, QuadIn, QuadOut, QuadInOut, CubeIn, CubeOut, CubeInOut, QuartIn, QuartOut, QuartInOut, @@ -28,43 +29,41 @@ namespace Blah For previews go here: https://easings.net/ */ - inline float linear(float t) + constexpr float linear(float t) { return t; } - inline float quad_in(float t) + constexpr float quad_in(float t) { return t * t; } - inline float quad_out(float t) + constexpr float quad_out(float t) { return -(t * (t - 2)); } - inline float quad_in_out(float t) + constexpr float quad_in_out(float t) { if (t < 0.5f) return 2 * t * t; else - { return (-2 * t * t) + (4 * t) - 1; - } } - inline float cube_in(float t) + constexpr float cube_in(float t) { return t * t * t; } - inline float cube_out(float t) + constexpr float cube_out(float t) { float f = (t - 1); return f * f * f + 1; } - inline float cube_in_out(float t) + constexpr float cube_in_out(float t) { if (t < 0.5f) return 4 * t * t * t; @@ -75,18 +74,18 @@ namespace Blah } } - inline float quart_in(float t) + constexpr float quart_in(float t) { return t * t * t * t; } - inline float quart_out(float t) + constexpr float quart_out(float t) { float f = (t - 1); return f * f * f * (1 - t) + 1; } - inline float quart_in_out(float t) + constexpr float quart_in_out(float t) { if (t < 0.5f) return 8 * t * t * t * t; @@ -97,18 +96,18 @@ namespace Blah } } - inline float quint_in(float t) + constexpr float quint_in(float t) { return t * t * t * t * t; } - inline float quint_out(float t) + constexpr float quint_out(float t) { float f = (t - 1); return f * f * f * f * f + 1; } - inline float quint_in_out(float t) + constexpr float quint_in_out(float t) { if (t < 0.5f) return 16 * t * t * t * t * t; @@ -216,7 +215,7 @@ namespace Blah } } - inline float bounce_out(float t) + constexpr float bounce_out(float t) { if (t < 4 / 11.0f) return (121 * t * t) / 16.0f; @@ -228,12 +227,12 @@ namespace Blah return (54 / 5.0f * t * t) - (513 / 25.0f * t) + 268 / 25.0f; } - inline float bounce_in(float t) + constexpr float bounce_in(float t) { return 1 - bounce_out(1 - t); } - inline float bounce_in_out(float t) + constexpr float bounce_in_out(float t) { if (t < 0.5f) return 0.5f * bounce_in(t * 2); @@ -245,6 +244,8 @@ namespace Blah { switch (e) { + case Easers::Linear: return &linear; + case Easers::CubeIn: return &cube_in; case Easers::CubeOut: return &cube_out; case Easers::CubeInOut: return &cube_in_out; @@ -296,6 +297,7 @@ namespace Blah { switch (e) { + case Easers::Linear: return "Linear"; case Easers::CubeIn: return "CubeIn"; case Easers::CubeOut: return "CubeOut"; case Easers::CubeInOut: return "CubeInOut"; diff --git a/include/blah/math/line.h b/include/blah/math/line.h index 14e2c50..e36fb03 100644 --- a/include/blah/math/line.h +++ b/include/blah/math/line.h @@ -10,7 +10,7 @@ namespace Blah Vec2 a; Vec2 b; - Line() {} + Line() = default; Line(float x0, float y0, float x1, float y1); Line(const Vec2& start, const Vec2& end); diff --git a/include/blah/math/stopwatch.h b/include/blah/math/stopwatch.h index 1ea0b2a..69260b2 100644 --- a/include/blah/math/stopwatch.h +++ b/include/blah/math/stopwatch.h @@ -1,5 +1,5 @@ #pragma once -#include +#include namespace Blah { @@ -8,9 +8,9 @@ namespace Blah public: Stopwatch(); void reset(); - uint64_t microseconds(); - uint64_t milliseconds(); + u64 microseconds(); + u64 milliseconds(); private: - uint64_t start_time; + u64 start_time; }; } \ No newline at end of file diff --git a/include/blah/streams/bufferstream.h b/include/blah/streams/bufferstream.h index 4a0303e..3cf5965 100644 --- a/include/blah/streams/bufferstream.h +++ b/include/blah/streams/bufferstream.h @@ -12,9 +12,9 @@ namespace Blah BufferStream& operator=(BufferStream&& bs) noexcept; ~BufferStream(); - virtual int64_t length() const override { return m_length; } - virtual int64_t position() const override { return m_position; } - virtual int64_t seek(int64_t seekTo) override { return m_position = (seekTo < 0 ? 0 : (seekTo > m_length ? m_length : seekTo)); } + virtual i64 length() const override { return m_length; } + virtual i64 position() const override { return m_position; } + virtual i64 seek(i64 seekTo) override { return m_position = (seekTo < 0 ? 0 : (seekTo > m_length ? m_length : seekTo)); } virtual bool is_open() const override { return m_buffer != nullptr; } virtual bool is_readable() const override { return true; } virtual bool is_writable() const override { return true; } @@ -25,13 +25,13 @@ namespace Blah const char* data() const { return m_buffer; } protected: - virtual int64_t read_into(void* ptr, int64_t length) override; - virtual int64_t write_from(const void* ptr, int64_t length) override; + virtual i64 read_into(void* ptr, i64 length) override; + virtual i64 write_from(const void* ptr, i64 length) override; private: char* m_buffer; - int64_t m_capacity; - int64_t m_length; - int64_t m_position; + i64 m_capacity; + i64 m_length; + i64 m_position; }; } \ No newline at end of file diff --git a/include/blah/streams/filestream.h b/include/blah/streams/filestream.h index 093ffae..56da825 100644 --- a/include/blah/streams/filestream.h +++ b/include/blah/streams/filestream.h @@ -8,25 +8,25 @@ namespace Blah { public: FileStream(); - FileStream(const char* path, FileMode mode = FileMode::ReadWrite); + FileStream(const FilePath& path, FileMode mode = FileMode::ReadWrite); FileStream(FileStream&& fs) noexcept; FileStream& operator=(FileStream&& fs) noexcept; ~FileStream(); - virtual int64_t length() const override; - virtual int64_t position() const override; - virtual int64_t seek(int64_t seekTo) override; - virtual bool is_open() const override { return m_handle != nullptr; } - virtual bool is_readable() const override { return m_handle != nullptr && (m_mode == FileMode::ReadWrite || m_mode == FileMode::Read); } - virtual bool is_writable() const override { return m_handle != nullptr && (m_mode == FileMode::ReadWrite || m_mode == FileMode::Write); } + virtual i64 length() const override; + virtual i64 position() const override; + virtual i64 seek(i64 seekTo) override; + virtual bool is_open() const override; + virtual bool is_readable() const override; + virtual bool is_writable() const override; virtual void close() override; protected: - virtual int64_t read_into(void* ptr, int64_t length) override; - virtual int64_t write_from(const void* ptr, int64_t length) override; + virtual i64 read_into(void* ptr, i64 length) override; + virtual i64 write_from(const void* ptr, i64 length) override; private: - FileMode m_mode; - void* m_handle; + FileMode m_mode; + void* m_handle; }; } \ No newline at end of file diff --git a/include/blah/streams/memorystream.h b/include/blah/streams/memorystream.h index 2fccf81..ffcbe24 100644 --- a/include/blah/streams/memorystream.h +++ b/include/blah/streams/memorystream.h @@ -7,14 +7,14 @@ namespace Blah { public: MemoryStream(); - MemoryStream(char* data, int64_t length); + MemoryStream(char* data, i64 length); MemoryStream(MemoryStream&& ms) noexcept; MemoryStream& operator=(MemoryStream&& ms) noexcept; ~MemoryStream() { m_data = nullptr; m_length = m_position = 0; } - virtual int64_t length() const override { return m_length; } - virtual int64_t position() const override { return m_position; } - virtual int64_t seek(int64_t seekTo) override { return m_position = (seekTo < 0 ? 0 : (seekTo > m_length ? m_length : seekTo)); } + virtual i64 length() const override { return m_length; } + virtual i64 position() const override { return m_position; } + virtual i64 seek(i64 seekTo) override { return m_position = (seekTo < 0 ? 0 : (seekTo > m_length ? m_length : seekTo)); } virtual bool is_open() const override { return m_data != nullptr; } virtual bool is_readable() const override { return true; } virtual bool is_writable() const override { return true; } @@ -24,12 +24,12 @@ namespace Blah const char* data() const { return m_data; } protected: - virtual int64_t read_into(void* ptr, int64_t length) override; - virtual int64_t write_from(const void* ptr, int64_t length) override; + virtual i64 read_into(void* ptr, i64 length) override; + virtual i64 write_from(const void* ptr, i64 length) override; private: char* m_data; - int64_t m_length; - int64_t m_position; + i64 m_length; + i64 m_position; }; } \ No newline at end of file diff --git a/include/blah/streams/stream.h b/include/blah/streams/stream.h index 369dade..5aeb205 100644 --- a/include/blah/streams/stream.h +++ b/include/blah/streams/stream.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include #include @@ -16,13 +16,13 @@ namespace Blah virtual ~Stream() = default; // returns the length of the stream - virtual int64_t length() const = 0; + virtual i64 length() const = 0; // returns the position of the stream - virtual int64_t position() const = 0; + virtual i64 position() const = 0; // seeks the position of the stream - virtual int64_t seek(int64_t seek_to) = 0; + virtual i64 seek(i64 seek_to) = 0; // returns true of the stream is open virtual bool is_open() const = 0; @@ -36,11 +36,11 @@ namespace Blah // closes the stream virtual void close() = 0; - // pipes the contents of this tream to another stream - int64_t pipe(Stream& to, int64_t length); + // pipes the contents of this stream to another stream + i64 pipe(Stream& to, i64 length); // reads the amount of bytes into the given buffer, and returns the amount read - int64_t read(void* buffer, int64_t length) { return read_into(buffer, length); } + i64 read(void* buffer, i64 length) { return read_into(buffer, length); } // reads a string. if length < 0, assumes null-terminated String read_string(int length = -1); @@ -67,21 +67,21 @@ namespace Blah } // writes the amount of bytes to the stream from the given buffer, and returns the amount written - int64_t write(const void* buffer, int64_t length); + i64 write(const void* buffer, i64 length); // writes the contents of a string to the stream - int64_t write(const String& string); + i64 write(const String& string); // writes a number template::value, T>::type> - int64_t write(const T& value) + i64 write(const T& value) { return write(value, Endian::Little); } // writes a number template::value, T>::type> - int64_t write(const T& value, Endian endian) + i64 write(const T& value, Endian endian) { T writing = value; @@ -93,9 +93,9 @@ namespace Blah protected: // reads from the stream into the given buffer, and returns the number of bytes read - virtual int64_t read_into(void* buffer, int64_t length) = 0; + virtual i64 read_into(void* buffer, i64 length) = 0; // writes from the stream from the given buffer, and returns the number of bytes written - virtual int64_t write_from(const void* buffer, int64_t length) = 0; + virtual i64 write_from(const void* buffer, i64 length) = 0; }; } \ No newline at end of file diff --git a/src/containers/str.cpp b/src/containers/str.cpp index cfdb20c..da7929e 100644 --- a/src/containers/str.cpp +++ b/src/containers/str.cpp @@ -44,7 +44,7 @@ void Str::reserve(int size) { char* local = data(); m_buffer = new char[m_capacity]; - strncpy(m_buffer, local, m_local_size); + memcpy(m_buffer, local, m_local_size); m_buffer[m_local_size] = '\0'; } // expand from empty buffer @@ -72,9 +72,9 @@ void Str::set_length(int len) m_length = len; } -uint32_t Str::utf8_at(int index) const +u32 Str::utf8_at(int index) const { - uint32_t charcode = 0; + u32 charcode = 0; int t = (unsigned char)(this->operator[](index++)); if (t < 128) @@ -124,7 +124,7 @@ Str& Str::append(char c) return *this; } -Str& Str::append(uint32_t c) +Str& Str::append(u32 c) { // one octet if (c < 0x80) @@ -210,21 +210,21 @@ Str& Str::append_fmt(const char* fmt, ...) return *this; } -Str& Str::append_utf16(const uint16_t* start, const uint16_t* end, bool swap_endian) +Str& Str::append_utf16(const u16* start, const u16* end, bool swap_endian) { // converts utf16 into utf8 // more info: https://en.wikipedia.org/wiki/UTF-16#Description - const uint16_t surrogate_min = 0xd800u; - const uint16_t surrogate_max = 0xdbffu; + const u16 surrogate_min = 0xd800u; + const u16 surrogate_max = 0xdbffu; while (start != end) { - uint16_t next = (*start++); + u16 next = (*start++); if (swap_endian) next = ((next & 0xff) << 8 | ((next & 0xff00) >> 8)); - uint32_t cp = 0xffff & next; + u32 cp = 0xffff & next; if ((cp >= surrogate_min && cp <= surrogate_max)) { @@ -232,7 +232,7 @@ Str& Str::append_utf16(const uint16_t* start, const uint16_t* end, bool swap_end if (swap_endian) next = ((next & 0xff) << 8 | ((next & 0xff00) >> 8)); - uint32_t trail = 0xffff & next; + u32 trail = 0xffff & next; cp = (cp << 10) + trail + 0x10000u - (surrogate_min << 10) - 0xdc00u; } diff --git a/src/core/app.cpp b/src/core/app.cpp index 5ea0bb3..d4c059c 100644 --- a/src/core/app.cpp +++ b/src/core/app.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -35,8 +35,8 @@ namespace Config app_config; bool app_is_running = false; bool app_is_exiting = false; - uint64_t time_last; - uint64_t time_accumulator = 0; + u64 time_last; + u64 time_accumulator = 0; void app_iterate() { @@ -46,9 +46,9 @@ namespace // update at a fixed timerate // TODO: allow a non-fixed step update? { - uint64_t time_target = (uint64_t)((1.0 / app_config.target_framerate) * Time::ticks_per_second); - uint64_t time_curr = PlatformBackend::ticks(); - uint64_t time_diff = time_curr - time_last; + u64 time_target = (u64)((1.0 / app_config.target_framerate) * Time::ticks_per_second); + u64 time_curr = PlatformBackend::ticks(); + u64 time_diff = time_curr - time_last; time_last = time_curr; time_accumulator += time_diff; @@ -66,7 +66,7 @@ namespace // Do not allow us to fall behind too many updates // (otherwise we'll get spiral of death) - uint64_t time_maximum = app_config.max_updates * time_target; + u64 time_maximum = app_config.max_updates * time_target; if (time_accumulator > time_maximum) time_accumulator = time_maximum; @@ -300,7 +300,7 @@ namespace return App::draw_height(); } - virtual void clear(Color color, float depth, uint8_t stencil, ClearMask mask) override + virtual void clear(Color color, float depth, u8 stencil, ClearMask mask) override { GraphicsBackend::clear_backbuffer(color, depth, stencil, mask); } diff --git a/src/core/log.cpp b/src/core/common.cpp similarity index 93% rename from src/core/log.cpp rename to src/core/common.cpp index 6913ec2..152a00b 100644 --- a/src/core/log.cpp +++ b/src/core/common.cpp @@ -1,11 +1,11 @@ -#include +#include #include #include // for logging methods #include // for sprintf using namespace Blah; -void Log::print(const char* format, ...) +void Log::info(const char* format, ...) { char msg[BLAH_MESSAGE]; va_list ap; diff --git a/src/core/filesystem.cpp b/src/core/filesystem.cpp index e88f52d..6b80adf 100644 --- a/src/core/filesystem.cpp +++ b/src/core/filesystem.cpp @@ -1,4 +1,5 @@ #include +#include #include "../internal/platform_backend.h" using namespace Blah; @@ -13,6 +14,11 @@ bool File::remove(const FilePath& path) return PlatformBackend::file_delete(path.cstr()); } +FileStream File::open(const FilePath& path , FileMode mode) +{ + return FileStream(path, mode); +} + bool Directory::create(const FilePath& path) { return PlatformBackend::dir_create(path.cstr()); diff --git a/src/core/time.cpp b/src/core/time.cpp index a61938a..2a61d8d 100644 --- a/src/core/time.cpp +++ b/src/core/time.cpp @@ -10,8 +10,8 @@ namespace } } -uint64_t Time::ticks = 0; -uint64_t Time::previous_ticks = 0; +u64 Time::ticks = 0; +u64 Time::previous_ticks = 0; double Time::seconds = 0; double Time::previous_seconds = 0; float Time::delta = 0; diff --git a/src/drawing/batch.cpp b/src/graphics/batch.cpp similarity index 97% rename from src/drawing/batch.cpp rename to src/graphics/batch.cpp index cddac61..95cdf73 100644 --- a/src/drawing/batch.cpp +++ b/src/graphics/batch.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -15,9 +15,7 @@ namespace // TODO: // This shader needs to be graphics API agnostic -#ifdef BLAH_USE_OPENGL - - const ShaderData shader_data = { + const ShaderData opengl_shader_data = { // vertex shader #ifdef __EMSCRIPTEN__ "#version 300 es\n" @@ -62,8 +60,6 @@ namespace "}" }; -#elif BLAH_USE_D3D11 - const char* d3d11_shader = "" "cbuffer constants : register(b0)\n" "{\n" @@ -110,7 +106,7 @@ namespace " input.mask.z * input.color;\n" "}\n"; - const ShaderData shader_data = { + const ShaderData d3d11_shader_data = { d3d11_shader, d3d11_shader, { @@ -121,10 +117,6 @@ namespace } }; -#else - const ShaderData shader_data; -#endif - const VertexFormat format = VertexFormat( { { 0, VertexType::Float2, false }, @@ -164,12 +156,12 @@ namespace { \ m_batch.elements += 2; \ auto _i = m_indices.expand(6); \ - *_i++ = (uint32_t)m_vertices.size() + 0; \ - *_i++ = (uint32_t)m_vertices.size() + 1; \ - *_i++ = (uint32_t)m_vertices.size() + 2; \ - *_i++ = (uint32_t)m_vertices.size() + 0; \ - *_i++ = (uint32_t)m_vertices.size() + 2; \ - *_i++ = (uint32_t)m_vertices.size() + 3; \ + *_i++ = (u32)m_vertices.size() + 0; \ + *_i++ = (u32)m_vertices.size() + 1; \ + *_i++ = (u32)m_vertices.size() + 2; \ + *_i++ = (u32)m_vertices.size() + 0; \ + *_i++ = (u32)m_vertices.size() + 2; \ + *_i++ = (u32)m_vertices.size() + 3; \ Vertex* _v = m_vertices.expand(4); \ MAKE_VERTEX(_v, m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash); _v++; \ MAKE_VERTEX(_v, m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash); _v++; \ @@ -181,9 +173,9 @@ namespace { \ m_batch.elements += 1; \ auto* _i = m_indices.expand(3); \ - *_i++ = (uint32_t)m_vertices.size() + 0; \ - *_i++ = (uint32_t)m_vertices.size() + 1; \ - *_i++ = (uint32_t)m_vertices.size() + 2; \ + *_i++ = (u32)m_vertices.size() + 0; \ + *_i++ = (u32)m_vertices.size() + 1; \ + *_i++ = (u32)m_vertices.size() + 2; \ Vertex* _v = m_vertices.expand(3); \ MAKE_VERTEX(_v, m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash); _v++; \ MAKE_VERTEX(_v, m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash); _v++; \ @@ -384,7 +376,12 @@ void Batch::render(const FrameBufferRef& target, const Mat4x4& matrix) m_mesh = Mesh::create(); if (!m_default_shader) - m_default_shader = Shader::create(shader_data); + { + if (App::renderer() == Renderer::OpenGL) + m_default_shader = Shader::create(opengl_shader_data); + else if (App::renderer() == Renderer::D3D11) + m_default_shader = Shader::create(d3d11_shader_data); + } if (!m_default_material) m_default_material = Material::create(m_default_shader); @@ -423,8 +420,8 @@ void Batch::render_single_batch(RenderPass& pass, const DrawBatch& b, const Mat4 pass.blend = b.blend; pass.has_scissor = b.scissor.w >= 0 && b.scissor.h >= 0; pass.scissor = b.scissor; - pass.index_start = (int64_t)b.offset * 3; - pass.index_count = (int64_t)b.elements * 3; + pass.index_start = (i64)b.offset * 3; + pass.index_count = (i64)b.elements * 3; pass.perform(); } @@ -1046,7 +1043,7 @@ void Batch::str(const SpriteFont& font, const String& text, const Vec2& pos, Tex else offset.y = (font.ascent + font.descent + font.height() - font.height_of(text)) * 0.5f; - uint32_t last = 0; + u32 last = 0; for (int i = 0, l = text.length(); i < l; i++) { if (text[i] == '\n') @@ -1067,7 +1064,7 @@ void Batch::str(const SpriteFont& font, const String& text, const Vec2& pos, Tex } // get the character - uint32_t next = text.utf8_at(i); + u32 next = text.utf8_at(i); const auto& ch = font[next]; // draw it, if the subtexture exists diff --git a/src/graphics/framebuffer.cpp b/src/graphics/framebuffer.cpp index 4ed290b..19d7e0e 100644 --- a/src/graphics/framebuffer.cpp +++ b/src/graphics/framebuffer.cpp @@ -12,7 +12,7 @@ FrameBufferRef FrameBuffer::create(int width, int height) FrameBufferRef FrameBuffer::create(int width, int height, const TextureFormat* attachments, int attachment_count) { BLAH_ASSERT(width > 0 && height > 0, "FrameBuffer width and height must be larger than 0"); - BLAH_ASSERT(attachment_count <= BLAH_ATTACHMENTS, "Exceeded maximum attachment count"); + BLAH_ASSERT(attachment_count <= Attachments::MaxCapacity, "Exceeded maximum attachment count"); BLAH_ASSERT(attachment_count > 0, "At least one attachment must be provided"); int color_count = 0; @@ -29,7 +29,7 @@ FrameBufferRef FrameBuffer::create(int width, int height, const TextureFormat* a } BLAH_ASSERT(depth_count <= 1, "FrameBuffer can only have 1 Depth/Stencil Texture"); - BLAH_ASSERT(color_count <= BLAH_ATTACHMENTS - 1, "Exceeded maximum Color attachment count"); + BLAH_ASSERT(color_count <= Attachments::MaxCapacity - 1, "Exceeded maximum Color attachment count"); return GraphicsBackend::create_framebuffer(width, height, attachments, attachment_count); } diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index 2616164..07aa4a7 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include using namespace Blah; @@ -277,7 +277,7 @@ TextureSampler Material::get_sampler(int slot, int index) const return TextureSampler(); } -void Material::set_value(const char* name, const float* value, int64_t length) +void Material::set_value(const char* name, const float* value, i64 length) { BLAH_ASSERT(m_shader, "Material Shader is invalid"); BLAH_ASSERT(length >= 0, "Length must be >= 0"); @@ -311,7 +311,7 @@ void Material::set_value(const char* name, const float* value, int64_t length) Log::warn("No Uniform '%s' exists", name); } -const float* Material::get_value(const char* name, int64_t* length) const +const float* Material::get_value(const char* name, i64* length) const { BLAH_ASSERT(m_shader, "Material Shader is invalid"); diff --git a/src/graphics/mesh.cpp b/src/graphics/mesh.cpp index dc7832a..59fe7a1 100644 --- a/src/graphics/mesh.cpp +++ b/src/graphics/mesh.cpp @@ -22,6 +22,7 @@ VertexFormat::VertexFormat(std::initializer_list attributes, in { switch (it.type) { + case VertexType::None: break; case VertexType::Float: stride += 4; break; case VertexType::Float2: stride += 8; break; case VertexType::Float3: stride += 12; break; diff --git a/src/graphics/renderpass.cpp b/src/graphics/renderpass.cpp index 61bb766..cbd6433 100644 --- a/src/graphics/renderpass.cpp +++ b/src/graphics/renderpass.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "../internal/graphics_backend.h" using namespace Blah; @@ -38,7 +38,7 @@ void RenderPass::perform() } // Validate Index Count - int64_t index_count = pass.mesh->index_count(); + i64 index_count = pass.mesh->index_count(); if (pass.index_start + pass.index_count > index_count) { Log::warn( @@ -54,7 +54,7 @@ void RenderPass::perform() } // Validate Instance Count - int64_t instance_count = pass.mesh->instance_count(); + i64 instance_count = pass.mesh->instance_count(); if (pass.instance_count > instance_count) { Log::warn( diff --git a/src/drawing/spritefont.cpp b/src/graphics/spritefont.cpp similarity index 68% rename from src/drawing/spritefont.cpp rename to src/graphics/spritefont.cpp index 86b6d0a..3c75ed9 100644 --- a/src/drawing/spritefont.cpp +++ b/src/graphics/spritefont.cpp @@ -1,10 +1,19 @@ -#include +#include #include #include -#include +#include using namespace Blah; +SpriteFont::CharRange::CharRange() + : from(0), to(0) {} +SpriteFont::CharRange::CharRange(Codepoint single) + : from(single), to(single) {} +SpriteFont::CharRange::CharRange(Codepoint from, Codepoint to) + : from(from), to(to) {} + +const SpriteFont::CharSet SpriteFont::CharRange::ASCII = SpriteFont::CharSet({ CharRange(32, 128) }); + SpriteFont::SpriteFont() { size = 0; @@ -13,27 +22,24 @@ SpriteFont::SpriteFont() line_gap = 0; } -const uint32_t ascii[]{ 32, 128, 0 }; -const uint32_t* SpriteFont::ASCII = ascii; - -SpriteFont::SpriteFont(const char* file, float size) +SpriteFont::SpriteFont(const FilePath& file, float size) { - build(file, size, ASCII); + rebuild(file, size, CharRange::ASCII); } -SpriteFont::SpriteFont(const char* file, float size, const uint32_t* charset) +SpriteFont::SpriteFont(const FilePath& file, float size, const CharSet& charset) { - build(file, size, charset); + rebuild(file, size, charset); } SpriteFont::SpriteFont(const Font& font, float size) { - build(font, size, ASCII); + rebuild(font, size, CharRange::ASCII); } -SpriteFont::SpriteFont(const Font& font, float size, const uint32_t* charset) +SpriteFont::SpriteFont(const Font& font, float size, const CharSet& charset) { - build(font, size, charset); + rebuild(font, size, charset); } SpriteFont::SpriteFont(SpriteFont&& src) noexcept @@ -79,7 +85,7 @@ float SpriteFont::width_of(const String& text) const float width = 0; float line_width = 0; - uint32_t last; + Codepoint last = 0; for (int i = 0; i < text.length(); i ++) { if (text[i] == '\n') @@ -116,7 +122,7 @@ float SpriteFont::width_of_line(const String& text, int start) const float width = 0; - uint32_t last; + Codepoint last = 0; for (int i = start; i < text.length(); i ++) { if (text[i] == '\n') @@ -157,16 +163,16 @@ float SpriteFont::height_of(const String& text) const return height - line_gap; } -void SpriteFont::build(const char* file, float sz, const uint32_t* charset) +void SpriteFont::rebuild(const FilePath& file, float sz, const CharSet& charset) { dispose(); Font font(file); if (font.is_valid()) - build(font, sz, charset); + rebuild(font, sz, charset); } -void SpriteFont::build(const Font& font, float size, const uint32_t* charset) +void SpriteFont::rebuild(const Font& font, float size, const CharSet& charset) { dispose(); @@ -184,14 +190,13 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset) packer.max_size = 8192; packer.power_of_two = true; - std::unordered_map glyphs; + std::unordered_map glyphs; Vector buffer; - auto ranges = charset; - while (*ranges != 0) + for (auto& range : charset) { - auto from = *ranges; - auto to = *(ranges + 1); + auto from = range.from; + auto to = range.to + 1; BLAH_ASSERT(to >= from, "Charset Range must be in pairs of [min,max]"); @@ -204,7 +209,7 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset) glyphs[i] = glyph; // add character - Font::Char ch = font.get_character(glyph, scale); + auto ch = font.get_character(glyph, scale); m_characters[i].advance = ch.advance; m_characters[i].offset = Vec2(ch.offset_x, ch.offset_y); @@ -218,8 +223,6 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset) packer.add(i, ch.width, ch.height, buffer.data()); } } - - ranges += 2; } buffer.clear(); @@ -229,9 +232,9 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset) m_atlas.push_back(Texture::create(it)); // add character subtextures - for (auto& it : packer.entries) + for (auto& it : packer.entries()) if (!it.empty) - m_characters[(uint32_t)it.id].subtexture = Subtexture(m_atlas[it.page], it.packed, it.frame); + m_characters[(Codepoint)it.id].subtexture = Subtexture(m_atlas[it.page], it.packed, it.frame); // add kerning for (auto a = glyphs.begin(); a != glyphs.end(); a++) @@ -243,9 +246,9 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset) } } -float SpriteFont::get_kerning(uint32_t codepoint0, uint32_t codepoint1) const +float SpriteFont::get_kerning(Codepoint codepoint0, Codepoint codepoint1) const { - uint64_t index = ((uint64_t)codepoint0 << 32) | codepoint1; + u64 index = ((u64)codepoint0 << 32) | codepoint1; auto it = m_kerning.find(index); if (it != m_kerning.end()) @@ -253,9 +256,9 @@ float SpriteFont::get_kerning(uint32_t codepoint0, uint32_t codepoint1) const return 0.0f; } -void SpriteFont::set_kerning(uint32_t codepoint0, uint32_t codepoint1, float value) +void SpriteFont::set_kerning(Codepoint codepoint0, Codepoint codepoint1, float value) { - uint64_t index = ((uint64_t)codepoint0 << 32) | codepoint1; + u64 index = ((u64)codepoint0 << 32) | codepoint1; if (value == 0) { @@ -267,7 +270,12 @@ void SpriteFont::set_kerning(uint32_t codepoint0, uint32_t codepoint1, float val } } -const SpriteFont::Character& SpriteFont::get_character(uint32_t codepoint) const +SpriteFont::Character& SpriteFont::get_character(Codepoint codepoint) +{ + return m_characters[codepoint]; +} + +const SpriteFont::Character& SpriteFont::get_character(Codepoint codepoint) const { static const Character empty; auto it = m_characters.find(codepoint); @@ -276,7 +284,12 @@ const SpriteFont::Character& SpriteFont::get_character(uint32_t codepoint) const return empty; } -const SpriteFont::Character& SpriteFont::operator[](uint32_t codepoint) const +SpriteFont::Character& SpriteFont::operator[](Codepoint codepoint) +{ + return m_characters[codepoint]; +} + +const SpriteFont::Character& SpriteFont::operator[](Codepoint codepoint) const { static const Character empty; auto it = m_characters.find(codepoint); diff --git a/src/drawing/subtexture.cpp b/src/graphics/subtexture.cpp similarity index 97% rename from src/drawing/subtexture.cpp rename to src/graphics/subtexture.cpp index f2e9ff8..e144390 100644 --- a/src/drawing/subtexture.cpp +++ b/src/graphics/subtexture.cpp @@ -1,4 +1,4 @@ -#include +#include #include using namespace Blah; diff --git a/src/graphics/texture.cpp b/src/graphics/texture.cpp index ff17353..5dd3005 100644 --- a/src/graphics/texture.cpp +++ b/src/graphics/texture.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "../internal/graphics_backend.h" using namespace Blah; diff --git a/src/images/aseprite.cpp b/src/images/aseprite.cpp index 7c51534..04b2a8b 100644 --- a/src/images/aseprite.cpp +++ b/src/images/aseprite.cpp @@ -1,17 +1,13 @@ #include #include #include -#include +#include +#include #define STBI_NO_STDIO #define STBI_ONLY_ZLIB #include "../third_party/stb_image.h" -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MUL_UN8(a, b, t) \ - ((t) = (a) * (uint16_t)(b) + 0x80, ((((t) >> 8) + (t) ) >> 8)) - using namespace Blah; Aseprite::Aseprite() @@ -19,7 +15,7 @@ Aseprite::Aseprite() } -Aseprite::Aseprite(const char* path) +Aseprite::Aseprite(const FilePath& path) { FileStream fs(path, FileMode::Read); parse(fs); @@ -98,10 +94,10 @@ void Aseprite::parse(Stream& stream) // header { // filesize - stream.read(Endian::Little); + stream.read(Endian::Little); // magic number - auto magic = stream.read(Endian::Little); + auto magic = stream.read(Endian::Little); if (magic != 0xA5E0) { BLAH_ERROR("File is not a valid Aseprite file"); @@ -109,21 +105,21 @@ void Aseprite::parse(Stream& stream) } // main info - frame_count = stream.read(Endian::Little); - width = stream.read(Endian::Little); - height = stream.read(Endian::Little); - mode = static_cast(stream.read(Endian::Little) / 8); + frame_count = stream.read(Endian::Little); + width = stream.read(Endian::Little); + height = stream.read(Endian::Little); + mode = static_cast(stream.read(Endian::Little) / 8); // don't care about other info - stream.read(Endian::Little); // Flags - stream.read(Endian::Little); // Speed (deprecated) - stream.read(Endian::Little); // Should be 0 - stream.read(Endian::Little); // Should be 0 - stream.read(Endian::Little); // Palette entry + stream.read(Endian::Little); // Flags + stream.read(Endian::Little); // Speed (deprecated) + stream.read(Endian::Little); // Should be 0 + stream.read(Endian::Little); // Should be 0 + stream.read(Endian::Little); // Palette entry stream.seek(stream.position() + 3); // Ignore these bytes - stream.read(Endian::Little); // Number of colors (0 means 256 for old sprites) - stream.read(Endian::Little); // Pixel width - stream.read(Endian::Little); // Pixel height + stream.read(Endian::Little); // Number of colors (0 means 256 for old sprites) + stream.read(Endian::Little); // Pixel width + stream.read(Endian::Little); // Pixel height stream.seek(stream.position() + 92); // For Future } @@ -133,22 +129,22 @@ void Aseprite::parse(Stream& stream) for (int i = 0; i < frame_count; i++) { auto frameStart = stream.position(); - auto frameEnd = frameStart + stream.read(Endian::Little); + auto frameEnd = frameStart + stream.read(Endian::Little); unsigned int chunks = 0; // frame header { - auto magic = stream.read(Endian::Little); // magic number + auto magic = stream.read(Endian::Little); // magic number if (magic != 0xF1FA) { BLAH_ERROR("File is not a valid Aseprite file"); return; } - auto old_chunk_count = stream.read(Endian::Little); - frames[i].duration = stream.read(Endian::Little); + auto old_chunk_count = stream.read(Endian::Little); + frames[i].duration = stream.read(Endian::Little); stream.seek(stream.position() + 2); // for future - auto new_chunk_count = stream.read(Endian::Little); + auto new_chunk_count = stream.read(Endian::Little); if (old_chunk_count == 0xFFFF) chunks = new_chunk_count; @@ -163,8 +159,8 @@ void Aseprite::parse(Stream& stream) for (unsigned int j = 0; j < chunks; j++) { auto chunkStart = stream.position(); - auto chunkEnd = chunkStart + stream.read(Endian::Little); - auto chunkType = static_cast(stream.read(Endian::Little)); + auto chunkEnd = chunkStart + stream.read(Endian::Little); + auto chunkType = static_cast(stream.read(Endian::Little)); switch (chunkType) { @@ -189,17 +185,17 @@ void Aseprite::parse_layer(Stream& stream, int frame) layers.emplace_back(); auto& layer = layers.back(); - layer.flag = static_cast(stream.read(Endian::Little)); + layer.flag = static_cast(stream.read(Endian::Little)); layer.visible = ((int)layer.flag & (int)LayerFlags::Visible) == (int)LayerFlags::Visible; - layer.type = static_cast(stream.read(Endian::Little)); - layer.child_level = stream.read(Endian::Little); - stream.read(Endian::Little); // width - stream.read(Endian::Little); // height - layer.blendmode = stream.read(Endian::Little); - layer.alpha = stream.read(Endian::Little); + layer.type = static_cast(stream.read(Endian::Little)); + layer.child_level = stream.read(Endian::Little); + stream.read(Endian::Little); // width + stream.read(Endian::Little); // height + layer.blendmode = stream.read(Endian::Little); + layer.alpha = stream.read(Endian::Little); stream.seek(stream.position() + 3); // for future - layer.name.set_length(stream.read(Endian::Little)); + layer.name.set_length(stream.read(Endian::Little)); stream.read(layer.name.cstr(), layer.name.length()); layer.userdata.color = 0xffffff; @@ -213,20 +209,20 @@ void Aseprite::parse_cel(Stream& stream, int frameIndex, size_t maxPosition) frame.cels.emplace_back(); auto& cel = frame.cels.back(); - cel.layer_index = stream.read(Endian::Little); - cel.x = stream.read(Endian::Little); - cel.y = stream.read(Endian::Little); - cel.alpha = stream.read(Endian::Little); + cel.layer_index = stream.read(Endian::Little); + cel.x = stream.read(Endian::Little); + cel.y = stream.read(Endian::Little); + cel.alpha = stream.read(Endian::Little); cel.linked_frame_index = -1; - auto celType = stream.read(Endian::Little); + auto celType = stream.read(Endian::Little); stream.seek(stream.position() + 7); // RAW or DEFLATE if (celType == 0 || celType == 2) { - auto width = stream.read(Endian::Little); - auto height = stream.read(Endian::Little); + auto width = stream.read(Endian::Little); + auto height = stream.read(Endian::Little); auto count = width * height * (int)mode; cel.image = Image(width, height); @@ -282,7 +278,7 @@ void Aseprite::parse_cel(Stream& stream, int frameIndex, size_t maxPosition) // this cel directly references a previous cel else if (celType == 1) { - cel.linked_frame_index = stream.read(Endian::Little); + cel.linked_frame_index = stream.read(Endian::Little); } // draw to frame if visible @@ -298,21 +294,21 @@ void Aseprite::parse_cel(Stream& stream, int frameIndex, size_t maxPosition) void Aseprite::parse_palette(Stream& stream, int frame) { - /* size */ stream.read(Endian::Little); - auto start = stream.read(Endian::Little); - auto end = stream.read(Endian::Little); + /* size */ stream.read(Endian::Little); + auto start = stream.read(Endian::Little); + auto end = stream.read(Endian::Little); stream.seek(stream.position() + 8); palette.resize(palette.size() + (end - start + 1)); for (int p = 0, len = static_cast(end - start) + 1; p < len; p++) { - auto hasName = stream.read(Endian::Little); - palette[start + p] = stream.read(Endian::Little); + auto hasName = stream.read(Endian::Little); + palette[start + p] = stream.read(Endian::Little); if (hasName & 0xF000) { - int len = stream.read(Endian::Little); + int len = stream.read(Endian::Little); stream.seek(stream.position() + len); } } @@ -322,38 +318,38 @@ void Aseprite::parse_user_data(Stream& stream, int frame) { if (m_last_userdata != nullptr) { - auto flags = stream.read(Endian::Little); + auto flags = stream.read(Endian::Little); // has text if (flags & (1 << 0)) { - m_last_userdata->text.set_length(stream.read(Endian::Little)); + m_last_userdata->text.set_length(stream.read(Endian::Little)); stream.read(m_last_userdata->text.cstr(), m_last_userdata->text.length()); } // has color if (flags & (1 << 1)) - m_last_userdata->color = stream.read(Endian::Little); + m_last_userdata->color = stream.read(Endian::Little); } } void Aseprite::parse_tag(Stream& stream, int frame) { - auto count = stream.read(Endian::Little); + auto count = stream.read(Endian::Little); stream.seek(stream.position() + 8); for (int t = 0; t < count; t++) { Tag tag; - tag.from = stream.read(Endian::Little); - tag.to = stream.read(Endian::Little); - tag.loops = static_cast(stream.read(Endian::Little)); + tag.from = stream.read(Endian::Little); + tag.to = stream.read(Endian::Little); + tag.loops = static_cast(stream.read(Endian::Little)); stream.seek(stream.position() + 8); - tag.color = Color(stream.read(), stream.read(), stream.read(Endian::Little), 255); + tag.color = Color(stream.read(), stream.read(), stream.read(Endian::Little), 255); stream.seek(stream.position() + 1); - tag.name.set_length(stream.read(Endian::Little)); + tag.name.set_length(stream.read(Endian::Little)); stream.read(tag.name.cstr(), tag.name.length()); tags.push_back(tag); @@ -362,12 +358,12 @@ void Aseprite::parse_tag(Stream& stream, int frame) void Aseprite::parse_slice(Stream& stream, int frame) { - int count = stream.read(Endian::Little); - int flags = stream.read(Endian::Little); - stream.read(Endian::Little); // reserved + int count = stream.read(Endian::Little); + int flags = stream.read(Endian::Little); + stream.read(Endian::Little); // reserved String name; - name.set_length(stream.read(Endian::Little)); + name.set_length(stream.read(Endian::Little)); stream.read(name.cstr(), name.length()); for (int s = 0; s < count; s++) @@ -376,19 +372,19 @@ void Aseprite::parse_slice(Stream& stream, int frame) auto& slice = slices.back(); slice.name = name; - slice.frame = stream.read(Endian::Little); - slice.origin.x = stream.read(Endian::Little); - slice.origin.y = stream.read(Endian::Little); - slice.width = stream.read(Endian::Little); - slice.height = stream.read(Endian::Little); + slice.frame = stream.read(Endian::Little); + slice.origin.x = stream.read(Endian::Little); + slice.origin.y = stream.read(Endian::Little); + slice.width = stream.read(Endian::Little); + slice.height = stream.read(Endian::Little); // 9 slice (ignored atm) if (flags & (1 << 0)) { - stream.read(Endian::Little); - stream.read(Endian::Little); - stream.read(Endian::Little); - stream.read(Endian::Little); + stream.read(Endian::Little); + stream.read(Endian::Little); + stream.read(Endian::Little); + stream.read(Endian::Little); } // pivot point @@ -396,8 +392,8 @@ void Aseprite::parse_slice(Stream& stream, int frame) if (flags & (1 << 1)) { slice.has_pivot = true; - slice.pivot.x = stream.read(Endian::Little); - slice.pivot.y = stream.read(Endian::Little); + slice.pivot.x = stream.read(Endian::Little); + slice.pivot.y = stream.read(Endian::Little); } slice.userdata.color = 0xffffff; @@ -406,6 +402,9 @@ void Aseprite::parse_slice(Stream& stream, int frame) } } +#define MUL_UN8(a, b, t) \ + ((t) = (a) * (u16)(b) + 0x80, ((((t) >> 8) + (t) ) >> 8)) + void Aseprite::render_cel(Cel* cel, Frame* frame) { Layer& layer = layers[cel->layer_index]; @@ -436,16 +435,16 @@ void Aseprite::render_cel(Cel* cel, Frame* frame) auto dstH = frame->image.height; // blit pixels - int left = MAX(0, srcX); - int right = MIN(dstW, srcX + srcW); - int top = MAX(0, srcY); - int bottom = MIN(dstH, srcY + srcH); + int left = Calc::max(0, srcX); + int right = Calc::min(dstW, srcX + srcW); + int top = Calc::max(0, srcY); + int bottom = Calc::min(dstH, srcY + srcH); if (layer.blendmode == 0) { - for (int dx = left, sx = -MIN(srcX, 0); dx < right; dx++, sx++) + for (int dx = left, sx = -Calc::min(srcX, 0); dx < right; dx++, sx++) { - for (int dy = top, sy = -MIN(srcY, 0); dy < bottom; dy++, sy++) + for (int dy = top, sy = -Calc::min(srcY, 0); dy < bottom; dy++, sy++) { Color* srcColor = (src + sx + sy * srcW); Color* dstColor = (dst + dx + dy * dstW); diff --git a/src/images/font.cpp b/src/images/font.cpp index af6268c..cd27931 100644 --- a/src/images/font.cpp +++ b/src/images/font.cpp @@ -1,32 +1,44 @@ #include #include #include -#include +#include using namespace Blah; +#ifdef __CLANG__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + #define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION #include "../third_party/stb_truetype.h" -String GetName(stbtt_fontinfo* font, int nameId) +#ifdef __CLANG__ +#pragma clang diagnostic pop +#endif + +namespace { - int length = 0; + String get_font_name(stbtt_fontinfo* font, int nameId) + { + int length = 0; - // get the name - const uint16_t* ptr = (const uint16_t*)stbtt_GetFontNameStr(font, &length, - STBTT_PLATFORM_ID_MICROSOFT, - STBTT_MS_EID_UNICODE_BMP, - STBTT_MS_LANG_ENGLISH, - nameId); + // get the name + const u16* ptr = (const u16*)stbtt_GetFontNameStr(font, &length, + STBTT_PLATFORM_ID_MICROSOFT, + STBTT_MS_EID_UNICODE_BMP, + STBTT_MS_LANG_ENGLISH, + nameId); - // we want the size in wide chars - length /= 2; + // we want the size in wide chars + length /= 2; - String str; - if (length > 0) - str.append_utf16(ptr, ptr + length, Calc::is_little_endian()); - return str; + String str; + if (length > 0) + str.append_utf16(ptr, ptr + length, Calc::is_little_endian()); + return str; + } } Font::Font() @@ -44,7 +56,7 @@ Font::Font(Stream& stream) : Font() load(stream); } -Font::Font(const char* path) : Font() +Font::Font(const FilePath& path) : Font() { FileStream fs(path, FileMode::Read); if (fs.is_readable()) @@ -112,8 +124,8 @@ void Font::load(Stream& stream) m_font = new stbtt_fontinfo(); auto fn = (stbtt_fontinfo*)m_font; stbtt_InitFont(fn, m_data, 0); - m_family_name = GetName(fn, 1); - m_style_name = GetName(fn, 2); + m_family_name = get_font_name(fn, 1); + m_style_name = get_font_name(fn, 2); // properties stbtt_GetFontVMetrics(fn, &m_ascent, &m_descent, &m_line_gap); @@ -130,14 +142,14 @@ void Font::dispose() m_style_name.dispose(); } -const char* Font::family_name() const +const String& Font::family_name() const { - return m_family_name.cstr(); + return m_family_name; } -const char* Font::style_name() const +const String& Font::style_name() const { - return m_style_name.cstr(); + return m_style_name; } int Font::ascent() const @@ -187,9 +199,9 @@ float Font::get_kerning(int glyph1, int glyph2, float scale) const return stbtt_GetGlyphKernAdvance((stbtt_fontinfo*)m_font, glyph1, glyph2) * scale; } -Font::Char Font::get_character(int glyph, float scale) const +Font::Character Font::get_character(int glyph, float scale) const { - Char ch; + Character ch; if (!m_font) return ch; @@ -215,7 +227,7 @@ Font::Char Font::get_character(int glyph, float scale) const return ch; } -bool Font::get_image(const Font::Char& ch, Color* pixels) const +bool Font::get_image(const Font::Character& ch, Color* pixels) const { if (ch.has_glyph) { @@ -239,6 +251,16 @@ bool Font::get_image(const Font::Char& ch, Color* pixels) const return false; } +Image Font::get_image(const Font::Character& ch) const +{ + Image img(ch.width, ch.height); + + if (get_image(ch, img.pixels)) + return img; + + return Image(); +} + bool Font::is_valid() const { return m_valid; diff --git a/src/images/image.cpp b/src/images/image.cpp index 33f1d18..7156119 100644 --- a/src/images/image.cpp +++ b/src/images/image.cpp @@ -1,14 +1,13 @@ #include #include #include -#include +#include using namespace Blah; #define STB_IMAGE_IMPLEMENTATION #define STBI_ONLY_JPEG #define STBI_ONLY_PNG -#define STBI_ONLY_BMP #include "../third_party/stb_image.h" #define STB_IMAGE_WRITE_IMPLEMENTATION @@ -18,7 +17,7 @@ namespace { int Blah_STBI_Read(void* user, char* data, int size) { - int64_t read = ((Stream*)user)->read(data, size); + i64 read = ((Stream*)user)->read(data, size); return (int)read; } @@ -29,8 +28,8 @@ namespace int Blah_STBI_Eof(void* user) { - int64_t position = ((Stream*)user)->position(); - int64_t length = ((Stream*)user)->length(); + i64 position = ((Stream*)user)->position(); + i64 length = ((Stream*)user)->length(); if (position >= length) return 1; @@ -59,7 +58,7 @@ Image::Image(Stream& stream) from_stream(stream); } -Image::Image(const char* file) +Image::Image(const FilePath& file) { width = height = 0; pixels = nullptr; @@ -155,7 +154,7 @@ void Image::from_stream(Stream& stream) callbacks.skip = Blah_STBI_Skip; int x, y, comps; - uint8_t* data = stbi_load_from_callbacks(&callbacks, &stream, &x, &y, &comps, 4); + u8* data = stbi_load_from_callbacks(&callbacks, &stream, &x, &y, &comps, 4); if (data == nullptr) { @@ -175,6 +174,7 @@ void Image::dispose() stbi_image_free(pixels); else delete[] pixels; + pixels = nullptr; width = height = 0; m_stbi_ownership = false; @@ -186,9 +186,9 @@ void Image::premultiply() { for (int n = 0; n < width * height; n ++) { - pixels[n].r = (uint8_t)(pixels[n].r * pixels[n].a / 255); - pixels[n].g = (uint8_t)(pixels[n].g * pixels[n].a / 255); - pixels[n].b = (uint8_t)(pixels[n].b * pixels[n].a / 255); + pixels[n].r = (u8)(pixels[n].r * pixels[n].a / 255); + pixels[n].g = (u8)(pixels[n].g * pixels[n].a / 255); + pixels[n].b = (u8)(pixels[n].b * pixels[n].a / 255); } } } @@ -203,7 +203,7 @@ void Image::set_pixels(const RectI& rect, Color* data) } } -bool Image::save_png(const char* file) const +bool Image::save_png(const FilePath& file) const { FileStream fs(file, FileMode::Write); return save_png(fs); @@ -232,7 +232,7 @@ bool Image::save_png(Stream& stream) const return false; } -bool Image::save_jpg(const char* file, int quality) const +bool Image::save_jpg(const FilePath& file, int quality) const { FileStream fs(file, FileMode::Write); return save_jpg(fs, quality); @@ -269,33 +269,31 @@ bool Image::save_jpg(Stream& stream, int quality) const return false; } - - -void Image::get_pixels(Color* dest, const Point& destPos, const Point& destSize, RectI sourceRect) +void Image::get_pixels(Color* dest, const Point& dest_pos, const Point& dest_size, RectI source_rect) { // can't be outside of the source image - if (sourceRect.x < 0) sourceRect.x = 0; - if (sourceRect.y < 0) sourceRect.y = 0; - if (sourceRect.x + sourceRect.w > width) sourceRect.w = width - sourceRect.x; - if (sourceRect.y + sourceRect.h > height) sourceRect.h = height - sourceRect.y; + if (source_rect.x < 0) source_rect.x = 0; + if (source_rect.y < 0) source_rect.y = 0; + if (source_rect.x + source_rect.w > width) source_rect.w = width - source_rect.x; + if (source_rect.y + source_rect.h > height) source_rect.h = height - source_rect.y; // can't be larger than our destination - if (sourceRect.w > destSize.x - destPos.x) - sourceRect.w = destSize.x - destPos.x; - if (sourceRect.h > destSize.y - destPos.y) - sourceRect.h = destSize.y - destPos.y; + if (source_rect.w > dest_size.x - dest_pos.x) + source_rect.w = dest_size.x - dest_pos.x; + if (source_rect.h > dest_size.y - dest_pos.y) + source_rect.h = dest_size.y - dest_pos.y; - for (int y = 0; y < sourceRect.h; y++) + for (int y = 0; y < source_rect.h; y++) { - int to = destPos.x + (destPos.y + y) * destSize.x; - int from = sourceRect.x + (sourceRect.y + y) * width; - memcpy(dest + to, pixels + from, sizeof(Color) * (int)sourceRect.w); + int to = dest_pos.x + (dest_pos.y + y) * dest_size.x; + int from = source_rect.x + (source_rect.y + y) * width; + memcpy(dest + to, pixels + from, sizeof(Color) * (int)source_rect.w); } } -Image Image::get_sub_image(const RectI& sourceRect) +Image Image::get_sub_image(const RectI& source_rect) { - Image img(sourceRect.w, sourceRect.h); - get_pixels(img.pixels, Point::zero, Point(img.width, img.height), sourceRect); + Image img(source_rect.w, source_rect.h); + get_pixels(img.pixels, Point::zero, Point(img.width, img.height), source_rect); return img; } diff --git a/src/images/packer.cpp b/src/images/packer.cpp index 77fc1c2..dfdbaaf 100644 --- a/src/images/packer.cpp +++ b/src/images/packer.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -19,7 +19,7 @@ Packer::Packer(Packer&& src) noexcept padding = src.padding; m_dirty = src.m_dirty; pages = std::move(src.pages); - entries = std::move(src.entries); + m_entries = std::move(src.m_entries); m_buffer = std::move(src.m_buffer); } @@ -31,7 +31,7 @@ Packer& Packer::operator=(Packer&& src) noexcept padding = src.padding; m_dirty = src.m_dirty; pages = std::move(src.pages); - entries = std::move(src.entries); + m_entries = std::move(src.m_entries); m_buffer = std::move(src.m_buffer); return *this; } @@ -41,22 +41,22 @@ Packer::~Packer() dispose(); } -void Packer::add(uint64_t id, int width, int height, const Color* pixels) +void Packer::add(u64 id, int width, int height, const Color* pixels) { add_entry(id, width, height, pixels); } -void Packer::add(uint64_t id, const Image& image) +void Packer::add(u64 id, const Image& image) { add_entry(id, image.width, image.height, image.pixels); } -void Packer::add(uint64_t id, const String& path) +void Packer::add(u64 id, const FilePath& path) { add(id, Image(path.cstr())); } -void Packer::add_entry(uint64_t id, int w, int h, const Color* pixels) +void Packer::add_entry(u64 id, int w, int h, const Color* pixels) { m_dirty = true; @@ -125,7 +125,12 @@ void Packer::add_entry(uint64_t id, int w, int h, const Color* pixels) } } - entries.push_back(entry); + m_entries.push_back(entry); +} + +const Vector& Packer::entries() const +{ + return m_entries; } void Packer::pack() @@ -137,7 +142,7 @@ void Packer::pack() pages.clear(); // only if we have stuff to pack - auto count = entries.size(); + auto count = m_entries.size(); if (count > 0) { // get all the sources sorted largest -> smallest @@ -146,8 +151,8 @@ void Packer::pack() sources.resize(count); int index = 0; - for (int i = 0; i < entries.size(); i++) - sources[index++] = &entries[i]; + for (int i = 0; i < m_entries.size(); i++) + sources[index++] = &m_entries[i]; std::sort(sources.begin(), sources.end(), [](Packer::Entry* a, Packer::Entry* b) { @@ -292,14 +297,14 @@ void Packer::pack() void Packer::clear() { pages.clear(); - entries.clear(); + m_entries.clear(); m_dirty = false; } void Packer::dispose() { pages.clear(); - entries.clear(); + m_entries.clear(); m_buffer.close(); max_size = 0; power_of_two = 0; diff --git a/src/input/binding.cpp b/src/input/binding.cpp new file mode 100644 index 0000000..595df6f --- /dev/null +++ b/src/input/binding.cpp @@ -0,0 +1,469 @@ +#include +#include +#include + +using namespace Blah; + +Binding::TriggerBind::TriggerBind(Axis axis) + : axis(axis) +{ + +} + +Binding::TriggerBind::TriggerBind(int controller, Axis axis, float threshold, bool positive) + : controller(controller), axis(axis), threshold(threshold), positive(positive) +{ + +} + +bool Binding::TriggerBind::is_down(float axis_value) const +{ + if ((axis_value > 0 && positive) || (axis_value < 0 && !positive)) + { + if (Calc::abs(axis_value) >= threshold) + return true; + } + + return false; +} + +Binding::ButtonBind::ButtonBind(Button button) + : button(button) {} + +Binding::ButtonBind::ButtonBind(int controller, Button button) + : controller(controller), button(button) {} + +bool Binding::pressed() const +{ + if (m_press_consumed) + return false; + + if (m_last_press_time >= 0 && (Time::seconds - m_last_press_time) <= press_buffer) + return true; + + return m_pressed; +} + +bool Binding::released() const +{ + if (m_release_consumed) + return false; + + if (m_last_release_time >= 0 && (Time::seconds - m_last_release_time) <= release_buffer) + return true; + + return m_released; +} + +bool Binding::down() const +{ + return m_down; +} + +float Binding::value() const +{ + return m_value; +} + +int Binding::sign() const +{ + return (int)Calc::sign(m_value); +} + +double Binding::timestamp() const +{ + return m_last_timestamp; +} + +void Binding::update() +{ + m_press_consumed = false; + m_release_consumed = false; + + if (get_pressed()) + { + m_last_timestamp = Time::seconds; + m_last_press_time = Time::seconds; + m_pressed = true; + } + else + { + m_pressed = false; + } + + if (get_released()) + { + m_last_release_time = Time::seconds; + m_released = true; + } + else + { + m_released = false; + } + + m_down = get_down(); + m_value = get_value(); +} + +void Binding::consume_press() +{ + m_press_consumed = true; + m_last_press_time = -1; +} + +void Binding::consume_release() +{ + m_release_consumed = true; + m_last_release_time = -1; +} + +Binding& Binding::add(Key key) +{ + keys.push_back(key); + return *this; +} + +Binding& Binding::add(ButtonBind button) +{ + buttons.push_back(button); + return *this; +} + +Binding& Binding::add(TriggerBind trigger) +{ + triggers.push_back(trigger); + return *this; +} + +Binding& Binding::add(MouseButton button) +{ + mouse.push_back(button); + return *this; +} + +Binding& Binding::add_left_trigger(int controller, float threshold) +{ + triggers.push_back(TriggerBind(controller, Axis::LeftTrigger, threshold, true)); + return *this; +} + +Binding& Binding::add_right_trigger(int controller, float threshold) +{ + triggers.push_back(TriggerBind(controller, Axis::RightTrigger, threshold, true)); + return *this; +} + +Binding& Binding::set_controller(int index) +{ + for (auto& it : buttons) + it.controller = index; + for (auto& it : triggers) + it.controller = index; + + return *this; +} + +void Binding::clear() +{ + keys.clear(); + buttons.clear(); + triggers.clear(); + mouse.clear(); +} + +bool Binding::get_pressed() const +{ + for (auto& it : keys) + if (Input::pressed(it)) + return true; + + for (auto& it : mouse) + if (Input::pressed(it)) + return true; + + for (auto& it : buttons) + if (Input::pressed(it.controller, it.button)) + return true; + + for (auto& it : triggers) + { + if (it.controller < 0 || it.controller >= Input::max_controllers) + continue; + + if ((int)it.axis < 0 || (int)it.axis >= Input::max_controller_axis) + continue; + + if (it.is_down(Input::state()->controllers[it.controller].axis[(int)it.axis]) && + !it.is_down(Input::last_state()->controllers[it.controller].axis[(int)it.axis])) + return true; + } + + return false; +} + +bool Binding::get_released() const +{ + for (auto& it : keys) + if (Input::released(it)) + return true; + + for (auto& it : mouse) + if (Input::released(it)) + return true; + + for (auto& it : buttons) + if (Input::released(it.controller, it.button)) + return true; + + for (auto& it : triggers) + { + if (it.controller < 0 || it.controller >= Input::max_controllers) + continue; + + if ((int)it.axis < 0 || (int)it.axis >= Input::max_controller_axis) + continue; + + if (!it.is_down(Input::state()->controllers[it.controller].axis[(int)it.axis]) && + it.is_down(Input::last_state()->controllers[it.controller].axis[(int)it.axis])) + return true; + } + + return false; +} + +bool Binding::get_down() const +{ + for (auto& it : keys) + if (Input::down(it)) + return true; + + for (auto& it : mouse) + if (Input::down(it)) + return true; + + for (auto& it : buttons) + if (Input::down(it.controller, it.button)) + return true; + + for (auto& it : triggers) + { + if (it.controller < 0 || it.controller >= Input::max_controllers) + continue; + + if ((int)it.axis < 0 || (int)it.axis >= Input::max_controller_axis) + continue; + + if (it.is_down(Input::state()->controllers[it.controller].axis[(int)it.axis])) + return true; + } + + return false; +} + +float Binding::get_value() const +{ + for (auto& it : keys) + if (Input::down(it)) + return 1.0f; + + for (auto& it : mouse) + if (Input::down(it)) + return 1.0f; + + for (auto& it : buttons) + if (Input::down(it.controller, it.button)) + return 1.0f; + + float highest = 0; + + for (auto& it : triggers) + { + if (it.controller < 0 || it.controller >= Input::max_controllers) + continue; + + if ((int)it.axis < 0 || (int)it.axis >= Input::max_controller_axis) + continue; + + float raw_value = Input::state()->controllers[it.controller].axis[(int)it.axis]; + + if (it.is_down(raw_value)) + { + float mapped_value = Calc::clamped_map(Calc::abs(raw_value), it.threshold, 1.0f, 0.0f, 1.0f); + if (mapped_value > highest) + highest = mapped_value; + } + } + + return highest; +} + +float AxisBinding::value() const +{ + float neg = negative.value(); + float pos = positive.value(); + + // neither are down + if (neg <= 0 && pos <= 0) + return 0; + + // negative-only is down + if (neg > 0 && pos <= 0) + return -neg; + + // positive-only is down + if (pos > 0 && neg <= 0) + return pos; + + // both are down: + + // overlap cancel out + if (overlap == Overlap::Cancel) + return 0; + + // overlap takes older + if (overlap == Overlap::Older) + { + if (negative.timestamp() < positive.timestamp()) + return -neg; + else + return pos; + } + + // overlap takes newer + if (negative.timestamp() > positive.timestamp()) + return -neg; + else + return pos; +} + +int AxisBinding::sign() const +{ + return (int)Calc::sign(value()); +} + +void AxisBinding::update() +{ + negative.update(); + positive.update(); +} + +void AxisBinding::consume_press() +{ + negative.consume_press(); + positive.consume_press(); +} + +void AxisBinding::consume_release() +{ + negative.consume_release(); + positive.consume_release(); +} + +AxisBinding& AxisBinding::add_left_stick_x(int controller, float threshold) +{ + negative.add(Binding::TriggerBind(controller, Axis::LeftX, threshold, false)); + positive.add(Binding::TriggerBind(controller, Axis::LeftX, threshold, true)); + return *this; +} + +AxisBinding& AxisBinding::add_left_stick_y(int controller, float threshold) +{ + negative.add(Binding::TriggerBind(controller, Axis::LeftY, threshold, false)); + positive.add(Binding::TriggerBind(controller, Axis::LeftY, threshold, true)); + return *this; +} + +AxisBinding& AxisBinding::add_right_stick_x(int controller, float threshold) +{ + negative.add(Binding::TriggerBind(controller, Axis::RightX, threshold, false)); + positive.add(Binding::TriggerBind(controller, Axis::RightX, threshold, true)); + return *this; +} + +AxisBinding& AxisBinding::add_right_stick_y(int controller, float threshold) +{ + negative.add(Binding::TriggerBind(controller, Axis::RightY, threshold, false)); + positive.add(Binding::TriggerBind(controller, Axis::RightY, threshold, true)); + return *this; +} + +AxisBinding& AxisBinding::set_controller(int index) +{ + negative.set_controller(index); + positive.set_controller(index); + return *this; +} + +void AxisBinding::clear() +{ + negative.clear(); + positive.clear(); +} + +Vec2 StickBinding::value() const +{ + Vec2 result = Vec2(x.value(), y.value()); + if (round_threshold > 0 && result.length() < round_threshold) + return Vec2::zero; + return result; +} + +Point StickBinding::sign() const +{ + Vec2 result = value(); + return Point((int)Calc::sign(result.x), (int)Calc::sign(result.y)); +} + +void StickBinding::update() +{ + x.update(); + y.update(); +} + +void StickBinding::consume_press() +{ + x.consume_press(); + y.consume_press(); +} + +void StickBinding::consume_release() +{ + x.consume_release(); + y.consume_release(); +} + +StickBinding& StickBinding::add_dpad(int controller) +{ + x.negative.add(Binding::ButtonBind(controller, Button::Left)); + x.positive.add(Binding::ButtonBind(controller, Button::Right)); + y.negative.add(Binding::ButtonBind(controller, Button::Up)); + y.positive.add(Binding::ButtonBind(controller, Button::Down)); + return *this; +} + +StickBinding& StickBinding::add_left_stick(int controller, float threshold) +{ + x.add_left_stick_x(controller, threshold); + y.add_left_stick_y(controller, threshold); + return *this; +} + +StickBinding& StickBinding::add_right_stick(int controller, float threshold) +{ + x.add_right_stick_x(controller, threshold); + y.add_right_stick_y(controller, threshold); + return *this; +} + +StickBinding& StickBinding::set_controller(int index) +{ + x.set_controller(index); + y.set_controller(index); + return *this; +} + +void StickBinding::clear() +{ + x.clear(); + y.clear(); +} \ No newline at end of file diff --git a/src/input/binding_registry.cpp b/src/input/binding_registry.cpp new file mode 100644 index 0000000..43ec290 --- /dev/null +++ b/src/input/binding_registry.cpp @@ -0,0 +1,70 @@ +#include + +using namespace Blah; + +Vector> BindingRegistry::bindings; +Vector> BindingRegistry::axes; +Vector> BindingRegistry::sticks; + +BindingRef BindingRegistry::register_binding(const Binding& binding) +{ + auto result = std::make_shared(binding); + bindings.push_back(std::weak_ptr(result)); + return result; +} + +AxisBindingRef BindingRegistry::register_axis(const AxisBinding& binding) +{ + auto result = std::make_shared(binding); + axes.push_back(std::weak_ptr(result)); + return result; +} + +StickBindingRef BindingRegistry::register_stick(const StickBinding& binding) +{ + auto result = std::make_shared(binding); + sticks.push_back(std::weak_ptr(result)); + return result; +} + +void BindingRegistry::update() +{ + for (int i = 0; i < bindings.size(); i++) + { + if (bindings[i].use_count() <= 0) + { + bindings.erase(i); + i--; + } + else if (auto binding = bindings[i].lock()) + { + binding->update(); + } + } + + for (int i = 0; i < axes.size(); i++) + { + if (axes[i].use_count() <= 0) + { + axes.erase(i); + i--; + } + else if (auto binding = axes[i].lock()) + { + binding->update(); + } + } + + for (int i = 0; i < sticks.size(); i++) + { + if (sticks[i].use_count() <= 0) + { + sticks.erase(i); + i--; + } + else if (auto binding = sticks[i].lock()) + { + binding->update(); + } + } +} diff --git a/src/input/input.cpp b/src/input/input.cpp index 82fe4a8..034f53f 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -1,7 +1,8 @@ #include +#include #include #include -#include +#include #include #include "../internal/input_backend.h" #include @@ -47,10 +48,9 @@ void InputBackend::frame() g_next_state.mouse.pressed[i] = false; g_next_state.mouse.released[i] = false; } - g_next_state.mouse.wheel = Point::zero; - for (int i = 0; i < Blah::Input::max_text_input; i++) - g_next_state.keyboard.text[i] = 0; + g_next_state.mouse.wheel = Point::zero; + g_next_state.keyboard.text.clear(); for (int i = 0; i < Blah::Input::max_controllers; i++) { @@ -66,6 +66,9 @@ void InputBackend::frame() } } } + + // update bindings + BindingRegistry::update(); } void InputBackend::on_mouse_move(float x, float y) @@ -135,10 +138,10 @@ void InputBackend::on_key_up(Key key) void InputBackend::on_text_utf8(const char* text) { - strncat(g_next_state.keyboard.text, text, Blah::Input::max_text_input); + g_next_state.keyboard.text += text; } -void InputBackend::on_controller_connect(int index, const char* name, int is_gamepad, int button_count, int axis_count, uint16_t vendor, uint16_t product, uint16_t version) +void InputBackend::on_controller_connect(int index, const char* name, int is_gamepad, int button_count, int axis_count, u16 vendor, u16 product, u16 version) { if (index < Blah::Input::max_controllers) { diff --git a/src/input/virtual_axis.cpp b/src/input/virtual_axis.cpp deleted file mode 100644 index f333b8a..0000000 --- a/src/input/virtual_axis.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include -#include - -using namespace Blah; - -VirtualAxis& VirtualAxis::add_keys(Key negative, Key positive) -{ - if (m_axes_len >= Input::max_virtual_nodes) - BLAH_ERROR("VirtualAxis Keys out of bounds!"); - else - { - m_keys[m_keys_len].init(negative, positive); - m_keys_len++; - } - - return *this; -} - -VirtualAxis& VirtualAxis::add_buttons(int gamepad_id, Button negative, Button positive) -{ - if (m_axes_len >= Input::max_virtual_nodes) - BLAH_ERROR("VirtualAxis Buttons out of bounds!"); - else - { - m_buttons[m_buttons_len].init(gamepad_id, negative, positive); - m_buttons_len++; - } - - return *this; -} - -VirtualAxis& VirtualAxis::add_axis(int gamepad_id, Axis axis, float deadzone) -{ - if (m_axes_len >= Input::max_virtual_nodes) - BLAH_ERROR("VirtualAxis Axes out of bounds!"); - else - { - m_axes[m_axes_len].init(gamepad_id, axis, deadzone); - m_axes_len++; - } - - return *this; -} - -VirtualAxis& VirtualAxis::repeat(float m_repeat_delay, float m_repeat_interval) -{ - this->m_repeat_delay = m_repeat_delay; - this->m_repeat_interval = m_repeat_interval; - return *this; -} - -VirtualAxis& VirtualAxis::press_buffer(float duration) -{ - this->m_press_buffer = duration; - return *this; -} - -VirtualAxis& VirtualAxis::release_buffer(float duration) -{ - this->m_release_buffer = duration; - return *this; -} - -void VirtualAxis::update() -{ - m_last_value = m_value; - m_value = 0; - - for (int i = 0; i < m_keys_len; i++) - { - m_keys[i].update(); - if (m_value == 0) - m_value = (float)m_keys[i].value; - } - - for (int i = 0; i < m_buttons_len; i++) - { - m_buttons[i].update(); - if (m_value == 0) - m_value = (float)m_buttons[i].value; - } - - for (int i = 0; i < m_axes_len; i++) - { - m_axes[i].update(); - if (m_value == 0) - m_value = m_axes[i].value; - } - - //Valuei - m_last_value_i = m_value_i; - if (m_value > 0) - m_value_i = 1; - else if (m_value < 0) - m_value_i = -1; - else - m_value_i = 0; - - //pressed? - m_pressed = false; - if (m_value_i != 0 && m_last_value_i != m_value_i) - { - m_pressed = true; - m_last_press_time = m_repeat_press_time = Time::seconds; - } - else if (m_value_i == m_last_value_i && m_value_i != 0) - { - if (Time::seconds - m_last_press_time <= m_press_buffer) - m_pressed = true; - else if (m_repeat_interval > 0 && Time::seconds >= m_repeat_press_time + m_repeat_delay) - { - int prev = (int)((Time::previous_seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval); - int cur = (int)((Time::seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval); - m_pressed = prev < cur; - } - } - - //released? - if (m_last_value_i != 0 && m_value_i != m_last_value_i) - { - m_released = true; - m_last_release_time = Time::seconds; - } - else if (Time::seconds - m_last_release_time <= m_release_buffer) - m_released = true; - else - m_released = false; -} - -void VirtualAxis::KeysNode::init(Key negative, Key positive) -{ - this->negative = negative; - this->positive = positive; -} - -void VirtualAxis::KeysNode::update() -{ - value = Input::axis_check(value, negative, positive); -} - -void VirtualAxis::ButtonsNode::init(int gamepad_id, Button negative, Button positive) -{ - this->gamepad_id = gamepad_id; - this->negative = negative; - this->positive = positive; -} - -void VirtualAxis::ButtonsNode::update() -{ - value = Input::axis_check(value, gamepad_id, negative, positive); -} - -void VirtualAxis::AxisNode::init(int gamepad_id, Axis axis, float deadzone) -{ - this->gamepad_id = gamepad_id; - this->axis = axis; - this->deadzone = deadzone; -} - -void VirtualAxis::AxisNode::update() -{ - value = Input::axis_check(gamepad_id, axis); - if (value < deadzone && value > -deadzone) - value = 0; -} \ No newline at end of file diff --git a/src/input/virtual_button.cpp b/src/input/virtual_button.cpp deleted file mode 100644 index fa17e65..0000000 --- a/src/input/virtual_button.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include -#include -#include - -using namespace Blah; - -VirtualButton& VirtualButton::add_key(Key key) -{ - if (m_keys_len >= Input::max_virtual_nodes) - BLAH_ERROR("VirtualButton Keys out of bounds!"); - else - { - m_keys[m_keys_len].init(key); - m_keys_len++; - } - - return *this; -} - -VirtualButton& VirtualButton::add_button(int gamepad_id, Button button) -{ - if (m_buttons_len >= Input::max_virtual_nodes) - BLAH_ERROR("VirtualButton Buttons out of bounds!"); - else - { - m_buttons[m_buttons_len].init(gamepad_id, button); - m_buttons_len++; - } - - return *this; -} - -VirtualButton& VirtualButton::add_axis(int gamepad_id, Axis axis, float threshold, bool greater_than) -{ - if (m_axes_len >= Input::max_virtual_nodes) - BLAH_ERROR("VirtualButton Axes out of bounds!"); - else - { - m_axes[m_axes_len].init(gamepad_id, axis, threshold, greater_than); - m_axes_len++; - } - - return *this; -} - -VirtualButton& VirtualButton::repeat(float m_repeat_delay, float m_repeat_interval) -{ - this->m_repeat_delay = m_repeat_delay; - this->m_repeat_interval = m_repeat_interval; - return *this; -} - -VirtualButton& VirtualButton::press_buffer(float duration) -{ - this->m_press_buffer = duration; - return *this; -} - -VirtualButton& VirtualButton::release_buffer(float duration) -{ - this->m_release_buffer = duration; - return *this; -} - -void VirtualButton::update() -{ - m_down = false; - m_pressed = false; - m_released = false; - - // Keys - for (int i = 0; i < m_keys_len; i++) - { - m_keys[i].update(); - - m_down = m_down || m_keys[i].down; - m_pressed = m_pressed || m_keys[i].pressed; - m_released = m_released || m_keys[i].released; - } - - // Buttons - for (int i = 0; i < m_buttons_len; i++) - { - m_buttons[i].update(); - - m_down = m_down || m_buttons[i].down; - m_pressed = m_pressed || m_buttons[i].pressed; - m_released = m_released || m_buttons[i].released; - } - - // Axes - for (int i = 0; i < m_axes_len; i++) - { - m_axes[i].update(); - - m_down = m_down || m_axes[i].down; - m_pressed = m_pressed || m_axes[i].pressed; - m_released = m_released || m_axes[i].released; - } - - // pressed? - if (m_pressed) - { - m_repeat_press_time = m_last_press_time = Time::seconds; - } - else if (Time::seconds - m_last_press_time <= m_press_buffer) - { - m_pressed = true; - } - else if (m_down && m_repeat_interval > 0 && Time::seconds >= m_repeat_press_time + m_repeat_delay) - { - int prev = (int)((Time::previous_seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval); - int cur = (int)((Time::seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval); - m_pressed = prev < cur; - } - - // released? - if (m_released) - m_last_release_time = Time::seconds; - else - m_released = Time::seconds - m_last_release_time <= m_release_buffer; -} - -void VirtualButton::KeyNode::init(Key key) -{ - this->key = key; -} - -void VirtualButton::KeyNode::update() -{ - down = Input::down(key); - pressed = Input::pressed(key); - released = Input::released(key); -} - -void VirtualButton::ButtonNode::init(int gamepad_id, Button button) -{ - this->gamepad_id = gamepad_id; - this->button = button; -} - -void VirtualButton::ButtonNode::update() -{ - down = Input::down(gamepad_id, button); - pressed = Input::pressed(gamepad_id, button); - released = Input::released(gamepad_id, button); -} - -void VirtualButton::AxisNode::init(int gamepad_id, Axis axis, float threshold, bool greater_than) -{ - this->gamepad_id = gamepad_id; - this->axis = axis; - this->threshold = threshold; - this->greater_than = greater_than; -} - -void VirtualButton::AxisNode::update() -{ - float curr = Input::state()->controllers[gamepad_id].axis[(int)axis]; - float prev = Input::last_state()->controllers[gamepad_id].axis[(int)axis]; - - if (greater_than) - { - down = curr >= threshold; - pressed = down && prev < threshold; - released = !down && prev >= threshold; - } - else - { - down = curr <= threshold; - pressed = down && prev > threshold; - released = !down && prev <= threshold; - } -} \ No newline at end of file diff --git a/src/input/virtual_stick.cpp b/src/input/virtual_stick.cpp deleted file mode 100644 index 11e4874..0000000 --- a/src/input/virtual_stick.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include -#include -#include - -using namespace Blah; - -VirtualStick::VirtualStick() -{ - this->m_i_deadzone = 0; -} - -VirtualStick::VirtualStick(float iDeadzone) -{ - this->m_i_deadzone = iDeadzone; -} - -VirtualStick& VirtualStick::add_keys(Key left, Key right, Key up, Key down) -{ - if (m_keys_len >= Input::max_virtual_nodes) - BLAH_ERROR("VirtualStick Keys out of bounds!"); - else - { - m_keys[m_keys_len].init(left, right, up, down); - m_keys_len++; - } - - return *this; -} - -VirtualStick& VirtualStick::add_buttons(int gamepad_id, Button left, Button right, Button up, Button down) -{ - if (m_buttons_len >= Input::max_virtual_nodes) - BLAH_ERROR("VirtualStick Buttons out of bounds!"); - else - { - m_buttons[m_buttons_len].init(gamepad_id, left, right, up, down); - m_buttons_len++; - } - - return *this; -} - -VirtualStick& VirtualStick::add_axes(int gamepad_id, Axis horizontal, Axis vertical, float deadzone) -{ - if (m_axes_len >= Input::max_virtual_nodes) - BLAH_ERROR("VirtualStick Axes out of bounds!"); - else - { - m_axes[m_axes_len].init(gamepad_id, horizontal, vertical, deadzone); - m_axes_len++; - } - - return *this; -} - -VirtualStick& VirtualStick::repeat(float repeat_delay, float repeat_interval) -{ - this->m_repeat_delay = repeat_delay; - this->m_repeat_interval = repeat_interval; - return *this; -} - -VirtualStick& VirtualStick::press_buffer(float duration) -{ - m_press_buffer = duration; - return *this; -} - -VirtualStick& VirtualStick::release_buffer(float duration) -{ - m_release_buffer = duration; - return *this; -} - -void VirtualStick::update() -{ - m_last_value = m_value; - m_value = Vec2::zero; - - for (int i = 0; i < m_keys_len; i++) - { - m_keys[i].update(); - if (m_value == Vec2::zero) - m_value = m_keys[i].value; - } - - for (int i = 0; i < m_buttons_len; i++) - { - m_buttons[i].update(); - if (m_value == Vec2::zero) - m_value = m_buttons[i].value; - } - - for (int i = 0; i < m_axes_len; i++) - { - m_axes[i].update(); - if (m_value == Vec2::zero) - m_value = m_axes[i].value; - } - - //Valuei - m_last_value_i = m_value_i; - if (m_value.x > m_i_deadzone) - m_value_i.x = 1; - else if (m_value.x < -m_i_deadzone) - m_value_i.x = -1; - else - m_value_i.x = 0; - if (m_value.y > m_i_deadzone) - m_value_i.y = 1; - else if (m_value.y < -m_i_deadzone) - m_value_i.y = -1; - else - m_value_i.y = 0; - - //pressed? - m_pressed = false; - if (m_value_i != Point::zero && m_last_value_i != m_value_i) - { - m_pressed = true; - m_last_press_time = m_repeat_press_time = Time::seconds; - } - else if (m_value_i == m_last_value_i && m_value_i != Point::zero) - { - if (Time::seconds - m_last_press_time <= m_press_buffer) - m_pressed = true; - else if (m_repeat_interval > 0 && Time::seconds >= m_repeat_press_time + m_repeat_delay) - { - int prev = (int)((Time::previous_seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval); - int cur = (int)((Time::seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval); - m_pressed = prev < cur; - } - } - - //released? - if (m_last_value_i != Point::zero && m_value_i != m_last_value_i) - { - m_released = true; - m_last_release_time = Time::seconds; - } - else if (Time::seconds - m_last_release_time <= m_release_buffer) - m_released = true; - else - m_released = false; -} - -void VirtualStick::KeysNode::init(Key left, Key right, Key up, Key down) -{ - this->left = left; - this->right = right; - this->up = up; - this->down = down; -} - -void VirtualStick::KeysNode::update() -{ - value.x = Input::axis_check(value.x, left, right); - value.y = Input::axis_check(value.y, up, down); -} - -void VirtualStick::ButtonsNode::init(int gamepad_id, Button left, Button right, Button up, Button down) -{ - this->gamepad_id = gamepad_id; - this->left = left; - this->right = right; - this->up = up; - this->down = down; -} - -void VirtualStick::ButtonsNode::update() -{ - value.x = Input::axis_check(value.x, gamepad_id, left, right); - value.y = Input::axis_check(value.y, gamepad_id, up, down); -} - -void VirtualStick::AxesNode::init(int gamepad_id, Axis horizontal, Axis vertical, float deadzone) -{ - this->gamepad_id = gamepad_id; - this->horizontal = horizontal; - this->vertical = vertical; - this->deadzone = deadzone; -} - -void VirtualStick::AxesNode::update() -{ - value.x = Input::axis_check(gamepad_id, horizontal); - value.y = Input::axis_check(gamepad_id, vertical); - - if (value.length() < deadzone) - value = Vec2::zero; -} \ No newline at end of file diff --git a/src/internal/graphics_backend.h b/src/internal/graphics_backend.h index b388fea..9185c39 100644 --- a/src/internal/graphics_backend.h +++ b/src/internal/graphics_backend.h @@ -39,7 +39,7 @@ namespace Blah void render(const RenderPass& pass); // Clears the backbuffer - void clear_backbuffer(Color color, float depth, uint8_t stencil, ClearMask mask); + void clear_backbuffer(Color color, float depth, u8 stencil, ClearMask mask); // Creates a new Texture. // if the Texture is invalid, this should return an empty reference. diff --git a/src/internal/graphics_backend_d3d11.cpp b/src/internal/graphics_backend_d3d11.cpp index 5a0ad3a..abeaa71 100644 --- a/src/internal/graphics_backend_d3d11.cpp +++ b/src/internal/graphics_backend_d3d11.cpp @@ -1,11 +1,11 @@ -#ifdef BLAH_USE_D3D11 +#ifdef BLAH_GRAPHICS_D3D11 // TODO: // Note the D3D11 Implementation is still a work-in-progress #include "../internal/graphics_backend.h" #include "../internal/platform_backend.h" -#include +#include #include #include #include @@ -36,7 +36,7 @@ namespace Blah struct StoredInputLayout { - uint32_t shader_hash; + u32 shader_hash; VertexFormat format; ID3D11InputLayout* layout; }; @@ -145,6 +145,9 @@ namespace Blah m_size = width * height * 4; is_depth_stencil = true; break; + case TextureFormat::None: + case TextureFormat::Count: + break; } if (!is_depth_stencil) @@ -349,7 +352,7 @@ namespace Blah return m_attachments[0]->height(); } - virtual void clear(Color color, float depth, uint8_t stencil, ClearMask mask) override + virtual void clear(Color color, float depth, u8 stencil, ClearMask mask) override { float col[4] = { color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f }; @@ -386,7 +389,7 @@ namespace Blah Vector> fragment_uniform_values; StackVector attributes; Vector uniform_list; - uint32_t hash = 0; + u32 hash = 0; bool valid = false; D3D11_Shader(const ShaderData* data) @@ -542,10 +545,10 @@ namespace Blah class D3D11_Mesh : public Mesh { private: - int64_t m_vertex_count = 0; - int64_t m_vertex_capacity = 0; - int64_t m_index_count = 0; - int64_t m_index_capacity = 0; + i64 m_vertex_count = 0; + i64 m_vertex_capacity = 0; + i64 m_index_count = 0; + i64 m_index_capacity = 0; public: ID3D11Buffer* vertex_buffer = nullptr; @@ -567,7 +570,7 @@ namespace Blah index_buffer->Release(); } - virtual void index_data(IndexFormat format, const void* indices, int64_t count) override + virtual void index_data(IndexFormat format, const void* indices, i64 count) override { m_index_count = count; @@ -579,8 +582,8 @@ namespace Blah switch (format) { - case IndexFormat::UInt16: index_stride = sizeof(int16_t); break; - case IndexFormat::UInt32: index_stride = sizeof(int32_t); break; + case IndexFormat::UInt16: index_stride = sizeof(i16); break; + case IndexFormat::UInt32: index_stride = sizeof(i32); break; } if (m_index_capacity > 0 && indices) @@ -589,7 +592,7 @@ namespace Blah if (index_buffer) index_buffer->Release(); index_buffer = nullptr; - + // buffer description D3D11_BUFFER_DESC desc = { 0 }; desc.ByteWidth = (UINT)(index_stride * m_index_capacity); @@ -621,7 +624,7 @@ namespace Blah } } - virtual void vertex_data(const VertexFormat& format, const void* vertices, int64_t count) override + virtual void vertex_data(const VertexFormat& format, const void* vertices, i64 count) override { m_vertex_count = count; @@ -669,22 +672,22 @@ namespace Blah } } - virtual void instance_data(const VertexFormat& format, const void* instances, int64_t count) override + virtual void instance_data(const VertexFormat& format, const void* instances, i64 count) override { } - virtual int64_t index_count() const override + virtual i64 index_count() const override { return m_index_count; } - virtual int64_t vertex_count() const override + virtual i64 vertex_count() const override { return m_vertex_count; } - virtual int64_t instance_count() const override + virtual i64 instance_count() const override { return 0; } @@ -696,7 +699,7 @@ namespace Blah state.last_size = Point(App::draw_width(), App::draw_height()); // Define Swap Chain - DXGI_SWAP_CHAIN_DESC desc = { 0 }; + DXGI_SWAP_CHAIN_DESC desc = {}; desc.BufferDesc.RefreshRate.Numerator = 0; desc.BufferDesc.RefreshRate.Denominator = 1; desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; @@ -705,7 +708,6 @@ namespace Blah desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; desc.BufferCount = 1; desc.OutputWindow = (HWND)PlatformBackend::d3d11_get_hwnd(); - //desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; desc.Windowed = true; // Creation Flags @@ -764,10 +766,10 @@ namespace Blah dxgi_device->GetAdapter(&dxgi_adapter); dxgi_adapter->GetDesc(&adapter_desc); - Log::print("D3D11 %ls", adapter_desc.Description); + Log::info("D3D11 %ls", adapter_desc.Description); } else - Log::print("D3D11"); + Log::info("D3D11"); } return true; @@ -1056,7 +1058,7 @@ namespace Blah } } - void GraphicsBackend::clear_backbuffer(Color color, float depth, uint8_t stencil, ClearMask mask) + void GraphicsBackend::clear_backbuffer(Color color, float depth, u8 stencil, ClearMask mask) { if (((int)mask & (int)ClearMask::Color) == (int)ClearMask::Color) { @@ -1243,6 +1245,9 @@ namespace Blah int size = 0; switch (it.type) { + case UniformType::None: break; + case UniformType::Texture2D: break; + case UniformType::Sampler2D: break; case UniformType::Float: size = 1; break; case UniformType::Float2: size = 2; break; case UniformType::Float3: size = 3; break; @@ -1282,7 +1287,7 @@ namespace Blah { bool same_format = true; for (int n = 0; same_format && n < format.attributes.size(); n++) - if (it.format.attributes[n].index != format.attributes[n].index || + if (it.format.attributes[n].index != format.attributes[n].index || it.format.attributes[n].type != format.attributes[n].type || it.format.attributes[n].normalized != format.attributes[n].normalized) same_format = false; @@ -1304,6 +1309,7 @@ namespace Blah { switch (format.attributes[i].type) { + case VertexType::None: break; case VertexType::Float: it->Format = DXGI_FORMAT_R32_FLOAT; break; case VertexType::Float2: it->Format = DXGI_FORMAT_R32G32_FLOAT; break; case VertexType::Float3: it->Format = DXGI_FORMAT_R32G32B32_FLOAT; break; @@ -1320,6 +1326,7 @@ namespace Blah { switch (format.attributes[i].type) { + case VertexType::None: break; case VertexType::Float: it->Format = DXGI_FORMAT_R32_FLOAT; break; case VertexType::Float2: it->Format = DXGI_FORMAT_R32G32_FLOAT; break; case VertexType::Float3: it->Format = DXGI_FORMAT_R32G32B32_FLOAT; break; @@ -1396,7 +1403,7 @@ namespace Blah desc.RenderTarget[0].DestBlendAlpha = blend_factor(blend.alpha_dst); } - for (int i = 1; i < 8; i ++) + for (int i = 1; i < 8; i++) desc.RenderTarget[i] = desc.RenderTarget[0]; ID3D11BlendState* blend_state = nullptr; @@ -1428,22 +1435,25 @@ namespace Blah switch (sampler.filter) { + case TextureFilter::None: break; case TextureFilter::Nearest: desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; break; case TextureFilter::Linear: desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; break; } switch (sampler.wrap_x) { + case TextureWrap::None: break; case TextureWrap::Clamp: desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; break; case TextureWrap::Repeat: desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; break; } switch (sampler.wrap_y) { + case TextureWrap::None: break; case TextureWrap::Clamp: desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; break; case TextureWrap::Repeat: desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; break; } - + ID3D11SamplerState* result; auto hr = state.device->CreateSamplerState(&desc, &result); @@ -1512,15 +1522,15 @@ namespace Blah switch (pass.depth) { - case Compare::None: desc.DepthFunc = D3D11_COMPARISON_NEVER; break; - case Compare::Always: desc.DepthFunc = D3D11_COMPARISON_ALWAYS; break; - case Compare::Never: desc.DepthFunc = D3D11_COMPARISON_NEVER; break; - case Compare::Less: desc.DepthFunc = D3D11_COMPARISON_LESS; break; - case Compare::Equal: desc.DepthFunc = D3D11_COMPARISON_EQUAL; break; - case Compare::LessOrEqual: desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; break; - case Compare::Greater: desc.DepthFunc = D3D11_COMPARISON_GREATER; break; - case Compare::NotEqual: desc.DepthFunc = D3D11_COMPARISON_NOT_EQUAL; break; - case Compare::GreatorOrEqual: desc.DepthFunc = D3D11_COMPARISON_GREATER_EQUAL; break; + case Compare::None: desc.DepthFunc = D3D11_COMPARISON_NEVER; break; + case Compare::Always: desc.DepthFunc = D3D11_COMPARISON_ALWAYS; break; + case Compare::Never: desc.DepthFunc = D3D11_COMPARISON_NEVER; break; + case Compare::Less: desc.DepthFunc = D3D11_COMPARISON_LESS; break; + case Compare::Equal: desc.DepthFunc = D3D11_COMPARISON_EQUAL; break; + case Compare::LessOrEqual: desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; break; + case Compare::Greater: desc.DepthFunc = D3D11_COMPARISON_GREATER; break; + case Compare::NotEqual: desc.DepthFunc = D3D11_COMPARISON_NOT_EQUAL; break; + case Compare::GreatorOrEqual: desc.DepthFunc = D3D11_COMPARISON_GREATER_EQUAL; break; } ID3D11DepthStencilState* result; @@ -1538,4 +1548,4 @@ namespace Blah } } -#endif // BLAH_USE_D3D11 +#endif // BLAH_GRAPHICS_D3D11 diff --git a/src/internal/graphics_backend_dummy.cpp b/src/internal/graphics_backend_dummy.cpp index 8e5c2dc..f3359fc 100644 --- a/src/internal/graphics_backend_dummy.cpp +++ b/src/internal/graphics_backend_dummy.cpp @@ -1,8 +1,8 @@ -#if !(defined(BLAH_USE_OPENGL) || defined(BLAH_USE_D3D11)) +#if !(defined(BLAH_GRAPHICS_OPENGL) || defined(BLAH_GRAPHICS_D3D11)) #include "../internal/graphics_backend.h" #include "../internal/platform_backend.h" -#include +#include namespace Blah { @@ -134,9 +134,9 @@ namespace Blah class Dummy_Mesh : public Mesh { private: - int64_t m_index_count = 0; - int64_t m_vertex_count = 0; - int64_t m_instance_count = 0; + i64 m_index_count = 0; + i64 m_vertex_count = 0; + i64 m_instance_count = 0; public: Dummy_Mesh() @@ -144,32 +144,32 @@ namespace Blah } - virtual void index_data(IndexFormat format, const void* indices, int64_t count) override + virtual void index_data(IndexFormat format, const void* indices, i64 count) override { m_index_count = count; } - virtual void vertex_data(const VertexFormat& format, const void* vertices, int64_t count) override + virtual void vertex_data(const VertexFormat& format, const void* vertices, i64 count) override { m_vertex_count = count; } - virtual void instance_data(const VertexFormat& format, const void* instances, int64_t count) override + virtual void instance_data(const VertexFormat& format, const void* instances, i64 count) override { m_instance_count = count; } - virtual int64_t index_count() const override + virtual i64 index_count() const override { return m_index_count; } - virtual int64_t vertex_count() const override + virtual i64 vertex_count() const override { return m_vertex_count; } - virtual int64_t instance_count() const override + virtual i64 instance_count() const override { return m_instance_count; } @@ -177,7 +177,7 @@ namespace Blah bool GraphicsBackend::init() { - Log::print("Dummy Renderer"); + Log::info("Dummy Renderer"); return true; } @@ -193,7 +193,7 @@ namespace Blah const RendererFeatures& GraphicsBackend::features() { - static const RendererFeatures features { false, true, 4096 }; + static const RendererFeatures features{ false, true, 4096 }; return features; } @@ -232,4 +232,4 @@ namespace Blah } } -#endif // !(defined(BLAH_USE_OPENGL) || defined(BLAH_USE_D3D11)) +#endif // !(defined(BLAH_GRAPHICS_OPENGL) || defined(BLAH_GRAPHICS_D3D11)) diff --git a/src/internal/graphics_backend_gl.cpp b/src/internal/graphics_backend_gl.cpp index 329cb57..530e17d 100644 --- a/src/internal/graphics_backend_gl.cpp +++ b/src/internal/graphics_backend_gl.cpp @@ -1,8 +1,8 @@ -#ifdef BLAH_USE_OPENGL +#ifdef BLAH_GRAPHICS_OPENGL #include "../internal/graphics_backend.h" #include "../internal/platform_backend.h" -#include +#include #include #include #include @@ -401,7 +401,7 @@ namespace Blah else if (severity != GL_DEBUG_SEVERITY_NOTIFICATION) Log::warn("GL (%s:%s) %s", typeName, severityName, message); else - Log::print("GL (%s) %s", typeName, message); + Log::info("GL (%s) %s", typeName, message); } // assign attributes @@ -484,7 +484,7 @@ namespace Blah components = 4; } - uint32_t location = (uint32_t)(attribute.index); + u32 location = (u32)(attribute.index); gl.EnableVertexAttribArray(location); gl.VertexAttribPointer(location, components, type, attribute.normalized, format.stride, (void*)ptr); gl.VertexAttribDivisor(location, divisor); @@ -674,7 +674,7 @@ namespace Blah GLuint m_id; int m_width; int m_height; - StackVector m_attachments; + StackVector m_attachments; public: @@ -749,7 +749,7 @@ namespace Blah return m_height; } - virtual void clear(Color color, float depth, uint8_t stencil, ClearMask mask) override + virtual void clear(Color color, float depth, u8 stencil, ClearMask mask) override { int clear = 0; @@ -967,13 +967,13 @@ namespace Blah GLuint m_index_buffer; GLuint m_vertex_buffer; GLuint m_instance_buffer; - int64_t m_index_count; - int64_t m_vertex_count; - int64_t m_instance_count; - uint16_t m_vertex_size; - uint16_t m_instance_size; - uint8_t m_vertex_attribs_enabled; - uint8_t m_instance_attribs_enabled; + i64 m_index_count; + i64 m_vertex_count; + i64 m_instance_count; + u16 m_vertex_size; + u16 m_instance_size; + u8 m_vertex_attribs_enabled; + u8 m_instance_attribs_enabled; Vector m_vertex_attribs; Vector m_instance_attribs; GLenum m_index_format; @@ -1026,7 +1026,7 @@ namespace Blah return m_index_size; } - virtual void index_data(IndexFormat format, const void* indices, int64_t count) override + virtual void index_data(IndexFormat format, const void* indices, i64 count) override { m_index_count = count; @@ -1053,7 +1053,7 @@ namespace Blah gl.BindVertexArray(0); } - virtual void vertex_data(const VertexFormat& format, const void* vertices, int64_t count) override + virtual void vertex_data(const VertexFormat& format, const void* vertices, i64 count) override { m_vertex_count = count; @@ -1074,7 +1074,7 @@ namespace Blah gl.BindVertexArray(0); } - virtual void instance_data(const VertexFormat& format, const void* instances, int64_t count) override + virtual void instance_data(const VertexFormat& format, const void* instances, i64 count) override { m_instance_count = count; @@ -1095,17 +1095,17 @@ namespace Blah gl.BindVertexArray(0); } - virtual int64_t index_count() const override + virtual i64 index_count() const override { return m_index_count; } - virtual int64_t vertex_count() const override + virtual i64 vertex_count() const override { return m_vertex_count; } - virtual int64_t instance_count() const override + virtual i64 instance_count() const override { return m_instance_count; } @@ -1147,7 +1147,7 @@ namespace Blah gl.GetIntegerv(0x0D33, &gl.max_texture_size); // log - Log::print("OpenGL %s, %s", + Log::info("OpenGL %s, %s", gl.GetString(GL_VERSION), gl.GetString(GL_RENDERER)); @@ -1496,7 +1496,7 @@ namespace Blah } } - void GraphicsBackend::clear_backbuffer(Color color, float depth, uint8_t stencil, ClearMask mask) + void GraphicsBackend::clear_backbuffer(Color color, float depth, u8 stencil, ClearMask mask) { int clear = 0; @@ -1517,4 +1517,4 @@ namespace Blah } } -#endif // BLAH_USE_OPENGL +#endif // BLAH_GRAPHICS_OPENGL diff --git a/src/internal/input_backend.h b/src/internal/input_backend.h index cb8c93b..8c09624 100644 --- a/src/internal/input_backend.h +++ b/src/internal/input_backend.h @@ -37,7 +37,7 @@ namespace Blah // Call this when a Controller is connected. Note that the Name parameter must be kept valid // until on_controller_disconnect is called with the same index. - void on_controller_connect(int index, const char* name, int isGamepad, int buttonCount, int axisCount, uint16_t vendor, uint16_t product, uint16_t version); + void on_controller_connect(int index, const char* name, int isGamepad, int buttonCount, int axisCount, u16 vendor, u16 product, u16 version); // Call this when a controller is disconnected void on_controller_disconnect(int index); diff --git a/src/internal/platform_backend.h b/src/internal/platform_backend.h index 9b1016e..4f94a7e 100644 --- a/src/internal/platform_backend.h +++ b/src/internal/platform_backend.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include @@ -22,7 +22,7 @@ namespace Blah void shutdown(); // The time, in ticks (microseconds) since the Application was started - uint64_t ticks(); + u64 ticks(); // Called every frame void frame(); @@ -91,19 +91,19 @@ namespace Blah bool file_open(const char* path, FileHandle* handle, FileMode mode); // Returns the length of the file - int64_t file_length(FileHandle file); + i64 file_length(FileHandle file); // Returns the Position of the file - int64_t file_position(FileHandle file); + i64 file_position(FileHandle file); // Seeks the Position of the file and returns the new position from the start of the file - int64_t file_seek(FileHandle file, int64_t seekTo); + i64 file_seek(FileHandle file, i64 seekTo); // Reads a specific number of elements of a given size from the file into ptr - int64_t file_read(FileHandle file, void* ptr, int64_t size); + i64 file_read(FileHandle file, void* ptr, i64 size); // Writes a specific number of elements of the given size from ptr to the file - int64_t file_write(FileHandle file, const void* ptr, int64_t size); + i64 file_write(FileHandle file, const void* ptr, i64 size); // Closes a file void file_close(FileHandle file); diff --git a/src/internal/platform_backend_sdl2.cpp b/src/internal/platform_backend_sdl2.cpp index 6350233..3716edd 100644 --- a/src/internal/platform_backend_sdl2.cpp +++ b/src/internal/platform_backend_sdl2.cpp @@ -1,4 +1,4 @@ -#ifdef BLAH_USE_SDL2 +#ifdef BLAH_PLATFORM_SDL2 #include "../internal/platform_backend.h" #include "../internal/input_backend.h" @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -41,12 +41,34 @@ namespace void sdl_log(void* userdata, int category, SDL_LogPriority priority, const char* message) { if (priority <= SDL_LOG_PRIORITY_INFO) - Log::print(message); + Log::info(message); else if (priority <= SDL_LOG_PRIORITY_WARN) Log::warn(message); else Log::error(message); } + + int find_joystick_index(SDL_JoystickID instance_id) + { + for (int i = 0; i < Blah::Input::max_controllers; i++) + if (joysticks[i] != nullptr && SDL_JoystickInstanceID(joysticks[i]) == instance_id) + return i; + return -1; + } + + int find_gamepad_index(SDL_JoystickID instance_id) + { + for (int i = 0; i < Blah::Input::max_controllers; i++) + { + if (gamepads[i] != nullptr) + { + auto joystick = SDL_GameControllerGetJoystick(gamepads[i]); + if (SDL_JoystickInstanceID(joystick) == instance_id) + return i; + } + } + return -1; + } } bool PlatformBackend::init(const Config* config) @@ -65,7 +87,7 @@ bool PlatformBackend::init(const Config* config) // Get SDL version SDL_version version; SDL_GetVersion(&version); - Log::print("SDL v%i.%i.%i", version.major, version.minor, version.patch); + Log::info("SDL v%i.%i.%i", version.major, version.minor, version.patch); // initialize SDL if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) != 0) @@ -170,11 +192,11 @@ void PlatformBackend::shutdown() SDL_Quit(); } -uint64_t PlatformBackend::ticks() +u64 PlatformBackend::ticks() { auto counter = SDL_GetPerformanceCounter(); auto per_second = (double)SDL_GetPerformanceFrequency(); - return (uint64_t)(counter * (Time::ticks_per_second / per_second)); + return (u64)(counter * (Time::ticks_per_second / per_second)); } // Macro defined by X11 conflicts with MouseButton enum @@ -247,109 +269,132 @@ void PlatformBackend::frame() // Joystick Controller else if (event.type == SDL_JOYDEVICEADDED) { - Sint32 index = event.jdevice.which; + auto index = event.jdevice.which; - if (SDL_IsGameController(index) == SDL_FALSE) + if (SDL_IsGameController(index) == SDL_FALSE && index >= 0 && index < Input::max_controllers) { - SDL_Joystick* ptr = joysticks[index] = SDL_JoystickOpen(index); - const char* name = SDL_JoystickName(ptr); - int button_count = SDL_JoystickNumButtons(ptr); - int axis_count = SDL_JoystickNumAxes(ptr); - uint16_t vendor = SDL_JoystickGetVendor(ptr); - uint16_t product = SDL_JoystickGetProduct(ptr); - uint16_t version = SDL_JoystickGetProductVersion(ptr); + auto ptr = joysticks[index] = SDL_JoystickOpen(index); + auto name = SDL_JoystickName(ptr); + auto button_count = SDL_JoystickNumButtons(ptr); + auto axis_count = SDL_JoystickNumAxes(ptr); + auto vendor = SDL_JoystickGetVendor(ptr); + auto product = SDL_JoystickGetProduct(ptr); + auto version = SDL_JoystickGetProductVersion(ptr); InputBackend::on_controller_connect(index, name, 0, button_count, axis_count, vendor, product, version); } } else if (event.type == SDL_JOYDEVICEREMOVED) { - Sint32 index = event.jdevice.which; - - if (SDL_IsGameController(index) == SDL_FALSE) + auto index = find_joystick_index(event.jdevice.which); + if (index >= 0) { - InputBackend::on_controller_disconnect(index); - SDL_JoystickClose(joysticks[index]); + if (SDL_IsGameController(index) == SDL_FALSE) + { + InputBackend::on_controller_disconnect(index); + SDL_JoystickClose(joysticks[index]); + } } } else if (event.type == SDL_JOYBUTTONDOWN) { - Sint32 index = event.jdevice.which; - if (SDL_IsGameController(index) == SDL_FALSE) - InputBackend::on_button_down(index, event.jbutton.button); + auto index = find_joystick_index(event.jdevice.which); + if (index >= 0) + { + if (SDL_IsGameController(index) == SDL_FALSE) + InputBackend::on_button_down(index, event.jbutton.button); + } } else if (event.type == SDL_JOYBUTTONUP) { - Sint32 index = event.jdevice.which; - if (SDL_IsGameController(index) == SDL_FALSE) - InputBackend::on_button_up(index, event.jbutton.button); + auto index = find_joystick_index(event.jdevice.which); + if (index >= 0) + { + if (SDL_IsGameController(index) == SDL_FALSE) + InputBackend::on_button_up(index, event.jbutton.button); + } } else if (event.type == SDL_JOYAXISMOTION) { - Sint32 index = event.jaxis.which; - if (SDL_IsGameController(index) == SDL_FALSE) + auto index = find_joystick_index(event.jdevice.which); + if (index >= 0) { - float value; - if (event.jaxis.value >= 0) - value = event.jaxis.value / 32767.0f; - else - value = event.jaxis.value / 32768.0f; - InputBackend::on_axis_move(index, event.jaxis.axis, value); + if (SDL_IsGameController(index) == SDL_FALSE) + { + float value; + if (event.jaxis.value >= 0) + value = event.jaxis.value / 32767.0f; + else + value = event.jaxis.value / 32768.0f; + InputBackend::on_axis_move(index, event.jaxis.axis, value); + } } } // Gamepad Controller else if (event.type == SDL_CONTROLLERDEVICEADDED) { - Sint32 index = event.cdevice.which; - SDL_GameController* ptr = gamepads[index] = SDL_GameControllerOpen(index); - const char* name = SDL_GameControllerName(ptr); - uint16_t vendor = SDL_GameControllerGetVendor(ptr); - uint16_t product = SDL_GameControllerGetProduct(ptr); - uint16_t version = SDL_GameControllerGetProductVersion(ptr); + auto index = event.cdevice.which; + if (index >= 0 && index < Input::max_controllers) + { + auto ptr = gamepads[index] = SDL_GameControllerOpen(index); + auto name = SDL_GameControllerName(ptr); + auto vendor = SDL_GameControllerGetVendor(ptr); + auto product = SDL_GameControllerGetProduct(ptr); + auto version = SDL_GameControllerGetProductVersion(ptr); - InputBackend::on_controller_connect(index, name, 1, 15, 6, vendor, product, version); + InputBackend::on_controller_connect(index, name, 1, 15, 6, vendor, product, version); + } } else if (event.type == SDL_CONTROLLERDEVICEREMOVED) { - Sint32 index = event.cdevice.which; - InputBackend::on_controller_disconnect(index); - SDL_GameControllerClose(gamepads[index]); + auto index = find_gamepad_index(event.cdevice.which); + if (index >= 0) + { + InputBackend::on_controller_disconnect(index); + SDL_GameControllerClose(gamepads[index]); + } } else if (event.type == SDL_CONTROLLERBUTTONDOWN) { - Sint32 index = event.cbutton.which; + auto index = find_gamepad_index(event.cdevice.which); + if (index >= 0) + { + int button = (int)Button::None; + if (event.cbutton.button >= 0 && event.cbutton.button < 15) + button = event.cbutton.button; // NOTE: These map directly to Engine Buttons enum! - int button = (int)Button::None; - if (event.cbutton.button >= 0 && event.cbutton.button < 15) - button = event.cbutton.button; // NOTE: These map directly to Engine Buttons enum! - - InputBackend::on_button_down(index, button); + InputBackend::on_button_down(index, button); + } } else if (event.type == SDL_CONTROLLERBUTTONUP) { - Sint32 index = event.cbutton.which; + auto index = find_gamepad_index(event.cdevice.which); + if (index >= 0) + { + int button = (int)Button::None; + if (event.cbutton.button >= 0 && event.cbutton.button < 15) + button = event.cbutton.button; // NOTE: These map directly to Engine Buttons enum! - int button = (int)Button::None; - if (event.cbutton.button >= 0 && event.cbutton.button < 15) - button = event.cbutton.button; // NOTE: These map directly to Engine Buttons enum! - - InputBackend::on_button_up(index, button); + InputBackend::on_button_up(index, button); + } } else if (event.type == SDL_CONTROLLERAXISMOTION) { - Sint32 index = event.caxis.which; + auto index = find_gamepad_index(event.cdevice.which); + if (index >= 0) + { + int axis = (int)Axis::None; + if (event.caxis.axis >= 0 && event.caxis.axis < 6) + axis = event.caxis.axis; // NOTE: These map directly to Engine Axis enum! - int axis = (int)Axis::None; - if (event.caxis.axis >= 0 && event.caxis.axis < 6) - axis = event.caxis.axis; // NOTE: These map directly to Engine Axis enum! + float value; + if (event.caxis.value >= 0) + value = event.caxis.value / 32767.0f; + else + value = event.caxis.value / 32768.0f; - float value; - if (event.caxis.value >= 0) - value = event.caxis.value / 32767.0f; - else - value = event.caxis.value / 32768.0f; - - InputBackend::on_axis_move(index, axis, value); + InputBackend::on_axis_move(index, axis, value); + } } } } @@ -357,7 +402,7 @@ void PlatformBackend::frame() void PlatformBackend::sleep(int milliseconds) { if (milliseconds >= 0) - SDL_Delay((uint32_t)milliseconds); + SDL_Delay((u32)milliseconds); } void PlatformBackend::present() @@ -611,27 +656,27 @@ bool PlatformBackend::file_open(const char* path, PlatformBackend::FileHandle* h return ptr != nullptr; } -int64_t PlatformBackend::file_length(PlatformBackend::FileHandle stream) +i64 PlatformBackend::file_length(PlatformBackend::FileHandle stream) { return SDL_RWsize((SDL_RWops*)stream); } -int64_t PlatformBackend::file_position(PlatformBackend::FileHandle stream) +i64 PlatformBackend::file_position(PlatformBackend::FileHandle stream) { return SDL_RWtell((SDL_RWops*)stream); } -int64_t PlatformBackend::file_seek(PlatformBackend::FileHandle stream, int64_t seekTo) +i64 PlatformBackend::file_seek(PlatformBackend::FileHandle stream, i64 seekTo) { return SDL_RWseek((SDL_RWops*)stream, seekTo, RW_SEEK_SET); } -int64_t PlatformBackend::file_read(PlatformBackend::FileHandle stream, void* ptr, int64_t length) +i64 PlatformBackend::file_read(PlatformBackend::FileHandle stream, void* ptr, i64 length) { return SDL_RWread((SDL_RWops*)stream, ptr, sizeof(char), length); } -int64_t PlatformBackend::file_write(PlatformBackend::FileHandle stream, const void* ptr, int64_t length) +i64 PlatformBackend::file_write(PlatformBackend::FileHandle stream, const void* ptr, i64 length) { return SDL_RWwrite((SDL_RWops*)stream, ptr, sizeof(char), length); } @@ -677,4 +722,4 @@ void* PlatformBackend::d3d11_get_hwnd() #endif } -#endif // BLAH_USE_SDL2 +#endif // BLAH_PLATFORM_SDL2 diff --git a/src/internal/platform_backend_win32.cpp b/src/internal/platform_backend_win32.cpp new file mode 100644 index 0000000..7742723 --- /dev/null +++ b/src/internal/platform_backend_win32.cpp @@ -0,0 +1,776 @@ +#ifdef BLAH_PLATFORM_WIN32 + +// Note: +// This backend implementation is unfinished! +// It's missing a few things, namely: +// - Controller Support +// - Mouse wheel +// - Text input +// - Probably other stuff? +// (And error testing) + +#include "../internal/platform_backend.h" +#include "../internal/input_backend.h" +#include "../internal/graphics_backend.h" +#include +#include +#include +#include +#include +#include + +#define WIN32_LEAN_AND_MEAN +#include +#include // for SetProcessDPIAware +#include // for File Reading/Writing +#include // for file explore +#include // for known folder +#include // for ticks method + +using namespace Blah; +namespace fs = std::filesystem; + +namespace +{ + // Primary Window + HWND g_hwnd; + + // Working Directories + FilePath g_working_directory; + FilePath g_user_directory; + + // Timestamp for calculating ticks + std::chrono::system_clock::duration g_start_time; + + // OpenGL Methods + // These are only loaded if built using the OpenGL Backend + HMODULE g_opengl_dll; + void* (WINAPI* g_wglGetProcAddress) (const char* proc); + HGLRC(WINAPI* g_wglCreateContext) (HDC hdc); + BOOL(WINAPI* g_wglDeleteContext) (HGLRC hglrc); + BOOL(WINAPI* g_wglMakeCurrent) (HDC hdc, HGLRC hglrc); + + // fullscreen state + RECT g_windowed_position; + bool g_fullscreen = false; +} + +Key blah_scancode_to_key(WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK blah_window_procedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +bool PlatformBackend::init(const Config* config) +{ + // Required to call this for Windows + // I'm not sure why SDL2 doesn't do this on Windows automatically? + SetProcessDPIAware(); + + // Get the hInstance + HINSTANCE hInstance = GetModuleHandle(NULL); + + // Create the Window Class + WNDCLASS wc = {}; + wc.lpfnWndProc = DefWindowProc; + wc.lpszClassName = "BLAH WINDOW"; + wc.hInstance = hInstance; + wc.lpfnWndProc = blah_window_procedure; + wc.hCursor = NULL; + wc.hIcon = NULL; + wc.lpszMenuName = NULL; + wc.hbrBackground = (HBRUSH)COLOR_WINDOW; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + + // Register the Window class + RegisterClass(&wc); + + // Create the Window Instance + g_hwnd = CreateWindow("BLAH WINDOW", config->name, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 640, 480, NULL, NULL, hInstance, NULL); + + // Failed to create the Window + if (g_hwnd == NULL) + { + Log::error("Window Creation Failed"); + return false; + } + + // Create the OpenGL device info + if (App::renderer() == Renderer::OpenGL) + { + // Load the DLL + g_opengl_dll = LoadLibraryA("opengl32.dll"); + if (g_opengl_dll == NULL) + { + Log::error("OpenGL Instantiation Failed - unable to fine opengl32.dll"); + return false; + } + + // Get the Windows GL functions we need + g_wglGetProcAddress = (void*(WINAPI*) (const char*))GetProcAddress(g_opengl_dll, "wglGetProcAddress"); + g_wglCreateContext = (HGLRC(WINAPI*) (HDC))GetProcAddress(g_opengl_dll, "wglCreateContext"); + g_wglDeleteContext = (BOOL(WINAPI*) (HGLRC))GetProcAddress(g_opengl_dll, "wglDeleteContext"); + g_wglMakeCurrent = (BOOL(WINAPI*) (HDC, HGLRC))GetProcAddress(g_opengl_dll, "wglMakeCurrent"); + + // TODO: + // Allow the user to apply (some of) these values before instantiation. + // Also applies to the SDL2 Backend + + PIXELFORMATDESCRIPTOR pfd = + { + sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd + 1, // version number + PFD_DRAW_TO_WINDOW | // support window + PFD_SUPPORT_OPENGL | // support OpenGL + PFD_DOUBLEBUFFER, // double buffered + PFD_TYPE_RGBA, // RGBA type + 32, // 24-bit color depth + 0, 0, 0, 0, 0, 0, // color bits ignored + 0, // no alpha buffer + 0, // shift bit ignored + 0, // no accumulation buffer + 0, 0, 0, 0, // accum bits ignored + 24, // 32-bit z-buffer + 8, // no stencil buffer + 0, // no auxiliary buffer + PFD_MAIN_PLANE, // main layer + 0, // reserved + 0, 0, 0 // layer masks ignored + }; + + HDC hdc = GetDC(g_hwnd); + + // get the best available match of pixel format for the device context + int pixel_format = ChoosePixelFormat(hdc, &pfd); + + // make that the pixel format of the device context + SetPixelFormat(hdc, pixel_format, &pfd); + } + + // Reset our game timer + g_start_time = std::chrono::system_clock::now().time_since_epoch(); + + // Get Working Directory + { + TCHAR buffer[MAX_PATH]; + GetModuleFileName(NULL, buffer, MAX_PATH); + + auto normalized = Path::normalize(buffer); + auto end = normalized.last_index_of('/');; + if (end >= 0) + g_working_directory = FilePath(normalized.begin(), normalized.begin() + end); + else + g_working_directory = normalized; + g_working_directory.append("/"); + } + + // Get Application User Directory + { + PWSTR path = NULL; + if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE, NULL, &path))) + { + auto end = path; + while (*end != 0) end++; + + FilePath result; + result.append_utf16((u16*)path, (u16*)end); + + g_user_directory = Path::join(Path::normalize(result), config->name) + "/"; + } + CoTaskMemFree(path); + } + + // Not currently fullscreen + g_fullscreen = false; + + // Finished Platform Setup + return true; +} + +void PlatformBackend::ready() +{ + // Setup Window Size + { + auto scale = get_content_scale(); + int sw = (int)(App::config()->width * scale); + int sh = (int)(App::config()->height * scale); + set_size(sw, sh); + } + + // Display the game window + ShowWindow(g_hwnd, SW_SHOW); +} + +void PlatformBackend::shutdown() +{ + DestroyWindow(g_hwnd); +} + +u64 PlatformBackend::ticks() +{ + // Todo: + // This should account for whatever Time::ticks_per_second is set to + + auto now = std::chrono::system_clock::now().time_since_epoch(); + return std::chrono::duration_cast(now - g_start_time).count(); +} + +LRESULT CALLBACK blah_window_procedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_CLOSE: + { + auto config = App::config(); + if (config->on_exit_request != nullptr) + config->on_exit_request(); + return 0; + } + + case WM_DESTROY: + PostQuitMessage(0); + return 0; + + case WM_LBUTTONDOWN: + InputBackend::on_mouse_down(MouseButton::Left); + return 0; + + case WM_LBUTTONUP: + InputBackend::on_mouse_up(MouseButton::Left); + return 0; + + case WM_RBUTTONDOWN: + InputBackend::on_mouse_down(MouseButton::Right); + return 0; + + case WM_RBUTTONUP: + InputBackend::on_mouse_up(MouseButton::Right); + return 0; + + case WM_MBUTTONDOWN: + InputBackend::on_mouse_down(MouseButton::Middle); + return 0; + + case WM_MBUTTONUP: + InputBackend::on_mouse_up(MouseButton::Middle); + return 0; + + case WM_MOUSEMOVE: + InputBackend::on_mouse_move((u16)(lParam), lParam >> 16); + return 0; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + { + auto is_repeat = ((lParam & (1 << 30)) >> 30) == 1; + if (!is_repeat) + { + auto key = blah_scancode_to_key(wParam, lParam); + if (key != Key::Unknown) + InputBackend::on_key_down(key); + } + return 0; + } + + case WM_KEYUP: + case WM_SYSKEYUP: + { + auto key = blah_scancode_to_key(wParam, lParam); + if (key != Key::Unknown) + InputBackend::on_key_up(key); + return 0; + } + } + + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +void PlatformBackend::frame() +{ + // Catch & Dispatch Window Messages + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +void PlatformBackend::sleep(int milliseconds) +{ + if (milliseconds > 0) + Sleep(milliseconds); +} + +void PlatformBackend::present() +{ + if (App::renderer() == Renderer::OpenGL) + { + HDC hdc = GetDC(g_hwnd); + SwapBuffers(hdc); + } +} + +const char* PlatformBackend::get_title() +{ + return nullptr; +} + +void PlatformBackend::set_title(const char* title) +{ + SetWindowText(g_hwnd, title); +} + +void PlatformBackend::get_position(int* x, int* y) +{ + RECT rect; + if (GetWindowRect(g_hwnd, &rect)) + { + *x = rect.left; + *y = rect.top; + } +} + +void PlatformBackend::set_position(int x, int y) +{ + int w, h; + get_size(&w, &h); + SetWindowPos(g_hwnd, NULL, x, y, w, h, 0); +} + +void PlatformBackend::set_fullscreen(bool enabled) +{ + if (g_fullscreen == enabled) + return; + + g_fullscreen = enabled; + + if (g_fullscreen) + { + GetWindowRect(g_hwnd, &g_windowed_position); + + int w = GetSystemMetrics(SM_CXSCREEN); + int h = GetSystemMetrics(SM_CYSCREEN); + SetWindowLongPtr(g_hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP); + SetWindowPos(g_hwnd, HWND_TOP, 0, 0, w, h, 0); + ShowWindow(g_hwnd, SW_SHOW); + } + else + { + SetWindowLongPtr(g_hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); + SetWindowPos(g_hwnd, HWND_TOP, + g_windowed_position.left, + g_windowed_position.top, + g_windowed_position.right - g_windowed_position.left, + g_windowed_position.bottom - g_windowed_position.top, 0); + ShowWindow(g_hwnd, SW_SHOW); + } +} + +void PlatformBackend::get_size(int* width, int* height) +{ + RECT rect; + if (GetClientRect(g_hwnd, &rect)) + { + *width = rect.right - rect.left; + *height = rect.bottom - rect.top; + } +} + +void PlatformBackend::set_size(int width, int height) +{ + RECT client_rect; + RECT border_rect; + + GetClientRect(g_hwnd, &client_rect); + GetWindowRect(g_hwnd, &border_rect); + + int border_width = (border_rect.right - border_rect.left) - (client_rect.right - client_rect.left); + int border_height = (border_rect.bottom - border_rect.top) - (client_rect.bottom - client_rect.top); + + SetWindowPos(g_hwnd, NULL, border_rect.left, border_rect.top, width + border_width, height + border_height, 0); +} + +void PlatformBackend::get_draw_size(int* width, int* height) +{ + RECT rect; + if (GetClientRect(g_hwnd, &rect)) + { + *width = rect.right - rect.left; + *height = rect.bottom - rect.top; + } +} + +float PlatformBackend::get_content_scale() +{ + // base value of Windows DPI + // as seen here: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforwindow + constexpr float base_raw_value = 96.0f; + + UINT raw_value = GetDpiForWindow(g_hwnd); + + return (raw_value / base_raw_value); +} + +// FILE IO + +const char* PlatformBackend::app_path() +{ + return g_working_directory.cstr(); +} + +const char* PlatformBackend::user_path() +{ + return g_user_directory.cstr(); +} + +bool PlatformBackend::file_exists(const char* path) +{ + return fs::is_regular_file(path); +} + +bool PlatformBackend::file_delete(const char* path) +{ + return fs::remove(path); +} + +bool PlatformBackend::dir_create(const char* path) +{ + std::error_code error; + return fs::create_directories(path, error); +} + +bool PlatformBackend::dir_exists(const char* path) +{ + return fs::is_directory(path); +} + +bool PlatformBackend::dir_delete(const char* path) +{ + BLAH_ERROR("not implemented"); + return false; +} + +void PlatformBackend::dir_enumerate(Vector& list, const char* path, bool recursive) +{ + if (fs::is_directory(path)) + { + if (recursive) + { + for (auto& p : fs::recursive_directory_iterator(path)) + list.emplace_back(p.path().string().c_str()); + } + else + { + for (auto& p : fs::directory_iterator(path)) + list.emplace_back(p.path().string().c_str()); + } + } +} + +void PlatformBackend::dir_explore(const char* path) +{ + ShellExecute(NULL, "open", path, NULL, NULL, SW_SHOWDEFAULT); +} + +bool PlatformBackend::file_open(const char* path, PlatformBackend::FileHandle* handle, FileMode mode) +{ + int access = 0; + int creation = 0; + + if (((int)mode & (int)FileMode::Read) == (int)FileMode::Read) + { + access |= GENERIC_READ; + creation = OPEN_EXISTING; + } + + if (((int)mode & (int)FileMode::Write) == (int)FileMode::Write) + { + access |= GENERIC_WRITE; + creation = OPEN_ALWAYS; + } + + auto result = CreateFile(path, access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL); + + if (result == INVALID_HANDLE_VALUE) + return false; + + *handle = result; + return true; +} + +i64 PlatformBackend::file_length(PlatformBackend::FileHandle handle) +{ + // Todo: cache this value? not sure how performant it is + + LARGE_INTEGER file_size; + if (GetFileSizeEx(handle, &file_size)) + return file_size.QuadPart; + + return 0; +} + +i64 PlatformBackend::file_position(PlatformBackend::FileHandle handle) +{ + // Todo: handle 64-bit values properly + // Todo: cache this value? not sure how performant it is + return SetFilePointer(handle, 0, NULL, FILE_CURRENT); +} + +i64 PlatformBackend::file_seek(PlatformBackend::FileHandle handle, i64 seekTo) +{ + // Todo: handle 64-bit values properly + return SetFilePointer(handle, seekTo, NULL, FILE_BEGIN); +} + +i64 PlatformBackend::file_read(PlatformBackend::FileHandle handle, void* ptr, i64 length) +{ + DWORD read = 0; + if (ReadFile(handle, ptr, length, &read, NULL)) + return read; + return 0; +} + +i64 PlatformBackend::file_write(PlatformBackend::FileHandle handle, const void* ptr, i64 length) +{ + DWORD written = 0; + if (WriteFile(handle, ptr, length, &written, NULL)) + return written; + return 0; +} + +void PlatformBackend::file_close(PlatformBackend::FileHandle handle) +{ + CloseHandle(handle); +} + +void* PlatformBackend::gl_get_func(const char* name) +{ + // this check is taken from https://www.khronos.org/opengl/wiki/Load_OpenGL_Functions + // wglGetProcAddress doesn't always return valid pointers for some specific methods? + + void* p = (void*)g_wglGetProcAddress(name); + if ((p == 0) || + (p == (void*)0x1) || + (p == (void*)0x2) || + (p == (void*)0x3) || + (p == (void*)-1)) + { + p = (void*)GetProcAddress(g_opengl_dll, name); + } + + return p; +} + +void* PlatformBackend::gl_context_create() +{ + HDC hdc = GetDC(g_hwnd); + return g_wglCreateContext(hdc); +} + +void PlatformBackend::gl_context_make_current(void* context) +{ + if (context != nullptr) + { + HDC hdc = GetDC(g_hwnd); + g_wglMakeCurrent(hdc, (HGLRC)context); + } + else + g_wglMakeCurrent(NULL, NULL); +} + +void PlatformBackend::gl_context_destroy(void* context) +{ + g_wglDeleteContext((HGLRC)context); +} + +void* PlatformBackend::d3d11_get_hwnd() +{ + return g_hwnd; +} + +Key blah_scancode_to_key(WPARAM wParam, LPARAM lParam) +{ + Key key = Key::Unknown; + + switch (wParam) + { + case VK_CANCEL: key = Key::Cancel; break; + case VK_BACK: key = Key::Backspace; break; + case VK_TAB: key = Key::Tab; break; + case VK_CLEAR: key = Key::Clear; break; + case VK_RETURN: key = Key::Enter; break; + case VK_SHIFT: key = Key::LeftShift; break; + case VK_CONTROL: key = Key::LeftControl; break; + case VK_MENU: key = Key::Menu; break; + case VK_PAUSE: key = Key::Pause; break; + case VK_CAPITAL: key = Key::Capslock; break; + case VK_ESCAPE: key = Key::Escape; break; + case VK_SPACE: key = Key::Space; break; + case VK_PRIOR: key = Key::Prior; break; + case VK_END: key = Key::End; break; + case VK_HOME: key = Key::Home; break; + case VK_LEFT: key = Key::Left; break; + case VK_UP: key = Key::Up; break; + case VK_RIGHT: key = Key::Right; break; + case VK_DOWN: key = Key::Down; break; + case VK_SELECT: key = Key::Select; break; + case VK_PRINT: key = Key::PrintScreen; break; + case VK_EXECUTE: key = Key::Execute; break; + case VK_SNAPSHOT: key = Key::PrintScreen; break; + case VK_INSERT: key = Key::Insert; break; + case VK_DELETE: key = Key::Delete; break; + case VK_HELP: key = Key::Help; break; + case VK_LWIN: key = Key::LeftOS; break; + case VK_RWIN: key = Key::RightOS; break; + case VK_APPS: key = Key::Application; break; + case VK_SLEEP: key = Key::Unknown; break; + case VK_NUMPAD0: key = Key::Keypad0; break; + case VK_NUMPAD1: key = Key::Keypad1; break; + case VK_NUMPAD2: key = Key::Keypad2; break; + case VK_NUMPAD3: key = Key::Keypad3; break; + case VK_NUMPAD4: key = Key::Keypad4; break; + case VK_NUMPAD5: key = Key::Keypad5; break; + case VK_NUMPAD6: key = Key::Keypad6; break; + case VK_NUMPAD7: key = Key::Keypad7; break; + case VK_NUMPAD8: key = Key::Keypad8; break; + case VK_NUMPAD9: key = Key::Keypad9; break; + case VK_F1: key = Key::F1; break; + case VK_F2: key = Key::F2; break; + case VK_F3: key = Key::F3; break; + case VK_F4: key = Key::F4; break; + case VK_F5: key = Key::F5; break; + case VK_F6: key = Key::F6; break; + case VK_F7: key = Key::F7; break; + case VK_F8: key = Key::F8; break; + case VK_F9: key = Key::F9; break; + case VK_F10: key = Key::F10; break; + case VK_F11: key = Key::F11; break; + case VK_F12: key = Key::F12; break; + case VK_F13: key = Key::F13; break; + case VK_F14: key = Key::F14; break; + case VK_F15: key = Key::F15; break; + case VK_F16: key = Key::F16; break; + case VK_F17: key = Key::F17; break; + case VK_F18: key = Key::F18; break; + case VK_F19: key = Key::F19; break; + case VK_F20: key = Key::F20; break; + case VK_F21: key = Key::F21; break; + case VK_F22: key = Key::F22; break; + case VK_F23: key = Key::F23; break; + case VK_F24: key = Key::F24; break; + case VK_NUMLOCK: key = Key::Numlock; break; + case VK_LSHIFT: key = Key::LeftShift; break; + case VK_RSHIFT: key = Key::RightShift; break; + case VK_LCONTROL: key = Key::LeftControl; break; + case VK_RCONTROL: key = Key::RightControl; break; + case VK_VOLUME_MUTE: key = Key::Mute; break; + case VK_VOLUME_DOWN: key = Key::VolumeDown; break; + case VK_VOLUME_UP: key = Key::VolumeUp; break; + } + + if (key == Key::Unknown) + { + int scancode = (lParam >> 16) & 0xFF; + + switch (scancode) + { + case 1: key = Key::Escape; break; + case 2: key = Key::D1; break; + case 3: key = Key::D2; break; + case 4: key = Key::D3; break; + case 5: key = Key::D4; break; + case 6: key = Key::D5; break; + case 7: key = Key::D6; break; + case 8: key = Key::D7; break; + case 9: key = Key::D8; break; + case 10: key = Key::D9; break; + case 11: key = Key::D0; break; + case 12: key = Key::Minus; break; + case 13: key = Key::Equals; break; + case 14: key = Key::Backspace; break; + case 15: key = Key::Tab; break; + case 16: key = Key::Q; break; + case 17: key = Key::W; break; + case 18: key = Key::E; break; + case 19: key = Key::R; break; + case 20: key = Key::T; break; + case 21: key = Key::Y; break; + case 22: key = Key::U; break; + case 23: key = Key::I; break; + case 24: key = Key::O; break; + case 25: key = Key::P; break; + case 26: key = Key::LeftBracket; break; + case 27: key = Key::RightBracket; break; + case 28: key = Key::Enter; break; + case 29: key = Key::LeftControl; break; + case 30: key = Key::A; break; + case 31: key = Key::S; break; + case 32: key = Key::D; break; + case 33: key = Key::F; break; + case 34: key = Key::G; break; + case 35: key = Key::H; break; + case 36: key = Key::J; break; + case 37: key = Key::K; break; + case 38: key = Key::L; break; + case 39: key = Key::Semicolon; break; + case 40: key = Key::Apostrophe; break; + case 41: key = Key::Tilde; break; + case 42: key = Key::LeftShift; break; + case 43: key = Key::Backslash; break; + case 44: key = Key::Z; break; + case 45: key = Key::X; break; + case 46: key = Key::C; break; + case 47: key = Key::V; break; + case 48: key = Key::B; break; + case 49: key = Key::N; break; + case 50: key = Key::M; break; + case 51: key = Key::Comma; break; + case 52: key = Key::Period; break; + case 53: key = Key::Slash; break; + case 54: key = Key::RightShift; break; + case 55: key = Key::PrintScreen; break; + case 56: key = Key::LeftAlt; break; + case 57: key = Key::Space; break; + case 58: key = Key::Capslock; break; + case 59: key = Key::F1; break; + case 60: key = Key::F2; break; + case 61: key = Key::F3; break; + case 62: key = Key::F4; break; + case 63: key = Key::F5; break; + case 64: key = Key::F6; break; + case 65: key = Key::F7; break; + case 66: key = Key::F8; break; + case 67: key = Key::F9; break; + case 68: key = Key::F10; break; + case 71: key = Key::Home; break; + case 72: key = Key::Up; break; + case 73: key = Key::PageUp; break; + case 74: key = Key::KeypadMinus; break; + case 75: key = Key::Left; break; + case 76: key = Key::Keypad5; break; + case 77: key = Key::Right; break; + case 78: key = Key::KeypadPlus; break; + case 79: key = Key::End; break; + case 80: key = Key::Down; break; + case 81: key = Key::PageDown; break; + case 82: key = Key::Insert; break; + case 83: key = Key::Delete; break; + case 87: key = Key::F11; break; + case 88: key = Key::F12; break; + case 89: key = Key::Pause; break; + case 91: key = Key::LeftOS; break; + case 92: key = Key::RightOS; break; + case 93: key = Key::Application; break; + case 100: key = Key::F13; break; + case 101: key = Key::F14; break; + case 102: key = Key::F15; break; + case 103: key = Key::F16; break; + case 104: key = Key::F17; break; + case 105: key = Key::F18; break; + case 106: key = Key::F19; break; + } + } + + return key; +} + +#endif // BLAH_PLATFORM_WINDOWS diff --git a/src/math/calc.cpp b/src/math/calc.cpp index 67a4b5b..f14c676 100644 --- a/src/math/calc.cpp +++ b/src/math/calc.cpp @@ -43,16 +43,6 @@ Vec2 Calc::approach(const Vec2& t, const Vec2& target, float delta) return t + (target - t).normal() * delta; } -float Calc::clamp(float t, float min, float max) -{ - return t < min ? min : (t > max ? max : t); -} - -int Calc::clamp_int(int t, int min, int max) -{ - return t < min ? min : (t > max ? max : t); -} - float Calc::map(float t, float old_min, float old_max, float new_min, float new_max) { return new_min + ((t - old_min) / (old_max - old_min)) * (new_max - new_min); diff --git a/src/math/color.cpp b/src/math/color.cpp index 3faae74..cd3b516 100644 --- a/src/math/color.cpp +++ b/src/math/color.cpp @@ -1,4 +1,5 @@ #include +#include #include using namespace Blah; @@ -7,45 +8,69 @@ char const hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B #define LT_HEX_VALUE(n) ((n >= '0' && n <= '9') ? (n - '0') : ((n >= 'A' && n <= 'F') ? (10 + n - 'A') : ((n >= 'a' && n <= 'f') ? (10 + n - 'a') : 0))) Color::Color() - : r(0), g(0), b(0), a(0) {} + : r(0) + , g(0) + , b(0) + , a(0) {} -Color::Color(int rgb) : - r((uint8_t)((rgb & 0xFF0000) >> 16)), - g((uint8_t)((rgb & 0x00FF00) >> 8)), - b((uint8_t)(rgb & 0x0000FF)), - a(255) {} +Color::Color(int rgb) + : r((u8)((rgb & 0xFF0000) >> 16)) + , g((u8)((rgb & 0x00FF00) >> 8)) + , b((u8)(rgb & 0x0000FF)) + , a(255) {} -Color::Color(int rgb, float alpha) : - r((int)(((uint8_t)((rgb & 0xFF0000) >> 16)) * alpha)), - g((int)(((uint8_t)((rgb & 0x00FF00) >> 8)) * alpha)), - b((int)(((uint8_t)(rgb & 0x0000FF)) * alpha)), - a((int)(255 * alpha)) {} +Color::Color(int rgb, float alpha) + : r((int)(((u8)((rgb & 0xFF0000) >> 16)) * alpha)) + , g((int)(((u8)((rgb & 0x00FF00) >> 8)) * alpha)) + , b((int)(((u8)(rgb & 0x0000FF)) * alpha)) + , a((int)(255 * alpha)) {} -Color::Color(uint8_t r, uint8_t g, uint8_t b) - : r(r), g(g), b(b), a(255) {} +Color::Color(u8 r, u8 g, u8 b) + : r(r) + , g(g) + , b(b) + , a(255) {} -Color::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) - : r(r), g(g), b(b), a(a) {} +Color::Color(u8 r, u8 g, u8 b, u8 a) + : r(r) + , g(g) + , b(b) + , a(a) {} + +Color::Color(const Vec3& vec3) + : r((int)(vec3.x * 255)) + , g((int)(vec3.y * 255)) + , b((int)(vec3.z * 255)) + , a((int)(255)) {} + +Color::Color(const Vec3& vec3, float alpha) + : r((int)(vec3.x * alpha * 255)) + , g((int)(vec3.y* alpha * 255)) + , b((int)(vec3.z* alpha * 255)) + , a((int)(alpha * 255)) {} Color::Color(const Vec4& vec4) - : r((int)(vec4.x * 255)), g((int)(vec4.y * 255)), b((int)(vec4.z * 255)), a((int)(vec4.w * 255)) {} + : r((int)(vec4.x * 255)) + , g((int)(vec4.y * 255)) + , b((int)(vec4.z * 255)) + , a((int)(vec4.w * 255)) {} -Color::Color(const char* value) : r(0), g(0), b(0), a(255) +Color::Color(const String& value) + : r(0) + , g(0) + , b(0) + , a(255) { - int length = 0; - while (value[length] != '\0' && length < 10) - length ++; - int offset = 0; - if (length > 0 && value[0] == '#') + if (value.length() > 0 && value[0] == '#') offset = 1; - else if (length >= 1 && value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) + else if (value.length() >= 1 && value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) offset = 2; - if (length - offset >= 8) + if (value.length() - offset >= 8) a = (LT_HEX_VALUE(value[offset + 6]) << 4) + LT_HEX_VALUE(value[offset + 7]); - if (length - offset >= 6) + if (value.length() - offset >= 6) { r = (LT_HEX_VALUE(value[offset + 0]) << 4) + LT_HEX_VALUE(value[offset + 1]); g = (LT_HEX_VALUE(value[offset + 2]) << 4) + LT_HEX_VALUE(value[offset + 3]); @@ -60,13 +85,13 @@ void Color::premultiply() b = b * a / 255; } -uint32_t Color::to_rgba() const +u32 Color::to_rgba() const { return - ((uint32_t)r << 24) | - ((uint32_t)g << 16) | - ((uint32_t)b << 8) | - (uint32_t)a; + ((u32)r << 24) | + ((u32)g << 16) | + ((u32)b << 8) | + (u32)a; } Vec4 Color::to_vec4() const @@ -110,24 +135,24 @@ String Color::to_hex_rgb() const return str; } -Color Color::from_rgba(uint32_t value) +Color Color::from_rgba(u32 value) { return { - (uint8_t)((value & 0xFF000000) >> 24), - (uint8_t)((value & 0x00FF0000) >> 16), - (uint8_t)((value & 0x0000FF00) >> 8), - (uint8_t)((value & 0x000000FF)) + (u8)((value & 0xFF000000) >> 24), + (u8)((value & 0x00FF0000) >> 16), + (u8)((value & 0x0000FF00) >> 8), + (u8)((value & 0x000000FF)) }; } -Color Color::from_rgb(uint32_t value) +Color Color::from_rgb(u32 value) { return { - (uint8_t)((value & 0xFF0000) >> 16), - (uint8_t)((value & 0x00FF00) >> 8), - (uint8_t)((value & 0x0000FF)) + (u8)((value & 0xFF0000) >> 16), + (u8)((value & 0x00FF00) >> 8), + (u8)((value & 0x0000FF)) }; } @@ -137,10 +162,10 @@ Color Color::lerp(Color a, Color b, float amount) if (amount > 1) amount = 1; return Color( - (uint8_t)(a.r + (b.r - a.r) * amount), - (uint8_t)(a.g + (b.g - a.g) * amount), - (uint8_t)(a.b + (b.b - a.b) * amount), - (uint8_t)(a.a + (b.a - a.a) * amount) + (u8)(a.r + (b.r - a.r) * amount), + (u8)(a.g + (b.g - a.g) * amount), + (u8)(a.b + (b.b - a.b) * amount), + (u8)(a.a + (b.a - a.a) * amount) ); } @@ -155,9 +180,9 @@ Color Color::operator*(float multiply) const Color& Color::operator=(const int rgb) { - r = (uint8_t)((rgb & 0xFF0000) >> 16); - g = (uint8_t)((rgb & 0x00FF00) >> 8); - b = (uint8_t)(rgb & 0x0000FF); + r = (u8)((rgb & 0xFF0000) >> 16); + g = (u8)((rgb & 0x00FF00) >> 8); + b = (u8)(rgb & 0x0000FF); a = 255; return *this; } diff --git a/src/math/line.cpp b/src/math/line.cpp index fce49bb..647adf3 100644 --- a/src/math/line.cpp +++ b/src/math/line.cpp @@ -31,7 +31,7 @@ Vec2 Line::closest_point(const Vec2& pt) const Vec2 v = b - a; Vec2 w = pt - a; float t = Vec2::dot(w, v) / Vec2::dot(v, v); - t = Calc::clamp(t, 0, 1); + t = Calc::clamp(t, 0.0f, 1.0f); return v * t + a; } diff --git a/src/math/mat4x4.cpp b/src/math/mat4x4.cpp index 3ea3ca0..7c2b063 100644 --- a/src/math/mat4x4.cpp +++ b/src/math/mat4x4.cpp @@ -1,5 +1,5 @@ #include -#include +#include using namespace Blah; diff --git a/src/math/stopwatch.cpp b/src/math/stopwatch.cpp index b28d39b..33191cb 100644 --- a/src/math/stopwatch.cpp +++ b/src/math/stopwatch.cpp @@ -14,13 +14,12 @@ void Stopwatch::reset() start_time = std::chrono::duration_cast(system_clock::now().time_since_epoch()).count(); } -uint64_t Stopwatch::milliseconds() +u64 Stopwatch::milliseconds() { return microseconds() / 1000; } - -uint64_t Stopwatch::microseconds() +u64 Stopwatch::microseconds() { return std::chrono::duration_cast(system_clock::now().time_since_epoch()).count() - start_time; } diff --git a/src/streams/bufferstream.cpp b/src/streams/bufferstream.cpp index 3990e66..92c35e9 100644 --- a/src/streams/bufferstream.cpp +++ b/src/streams/bufferstream.cpp @@ -42,7 +42,7 @@ BufferStream::~BufferStream() delete[] m_buffer; } -int64_t BufferStream::read_into(void* ptr, int64_t len) +i64 BufferStream::read_into(void* ptr, i64 len) { if (m_buffer == nullptr || ptr == nullptr) return 0; @@ -58,7 +58,7 @@ int64_t BufferStream::read_into(void* ptr, int64_t len) return len; } -int64_t BufferStream::write_from(const void* ptr, int64_t len) +i64 BufferStream::write_from(const void* ptr, i64 len) { if (len < 0) return 0; diff --git a/src/streams/filestream.cpp b/src/streams/filestream.cpp index 36f5ca7..92b798d 100644 --- a/src/streams/filestream.cpp +++ b/src/streams/filestream.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "../internal/platform_backend.h" #include @@ -11,7 +11,7 @@ FileStream::FileStream() m_mode = FileMode::None; } -FileStream::FileStream(const char* path, FileMode mode) +FileStream::FileStream(const FilePath& path, FileMode mode) : m_mode(mode) { if (!PlatformBackend::file_open(path, &m_handle, mode)) @@ -39,7 +39,7 @@ FileStream::~FileStream() PlatformBackend::file_close(m_handle); } -int64_t FileStream::length() const +i64 FileStream::length() const { if (m_handle == nullptr) return 0; @@ -47,7 +47,7 @@ int64_t FileStream::length() const return PlatformBackend::file_length(m_handle); } -int64_t FileStream::position() const +i64 FileStream::position() const { if (m_handle == nullptr) return 0; @@ -55,7 +55,7 @@ int64_t FileStream::position() const return PlatformBackend::file_position(m_handle); } -int64_t FileStream::seek(int64_t seek_to) +i64 FileStream::seek(i64 seek_to) { if (m_handle == nullptr) return 0; @@ -63,7 +63,22 @@ int64_t FileStream::seek(int64_t seek_to) return PlatformBackend::file_seek(m_handle, seek_to); } -int64_t FileStream::read_into(void* ptr, int64_t length) +bool FileStream::is_open() const +{ + return m_handle != nullptr; +} + +bool FileStream::is_readable() const +{ + return m_handle != nullptr && (m_mode == FileMode::ReadWrite || m_mode == FileMode::Read); +} + +bool FileStream::is_writable() const +{ + return m_handle != nullptr && (m_mode == FileMode::ReadWrite || m_mode == FileMode::Write); +} + +i64 FileStream::read_into(void* ptr, i64 length) { if (m_handle == nullptr) { @@ -74,7 +89,7 @@ int64_t FileStream::read_into(void* ptr, int64_t length) return PlatformBackend::file_read(m_handle, ptr, length); } -int64_t FileStream::write_from(const void* ptr, int64_t length) +i64 FileStream::write_from(const void* ptr, i64 length) { if (length <= 0) return 0; diff --git a/src/streams/memorystream.cpp b/src/streams/memorystream.cpp index fafc807..9c3b04e 100644 --- a/src/streams/memorystream.cpp +++ b/src/streams/memorystream.cpp @@ -6,7 +6,7 @@ using namespace Blah; MemoryStream::MemoryStream() : m_data(nullptr), m_length(0), m_position(0) {} -MemoryStream::MemoryStream(char* data, int64_t length) +MemoryStream::MemoryStream(char* data, i64 length) : m_data(data), m_length(length), m_position(0) {} MemoryStream::MemoryStream(MemoryStream&& src) noexcept @@ -28,7 +28,7 @@ MemoryStream& MemoryStream::operator=(MemoryStream&& src) noexcept return *this; } -int64_t MemoryStream::read_into(void* ptr, int64_t len) +i64 MemoryStream::read_into(void* ptr, i64 len) { if (len < 0 || ptr == nullptr) return 0; @@ -41,7 +41,7 @@ int64_t MemoryStream::read_into(void* ptr, int64_t len) return len; } -int64_t MemoryStream::write_from(const void* ptr, int64_t len) +i64 MemoryStream::write_from(const void* ptr, i64 len) { if (len < 0 || ptr == nullptr) return 0; diff --git a/src/streams/stream.cpp b/src/streams/stream.cpp index b393537..5001ca1 100644 --- a/src/streams/stream.cpp +++ b/src/streams/stream.cpp @@ -4,10 +4,10 @@ using namespace Blah; -int64_t Stream::pipe(Stream& stream, int64_t length) +i64 Stream::pipe(Stream& stream, i64 length) { const int BUFFER_LENGTH = 4096; - int64_t result = 0; + i64 result = 0; char buffer[BUFFER_LENGTH]; while (length > 0) @@ -59,12 +59,12 @@ String Stream::read_line() return result; } -int64_t Stream::write(const void* buffer, int64_t length) +i64 Stream::write(const void* buffer, i64 length) { return write_from(buffer, length); } -int64_t Stream::write(const String& string) +i64 Stream::write(const String& string) { return write_from(string.begin(), string.length()); }