mirror of
https://github.com/NoelFB/blah.git
synced 2024-11-28 16:58:57 +08:00
Merge branch 'master' into master
This commit is contained in:
commit
6c13753c64
|
@ -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)
|
||||
# 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()
|
||||
# Attempt to find SDL2
|
||||
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)
|
||||
# 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})
|
||||
|
|
19
README.md
19
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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <new>
|
||||
#include <initializer_list>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <stdarg.h>
|
||||
#include <cstdio>
|
||||
#include <blah/containers/vector.h>
|
||||
|
@ -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<String> 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<int T>
|
||||
class StrOf : public Str
|
||||
{
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#pragma once
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <type_traits>
|
||||
#include <initializer_list>
|
||||
#include <new>
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
// A lightweight Vector implementation
|
||||
template<class T>
|
||||
class Vector
|
||||
{
|
||||
|
@ -19,6 +21,7 @@ namespace Blah
|
|||
Vector(int capacity);
|
||||
Vector(const Vector& src);
|
||||
Vector(Vector&& src) noexcept;
|
||||
Vector(std::initializer_list<T> list);
|
||||
~Vector();
|
||||
|
||||
Vector& operator=(const Vector& src);
|
||||
|
@ -95,6 +98,17 @@ namespace Blah
|
|||
src.m_count = 0;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Vector<T>::Vector(std::initializer_list<T> list)
|
||||
{
|
||||
m_buffer = nullptr;
|
||||
m_count = m_capacity = 0;
|
||||
reserve(list.size());
|
||||
for (auto& it : list)
|
||||
push_back(std::move(it));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline Vector<T>::~Vector()
|
||||
{
|
||||
|
|
|
@ -1,31 +1,72 @@
|
|||
#pragma once
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
// Application Event Functions
|
||||
using AppEventFn = std::function<void()>;
|
||||
|
||||
// Application Logging Functions
|
||||
using AppLogFn = std::function<void(const char* message, Log::Category category)>;
|
||||
|
||||
// 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<FrameBuffer>;
|
||||
|
||||
// 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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
// error / abort
|
||||
#if defined(DEBUG) || defined(_DEBUG)
|
||||
|
@ -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, ...);
|
||||
}
|
||||
}
|
|
@ -5,40 +5,71 @@
|
|||
namespace Blah
|
||||
{
|
||||
using FilePath = StrOf<265>;
|
||||
class FileStream;
|
||||
|
||||
enum class FileMode
|
||||
{
|
||||
None = 0,
|
||||
Read = 1 << 1,
|
||||
Write = 1 << 2,
|
||||
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<FilePath> enumerate(const FilePath& str, bool recursive = true);
|
||||
|
||||
// Enumerates over a directory and returns a list of files & directories
|
||||
Vector<FilePath> 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<typename ... Args>
|
||||
FilePath join(const FilePath& a, const FilePath& b, const Args&... args)
|
||||
{
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <blah/core/common.h>
|
||||
|
||||
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;
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <blah/containers/str.h>
|
||||
#include <blah/containers/vector.h>
|
||||
#include <blah/drawing/subtexture.h>
|
||||
#include <blah/math/vec2.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
class Font;
|
||||
|
||||
class SpriteFont
|
||||
{
|
||||
public:
|
||||
struct Character
|
||||
{
|
||||
Subtexture subtexture;
|
||||
float advance = 0;
|
||||
Vec2 offset;
|
||||
};
|
||||
private:
|
||||
// charset & kerning maps
|
||||
std::unordered_map<uint32_t, Character> m_characters;
|
||||
std::unordered_map<uint64_t, float> m_kerning;
|
||||
|
||||
// built texture
|
||||
Vector<TextureRef> 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<TextureRef>& 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;
|
||||
};
|
||||
}
|
|
@ -5,8 +5,8 @@
|
|||
#include <blah/math/mat3x2.h>
|
||||
#include <blah/math/mat4x4.h>
|
||||
#include <blah/math/color.h>
|
||||
#include <blah/drawing/subtexture.h>
|
||||
#include <blah/drawing/spritefont.h>
|
||||
#include <blah/graphics/subtexture.h>
|
||||
#include <blah/graphics/spritefont.h>
|
||||
#include <blah/containers/vector.h>
|
||||
#include <blah/graphics/blend.h>
|
||||
#include <blah/graphics/sampler.h>
|
||||
|
@ -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<TextAlign>(static_cast<char>(lhs) | static_cast<char>(rhs)); }
|
||||
inline TextAlign operator&(TextAlign lhs, TextAlign rhs) { return static_cast<TextAlign>(static_cast<char>(lhs) & static_cast<char>(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
|
||||
|
@ -219,11 +224,11 @@ namespace Blah
|
|||
MeshRef m_mesh;
|
||||
Mat3x2 m_matrix;
|
||||
ColorMode m_color_mode;
|
||||
uint8_t m_tex_mult;
|
||||
uint8_t m_tex_wash;
|
||||
u8 m_tex_mult;
|
||||
u8 m_tex_wash;
|
||||
DrawBatch m_batch;
|
||||
Vector<Vertex> m_vertices;
|
||||
Vector<uint32_t> m_indices;
|
||||
Vector<u32> m_indices;
|
||||
Vector<Mat3x2> m_matrix_stack;
|
||||
Vector<Rect> m_scissor_stack;
|
||||
Vector<BlendMode> m_blend_stack;
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <blah/core/common.h>
|
||||
|
||||
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),
|
||||
|
|
|
@ -4,16 +4,8 @@
|
|||
#include <blah/math/color.h>
|
||||
#include <memory>
|
||||
|
||||
// 4 color attachments + 1 depth/stencil
|
||||
#define BLAH_ATTACHMENTS 5
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
typedef StackVector<TextureRef, BLAH_ATTACHMENTS> Attachments;
|
||||
|
||||
class FrameBuffer;
|
||||
typedef std::shared_ptr<FrameBuffer> 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<TextureRef, 5>;
|
||||
|
||||
class FrameBuffer;
|
||||
using FrameBufferRef = std::shared_ptr<FrameBuffer>;
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Blah
|
|||
class Material;
|
||||
typedef std::shared_ptr<Material> 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<TextureRef>& textures() const;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <memory>
|
||||
#include <blah/containers/stackvector.h>
|
||||
|
||||
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<VertexAttribute> 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<Mesh> 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;
|
||||
};
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <blah/math/rect.h>
|
||||
#include <blah/containers/str.h>
|
||||
#include <blah/graphics/texture.h>
|
||||
|
@ -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;
|
||||
|
|
|
@ -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() :
|
||||
|
|
|
@ -72,6 +72,7 @@ namespace Blah
|
|||
class Shader;
|
||||
typedef std::shared_ptr<Shader> ShaderRef;
|
||||
|
||||
// A shader used during Rendering
|
||||
class Shader
|
||||
{
|
||||
protected:
|
||||
|
|
132
include/blah/graphics/spritefont.h
Normal file
132
include/blah/graphics/spritefont.h
Normal file
|
@ -0,0 +1,132 @@
|
|||
#pragma once
|
||||
#include <blah/core/common.h>
|
||||
#include <blah/containers/str.h>
|
||||
#include <blah/containers/vector.h>
|
||||
#include <blah/graphics/subtexture.h>
|
||||
#include <blah/math/vec2.h>
|
||||
#include <blah/core/filesystem.h>
|
||||
#include <unordered_map>
|
||||
|
||||
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<CharRange>;
|
||||
|
||||
// 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<TextureRef>& 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<Codepoint, Character> m_characters;
|
||||
|
||||
// kerning
|
||||
// key is 2 codepoints combined ((first << 32) | second)
|
||||
std::unordered_map<u64, float> m_kerning;
|
||||
|
||||
// built texture
|
||||
Vector<TextureRef> m_atlas;
|
||||
};
|
||||
}
|
|
@ -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<Texture> TextureRef;
|
||||
|
||||
// A 2D Texture held by the GPU to be used during rendering
|
||||
class Texture
|
||||
{
|
||||
protected:
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
#include <blah/images/image.h>
|
||||
#include <blah/containers/str.h>
|
||||
#include <blah/streams/stream.h>
|
||||
#include <blah/core/filesystem.h>
|
||||
|
||||
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:
|
||||
|
@ -130,7 +131,7 @@ namespace Blah
|
|||
Vector<Color> palette;
|
||||
|
||||
Aseprite();
|
||||
Aseprite(const char* path);
|
||||
Aseprite(const FilePath& path);
|
||||
Aseprite(Stream& stream);
|
||||
Aseprite(const Aseprite& src);
|
||||
Aseprite(Aseprite&& src) noexcept;
|
||||
|
|
|
@ -2,50 +2,102 @@
|
|||
#include <blah/streams/stream.h>
|
||||
#include <blah/images/image.h>
|
||||
#include <blah/containers/str.h>
|
||||
#include <blah/core/filesystem.h>
|
||||
|
||||
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:
|
||||
|
|
|
@ -2,21 +2,31 @@
|
|||
#include <blah/math/color.h>
|
||||
#include <blah/math/rectI.h>
|
||||
#include <blah/math/point.h>
|
||||
#include <blah/core/filesystem.h>
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
|
@ -6,37 +6,67 @@
|
|||
#include <blah/containers/str.h>
|
||||
#include <blah/containers/vector.h>
|
||||
#include <blah/streams/bufferstream.h>
|
||||
#include <blah/core/filesystem.h>
|
||||
|
||||
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<Image> pages;
|
||||
Vector<Entry> 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<Entry>& 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<Entry> m_entries;
|
||||
|
||||
// adds a new entry
|
||||
void add_entry(u64 id, int w, int h, const Color* pixels);
|
||||
};
|
||||
}
|
299
include/blah/input/binding.h
Normal file
299
include/blah/input/binding.h
Normal file
|
@ -0,0 +1,299 @@
|
|||
#pragma once
|
||||
#include <blah/input/input.h>
|
||||
#include <blah/containers/stackvector.h>
|
||||
#include <blah/math/point.h>
|
||||
#include <blah/math/vec2.h>
|
||||
|
||||
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<Key, 16> keys;
|
||||
|
||||
// List of bound Buttons
|
||||
StackVector<ButtonBind, 16> buttons;
|
||||
|
||||
// List of bound Triggers / Axis
|
||||
StackVector<TriggerBind, 16> triggers;
|
||||
|
||||
// List of bound Mouse buttons
|
||||
StackVector<MouseButton, 16> mouse;
|
||||
|
||||
Binding() = default;
|
||||
|
||||
Binding(float press_buffer)
|
||||
: press_buffer(press_buffer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename ... Args>
|
||||
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<typename T, typename T2, typename ... Args>
|
||||
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<typename NegativeT, typename PositiveT>
|
||||
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<typename LeftT, typename RightT, typename UpT, typename DownT>
|
||||
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();
|
||||
};
|
||||
}
|
35
include/blah/input/binding_registry.h
Normal file
35
include/blah/input/binding_registry.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include <blah/input/binding.h>
|
||||
#include <blah/containers/vector.h>
|
||||
#include <memory>
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
using BindingRef = std::shared_ptr<Binding>;
|
||||
using AxisBindingRef = std::shared_ptr<AxisBinding>;
|
||||
using StickBindingRef = std::shared_ptr<StickBinding>;
|
||||
|
||||
// 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<std::weak_ptr<Binding>> bindings;
|
||||
static Vector<std::weak_ptr<AxisBinding>> axes;
|
||||
static Vector<std::weak_ptr<StickBinding>> sticks;
|
||||
};
|
||||
}
|
|
@ -1,11 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <blah/math/vec2.h>
|
||||
#include <blah/containers/str.h>
|
||||
|
||||
// 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) \
|
||||
|
@ -32,6 +36,7 @@
|
|||
DEFINE_KEY(X, 27) \
|
||||
DEFINE_KEY(Y, 28) \
|
||||
DEFINE_KEY(Z, 29) \
|
||||
\
|
||||
DEFINE_KEY(D1, 30) \
|
||||
DEFINE_KEY(D2, 31) \
|
||||
DEFINE_KEY(D3, 32) \
|
||||
|
@ -42,24 +47,27 @@
|
|||
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) \
|
||||
|
@ -72,6 +80,19 @@
|
|||
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) \
|
||||
|
@ -85,45 +106,17 @@
|
|||
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(Numlock, 83) \
|
||||
\
|
||||
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(Redo, 121) \
|
||||
DEFINE_KEY(Undo, 122) \
|
||||
DEFINE_KEY(Cut, 123) \
|
||||
DEFINE_KEY(Copy, 124) \
|
||||
|
@ -132,92 +125,69 @@
|
|||
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(Clear, 156) \
|
||||
DEFINE_KEY(Prior, 157) \
|
||||
DEFINE_KEY(Return2, 158) \
|
||||
DEFINE_KEY(Enter2, 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(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(LeftGui, 227) \
|
||||
DEFINE_KEY(LeftOS, 227) \
|
||||
DEFINE_KEY(RightControl, 228) \
|
||||
DEFINE_KEY(RightShift, 229) \
|
||||
DEFINE_KEY(RightAlt, 230) \
|
||||
DEFINE_KEY(RightGui, 231)
|
||||
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;
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
#pragma once
|
||||
#include <blah/input/input.h>
|
||||
|
||||
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; }
|
||||
};
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
#pragma once
|
||||
#include <blah/input/input.h>
|
||||
|
||||
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; }
|
||||
};
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
#pragma once
|
||||
#include <blah/input/input.h>
|
||||
#include <blah/math/vec2.h>
|
||||
#include <blah/math/point.h>
|
||||
|
||||
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; }
|
||||
};
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <blah/math/vec2.h>
|
||||
|
||||
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<class T>
|
||||
T clamp(T value, T min, T max) { return value < min ? min : (value > max ? max : value); }
|
||||
|
||||
template<class T, class U>
|
||||
T min(T a, U b) { return (T)(a < b ? a : b); }
|
||||
|
||||
|
|
|
@ -1,38 +1,41 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <blah/containers/str.h>
|
||||
|
||||
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);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
#include <blah/math/calc.h>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
|
||||
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";
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <blah/core/common.h>
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -8,22 +8,22 @@ 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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <blah/containers/str.h>
|
||||
#include <blah/streams/endian.h>
|
||||
#include <string.h>
|
||||
|
@ -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<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
|
||||
int64_t write(const T& value)
|
||||
i64 write(const T& value)
|
||||
{
|
||||
return write<T>(value, Endian::Little);
|
||||
}
|
||||
|
||||
// writes a number
|
||||
template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::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;
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <blah/core/app.h>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <blah/core/time.h>
|
||||
#include <blah/math/point.h>
|
||||
#include <blah/graphics/framebuffer.h>
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <blah/core/app.h>
|
||||
#include <stdarg.h> // for logging methods
|
||||
#include <stdio.h> // for sprintf
|
||||
|
||||
using namespace Blah;
|
||||
|
||||
void Log::print(const char* format, ...)
|
||||
void Log::info(const char* format, ...)
|
||||
{
|
||||
char msg[BLAH_MESSAGE];
|
||||
va_list ap;
|
|
@ -1,4 +1,5 @@
|
|||
#include <blah/core/filesystem.h>
|
||||
#include <blah/streams/filestream.h>
|
||||
#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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <blah/drawing/batch.h>
|
||||
#include <blah/graphics/batch.h>
|
||||
#include <blah/graphics/texture.h>
|
||||
#include <blah/graphics/framebuffer.h>
|
||||
#include <blah/graphics/mesh.h>
|
||||
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <blah/graphics/material.h>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <cstring>
|
||||
|
||||
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");
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ VertexFormat::VertexFormat(std::initializer_list<VertexAttribute> 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;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <blah/graphics/renderpass.h>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
#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(
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
#include <blah/drawing/spritefont.h>
|
||||
#include <blah/graphics/spritefont.h>
|
||||
#include <blah/images/font.h>
|
||||
#include <blah/images/packer.h>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
|
||||
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<uint32_t, int> glyphs;
|
||||
std::unordered_map<Codepoint, int> glyphs;
|
||||
Vector<Color> 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);
|
|
@ -1,4 +1,4 @@
|
|||
#include <blah/drawing/subtexture.h>
|
||||
#include <blah/graphics/subtexture.h>
|
||||
#include <blah/math/calc.h>
|
||||
|
||||
using namespace Blah;
|
|
@ -1,7 +1,7 @@
|
|||
#include <blah/graphics/texture.h>
|
||||
#include <blah/images/image.h>
|
||||
#include <blah/streams/stream.h>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
#include "../internal/graphics_backend.h"
|
||||
|
||||
using namespace Blah;
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
#include <blah/images/aseprite.h>
|
||||
#include <blah/streams/filestream.h>
|
||||
#include <blah/core/filesystem.h>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <blah/math/calc.h>
|
||||
|
||||
#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<uint32_t>(Endian::Little);
|
||||
stream.read<u32>(Endian::Little);
|
||||
|
||||
// magic number
|
||||
auto magic = stream.read<uint16_t>(Endian::Little);
|
||||
auto magic = stream.read<u16>(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<uint16_t>(Endian::Little);
|
||||
width = stream.read<uint16_t>(Endian::Little);
|
||||
height = stream.read<uint16_t>(Endian::Little);
|
||||
mode = static_cast<Aseprite::Modes>(stream.read<uint16_t>(Endian::Little) / 8);
|
||||
frame_count = stream.read<u16>(Endian::Little);
|
||||
width = stream.read<u16>(Endian::Little);
|
||||
height = stream.read<u16>(Endian::Little);
|
||||
mode = static_cast<Aseprite::Modes>(stream.read<u16>(Endian::Little) / 8);
|
||||
|
||||
// don't care about other info
|
||||
stream.read<uint32_t>(Endian::Little); // Flags
|
||||
stream.read<uint16_t>(Endian::Little); // Speed (deprecated)
|
||||
stream.read<uint32_t>(Endian::Little); // Should be 0
|
||||
stream.read<uint32_t>(Endian::Little); // Should be 0
|
||||
stream.read<uint8_t>(Endian::Little); // Palette entry
|
||||
stream.read<u32>(Endian::Little); // Flags
|
||||
stream.read<u16>(Endian::Little); // Speed (deprecated)
|
||||
stream.read<u32>(Endian::Little); // Should be 0
|
||||
stream.read<u32>(Endian::Little); // Should be 0
|
||||
stream.read<u8>(Endian::Little); // Palette entry
|
||||
stream.seek(stream.position() + 3); // Ignore these bytes
|
||||
stream.read<uint16_t>(Endian::Little); // Number of colors (0 means 256 for old sprites)
|
||||
stream.read<int8_t>(Endian::Little); // Pixel width
|
||||
stream.read<int8_t>(Endian::Little); // Pixel height
|
||||
stream.read<u16>(Endian::Little); // Number of colors (0 means 256 for old sprites)
|
||||
stream.read<i8>(Endian::Little); // Pixel width
|
||||
stream.read<i8>(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<uint32_t>(Endian::Little);
|
||||
auto frameEnd = frameStart + stream.read<u32>(Endian::Little);
|
||||
unsigned int chunks = 0;
|
||||
|
||||
// frame header
|
||||
{
|
||||
auto magic = stream.read<uint16_t>(Endian::Little); // magic number
|
||||
auto magic = stream.read<u16>(Endian::Little); // magic number
|
||||
if (magic != 0xF1FA)
|
||||
{
|
||||
BLAH_ERROR("File is not a valid Aseprite file");
|
||||
return;
|
||||
}
|
||||
|
||||
auto old_chunk_count = stream.read<uint16_t>(Endian::Little);
|
||||
frames[i].duration = stream.read<uint16_t>(Endian::Little);
|
||||
auto old_chunk_count = stream.read<u16>(Endian::Little);
|
||||
frames[i].duration = stream.read<u16>(Endian::Little);
|
||||
stream.seek(stream.position() + 2); // for future
|
||||
auto new_chunk_count = stream.read<uint32_t>(Endian::Little);
|
||||
auto new_chunk_count = stream.read<u32>(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<uint32_t>(Endian::Little);
|
||||
auto chunkType = static_cast<Chunks>(stream.read<uint16_t>(Endian::Little));
|
||||
auto chunkEnd = chunkStart + stream.read<u32>(Endian::Little);
|
||||
auto chunkType = static_cast<Chunks>(stream.read<u16>(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<LayerFlags>(stream.read<uint16_t>(Endian::Little));
|
||||
layer.flag = static_cast<LayerFlags>(stream.read<u16>(Endian::Little));
|
||||
layer.visible = ((int)layer.flag & (int)LayerFlags::Visible) == (int)LayerFlags::Visible;
|
||||
layer.type = static_cast<LayerTypes>(stream.read<uint16_t>(Endian::Little));
|
||||
layer.child_level = stream.read<uint16_t>(Endian::Little);
|
||||
stream.read<uint16_t>(Endian::Little); // width
|
||||
stream.read<uint16_t>(Endian::Little); // height
|
||||
layer.blendmode = stream.read<uint16_t>(Endian::Little);
|
||||
layer.alpha = stream.read<uint8_t>(Endian::Little);
|
||||
layer.type = static_cast<LayerTypes>(stream.read<u16>(Endian::Little));
|
||||
layer.child_level = stream.read<u16>(Endian::Little);
|
||||
stream.read<u16>(Endian::Little); // width
|
||||
stream.read<u16>(Endian::Little); // height
|
||||
layer.blendmode = stream.read<u16>(Endian::Little);
|
||||
layer.alpha = stream.read<u8>(Endian::Little);
|
||||
stream.seek(stream.position() + 3); // for future
|
||||
|
||||
layer.name.set_length(stream.read<uint16_t>(Endian::Little));
|
||||
layer.name.set_length(stream.read<u16>(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<uint16_t>(Endian::Little);
|
||||
cel.x = stream.read<uint16_t>(Endian::Little);
|
||||
cel.y = stream.read<uint16_t>(Endian::Little);
|
||||
cel.alpha = stream.read<uint8_t>(Endian::Little);
|
||||
cel.layer_index = stream.read<u16>(Endian::Little);
|
||||
cel.x = stream.read<u16>(Endian::Little);
|
||||
cel.y = stream.read<u16>(Endian::Little);
|
||||
cel.alpha = stream.read<u8>(Endian::Little);
|
||||
cel.linked_frame_index = -1;
|
||||
|
||||
auto celType = stream.read<uint16_t>(Endian::Little);
|
||||
auto celType = stream.read<u16>(Endian::Little);
|
||||
stream.seek(stream.position() + 7);
|
||||
|
||||
// RAW or DEFLATE
|
||||
if (celType == 0 || celType == 2)
|
||||
{
|
||||
auto width = stream.read<uint16_t>(Endian::Little);
|
||||
auto height = stream.read<uint16_t>(Endian::Little);
|
||||
auto width = stream.read<u16>(Endian::Little);
|
||||
auto height = stream.read<u16>(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<uint16_t>(Endian::Little);
|
||||
cel.linked_frame_index = stream.read<u16>(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<uint32_t>(Endian::Little);
|
||||
auto start = stream.read<uint32_t>(Endian::Little);
|
||||
auto end = stream.read<uint32_t>(Endian::Little);
|
||||
/* size */ stream.read<u32>(Endian::Little);
|
||||
auto start = stream.read<u32>(Endian::Little);
|
||||
auto end = stream.read<u32>(Endian::Little);
|
||||
stream.seek(stream.position() + 8);
|
||||
|
||||
palette.resize(palette.size() + (end - start + 1));
|
||||
|
||||
for (int p = 0, len = static_cast<int>(end - start) + 1; p < len; p++)
|
||||
{
|
||||
auto hasName = stream.read<uint16_t>(Endian::Little);
|
||||
palette[start + p] = stream.read<uint32_t>(Endian::Little);
|
||||
auto hasName = stream.read<u16>(Endian::Little);
|
||||
palette[start + p] = stream.read<u32>(Endian::Little);
|
||||
|
||||
if (hasName & 0xF000)
|
||||
{
|
||||
int len = stream.read<uint16_t>(Endian::Little);
|
||||
int len = stream.read<u16>(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<uint32_t>(Endian::Little);
|
||||
auto flags = stream.read<u32>(Endian::Little);
|
||||
|
||||
// has text
|
||||
if (flags & (1 << 0))
|
||||
{
|
||||
m_last_userdata->text.set_length(stream.read<uint16_t>(Endian::Little));
|
||||
m_last_userdata->text.set_length(stream.read<u16>(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<uint32_t>(Endian::Little);
|
||||
m_last_userdata->color = stream.read<u32>(Endian::Little);
|
||||
}
|
||||
}
|
||||
|
||||
void Aseprite::parse_tag(Stream& stream, int frame)
|
||||
{
|
||||
auto count = stream.read<uint16_t>(Endian::Little);
|
||||
auto count = stream.read<u16>(Endian::Little);
|
||||
stream.seek(stream.position() + 8);
|
||||
|
||||
for (int t = 0; t < count; t++)
|
||||
{
|
||||
Tag tag;
|
||||
tag.from = stream.read<uint16_t>(Endian::Little);
|
||||
tag.to = stream.read<uint16_t>(Endian::Little);
|
||||
tag.loops = static_cast<LoopDirections>(stream.read<int8_t>(Endian::Little));
|
||||
tag.from = stream.read<u16>(Endian::Little);
|
||||
tag.to = stream.read<u16>(Endian::Little);
|
||||
tag.loops = static_cast<LoopDirections>(stream.read<i8>(Endian::Little));
|
||||
|
||||
stream.seek(stream.position() + 8);
|
||||
tag.color = Color(stream.read<int8_t>(), stream.read<int8_t>(), stream.read<int8_t>(Endian::Little), 255);
|
||||
tag.color = Color(stream.read<i8>(), stream.read<i8>(), stream.read<i8>(Endian::Little), 255);
|
||||
stream.seek(stream.position() + 1);
|
||||
|
||||
tag.name.set_length(stream.read<uint16_t>(Endian::Little));
|
||||
tag.name.set_length(stream.read<u16>(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<uint32_t>(Endian::Little);
|
||||
int flags = stream.read<uint32_t>(Endian::Little);
|
||||
stream.read<uint32_t>(Endian::Little); // reserved
|
||||
int count = stream.read<u32>(Endian::Little);
|
||||
int flags = stream.read<u32>(Endian::Little);
|
||||
stream.read<u32>(Endian::Little); // reserved
|
||||
|
||||
String name;
|
||||
name.set_length(stream.read<uint16_t>(Endian::Little));
|
||||
name.set_length(stream.read<u16>(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<uint32_t>(Endian::Little);
|
||||
slice.origin.x = stream.read<int32_t>(Endian::Little);
|
||||
slice.origin.y = stream.read<int32_t>(Endian::Little);
|
||||
slice.width = stream.read<uint32_t>(Endian::Little);
|
||||
slice.height = stream.read<uint32_t>(Endian::Little);
|
||||
slice.frame = stream.read<u32>(Endian::Little);
|
||||
slice.origin.x = stream.read<i32>(Endian::Little);
|
||||
slice.origin.y = stream.read<i32>(Endian::Little);
|
||||
slice.width = stream.read<u32>(Endian::Little);
|
||||
slice.height = stream.read<u32>(Endian::Little);
|
||||
|
||||
// 9 slice (ignored atm)
|
||||
if (flags & (1 << 0))
|
||||
{
|
||||
stream.read<int32_t>(Endian::Little);
|
||||
stream.read<int32_t>(Endian::Little);
|
||||
stream.read<uint32_t>(Endian::Little);
|
||||
stream.read<uint32_t>(Endian::Little);
|
||||
stream.read<i32>(Endian::Little);
|
||||
stream.read<i32>(Endian::Little);
|
||||
stream.read<u32>(Endian::Little);
|
||||
stream.read<u32>(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<uint32_t>(Endian::Little);
|
||||
slice.pivot.y = stream.read<uint32_t>(Endian::Little);
|
||||
slice.pivot.x = stream.read<u32>(Endian::Little);
|
||||
slice.pivot.y = stream.read<u32>(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);
|
||||
|
|
|
@ -1,20 +1,31 @@
|
|||
#include <blah/images/font.h>
|
||||
#include <blah/streams/filestream.h>
|
||||
#include <blah/math/calc.h>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
|
||||
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
|
||||
{
|
||||
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,
|
||||
const u16* ptr = (const u16*)stbtt_GetFontNameStr(font, &length,
|
||||
STBTT_PLATFORM_ID_MICROSOFT,
|
||||
STBTT_MS_EID_UNICODE_BMP,
|
||||
STBTT_MS_LANG_ENGLISH,
|
||||
|
@ -28,6 +39,7 @@ String GetName(stbtt_fontinfo* font, int nameId)
|
|||
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;
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
#include <blah/images/image.h>
|
||||
#include <blah/streams/stream.h>
|
||||
#include <blah/streams/filestream.h>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <blah/images/packer.h>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
|
@ -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::Entry>& 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;
|
||||
|
|
469
src/input/binding.cpp
Normal file
469
src/input/binding.cpp
Normal file
|
@ -0,0 +1,469 @@
|
|||
#include <blah/input/binding.h>
|
||||
#include <blah/math/calc.h>
|
||||
#include <blah/core/time.h>
|
||||
|
||||
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();
|
||||
}
|
70
src/input/binding_registry.cpp
Normal file
70
src/input/binding_registry.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include <blah/input/binding_registry.h>
|
||||
|
||||
using namespace Blah;
|
||||
|
||||
Vector<std::weak_ptr<Binding>> BindingRegistry::bindings;
|
||||
Vector<std::weak_ptr<AxisBinding>> BindingRegistry::axes;
|
||||
Vector<std::weak_ptr<StickBinding>> BindingRegistry::sticks;
|
||||
|
||||
BindingRef BindingRegistry::register_binding(const Binding& binding)
|
||||
{
|
||||
auto result = std::make_shared<Binding>(binding);
|
||||
bindings.push_back(std::weak_ptr<Binding>(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
AxisBindingRef BindingRegistry::register_axis(const AxisBinding& binding)
|
||||
{
|
||||
auto result = std::make_shared<AxisBinding>(binding);
|
||||
axes.push_back(std::weak_ptr<AxisBinding>(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
StickBindingRef BindingRegistry::register_stick(const StickBinding& binding)
|
||||
{
|
||||
auto result = std::make_shared<StickBinding>(binding);
|
||||
sticks.push_back(std::weak_ptr<StickBinding>(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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
#include <blah/input/input.h>
|
||||
#include <blah/input/binding_registry.h>
|
||||
#include <blah/core/app.h>
|
||||
#include <blah/core/time.h>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <blah/math/point.h>
|
||||
#include "../internal/input_backend.h"
|
||||
#include <string.h>
|
||||
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
#include <blah/input/virtual_axis.h>
|
||||
#include <blah/core/time.h>
|
||||
#include <blah/core/log.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
#include <blah/input/virtual_button.h>
|
||||
#include <blah/core/time.h>
|
||||
#include <blah/core/log.h>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -1,191 +0,0 @@
|
|||
#include <blah/input/virtual_stick.h>
|
||||
#include <blah/core/time.h>
|
||||
#include <blah/core/log.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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 <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
@ -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<Vector<float>> fragment_uniform_values;
|
||||
StackVector<ShaderData::HLSL_Attribute, 16> attributes;
|
||||
Vector<UniformInfo> 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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -1428,18 +1435,21 @@ 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;
|
||||
}
|
||||
|
@ -1538,4 +1548,4 @@ namespace Blah
|
|||
}
|
||||
}
|
||||
|
||||
#endif // BLAH_USE_D3D11
|
||||
#endif // BLAH_GRAPHICS_D3D11
|
||||
|
|
|
@ -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 <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -232,4 +232,4 @@ namespace Blah
|
|||
}
|
||||
}
|
||||
|
||||
#endif // !(defined(BLAH_USE_OPENGL) || defined(BLAH_USE_D3D11))
|
||||
#endif // !(defined(BLAH_GRAPHICS_OPENGL) || defined(BLAH_GRAPHICS_D3D11))
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifdef BLAH_USE_OPENGL
|
||||
#ifdef BLAH_GRAPHICS_OPENGL
|
||||
|
||||
#include "../internal/graphics_backend.h"
|
||||
#include "../internal/platform_backend.h"
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
@ -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<TextureRef, BLAH_ATTACHMENTS> m_attachments;
|
||||
StackVector<TextureRef, Attachments::MaxCapacity> 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<GLuint> m_vertex_attribs;
|
||||
Vector<GLuint> 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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <blah/core/filesystem.h>
|
||||
#include <blah/containers/vector.h>
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -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 <blah/input/input.h>
|
||||
#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 <SDL.h>
|
||||
|
@ -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,46 +269,56 @@ 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;
|
||||
|
||||
auto index = find_joystick_index(event.jdevice.which);
|
||||
if (index >= 0)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
auto index = find_joystick_index(event.jdevice.which);
|
||||
if (index >= 0)
|
||||
{
|
||||
if (SDL_IsGameController(index) == SDL_FALSE)
|
||||
{
|
||||
float value;
|
||||
|
@ -297,48 +329,60 @@ void PlatformBackend::frame()
|
|||
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);
|
||||
}
|
||||
}
|
||||
else if (event.type == SDL_CONTROLLERDEVICEREMOVED)
|
||||
{
|
||||
Sint32 index = event.cdevice.which;
|
||||
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!
|
||||
|
||||
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!
|
||||
|
||||
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!
|
||||
|
@ -353,11 +397,12 @@ 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
|
||||
|
|
776
src/internal/platform_backend_win32.cpp
Normal file
776
src/internal/platform_backend_win32.cpp
Normal file
|
@ -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 <blah/input/input.h>
|
||||
#include <blah/core/app.h>
|
||||
#include <blah/core/filesystem.h>
|
||||
#include <blah/core/common.h>
|
||||
#include <blah/core/time.h>
|
||||
#include <blah/math/stopwatch.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winuser.h> // for SetProcessDPIAware
|
||||
#include <filesystem> // for File Reading/Writing
|
||||
#include <shellapi.h> // for file explore
|
||||
#include <shlobj.h> // for known folder
|
||||
#include <chrono> // 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<std::chrono::microseconds>(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<FilePath>& 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
|
|
@ -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);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <blah/math/color.h>
|
||||
#include <blah/math/vec3.h>
|
||||
#include <blah/math/vec4.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <blah/math/mat4x4.h>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
|
||||
using namespace Blah;
|
||||
|
||||
|
|
|
@ -14,13 +14,12 @@ void Stopwatch::reset()
|
|||
start_time = std::chrono::duration_cast<std::chrono::microseconds>(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<std::chrono::microseconds>(system_clock::now().time_since_epoch()).count() - start_time;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <blah/streams/filestream.h>
|
||||
#include <blah/core/log.h>
|
||||
#include <blah/core/common.h>
|
||||
#include "../internal/platform_backend.h"
|
||||
#include <string.h>
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user