mirror of
				https://github.com/NoelFB/blah.git
				synced 2025-11-04 01:41:34 +08:00 
			
		
		
		
	Merge branch 'master' into master
This commit is contained in:
		@ -9,28 +9,26 @@ add_library(blah
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	src/core/app.cpp
 | 
						src/core/app.cpp
 | 
				
			||||||
	src/core/filesystem.cpp
 | 
						src/core/filesystem.cpp
 | 
				
			||||||
	src/core/log.cpp
 | 
						src/core/common.cpp
 | 
				
			||||||
	src/core/time.cpp
 | 
						src/core/time.cpp
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						src/graphics/batch.cpp
 | 
				
			||||||
	src/graphics/blend.cpp
 | 
						src/graphics/blend.cpp
 | 
				
			||||||
	src/graphics/framebuffer.cpp
 | 
						src/graphics/framebuffer.cpp
 | 
				
			||||||
	src/graphics/material.cpp
 | 
						src/graphics/material.cpp
 | 
				
			||||||
	src/graphics/mesh.cpp
 | 
						src/graphics/mesh.cpp
 | 
				
			||||||
	src/graphics/renderpass.cpp
 | 
						src/graphics/renderpass.cpp
 | 
				
			||||||
	src/graphics/shader.cpp
 | 
						src/graphics/shader.cpp
 | 
				
			||||||
 | 
						src/graphics/spritefont.cpp
 | 
				
			||||||
 | 
						src/graphics/subtexture.cpp
 | 
				
			||||||
	src/graphics/texture.cpp
 | 
						src/graphics/texture.cpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	src/input/input.cpp
 | 
						src/input/input.cpp
 | 
				
			||||||
	src/input/virtual_stick.cpp
 | 
						src/input/binding.cpp
 | 
				
			||||||
	src/input/virtual_button.cpp
 | 
						src/input/binding_registry.cpp
 | 
				
			||||||
	src/input/virtual_axis.cpp
 | 
					 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	src/containers/str.cpp
 | 
						src/containers/str.cpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	src/drawing/batch.cpp
 | 
					 | 
				
			||||||
	src/drawing/spritefont.cpp
 | 
					 | 
				
			||||||
	src/drawing/subtexture.cpp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	src/images/aseprite.cpp
 | 
						src/images/aseprite.cpp
 | 
				
			||||||
	src/images/font.cpp
 | 
						src/images/font.cpp
 | 
				
			||||||
	src/images/image.cpp
 | 
						src/images/image.cpp
 | 
				
			||||||
@ -54,11 +52,11 @@ add_library(blah
 | 
				
			|||||||
	src/streams/memorystream.cpp
 | 
						src/streams/memorystream.cpp
 | 
				
			||||||
	src/streams/stream.cpp
 | 
						src/streams/stream.cpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
	src/internal/graphics_backend_gl.cpp
 | 
						src/internal/graphics_backend_gl.cpp
 | 
				
			||||||
	src/internal/graphics_backend_d3d11.cpp
 | 
						src/internal/graphics_backend_d3d11.cpp
 | 
				
			||||||
	src/internal/graphics_backend_dummy.cpp
 | 
						src/internal/graphics_backend_dummy.cpp
 | 
				
			||||||
	src/internal/platform_backend_sdl2.cpp
 | 
						src/internal/platform_backend_sdl2.cpp
 | 
				
			||||||
 | 
						src/internal/platform_backend_win32.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_include_directories(blah
 | 
					target_include_directories(blah
 | 
				
			||||||
@ -69,34 +67,49 @@ target_include_directories(blah
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Platform Variables
 | 
					# Platform Variables
 | 
				
			||||||
set(SDL2_ENABLED true CACHE BOOL "Use SDL2 as the System implementation")
 | 
					set(PLATFORM_SDL2 true CACHE BOOL "Use SDL2 Platform Backend")
 | 
				
			||||||
set(OPENGL_ENABLED true CACHE BOOL "Use OpenGL graphics implementation")
 | 
					set(PLATFORM_WIN32 false CACHE BOOL "Use Win32 Platform Backend")
 | 
				
			||||||
set(D3D11_ENABLED false CACHE BOOL "Use D3D11 graphics implementation")
 | 
					set(GRAPHICS_OPENGL true CACHE BOOL "Use OpenGL Graphics Backend")
 | 
				
			||||||
 | 
					set(GRAPHICS_D3D11 false CACHE BOOL "Use D3D11 Graphics Backend")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(LIBS "")
 | 
					set(LIBS "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# add OpenGL definition if we're using it
 | 
					# use the OpenGL Graphics Backend
 | 
				
			||||||
if (OPENGL_ENABLED)
 | 
					if (GRAPHICS_OPENGL)
 | 
				
			||||||
	add_compile_definitions(BLAH_USE_OPENGL)
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# add D3D11 definition if we're using it
 | 
						add_compile_definitions(BLAH_GRAPHICS_OPENGL)
 | 
				
			||||||
if (D3D11_ENABLED)
 | 
					
 | 
				
			||||||
	add_compile_definitions(BLAH_USE_D3D11)
 | 
					# use the D3D11 Graphics Backend
 | 
				
			||||||
 | 
					elseif (GRAPHICS_D3D11)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						add_compile_definitions(BLAH_GRAPHICS_D3D11)
 | 
				
			||||||
	set(LIBS ${LIBS} d3d11.lib dxguid.lib D3Dcompiler.lib)
 | 
						set(LIBS ${LIBS} d3d11.lib dxguid.lib D3Dcompiler.lib)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Link and create SDL2 Definition if we're using it
 | 
					# use the SDL2 Platform Backend
 | 
				
			||||||
if (SDL2_ENABLED)
 | 
					# Link and create SDL2 Definition
 | 
				
			||||||
	add_compile_definitions(BLAH_USE_SDL2)
 | 
					if (PLATFORM_SDL2)
 | 
				
			||||||
 | 
						add_compile_definitions(BLAH_PLATFORM_SDL2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Emscripten can import SDL2 directly
 | 
				
			||||||
	if (EMSCRIPTEN)
 | 
						if (EMSCRIPTEN)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  		set_target_properties(blah PROPERTIES COMPILE_FLAGS "-s USE_SDL=2")
 | 
					  		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()
 | 
							else()
 | 
				
			||||||
		# Attempt to find SDL2
 | 
					 | 
				
			||||||
			find_package(SDL2 QUIET)
 | 
								find_package(SDL2 QUIET)
 | 
				
			||||||
 | 
							endif()
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		# If CMake cannot find SDL2 library, then it gets downloaded and compiled that way
 | 
							# If CMake cannot find SDL2 library, then it gets downloaded and compiled that way
 | 
				
			||||||
		if (NOT ${SDL2_FOUND})
 | 
							if (NOT ${SDL2_FOUND})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			include(FetchContent)
 | 
								include(FetchContent)
 | 
				
			||||||
			FetchContent_Declare(
 | 
								FetchContent_Declare(
 | 
				
			||||||
				SDL2
 | 
									SDL2
 | 
				
			||||||
@ -108,11 +121,20 @@ if (SDL2_ENABLED)
 | 
				
			|||||||
				FetchContent_Populate(SDL2)
 | 
									FetchContent_Populate(SDL2)
 | 
				
			||||||
				add_subdirectory(${sdl2_SOURCE_DIR} ${sdl2_BINARY_DIR})
 | 
									add_subdirectory(${sdl2_SOURCE_DIR} ${sdl2_BINARY_DIR})
 | 
				
			||||||
			endif()
 | 
								endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		endif()
 | 
							endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		# Either way we are linking to SDL2
 | 
							# Add Library and Include Dirs
 | 
				
			||||||
		set(LIBS ${LIBS} SDL2)
 | 
							set(LIBS ${LIBS} ${SDL2_LIBRARIES})
 | 
				
			||||||
 | 
							target_include_directories(blah PUBLIC ${SDL2_INCLUDE_DIRS})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    endif()
 | 
					    endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# use the Win32 Platform Backend
 | 
				
			||||||
 | 
					elseif (PLATFORM_WIN32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						add_compile_definitions(BLAH_PLATFORM_WIN32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_link_libraries(blah PUBLIC ${LIBS})
 | 
					target_link_libraries(blah PUBLIC ${LIBS})
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										19
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								README.md
									
									
									
									
									
								
							@ -1,17 +1,18 @@
 | 
				
			|||||||
## blah
 | 
					## blah
 | 
				
			||||||
A small C++ game framework for 2D games.
 | 
					A small 2D C++ Game Framework, using few dependencies and simple code to mainain easy building and portability.
 | 
				
			||||||
Goal is to be simple and use as few dependencies as possible, to maintain easy building and portability.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
**☆ This will likely see breaking changes! Use at your own risk! ☆**
 | 
					**☆ This will likely see breaking changes! Use at your own risk! ☆**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### building
 | 
					#### building
 | 
				
			||||||
 - Requires C++17 and CMake 3.12+
 | 
					 - Requires C++17 and CMake 3.12+
 | 
				
			||||||
 - Platform Backend
 | 
					 - 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 `SDL2_ENABLED`, and setting `SDL2_INCLUDE_DIRS` and `SDL2_LIBRARIES`
 | 
						- [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`
 | 
				
			||||||
 - Graphics Backend
 | 
						- [WIN32](https://github.com/NoelFB/blah/blob/master/src/internal/platform_backend_win32.cpp) (UNFINISHED) can be enabled in CMake with `PLATFORM_WIN32`.
 | 
				
			||||||
	- [OpenGL](https://github.com/NoelFB/blah/blob/master/src/internal/graphics_backend_gl.cpp) can be enabled in CMake with `OPENGL_ENABLED`.
 | 
						- Additional backends can be added by implementing the [Platform Backend](https://github.com/NoelFB/blah/blob/master/src/internal/platform_backend.h)
 | 
				
			||||||
	- [D3D11](https://github.com/NoelFB/blah/blob/master/src/internal/graphics_backend_d3d11.cpp) (unfinished) can be enabled in CMake with `D3D11_ENABLED`.
 | 
					 - A single *Graphics* backend must be 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).
 | 
						- [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
 | 
					#### 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.
 | 
					 - 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);
 | 
						App::backbuffer->clear(Color::black);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	auto center = Vec2(App::backbuffer->width(), App::backbuffer->height()) / 2;
 | 
						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);
 | 
						auto transform = Mat3x2::create_transform(center, Vec2::zero, Vec2::one, rotation);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	batch.push_matrix(transform);
 | 
						batch.push_matrix(transform);
 | 
				
			||||||
 | 
				
			|||||||
@ -2,16 +2,16 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "blah/core/app.h"
 | 
					#include "blah/core/app.h"
 | 
				
			||||||
#include "blah/core/filesystem.h"
 | 
					#include "blah/core/filesystem.h"
 | 
				
			||||||
#include "blah/core/log.h"
 | 
					#include "blah/core/common.h"
 | 
				
			||||||
#include "blah/core/time.h"
 | 
					#include "blah/core/time.h"
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
#include "blah/containers/vector.h"
 | 
					#include "blah/containers/vector.h"
 | 
				
			||||||
#include "blah/containers/stackvector.h"
 | 
					#include "blah/containers/stackvector.h"
 | 
				
			||||||
#include "blah/containers/str.h"
 | 
					#include "blah/containers/str.h"
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
#include "blah/drawing/batch.h"
 | 
					#include "blah/graphics/batch.h"
 | 
				
			||||||
#include "blah/drawing/spritefont.h"
 | 
					#include "blah/graphics/spritefont.h"
 | 
				
			||||||
#include "blah/drawing/subtexture.h"
 | 
					#include "blah/graphics/subtexture.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "blah/graphics/blend.h"
 | 
					#include "blah/graphics/blend.h"
 | 
				
			||||||
#include "blah/graphics/framebuffer.h"
 | 
					#include "blah/graphics/framebuffer.h"
 | 
				
			||||||
@ -28,9 +28,8 @@
 | 
				
			|||||||
#include "blah/images/packer.h"
 | 
					#include "blah/images/packer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "blah/input/input.h"
 | 
					#include "blah/input/input.h"
 | 
				
			||||||
#include "blah/input/virtual_stick.h"
 | 
					#include "blah/input/binding.h"
 | 
				
			||||||
#include "blah/input/virtual_button.h"
 | 
					#include "blah/input/binding_registry.h"
 | 
				
			||||||
#include "blah/input/virtual_axis.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "blah/math/calc.h"
 | 
					#include "blah/math/calc.h"
 | 
				
			||||||
#include "blah/math/circle.h"
 | 
					#include "blah/math/circle.h"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <new>
 | 
					#include <new>
 | 
				
			||||||
#include <initializer_list>
 | 
					#include <initializer_list>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <stdarg.h>
 | 
					#include <stdarg.h>
 | 
				
			||||||
#include <cstdio>
 | 
					#include <cstdio>
 | 
				
			||||||
#include <blah/containers/vector.h>
 | 
					#include <blah/containers/vector.h>
 | 
				
			||||||
@ -10,6 +10,7 @@ namespace Blah
 | 
				
			|||||||
	class StrOf;
 | 
						class StrOf;
 | 
				
			||||||
	using String = StrOf<64>;
 | 
						using String = StrOf<64>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// A simple String implementation
 | 
				
			||||||
	class Str
 | 
						class Str
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
@ -78,7 +79,7 @@ namespace Blah
 | 
				
			|||||||
		
 | 
							
 | 
				
			||||||
		// Returns the unicode value at the given index.
 | 
							// Returns the unicode value at the given index.
 | 
				
			||||||
		// Assumes the index is a valid utf8 starting point.
 | 
							// 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.
 | 
							// Returns the byte-length of the utf8 character.
 | 
				
			||||||
		// Assumes the index is a valid utf8 starting point.
 | 
							// Assumes the index is a valid utf8 starting point.
 | 
				
			||||||
@ -88,7 +89,7 @@ namespace Blah
 | 
				
			|||||||
		Str& append(char c);
 | 
							Str& append(char c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// appends the given unicode character
 | 
							// appends the given unicode character
 | 
				
			||||||
		Str& append(uint32_t c);
 | 
							Str& append(u32 c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// appends the given c string
 | 
							// appends the given c string
 | 
				
			||||||
		Str& append(const char* start, const char* end = nullptr);
 | 
							Str& append(const char* start, const char* end = nullptr);
 | 
				
			||||||
@ -100,7 +101,7 @@ namespace Blah
 | 
				
			|||||||
		Str& append_fmt(const char* fmt, ...);
 | 
							Str& append_fmt(const char* fmt, ...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// appends a utf16 string
 | 
							// 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
 | 
							// trims whitespace
 | 
				
			||||||
		Str& trim();
 | 
							Str& trim();
 | 
				
			||||||
@ -138,8 +139,10 @@ namespace Blah
 | 
				
			|||||||
		// returns a substring of the string
 | 
							// returns a substring of the string
 | 
				
			||||||
		String substr(int start, int end) const;
 | 
							String substr(int start, int end) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Splits the string into a vector of strings
 | 
				
			||||||
		Vector<String> split(char ch) const;
 | 
							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);
 | 
							Str& replace(const Str& old_str, const Str& new_str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// replaces all occurances of the given character in the string
 | 
							// 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
 | 
							// returns a pointer to the heap buffer or to our stack allocation
 | 
				
			||||||
		char* data()			 { return (m_buffer != nullptr ? m_buffer : ((char*)(this) + sizeof(Str))); }
 | 
							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))); }
 | 
							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); }
 | 
							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);
 | 
							void set(const char* start, const char* end = nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
@ -187,6 +195,7 @@ namespace Blah
 | 
				
			|||||||
	// combine string
 | 
						// combine string
 | 
				
			||||||
	inline Str operator+(const Str& lhs, const Str& rhs) { Str str; str.append(lhs).append(rhs); return str; }
 | 
						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>
 | 
						template<int T>
 | 
				
			||||||
	class StrOf : public Str
 | 
						class StrOf : public Str
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,12 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <type_traits>
 | 
					#include <type_traits>
 | 
				
			||||||
 | 
					#include <initializer_list>
 | 
				
			||||||
#include <new>
 | 
					#include <new>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						// A lightweight Vector implementation
 | 
				
			||||||
	template<class T>
 | 
						template<class T>
 | 
				
			||||||
	class Vector
 | 
						class Vector
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -19,6 +21,7 @@ namespace Blah
 | 
				
			|||||||
		Vector(int capacity);
 | 
							Vector(int capacity);
 | 
				
			||||||
		Vector(const Vector& src);
 | 
							Vector(const Vector& src);
 | 
				
			||||||
		Vector(Vector&& src) noexcept;
 | 
							Vector(Vector&& src) noexcept;
 | 
				
			||||||
 | 
							Vector(std::initializer_list<T> list);
 | 
				
			||||||
		~Vector();
 | 
							~Vector();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Vector& operator=(const Vector& src);
 | 
							Vector& operator=(const Vector& src);
 | 
				
			||||||
@ -95,6 +98,17 @@ namespace Blah
 | 
				
			|||||||
		src.m_count = 0;
 | 
							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>
 | 
						template<class T>
 | 
				
			||||||
	inline Vector<T>::~Vector()
 | 
						inline Vector<T>::~Vector()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
				
			|||||||
@ -1,31 +1,72 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						// Application Event Functions
 | 
				
			||||||
	using AppEventFn = std::function<void()>;
 | 
						using AppEventFn = std::function<void()>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Application Logging Functions
 | 
				
			||||||
	using AppLogFn = std::function<void(const char* message, Log::Category category)>;
 | 
						using AppLogFn = std::function<void(const char* message, Log::Category category)>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Application Configuration
 | 
				
			||||||
	struct Config
 | 
						struct Config
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							// Application name.
 | 
				
			||||||
 | 
							// This has no default and must be set.
 | 
				
			||||||
		const char* name;
 | 
							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;
 | 
							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;
 | 
							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;
 | 
							int max_updates;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// target framerate.
 | 
				
			||||||
 | 
							// defaults to 60.
 | 
				
			||||||
		int target_framerate;
 | 
							int target_framerate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Callback on application startup
 | 
				
			||||||
 | 
							// Defaults to nothing.
 | 
				
			||||||
		AppEventFn on_startup;
 | 
							AppEventFn on_startup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Callback on application shutdown
 | 
				
			||||||
 | 
							// Defaults to nothing.
 | 
				
			||||||
		AppEventFn on_shutdown;
 | 
							AppEventFn on_shutdown;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Callback on application update
 | 
				
			||||||
 | 
							// Defaults to nothing.
 | 
				
			||||||
		AppEventFn on_update;
 | 
							AppEventFn on_update;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Callback on application render
 | 
				
			||||||
 | 
							// Defaults to nothing.
 | 
				
			||||||
		AppEventFn on_render;
 | 
							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;
 | 
							AppEventFn on_exit_request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Callback when the application logs info/warning/errors
 | 
				
			||||||
 | 
							// Defaults to printf.
 | 
				
			||||||
		AppLogFn on_log;
 | 
							AppLogFn on_log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Default config setup
 | 
				
			||||||
		Config();
 | 
							Config();
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Renderer the Application is using
 | 
				
			||||||
	enum class Renderer
 | 
						enum class Renderer
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		None = -1,
 | 
							None = -1,
 | 
				
			||||||
@ -35,16 +76,24 @@ namespace Blah
 | 
				
			|||||||
		Count
 | 
							Count
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Features available on the current Renderer
 | 
				
			||||||
	struct RendererFeatures
 | 
						struct RendererFeatures
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							// Whether Mesh Instancing is available
 | 
				
			||||||
		bool instancing = false;
 | 
							bool instancing = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Whether the Texture origin is the bottom left.
 | 
				
			||||||
 | 
							// This is true for OpenGL.
 | 
				
			||||||
		bool origin_bottom_left = false;
 | 
							bool origin_bottom_left = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Maximum Texture Size available
 | 
				
			||||||
		int max_texture_size = 0;
 | 
							int max_texture_size = 0;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class FrameBuffer;
 | 
						class FrameBuffer;
 | 
				
			||||||
	using FrameBufferRef = std::shared_ptr<FrameBuffer>;
 | 
						using FrameBufferRef = std::shared_ptr<FrameBuffer>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Application
 | 
				
			||||||
	namespace App
 | 
						namespace App
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// Runs the application
 | 
							// Runs the application
 | 
				
			||||||
@ -53,7 +102,9 @@ namespace Blah
 | 
				
			|||||||
		// Returns whether the application is running
 | 
							// Returns whether the application is running
 | 
				
			||||||
		bool 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();
 | 
							void exit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Gets the config data used to run the application
 | 
							// Gets the config data used to run the application
 | 
				
			||||||
@ -71,16 +122,20 @@ namespace Blah
 | 
				
			|||||||
		// Gets the height of the window
 | 
							// Gets the height of the window
 | 
				
			||||||
		int height();
 | 
							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();
 | 
							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();
 | 
							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();
 | 
							float content_scale();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Toggles fullscreen
 | 
							// Toggles fullscreen if supported on the platform.
 | 
				
			||||||
 | 
							// Otherwise this function does nothing.
 | 
				
			||||||
		void fullscreen(bool enabled);
 | 
							void fullscreen(bool enabled);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Returns the Rendering API in use
 | 
							// Returns the Rendering API in use
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// error / abort
 | 
					// error / abort
 | 
				
			||||||
#if defined(DEBUG) || defined(_DEBUG)
 | 
					#if defined(DEBUG) || defined(_DEBUG)
 | 
				
			||||||
@ -33,6 +34,16 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					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
 | 
						namespace Log
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		enum class Category
 | 
							enum class Category
 | 
				
			||||||
@ -42,8 +53,8 @@ namespace Blah
 | 
				
			|||||||
			Error
 | 
								Error
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void print(const char* info, ...);
 | 
							void info(const char* message, ...);
 | 
				
			||||||
		void warn(const char* info, ...);
 | 
							void warn(const char* message, ...);
 | 
				
			||||||
		void error(const char* info, ...);
 | 
							void error(const char* message, ...);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -5,40 +5,71 @@
 | 
				
			|||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	using FilePath = StrOf<265>;
 | 
						using FilePath = StrOf<265>;
 | 
				
			||||||
 | 
						class FileStream;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	enum class FileMode
 | 
						enum class FileMode
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		None       = 0,
 | 
							None       = 0,
 | 
				
			||||||
		Read		= 1 << 1,
 | 
							Read       = 1 << 0,
 | 
				
			||||||
		Write		= 1 << 2,
 | 
							Write      = 1 << 1,
 | 
				
			||||||
		ReadWrite  = Read | Write,
 | 
							ReadWrite  = Read | Write,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	namespace Directory
 | 
						namespace Directory
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							// Creates a new directory at the given location.
 | 
				
			||||||
 | 
							// Returns false if unable to create the directory.
 | 
				
			||||||
		bool create(const FilePath& path);
 | 
							bool create(const FilePath& path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Returns whether the given directory exists
 | 
				
			||||||
		bool exists(const FilePath& path);
 | 
							bool exists(const FilePath& path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Tries to delete a path and returns whether it was successful
 | 
				
			||||||
		bool remove(const FilePath& path);
 | 
							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);
 | 
							void explore(const FilePath& path);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	namespace File
 | 
						namespace File
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							// Checks if the given file exists
 | 
				
			||||||
		bool exists(const FilePath& path);
 | 
							bool exists(const FilePath& path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Tries to delete a file and returns whether it was successful
 | 
				
			||||||
		bool remove(const FilePath& path);
 | 
							bool remove(const FilePath& path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Opens the given file and returns a stream
 | 
				
			||||||
 | 
							FileStream open(const FilePath& path, FileMode mode = FileMode::ReadWrite);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	namespace Path
 | 
						namespace Path
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							// Returns the file name of the path
 | 
				
			||||||
		FilePath get_file_name(const FilePath& 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);
 | 
							FilePath get_file_name_no_ext(const FilePath& path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Returns the path without any file extensions
 | 
				
			||||||
		FilePath get_path_no_ext(const FilePath& path);
 | 
							FilePath get_path_no_ext(const FilePath& path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Returns relative path
 | 
				
			||||||
		FilePath get_path_after(const FilePath& path, const FilePath& after);
 | 
							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);
 | 
							FilePath get_directory_name(const FilePath& path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Normalizes a path (removes ../, changes \\ to /, removes redundant slashes, etc)
 | 
				
			||||||
		FilePath normalize(const FilePath& path);
 | 
							FilePath normalize(const FilePath& path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Joins two paths together
 | 
				
			||||||
		FilePath join(const FilePath& a, const FilePath& b);
 | 
							FilePath join(const FilePath& a, const FilePath& b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Joins two paths together
 | 
				
			||||||
		template<typename ... Args>
 | 
							template<typename ... Args>
 | 
				
			||||||
		FilePath join(const FilePath& a, const FilePath& b, const Args&... args)
 | 
							FilePath join(const FilePath& a, const FilePath& b, const Args&... args)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
 | 
				
			|||||||
@ -1,21 +1,21 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct Time
 | 
						struct Time
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// ticks per second (microseconds, in this case)
 | 
							// 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
 | 
							// uptime, in ticks
 | 
				
			||||||
		static uint64_t ticks;
 | 
							static u64 ticks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// uptime, in seconds
 | 
							// uptime, in seconds
 | 
				
			||||||
		static double seconds;
 | 
							static double seconds;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// previous frame uptime, in ticks
 | 
							// previous frame uptime, in ticks
 | 
				
			||||||
		static uint64_t previous_ticks;
 | 
							static u64 previous_ticks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// previous frame uptime, in seconds
 | 
							// previous frame uptime, in seconds
 | 
				
			||||||
		static double previous_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/mat3x2.h>
 | 
				
			||||||
#include <blah/math/mat4x4.h>
 | 
					#include <blah/math/mat4x4.h>
 | 
				
			||||||
#include <blah/math/color.h>
 | 
					#include <blah/math/color.h>
 | 
				
			||||||
#include <blah/drawing/subtexture.h>
 | 
					#include <blah/graphics/subtexture.h>
 | 
				
			||||||
#include <blah/drawing/spritefont.h>
 | 
					#include <blah/graphics/spritefont.h>
 | 
				
			||||||
#include <blah/containers/vector.h>
 | 
					#include <blah/containers/vector.h>
 | 
				
			||||||
#include <blah/graphics/blend.h>
 | 
					#include <blah/graphics/blend.h>
 | 
				
			||||||
#include <blah/graphics/sampler.h>
 | 
					#include <blah/graphics/sampler.h>
 | 
				
			||||||
@ -15,9 +15,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						// Spritebatcher Color Mode
 | 
				
			||||||
	enum class ColorMode
 | 
						enum class ColorMode
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							// Draws textures and shapes normally
 | 
				
			||||||
		Normal,
 | 
							Normal,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Ignores the texture color but still uses transparency, essentially
 | 
				
			||||||
 | 
							// drawing the "shape" of the texture a solid color
 | 
				
			||||||
		Wash
 | 
							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)); }
 | 
				
			||||||
	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
 | 
						class Batch
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
@ -187,10 +192,10 @@ namespace Blah
 | 
				
			|||||||
			Vec2 tex;
 | 
								Vec2 tex;
 | 
				
			||||||
			Color col;
 | 
								Color col;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			uint8_t mult;
 | 
								u8 mult;
 | 
				
			||||||
			uint8_t wash;
 | 
								u8 wash;
 | 
				
			||||||
			uint8_t fill;
 | 
								u8 fill;
 | 
				
			||||||
			uint8_t pad;
 | 
								u8 pad;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct DrawBatch
 | 
							struct DrawBatch
 | 
				
			||||||
@ -219,11 +224,11 @@ namespace Blah
 | 
				
			|||||||
		MeshRef m_mesh;
 | 
							MeshRef m_mesh;
 | 
				
			||||||
		Mat3x2 m_matrix;
 | 
							Mat3x2 m_matrix;
 | 
				
			||||||
		ColorMode m_color_mode;
 | 
							ColorMode m_color_mode;
 | 
				
			||||||
		uint8_t					m_tex_mult;
 | 
							u8 m_tex_mult;
 | 
				
			||||||
		uint8_t					m_tex_wash;
 | 
							u8 m_tex_wash;
 | 
				
			||||||
		DrawBatch m_batch;
 | 
							DrawBatch m_batch;
 | 
				
			||||||
		Vector<Vertex> m_vertices;
 | 
							Vector<Vertex> m_vertices;
 | 
				
			||||||
		Vector<uint32_t>		m_indices;
 | 
							Vector<u32> m_indices;
 | 
				
			||||||
		Vector<Mat3x2> m_matrix_stack;
 | 
							Vector<Mat3x2> m_matrix_stack;
 | 
				
			||||||
		Vector<Rect> m_scissor_stack;
 | 
							Vector<Rect> m_scissor_stack;
 | 
				
			||||||
		Vector<BlendMode> m_blend_stack;
 | 
							Vector<BlendMode> m_blend_stack;
 | 
				
			||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -46,6 +46,7 @@ namespace Blah
 | 
				
			|||||||
		RGBA = Red | Green | Blue | Alpha,
 | 
							RGBA = Red | Green | Blue | Alpha,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// BlendMode using for rendering
 | 
				
			||||||
	struct BlendMode
 | 
						struct BlendMode
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// Normal, pre-multiplied, Blend Mode
 | 
							// Normal, pre-multiplied, Blend Mode
 | 
				
			||||||
@ -61,7 +62,7 @@ namespace Blah
 | 
				
			|||||||
		BlendFactor alpha_src;
 | 
							BlendFactor alpha_src;
 | 
				
			||||||
		BlendFactor alpha_dst;
 | 
							BlendFactor alpha_dst;
 | 
				
			||||||
		BlendMask mask;
 | 
							BlendMask mask;
 | 
				
			||||||
		uint32_t rgba;
 | 
							u32 rgba;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		BlendMode() = default;
 | 
							BlendMode() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -78,7 +79,7 @@ namespace Blah
 | 
				
			|||||||
		BlendMode(
 | 
							BlendMode(
 | 
				
			||||||
			BlendOp color_op, BlendFactor color_src, BlendFactor color_dst,
 | 
								BlendOp color_op, BlendFactor color_src, BlendFactor color_dst,
 | 
				
			||||||
			BlendOp alpha_op, BlendFactor alpha_src, BlendFactor alpha_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_op(color_op),
 | 
				
			||||||
			color_src(color_src),
 | 
								color_src(color_src),
 | 
				
			||||||
			color_dst(color_dst),
 | 
								color_dst(color_dst),
 | 
				
			||||||
 | 
				
			|||||||
@ -4,16 +4,8 @@
 | 
				
			|||||||
#include <blah/math/color.h>
 | 
					#include <blah/math/color.h>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 4 color attachments + 1 depth/stencil
 | 
					 | 
				
			||||||
#define BLAH_ATTACHMENTS 5
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	typedef StackVector<TextureRef, BLAH_ATTACHMENTS> Attachments;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	class FrameBuffer;
 | 
					 | 
				
			||||||
	typedef std::shared_ptr<FrameBuffer> FrameBufferRef;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	enum class ClearMask
 | 
						enum class ClearMask
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		None = 0,
 | 
							None = 0,
 | 
				
			||||||
@ -23,6 +15,14 @@ namespace Blah
 | 
				
			|||||||
		All = (int)Color | (int)Depth | (int)Stencil
 | 
							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
 | 
						class FrameBuffer
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	protected:
 | 
						protected:
 | 
				
			||||||
@ -65,7 +65,7 @@ namespace Blah
 | 
				
			|||||||
		virtual int height() const = 0;
 | 
							virtual int height() const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Clears the FrameBuffer
 | 
							// 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;
 | 
						class Material;
 | 
				
			||||||
	typedef std::shared_ptr<Material> MaterialRef;
 | 
						typedef std::shared_ptr<Material> MaterialRef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Materials hold values that can be assigned to a shader during rendering
 | 
				
			||||||
	class Material final
 | 
						class Material final
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
@ -59,10 +60,10 @@ namespace Blah
 | 
				
			|||||||
		// Sets the value. `length` is the total number of floats to set
 | 
							// 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
 | 
							// For example if the uniform is a float2[4], a total of 8 float values
 | 
				
			||||||
		// can be set.
 | 
							// 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.
 | 
							// 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
 | 
							// Returns the internal Texture buffer
 | 
				
			||||||
		const Vector<TextureRef>& textures() const;
 | 
							const Vector<TextureRef>& textures() const;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,11 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <blah/containers/stackvector.h>
 | 
					#include <blah/containers/stackvector.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						// Supported Vertex value types
 | 
				
			||||||
	enum class VertexType
 | 
						enum class VertexType
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		None,
 | 
							None,
 | 
				
			||||||
@ -20,6 +21,7 @@ namespace Blah
 | 
				
			|||||||
		UShort4
 | 
							UShort4
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Vertex Attribute information
 | 
				
			||||||
	struct VertexAttribute
 | 
						struct VertexAttribute
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// Location / Attribute Index
 | 
							// Location / Attribute Index
 | 
				
			||||||
@ -32,6 +34,8 @@ namespace Blah
 | 
				
			|||||||
		bool normalized = false;
 | 
							bool normalized = false;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Vertex Format information.
 | 
				
			||||||
 | 
						// Holds a list of attributes and total stride per-vertex.
 | 
				
			||||||
	struct VertexFormat
 | 
						struct VertexFormat
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// List of Attributes
 | 
							// List of Attributes
 | 
				
			||||||
@ -44,15 +48,20 @@ namespace Blah
 | 
				
			|||||||
		VertexFormat(std::initializer_list<VertexAttribute> attributes, int stride = 0);
 | 
							VertexFormat(std::initializer_list<VertexAttribute> attributes, int stride = 0);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Supported Vertex Index formats
 | 
				
			||||||
	enum class IndexFormat
 | 
						enum class IndexFormat
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							// Indices are 16 bit unsigned integers
 | 
				
			||||||
		UInt16,
 | 
							UInt16,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Indices are 32 bit unsigned integers
 | 
				
			||||||
		UInt32
 | 
							UInt32
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class Mesh;
 | 
						class Mesh;
 | 
				
			||||||
	typedef std::shared_ptr<Mesh> MeshRef;
 | 
						typedef std::shared_ptr<Mesh> MeshRef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// A Mesh is a set of Indices and Vertices which are used for drawing
 | 
				
			||||||
	class Mesh
 | 
						class Mesh
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	protected:
 | 
						protected:
 | 
				
			||||||
@ -73,21 +82,21 @@ namespace Blah
 | 
				
			|||||||
		static MeshRef create();
 | 
							static MeshRef create();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Uploads the given index buffer to the Mesh
 | 
							// 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
 | 
							// 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
 | 
							// 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
 | 
							// 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
 | 
							// 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
 | 
							// 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
 | 
					#pragma once
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <blah/math/rect.h>
 | 
					#include <blah/math/rect.h>
 | 
				
			||||||
#include <blah/containers/str.h>
 | 
					#include <blah/containers/str.h>
 | 
				
			||||||
#include <blah/graphics/texture.h>
 | 
					#include <blah/graphics/texture.h>
 | 
				
			||||||
@ -11,6 +11,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						// Depth comparison function to use during a draw call
 | 
				
			||||||
	enum class Compare
 | 
						enum class Compare
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		None,
 | 
							None,
 | 
				
			||||||
@ -24,13 +25,20 @@ namespace Blah
 | 
				
			|||||||
		GreatorOrEqual
 | 
							GreatorOrEqual
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Cull mode during a draw call
 | 
				
			||||||
	enum class Cull
 | 
						enum class Cull
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							// No Culling enabled
 | 
				
			||||||
		None = 0,
 | 
							None = 0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Cull front faces
 | 
				
			||||||
		Front = 1,
 | 
							Front = 1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Cull back faces
 | 
				
			||||||
		Back = 2,
 | 
							Back = 2,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// A single draw call
 | 
				
			||||||
	struct RenderPass
 | 
						struct RenderPass
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// Framebuffer to draw to
 | 
							// Framebuffer to draw to
 | 
				
			||||||
@ -55,13 +63,13 @@ namespace Blah
 | 
				
			|||||||
		Rect scissor;
 | 
							Rect scissor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// First index in the Mesh to draw from
 | 
							// First index in the Mesh to draw from
 | 
				
			||||||
		int64_t index_start;
 | 
							i64 index_start;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Total amount of indices to draw from the Mesh
 | 
							// 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
 | 
							// Total amount of instances to draw from the Mesh
 | 
				
			||||||
		int64_t instance_count;
 | 
							i64 instance_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Depth Compare Function
 | 
							// Depth Compare Function
 | 
				
			||||||
		Compare depth;
 | 
							Compare depth;
 | 
				
			||||||
 | 
				
			|||||||
@ -2,24 +2,42 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						// Texture filter
 | 
				
			||||||
	enum class TextureFilter
 | 
						enum class TextureFilter
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							// None will fallback to whatever default the driver sets
 | 
				
			||||||
		None,
 | 
							None,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Linear interpolation
 | 
				
			||||||
		Linear,
 | 
							Linear,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Nearest Neighbour interpolation
 | 
				
			||||||
		Nearest
 | 
							Nearest
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Texture Wrap Mode
 | 
				
			||||||
	enum class TextureWrap
 | 
						enum class TextureWrap
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							// None will fallback to whatever default the driver sets
 | 
				
			||||||
		None,
 | 
							None,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Clamps the texture to the edges
 | 
				
			||||||
		Clamp,
 | 
							Clamp,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Repeats the texture
 | 
				
			||||||
		Repeat
 | 
							Repeat
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Texture Sampler State, applied during rendering
 | 
				
			||||||
	struct TextureSampler
 | 
						struct TextureSampler
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							// Filter Mode
 | 
				
			||||||
		TextureFilter filter;
 | 
							TextureFilter filter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Wrap X Mode
 | 
				
			||||||
		TextureWrap wrap_x;
 | 
							TextureWrap wrap_x;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Wrap Y Mode
 | 
				
			||||||
		TextureWrap wrap_y;
 | 
							TextureWrap wrap_y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		TextureSampler() :
 | 
							TextureSampler() :
 | 
				
			||||||
 | 
				
			|||||||
@ -72,6 +72,7 @@ namespace Blah
 | 
				
			|||||||
	class Shader;
 | 
						class Shader;
 | 
				
			||||||
	typedef std::shared_ptr<Shader> ShaderRef;
 | 
						typedef std::shared_ptr<Shader> ShaderRef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// A shader used during Rendering
 | 
				
			||||||
	class Shader
 | 
						class Shader
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	protected:
 | 
						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
 | 
						enum class TextureFormat
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							// Invalid Format
 | 
				
			||||||
		None,
 | 
							None,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Single 8-bit channe;
 | 
				
			||||||
		R,
 | 
							R,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 2 8-bit channels
 | 
				
			||||||
		RG,
 | 
							RG,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 4 8-bit channels
 | 
				
			||||||
		RGBA,
 | 
							RGBA,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Depth 24, Stencil 8
 | 
				
			||||||
		DepthStencil,
 | 
							DepthStencil,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Total Formats
 | 
				
			||||||
		Count
 | 
							Count
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -18,6 +29,7 @@ namespace Blah
 | 
				
			|||||||
	class Texture;
 | 
						class Texture;
 | 
				
			||||||
	typedef std::shared_ptr<Texture> TextureRef;
 | 
						typedef std::shared_ptr<Texture> TextureRef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// A 2D Texture held by the GPU to be used during rendering
 | 
				
			||||||
	class Texture
 | 
						class Texture
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	protected:
 | 
						protected:
 | 
				
			||||||
 | 
				
			|||||||
@ -3,12 +3,13 @@
 | 
				
			|||||||
#include <blah/images/image.h>
 | 
					#include <blah/images/image.h>
 | 
				
			||||||
#include <blah/containers/str.h>
 | 
					#include <blah/containers/str.h>
 | 
				
			||||||
#include <blah/streams/stream.h>
 | 
					#include <blah/streams/stream.h>
 | 
				
			||||||
 | 
					#include <blah/core/filesystem.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// A simple Aseprite file parser.
 | 
						// A simple Aseprite file parser.
 | 
				
			||||||
	// This implementation does not support Aseprite blendmodes,
 | 
						// This implementation does not support Aseprite blendmodes,
 | 
				
			||||||
	// besides the default blend mode.
 | 
						// aside from the default blend mode.
 | 
				
			||||||
	class Aseprite
 | 
						class Aseprite
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
@ -130,7 +131,7 @@ namespace Blah
 | 
				
			|||||||
		Vector<Color> palette;
 | 
							Vector<Color> palette;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Aseprite();
 | 
							Aseprite();
 | 
				
			||||||
		Aseprite(const char* path);
 | 
							Aseprite(const FilePath& path);
 | 
				
			||||||
		Aseprite(Stream& stream);
 | 
							Aseprite(Stream& stream);
 | 
				
			||||||
		Aseprite(const Aseprite& src);
 | 
							Aseprite(const Aseprite& src);
 | 
				
			||||||
		Aseprite(Aseprite&& src) noexcept;
 | 
							Aseprite(Aseprite&& src) noexcept;
 | 
				
			||||||
 | 
				
			|||||||
@ -2,50 +2,102 @@
 | 
				
			|||||||
#include <blah/streams/stream.h>
 | 
					#include <blah/streams/stream.h>
 | 
				
			||||||
#include <blah/images/image.h>
 | 
					#include <blah/images/image.h>
 | 
				
			||||||
#include <blah/containers/str.h>
 | 
					#include <blah/containers/str.h>
 | 
				
			||||||
 | 
					#include <blah/core/filesystem.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	typedef uint32_t Codepoint;
 | 
						// Loads fonts from file and can blit individual characters to images
 | 
				
			||||||
 | 
					 | 
				
			||||||
	class Font
 | 
						class Font
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	public:
 | 
						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;
 | 
								int glyph = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// width of the character, in pixels
 | 
				
			||||||
			int width = 0;
 | 
								int width = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// height of the character, in pixels
 | 
				
			||||||
			int height = 0;
 | 
								int height = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// advance (how much to move horizontally)
 | 
				
			||||||
			float advance = 0;
 | 
								float advance = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// render x-offset
 | 
				
			||||||
			float offset_x = 0;
 | 
								float offset_x = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// render y-offset
 | 
				
			||||||
			float offset_y = 0;
 | 
								float offset_y = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// scale the character was created at
 | 
				
			||||||
			float scale = 0;
 | 
								float scale = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// whether the character has a visible glyph
 | 
				
			||||||
			bool has_glyph = false;
 | 
								bool has_glyph = false;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Font();
 | 
							Font();
 | 
				
			||||||
		Font(Stream& stream);
 | 
							Font(Stream& stream);
 | 
				
			||||||
		Font(const char* path);
 | 
							Font(const FilePath& path);
 | 
				
			||||||
		Font(const Font&) = delete;
 | 
							Font(const Font&) = delete;
 | 
				
			||||||
		Font& operator=(const Font&) = delete;
 | 
							Font& operator=(const Font&) = delete;
 | 
				
			||||||
		Font(Font&& src) noexcept;
 | 
							Font(Font&& src) noexcept;
 | 
				
			||||||
		Font& operator=(Font&& src) noexcept;
 | 
							Font& operator=(Font&& src) noexcept;
 | 
				
			||||||
		~Font();
 | 
							~Font();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Releases all Font resources
 | 
				
			||||||
 | 
							// Note that after doing this various properties may become invalid (ex. font name)
 | 
				
			||||||
		void dispose();
 | 
							void dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const char* family_name() const;
 | 
							// returns the font family name
 | 
				
			||||||
		const char* style_name() const;
 | 
							const String& family_name() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// returns the font style name
 | 
				
			||||||
 | 
							const String& style_name() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// the font ascent
 | 
				
			||||||
		int ascent() const;
 | 
							int ascent() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// the font descent
 | 
				
			||||||
		int descent() const;
 | 
							int descent() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// the font line gap (space between lines)
 | 
				
			||||||
		int line_gap() const;
 | 
							int line_gap() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// the height of the font
 | 
				
			||||||
		int height() const;
 | 
							int height() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// the height of the line, including line gap
 | 
				
			||||||
		int line_height() const;
 | 
							int line_height() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// gets the glyph index for the given codepoint
 | 
				
			||||||
		int get_glyph(Codepoint codepoint) const;
 | 
							int get_glyph(Codepoint codepoint) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// gets the font scale for the given font size in pixels
 | 
				
			||||||
		float get_scale(float size) const;
 | 
							float get_scale(float size) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// gets the font kerning between 2 glyphs
 | 
				
			||||||
		float get_kerning(int glyph1, int glyph2, float scale) const;
 | 
							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;
 | 
							bool is_valid() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
 | 
				
			|||||||
@ -2,21 +2,31 @@
 | 
				
			|||||||
#include <blah/math/color.h>
 | 
					#include <blah/math/color.h>
 | 
				
			||||||
#include <blah/math/rectI.h>
 | 
					#include <blah/math/rectI.h>
 | 
				
			||||||
#include <blah/math/point.h>
 | 
					#include <blah/math/point.h>
 | 
				
			||||||
 | 
					#include <blah/core/filesystem.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	class Stream;
 | 
						class Stream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// A 2D Bitmap stored on the CPU.
 | 
				
			||||||
 | 
						// For drawing images to the screen, use a Texture.
 | 
				
			||||||
	class Image
 | 
						class Image
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// width of the image, in pixels.
 | 
				
			||||||
		int width = 0;
 | 
							int width = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// height of the image, in pixels.
 | 
				
			||||||
		int height = 0;
 | 
							int height = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// pixel data of the image.
 | 
				
			||||||
 | 
							// this can be nullptr if the image is never assigned to anything.
 | 
				
			||||||
		Color* pixels = nullptr;
 | 
							Color* pixels = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Image();
 | 
							Image();
 | 
				
			||||||
		Image(Stream& stream);
 | 
							Image(Stream& stream);
 | 
				
			||||||
		Image(const char* file);
 | 
							Image(const FilePath& file);
 | 
				
			||||||
		Image(int width, int height);
 | 
							Image(int width, int height);
 | 
				
			||||||
		Image(const Image& src);
 | 
							Image(const Image& src);
 | 
				
			||||||
		Image& operator=(const Image& src);
 | 
							Image& operator=(const Image& src);
 | 
				
			||||||
@ -24,19 +34,41 @@ namespace Blah
 | 
				
			|||||||
		Image& operator=(Image&& src) noexcept;
 | 
							Image& operator=(Image&& src) noexcept;
 | 
				
			||||||
		~Image();
 | 
							~Image();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// disposes the existing image and recreates it from a stream
 | 
				
			||||||
		void from_stream(Stream& stream);
 | 
							void from_stream(Stream& stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// disposes the image and resets its values to defaults
 | 
				
			||||||
		void dispose();
 | 
							void dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// applies alpha premultiplication to the image data
 | 
				
			||||||
		void premultiply();
 | 
							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);
 | 
							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_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;
 | 
							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:
 | 
						private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// whether the stbi library owns the image data.
 | 
				
			||||||
 | 
							// we should let it free the data if it created it.
 | 
				
			||||||
		bool m_stbi_ownership;
 | 
							bool m_stbi_ownership;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -6,37 +6,67 @@
 | 
				
			|||||||
#include <blah/containers/str.h>
 | 
					#include <blah/containers/str.h>
 | 
				
			||||||
#include <blah/containers/vector.h>
 | 
					#include <blah/containers/vector.h>
 | 
				
			||||||
#include <blah/streams/bufferstream.h>
 | 
					#include <blah/streams/bufferstream.h>
 | 
				
			||||||
 | 
					#include <blah/core/filesystem.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// Texture Packer, which takes source images and combines
 | 
						// 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
 | 
						class Packer
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Packer Entry, which stores information about the resulting packed texture
 | 
				
			||||||
		class Entry
 | 
							class Entry
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
		friend class Packer;
 | 
							friend class Packer;
 | 
				
			||||||
		private:
 | 
							private:
 | 
				
			||||||
			int64_t memory_index;
 | 
								i64 memory_index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public:
 | 
							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;
 | 
								int page;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Whether the entry is empty
 | 
				
			||||||
			bool empty;
 | 
								bool empty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Packed frame rectangle.
 | 
				
			||||||
 | 
								// This won't be set until after the packer has run.
 | 
				
			||||||
			RectI frame;
 | 
								RectI frame;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Packed position and size.
 | 
				
			||||||
 | 
								// This won't be set until after the packer has run.
 | 
				
			||||||
			RectI packed;
 | 
								RectI packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Entry(uint64_t id, const RectI& frame)
 | 
								Entry(u64 id, const RectI& frame)
 | 
				
			||||||
				: memory_index(0), id(id), page(0), empty(true), frame(frame), packed(0, 0, 0, 0) {}
 | 
									: 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;
 | 
							int max_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// whether the generated texture must be a power of 2
 | 
				
			||||||
		bool power_of_two;
 | 
							bool power_of_two;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// spacing between each packed subtexture
 | 
				
			||||||
		int spacing;
 | 
							int spacing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// padding on each subtexture (extrudes their borders outwards)
 | 
				
			||||||
		int padding;
 | 
							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<Image> pages;
 | 
				
			||||||
		Vector<Entry> entries;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Packer();
 | 
							Packer();
 | 
				
			||||||
		Packer(int max_size, int spacing, bool power_of_two);
 | 
							Packer(int max_size, int spacing, bool power_of_two);
 | 
				
			||||||
@ -46,12 +76,25 @@ namespace Blah
 | 
				
			|||||||
		Packer& operator=(Packer&& src) noexcept;
 | 
							Packer& operator=(Packer&& src) noexcept;
 | 
				
			||||||
		~Packer();
 | 
							~Packer();
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		void add(uint64_t id, int width, int height, const Color* pixels);
 | 
							// add a new entry
 | 
				
			||||||
		void add(uint64_t id, const Image& bitmap);
 | 
							void add(u64 id, int width, int height, const Color* pixels);
 | 
				
			||||||
		void add(uint64_t id, const String& path);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 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();
 | 
							void pack();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// clear the current packer data
 | 
				
			||||||
		void clear();
 | 
							void clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// dispose all resources used by the packer
 | 
				
			||||||
		void dispose();
 | 
							void dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
@ -67,9 +110,16 @@ namespace Blah
 | 
				
			|||||||
			Node* Reset(const RectI& rect);
 | 
								Node* Reset(const RectI& rect);
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// whether the packer has any changes that require it to run again
 | 
				
			||||||
		bool m_dirty;
 | 
							bool m_dirty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// buffer of all the image data we will be packing
 | 
				
			||||||
		BufferStream m_buffer;
 | 
							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
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <blah/math/vec2.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 BLAH_KEY_DEFINITIONS \
 | 
				
			||||||
	DEFINE_KEY(Unknown, 0) \
 | 
						DEFINE_KEY(Unknown, 0) \
 | 
				
			||||||
 | 
					    \
 | 
				
			||||||
    DEFINE_KEY(A, 4) \
 | 
					    DEFINE_KEY(A, 4) \
 | 
				
			||||||
    DEFINE_KEY(B, 5) \
 | 
					    DEFINE_KEY(B, 5) \
 | 
				
			||||||
    DEFINE_KEY(C, 6) \
 | 
					    DEFINE_KEY(C, 6) \
 | 
				
			||||||
@ -32,6 +36,7 @@
 | 
				
			|||||||
    DEFINE_KEY(X, 27) \
 | 
					    DEFINE_KEY(X, 27) \
 | 
				
			||||||
    DEFINE_KEY(Y, 28) \
 | 
					    DEFINE_KEY(Y, 28) \
 | 
				
			||||||
    DEFINE_KEY(Z, 29) \
 | 
					    DEFINE_KEY(Z, 29) \
 | 
				
			||||||
 | 
					    \
 | 
				
			||||||
    DEFINE_KEY(D1, 30) \
 | 
					    DEFINE_KEY(D1, 30) \
 | 
				
			||||||
    DEFINE_KEY(D2, 31) \
 | 
					    DEFINE_KEY(D2, 31) \
 | 
				
			||||||
    DEFINE_KEY(D3, 32) \
 | 
					    DEFINE_KEY(D3, 32) \
 | 
				
			||||||
@ -42,24 +47,27 @@
 | 
				
			|||||||
    DEFINE_KEY(D8, 37) \
 | 
					    DEFINE_KEY(D8, 37) \
 | 
				
			||||||
    DEFINE_KEY(D9, 38) \
 | 
					    DEFINE_KEY(D9, 38) \
 | 
				
			||||||
    DEFINE_KEY(D0, 39) \
 | 
					    DEFINE_KEY(D0, 39) \
 | 
				
			||||||
 | 
					    \
 | 
				
			||||||
	DEFINE_KEY(Enter, 40) \
 | 
						DEFINE_KEY(Enter, 40) \
 | 
				
			||||||
	DEFINE_KEY(Escape, 41) \
 | 
						DEFINE_KEY(Escape, 41) \
 | 
				
			||||||
	DEFINE_KEY(Backspace, 42) \
 | 
						DEFINE_KEY(Backspace, 42) \
 | 
				
			||||||
	DEFINE_KEY(Tab, 43) \
 | 
						DEFINE_KEY(Tab, 43) \
 | 
				
			||||||
	DEFINE_KEY(Space, 44) \
 | 
						DEFINE_KEY(Space, 44) \
 | 
				
			||||||
 | 
					    \
 | 
				
			||||||
	DEFINE_KEY(Minus, 45) \
 | 
						DEFINE_KEY(Minus, 45) \
 | 
				
			||||||
	DEFINE_KEY(Equals, 46) \
 | 
						DEFINE_KEY(Equals, 46) \
 | 
				
			||||||
	DEFINE_KEY(LeftBracket, 47) \
 | 
						DEFINE_KEY(LeftBracket, 47) \
 | 
				
			||||||
	DEFINE_KEY(RightBracket, 48) \
 | 
						DEFINE_KEY(RightBracket, 48) \
 | 
				
			||||||
	DEFINE_KEY(BackSlash, 49) \
 | 
						DEFINE_KEY(Backslash, 49) \
 | 
				
			||||||
	DEFINE_KEY(NonUSHash, 50) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(Semicolon, 51) \
 | 
						DEFINE_KEY(Semicolon, 51) \
 | 
				
			||||||
	DEFINE_KEY(Apostrophe, 52) \
 | 
						DEFINE_KEY(Apostrophe, 52) \
 | 
				
			||||||
	DEFINE_KEY(Grave, 53) \
 | 
						DEFINE_KEY(Tilde, 53) \
 | 
				
			||||||
	DEFINE_KEY(Comma, 54) \
 | 
						DEFINE_KEY(Comma, 54) \
 | 
				
			||||||
	DEFINE_KEY(Period, 55) \
 | 
						DEFINE_KEY(Period, 55) \
 | 
				
			||||||
	DEFINE_KEY(Slash, 56) \
 | 
						DEFINE_KEY(Slash, 56) \
 | 
				
			||||||
 | 
					    \
 | 
				
			||||||
	DEFINE_KEY(Capslock, 57) \
 | 
						DEFINE_KEY(Capslock, 57) \
 | 
				
			||||||
 | 
					    \
 | 
				
			||||||
    DEFINE_KEY(F1, 58) \
 | 
					    DEFINE_KEY(F1, 58) \
 | 
				
			||||||
    DEFINE_KEY(F2, 59) \
 | 
					    DEFINE_KEY(F2, 59) \
 | 
				
			||||||
    DEFINE_KEY(F3, 60) \
 | 
					    DEFINE_KEY(F3, 60) \
 | 
				
			||||||
@ -72,6 +80,19 @@
 | 
				
			|||||||
    DEFINE_KEY(F10, 67) \
 | 
					    DEFINE_KEY(F10, 67) \
 | 
				
			||||||
    DEFINE_KEY(F11, 68) \
 | 
					    DEFINE_KEY(F11, 68) \
 | 
				
			||||||
    DEFINE_KEY(F12, 69) \
 | 
					    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(PrintScreen, 70) \
 | 
				
			||||||
    DEFINE_KEY(ScrollLock, 71) \
 | 
					    DEFINE_KEY(ScrollLock, 71) \
 | 
				
			||||||
    DEFINE_KEY(Pause, 72) \
 | 
					    DEFINE_KEY(Pause, 72) \
 | 
				
			||||||
@ -85,45 +106,17 @@
 | 
				
			|||||||
    DEFINE_KEY(Left, 80) \
 | 
					    DEFINE_KEY(Left, 80) \
 | 
				
			||||||
    DEFINE_KEY(Down, 81) \
 | 
					    DEFINE_KEY(Down, 81) \
 | 
				
			||||||
    DEFINE_KEY(Up, 82) \
 | 
					    DEFINE_KEY(Up, 82) \
 | 
				
			||||||
	DEFINE_KEY(NumlockClear, 83) \
 | 
					    \
 | 
				
			||||||
	DEFINE_KEY(KP_Divide, 84) \
 | 
					    DEFINE_KEY(Numlock, 83) \
 | 
				
			||||||
	DEFINE_KEY(KP_Multiply, 85) \
 | 
					    \
 | 
				
			||||||
	DEFINE_KEY(KP_Minus, 86) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_Plus, 87) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_Enter, 88) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_1, 89) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_2, 90) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_3, 91) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_4, 92) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_5, 93) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_6, 94) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_7, 95) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_8, 96) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_9, 97) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_0, 98) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_Period, 99) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(NonUSBackSlash, 100) \
 | 
					 | 
				
			||||||
    DEFINE_KEY(Application, 101) \
 | 
					    DEFINE_KEY(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(Execute, 116) \
 | 
				
			||||||
    DEFINE_KEY(Help, 117) \
 | 
					    DEFINE_KEY(Help, 117) \
 | 
				
			||||||
    DEFINE_KEY(Menu, 118) \
 | 
					    DEFINE_KEY(Menu, 118) \
 | 
				
			||||||
    DEFINE_KEY(Select, 119) \
 | 
					    DEFINE_KEY(Select, 119) \
 | 
				
			||||||
    DEFINE_KEY(Stop, 120) \
 | 
					    DEFINE_KEY(Stop, 120) \
 | 
				
			||||||
	DEFINE_KEY(Again, 121) \
 | 
					    DEFINE_KEY(Redo, 121) \
 | 
				
			||||||
    DEFINE_KEY(Undo, 122) \
 | 
					    DEFINE_KEY(Undo, 122) \
 | 
				
			||||||
    DEFINE_KEY(Cut, 123) \
 | 
					    DEFINE_KEY(Cut, 123) \
 | 
				
			||||||
    DEFINE_KEY(Copy, 124) \
 | 
					    DEFINE_KEY(Copy, 124) \
 | 
				
			||||||
@ -132,92 +125,69 @@
 | 
				
			|||||||
    DEFINE_KEY(Mute, 127) \
 | 
					    DEFINE_KEY(Mute, 127) \
 | 
				
			||||||
    DEFINE_KEY(VolumeUp, 128) \
 | 
					    DEFINE_KEY(VolumeUp, 128) \
 | 
				
			||||||
    DEFINE_KEY(VolumeDown, 129) \
 | 
					    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(AltErase, 153) \
 | 
				
			||||||
    DEFINE_KEY(SysReq, 154) \
 | 
					    DEFINE_KEY(SysReq, 154) \
 | 
				
			||||||
    DEFINE_KEY(Cancel, 155) \
 | 
					    DEFINE_KEY(Cancel, 155) \
 | 
				
			||||||
	DEFINE_KEY(clear, 156) \
 | 
					    DEFINE_KEY(Clear, 156) \
 | 
				
			||||||
    DEFINE_KEY(Prior, 157) \
 | 
					    DEFINE_KEY(Prior, 157) \
 | 
				
			||||||
	DEFINE_KEY(Return2, 158) \
 | 
					    DEFINE_KEY(Enter2, 158) \
 | 
				
			||||||
    DEFINE_KEY(Separator, 159) \
 | 
					    DEFINE_KEY(Separator, 159) \
 | 
				
			||||||
    DEFINE_KEY(Out, 160) \
 | 
					    DEFINE_KEY(Out, 160) \
 | 
				
			||||||
    DEFINE_KEY(Oper, 161) \
 | 
					    DEFINE_KEY(Oper, 161) \
 | 
				
			||||||
    DEFINE_KEY(ClearAgain, 162) \
 | 
					    DEFINE_KEY(ClearAgain, 162) \
 | 
				
			||||||
	DEFINE_KEY(CRSEL, 163) \
 | 
					    \
 | 
				
			||||||
	DEFINE_KEY(EXSEL, 164) \
 | 
					    DEFINE_KEY(KeypadA, 188) \
 | 
				
			||||||
	DEFINE_KEY(KP_00, 176) \
 | 
					    DEFINE_KEY(KeypadB, 189) \
 | 
				
			||||||
	DEFINE_KEY(KP_000, 177) \
 | 
					    DEFINE_KEY(KeypadC, 190) \
 | 
				
			||||||
	DEFINE_KEY(ThousandsSeparator, 178) \
 | 
					    DEFINE_KEY(KeypadD, 191) \
 | 
				
			||||||
	DEFINE_KEY(DecimalSeparator, 179) \
 | 
					    DEFINE_KEY(KeypadE, 192) \
 | 
				
			||||||
	DEFINE_KEY(CurrencyUnit, 180) \
 | 
					    DEFINE_KEY(KeypadF, 193) \
 | 
				
			||||||
	DEFINE_KEY(CurrencySubUnit, 181) \
 | 
						DEFINE_KEY(Keypad0, 98) \
 | 
				
			||||||
	DEFINE_KEY(KP_LeftParen, 182) \
 | 
					    DEFINE_KEY(Keypad00, 176) \
 | 
				
			||||||
	DEFINE_KEY(KP_RightParent, 183) \
 | 
					    DEFINE_KEY(Keypad000, 177) \
 | 
				
			||||||
	DEFINE_KEY(KP_LeftBrace, 184) \
 | 
						DEFINE_KEY(Keypad1, 89) \
 | 
				
			||||||
	DEFINE_KEY(KP_RightBrace, 185) \
 | 
						DEFINE_KEY(Keypad2, 90) \
 | 
				
			||||||
	DEFINE_KEY(KP_Tab, 186) \
 | 
						DEFINE_KEY(Keypad3, 91) \
 | 
				
			||||||
	DEFINE_KEY(KP_BackSpace, 187) \
 | 
						DEFINE_KEY(Keypad4, 92) \
 | 
				
			||||||
	DEFINE_KEY(KP_A, 188) \
 | 
						DEFINE_KEY(Keypad5, 93) \
 | 
				
			||||||
	DEFINE_KEY(KP_B, 189) \
 | 
						DEFINE_KEY(Keypad6, 94) \
 | 
				
			||||||
	DEFINE_KEY(KP_C, 190) \
 | 
						DEFINE_KEY(Keypad7, 95) \
 | 
				
			||||||
	DEFINE_KEY(KP_D, 191) \
 | 
						DEFINE_KEY(Keypad8, 96) \
 | 
				
			||||||
	DEFINE_KEY(KP_E, 192) \
 | 
						DEFINE_KEY(Keypad9, 97) \
 | 
				
			||||||
	DEFINE_KEY(KP_F, 193) \
 | 
						DEFINE_KEY(KeypadDivide, 84) \
 | 
				
			||||||
	DEFINE_KEY(KP_XOR, 194) \
 | 
						DEFINE_KEY(KeypadMultiply, 85) \
 | 
				
			||||||
	DEFINE_KEY(KP_Power, 195) \
 | 
						DEFINE_KEY(KeypadMinus, 86) \
 | 
				
			||||||
	DEFINE_KEY(KP_Percent, 196) \
 | 
						DEFINE_KEY(KeypadPlus, 87) \
 | 
				
			||||||
	DEFINE_KEY(KP_Less, 197) \
 | 
						DEFINE_KEY(KeypadEnter, 88) \
 | 
				
			||||||
	DEFINE_KEY(KP_Greater, 198) \
 | 
						DEFINE_KEY(KeypadPeroid, 99) \
 | 
				
			||||||
	DEFINE_KEY(KP_Ampersand, 199) \
 | 
					    DEFINE_KEY(KeypadEquals, 103) \
 | 
				
			||||||
	DEFINE_KEY(KP_DoubleAmpersand, 200) \
 | 
						DEFINE_KEY(KeypadComma, 133) \
 | 
				
			||||||
	DEFINE_KEY(KP_VerticalBar, 201) \
 | 
					    DEFINE_KEY(KeypadLeftParen, 182) \
 | 
				
			||||||
	DEFINE_KEY(KP_DoubleVerticalBar, 202) \
 | 
					    DEFINE_KEY(KeypadRightParen, 183) \
 | 
				
			||||||
	DEFINE_KEY(KP_Colon, 203) \
 | 
					    DEFINE_KEY(KeypadLeftBrace, 184) \
 | 
				
			||||||
	DEFINE_KEY(KP_Hash, 204) \
 | 
					    DEFINE_KEY(KeypadRightBrace, 185) \
 | 
				
			||||||
	DEFINE_KEY(KP_Space, 205) \
 | 
					    DEFINE_KEY(KeypadTab, 186) \
 | 
				
			||||||
	DEFINE_KEY(KP_At, 206) \
 | 
					    DEFINE_KEY(KeypadBackspace, 187) \
 | 
				
			||||||
	DEFINE_KEY(KP_EXCLAM, 207) \
 | 
					    DEFINE_KEY(KeypadXor, 194) \
 | 
				
			||||||
	DEFINE_KEY(KP_MemStore, 208) \
 | 
					    DEFINE_KEY(KeypadPower, 195) \
 | 
				
			||||||
	DEFINE_KEY(KP_MemRecall, 209) \
 | 
					    DEFINE_KEY(KeypadPercent, 196) \
 | 
				
			||||||
	DEFINE_KEY(KP_MemClear, 210) \
 | 
					    DEFINE_KEY(KeypadLess, 197) \
 | 
				
			||||||
	DEFINE_KEY(KP_MemAdd, 211) \
 | 
					    DEFINE_KEY(KeypadGreater, 198) \
 | 
				
			||||||
	DEFINE_KEY(KP_MemSubstract, 212) \
 | 
					    DEFINE_KEY(KeypadAmpersand, 199) \
 | 
				
			||||||
	DEFINE_KEY(KP_MemMultiply, 213) \
 | 
					    DEFINE_KEY(KeypadColon, 203) \
 | 
				
			||||||
	DEFINE_KEY(KP_MemDivide, 214) \
 | 
					    DEFINE_KEY(KeypadHash, 204) \
 | 
				
			||||||
	DEFINE_KEY(KP_PlusMinus, 215) \
 | 
					    DEFINE_KEY(KeypadSpace, 205) \
 | 
				
			||||||
	DEFINE_KEY(KP_Clear, 216) \
 | 
					    DEFINE_KEY(KeypadClear, 216) \
 | 
				
			||||||
	DEFINE_KEY(KP_ClearEntry, 217) \
 | 
					    \
 | 
				
			||||||
	DEFINE_KEY(KP_Binary, 218) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_Octal, 219) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_Decimal, 220) \
 | 
					 | 
				
			||||||
	DEFINE_KEY(KP_Hexadecimal, 221) \
 | 
					 | 
				
			||||||
    DEFINE_KEY(LeftControl, 224) \
 | 
					    DEFINE_KEY(LeftControl, 224) \
 | 
				
			||||||
    DEFINE_KEY(LeftShift, 225) \
 | 
					    DEFINE_KEY(LeftShift, 225) \
 | 
				
			||||||
    DEFINE_KEY(LeftAlt, 226) \
 | 
					    DEFINE_KEY(LeftAlt, 226) \
 | 
				
			||||||
	DEFINE_KEY(LeftGui, 227) \
 | 
					    DEFINE_KEY(LeftOS, 227) \
 | 
				
			||||||
    DEFINE_KEY(RightControl, 228) \
 | 
					    DEFINE_KEY(RightControl, 228) \
 | 
				
			||||||
    DEFINE_KEY(RightShift, 229) \
 | 
					    DEFINE_KEY(RightShift, 229) \
 | 
				
			||||||
    DEFINE_KEY(RightAlt, 230) \
 | 
					    DEFINE_KEY(RightAlt, 230) \
 | 
				
			||||||
	DEFINE_KEY(RightGui, 231)
 | 
					    DEFINE_KEY(RightOS, 231)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define BLAH_BUTTON_DEFINITIONS \
 | 
					#define BLAH_BUTTON_DEFINITIONS \
 | 
				
			||||||
	DEFINE_BTN(None, -1) \
 | 
						DEFINE_BTN(None, -1) \
 | 
				
			||||||
@ -255,12 +225,6 @@ namespace Blah
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// maximum number of keys the input will track
 | 
							// maximum number of keys the input will track
 | 
				
			||||||
		constexpr int max_keyboard_keys = 512;
 | 
							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
 | 
						struct ControllerState
 | 
				
			||||||
@ -293,19 +257,19 @@ namespace Blah
 | 
				
			|||||||
		float axis[Input::max_controller_axis];
 | 
							float axis[Input::max_controller_axis];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Timestamp, in milliseconds, since each button was last pressed
 | 
							// 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
 | 
							// 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
 | 
							// The USB Vendor ID
 | 
				
			||||||
		uint16_t vendor;
 | 
							u16 vendor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// The USB Product ID
 | 
							// The USB Product ID
 | 
				
			||||||
		uint16_t product;
 | 
							u16 product;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// the Product Version
 | 
							// the Product Version
 | 
				
			||||||
		uint16_t version;
 | 
							u16 version;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct KeyboardState
 | 
						struct KeyboardState
 | 
				
			||||||
@ -313,8 +277,8 @@ namespace Blah
 | 
				
			|||||||
		bool pressed[Input::max_keyboard_keys];
 | 
							bool pressed[Input::max_keyboard_keys];
 | 
				
			||||||
		bool down[Input::max_keyboard_keys];
 | 
							bool down[Input::max_keyboard_keys];
 | 
				
			||||||
		bool released[Input::max_keyboard_keys];
 | 
							bool released[Input::max_keyboard_keys];
 | 
				
			||||||
		uint64_t timestamp[Input::max_keyboard_keys];
 | 
							u64 timestamp[Input::max_keyboard_keys];
 | 
				
			||||||
		char text[Input::max_text_input];
 | 
							String text;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct MouseState
 | 
						struct MouseState
 | 
				
			||||||
@ -322,7 +286,7 @@ namespace Blah
 | 
				
			|||||||
		bool pressed[Input::max_mouse_buttons];
 | 
							bool pressed[Input::max_mouse_buttons];
 | 
				
			||||||
		bool down[Input::max_mouse_buttons];
 | 
							bool down[Input::max_mouse_buttons];
 | 
				
			||||||
		bool released[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 screen_position;
 | 
				
			||||||
		Vec2 draw_position;
 | 
							Vec2 draw_position;
 | 
				
			||||||
		Vec2 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
 | 
					#pragma once
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <blah/math/vec2.h>
 | 
					#include <blah/math/vec2.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
@ -27,10 +27,6 @@ namespace Blah
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		Vec2 approach(const Vec2& t, const Vec2& target, float delta);
 | 
							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 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);
 | 
							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);
 | 
							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>
 | 
							template<class T, class U>
 | 
				
			||||||
		T min(T a, U b) { return  (T)(a < b ? a : b); }
 | 
							T min(T a, U b) { return  (T)(a < b ? a : b); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,38 +1,41 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <blah/containers/str.h>
 | 
					#include <blah/containers/str.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct Vec3;
 | 
				
			||||||
	struct Vec4;
 | 
						struct Vec4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct Color
 | 
						struct Color
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		uint8_t r;
 | 
							u8 r;
 | 
				
			||||||
		uint8_t g;
 | 
							u8 g;
 | 
				
			||||||
		uint8_t b;
 | 
							u8 b;
 | 
				
			||||||
		uint8_t a;
 | 
							u8 a;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Color();
 | 
							Color();
 | 
				
			||||||
		Color(int rgb);
 | 
							Color(int rgb);
 | 
				
			||||||
		Color(int rgb, float alpha);
 | 
							Color(int rgb, float alpha);
 | 
				
			||||||
		Color(uint8_t r, uint8_t g, uint8_t b);
 | 
							Color(u8 r, u8 g, u8 b);
 | 
				
			||||||
		Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
 | 
							Color(u8 r, u8 g, u8 b, u8 a);
 | 
				
			||||||
 | 
							Color(const Vec3& vec3);
 | 
				
			||||||
 | 
							Color(const Vec3& vec3, float alpha);
 | 
				
			||||||
		Color(const Vec4& vec4);
 | 
							Color(const Vec4& vec4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Parses a Hex string in the format of "#00000000" or "0x00000000" or "00000000"
 | 
							// 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
 | 
							// Premultiplies the Color
 | 
				
			||||||
		void premultiply();
 | 
							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
 | 
							// Sets a Hex string to the given buffer, in the format of RRGGBBAA
 | 
				
			||||||
		// The buffer must be at least 8 bytes long
 | 
							// The buffer must be at least 8 bytes long
 | 
				
			||||||
		void to_hex_rgba(char* buffer) const;
 | 
							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
 | 
							// Sets a Hex string to the given buffer, in the format of RRGGBB
 | 
				
			||||||
		// The buffer must be at least 6 bytes long
 | 
							// The buffer must be at least 6 bytes long
 | 
				
			||||||
		void to_hex_rgb(char* buffer) const;
 | 
							void to_hex_rgb(char* buffer) const;
 | 
				
			||||||
@ -40,17 +43,17 @@ namespace Blah
 | 
				
			|||||||
		// Returns an RGB hex string of the color
 | 
							// Returns an RGB hex string of the color
 | 
				
			||||||
		String to_hex_rgb() const;
 | 
							String to_hex_rgb() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Convers the Color to a uint32_t
 | 
							// Convers the Color to a u32
 | 
				
			||||||
		uint32_t to_rgba() const;
 | 
							u32 to_rgba() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Converts the Color to a Vec4
 | 
							// Converts the Color to a Vec4
 | 
				
			||||||
		Vec4 to_vec4() const;
 | 
							Vec4 to_vec4() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Returns a RGBA Color representation of the integer value
 | 
							// 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
 | 
							// 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
 | 
							// Lerps between two colors
 | 
				
			||||||
		static Color lerp(Color a, Color b, float amount);
 | 
							static Color lerp(Color a, Color b, float amount);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <blah/math/calc.h>
 | 
					#include <blah/math/calc.h>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -8,6 +8,7 @@ namespace Blah
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	enum class Easers
 | 
						enum class Easers
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							Linear,
 | 
				
			||||||
		QuadIn, QuadOut, QuadInOut,
 | 
							QuadIn, QuadOut, QuadInOut,
 | 
				
			||||||
		CubeIn, CubeOut, CubeInOut,
 | 
							CubeIn, CubeOut, CubeInOut,
 | 
				
			||||||
		QuartIn, QuartOut, QuartInOut,
 | 
							QuartIn, QuartOut, QuartInOut,
 | 
				
			||||||
@ -28,43 +29,41 @@ namespace Blah
 | 
				
			|||||||
			For previews go here: https://easings.net/
 | 
								For previews go here: https://easings.net/
 | 
				
			||||||
		*/
 | 
							*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline float linear(float t)
 | 
							constexpr float linear(float t)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return t;
 | 
								return t;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline float quad_in(float t)
 | 
							constexpr float quad_in(float t)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return t * t;
 | 
								return t * t;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline float quad_out(float t)
 | 
							constexpr float quad_out(float t)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return -(t * (t - 2));
 | 
								return -(t * (t - 2));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline float quad_in_out(float t)
 | 
							constexpr float quad_in_out(float t)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (t < 0.5f)
 | 
								if (t < 0.5f)
 | 
				
			||||||
				return 2 * t * t;
 | 
									return 2 * t * t;
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				return (-2 * t * t) + (4 * t) - 1;
 | 
									return (-2 * t * t) + (4 * t) - 1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline float cube_in(float t)
 | 
							constexpr float cube_in(float t)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return t * t * t;
 | 
								return t * t * t;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline float cube_out(float t)
 | 
							constexpr float cube_out(float t)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			float f = (t - 1);
 | 
								float f = (t - 1);
 | 
				
			||||||
			return f * f * f + 1;
 | 
								return f * f * f + 1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline float cube_in_out(float t)
 | 
							constexpr float cube_in_out(float t)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (t < 0.5f)
 | 
								if (t < 0.5f)
 | 
				
			||||||
				return 4 * t * t * t;
 | 
									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;
 | 
								return t * t * t * t;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline float quart_out(float t)
 | 
							constexpr float quart_out(float t)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			float f = (t - 1);
 | 
								float f = (t - 1);
 | 
				
			||||||
			return f * f * f * (1 - 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)
 | 
								if (t < 0.5f)
 | 
				
			||||||
				return 8 * t * t * t * t;
 | 
									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;
 | 
								return t * t * t * t * t;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline float quint_out(float t)
 | 
							constexpr float quint_out(float t)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			float f = (t - 1);
 | 
								float f = (t - 1);
 | 
				
			||||||
			return f * f * f * f * f + 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)
 | 
								if (t < 0.5f)
 | 
				
			||||||
				return 16 * t * t * t * t * t;
 | 
									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)
 | 
								if (t < 4 / 11.0f)
 | 
				
			||||||
				return (121 * t * t) / 16.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;
 | 
									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);
 | 
								return 1 - bounce_out(1 - t);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inline float bounce_in_out(float t)
 | 
							constexpr float bounce_in_out(float t)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (t < 0.5f)
 | 
								if (t < 0.5f)
 | 
				
			||||||
				return 0.5f * bounce_in(t * 2);
 | 
									return 0.5f * bounce_in(t * 2);
 | 
				
			||||||
@ -245,6 +244,8 @@ namespace Blah
 | 
				
			|||||||
		{
 | 
							{
 | 
				
			||||||
			switch (e)
 | 
								switch (e)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
 | 
								case Easers::Linear: return &linear;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case Easers::CubeIn: return &cube_in;
 | 
								case Easers::CubeIn: return &cube_in;
 | 
				
			||||||
			case Easers::CubeOut: return &cube_out;
 | 
								case Easers::CubeOut: return &cube_out;
 | 
				
			||||||
			case Easers::CubeInOut: return &cube_in_out;
 | 
								case Easers::CubeInOut: return &cube_in_out;
 | 
				
			||||||
@ -296,6 +297,7 @@ namespace Blah
 | 
				
			|||||||
		{
 | 
							{
 | 
				
			||||||
			switch (e)
 | 
								switch (e)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
 | 
								case Easers::Linear: return "Linear";
 | 
				
			||||||
			case Easers::CubeIn: return "CubeIn";
 | 
								case Easers::CubeIn: return "CubeIn";
 | 
				
			||||||
			case Easers::CubeOut: return "CubeOut";
 | 
								case Easers::CubeOut: return "CubeOut";
 | 
				
			||||||
			case Easers::CubeInOut: return "CubeInOut";
 | 
								case Easers::CubeInOut: return "CubeInOut";
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ namespace Blah
 | 
				
			|||||||
		Vec2 a;
 | 
							Vec2 a;
 | 
				
			||||||
		Vec2 b;
 | 
							Vec2 b;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Line() {}
 | 
							Line() = default;
 | 
				
			||||||
		Line(float x0, float y0, float x1, float y1);
 | 
							Line(float x0, float y0, float x1, float y1);
 | 
				
			||||||
		Line(const Vec2& start, const Vec2& end);
 | 
							Line(const Vec2& start, const Vec2& end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -8,9 +8,9 @@ namespace Blah
 | 
				
			|||||||
	public:
 | 
						public:
 | 
				
			||||||
		Stopwatch();
 | 
							Stopwatch();
 | 
				
			||||||
		void reset();
 | 
							void reset();
 | 
				
			||||||
		uint64_t microseconds();
 | 
							u64 microseconds();
 | 
				
			||||||
		uint64_t milliseconds();
 | 
							u64 milliseconds();
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		uint64_t start_time;
 | 
							u64 start_time;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -12,9 +12,9 @@ namespace Blah
 | 
				
			|||||||
		BufferStream& operator=(BufferStream&& bs) noexcept;
 | 
							BufferStream& operator=(BufferStream&& bs) noexcept;
 | 
				
			||||||
		~BufferStream();
 | 
							~BufferStream();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		virtual int64_t length() const override { return m_length; }
 | 
							virtual i64 length() const override { return m_length; }
 | 
				
			||||||
		virtual int64_t position() const override { return m_position; }
 | 
							virtual i64 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 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_open() const override { return m_buffer != nullptr; }
 | 
				
			||||||
		virtual bool is_readable() const override { return true; }
 | 
							virtual bool is_readable() const override { return true; }
 | 
				
			||||||
		virtual bool is_writable() 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; }
 | 
							const char* data() const { return m_buffer; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected:
 | 
						protected:
 | 
				
			||||||
		virtual int64_t read_into(void* ptr, int64_t length) override;
 | 
							virtual i64 read_into(void* ptr, i64 length) override;
 | 
				
			||||||
		virtual int64_t write_from(const void* ptr, int64_t length) override;
 | 
							virtual i64 write_from(const void* ptr, i64 length) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		char* m_buffer;
 | 
							char* m_buffer;
 | 
				
			||||||
		int64_t m_capacity;
 | 
							i64 m_capacity;
 | 
				
			||||||
		int64_t m_length;
 | 
							i64 m_length;
 | 
				
			||||||
		int64_t m_position;
 | 
							i64 m_position;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -8,22 +8,22 @@ namespace Blah
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		FileStream();
 | 
							FileStream();
 | 
				
			||||||
		FileStream(const char* path, FileMode mode = FileMode::ReadWrite);
 | 
							FileStream(const FilePath& path, FileMode mode = FileMode::ReadWrite);
 | 
				
			||||||
		FileStream(FileStream&& fs) noexcept;
 | 
							FileStream(FileStream&& fs) noexcept;
 | 
				
			||||||
		FileStream& operator=(FileStream&& fs) noexcept;
 | 
							FileStream& operator=(FileStream&& fs) noexcept;
 | 
				
			||||||
		~FileStream();
 | 
							~FileStream();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		virtual int64_t length() const override;
 | 
							virtual i64 length() const override;
 | 
				
			||||||
		virtual int64_t position() const override;
 | 
							virtual i64 position() const override;
 | 
				
			||||||
		virtual int64_t seek(int64_t seekTo) override;
 | 
							virtual i64 seek(i64 seekTo) override;
 | 
				
			||||||
		virtual bool is_open() const override { return m_handle != nullptr; }
 | 
							virtual bool is_open() const override;
 | 
				
			||||||
		virtual bool is_readable() const override { return m_handle != nullptr && (m_mode == FileMode::ReadWrite || m_mode == FileMode::Read); }
 | 
							virtual bool is_readable() const override;
 | 
				
			||||||
		virtual bool is_writable() const override { return m_handle != nullptr && (m_mode == FileMode::ReadWrite || m_mode == FileMode::Write); }
 | 
							virtual bool is_writable() const override;
 | 
				
			||||||
		virtual void close() override;
 | 
							virtual void close() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected:
 | 
						protected:
 | 
				
			||||||
		virtual int64_t read_into(void* ptr, int64_t length) override;
 | 
							virtual i64 read_into(void* ptr, i64 length) override;
 | 
				
			||||||
		virtual int64_t write_from(const void* ptr, int64_t length) override;
 | 
							virtual i64 write_from(const void* ptr, i64 length) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		FileMode m_mode;
 | 
							FileMode m_mode;
 | 
				
			||||||
 | 
				
			|||||||
@ -7,14 +7,14 @@ namespace Blah
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		MemoryStream();
 | 
							MemoryStream();
 | 
				
			||||||
		MemoryStream(char* data, int64_t length);
 | 
							MemoryStream(char* data, i64 length);
 | 
				
			||||||
		MemoryStream(MemoryStream&& ms) noexcept;
 | 
							MemoryStream(MemoryStream&& ms) noexcept;
 | 
				
			||||||
		MemoryStream& operator=(MemoryStream&& ms) noexcept;
 | 
							MemoryStream& operator=(MemoryStream&& ms) noexcept;
 | 
				
			||||||
		~MemoryStream() { m_data = nullptr; m_length = m_position = 0; }
 | 
							~MemoryStream() { m_data = nullptr; m_length = m_position = 0; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		virtual int64_t length() const override { return m_length; }
 | 
							virtual i64 length() const override { return m_length; }
 | 
				
			||||||
		virtual int64_t position() const override { return m_position; }
 | 
							virtual i64 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 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_open() const override { return m_data != nullptr; }
 | 
				
			||||||
		virtual bool is_readable() const override { return true; }
 | 
							virtual bool is_readable() const override { return true; }
 | 
				
			||||||
		virtual bool is_writable() 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; }
 | 
							const char* data() const { return m_data; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected:
 | 
						protected:
 | 
				
			||||||
		virtual int64_t read_into(void* ptr, int64_t length) override;
 | 
							virtual i64 read_into(void* ptr, i64 length) override;
 | 
				
			||||||
		virtual int64_t write_from(const void* ptr, int64_t length) override;
 | 
							virtual i64 write_from(const void* ptr, i64 length) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		char* m_data;
 | 
							char* m_data;
 | 
				
			||||||
		int64_t m_length;
 | 
							i64 m_length;
 | 
				
			||||||
		int64_t m_position;
 | 
							i64 m_position;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <blah/containers/str.h>
 | 
					#include <blah/containers/str.h>
 | 
				
			||||||
#include <blah/streams/endian.h>
 | 
					#include <blah/streams/endian.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
@ -16,13 +16,13 @@ namespace Blah
 | 
				
			|||||||
		virtual ~Stream() = default;
 | 
							virtual ~Stream() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// returns the length of the stream
 | 
							// returns the length of the stream
 | 
				
			||||||
		virtual int64_t length() const = 0;
 | 
							virtual i64 length() const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// returns the position of the stream
 | 
							// returns the position of the stream
 | 
				
			||||||
		virtual int64_t position() const = 0;
 | 
							virtual i64 position() const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// seeks the position of the stream
 | 
							// 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
 | 
							// returns true of the stream is open
 | 
				
			||||||
		virtual bool is_open() const = 0;
 | 
							virtual bool is_open() const = 0;
 | 
				
			||||||
@ -36,11 +36,11 @@ namespace Blah
 | 
				
			|||||||
		// closes the stream
 | 
							// closes the stream
 | 
				
			||||||
		virtual void close() = 0;
 | 
							virtual void close() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// pipes the contents of this tream to another stream
 | 
							// pipes the contents of this stream to another stream
 | 
				
			||||||
		int64_t pipe(Stream& to, int64_t length);
 | 
							i64 pipe(Stream& to, i64 length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// reads the amount of bytes into the given buffer, and returns the amount read
 | 
							// 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
 | 
							// reads a string. if length < 0, assumes null-terminated
 | 
				
			||||||
		String read_string(int length = -1);
 | 
							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
 | 
							// 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
 | 
							// writes the contents of a string to the stream
 | 
				
			||||||
		int64_t write(const String& string);
 | 
							i64 write(const String& string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// writes a number
 | 
							// writes a number
 | 
				
			||||||
		template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
 | 
							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);
 | 
								return write<T>(value, Endian::Little);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// writes a number
 | 
							// writes a number
 | 
				
			||||||
		template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
 | 
							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;
 | 
								T writing = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -93,9 +93,9 @@ namespace Blah
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	protected:
 | 
						protected:
 | 
				
			||||||
		// reads from the stream into the given buffer, and returns the number of bytes read
 | 
							// 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
 | 
							// 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();
 | 
								char* local = data();
 | 
				
			||||||
			m_buffer = new char[m_capacity];
 | 
								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';
 | 
								m_buffer[m_local_size] = '\0';
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// expand from empty buffer
 | 
							// expand from empty buffer
 | 
				
			||||||
@ -72,9 +72,9 @@ void Str::set_length(int len)
 | 
				
			|||||||
	m_length = 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++));
 | 
						int t = (unsigned char)(this->operator[](index++));
 | 
				
			||||||
	if (t < 128)
 | 
						if (t < 128)
 | 
				
			||||||
@ -124,7 +124,7 @@ Str& Str::append(char c)
 | 
				
			|||||||
	return *this;
 | 
						return *this;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Str& Str::append(uint32_t c)
 | 
					Str& Str::append(u32 c)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// one octet
 | 
						// one octet
 | 
				
			||||||
	if (c < 0x80)
 | 
						if (c < 0x80)
 | 
				
			||||||
@ -210,21 +210,21 @@ Str& Str::append_fmt(const char* fmt, ...)
 | 
				
			|||||||
	return *this;
 | 
						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
 | 
						// converts utf16 into utf8
 | 
				
			||||||
	// more info: https://en.wikipedia.org/wiki/UTF-16#Description
 | 
						// more info: https://en.wikipedia.org/wiki/UTF-16#Description
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const uint16_t surrogate_min = 0xd800u;
 | 
						const u16 surrogate_min = 0xd800u;
 | 
				
			||||||
	const uint16_t surrogate_max = 0xdbffu;
 | 
						const u16 surrogate_max = 0xdbffu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (start != end)
 | 
						while (start != end)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		uint16_t next = (*start++);
 | 
							u16 next = (*start++);
 | 
				
			||||||
		if (swap_endian)
 | 
							if (swap_endian)
 | 
				
			||||||
			next = ((next & 0xff) << 8 | ((next & 0xff00) >> 8));
 | 
								next = ((next & 0xff) << 8 | ((next & 0xff00) >> 8));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		uint32_t cp = 0xffff & next;
 | 
							u32 cp = 0xffff & next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((cp >= surrogate_min && cp <= surrogate_max))
 | 
							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)
 | 
								if (swap_endian)
 | 
				
			||||||
				next = ((next & 0xff) << 8 | ((next & 0xff00) >> 8));
 | 
									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;
 | 
								cp = (cp << 10) + trail + 0x10000u - (surrogate_min << 10) - 0xdc00u;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
#include <blah/core/app.h>
 | 
					#include <blah/core/app.h>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <blah/core/time.h>
 | 
					#include <blah/core/time.h>
 | 
				
			||||||
#include <blah/math/point.h>
 | 
					#include <blah/math/point.h>
 | 
				
			||||||
#include <blah/graphics/framebuffer.h>
 | 
					#include <blah/graphics/framebuffer.h>
 | 
				
			||||||
@ -35,8 +35,8 @@ namespace
 | 
				
			|||||||
	Config app_config;
 | 
						Config app_config;
 | 
				
			||||||
	bool app_is_running = false;
 | 
						bool app_is_running = false;
 | 
				
			||||||
	bool app_is_exiting = false;
 | 
						bool app_is_exiting = false;
 | 
				
			||||||
	uint64_t time_last;
 | 
						u64 time_last;
 | 
				
			||||||
	uint64_t time_accumulator = 0;
 | 
						u64 time_accumulator = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void app_iterate()
 | 
						void app_iterate()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -46,9 +46,9 @@ namespace
 | 
				
			|||||||
		// update at a fixed timerate
 | 
							// update at a fixed timerate
 | 
				
			||||||
		// TODO: allow a non-fixed step update?
 | 
							// TODO: allow a non-fixed step update?
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			uint64_t time_target = (uint64_t)((1.0 / app_config.target_framerate) * Time::ticks_per_second);
 | 
								u64 time_target = (u64)((1.0 / app_config.target_framerate) * Time::ticks_per_second);
 | 
				
			||||||
			uint64_t time_curr = PlatformBackend::ticks();
 | 
								u64 time_curr = PlatformBackend::ticks();
 | 
				
			||||||
			uint64_t time_diff = time_curr - time_last;
 | 
								u64 time_diff = time_curr - time_last;
 | 
				
			||||||
			time_last = time_curr;
 | 
								time_last = time_curr;
 | 
				
			||||||
			time_accumulator += time_diff;
 | 
								time_accumulator += time_diff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -66,7 +66,7 @@ namespace
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			// Do not allow us to fall behind too many updates
 | 
								// Do not allow us to fall behind too many updates
 | 
				
			||||||
			// (otherwise we'll get spiral of death)
 | 
								// (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)
 | 
								if (time_accumulator > time_maximum)
 | 
				
			||||||
				time_accumulator = time_maximum;
 | 
									time_accumulator = time_maximum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -300,7 +300,7 @@ namespace
 | 
				
			|||||||
			return App::draw_height();
 | 
								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);
 | 
								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 <blah/core/app.h>
 | 
				
			||||||
#include <stdarg.h> // for logging methods
 | 
					#include <stdarg.h> // for logging methods
 | 
				
			||||||
#include <stdio.h>  // for sprintf
 | 
					#include <stdio.h>  // for sprintf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace Blah;
 | 
					using namespace Blah;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Log::print(const char* format, ...)
 | 
					void Log::info(const char* format, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char msg[BLAH_MESSAGE];
 | 
						char msg[BLAH_MESSAGE];
 | 
				
			||||||
	va_list ap;
 | 
						va_list ap;
 | 
				
			||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
#include <blah/core/filesystem.h>
 | 
					#include <blah/core/filesystem.h>
 | 
				
			||||||
 | 
					#include <blah/streams/filestream.h>
 | 
				
			||||||
#include "../internal/platform_backend.h"
 | 
					#include "../internal/platform_backend.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace Blah;
 | 
					using namespace Blah;
 | 
				
			||||||
@ -13,6 +14,11 @@ bool File::remove(const FilePath& path)
 | 
				
			|||||||
	return PlatformBackend::file_delete(path.cstr());
 | 
						return PlatformBackend::file_delete(path.cstr());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FileStream File::open(const FilePath& path , FileMode mode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return FileStream(path, mode);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Directory::create(const FilePath& path)
 | 
					bool Directory::create(const FilePath& path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return PlatformBackend::dir_create(path.cstr());
 | 
						return PlatformBackend::dir_create(path.cstr());
 | 
				
			||||||
 | 
				
			|||||||
@ -10,8 +10,8 @@ namespace
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint64_t Time::ticks = 0;
 | 
					u64 Time::ticks = 0;
 | 
				
			||||||
uint64_t Time::previous_ticks = 0;
 | 
					u64 Time::previous_ticks = 0;
 | 
				
			||||||
double Time::seconds = 0;
 | 
					double Time::seconds = 0;
 | 
				
			||||||
double Time::previous_seconds = 0;
 | 
					double Time::previous_seconds = 0;
 | 
				
			||||||
float Time::delta = 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/texture.h>
 | 
				
			||||||
#include <blah/graphics/framebuffer.h>
 | 
					#include <blah/graphics/framebuffer.h>
 | 
				
			||||||
#include <blah/graphics/mesh.h>
 | 
					#include <blah/graphics/mesh.h>
 | 
				
			||||||
@ -15,9 +15,7 @@ namespace
 | 
				
			|||||||
	// TODO:
 | 
						// TODO:
 | 
				
			||||||
	// This shader needs to be graphics API agnostic
 | 
						// This shader needs to be graphics API agnostic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef BLAH_USE_OPENGL
 | 
						const ShaderData opengl_shader_data = {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	const ShaderData shader_data = {
 | 
					 | 
				
			||||||
		// vertex shader
 | 
							// vertex shader
 | 
				
			||||||
#ifdef __EMSCRIPTEN__
 | 
					#ifdef __EMSCRIPTEN__
 | 
				
			||||||
		"#version 300 es\n"
 | 
							"#version 300 es\n"
 | 
				
			||||||
@ -62,8 +60,6 @@ namespace
 | 
				
			|||||||
		"}"
 | 
							"}"
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#elif BLAH_USE_D3D11
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const char* d3d11_shader = ""
 | 
						const char* d3d11_shader = ""
 | 
				
			||||||
		"cbuffer constants : register(b0)\n"
 | 
							"cbuffer constants : register(b0)\n"
 | 
				
			||||||
		"{\n"
 | 
							"{\n"
 | 
				
			||||||
@ -110,7 +106,7 @@ namespace
 | 
				
			|||||||
		"		input.mask.z * input.color;\n"
 | 
							"		input.mask.z * input.color;\n"
 | 
				
			||||||
		"}\n";
 | 
							"}\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const ShaderData shader_data = {
 | 
						const ShaderData d3d11_shader_data = {
 | 
				
			||||||
		d3d11_shader,
 | 
							d3d11_shader,
 | 
				
			||||||
		d3d11_shader,
 | 
							d3d11_shader,
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@ -121,10 +117,6 @@ namespace
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
	const ShaderData shader_data;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const VertexFormat format = VertexFormat(
 | 
						const VertexFormat format = VertexFormat(
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			{ 0, VertexType::Float2, false },
 | 
								{ 0, VertexType::Float2, false },
 | 
				
			||||||
@ -164,12 +156,12 @@ namespace
 | 
				
			|||||||
	{ \
 | 
						{ \
 | 
				
			||||||
		m_batch.elements += 2; \
 | 
							m_batch.elements += 2; \
 | 
				
			||||||
		auto _i = m_indices.expand(6); \
 | 
							auto _i = m_indices.expand(6); \
 | 
				
			||||||
		*_i++ = (uint32_t)m_vertices.size() + 0; \
 | 
							*_i++ = (u32)m_vertices.size() + 0; \
 | 
				
			||||||
		*_i++ = (uint32_t)m_vertices.size() + 1; \
 | 
							*_i++ = (u32)m_vertices.size() + 1; \
 | 
				
			||||||
		*_i++ = (uint32_t)m_vertices.size() + 2; \
 | 
							*_i++ = (u32)m_vertices.size() + 2; \
 | 
				
			||||||
		*_i++ = (uint32_t)m_vertices.size() + 0; \
 | 
							*_i++ = (u32)m_vertices.size() + 0; \
 | 
				
			||||||
		*_i++ = (uint32_t)m_vertices.size() + 2; \
 | 
							*_i++ = (u32)m_vertices.size() + 2; \
 | 
				
			||||||
		*_i++ = (uint32_t)m_vertices.size() + 3; \
 | 
							*_i++ = (u32)m_vertices.size() + 3; \
 | 
				
			||||||
		Vertex* _v = m_vertices.expand(4); \
 | 
							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, px0, py0, tx0, ty0, col0, mult, fill, wash); _v++; \
 | 
				
			||||||
		MAKE_VERTEX(_v, m_matrix, px1, py1, tx1, ty1, col1, 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; \
 | 
							m_batch.elements += 1; \
 | 
				
			||||||
		auto* _i = m_indices.expand(3); \
 | 
							auto* _i = m_indices.expand(3); \
 | 
				
			||||||
		*_i++ = (uint32_t)m_vertices.size() + 0; \
 | 
							*_i++ = (u32)m_vertices.size() + 0; \
 | 
				
			||||||
		*_i++ = (uint32_t)m_vertices.size() + 1; \
 | 
							*_i++ = (u32)m_vertices.size() + 1; \
 | 
				
			||||||
		*_i++ = (uint32_t)m_vertices.size() + 2; \
 | 
							*_i++ = (u32)m_vertices.size() + 2; \
 | 
				
			||||||
		Vertex* _v = m_vertices.expand(3); \
 | 
							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, px0, py0, tx0, ty0, col0, mult, fill, wash); _v++; \
 | 
				
			||||||
		MAKE_VERTEX(_v, m_matrix, px1, py1, tx1, ty1, col1, 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();
 | 
								m_mesh = Mesh::create();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!m_default_shader)
 | 
							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)
 | 
							if (!m_default_material)
 | 
				
			||||||
			m_default_material = Material::create(m_default_shader);
 | 
								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.blend = b.blend;
 | 
				
			||||||
	pass.has_scissor = b.scissor.w >= 0 && b.scissor.h >= 0;
 | 
						pass.has_scissor = b.scissor.w >= 0 && b.scissor.h >= 0;
 | 
				
			||||||
	pass.scissor = b.scissor;
 | 
						pass.scissor = b.scissor;
 | 
				
			||||||
	pass.index_start = (int64_t)b.offset * 3;
 | 
						pass.index_start = (i64)b.offset * 3;
 | 
				
			||||||
	pass.index_count = (int64_t)b.elements * 3;
 | 
						pass.index_count = (i64)b.elements * 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pass.perform();
 | 
						pass.perform();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1046,7 +1043,7 @@ void Batch::str(const SpriteFont& font, const String& text, const Vec2& pos, Tex
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
		offset.y = (font.ascent + font.descent + font.height() - font.height_of(text)) * 0.5f;
 | 
							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++)
 | 
						for (int i = 0, l = text.length(); i < l; i++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (text[i] == '\n')
 | 
							if (text[i] == '\n')
 | 
				
			||||||
@ -1067,7 +1064,7 @@ void Batch::str(const SpriteFont& font, const String& text, const Vec2& pos, Tex
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// get the character
 | 
							// get the character
 | 
				
			||||||
		uint32_t next = text.utf8_at(i);
 | 
							u32 next = text.utf8_at(i);
 | 
				
			||||||
		const auto& ch = font[next];
 | 
							const auto& ch = font[next];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// draw it, if the subtexture exists
 | 
							// 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)
 | 
					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(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");
 | 
						BLAH_ASSERT(attachment_count > 0, "At least one attachment must be provided");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int color_count = 0;
 | 
						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(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);
 | 
						return GraphicsBackend::create_framebuffer(width, height, attachments, attachment_count);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
#include <blah/graphics/material.h>
 | 
					#include <blah/graphics/material.h>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <cstring>
 | 
					#include <cstring>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace Blah;
 | 
					using namespace Blah;
 | 
				
			||||||
@ -277,7 +277,7 @@ TextureSampler Material::get_sampler(int slot, int index) const
 | 
				
			|||||||
	return TextureSampler();
 | 
						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(m_shader, "Material Shader is invalid");
 | 
				
			||||||
	BLAH_ASSERT(length >= 0, "Length must be >= 0");
 | 
						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);
 | 
						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");
 | 
						BLAH_ASSERT(m_shader, "Material Shader is invalid");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -22,6 +22,7 @@ VertexFormat::VertexFormat(std::initializer_list<VertexAttribute> attributes, in
 | 
				
			|||||||
		{
 | 
							{
 | 
				
			||||||
			switch (it.type)
 | 
								switch (it.type)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
 | 
								case VertexType::None: break;
 | 
				
			||||||
			case VertexType::Float: stride += 4; break;
 | 
								case VertexType::Float: stride += 4; break;
 | 
				
			||||||
			case VertexType::Float2: stride += 8; break;
 | 
								case VertexType::Float2: stride += 8; break;
 | 
				
			||||||
			case VertexType::Float3: stride += 12; break;
 | 
								case VertexType::Float3: stride += 12; break;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
#include <blah/graphics/renderpass.h>
 | 
					#include <blah/graphics/renderpass.h>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include "../internal/graphics_backend.h"
 | 
					#include "../internal/graphics_backend.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace Blah;
 | 
					using namespace Blah;
 | 
				
			||||||
@ -38,7 +38,7 @@ void RenderPass::perform()
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Validate Index Count
 | 
						// 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)
 | 
						if (pass.index_start + pass.index_count > index_count)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Log::warn(
 | 
							Log::warn(
 | 
				
			||||||
@ -54,7 +54,7 @@ void RenderPass::perform()
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Validate Instance Count
 | 
						// Validate Instance Count
 | 
				
			||||||
	int64_t instance_count = pass.mesh->instance_count();
 | 
						i64 instance_count = pass.mesh->instance_count();
 | 
				
			||||||
	if (pass.instance_count > instance_count)
 | 
						if (pass.instance_count > instance_count)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Log::warn(
 | 
							Log::warn(
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,19 @@
 | 
				
			|||||||
#include <blah/drawing/spritefont.h>
 | 
					#include <blah/graphics/spritefont.h>
 | 
				
			||||||
#include <blah/images/font.h>
 | 
					#include <blah/images/font.h>
 | 
				
			||||||
#include <blah/images/packer.h>
 | 
					#include <blah/images/packer.h>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace Blah;
 | 
					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()
 | 
					SpriteFont::SpriteFont()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	size = 0;
 | 
						size = 0;
 | 
				
			||||||
@ -13,27 +22,24 @@ SpriteFont::SpriteFont()
 | 
				
			|||||||
	line_gap = 0;
 | 
						line_gap = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const uint32_t ascii[]{ 32, 128, 0 };
 | 
					SpriteFont::SpriteFont(const FilePath& file, float size)
 | 
				
			||||||
const uint32_t* SpriteFont::ASCII = ascii;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SpriteFont::SpriteFont(const char* 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)
 | 
					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
 | 
					SpriteFont::SpriteFont(SpriteFont&& src) noexcept
 | 
				
			||||||
@ -79,7 +85,7 @@ float SpriteFont::width_of(const String& text) const
 | 
				
			|||||||
	float width = 0;
 | 
						float width = 0;
 | 
				
			||||||
	float line_width = 0;
 | 
						float line_width = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t last;
 | 
						Codepoint last = 0;
 | 
				
			||||||
	for (int i = 0; i < text.length(); i ++)
 | 
						for (int i = 0; i < text.length(); i ++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (text[i] == '\n')
 | 
							if (text[i] == '\n')
 | 
				
			||||||
@ -116,7 +122,7 @@ float SpriteFont::width_of_line(const String& text, int start) const
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	float width = 0;
 | 
						float width = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t last;
 | 
						Codepoint last = 0;
 | 
				
			||||||
	for (int i = start; i < text.length(); i ++)
 | 
						for (int i = start; i < text.length(); i ++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (text[i] == '\n')
 | 
							if (text[i] == '\n')
 | 
				
			||||||
@ -157,16 +163,16 @@ float SpriteFont::height_of(const String& text) const
 | 
				
			|||||||
	return height - line_gap;
 | 
						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();
 | 
						dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Font font(file);
 | 
						Font font(file);
 | 
				
			||||||
	if (font.is_valid())
 | 
						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();
 | 
						dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -184,14 +190,13 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset)
 | 
				
			|||||||
	packer.max_size = 8192;
 | 
						packer.max_size = 8192;
 | 
				
			||||||
	packer.power_of_two = true;
 | 
						packer.power_of_two = true;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	std::unordered_map<uint32_t, int> glyphs;
 | 
						std::unordered_map<Codepoint, int> glyphs;
 | 
				
			||||||
	Vector<Color> buffer;
 | 
						Vector<Color> buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto ranges = charset;
 | 
						for (auto& range : charset)
 | 
				
			||||||
	while (*ranges != 0)
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		auto from = *ranges;
 | 
							auto from = range.from;
 | 
				
			||||||
		auto to = *(ranges + 1);
 | 
							auto to = range.to + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		BLAH_ASSERT(to >= from, "Charset Range must be in pairs of [min,max]");
 | 
							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;
 | 
								glyphs[i] = glyph;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// add character
 | 
								// 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].advance = ch.advance;
 | 
				
			||||||
			m_characters[i].offset = Vec2(ch.offset_x, ch.offset_y);
 | 
								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());
 | 
										packer.add(i, ch.width, ch.height, buffer.data());
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		ranges += 2;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buffer.clear();
 | 
						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));
 | 
							m_atlas.push_back(Texture::create(it));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// add character subtextures
 | 
						// add character subtextures
 | 
				
			||||||
	for (auto& it : packer.entries)
 | 
						for (auto& it : packer.entries())
 | 
				
			||||||
		if (!it.empty)
 | 
							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
 | 
						// add kerning
 | 
				
			||||||
	for (auto a = glyphs.begin(); a != glyphs.end(); a++)
 | 
						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);
 | 
						auto it = m_kerning.find(index);
 | 
				
			||||||
	if (it != m_kerning.end())
 | 
						if (it != m_kerning.end())
 | 
				
			||||||
@ -253,9 +256,9 @@ float SpriteFont::get_kerning(uint32_t codepoint0, uint32_t codepoint1) const
 | 
				
			|||||||
	return 0.0f;
 | 
						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)
 | 
						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;
 | 
						static const Character empty;
 | 
				
			||||||
	auto it = m_characters.find(codepoint);
 | 
						auto it = m_characters.find(codepoint);
 | 
				
			||||||
@ -276,7 +284,12 @@ const SpriteFont::Character& SpriteFont::get_character(uint32_t codepoint) const
 | 
				
			|||||||
	return empty;
 | 
						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;
 | 
						static const Character empty;
 | 
				
			||||||
	auto it = m_characters.find(codepoint);
 | 
						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>
 | 
					#include <blah/math/calc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace Blah;
 | 
					using namespace Blah;
 | 
				
			||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
#include <blah/graphics/texture.h>
 | 
					#include <blah/graphics/texture.h>
 | 
				
			||||||
#include <blah/images/image.h>
 | 
					#include <blah/images/image.h>
 | 
				
			||||||
#include <blah/streams/stream.h>
 | 
					#include <blah/streams/stream.h>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include "../internal/graphics_backend.h"
 | 
					#include "../internal/graphics_backend.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace Blah;
 | 
					using namespace Blah;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,17 +1,13 @@
 | 
				
			|||||||
#include <blah/images/aseprite.h>
 | 
					#include <blah/images/aseprite.h>
 | 
				
			||||||
#include <blah/streams/filestream.h>
 | 
					#include <blah/streams/filestream.h>
 | 
				
			||||||
#include <blah/core/filesystem.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_NO_STDIO
 | 
				
			||||||
#define STBI_ONLY_ZLIB
 | 
					#define STBI_ONLY_ZLIB
 | 
				
			||||||
#include "../third_party/stb_image.h"
 | 
					#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;
 | 
					using namespace Blah;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Aseprite::Aseprite()
 | 
					Aseprite::Aseprite()
 | 
				
			||||||
@ -19,7 +15,7 @@ Aseprite::Aseprite()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Aseprite::Aseprite(const char* path)
 | 
					Aseprite::Aseprite(const FilePath& path)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	FileStream fs(path, FileMode::Read);
 | 
						FileStream fs(path, FileMode::Read);
 | 
				
			||||||
	parse(fs);
 | 
						parse(fs);
 | 
				
			||||||
@ -98,10 +94,10 @@ void Aseprite::parse(Stream& stream)
 | 
				
			|||||||
	// header
 | 
						// header
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// filesize
 | 
							// filesize
 | 
				
			||||||
		stream.read<uint32_t>(Endian::Little);
 | 
							stream.read<u32>(Endian::Little);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// magic number
 | 
							// magic number
 | 
				
			||||||
		auto magic = stream.read<uint16_t>(Endian::Little);
 | 
							auto magic = stream.read<u16>(Endian::Little);
 | 
				
			||||||
		if (magic != 0xA5E0)
 | 
							if (magic != 0xA5E0)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			BLAH_ERROR("File is not a valid Aseprite file");
 | 
								BLAH_ERROR("File is not a valid Aseprite file");
 | 
				
			||||||
@ -109,21 +105,21 @@ void Aseprite::parse(Stream& stream)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// main info
 | 
							// main info
 | 
				
			||||||
		frame_count = stream.read<uint16_t>(Endian::Little);
 | 
							frame_count = stream.read<u16>(Endian::Little);
 | 
				
			||||||
		width = stream.read<uint16_t>(Endian::Little);
 | 
							width = stream.read<u16>(Endian::Little);
 | 
				
			||||||
		height = stream.read<uint16_t>(Endian::Little);
 | 
							height = stream.read<u16>(Endian::Little);
 | 
				
			||||||
		mode = static_cast<Aseprite::Modes>(stream.read<uint16_t>(Endian::Little) / 8);
 | 
							mode = static_cast<Aseprite::Modes>(stream.read<u16>(Endian::Little) / 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// don't care about other info
 | 
							// don't care about other info
 | 
				
			||||||
		stream.read<uint32_t>(Endian::Little);		// Flags
 | 
							stream.read<u32>(Endian::Little);		// Flags
 | 
				
			||||||
		stream.read<uint16_t>(Endian::Little);		// Speed (deprecated)
 | 
							stream.read<u16>(Endian::Little);		// Speed (deprecated)
 | 
				
			||||||
		stream.read<uint32_t>(Endian::Little);		// Should be 0
 | 
							stream.read<u32>(Endian::Little);		// Should be 0
 | 
				
			||||||
		stream.read<uint32_t>(Endian::Little);		// Should be 0
 | 
							stream.read<u32>(Endian::Little);		// Should be 0
 | 
				
			||||||
		stream.read<uint8_t>(Endian::Little);		// Palette entry
 | 
							stream.read<u8>(Endian::Little);		// Palette entry
 | 
				
			||||||
		stream.seek(stream.position() + 3);			// Ignore these bytes
 | 
							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<u16>(Endian::Little);		// Number of colors (0 means 256 for old sprites)
 | 
				
			||||||
		stream.read<int8_t>(Endian::Little);		// Pixel width
 | 
							stream.read<i8>(Endian::Little);		// Pixel width
 | 
				
			||||||
		stream.read<int8_t>(Endian::Little);		// Pixel height
 | 
							stream.read<i8>(Endian::Little);		// Pixel height
 | 
				
			||||||
		stream.seek(stream.position() + 92);		// For Future
 | 
							stream.seek(stream.position() + 92);		// For Future
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -133,22 +129,22 @@ void Aseprite::parse(Stream& stream)
 | 
				
			|||||||
	for (int i = 0; i < frame_count; i++)
 | 
						for (int i = 0; i < frame_count; i++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		auto frameStart = stream.position();
 | 
							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;
 | 
							unsigned int chunks = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// frame header
 | 
							// frame header
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			auto magic = stream.read<uint16_t>(Endian::Little); // magic number
 | 
								auto magic = stream.read<u16>(Endian::Little); // magic number
 | 
				
			||||||
			if (magic != 0xF1FA)
 | 
								if (magic != 0xF1FA)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				BLAH_ERROR("File is not a valid Aseprite file");
 | 
									BLAH_ERROR("File is not a valid Aseprite file");
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			auto old_chunk_count = stream.read<uint16_t>(Endian::Little);
 | 
								auto old_chunk_count = stream.read<u16>(Endian::Little);
 | 
				
			||||||
			frames[i].duration = stream.read<uint16_t>(Endian::Little);
 | 
								frames[i].duration = stream.read<u16>(Endian::Little);
 | 
				
			||||||
			stream.seek(stream.position() + 2); // for future
 | 
								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)
 | 
								if (old_chunk_count == 0xFFFF)
 | 
				
			||||||
				chunks = new_chunk_count;
 | 
									chunks = new_chunk_count;
 | 
				
			||||||
@ -163,8 +159,8 @@ void Aseprite::parse(Stream& stream)
 | 
				
			|||||||
		for (unsigned int j = 0; j < chunks; j++)
 | 
							for (unsigned int j = 0; j < chunks; j++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			auto chunkStart = stream.position();
 | 
								auto chunkStart = stream.position();
 | 
				
			||||||
			auto chunkEnd = chunkStart + stream.read<uint32_t>(Endian::Little);
 | 
								auto chunkEnd = chunkStart + stream.read<u32>(Endian::Little);
 | 
				
			||||||
			auto chunkType = static_cast<Chunks>(stream.read<uint16_t>(Endian::Little));
 | 
								auto chunkType = static_cast<Chunks>(stream.read<u16>(Endian::Little));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			switch (chunkType)
 | 
								switch (chunkType)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
@ -189,17 +185,17 @@ void Aseprite::parse_layer(Stream& stream, int frame)
 | 
				
			|||||||
	layers.emplace_back();
 | 
						layers.emplace_back();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto& layer = layers.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.visible = ((int)layer.flag & (int)LayerFlags::Visible) == (int)LayerFlags::Visible;
 | 
				
			||||||
	layer.type = static_cast<LayerTypes>(stream.read<uint16_t>(Endian::Little));
 | 
						layer.type = static_cast<LayerTypes>(stream.read<u16>(Endian::Little));
 | 
				
			||||||
	layer.child_level = stream.read<uint16_t>(Endian::Little);
 | 
						layer.child_level = stream.read<u16>(Endian::Little);
 | 
				
			||||||
	stream.read<uint16_t>(Endian::Little); // width
 | 
						stream.read<u16>(Endian::Little); // width
 | 
				
			||||||
	stream.read<uint16_t>(Endian::Little); // height
 | 
						stream.read<u16>(Endian::Little); // height
 | 
				
			||||||
	layer.blendmode = stream.read<uint16_t>(Endian::Little);
 | 
						layer.blendmode = stream.read<u16>(Endian::Little);
 | 
				
			||||||
	layer.alpha = stream.read<uint8_t>(Endian::Little);
 | 
						layer.alpha = stream.read<u8>(Endian::Little);
 | 
				
			||||||
	stream.seek(stream.position() + 3); // for future
 | 
						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());
 | 
						stream.read(layer.name.cstr(), layer.name.length());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	layer.userdata.color = 0xffffff;
 | 
						layer.userdata.color = 0xffffff;
 | 
				
			||||||
@ -213,20 +209,20 @@ void Aseprite::parse_cel(Stream& stream, int frameIndex, size_t maxPosition)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	frame.cels.emplace_back();
 | 
						frame.cels.emplace_back();
 | 
				
			||||||
	auto& cel = frame.cels.back();
 | 
						auto& cel = frame.cels.back();
 | 
				
			||||||
	cel.layer_index = stream.read<uint16_t>(Endian::Little);
 | 
						cel.layer_index = stream.read<u16>(Endian::Little);
 | 
				
			||||||
	cel.x = stream.read<uint16_t>(Endian::Little);
 | 
						cel.x = stream.read<u16>(Endian::Little);
 | 
				
			||||||
	cel.y = stream.read<uint16_t>(Endian::Little);
 | 
						cel.y = stream.read<u16>(Endian::Little);
 | 
				
			||||||
	cel.alpha = stream.read<uint8_t>(Endian::Little);
 | 
						cel.alpha = stream.read<u8>(Endian::Little);
 | 
				
			||||||
	cel.linked_frame_index = -1;
 | 
						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);
 | 
						stream.seek(stream.position() + 7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// RAW or DEFLATE
 | 
						// RAW or DEFLATE
 | 
				
			||||||
	if (celType == 0 || celType == 2)
 | 
						if (celType == 0 || celType == 2)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		auto width = stream.read<uint16_t>(Endian::Little);
 | 
							auto width = stream.read<u16>(Endian::Little);
 | 
				
			||||||
		auto height = stream.read<uint16_t>(Endian::Little);
 | 
							auto height = stream.read<u16>(Endian::Little);
 | 
				
			||||||
		auto count = width * height * (int)mode;
 | 
							auto count = width * height * (int)mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cel.image = Image(width, height);
 | 
							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
 | 
						// this cel directly references a previous cel
 | 
				
			||||||
	else if (celType == 1)
 | 
						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
 | 
						// 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)
 | 
					void Aseprite::parse_palette(Stream& stream, int frame)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* size */ stream.read<uint32_t>(Endian::Little);
 | 
						/* size */ stream.read<u32>(Endian::Little);
 | 
				
			||||||
	auto start = stream.read<uint32_t>(Endian::Little);
 | 
						auto start = stream.read<u32>(Endian::Little);
 | 
				
			||||||
	auto end = stream.read<uint32_t>(Endian::Little);
 | 
						auto end = stream.read<u32>(Endian::Little);
 | 
				
			||||||
	stream.seek(stream.position() + 8);
 | 
						stream.seek(stream.position() + 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	palette.resize(palette.size() + (end - start + 1));
 | 
						palette.resize(palette.size() + (end - start + 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int p = 0, len = static_cast<int>(end - start) + 1; p < len; p++)
 | 
						for (int p = 0, len = static_cast<int>(end - start) + 1; p < len; p++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		auto hasName = stream.read<uint16_t>(Endian::Little);
 | 
							auto hasName = stream.read<u16>(Endian::Little);
 | 
				
			||||||
		palette[start + p] = stream.read<uint32_t>(Endian::Little);
 | 
							palette[start + p] = stream.read<u32>(Endian::Little);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (hasName & 0xF000)
 | 
							if (hasName & 0xF000)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			int len = stream.read<uint16_t>(Endian::Little);
 | 
								int len = stream.read<u16>(Endian::Little);
 | 
				
			||||||
			stream.seek(stream.position() + len);
 | 
								stream.seek(stream.position() + len);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -322,38 +318,38 @@ void Aseprite::parse_user_data(Stream& stream, int frame)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (m_last_userdata != nullptr)
 | 
						if (m_last_userdata != nullptr)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		auto flags = stream.read<uint32_t>(Endian::Little);
 | 
							auto flags = stream.read<u32>(Endian::Little);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// has text
 | 
							// has text
 | 
				
			||||||
		if (flags & (1 << 0))
 | 
							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());
 | 
								stream.read(m_last_userdata->text.cstr(), m_last_userdata->text.length());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// has color
 | 
							// has color
 | 
				
			||||||
		if (flags & (1 << 1))
 | 
							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)
 | 
					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);
 | 
						stream.seek(stream.position() + 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int t = 0; t < count; t++)
 | 
						for (int t = 0; t < count; t++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Tag tag;
 | 
							Tag tag;
 | 
				
			||||||
		tag.from = stream.read<uint16_t>(Endian::Little);
 | 
							tag.from = stream.read<u16>(Endian::Little);
 | 
				
			||||||
		tag.to = stream.read<uint16_t>(Endian::Little);
 | 
							tag.to = stream.read<u16>(Endian::Little);
 | 
				
			||||||
		tag.loops = static_cast<LoopDirections>(stream.read<int8_t>(Endian::Little));
 | 
							tag.loops = static_cast<LoopDirections>(stream.read<i8>(Endian::Little));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		stream.seek(stream.position() + 8);
 | 
							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);
 | 
							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());
 | 
							stream.read(tag.name.cstr(), tag.name.length());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		tags.push_back(tag);
 | 
							tags.push_back(tag);
 | 
				
			||||||
@ -362,12 +358,12 @@ void Aseprite::parse_tag(Stream& stream, int frame)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void Aseprite::parse_slice(Stream& stream, int frame)
 | 
					void Aseprite::parse_slice(Stream& stream, int frame)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int count = stream.read<uint32_t>(Endian::Little);
 | 
						int count = stream.read<u32>(Endian::Little);
 | 
				
			||||||
	int flags = stream.read<uint32_t>(Endian::Little);
 | 
						int flags = stream.read<u32>(Endian::Little);
 | 
				
			||||||
	stream.read<uint32_t>(Endian::Little); // reserved
 | 
						stream.read<u32>(Endian::Little); // reserved
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	String name;
 | 
						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());
 | 
						stream.read(name.cstr(), name.length());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int s = 0; s < count; s++)
 | 
						for (int s = 0; s < count; s++)
 | 
				
			||||||
@ -376,19 +372,19 @@ void Aseprite::parse_slice(Stream& stream, int frame)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		auto& slice = slices.back();
 | 
							auto& slice = slices.back();
 | 
				
			||||||
		slice.name = name;
 | 
							slice.name = name;
 | 
				
			||||||
		slice.frame = stream.read<uint32_t>(Endian::Little);
 | 
							slice.frame = stream.read<u32>(Endian::Little);
 | 
				
			||||||
		slice.origin.x = stream.read<int32_t>(Endian::Little);
 | 
							slice.origin.x = stream.read<i32>(Endian::Little);
 | 
				
			||||||
		slice.origin.y = stream.read<int32_t>(Endian::Little);
 | 
							slice.origin.y = stream.read<i32>(Endian::Little);
 | 
				
			||||||
		slice.width = stream.read<uint32_t>(Endian::Little);
 | 
							slice.width = stream.read<u32>(Endian::Little);
 | 
				
			||||||
		slice.height = stream.read<uint32_t>(Endian::Little);
 | 
							slice.height = stream.read<u32>(Endian::Little);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// 9 slice (ignored atm)
 | 
							// 9 slice (ignored atm)
 | 
				
			||||||
		if (flags & (1 << 0))
 | 
							if (flags & (1 << 0))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			stream.read<int32_t>(Endian::Little);
 | 
								stream.read<i32>(Endian::Little);
 | 
				
			||||||
			stream.read<int32_t>(Endian::Little);
 | 
								stream.read<i32>(Endian::Little);
 | 
				
			||||||
			stream.read<uint32_t>(Endian::Little);
 | 
								stream.read<u32>(Endian::Little);
 | 
				
			||||||
			stream.read<uint32_t>(Endian::Little);
 | 
								stream.read<u32>(Endian::Little);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// pivot point
 | 
							// pivot point
 | 
				
			||||||
@ -396,8 +392,8 @@ void Aseprite::parse_slice(Stream& stream, int frame)
 | 
				
			|||||||
		if (flags & (1 << 1))
 | 
							if (flags & (1 << 1))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			slice.has_pivot = true;
 | 
								slice.has_pivot = true;
 | 
				
			||||||
			slice.pivot.x = stream.read<uint32_t>(Endian::Little);
 | 
								slice.pivot.x = stream.read<u32>(Endian::Little);
 | 
				
			||||||
			slice.pivot.y = stream.read<uint32_t>(Endian::Little);
 | 
								slice.pivot.y = stream.read<u32>(Endian::Little);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		slice.userdata.color = 0xffffff;
 | 
							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)
 | 
					void Aseprite::render_cel(Cel* cel, Frame* frame)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Layer& layer = layers[cel->layer_index];
 | 
						Layer& layer = layers[cel->layer_index];
 | 
				
			||||||
@ -436,16 +435,16 @@ void Aseprite::render_cel(Cel* cel, Frame* frame)
 | 
				
			|||||||
	auto dstH = frame->image.height;
 | 
						auto dstH = frame->image.height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// blit pixels
 | 
						// blit pixels
 | 
				
			||||||
	int left = MAX(0, srcX);
 | 
						int left = Calc::max(0, srcX);
 | 
				
			||||||
	int right = MIN(dstW, srcX + srcW);
 | 
						int right = Calc::min(dstW, srcX + srcW);
 | 
				
			||||||
	int top = MAX(0, srcY);
 | 
						int top = Calc::max(0, srcY);
 | 
				
			||||||
	int bottom = MIN(dstH, srcY + srcH);
 | 
						int bottom = Calc::min(dstH, srcY + srcH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (layer.blendmode == 0)
 | 
						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* srcColor = (src + sx + sy * srcW);
 | 
				
			||||||
				Color* dstColor = (dst + dx + dy * dstW);
 | 
									Color* dstColor = (dst + dx + dy * dstW);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,20 +1,31 @@
 | 
				
			|||||||
#include <blah/images/font.h>
 | 
					#include <blah/images/font.h>
 | 
				
			||||||
#include <blah/streams/filestream.h>
 | 
					#include <blah/streams/filestream.h>
 | 
				
			||||||
#include <blah/math/calc.h>
 | 
					#include <blah/math/calc.h>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace Blah;
 | 
					using namespace Blah;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __CLANG__
 | 
				
			||||||
 | 
					#pragma clang diagnostic push
 | 
				
			||||||
 | 
					#pragma clang diagnostic ignored "-Wunused-function"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define STBTT_STATIC
 | 
					#define STBTT_STATIC
 | 
				
			||||||
#define STB_TRUETYPE_IMPLEMENTATION
 | 
					#define STB_TRUETYPE_IMPLEMENTATION
 | 
				
			||||||
#include "../third_party/stb_truetype.h"
 | 
					#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;
 | 
							int length = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// get the name
 | 
							// 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_PLATFORM_ID_MICROSOFT,
 | 
				
			||||||
			STBTT_MS_EID_UNICODE_BMP,
 | 
								STBTT_MS_EID_UNICODE_BMP,
 | 
				
			||||||
			STBTT_MS_LANG_ENGLISH,
 | 
								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());
 | 
								str.append_utf16(ptr, ptr + length, Calc::is_little_endian());
 | 
				
			||||||
		return str;
 | 
							return str;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Font::Font()
 | 
					Font::Font()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -44,7 +56,7 @@ Font::Font(Stream& stream) : Font()
 | 
				
			|||||||
	load(stream);
 | 
						load(stream);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Font::Font(const char* path) : Font()
 | 
					Font::Font(const FilePath& path) : Font()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	FileStream fs(path, FileMode::Read);
 | 
						FileStream fs(path, FileMode::Read);
 | 
				
			||||||
	if (fs.is_readable())
 | 
						if (fs.is_readable())
 | 
				
			||||||
@ -112,8 +124,8 @@ void Font::load(Stream& stream)
 | 
				
			|||||||
	m_font = new stbtt_fontinfo();
 | 
						m_font = new stbtt_fontinfo();
 | 
				
			||||||
	auto fn = (stbtt_fontinfo*)m_font;
 | 
						auto fn = (stbtt_fontinfo*)m_font;
 | 
				
			||||||
	stbtt_InitFont(fn, m_data, 0);
 | 
						stbtt_InitFont(fn, m_data, 0);
 | 
				
			||||||
	m_family_name = GetName(fn, 1);
 | 
						m_family_name = get_font_name(fn, 1);
 | 
				
			||||||
	m_style_name = GetName(fn, 2);
 | 
						m_style_name = get_font_name(fn, 2);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	// properties
 | 
						// properties
 | 
				
			||||||
	stbtt_GetFontVMetrics(fn, &m_ascent, &m_descent, &m_line_gap);
 | 
						stbtt_GetFontVMetrics(fn, &m_ascent, &m_descent, &m_line_gap);
 | 
				
			||||||
@ -130,14 +142,14 @@ void Font::dispose()
 | 
				
			|||||||
	m_style_name.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
 | 
					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;
 | 
						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)
 | 
						if (!m_font)
 | 
				
			||||||
		return ch;
 | 
							return ch;
 | 
				
			||||||
@ -215,7 +227,7 @@ Font::Char Font::get_character(int glyph, float scale) const
 | 
				
			|||||||
	return ch;
 | 
						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)
 | 
						if (ch.has_glyph)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -239,6 +251,16 @@ bool Font::get_image(const Font::Char& ch, Color* pixels) const
 | 
				
			|||||||
	return false;
 | 
						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
 | 
					bool Font::is_valid() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return m_valid;
 | 
						return m_valid;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,14 +1,13 @@
 | 
				
			|||||||
#include <blah/images/image.h>
 | 
					#include <blah/images/image.h>
 | 
				
			||||||
#include <blah/streams/stream.h>
 | 
					#include <blah/streams/stream.h>
 | 
				
			||||||
#include <blah/streams/filestream.h>
 | 
					#include <blah/streams/filestream.h>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace Blah;
 | 
					using namespace Blah;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define STB_IMAGE_IMPLEMENTATION
 | 
					#define STB_IMAGE_IMPLEMENTATION
 | 
				
			||||||
#define STBI_ONLY_JPEG
 | 
					#define STBI_ONLY_JPEG
 | 
				
			||||||
#define STBI_ONLY_PNG
 | 
					#define STBI_ONLY_PNG
 | 
				
			||||||
#define STBI_ONLY_BMP
 | 
					 | 
				
			||||||
#include "../third_party/stb_image.h"
 | 
					#include "../third_party/stb_image.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
 | 
					#define STB_IMAGE_WRITE_IMPLEMENTATION
 | 
				
			||||||
@ -18,7 +17,7 @@ namespace
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	int Blah_STBI_Read(void* user, char* data, int size)
 | 
						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;
 | 
							return (int)read;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -29,8 +28,8 @@ namespace
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	int Blah_STBI_Eof(void* user)
 | 
						int Blah_STBI_Eof(void* user)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int64_t position = ((Stream*)user)->position();
 | 
							i64 position = ((Stream*)user)->position();
 | 
				
			||||||
		int64_t length = ((Stream*)user)->length();
 | 
							i64 length = ((Stream*)user)->length();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (position >= length)
 | 
							if (position >= length)
 | 
				
			||||||
			return 1;
 | 
								return 1;
 | 
				
			||||||
@ -59,7 +58,7 @@ Image::Image(Stream& stream)
 | 
				
			|||||||
	from_stream(stream);
 | 
						from_stream(stream);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Image::Image(const char* file)
 | 
					Image::Image(const FilePath& file)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	width = height = 0;
 | 
						width = height = 0;
 | 
				
			||||||
	pixels = nullptr;
 | 
						pixels = nullptr;
 | 
				
			||||||
@ -155,7 +154,7 @@ void Image::from_stream(Stream& stream)
 | 
				
			|||||||
	callbacks.skip = Blah_STBI_Skip;
 | 
						callbacks.skip = Blah_STBI_Skip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int x, y, comps;
 | 
						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)
 | 
						if (data == nullptr)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -175,6 +174,7 @@ void Image::dispose()
 | 
				
			|||||||
		stbi_image_free(pixels);
 | 
							stbi_image_free(pixels);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		delete[] pixels;
 | 
							delete[] pixels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pixels = nullptr;
 | 
						pixels = nullptr;
 | 
				
			||||||
	width = height = 0;
 | 
						width = height = 0;
 | 
				
			||||||
	m_stbi_ownership = false;
 | 
						m_stbi_ownership = false;
 | 
				
			||||||
@ -186,9 +186,9 @@ void Image::premultiply()
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		for (int n = 0; n < width * height; n ++)
 | 
							for (int n = 0; n < width * height; n ++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			pixels[n].r = (uint8_t)(pixels[n].r * pixels[n].a / 255);
 | 
								pixels[n].r = (u8)(pixels[n].r * pixels[n].a / 255);
 | 
				
			||||||
			pixels[n].g = (uint8_t)(pixels[n].g * pixels[n].a / 255);
 | 
								pixels[n].g = (u8)(pixels[n].g * pixels[n].a / 255);
 | 
				
			||||||
			pixels[n].b = (uint8_t)(pixels[n].b * 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);
 | 
						FileStream fs(file, FileMode::Write);
 | 
				
			||||||
	return save_png(fs);
 | 
						return save_png(fs);
 | 
				
			||||||
@ -232,7 +232,7 @@ bool Image::save_png(Stream& stream) const
 | 
				
			|||||||
	return false;
 | 
						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);
 | 
						FileStream fs(file, FileMode::Write);
 | 
				
			||||||
	return save_jpg(fs, quality);
 | 
						return save_jpg(fs, quality);
 | 
				
			||||||
@ -269,33 +269,31 @@ bool Image::save_jpg(Stream& stream, int quality) const
 | 
				
			|||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Image::get_pixels(Color* dest, const Point& dest_pos, const Point& dest_size, RectI source_rect)
 | 
				
			||||||
 | 
					 | 
				
			||||||
void Image::get_pixels(Color* dest, const Point& destPos, const Point& destSize, RectI sourceRect)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// can't be outside of the source image
 | 
						// can't be outside of the source image
 | 
				
			||||||
	if (sourceRect.x < 0) sourceRect.x = 0;
 | 
						if (source_rect.x < 0) source_rect.x = 0;
 | 
				
			||||||
	if (sourceRect.y < 0) sourceRect.y = 0;
 | 
						if (source_rect.y < 0) source_rect.y = 0;
 | 
				
			||||||
	if (sourceRect.x + sourceRect.w > width) sourceRect.w = width - sourceRect.x;
 | 
						if (source_rect.x + source_rect.w > width) source_rect.w = width - source_rect.x;
 | 
				
			||||||
	if (sourceRect.y + sourceRect.h > height) sourceRect.h = height - sourceRect.y;
 | 
						if (source_rect.y + source_rect.h > height) source_rect.h = height - source_rect.y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// can't be larger than our destination
 | 
						// can't be larger than our destination
 | 
				
			||||||
	if (sourceRect.w > destSize.x - destPos.x)
 | 
						if (source_rect.w > dest_size.x - dest_pos.x)
 | 
				
			||||||
		sourceRect.w = destSize.x - destPos.x;
 | 
							source_rect.w = dest_size.x - dest_pos.x;
 | 
				
			||||||
	if (sourceRect.h > destSize.y - destPos.y)
 | 
						if (source_rect.h > dest_size.y - dest_pos.y)
 | 
				
			||||||
		sourceRect.h = destSize.y - destPos.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 to = dest_pos.x + (dest_pos.y + y) * dest_size.x;
 | 
				
			||||||
		int from = sourceRect.x + (sourceRect.y + y) * width;
 | 
							int from = source_rect.x + (source_rect.y + y) * width;
 | 
				
			||||||
		memcpy(dest + to, pixels + from, sizeof(Color) * (int)sourceRect.w);
 | 
							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);
 | 
						Image img(source_rect.w, source_rect.h);
 | 
				
			||||||
	get_pixels(img.pixels, Point::zero, Point(img.width, img.height), sourceRect);
 | 
						get_pixels(img.pixels, Point::zero, Point(img.width, img.height), source_rect);
 | 
				
			||||||
	return img;
 | 
						return img;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
#include <blah/images/packer.h>
 | 
					#include <blah/images/packer.h>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <cstring>
 | 
					#include <cstring>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -19,7 +19,7 @@ Packer::Packer(Packer&& src) noexcept
 | 
				
			|||||||
	padding = src.padding;
 | 
						padding = src.padding;
 | 
				
			||||||
	m_dirty = src.m_dirty;
 | 
						m_dirty = src.m_dirty;
 | 
				
			||||||
	pages = std::move(src.pages);
 | 
						pages = std::move(src.pages);
 | 
				
			||||||
	entries = std::move(src.entries);
 | 
						m_entries = std::move(src.m_entries);
 | 
				
			||||||
	m_buffer = std::move(src.m_buffer);
 | 
						m_buffer = std::move(src.m_buffer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -31,7 +31,7 @@ Packer& Packer::operator=(Packer&& src) noexcept
 | 
				
			|||||||
	padding = src.padding;
 | 
						padding = src.padding;
 | 
				
			||||||
	m_dirty = src.m_dirty;
 | 
						m_dirty = src.m_dirty;
 | 
				
			||||||
	pages = std::move(src.pages);
 | 
						pages = std::move(src.pages);
 | 
				
			||||||
	entries = std::move(src.entries);
 | 
						m_entries = std::move(src.m_entries);
 | 
				
			||||||
	m_buffer = std::move(src.m_buffer);
 | 
						m_buffer = std::move(src.m_buffer);
 | 
				
			||||||
	return *this;
 | 
						return *this;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -41,22 +41,22 @@ Packer::~Packer()
 | 
				
			|||||||
	dispose();
 | 
						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);
 | 
						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);
 | 
						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()));
 | 
						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;
 | 
						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()
 | 
					void Packer::pack()
 | 
				
			||||||
@ -137,7 +142,7 @@ void Packer::pack()
 | 
				
			|||||||
	pages.clear();
 | 
						pages.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// only if we have stuff to pack
 | 
						// only if we have stuff to pack
 | 
				
			||||||
	auto count = entries.size();
 | 
						auto count = m_entries.size();
 | 
				
			||||||
	if (count > 0)
 | 
						if (count > 0)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// get all the sources sorted largest -> smallest
 | 
							// get all the sources sorted largest -> smallest
 | 
				
			||||||
@ -146,8 +151,8 @@ void Packer::pack()
 | 
				
			|||||||
			sources.resize(count);
 | 
								sources.resize(count);
 | 
				
			||||||
			int index = 0;
 | 
								int index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (int i = 0; i < entries.size(); i++)
 | 
								for (int i = 0; i < m_entries.size(); i++)
 | 
				
			||||||
				sources[index++] = &entries[i];
 | 
									sources[index++] = &m_entries[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			std::sort(sources.begin(), sources.end(), [](Packer::Entry* a, Packer::Entry* b)
 | 
								std::sort(sources.begin(), sources.end(), [](Packer::Entry* a, Packer::Entry* b)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
@ -292,14 +297,14 @@ void Packer::pack()
 | 
				
			|||||||
void Packer::clear()
 | 
					void Packer::clear()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pages.clear();
 | 
						pages.clear();
 | 
				
			||||||
	entries.clear();
 | 
						m_entries.clear();
 | 
				
			||||||
	m_dirty = false;
 | 
						m_dirty = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Packer::dispose()
 | 
					void Packer::dispose()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pages.clear();
 | 
						pages.clear();
 | 
				
			||||||
	entries.clear();
 | 
						m_entries.clear();
 | 
				
			||||||
	m_buffer.close();
 | 
						m_buffer.close();
 | 
				
			||||||
	max_size = 0;
 | 
						max_size = 0;
 | 
				
			||||||
	power_of_two = 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/input.h>
 | 
				
			||||||
 | 
					#include <blah/input/binding_registry.h>
 | 
				
			||||||
#include <blah/core/app.h>
 | 
					#include <blah/core/app.h>
 | 
				
			||||||
#include <blah/core/time.h>
 | 
					#include <blah/core/time.h>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <blah/math/point.h>
 | 
					#include <blah/math/point.h>
 | 
				
			||||||
#include "../internal/input_backend.h"
 | 
					#include "../internal/input_backend.h"
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
@ -47,10 +48,9 @@ void InputBackend::frame()
 | 
				
			|||||||
			g_next_state.mouse.pressed[i] = false;
 | 
								g_next_state.mouse.pressed[i] = false;
 | 
				
			||||||
			g_next_state.mouse.released[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.mouse.wheel = Point::zero;
 | 
				
			||||||
			g_next_state.keyboard.text[i] = 0;
 | 
							g_next_state.keyboard.text.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (int i = 0; i < Blah::Input::max_controllers; i++)
 | 
							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)
 | 
					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)
 | 
					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)
 | 
						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);
 | 
							void render(const RenderPass& pass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Clears the backbuffer
 | 
							// 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.
 | 
							// Creates a new Texture.
 | 
				
			||||||
		// if the Texture is invalid, this should return an empty reference.
 | 
							// if the Texture is invalid, this should return an empty reference.
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,11 @@
 | 
				
			|||||||
#ifdef BLAH_USE_D3D11
 | 
					#ifdef BLAH_GRAPHICS_D3D11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO:
 | 
					// TODO:
 | 
				
			||||||
// Note the D3D11 Implementation is still a work-in-progress
 | 
					// Note the D3D11 Implementation is still a work-in-progress
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../internal/graphics_backend.h"
 | 
					#include "../internal/graphics_backend.h"
 | 
				
			||||||
#include "../internal/platform_backend.h"
 | 
					#include "../internal/platform_backend.h"
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <stddef.h>
 | 
					#include <stddef.h>
 | 
				
			||||||
@ -36,7 +36,7 @@ namespace Blah
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		struct StoredInputLayout
 | 
							struct StoredInputLayout
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			uint32_t shader_hash;
 | 
								u32 shader_hash;
 | 
				
			||||||
			VertexFormat format;
 | 
								VertexFormat format;
 | 
				
			||||||
			ID3D11InputLayout* layout;
 | 
								ID3D11InputLayout* layout;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
@ -145,6 +145,9 @@ namespace Blah
 | 
				
			|||||||
				m_size = width * height * 4;
 | 
									m_size = width * height * 4;
 | 
				
			||||||
				is_depth_stencil = true;
 | 
									is_depth_stencil = true;
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
 | 
								case TextureFormat::None:
 | 
				
			||||||
 | 
								case TextureFormat::Count:
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!is_depth_stencil)
 | 
								if (!is_depth_stencil)
 | 
				
			||||||
@ -349,7 +352,7 @@ namespace Blah
 | 
				
			|||||||
			return m_attachments[0]->height();
 | 
								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 };
 | 
								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;
 | 
							Vector<Vector<float>> fragment_uniform_values;
 | 
				
			||||||
		StackVector<ShaderData::HLSL_Attribute, 16> attributes;
 | 
							StackVector<ShaderData::HLSL_Attribute, 16> attributes;
 | 
				
			||||||
		Vector<UniformInfo> uniform_list;
 | 
							Vector<UniformInfo> uniform_list;
 | 
				
			||||||
		uint32_t hash = 0;
 | 
							u32 hash = 0;
 | 
				
			||||||
		bool valid = false;
 | 
							bool valid = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		D3D11_Shader(const ShaderData* data)
 | 
							D3D11_Shader(const ShaderData* data)
 | 
				
			||||||
@ -542,10 +545,10 @@ namespace Blah
 | 
				
			|||||||
	class D3D11_Mesh : public Mesh
 | 
						class D3D11_Mesh : public Mesh
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		int64_t m_vertex_count = 0;
 | 
							i64 m_vertex_count = 0;
 | 
				
			||||||
		int64_t m_vertex_capacity = 0;
 | 
							i64 m_vertex_capacity = 0;
 | 
				
			||||||
		int64_t m_index_count = 0;
 | 
							i64 m_index_count = 0;
 | 
				
			||||||
		int64_t m_index_capacity = 0;
 | 
							i64 m_index_capacity = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		ID3D11Buffer* vertex_buffer = nullptr;
 | 
							ID3D11Buffer* vertex_buffer = nullptr;
 | 
				
			||||||
@ -567,7 +570,7 @@ namespace Blah
 | 
				
			|||||||
				index_buffer->Release();
 | 
									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;
 | 
								m_index_count = count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -579,8 +582,8 @@ namespace Blah
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				switch (format)
 | 
									switch (format)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
				case IndexFormat::UInt16: index_stride = sizeof(int16_t); break;
 | 
									case IndexFormat::UInt16: index_stride = sizeof(i16); break;
 | 
				
			||||||
				case IndexFormat::UInt32: index_stride = sizeof(int32_t); break;
 | 
									case IndexFormat::UInt32: index_stride = sizeof(i32); break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (m_index_capacity > 0 && indices)
 | 
									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;
 | 
								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;
 | 
								return m_index_count;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		virtual int64_t vertex_count() const override
 | 
							virtual i64 vertex_count() const override
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return m_vertex_count;
 | 
								return m_vertex_count;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		virtual int64_t instance_count() const override
 | 
							virtual i64 instance_count() const override
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -696,7 +699,7 @@ namespace Blah
 | 
				
			|||||||
		state.last_size = Point(App::draw_width(), App::draw_height());
 | 
							state.last_size = Point(App::draw_width(), App::draw_height());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Define Swap Chain
 | 
							// Define Swap Chain
 | 
				
			||||||
		DXGI_SWAP_CHAIN_DESC desc = { 0 };
 | 
							DXGI_SWAP_CHAIN_DESC desc = {};
 | 
				
			||||||
		desc.BufferDesc.RefreshRate.Numerator = 0;
 | 
							desc.BufferDesc.RefreshRate.Numerator = 0;
 | 
				
			||||||
		desc.BufferDesc.RefreshRate.Denominator = 1;
 | 
							desc.BufferDesc.RefreshRate.Denominator = 1;
 | 
				
			||||||
		desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
 | 
							desc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
 | 
				
			||||||
@ -705,7 +708,6 @@ namespace Blah
 | 
				
			|||||||
		desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
 | 
							desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
 | 
				
			||||||
		desc.BufferCount = 1;
 | 
							desc.BufferCount = 1;
 | 
				
			||||||
		desc.OutputWindow = (HWND)PlatformBackend::d3d11_get_hwnd();
 | 
							desc.OutputWindow = (HWND)PlatformBackend::d3d11_get_hwnd();
 | 
				
			||||||
		//desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
 | 
					 | 
				
			||||||
		desc.Windowed = true;
 | 
							desc.Windowed = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Creation Flags
 | 
							// Creation Flags
 | 
				
			||||||
@ -764,10 +766,10 @@ namespace Blah
 | 
				
			|||||||
				dxgi_device->GetAdapter(&dxgi_adapter);
 | 
									dxgi_device->GetAdapter(&dxgi_adapter);
 | 
				
			||||||
				dxgi_adapter->GetDesc(&adapter_desc);
 | 
									dxgi_adapter->GetDesc(&adapter_desc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				Log::print("D3D11 %ls", adapter_desc.Description);
 | 
									Log::info("D3D11 %ls", adapter_desc.Description);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				Log::print("D3D11");
 | 
									Log::info("D3D11");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return true;
 | 
							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)
 | 
							if (((int)mask & (int)ClearMask::Color) == (int)ClearMask::Color)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@ -1243,6 +1245,9 @@ namespace Blah
 | 
				
			|||||||
				int size = 0;
 | 
									int size = 0;
 | 
				
			||||||
				switch (it.type)
 | 
									switch (it.type)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
 | 
									case UniformType::None: break;
 | 
				
			||||||
 | 
									case UniformType::Texture2D: break;
 | 
				
			||||||
 | 
									case UniformType::Sampler2D: break;
 | 
				
			||||||
				case UniformType::Float: size = 1; break;
 | 
									case UniformType::Float: size = 1; break;
 | 
				
			||||||
				case UniformType::Float2: size = 2; break;
 | 
									case UniformType::Float2: size = 2; break;
 | 
				
			||||||
				case UniformType::Float3: size = 3; break;
 | 
									case UniformType::Float3: size = 3; break;
 | 
				
			||||||
@ -1304,6 +1309,7 @@ namespace Blah
 | 
				
			|||||||
			{
 | 
								{
 | 
				
			||||||
				switch (format.attributes[i].type)
 | 
									switch (format.attributes[i].type)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
 | 
									case VertexType::None: break;
 | 
				
			||||||
				case VertexType::Float: it->Format = DXGI_FORMAT_R32_FLOAT;  break;
 | 
									case VertexType::Float: it->Format = DXGI_FORMAT_R32_FLOAT;  break;
 | 
				
			||||||
				case VertexType::Float2: it->Format = DXGI_FORMAT_R32G32_FLOAT; break;
 | 
									case VertexType::Float2: it->Format = DXGI_FORMAT_R32G32_FLOAT; break;
 | 
				
			||||||
				case VertexType::Float3: it->Format = DXGI_FORMAT_R32G32B32_FLOAT; break;
 | 
									case VertexType::Float3: it->Format = DXGI_FORMAT_R32G32B32_FLOAT; break;
 | 
				
			||||||
@ -1320,6 +1326,7 @@ namespace Blah
 | 
				
			|||||||
			{
 | 
								{
 | 
				
			||||||
				switch (format.attributes[i].type)
 | 
									switch (format.attributes[i].type)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
 | 
									case VertexType::None: break;
 | 
				
			||||||
				case VertexType::Float: it->Format = DXGI_FORMAT_R32_FLOAT;  break;
 | 
									case VertexType::Float: it->Format = DXGI_FORMAT_R32_FLOAT;  break;
 | 
				
			||||||
				case VertexType::Float2: it->Format = DXGI_FORMAT_R32G32_FLOAT; break;
 | 
									case VertexType::Float2: it->Format = DXGI_FORMAT_R32G32_FLOAT; break;
 | 
				
			||||||
				case VertexType::Float3: it->Format = DXGI_FORMAT_R32G32B32_FLOAT; break;
 | 
									case VertexType::Float3: it->Format = DXGI_FORMAT_R32G32B32_FLOAT; break;
 | 
				
			||||||
@ -1428,18 +1435,21 @@ namespace Blah
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		switch (sampler.filter)
 | 
							switch (sampler.filter)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
 | 
							case TextureFilter::None: break;
 | 
				
			||||||
		case TextureFilter::Nearest: desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; 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;
 | 
							case TextureFilter::Linear: desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch (sampler.wrap_x)
 | 
							switch (sampler.wrap_x)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
 | 
							case TextureWrap::None: break;
 | 
				
			||||||
		case TextureWrap::Clamp: desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; break;
 | 
							case TextureWrap::Clamp: desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; break;
 | 
				
			||||||
		case TextureWrap::Repeat: desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; break;
 | 
							case TextureWrap::Repeat: desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch (sampler.wrap_y)
 | 
							switch (sampler.wrap_y)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
 | 
							case TextureWrap::None: break;
 | 
				
			||||||
		case TextureWrap::Clamp: desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; break;
 | 
							case TextureWrap::Clamp: desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; break;
 | 
				
			||||||
		case TextureWrap::Repeat: desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; 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/graphics_backend.h"
 | 
				
			||||||
#include "../internal/platform_backend.h"
 | 
					#include "../internal/platform_backend.h"
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Blah
 | 
					namespace Blah
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -134,9 +134,9 @@ namespace Blah
 | 
				
			|||||||
	class Dummy_Mesh : public Mesh
 | 
						class Dummy_Mesh : public Mesh
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		int64_t m_index_count = 0;
 | 
							i64 m_index_count = 0;
 | 
				
			||||||
		int64_t m_vertex_count = 0;
 | 
							i64 m_vertex_count = 0;
 | 
				
			||||||
		int64_t m_instance_count = 0;
 | 
							i64 m_instance_count = 0;
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Dummy_Mesh()
 | 
							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;
 | 
								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;
 | 
								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;
 | 
								m_instance_count = count;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		virtual int64_t index_count() const override
 | 
							virtual i64 index_count() const override
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return m_index_count;
 | 
								return m_index_count;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		virtual int64_t vertex_count() const override
 | 
							virtual i64 vertex_count() const override
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return m_vertex_count;
 | 
								return m_vertex_count;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		virtual int64_t instance_count() const override
 | 
							virtual i64 instance_count() const override
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return m_instance_count;
 | 
								return m_instance_count;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -177,7 +177,7 @@ namespace Blah
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	bool GraphicsBackend::init()
 | 
						bool GraphicsBackend::init()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Log::print("Dummy Renderer");
 | 
							Log::info("Dummy Renderer");
 | 
				
			||||||
		return true;
 | 
							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/graphics_backend.h"
 | 
				
			||||||
#include "../internal/platform_backend.h"
 | 
					#include "../internal/platform_backend.h"
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <stddef.h>
 | 
					#include <stddef.h>
 | 
				
			||||||
@ -401,7 +401,7 @@ namespace Blah
 | 
				
			|||||||
		else if (severity != GL_DEBUG_SEVERITY_NOTIFICATION)
 | 
							else if (severity != GL_DEBUG_SEVERITY_NOTIFICATION)
 | 
				
			||||||
			Log::warn("GL (%s:%s) %s", typeName, severityName, message);
 | 
								Log::warn("GL (%s:%s) %s", typeName, severityName, message);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			Log::print("GL (%s) %s", typeName, message);
 | 
								Log::info("GL (%s) %s", typeName, message);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// assign attributes
 | 
						// assign attributes
 | 
				
			||||||
@ -484,7 +484,7 @@ namespace Blah
 | 
				
			|||||||
				components = 4;
 | 
									components = 4;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			uint32_t location = (uint32_t)(attribute.index);
 | 
								u32 location = (u32)(attribute.index);
 | 
				
			||||||
			gl.EnableVertexAttribArray(location);
 | 
								gl.EnableVertexAttribArray(location);
 | 
				
			||||||
			gl.VertexAttribPointer(location, components, type, attribute.normalized, format.stride, (void*)ptr);
 | 
								gl.VertexAttribPointer(location, components, type, attribute.normalized, format.stride, (void*)ptr);
 | 
				
			||||||
			gl.VertexAttribDivisor(location, divisor);
 | 
								gl.VertexAttribDivisor(location, divisor);
 | 
				
			||||||
@ -674,7 +674,7 @@ namespace Blah
 | 
				
			|||||||
		GLuint m_id;
 | 
							GLuint m_id;
 | 
				
			||||||
		int m_width;
 | 
							int m_width;
 | 
				
			||||||
		int m_height;
 | 
							int m_height;
 | 
				
			||||||
		StackVector<TextureRef, BLAH_ATTACHMENTS> m_attachments;
 | 
							StackVector<TextureRef, Attachments::MaxCapacity> m_attachments;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -749,7 +749,7 @@ namespace Blah
 | 
				
			|||||||
			return m_height;
 | 
								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;
 | 
								int clear = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -967,13 +967,13 @@ namespace Blah
 | 
				
			|||||||
		GLuint m_index_buffer;
 | 
							GLuint m_index_buffer;
 | 
				
			||||||
		GLuint m_vertex_buffer;
 | 
							GLuint m_vertex_buffer;
 | 
				
			||||||
		GLuint m_instance_buffer;
 | 
							GLuint m_instance_buffer;
 | 
				
			||||||
		int64_t m_index_count;
 | 
							i64 m_index_count;
 | 
				
			||||||
		int64_t m_vertex_count;
 | 
							i64 m_vertex_count;
 | 
				
			||||||
		int64_t m_instance_count;
 | 
							i64 m_instance_count;
 | 
				
			||||||
		uint16_t m_vertex_size;
 | 
							u16 m_vertex_size;
 | 
				
			||||||
		uint16_t m_instance_size;
 | 
							u16 m_instance_size;
 | 
				
			||||||
		uint8_t m_vertex_attribs_enabled;
 | 
							u8 m_vertex_attribs_enabled;
 | 
				
			||||||
		uint8_t m_instance_attribs_enabled;
 | 
							u8 m_instance_attribs_enabled;
 | 
				
			||||||
		Vector<GLuint> m_vertex_attribs;
 | 
							Vector<GLuint> m_vertex_attribs;
 | 
				
			||||||
		Vector<GLuint> m_instance_attribs;
 | 
							Vector<GLuint> m_instance_attribs;
 | 
				
			||||||
		GLenum m_index_format;
 | 
							GLenum m_index_format;
 | 
				
			||||||
@ -1026,7 +1026,7 @@ namespace Blah
 | 
				
			|||||||
			return m_index_size;
 | 
								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;
 | 
								m_index_count = count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1053,7 +1053,7 @@ namespace Blah
 | 
				
			|||||||
			gl.BindVertexArray(0);
 | 
								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;
 | 
								m_vertex_count = count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1074,7 +1074,7 @@ namespace Blah
 | 
				
			|||||||
			gl.BindVertexArray(0);
 | 
								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;
 | 
								m_instance_count = count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1095,17 +1095,17 @@ namespace Blah
 | 
				
			|||||||
			gl.BindVertexArray(0);
 | 
								gl.BindVertexArray(0);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		virtual int64_t index_count() const override
 | 
							virtual i64 index_count() const override
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return m_index_count;
 | 
								return m_index_count;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		virtual int64_t vertex_count() const override
 | 
							virtual i64 vertex_count() const override
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return m_vertex_count;
 | 
								return m_vertex_count;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		virtual int64_t instance_count() const override
 | 
							virtual i64 instance_count() const override
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return m_instance_count;
 | 
								return m_instance_count;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -1147,7 +1147,7 @@ namespace Blah
 | 
				
			|||||||
		gl.GetIntegerv(0x0D33, &gl.max_texture_size);
 | 
							gl.GetIntegerv(0x0D33, &gl.max_texture_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// log
 | 
							// log
 | 
				
			||||||
		Log::print("OpenGL %s, %s",
 | 
							Log::info("OpenGL %s, %s",
 | 
				
			||||||
			gl.GetString(GL_VERSION),
 | 
								gl.GetString(GL_VERSION),
 | 
				
			||||||
			gl.GetString(GL_RENDERER));
 | 
								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;
 | 
							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
 | 
							// 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.
 | 
							// 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
 | 
							// Call this when a controller is disconnected
 | 
				
			||||||
		void on_controller_disconnect(int index);
 | 
							void on_controller_disconnect(int index);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
#include <inttypes.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <blah/core/filesystem.h>
 | 
					#include <blah/core/filesystem.h>
 | 
				
			||||||
#include <blah/containers/vector.h>
 | 
					#include <blah/containers/vector.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -22,7 +22,7 @@ namespace Blah
 | 
				
			|||||||
		void shutdown();
 | 
							void shutdown();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// The time, in ticks (microseconds) since the Application was started
 | 
							// The time, in ticks (microseconds) since the Application was started
 | 
				
			||||||
		uint64_t ticks();
 | 
							u64 ticks();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Called every frame
 | 
							// Called every frame
 | 
				
			||||||
		void frame();
 | 
							void frame();
 | 
				
			||||||
@ -91,19 +91,19 @@ namespace Blah
 | 
				
			|||||||
		bool file_open(const char* path, FileHandle* handle, FileMode mode);
 | 
							bool file_open(const char* path, FileHandle* handle, FileMode mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Returns the length of the file
 | 
							// Returns the length of the file
 | 
				
			||||||
		int64_t file_length(FileHandle file);
 | 
							i64 file_length(FileHandle file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Returns the Position of the 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
 | 
							// 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
 | 
							// 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
 | 
							// 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
 | 
							// Closes a file
 | 
				
			||||||
		void file_close(FileHandle 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/platform_backend.h"
 | 
				
			||||||
#include "../internal/input_backend.h"
 | 
					#include "../internal/input_backend.h"
 | 
				
			||||||
@ -6,7 +6,7 @@
 | 
				
			|||||||
#include <blah/input/input.h>
 | 
					#include <blah/input/input.h>
 | 
				
			||||||
#include <blah/core/app.h>
 | 
					#include <blah/core/app.h>
 | 
				
			||||||
#include <blah/core/filesystem.h>
 | 
					#include <blah/core/filesystem.h>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include <blah/core/time.h>
 | 
					#include <blah/core/time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <SDL.h>
 | 
					#include <SDL.h>
 | 
				
			||||||
@ -41,12 +41,34 @@ namespace
 | 
				
			|||||||
	void sdl_log(void* userdata, int category, SDL_LogPriority priority, const char* message)
 | 
						void sdl_log(void* userdata, int category, SDL_LogPriority priority, const char* message)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (priority <= SDL_LOG_PRIORITY_INFO)
 | 
							if (priority <= SDL_LOG_PRIORITY_INFO)
 | 
				
			||||||
			Log::print(message);
 | 
								Log::info(message);
 | 
				
			||||||
		else if (priority <= SDL_LOG_PRIORITY_WARN)
 | 
							else if (priority <= SDL_LOG_PRIORITY_WARN)
 | 
				
			||||||
			Log::warn(message);
 | 
								Log::warn(message);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			Log::error(message);
 | 
								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)
 | 
					bool PlatformBackend::init(const Config* config)
 | 
				
			||||||
@ -65,7 +87,7 @@ bool PlatformBackend::init(const Config* config)
 | 
				
			|||||||
	// Get SDL version
 | 
						// Get SDL version
 | 
				
			||||||
	SDL_version version;
 | 
						SDL_version version;
 | 
				
			||||||
	SDL_GetVersion(&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
 | 
						// initialize SDL
 | 
				
			||||||
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) != 0)
 | 
						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();
 | 
						SDL_Quit();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint64_t PlatformBackend::ticks()
 | 
					u64 PlatformBackend::ticks()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto counter = SDL_GetPerformanceCounter();
 | 
						auto counter = SDL_GetPerformanceCounter();
 | 
				
			||||||
	auto per_second = (double)SDL_GetPerformanceFrequency();
 | 
						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
 | 
					// Macro defined by X11 conflicts with MouseButton enum
 | 
				
			||||||
@ -247,46 +269,56 @@ void PlatformBackend::frame()
 | 
				
			|||||||
		// Joystick Controller
 | 
							// Joystick Controller
 | 
				
			||||||
		else if (event.type == SDL_JOYDEVICEADDED)
 | 
							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);
 | 
									auto ptr = joysticks[index] = SDL_JoystickOpen(index);
 | 
				
			||||||
				const char* name = SDL_JoystickName(ptr);
 | 
									auto name = SDL_JoystickName(ptr);
 | 
				
			||||||
				int button_count = SDL_JoystickNumButtons(ptr);
 | 
									auto button_count = SDL_JoystickNumButtons(ptr);
 | 
				
			||||||
				int axis_count = SDL_JoystickNumAxes(ptr);
 | 
									auto axis_count = SDL_JoystickNumAxes(ptr);
 | 
				
			||||||
				uint16_t vendor = SDL_JoystickGetVendor(ptr);
 | 
									auto vendor = SDL_JoystickGetVendor(ptr);
 | 
				
			||||||
				uint16_t product = SDL_JoystickGetProduct(ptr);
 | 
									auto product = SDL_JoystickGetProduct(ptr);
 | 
				
			||||||
				uint16_t version = SDL_JoystickGetProductVersion(ptr);
 | 
									auto version = SDL_JoystickGetProductVersion(ptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				InputBackend::on_controller_connect(index, name, 0, button_count, axis_count, vendor, product, version);
 | 
									InputBackend::on_controller_connect(index, name, 0, button_count, axis_count, vendor, product, version);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else if (event.type == SDL_JOYDEVICEREMOVED)
 | 
							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)
 | 
									if (SDL_IsGameController(index) == SDL_FALSE)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					InputBackend::on_controller_disconnect(index);
 | 
										InputBackend::on_controller_disconnect(index);
 | 
				
			||||||
					SDL_JoystickClose(joysticks[index]);
 | 
										SDL_JoystickClose(joysticks[index]);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else if (event.type == SDL_JOYBUTTONDOWN)
 | 
							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)
 | 
									if (SDL_IsGameController(index) == SDL_FALSE)
 | 
				
			||||||
					InputBackend::on_button_down(index, event.jbutton.button);
 | 
										InputBackend::on_button_down(index, event.jbutton.button);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else if (event.type == SDL_JOYBUTTONUP)
 | 
							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)
 | 
									if (SDL_IsGameController(index) == SDL_FALSE)
 | 
				
			||||||
					InputBackend::on_button_up(index, event.jbutton.button);
 | 
										InputBackend::on_button_up(index, event.jbutton.button);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else if (event.type == SDL_JOYAXISMOTION)
 | 
							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)
 | 
									if (SDL_IsGameController(index) == SDL_FALSE)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					float value;
 | 
										float value;
 | 
				
			||||||
@ -297,48 +329,60 @@ void PlatformBackend::frame()
 | 
				
			|||||||
					InputBackend::on_axis_move(index, event.jaxis.axis, value);
 | 
										InputBackend::on_axis_move(index, event.jaxis.axis, value);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		// Gamepad Controller
 | 
							// Gamepad Controller
 | 
				
			||||||
		else if (event.type == SDL_CONTROLLERDEVICEADDED)
 | 
							else if (event.type == SDL_CONTROLLERDEVICEADDED)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Sint32 index = event.cdevice.which;
 | 
								auto index = event.cdevice.which;
 | 
				
			||||||
			SDL_GameController* ptr = gamepads[index] = SDL_GameControllerOpen(index);
 | 
								if (index >= 0 && index < Input::max_controllers)
 | 
				
			||||||
			const char* name = SDL_GameControllerName(ptr);
 | 
								{
 | 
				
			||||||
			uint16_t vendor = SDL_GameControllerGetVendor(ptr);
 | 
									auto ptr = gamepads[index] = SDL_GameControllerOpen(index);
 | 
				
			||||||
			uint16_t product = SDL_GameControllerGetProduct(ptr);
 | 
									auto name = SDL_GameControllerName(ptr);
 | 
				
			||||||
			uint16_t version = SDL_GameControllerGetProductVersion(ptr);
 | 
									auto vendor = SDL_GameControllerGetVendor(ptr);
 | 
				
			||||||
 | 
									auto product = SDL_GameControllerGetProduct(ptr);
 | 
				
			||||||
 | 
									auto version = SDL_GameControllerGetProductVersion(ptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				InputBackend::on_controller_connect(index, name, 1, 15, 6, vendor, product, version);
 | 
									InputBackend::on_controller_connect(index, name, 1, 15, 6, vendor, product, version);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else if (event.type == SDL_CONTROLLERDEVICEREMOVED)
 | 
							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);
 | 
									InputBackend::on_controller_disconnect(index);
 | 
				
			||||||
				SDL_GameControllerClose(gamepads[index]);
 | 
									SDL_GameControllerClose(gamepads[index]);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else if (event.type == SDL_CONTROLLERBUTTONDOWN)
 | 
							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;
 | 
									int button = (int)Button::None;
 | 
				
			||||||
				if (event.cbutton.button >= 0 && event.cbutton.button < 15)
 | 
									if (event.cbutton.button >= 0 && event.cbutton.button < 15)
 | 
				
			||||||
					button = event.cbutton.button; // NOTE: These map directly to Engine Buttons enum!
 | 
										button = event.cbutton.button; // NOTE: These map directly to Engine Buttons enum!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				InputBackend::on_button_down(index, button);
 | 
									InputBackend::on_button_down(index, button);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else if (event.type == SDL_CONTROLLERBUTTONUP)
 | 
							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;
 | 
									int button = (int)Button::None;
 | 
				
			||||||
				if (event.cbutton.button >= 0 && event.cbutton.button < 15)
 | 
									if (event.cbutton.button >= 0 && event.cbutton.button < 15)
 | 
				
			||||||
					button = event.cbutton.button; // NOTE: These map directly to Engine Buttons enum!
 | 
										button = event.cbutton.button; // NOTE: These map directly to Engine Buttons enum!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				InputBackend::on_button_up(index, button);
 | 
									InputBackend::on_button_up(index, button);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else if (event.type == SDL_CONTROLLERAXISMOTION)
 | 
							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;
 | 
									int axis = (int)Axis::None;
 | 
				
			||||||
				if (event.caxis.axis >= 0 && event.caxis.axis < 6)
 | 
									if (event.caxis.axis >= 0 && event.caxis.axis < 6)
 | 
				
			||||||
					axis = event.caxis.axis; // NOTE: These map directly to Engine Axis enum!
 | 
										axis = event.caxis.axis; // NOTE: These map directly to Engine Axis enum!
 | 
				
			||||||
@ -353,11 +397,12 @@ void PlatformBackend::frame()
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void PlatformBackend::sleep(int milliseconds)
 | 
					void PlatformBackend::sleep(int milliseconds)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (milliseconds >= 0)
 | 
						if (milliseconds >= 0)
 | 
				
			||||||
		SDL_Delay((uint32_t)milliseconds);
 | 
							SDL_Delay((u32)milliseconds);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void PlatformBackend::present()
 | 
					void PlatformBackend::present()
 | 
				
			||||||
@ -611,27 +656,27 @@ bool PlatformBackend::file_open(const char* path, PlatformBackend::FileHandle* h
 | 
				
			|||||||
	return ptr != nullptr;
 | 
						return ptr != nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int64_t PlatformBackend::file_length(PlatformBackend::FileHandle stream)
 | 
					i64 PlatformBackend::file_length(PlatformBackend::FileHandle stream)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return SDL_RWsize((SDL_RWops*)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);
 | 
						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);
 | 
						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);
 | 
						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);
 | 
						return SDL_RWwrite((SDL_RWops*)stream, ptr, sizeof(char), length);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -677,4 +722,4 @@ void* PlatformBackend::d3d11_get_hwnd()
 | 
				
			|||||||
#endif
 | 
					#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;
 | 
						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)
 | 
					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);
 | 
						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/color.h>
 | 
				
			||||||
 | 
					#include <blah/math/vec3.h>
 | 
				
			||||||
#include <blah/math/vec4.h>
 | 
					#include <blah/math/vec4.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace Blah;
 | 
					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)))
 | 
					#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()
 | 
					Color::Color()
 | 
				
			||||||
	: r(0), g(0), b(0), a(0) {}
 | 
						: r(0)
 | 
				
			||||||
 | 
						, g(0)
 | 
				
			||||||
 | 
						, b(0)
 | 
				
			||||||
 | 
						, a(0) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Color::Color(int rgb) :
 | 
					Color::Color(int rgb)
 | 
				
			||||||
	r((uint8_t)((rgb & 0xFF0000) >> 16)),
 | 
						: r((u8)((rgb & 0xFF0000) >> 16))
 | 
				
			||||||
	g((uint8_t)((rgb & 0x00FF00) >> 8)),
 | 
						, g((u8)((rgb & 0x00FF00) >> 8))
 | 
				
			||||||
	b((uint8_t)(rgb & 0x0000FF)),
 | 
						, b((u8)(rgb & 0x0000FF))
 | 
				
			||||||
	a(255) {}
 | 
						, a(255) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Color::Color(int rgb, float alpha) :
 | 
					Color::Color(int rgb, float alpha)
 | 
				
			||||||
	r((int)(((uint8_t)((rgb & 0xFF0000) >> 16)) * alpha)),
 | 
						: r((int)(((u8)((rgb & 0xFF0000) >> 16)) * alpha))
 | 
				
			||||||
	g((int)(((uint8_t)((rgb & 0x00FF00) >> 8)) * alpha)),
 | 
						, g((int)(((u8)((rgb & 0x00FF00) >> 8)) * alpha))
 | 
				
			||||||
	b((int)(((uint8_t)(rgb & 0x0000FF)) * alpha)),
 | 
						, b((int)(((u8)(rgb & 0x0000FF)) * alpha))
 | 
				
			||||||
	a((int)(255 * alpha)) {}
 | 
						, a((int)(255 * alpha)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Color::Color(uint8_t r, uint8_t g, uint8_t b)
 | 
					Color::Color(u8 r, u8 g, u8 b)
 | 
				
			||||||
	: r(r), g(g), b(b), a(255) {}
 | 
						: r(r)
 | 
				
			||||||
 | 
						, g(g)
 | 
				
			||||||
 | 
						, b(b)
 | 
				
			||||||
 | 
						, a(255) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Color::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
 | 
					Color::Color(u8 r, u8 g, u8 b, u8 a)
 | 
				
			||||||
	: r(r), g(g), b(b), a(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)
 | 
					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;
 | 
						int offset = 0;
 | 
				
			||||||
	if (length > 0 && value[0] == '#')
 | 
						if (value.length() > 0 && value[0] == '#')
 | 
				
			||||||
		offset = 1;
 | 
							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;
 | 
							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]);
 | 
							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]);
 | 
							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]);
 | 
							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;
 | 
						b = b * a / 255;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint32_t Color::to_rgba() const
 | 
					u32 Color::to_rgba() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
		((uint32_t)r << 24) |
 | 
							((u32)r << 24) |
 | 
				
			||||||
		((uint32_t)g << 16) |
 | 
							((u32)g << 16) |
 | 
				
			||||||
		((uint32_t)b << 8) |
 | 
							((u32)b << 8) |
 | 
				
			||||||
		(uint32_t)a;
 | 
							(u32)a;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Vec4 Color::to_vec4() const
 | 
					Vec4 Color::to_vec4() const
 | 
				
			||||||
@ -110,24 +135,24 @@ String Color::to_hex_rgb() const
 | 
				
			|||||||
	return str;
 | 
						return str;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Color Color::from_rgba(uint32_t value)
 | 
					Color Color::from_rgba(u32 value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		(uint8_t)((value & 0xFF000000) >> 24),
 | 
							(u8)((value & 0xFF000000) >> 24),
 | 
				
			||||||
		(uint8_t)((value & 0x00FF0000) >> 16),
 | 
							(u8)((value & 0x00FF0000) >> 16),
 | 
				
			||||||
		(uint8_t)((value & 0x0000FF00) >> 8),
 | 
							(u8)((value & 0x0000FF00) >> 8),
 | 
				
			||||||
		(uint8_t)((value & 0x000000FF))
 | 
							(u8)((value & 0x000000FF))
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Color Color::from_rgb(uint32_t value)
 | 
					Color Color::from_rgb(u32 value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		(uint8_t)((value & 0xFF0000) >> 16),
 | 
							(u8)((value & 0xFF0000) >> 16),
 | 
				
			||||||
		(uint8_t)((value & 0x00FF00) >> 8),
 | 
							(u8)((value & 0x00FF00) >> 8),
 | 
				
			||||||
		(uint8_t)((value & 0x0000FF))
 | 
							(u8)((value & 0x0000FF))
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -137,10 +162,10 @@ Color Color::lerp(Color a, Color b, float amount)
 | 
				
			|||||||
	if (amount > 1) amount = 1;
 | 
						if (amount > 1) amount = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return Color(
 | 
						return Color(
 | 
				
			||||||
		(uint8_t)(a.r + (b.r - a.r) * amount),
 | 
							(u8)(a.r + (b.r - a.r) * amount),
 | 
				
			||||||
		(uint8_t)(a.g + (b.g - a.g) * amount),
 | 
							(u8)(a.g + (b.g - a.g) * amount),
 | 
				
			||||||
		(uint8_t)(a.b + (b.b - a.b) * amount),
 | 
							(u8)(a.b + (b.b - a.b) * amount),
 | 
				
			||||||
		(uint8_t)(a.a + (b.a - a.a) * 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)
 | 
					Color& Color::operator=(const int rgb)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	r = (uint8_t)((rgb & 0xFF0000) >> 16);
 | 
						r = (u8)((rgb & 0xFF0000) >> 16);
 | 
				
			||||||
	g = (uint8_t)((rgb & 0x00FF00) >> 8);
 | 
						g = (u8)((rgb & 0x00FF00) >> 8);
 | 
				
			||||||
	b = (uint8_t)(rgb & 0x0000FF);
 | 
						b = (u8)(rgb & 0x0000FF);
 | 
				
			||||||
	a = 255;
 | 
						a = 255;
 | 
				
			||||||
	return *this;
 | 
						return *this;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -31,7 +31,7 @@ Vec2 Line::closest_point(const Vec2& pt) const
 | 
				
			|||||||
	Vec2 v = b - a;
 | 
						Vec2 v = b - a;
 | 
				
			||||||
	Vec2 w = pt - a;
 | 
						Vec2 w = pt - a;
 | 
				
			||||||
	float t = Vec2::dot(w, v) / Vec2::dot(v, v);
 | 
						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;
 | 
						return v * t + a;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
#include <blah/math/mat4x4.h>
 | 
					#include <blah/math/mat4x4.h>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace Blah;
 | 
					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();
 | 
						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;
 | 
						return microseconds() / 1000;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					u64 Stopwatch::microseconds()
 | 
				
			||||||
uint64_t Stopwatch::microseconds()
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return std::chrono::duration_cast<std::chrono::microseconds>(system_clock::now().time_since_epoch()).count() - start_time;
 | 
						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;
 | 
						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)
 | 
						if (m_buffer == nullptr || ptr == nullptr)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
@ -58,7 +58,7 @@ int64_t BufferStream::read_into(void* ptr, int64_t len)
 | 
				
			|||||||
	return 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)
 | 
						if (len < 0)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
#include <blah/streams/filestream.h>
 | 
					#include <blah/streams/filestream.h>
 | 
				
			||||||
#include <blah/core/log.h>
 | 
					#include <blah/core/common.h>
 | 
				
			||||||
#include "../internal/platform_backend.h"
 | 
					#include "../internal/platform_backend.h"
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -11,7 +11,7 @@ FileStream::FileStream()
 | 
				
			|||||||
	m_mode = FileMode::None;
 | 
						m_mode = FileMode::None;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FileStream::FileStream(const char* path, FileMode mode)
 | 
					FileStream::FileStream(const FilePath& path, FileMode mode)
 | 
				
			||||||
	: m_mode(mode)
 | 
						: m_mode(mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!PlatformBackend::file_open(path, &m_handle, mode))
 | 
						if (!PlatformBackend::file_open(path, &m_handle, mode))
 | 
				
			||||||
@ -39,7 +39,7 @@ FileStream::~FileStream()
 | 
				
			|||||||
		PlatformBackend::file_close(m_handle);
 | 
							PlatformBackend::file_close(m_handle);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int64_t FileStream::length() const
 | 
					i64 FileStream::length() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (m_handle == nullptr)
 | 
						if (m_handle == nullptr)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
@ -47,7 +47,7 @@ int64_t FileStream::length() const
 | 
				
			|||||||
	return PlatformBackend::file_length(m_handle);
 | 
						return PlatformBackend::file_length(m_handle);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int64_t FileStream::position() const
 | 
					i64 FileStream::position() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (m_handle == nullptr)
 | 
						if (m_handle == nullptr)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
@ -55,7 +55,7 @@ int64_t FileStream::position() const
 | 
				
			|||||||
	return PlatformBackend::file_position(m_handle);
 | 
						return PlatformBackend::file_position(m_handle);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int64_t FileStream::seek(int64_t seek_to)
 | 
					i64 FileStream::seek(i64 seek_to)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (m_handle == nullptr)
 | 
						if (m_handle == nullptr)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
@ -63,7 +63,22 @@ int64_t FileStream::seek(int64_t seek_to)
 | 
				
			|||||||
	return PlatformBackend::file_seek(m_handle, 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)
 | 
						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);
 | 
						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)
 | 
						if (length <= 0)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@ using namespace Blah;
 | 
				
			|||||||
MemoryStream::MemoryStream()
 | 
					MemoryStream::MemoryStream()
 | 
				
			||||||
	: m_data(nullptr), m_length(0), m_position(0) {}
 | 
						: 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) {}
 | 
						: m_data(data), m_length(length), m_position(0) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MemoryStream::MemoryStream(MemoryStream&& src) noexcept
 | 
					MemoryStream::MemoryStream(MemoryStream&& src) noexcept
 | 
				
			||||||
@ -28,7 +28,7 @@ MemoryStream& MemoryStream::operator=(MemoryStream&& src) noexcept
 | 
				
			|||||||
	return *this;
 | 
						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)
 | 
						if (len < 0 || ptr == nullptr)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
@ -41,7 +41,7 @@ int64_t MemoryStream::read_into(void* ptr, int64_t len)
 | 
				
			|||||||
	return 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)
 | 
						if (len < 0 || ptr == nullptr)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -4,10 +4,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using namespace Blah;
 | 
					using namespace Blah;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int64_t Stream::pipe(Stream& stream, int64_t length)
 | 
					i64 Stream::pipe(Stream& stream, i64 length)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const int BUFFER_LENGTH = 4096;
 | 
						const int BUFFER_LENGTH = 4096;
 | 
				
			||||||
	int64_t result = 0;
 | 
						i64 result = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char buffer[BUFFER_LENGTH];
 | 
						char buffer[BUFFER_LENGTH];
 | 
				
			||||||
	while (length > 0)
 | 
						while (length > 0)
 | 
				
			||||||
@ -59,12 +59,12 @@ String Stream::read_line()
 | 
				
			|||||||
	return result;
 | 
						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);
 | 
						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());
 | 
						return write_from(string.begin(), string.length());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user