large organizational & cleanup refactor

This commit is contained in:
Noel Berry 2021-05-09 17:23:02 -07:00
parent e65752f30b
commit e615b9d7e4
91 changed files with 3188 additions and 3224 deletions

View File

@ -6,27 +6,23 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(blah add_library(blah
src/app.cpp
src/core/app.cpp src/filesystem.cpp
src/core/filesystem.cpp src/common.cpp
src/core/common.cpp src/time.cpp
src/core/time.cpp src/input.cpp
src/graphics/batch.cpp src/graphics/batch.cpp
src/graphics/blend.cpp src/graphics/blend.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/spritefont.cpp
src/graphics/subtexture.cpp src/graphics/subtexture.cpp
src/graphics/target.cpp
src/graphics/texture.cpp src/graphics/texture.cpp
src/input/input.cpp
src/input/binding.cpp
src/input/binding_registry.cpp
src/containers/str.cpp src/containers/str.cpp
src/images/aseprite.cpp src/images/aseprite.cpp
@ -34,18 +30,17 @@ add_library(blah
src/images/image.cpp src/images/image.cpp
src/images/packer.cpp src/images/packer.cpp
src/math/calc.cpp src/numerics/calc.cpp
src/math/circle.cpp src/numerics/circle.cpp
src/math/color.cpp src/numerics/color.cpp
src/math/line.cpp src/numerics/line.cpp
src/math/mat3x2.cpp src/numerics/mat3x2.cpp
src/math/mat4x4.cpp src/numerics/mat4x4.cpp
src/math/point.cpp src/numerics/point.cpp
src/math/quad.cpp src/numerics/quad.cpp
src/math/rect.cpp src/numerics/rect.cpp
src/math/rectI.cpp src/numerics/rectI.cpp
src/math/stopwatch.cpp src/numerics/vec2.cpp
src/math/vec2.cpp
src/streams/bufferstream.cpp src/streams/bufferstream.cpp
src/streams/filestream.cpp src/streams/filestream.cpp

View File

@ -1,9 +1,10 @@
#pragma once #pragma once
#include "blah/core/app.h" #include "blah/app.h"
#include "blah/core/filesystem.h" #include "blah/filesystem.h"
#include "blah/core/common.h" #include "blah/common.h"
#include "blah/core/time.h" #include "blah/time.h"
#include "blah/input.h"
#include "blah/containers/vector.h" #include "blah/containers/vector.h"
#include "blah/containers/stackvector.h" #include "blah/containers/stackvector.h"
@ -14,12 +15,12 @@
#include "blah/graphics/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/material.h" #include "blah/graphics/material.h"
#include "blah/graphics/mesh.h" #include "blah/graphics/mesh.h"
#include "blah/graphics/renderpass.h" #include "blah/graphics/renderpass.h"
#include "blah/graphics/sampler.h" #include "blah/graphics/sampler.h"
#include "blah/graphics/shader.h" #include "blah/graphics/shader.h"
#include "blah/graphics/target.h"
#include "blah/graphics/texture.h" #include "blah/graphics/texture.h"
#include "blah/images/aseprite.h" #include "blah/images/aseprite.h"
@ -27,25 +28,21 @@
#include "blah/images/image.h" #include "blah/images/image.h"
#include "blah/images/packer.h" #include "blah/images/packer.h"
#include "blah/input/input.h"
#include "blah/input/binding.h"
#include "blah/input/binding_registry.h"
#include "blah/math/calc.h" #include "blah/numerics/calc.h"
#include "blah/math/circle.h" #include "blah/numerics/circle.h"
#include "blah/math/color.h" #include "blah/numerics/color.h"
#include "blah/math/ease.h" #include "blah/numerics/ease.h"
#include "blah/math/line.h" #include "blah/numerics/line.h"
#include "blah/math/mat3x2.h" #include "blah/numerics/mat3x2.h"
#include "blah/math/mat4x4.h" #include "blah/numerics/mat4x4.h"
#include "blah/math/point.h" #include "blah/numerics/point.h"
#include "blah/math/quad.h" #include "blah/numerics/quad.h"
#include "blah/math/rect.h" #include "blah/numerics/rect.h"
#include "blah/math/rectI.h" #include "blah/numerics/rectI.h"
#include "blah/math/stopwatch.h" #include "blah/numerics/vec2.h"
#include "blah/math/vec2.h" #include "blah/numerics/vec3.h"
#include "blah/math/vec3.h" #include "blah/numerics/vec4.h"
#include "blah/math/vec4.h"
#include "blah/streams/bufferstream.h" #include "blah/streams/bufferstream.h"
#include "blah/streams/filestream.h" #include "blah/streams/filestream.h"

View File

@ -1,15 +1,13 @@
#pragma once #pragma once
#include <memory> #include <blah/common.h>
#include <functional>
#include <blah/core/common.h>
namespace Blah namespace Blah
{ {
// Application Event Functions // Application Event Functions
using AppEventFn = std::function<void()>; using AppEventFn = Func<void()>;
// Application Logging Functions // Application Logging Functions
using AppLogFn = std::function<void(const char* message, Log::Category category)>; using AppLogFn = Func<void(const char* message, Log::Category category)>;
// Application Configuration // Application Configuration
struct Config struct Config
@ -90,8 +88,9 @@ namespace Blah
int max_texture_size = 0; int max_texture_size = 0;
}; };
class FrameBuffer; // Forward declare Target for the BackBuffer
using FrameBufferRef = std::shared_ptr<FrameBuffer>; class Target;
using TargetRef = Ref<Target>;
// Application // Application
namespace App namespace App
@ -145,6 +144,6 @@ namespace Blah
const RendererFeatures& renderer_features(); const RendererFeatures& renderer_features();
// Reference to the window's back buffer // Reference to the window's back buffer
extern const FrameBufferRef backbuffer; extern const TargetRef backbuffer;
} }
} }

56
include/blah/common.h Normal file
View File

@ -0,0 +1,56 @@
#pragma once
#include <cstdint> // for integer types
#include <cstddef> // for size_t type
#include <memory> // for std::shared_ptr
#include <functional> // for std::function
// Asserts
#if defined(DEBUG) || defined(_DEBUG)
#include <cstdlib> // for abort
#define BLAH_ASSERT(condition, msg) \
do { if (!(condition)) { Blah::Log::error("%s\n\tin %s:%d", (msg), __FILE__, __LINE__); abort(); } } while(0)
#else
#define BLAH_ASSERT(condition, msg) \
do { if (!(condition)) { Blah::Log::error("%s\n\tin %s:%d", (msg), __FILE__, __LINE__); } } while(0)
#endif
// maximum length of a print/warn/error message
#ifndef BLAH_MESSAGE
#define BLAH_MESSAGE 1024
#endif
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;
template<typename T>
using Ref = std::shared_ptr<T>;
template<typename T>
using WeakRef = std::weak_ptr<T>;
template<typename T>
using Func = std::function<T>;
namespace Log
{
enum class Category
{
Info,
Warning,
Error
};
void info(const char* message, ...);
void warn(const char* message, ...);
void error(const char* message, ...);
}
}

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <blah/core/common.h> #include <blah/common.h>
#include <new> #include <new>
#include <initializer_list> #include <initializer_list>
@ -16,7 +16,7 @@ namespace Blah
int m_count; int m_count;
public: public:
static inline constexpr size_t MaxCapacity = Capacity; static constexpr size_t capacity = Capacity;
StackVector(); StackVector();
StackVector(const std::initializer_list<T>& init); StackVector(const std::initializer_list<T>& init);
@ -30,7 +30,6 @@ namespace Blah
void clear(); void clear();
int size() const; int size() const;
constexpr int capacity() { return Capacity; }
T* expand(int amount = 1); T* expand(int amount = 1);
void push_back(const T& item); void push_back(const T& item);

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <blah/core/common.h> #include <blah/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
template<int T> template<int T>
class StrOf; class StrOf;
using String = StrOf<64>; using String = StrOf<64>;
using FilePath = StrOf<260>;
// A simple String implementation // A simple String implementation
class Str class Str

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <blah/core/common.h> #include <blah/common.h>
#include <type_traits>
#include <initializer_list> #include <initializer_list>
#include <new> #include <new>
@ -104,7 +103,7 @@ namespace Blah
{ {
m_buffer = nullptr; m_buffer = nullptr;
m_count = m_capacity = 0; m_count = m_capacity = 0;
reserve(list.size()); reserve((int)list.size());
for (auto& it : list) for (auto& it : list)
push_back(std::move(it)); push_back(std::move(it));
} }

View File

@ -1,60 +0,0 @@
#pragma once
#include <cstdint>
// error / abort
#if defined(DEBUG) || defined(_DEBUG)
#include <stdlib.h>
#define BLAH_ERROR(message) \
do { Blah::Log::error(message "\n\tin file: %s:%d", __FILE__, __LINE__); abort(); } while(0)
#define BLAH_ERROR_FMT(message, ...) \
do { Blah::Log::error(message "\n\tin file: %s:%d", __VA_ARGS__, __FILE__, __LINE__); abort(); } while(0)
#else
#define BLAH_ERROR(message) \
Blah::Log::error(message "\n\tin file: %s:%d", __FILE__, __LINE__)
#define BLAH_ERROR_FMT(message, ...) \
Blah::Log::error(message "\n\tin file: %s:%d", __VA_ARGS__, __FILE__, __LINE__)
#endif
#define BLAH_ASSERT(condition, message) \
do { if (!(condition)) { BLAH_ERROR(message); } } while(0)
#define BLAH_ASSERT_FMT(condition, message, ...) \
do { if (!(condition)) { BLAH_ERROR_FMT(message, __VA_ARGS__); } } while(0)
// maximum length of a print/warn/error message
#ifndef BLAH_MESSAGE
#define BLAH_MESSAGE 1024
#endif
namespace Blah
{
using i8 = int8_t;
using i16 = int16_t;
using i32 = int32_t;
using i64 = int64_t;
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
namespace Log
{
enum class Category
{
Info,
Warning,
Error
};
void info(const char* message, ...);
void warn(const char* message, ...);
void error(const char* message, ...);
}
}

View File

@ -1,11 +1,12 @@
#pragma once #pragma once
#include <blah/common.h>
#include <blah/containers/str.h> #include <blah/containers/str.h>
#include <blah/containers/vector.h> #include <blah/containers/vector.h>
namespace Blah namespace Blah
{ {
using FilePath = StrOf<265>; class File;
class FileStream; using FileRef = Ref<File>;
enum class FileMode enum class FileMode
{ {
@ -22,6 +23,41 @@ namespace Blah
Create, Create,
}; };
class File
{
protected:
File() = default;
public:
// Opens a file at the given path.
// If it fails, this will return an empty reference.
static FileRef open(const FilePath& path, FileMode mode);
// checks if the given file exists
static bool exists(const FilePath& path);
// deletes the given file
static bool destroy(const FilePath& path);
// Default Destructor
virtual ~File() = default;
// Gets the File Length
virtual size_t length() = 0;
// Gets the current File Position
virtual size_t position() = 0;
// Seeks to the given position in the File
virtual size_t seek(size_t position) = 0;
// Reads from the File into the buffer, and returns how many bytes were successfully read
virtual size_t read(unsigned char* buffer, size_t length) = 0;
// Writes from the buffer into the File, nd returns how many bytes were successfully written
virtual size_t write(const unsigned char* buffer, size_t length) = 0;
};
namespace Directory namespace Directory
{ {
// Creates a new directory at the given location. // Creates a new directory at the given location.
@ -32,7 +68,7 @@ namespace Blah
bool exists(const FilePath& path); bool exists(const FilePath& path);
// Tries to delete a path and returns whether it was successful // Tries to delete a path and returns whether it was successful
bool remove(const FilePath& path); bool destroy(const FilePath& path);
// Enumerates over a directory and returns a list of files & directories // Enumerates over a directory and returns a list of files & directories
Vector<FilePath> enumerate(const FilePath& path, bool recursive = true); Vector<FilePath> enumerate(const FilePath& path, bool recursive = true);
@ -41,18 +77,6 @@ namespace Blah
void explore(const FilePath& path); void explore(const FilePath& path);
} }
namespace File
{
// Checks if the given file exists
bool exists(const FilePath& path);
// Tries to delete a file and returns whether it was successful
bool remove(const FilePath& path);
// Opens the given file and returns a stream
FileStream open(const FilePath& path, FileMode mode);
}
namespace Path namespace Path
{ {
// Returns the file name of the path // Returns the file name of the path

View File

@ -1,17 +1,17 @@
#pragma once #pragma once
#include <blah/containers/str.h> #include <blah/containers/str.h>
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
#include <blah/math/rect.h> #include <blah/numerics/rect.h>
#include <blah/math/mat3x2.h> #include <blah/numerics/mat3x2.h>
#include <blah/math/mat4x4.h> #include <blah/numerics/mat4x4.h>
#include <blah/math/color.h> #include <blah/numerics/color.h>
#include <blah/graphics/subtexture.h> #include <blah/graphics/subtexture.h>
#include <blah/graphics/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>
#include <blah/graphics/renderpass.h> #include <blah/graphics/renderpass.h>
#include <blah/core/app.h> #include <blah/app.h>
namespace Blah namespace Blah
{ {
@ -125,10 +125,10 @@ namespace Blah
void set_sampler(const TextureSampler& sampler); void set_sampler(const TextureSampler& sampler);
// Draws the batch to the given target // Draws the batch to the given target
void render(const FrameBufferRef& target = App::backbuffer); void render(const TargetRef& target = App::backbuffer);
// Draws the batch to the given target, with the provided matrix // Draws the batch to the given target, with the provided matrix
void render(const FrameBufferRef& target, const Mat4x4& matrix); void render(const TargetRef& target, const Mat4x4& matrix);
// Clears the batch // Clears the batch
void clear(); void clear();

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <blah/core/common.h> #include <blah/common.h>
namespace Blah namespace Blah
{ {

View File

@ -1,72 +0,0 @@
#pragma once
#include <blah/graphics/texture.h>
#include <blah/containers/stackvector.h>
#include <blah/math/color.h>
#include <memory>
namespace Blah
{
enum class ClearMask
{
None = 0,
Color = 1,
Depth = 2,
Stencil = 4,
All = (int)Color | (int)Depth | (int)Stencil
};
// Up to 4 color attachments + 1 depth/stencil
using Attachments = StackVector<TextureRef, 5>;
using AttachmentFormats = StackVector<TextureFormat, 5>;
class FrameBuffer;
using FrameBufferRef = std::shared_ptr<FrameBuffer>;
// FrameBuffer is a 2D Buffer that can be drawn to.
// It can hold up to 4 color Textures, and 1 Depth/Stencil Texture.
class FrameBuffer
{
protected:
FrameBuffer() = default;
public:
// Copy / Moves not allowed
FrameBuffer(const FrameBuffer&) = delete;
FrameBuffer(FrameBuffer&&) = delete;
FrameBuffer& operator=(const FrameBuffer&) = delete;
FrameBuffer& operator=(FrameBuffer&&) = delete;
// Default Destructor
virtual ~FrameBuffer() = default;
// Creates a new FrameBuffer with a single Color attachment
// If the FrameBuffer creation fails, it will return an invalid FrameBufferRef.
static FrameBufferRef create(int width, int height);
// Creates a new FrameBuffer with the given Texture Attachments. You must provide at least one Attachment.
// If the FrameBuffer creation fails, it will return an invalid FrameBufferRef.
static FrameBufferRef create(int width, int height, const AttachmentFormats& attachments);
// Gets the list of Attachments from the FrameBuffer
virtual Attachments& attachments() = 0;
// Gets the list of Attachments from the FrameBuffer
virtual const Attachments& attachments() const = 0;
// Gets the Attachment at a given index from the FrameBuffer
TextureRef& attachment(int index);
// Gets the Attachment at a given index from the FrameBuffer
const TextureRef& attachment(int index) const;
// Gets the width of the FrameBuffer
virtual int width() const;
// Gets the height of the FrameBuffer
virtual int height() const;
// Clears the FrameBuffer
virtual void clear(Color color = Color::black, float depth = 1.0f, u8 stencil = 0, ClearMask mask = ClearMask::All) = 0;
};
}

View File

@ -1,14 +1,14 @@
#pragma once #pragma once
#include <blah/common.h>
#include <blah/graphics/texture.h> #include <blah/graphics/texture.h>
#include <blah/graphics/shader.h> #include <blah/graphics/shader.h>
#include <blah/graphics/sampler.h> #include <blah/graphics/sampler.h>
#include <blah/containers/vector.h> #include <blah/containers/vector.h>
#include <memory>
namespace Blah namespace Blah
{ {
class Material; class Material;
typedef std::shared_ptr<Material> MaterialRef; using MaterialRef = Ref<Material>;
// Materials hold values that can be assigned to a shader during rendering // Materials hold values that can be assigned to a shader during rendering
class Material final class Material final

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <blah/core/common.h> #include <blah/common.h>
#include <memory>
#include <blah/containers/stackvector.h> #include <blah/containers/stackvector.h>
namespace Blah namespace Blah
@ -59,7 +58,7 @@ namespace Blah
}; };
class Mesh; class Mesh;
typedef std::shared_ptr<Mesh> MeshRef; using MeshRef = Ref<Mesh>;
// A Mesh is a set of Indices and Vertices which are used for drawing // A Mesh is a set of Indices and Vertices which are used for drawing
class Mesh class Mesh

View File

@ -1,9 +1,9 @@
#pragma once #pragma once
#include <blah/core/common.h> #include <blah/common.h>
#include <blah/math/rect.h> #include <blah/numerics/rect.h>
#include <blah/containers/str.h> #include <blah/containers/str.h>
#include <blah/graphics/texture.h> #include <blah/graphics/texture.h>
#include <blah/graphics/framebuffer.h> #include <blah/graphics/target.h>
#include <blah/graphics/mesh.h> #include <blah/graphics/mesh.h>
#include <blah/graphics/shader.h> #include <blah/graphics/shader.h>
#include <blah/graphics/material.h> #include <blah/graphics/material.h>
@ -42,7 +42,7 @@ namespace Blah
struct RenderPass struct RenderPass
{ {
// Framebuffer to draw to // Framebuffer to draw to
FrameBufferRef target; TargetRef target;
// Mesh to draw with // Mesh to draw with
MeshRef mesh; MeshRef mesh;

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <blah/common.h>
#include <blah/containers/stackvector.h> #include <blah/containers/stackvector.h>
#include <blah/containers/str.h> #include <blah/containers/str.h>
#include <memory>
namespace Blah namespace Blah
{ {
@ -70,7 +70,7 @@ namespace Blah
}; };
class Shader; class Shader;
typedef std::shared_ptr<Shader> ShaderRef; using ShaderRef = Ref<Shader>;
// A shader used during Rendering // A shader used during Rendering
class Shader class Shader

View File

@ -1,10 +1,10 @@
#pragma once #pragma once
#include <blah/core/common.h> #include <blah/common.h>
#include <blah/containers/str.h> #include <blah/containers/str.h>
#include <blah/containers/vector.h> #include <blah/containers/vector.h>
#include <blah/graphics/subtexture.h> #include <blah/graphics/subtexture.h>
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
#include <blah/core/filesystem.h> #include <blah/filesystem.h>
#include <unordered_map> #include <unordered_map>
namespace Blah namespace Blah

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <blah/graphics/texture.h> #include <blah/graphics/texture.h>
#include <blah/math/rect.h> #include <blah/numerics/rect.h>
namespace Blah namespace Blah
{ {

View File

@ -0,0 +1,72 @@
#pragma once
#include <blah/common.h>
#include <blah/graphics/texture.h>
#include <blah/containers/stackvector.h>
#include <blah/numerics/color.h>
namespace Blah
{
enum class ClearMask
{
None = 0,
Color = 1,
Depth = 2,
Stencil = 4,
All = (int)Color | (int)Depth | (int)Stencil
};
// Up to 4 color textures + 1 depth/stencil
using Attachments = StackVector<TextureRef, 5>;
using AttachmentFormats = StackVector<TextureFormat, 5>;
class Target;
using TargetRef = Ref<Target>;
// Target is a 2D Buffer that can be drawn to.
// It can hold up to 4 color Textures, and 1 Depth/Stencil Texture.
class Target
{
protected:
Target() = default;
public:
// Copy / Moves not allowed
Target(const Target&) = delete;
Target(Target&&) = delete;
Target& operator=(const Target&) = delete;
Target& operator=(Target&&) = delete;
// Default Destructor
virtual ~Target() = default;
// Creates a new Target with a single Color texture
// If the Target creation fails, it will return an invalid TargetRef.
static TargetRef create(int width, int height);
// Creates a new Target with the given Texture Attachments. You must provide at least one Attachment.
// If the Target creation fails, it will return an invalid TargetRef.
static TargetRef create(int width, int height, const AttachmentFormats& textures);
// Gets the list of Attachments from the Target
virtual Attachments& textures() = 0;
// Gets the list of Attachments from the Target
virtual const Attachments& textures() const = 0;
// Gets the Attachment at a given index from the Target
TextureRef& texture(int index);
// Gets the Attachment at a given index from the Target
const TextureRef& texture(int index) const;
// Gets the width of the Target
virtual int width() const;
// Gets the height of the Target
virtual int height() const;
// Clears the Target
virtual void clear(Color color = Color::black, float depth = 1.0f, u8 stencil = 0, ClearMask mask = ClearMask::All) = 0;
};
}

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <memory> #include <blah/common.h>
#include <blah/core/filesystem.h> #include <blah/filesystem.h>
namespace Blah namespace Blah
{ {
@ -28,7 +28,7 @@ namespace Blah
class Image; class Image;
class Stream; class Stream;
class Texture; class Texture;
typedef std::shared_ptr<Texture> TextureRef; using TextureRef = Ref<Texture>;
// A 2D Texture held by the GPU to be used during rendering // A 2D Texture held by the GPU to be used during rendering
class Texture class Texture

View File

@ -1,9 +1,9 @@
#pragma once #pragma once
#include <blah/math/color.h> #include <blah/numerics/color.h>
#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> #include <blah/filesystem.h>
namespace Blah namespace Blah
{ {

View File

@ -2,7 +2,7 @@
#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> #include <blah/filesystem.h>
namespace Blah namespace Blah
{ {

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <blah/math/color.h> #include <blah/numerics/color.h>
#include <blah/math/rectI.h> #include <blah/numerics/rectI.h>
#include <blah/math/point.h> #include <blah/numerics/point.h>
#include <blah/core/filesystem.h> #include <blah/filesystem.h>
namespace Blah namespace Blah
{ {

View File

@ -1,12 +1,12 @@
#pragma once #pragma once
#include <blah/images/image.h> #include <blah/images/image.h>
#include <blah/math/color.h> #include <blah/numerics/color.h>
#include <blah/math/rectI.h> #include <blah/numerics/rectI.h>
#include <blah/math/point.h> #include <blah/numerics/point.h>
#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> #include <blah/filesystem.h>
namespace Blah namespace Blah
{ {

View File

@ -1,8 +1,9 @@
#pragma once #pragma once
#include <blah/core/common.h> #include <blah/common.h>
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
#include <blah/containers/str.h> #include <blah/containers/str.h>
#include <blah/containers/stackvector.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: // which are in turn based on the USB standards:
@ -345,6 +346,306 @@ namespace Blah
Right = 2, Right = 2,
}; };
class InputBinding;
using InputBindingRef = Ref<InputBinding>;
class AxisBinding;
using AxisBindingRef = Ref<AxisBinding>;
class StickBinding;
using StickBindingRef = Ref<StickBinding>;
// Single input Binding
// You must call Binding::update() every frame to poll the input state.
// Alternatively, bindings can be registered to Input which will
// automatically update them.
class InputBinding
{
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;
InputBinding() = default;
InputBinding(float press_buffer)
: press_buffer(press_buffer)
{
}
template<typename ... Args>
InputBinding(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
InputBinding& add(Key key);
// adds a button to the binding
InputBinding& add(ButtonBind button);
// adds an trigger to the binding
InputBinding& add(TriggerBind trigger);
// adds a mouse button to the binding
InputBinding& add(MouseButton mouse);
// adds an input to the binding
template<typename T, typename T2, typename ... Args>
InputBinding& add(T first, T2 second, const Args&... args)
{
add(first);
add(second, args...);
return *this;
}
// adds the left trigger to the binding
InputBinding& add_left_trigger(int controller, float threshold);
// adds the right trigger to the binding
InputBinding& add_right_trigger(int controller, float threshold);
// assigns all the bindings to the specific controller
InputBinding& 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 Input which will
// automatically update them.
class AxisBinding
{
public:
enum class Overlap
{
Newer,
Older,
Cancel
};
// Negative Value Binding
InputBinding negative;
// Positive Value Binding
InputBinding positive;
// How to handle overlaps (ex. Left and Right are both held)
Overlap overlap = Overlap::Newer;
AxisBinding() = default;
AxisBinding(const InputBinding& negative, const InputBinding& 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 Input 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();
};
namespace Input namespace Input
{ {
// Returns the Input State of the current frame. // Returns the Input State of the current frame.
@ -427,5 +728,14 @@ namespace Blah
// returns a string name of the given button // returns a string name of the given button
const char* name_of(Button button); const char* name_of(Button button);
// registers a new binding
InputBindingRef register_binding(const InputBinding& binding);
// registers a new axis binding
AxisBindingRef register_binding(const AxisBinding& binding);
// registers a new stick binding
StickBindingRef register_binding(const StickBinding& binding);
} }
} }

View File

@ -1,299 +0,0 @@
#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();
};
}

View File

@ -1,35 +0,0 @@
#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;
};
}

View File

@ -1,16 +0,0 @@
#pragma once
#include <blah/core/common.h>
namespace Blah
{
class Stopwatch
{
public:
Stopwatch();
void reset();
u64 microseconds();
u64 milliseconds();
private:
u64 start_time;
};
}

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <blah/core/common.h> #include <blah/common.h>
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
namespace Blah namespace Blah
{ {

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
namespace Blah namespace Blah
{ {

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <blah/core/common.h> #include <blah/common.h>
#include <blah/containers/str.h> #include <blah/containers/str.h>
namespace Blah namespace Blah

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <blah/math/calc.h> #include <blah/numerics/calc.h>
#include <blah/core/common.h> #include <blah/common.h>
namespace Blah namespace Blah
{ {
@ -289,7 +289,7 @@ namespace Blah
break; break;
} }
BLAH_ERROR("Invalid Easer Type"); BLAH_ASSERT(false, "Invalid Easer Type");
return nullptr; return nullptr;
} }

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
namespace Blah namespace Blah
{ {

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
namespace Blah namespace Blah
{ {

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <blah/math/point.h> #include <blah/numerics/point.h>
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
#include <blah/math/rectI.h> #include <blah/numerics/rectI.h>
#include <blah/math/line.h> #include <blah/numerics/line.h>
namespace Blah namespace Blah
{ {

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <blah/math/point.h> #include <blah/numerics/point.h>
namespace Blah namespace Blah
{ {

View File

@ -12,28 +12,28 @@ namespace Blah
BufferStream& operator=(BufferStream&& bs) noexcept; BufferStream& operator=(BufferStream&& bs) noexcept;
~BufferStream(); ~BufferStream();
virtual i64 length() const override { return m_length; } virtual size_t length() const override { return m_length; }
virtual i64 position() const override { return m_position; } virtual size_t position() const override { return m_position; }
virtual i64 seek(i64 seekTo) override { return m_position = (seekTo < 0 ? 0 : (seekTo > m_length ? m_length : seekTo)); } virtual size_t seek(size_t 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; }
virtual void close() override; virtual void close() override;
void resize(i64 length); void resize(size_t length);
void clear() { m_length = m_position = 0; } void clear() { m_length = m_position = 0; }
char* data() { return m_buffer; } char* data() { return m_buffer; }
const char* data() const { return m_buffer; } const char* data() const { return m_buffer; }
protected: protected:
virtual i64 read_into(void* ptr, i64 length) override; virtual size_t read_into(void* ptr, size_t length) override;
virtual i64 write_from(const void* ptr, i64 length) override; virtual size_t write_from(const void* ptr, size_t length) override;
private: private:
char* m_buffer; char* m_buffer;
i64 m_capacity; size_t m_capacity;
i64 m_length; size_t m_length;
i64 m_position; size_t m_position;
}; };
} }

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <blah/streams/stream.h> #include <blah/streams/stream.h>
#include <blah/core/filesystem.h> #include <blah/filesystem.h>
namespace Blah namespace Blah
{ {
@ -11,22 +11,21 @@ namespace Blah
FileStream(const FilePath& path, FileMode mode); FileStream(const FilePath& path, FileMode mode);
FileStream(FileStream&& fs) noexcept; FileStream(FileStream&& fs) noexcept;
FileStream& operator=(FileStream&& fs) noexcept; FileStream& operator=(FileStream&& fs) noexcept;
~FileStream();
i64 length() const override; size_t length() const override;
i64 position() const override; size_t position() const override;
i64 seek(i64 seekTo) override; size_t seek(size_t position) override;
bool is_open() const override; bool is_open() const override;
bool is_readable() const override; bool is_readable() const override;
bool is_writable() const override; bool is_writable() const override;
void close() override; void close() override;
protected: protected:
i64 read_into(void* ptr, i64 length) override; size_t read_into(void* ptr, size_t length) override;
i64 write_from(const void* ptr, i64 length) override; size_t write_from(const void* ptr, size_t length) override;
private: private:
FileMode m_mode; FileMode m_mode;
void* m_handle; FileRef m_file;
}; };
} }

View File

@ -7,14 +7,14 @@ namespace Blah
{ {
public: public:
MemoryStream(); MemoryStream();
MemoryStream(char* data, i64 length); MemoryStream(char* data, size_t length);
MemoryStream(MemoryStream&& ms) noexcept; MemoryStream(MemoryStream&& ms) noexcept;
MemoryStream& operator=(MemoryStream&& ms) noexcept; MemoryStream& operator=(MemoryStream&& ms) noexcept;
~MemoryStream() override { m_data = nullptr; m_length = m_position = 0; } ~MemoryStream() override { m_data = nullptr; m_length = m_position = 0; }
i64 length() const override { return m_length; } size_t length() const override { return m_length; }
i64 position() const override { return m_position; } size_t position() const override { return m_position; }
i64 seek(i64 seekTo) override { return m_position = (seekTo < 0 ? 0 : (seekTo > m_length ? m_length : seekTo)); } size_t seek(size_t seekTo) override { return m_position = (seekTo < 0 ? 0 : (seekTo > m_length ? m_length : seekTo)); }
bool is_open() const override { return m_data != nullptr; } bool is_open() const override { return m_data != nullptr; }
bool is_readable() const override { return true; } bool is_readable() const override { return true; }
bool is_writable() const override { return true; } 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:
i64 read_into(void* ptr, i64 length) override; size_t read_into(void* ptr, size_t length) override;
i64 write_from(const void* ptr, i64 length) override; size_t write_from(const void* ptr, size_t length) override;
private: private:
char* m_data; char* m_data;
i64 m_length; size_t m_length;
i64 m_position; size_t m_position;
}; };
} }

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <blah/core/common.h> #include <blah/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 i64 length() const = 0; virtual size_t length() const = 0;
// returns the position of the stream // returns the position of the stream
virtual i64 position() const = 0; virtual size_t position() const = 0;
// seeks the position of the stream // seeks the position of the stream
virtual i64 seek(i64 seek_to) = 0; virtual size_t seek(size_t position) = 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;
@ -37,10 +37,10 @@ namespace Blah
virtual void close() = 0; virtual void close() = 0;
// pipes the contents of this stream to another stream // pipes the contents of this stream to another stream
i64 pipe(Stream& to, i64 length); size_t pipe(Stream& to, size_t 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
i64 read(void* buffer, i64 length) { return read_into(buffer, length); } size_t read(void* buffer, size_t 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
i64 write(const void* buffer, i64 length); size_t write(const void* buffer, size_t length);
// writes the contents of a string to the stream // writes the contents of a string to the stream
i64 write(const String& string); size_t 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>
i64 write(const T& value) size_t 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>
i64 write(const T& value, Endian endian) size_t 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 i64 read_into(void* buffer, i64 length) = 0; virtual size_t read_into(void* buffer, size_t 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 i64 write_from(const void* buffer, i64 length) = 0; virtual size_t write_from(const void* buffer, size_t length) = 0;
}; };
} }

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <blah/core/common.h> #include <blah/common.h>
namespace Blah namespace Blah
{ {
@ -47,4 +47,16 @@ namespace Blah
// returns true between time intervals // returns true between time intervals
static bool between_interval(float interval, float offset = 0); static bool between_interval(float interval, float offset = 0);
}; };
class Stopwatch
{
public:
Stopwatch();
void reset();
u64 microseconds();
u64 milliseconds();
private:
u64 start_time;
};
} }

View File

@ -1,11 +1,11 @@
#include <blah/core/app.h> #include <blah/app.h>
#include <blah/core/common.h> #include <blah/common.h>
#include <blah/core/time.h> #include <blah/time.h>
#include <blah/math/point.h> #include <blah/numerics/point.h>
#include <blah/graphics/framebuffer.h> #include <blah/graphics/target.h>
#include "../internal/platform_backend.h" #include "internal/platform_backend.h"
#include "../internal/graphics_backend.h" #include "internal/graphics_backend.h"
#include "../internal/input_backend.h" #include "internal/input_backend.h"
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
#include <emscripten.h> #include <emscripten.h>
@ -261,21 +261,20 @@ namespace
{ {
// A dummy Frame Buffer that represents the Back Buffer // A dummy Frame Buffer that represents the Back Buffer
// it doesn't actually contain any textures or details. // it doesn't actually contain any textures or details.
class BackBuffer final : public FrameBuffer class BackBuffer final : public Target
{ {
Attachments empty_attachments; Attachments empty_textures;
TextureRef empty_texture;
Attachments& attachments() override Attachments& textures() override
{ {
BLAH_ASSERT(false, "Backbuffer doesn't have any attachments"); BLAH_ASSERT(false, "Backbuffer doesn't have any textures");
return empty_attachments; return empty_textures;
} }
const Attachments& attachments() const override const Attachments& textures() const override
{ {
BLAH_ASSERT(false, "Backbuffer doesn't have any attachments"); BLAH_ASSERT(false, "Backbuffer doesn't have any textures");
return empty_attachments; return empty_textures;
} }
int width() const override int width() const override
@ -296,4 +295,4 @@ namespace
} }
extern const FrameBufferRef App::backbuffer = FrameBufferRef(new BackBuffer()); extern const TargetRef App::backbuffer = TargetRef(new BackBuffer());

View File

@ -1,5 +1,5 @@
#include <blah/core/common.h> #include <blah/common.h>
#include <blah/core/app.h> #include <blah/app.h>
#include <stdarg.h> // for logging methods #include <stdarg.h> // for logging methods
#include <stdio.h> // for sprintf #include <stdio.h> // for sprintf

View File

@ -1,24 +1,24 @@
#include <blah/core/filesystem.h> #include <blah/filesystem.h>
#include <blah/streams/filestream.h> #include <blah/streams/filestream.h>
#include "../internal/platform_backend.h" #include "internal/platform_backend.h"
using namespace Blah; using namespace Blah;
FileRef File::open(const FilePath& path, FileMode mode)
{
return PlatformBackend::file_open(path.cstr(), mode);
}
bool File::exists(const FilePath& path) bool File::exists(const FilePath& path)
{ {
return PlatformBackend::file_exists(path.cstr()); return PlatformBackend::file_exists(path.cstr());
} }
bool File::remove(const FilePath& path) bool File::destroy(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());
@ -29,7 +29,7 @@ bool Directory::exists(const FilePath& path)
return PlatformBackend::dir_exists(path.cstr()); return PlatformBackend::dir_exists(path.cstr());
} }
bool Directory::remove(const FilePath& path) bool Directory::destroy(const FilePath& path)
{ {
return PlatformBackend::dir_delete(path.cstr()); return PlatformBackend::dir_delete(path.cstr());
} }
@ -56,11 +56,11 @@ void Directory::explore(const FilePath& path)
FilePath Path::get_file_name(const FilePath& path) FilePath Path::get_file_name(const FilePath& path)
{ {
const char* cstr = path.cstr(); const char* cstr = path.cstr();
for (int n = path.length() - 2; n >= 0; n --) auto length = path.length();
if (*(cstr + n) == '/')
{ for (auto n = length; n > 0; n--)
return FilePath(cstr + n + 1); if (*(cstr + n - 1) == '/')
} return FilePath(cstr + n);
return path; return path;
} }
@ -85,7 +85,7 @@ FilePath Path::get_directory_name(const FilePath& path)
FilePath directory = path; FilePath directory = path;
while (directory.ends_with("/")) while (directory.ends_with("/"))
directory = directory.substr(0, -1); directory = directory.substr(0, -1);
int last = directory.last_index_of('/'); auto last = directory.last_index_of('/');
if (last >= 0) if (last >= 0)
directory = directory.substr(0, last + 1); directory = directory.substr(0, last + 1);
return directory; return directory;
@ -107,8 +107,8 @@ FilePath Path::normalize(const FilePath& path)
{ {
FilePath normalized; FilePath normalized;
int len = path.length(); auto len = path.length();
for (int n = 0; n < len; n++) for (auto n = 0; n < len; n++)
{ {
// normalize slashes // normalize slashes
if (path[n] == '\\' || path[n] == '/') if (path[n] == '\\' || path[n] == '/')
@ -120,16 +120,19 @@ FilePath Path::normalize(const FilePath& path)
else if (path[n] == '.' && n < len - 1 && path[n + 1] == '.') else if (path[n] == '.' && n < len - 1 && path[n + 1] == '.')
{ {
// search backwards for last / // search backwards for last /
bool couldMoveUp = false; bool could_move_up = false;
for (int k = normalized.length() - 2; k >= 0; k--) if (normalized.length() > 0)
if (normalized[k] == '/')
{ {
normalized = normalized.substr(0, k); for (auto k = normalized.length() - 1; k > 0; k--)
couldMoveUp = true; if (normalized[k - 1] == '/')
{
normalized = normalized.substr(0, k - 1);
could_move_up = true;
break; break;
} }
}
if (!couldMoveUp) if (!could_move_up)
normalized.append('.'); normalized.append('.');
else else
n++; n++;

View File

@ -1,11 +1,11 @@
#include <blah/graphics/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/target.h>
#include <blah/graphics/mesh.h> #include <blah/graphics/mesh.h>
#include <blah/graphics/shader.h> #include <blah/graphics/shader.h>
#include <blah/graphics/material.h> #include <blah/graphics/material.h>
#include <blah/math/calc.h> #include <blah/numerics/calc.h>
#include <blah/core/app.h> #include <blah/app.h>
#include <cmath> #include <cmath>
using namespace Blah; using namespace Blah;
@ -185,7 +185,7 @@ namespace
#define INSERT_BATCH() \ #define INSERT_BATCH() \
do { \ do { \
m_batches.expand(); \ m_batches.expand(); \
for (int i = m_batches.size() - 1; i > m_batch_insert; i --) \ for (auto i = m_batches.size() - 1; i > m_batch_insert; i --) \
m_batches[i] = std::move(m_batches[i - 1]); \ m_batches[i] = std::move(m_batches[i - 1]); \
m_batches[m_batch_insert++] = m_batch; \ m_batches[m_batch_insert++] = m_batch; \
m_batch.offset += m_batch.elements; \ m_batch.offset += m_batch.elements; \
@ -378,7 +378,7 @@ void Batch::set_sampler(const TextureSampler& sampler)
m_batch.sampler = sampler; m_batch.sampler = sampler;
} }
void Batch::render(const FrameBufferRef& target) void Batch::render(const TargetRef& target)
{ {
Point size; Point size;
if (!target) if (!target)
@ -389,7 +389,7 @@ void Batch::render(const FrameBufferRef& target)
render(target, Mat4x4::create_ortho_offcenter(0, (float)size.x, (float)size.y, 0, 0.01f, 1000.0f)); render(target, Mat4x4::create_ortho_offcenter(0, (float)size.x, (float)size.y, 0, 0.01f, 1000.0f));
} }
void Batch::render(const FrameBufferRef& target, const Mat4x4& matrix) void Batch::render(const TargetRef& target, const Mat4x4& matrix)
{ {
// nothing to draw // nothing to draw
if ((m_batches.size() <= 0 && m_batch.elements <= 0) || m_indices.size() <= 0) if ((m_batches.size() <= 0 && m_batch.elements <= 0) || m_indices.size() <= 0)

View File

@ -1,53 +0,0 @@
#include <blah/graphics/framebuffer.h>
#include "../internal/graphics_backend.h"
using namespace Blah;
FrameBufferRef FrameBuffer::create(int width, int height)
{
return create(width, height, { TextureFormat::RGBA });
}
FrameBufferRef FrameBuffer::create(int width, int height, const AttachmentFormats& attachments)
{
BLAH_ASSERT(width > 0 && height > 0, "FrameBuffer width and height must be larger than 0");
BLAH_ASSERT(attachments.size() > 0, "At least one attachment must be provided");
int color_count = 0;
int depth_count = 0;
for (int i = 0; i < attachments.size(); i++)
{
BLAH_ASSERT((int)attachments[i] > (int)TextureFormat::None && (int)attachments[i] < (int)TextureFormat::Count, "Invalid texture format");
if (attachments[i] == TextureFormat::DepthStencil)
depth_count++;
else
color_count++;
}
BLAH_ASSERT(depth_count <= 1, "FrameBuffer can only have 1 Depth/Stencil Texture");
BLAH_ASSERT(color_count <= Attachments::MaxCapacity - 1, "Exceeded maximum Color attachment count");
return GraphicsBackend::create_framebuffer(width, height, attachments.data(), attachments.size());
}
TextureRef& FrameBuffer::attachment(int index)
{
return attachments()[index];
}
const TextureRef& FrameBuffer::attachment(int index) const
{
return attachments()[index];
}
int FrameBuffer::width() const
{
return attachments()[0]->width();
}
int FrameBuffer::height() const
{
return attachments()[0]->height();
}

View File

@ -1,5 +1,5 @@
#include <blah/graphics/material.h> #include <blah/graphics/material.h>
#include <blah/core/common.h> #include <blah/common.h>
#include <cstring> #include <cstring>
using namespace Blah; using namespace Blah;
@ -19,7 +19,7 @@ namespace
case UniformType::Mat3x2: components = 6; break; case UniformType::Mat3x2: components = 6; break;
case UniformType::Mat4x4: components = 16; break; case UniformType::Mat4x4: components = 16; break;
default: default:
BLAH_ERROR("Unespected Uniform Type"); BLAH_ASSERT(false, "Unespected Uniform Type");
break; break;
} }

View File

@ -1,5 +1,5 @@
#include <blah/graphics/renderpass.h> #include <blah/graphics/renderpass.h>
#include <blah/core/common.h> #include <blah/common.h>
#include "../internal/graphics_backend.h" #include "../internal/graphics_backend.h"
using namespace Blah; using namespace Blah;
@ -66,11 +66,7 @@ void RenderPass::perform()
} }
// get the total drawable size // get the total drawable size
Vec2 draw_size; auto draw_size = Vec2(pass.target->width(), pass.target->height());
if (!pass.target)
draw_size = Vec2(App::draw_width(), App::draw_height());
else
draw_size = Vec2(pass.target->width(), pass.target->height());
// Validate Viewport // Validate Viewport
if (!pass.has_viewport) if (!pass.has_viewport)

View File

@ -1,5 +1,5 @@
#include <blah/graphics/shader.h> #include <blah/graphics/shader.h>
#include <blah/core/app.h> #include <blah/app.h>
#include "../internal/graphics_backend.h" #include "../internal/graphics_backend.h"
using namespace Blah; using namespace Blah;
@ -21,7 +21,8 @@ ShaderRef Shader::create(const ShaderData& data)
for (auto& it : uniforms) for (auto& it : uniforms)
if (it.type == UniformType::None) if (it.type == UniformType::None)
{ {
BLAH_ERROR_FMT("Uniform '%s' has an invalid type!\n\tOnly Float/Float2/Float3/Float4/Mat3x2/Mat4x4/Texture are allowed!", it.name.cstr()); auto error = String::fmt("Uniform '%s' has an invalid type!\n\tOnly Float/Float2/Float3/Float4/Mat3x2/Mat4x4/Texture are allowed!", it.name.cstr());
BLAH_ASSERT(false, error.cstr());
return ShaderRef(); return ShaderRef();
} }
@ -30,7 +31,8 @@ ShaderRef Shader::create(const ShaderData& data)
for (int j = i + 1; j < uniforms.size(); j ++) for (int j = i + 1; j < uniforms.size(); j ++)
if (uniforms[i].name == uniforms[j].name) if (uniforms[i].name == uniforms[j].name)
{ {
BLAH_ERROR_FMT("Shader Uniform names '%s' overlap! All Names must be unique.", uniforms[0].name.cstr()); auto error = String::fmt("Shader Uniform names '%s' overlap! All Names must be unique.", uniforms[0].name.cstr());
BLAH_ASSERT(false, error.cstr());
return ShaderRef(); return ShaderRef();
} }
} }

View File

@ -1,7 +1,7 @@
#include <blah/graphics/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/common.h> #include <blah/common.h>
using namespace Blah; using namespace Blah;
@ -123,7 +123,7 @@ float SpriteFont::width_of_line(const String& text, int start) const
float width = 0; float width = 0;
Codepoint last = 0; Codepoint last = 0;
for (int i = start; i < text.length(); i ++) for (auto i = start; i < text.length(); i ++)
{ {
if (text[i] == '\n') if (text[i] == '\n')
return width; return width;
@ -139,7 +139,9 @@ float SpriteFont::width_of_line(const String& text, int start) const
width += get_kerning(last, next); width += get_kerning(last, next);
// move to thext utf8 character // move to thext utf8 character
i += text.utf8_length(i) - 1; auto len = text.utf8_length(i);
if (len > 0)
i += len - 1;
last = next; last = next;
} }
@ -153,7 +155,7 @@ float SpriteFont::height_of(const String& text) const
return 0; return 0;
float height = line_height(); float height = line_height();
for (int i = 0; i < text.length(); i ++) for (auto i = 0; i < text.length(); i ++)
{ {
if (text[i] == '\n') if (text[i] == '\n')
height += line_height(); height += line_height();

View File

@ -1,5 +1,5 @@
#include <blah/graphics/subtexture.h> #include <blah/graphics/subtexture.h>
#include <blah/math/calc.h> #include <blah/numerics/calc.h>
using namespace Blah; using namespace Blah;

53
src/graphics/target.cpp Normal file
View File

@ -0,0 +1,53 @@
#include <blah/graphics/target.h>
#include "../internal/graphics_backend.h"
using namespace Blah;
TargetRef Target::create(int width, int height)
{
return create(width, height, { TextureFormat::RGBA });
}
TargetRef Target::create(int width, int height, const AttachmentFormats& textures)
{
BLAH_ASSERT(width > 0 && height > 0, "Target width and height must be larger than 0");
BLAH_ASSERT(textures.size() > 0, "At least one texture must be provided");
int color_count = 0;
int depth_count = 0;
for (int i = 0; i < textures.size(); i++)
{
BLAH_ASSERT((int)textures[i] > (int)TextureFormat::None && (int)textures[i] < (int)TextureFormat::Count, "Invalid texture format");
if (textures[i] == TextureFormat::DepthStencil)
depth_count++;
else
color_count++;
}
BLAH_ASSERT(depth_count <= 1, "Target can only have 1 Depth/Stencil Texture");
BLAH_ASSERT(color_count <= Attachments::capacity - 1, "Exceeded maximum Color texture count");
return GraphicsBackend::create_target(width, height, textures.data(), textures.size());
}
TextureRef& Target::texture(int index)
{
return textures()[index];
}
const TextureRef& Target::texture(int index) const
{
return textures()[index];
}
int Target::width() const
{
return textures()[0]->width();
}
int Target::height() const
{
return textures()[0]->height();
}

View File

@ -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/common.h> #include <blah/common.h>
#include "../internal/graphics_backend.h" #include "../internal/graphics_backend.h"
using namespace Blah; using namespace Blah;

View File

@ -1,8 +1,8 @@
#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/filesystem.h>
#include <blah/core/common.h> #include <blah/common.h>
#include <blah/math/calc.h> #include <blah/numerics/calc.h>
#define STBI_NO_STDIO #define STBI_NO_STDIO
#define STBI_ONLY_ZLIB #define STBI_ONLY_ZLIB
@ -81,7 +81,7 @@ void Aseprite::parse(Stream& stream)
{ {
if (!stream.is_readable()) if (!stream.is_readable())
{ {
BLAH_ERROR("Stream is not readable"); BLAH_ASSERT(false, "Stream is not readable");
return; return;
} }
@ -96,7 +96,7 @@ void Aseprite::parse(Stream& stream)
auto magic = stream.read<u16>(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_ASSERT(false, "File is not a valid Aseprite file");
return; return;
} }
@ -133,7 +133,7 @@ void Aseprite::parse(Stream& stream)
auto magic = stream.read<u16>(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_ASSERT(false, "File is not a valid Aseprite file");
return; return;
} }
@ -247,7 +247,7 @@ void Aseprite::parse_cel(Stream& stream, int frameIndex, size_t maxPosition)
if (res < 0) if (res < 0)
{ {
BLAH_ERROR("Unable to parse Aseprite file"); BLAH_ASSERT(false, "Unable to parse Aseprite file");
return; return;
} }
} }
@ -460,6 +460,6 @@ void Aseprite::render_cel(Cel* cel, Frame* frame)
} }
else else
{ {
BLAH_ERROR("Aseprite blendmodes aren't implemented"); BLAH_ASSERT(false, "Aseprite blendmodes aren't implemented");
} }
} }

View File

@ -1,7 +1,7 @@
#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/numerics/calc.h>
#include <blah/core/common.h> #include <blah/common.h>
using namespace Blah; using namespace Blah;
@ -111,7 +111,7 @@ void Font::load(Stream& stream)
if (!stream.is_readable()) if (!stream.is_readable())
{ {
BLAH_ERROR("Unable to load a font as the Stream was not readable"); BLAH_ASSERT(false, "Unable to load a font as the Stream was not readable");
return; return;
} }

View File

@ -1,7 +1,7 @@
#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/common.h> #include <blah/common.h>
using namespace Blah; using namespace Blah;
@ -148,7 +148,7 @@ void Image::from_stream(Stream& stream)
if (!stream.is_readable()) if (!stream.is_readable())
{ {
BLAH_ERROR("Unable to load image as the Stream was not readable"); BLAH_ASSERT(false, "Unable to load image as the Stream was not readable");
return; return;
} }
@ -162,7 +162,7 @@ void Image::from_stream(Stream& stream)
if (data == nullptr) if (data == nullptr)
{ {
BLAH_ERROR("Unable to load image as the Stream's data was not a valid image"); BLAH_ASSERT(false, "Unable to load image as the Stream's data was not a valid image");
return; return;
} }

View File

@ -1,5 +1,5 @@
#include <blah/images/packer.h> #include <blah/images/packer.h>
#include <blah/core/common.h> #include <blah/common.h>
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
@ -169,7 +169,7 @@ void Packer::pack()
// make sure the largest isn't too large // make sure the largest isn't too large
if (sources[0]->packed.w + padding * 2 > max_size || sources[0]->packed.h + padding * 2 > max_size) if (sources[0]->packed.w + padding * 2 > max_size || sources[0]->packed.h + padding * 2 > max_size)
{ {
BLAH_ERROR("Source image is larger than max atlas size"); BLAH_ASSERT(false, "Source image is larger than max atlas size");
return; return;
} }

937
src/input.cpp Normal file
View File

@ -0,0 +1,937 @@
#include <blah/input.h>
#include <blah/app.h>
#include <blah/time.h>
#include <blah/common.h>
#include <blah/numerics/point.h>
#include <blah/numerics/calc.h>
#include "internal/input_backend.h"
#include <cstring>
using namespace Blah;
namespace
{
InputState g_last_state;
InputState g_curr_state;
InputState g_next_state;
InputState g_empty_state;
ControllerState g_empty_controller;
Vector<WeakRef<InputBinding>> g_bindings;
Vector<WeakRef<AxisBinding>> g_axes;
Vector<WeakRef<StickBinding>> g_sticks;
}
void InputBackend::init()
{
g_empty_controller.name = "Disconnected";
for (int i = 0; i < Blah::Input::max_controllers; i++)
g_empty_state.controllers[i].name = g_empty_controller.name;
g_last_state = g_empty_state;
g_curr_state = g_empty_state;
g_next_state = g_empty_state;
g_bindings.dispose();
g_axes.dispose();
g_sticks.dispose();
}
void InputBackend::frame()
{
// cycle states
g_last_state = g_curr_state;
g_curr_state = g_next_state;
// copy state, clear pressed / released values
{
for (int i = 0; i < Blah::Input::max_keyboard_keys; i++)
{
g_next_state.keyboard.pressed[i] = false;
g_next_state.keyboard.released[i] = false;
}
for (int i = 0; i < Blah::Input::max_mouse_buttons; i++)
{
g_next_state.mouse.pressed[i] = false;
g_next_state.mouse.released[i] = false;
}
g_next_state.mouse.wheel = Point::zero;
g_next_state.keyboard.text.clear();
for (int i = 0; i < Blah::Input::max_controllers; i++)
{
ControllerState* controller = &(g_next_state.controllers[i]);
if (!controller->is_connected)
controller->name = nullptr;
for (int j = 0; j < Blah::Input::max_controller_buttons; j++)
{
controller->pressed[j] = false;
controller->released[j] = false;
}
}
}
// update bindings
for (int i = 0; i < g_bindings.size(); i++)
{
if (g_bindings[i].use_count() <= 0)
{
g_bindings.erase(i);
i--;
}
else if (auto binding = g_bindings[i].lock())
{
binding->update();
}
}
for (int i = 0; i < g_axes.size(); i++)
{
if (g_axes[i].use_count() <= 0)
{
g_axes.erase(i);
i--;
}
else if (auto binding = g_axes[i].lock())
{
binding->update();
}
}
for (int i = 0; i < g_sticks.size(); i++)
{
if (g_sticks[i].use_count() <= 0)
{
g_sticks.erase(i);
i--;
}
else if (auto binding = g_sticks[i].lock())
{
binding->update();
}
}
}
void InputBackend::on_mouse_move(float x, float y)
{
g_next_state.mouse.position.x = x;
g_next_state.mouse.position.y = y;
Point size = Point(App::width(), App::height());
Point draw = Point(App::draw_width(), App::draw_height());
g_next_state.mouse.draw_position.x = (x / (float)size.x) * draw.x;
g_next_state.mouse.draw_position.y = (y / (float)size.y) * draw.y;
}
void InputBackend::on_mouse_screen_move(float x, float y)
{
g_next_state.mouse.screen_position.x = x;
g_next_state.mouse.screen_position.y = y;
}
void InputBackend::on_mouse_down(MouseButton button)
{
int i = (int)button;
if (i >= 0 && i < Blah::Input::max_mouse_buttons)
{
g_next_state.mouse.down[i] = true;
g_next_state.mouse.pressed[i] = true;
g_next_state.mouse.timestamp[i] = Time::ticks;
}
}
void InputBackend::on_mouse_up(MouseButton button)
{
int i = (int)button;
if (i >= 0 && i < Blah::Input::max_mouse_buttons)
{
g_next_state.mouse.down[i] = false;
g_next_state.mouse.released[i] = true;
}
}
void InputBackend::on_key_down(Key key)
{
int i = (int)key;
if (i >= 0 && i < Blah::Input::max_keyboard_keys)
{
g_next_state.keyboard.down[i] = true;
g_next_state.keyboard.pressed[i] = true;
g_next_state.keyboard.timestamp[i] = Time::ticks;
}
}
void InputBackend::on_mouse_wheel(Point wheel)
{
g_next_state.mouse.wheel = wheel;
}
void InputBackend::on_key_up(Key key)
{
int i = (int)key;
if (i >= 0 && i < Blah::Input::max_keyboard_keys)
{
g_next_state.keyboard.down[i] = false;
g_next_state.keyboard.released[i] = true;
}
}
void InputBackend::on_text_utf8(const char* text)
{
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, u16 vendor, u16 product, u16 version)
{
if (index < Blah::Input::max_controllers)
{
ControllerState* controller = &(g_next_state.controllers[index]);
*controller = g_empty_controller;
controller->name = name;
controller->is_connected = true;
controller->is_gamepad = is_gamepad;
controller->button_count = button_count;
controller->axis_count = axis_count;
controller->vendor = vendor;
controller->product = product;
controller->version = version;
}
}
void InputBackend::on_controller_disconnect(int index)
{
if (index < Blah::Input::max_controllers)
g_next_state.controllers[index] = g_empty_controller;
}
void InputBackend::on_button_down(int index, int button)
{
if (index < Blah::Input::max_controllers &&
button < Blah::Input::max_controller_buttons &&
g_next_state.controllers[index].is_connected &&
button < g_next_state.controllers[index].button_count)
{
g_next_state.controllers[index].down[button] = true;
g_next_state.controllers[index].pressed[button] = true;
g_next_state.controllers[index].button_timestamp[button] = Time::ticks;
}
}
void InputBackend::on_button_up(int index, int button)
{
if (index < Blah::Input::max_controllers &&
button < Blah::Input::max_controller_buttons &&
g_next_state.controllers[index].is_connected &&
button < g_next_state.controllers[index].button_count)
{
g_next_state.controllers[index].down[button] = false;
g_next_state.controllers[index].released[button] = true;
}
}
void InputBackend::on_axis_move(int index, int axis, float value)
{
if (index < Blah::Input::max_controllers &&
axis < Blah::Input::max_controller_axis &&
g_next_state.controllers[index].is_connected &&
axis < g_next_state.controllers[index].axis_count)
{
g_next_state.controllers[index].axis[axis] = value;
g_next_state.controllers[index].axis_timestamp[axis] = Time::ticks;
}
}
const InputState* Input::state()
{
return &g_curr_state;
}
const InputState* Input::last_state()
{
return &g_last_state;
}
Vec2 Input::mouse()
{
return g_curr_state.mouse.position;
}
Vec2 Input::mouse_draw()
{
return Vec2(g_curr_state.mouse.draw_position);
}
Vec2 Input::mouse_screen()
{
return Vec2(g_curr_state.mouse.screen_position);
}
bool Input::pressed(MouseButton button)
{
int i = (int)button;
return i >= 0 && i < Blah::Input::max_mouse_buttons&& g_curr_state.mouse.pressed[i];
}
bool Input::down(MouseButton button)
{
int i = (int)button;
return i >= 0 && i < Blah::Input::max_mouse_buttons&& g_curr_state.mouse.down[i];
}
bool Input::released(MouseButton button)
{
int i = (int)button;
return i >= 0 && i < Blah::Input::max_mouse_buttons&& g_curr_state.mouse.released[i];
}
Point Input::mouse_wheel()
{
return g_curr_state.mouse.wheel;
}
bool Input::pressed(Key key)
{
int i = (int)key;
return i > 0 && i < Blah::Input::max_keyboard_keys&& g_curr_state.keyboard.pressed[i];
}
bool Input::down(Key key)
{
int i = (int)key;
return i > 0 && i < Blah::Input::max_keyboard_keys&& g_curr_state.keyboard.down[i];
}
bool Input::released(Key key)
{
int i = (int)key;
return i > 0 && i < Blah::Input::max_keyboard_keys&& g_curr_state.keyboard.released[i];
}
bool Input::ctrl()
{
return down(Key::LeftControl) || down(Key::RightControl);
}
bool Input::shift()
{
return down(Key::LeftShift) || down(Key::RightShift);
}
bool Input::alt()
{
return down(Key::LeftAlt) || down(Key::RightAlt);
}
const char* Input::text()
{
return g_curr_state.keyboard.text;
}
const ControllerState* Input::controller(int controllerIndex)
{
if (controllerIndex >= Blah::Input::max_controllers)
{
Log::warn("Trying to access a out-of-range controller at %i", controllerIndex);
return &g_empty_controller;
}
else if (!g_curr_state.controllers[controllerIndex].is_connected)
{
return &g_empty_controller;
}
else
{
return &g_curr_state.controllers[controllerIndex];
}
}
bool Input::pressed(int controllerIndex, Button button)
{
int i = (int)button;
if (controllerIndex < Blah::Input::max_controllers && i >= 0 && i < Blah::Input::max_controller_buttons)
return g_curr_state.controllers[controllerIndex].pressed[i];
return false;
}
bool Input::down(int controllerIndex, Button button)
{
int i = (int)button;
if (controllerIndex < Blah::Input::max_controllers && i >= 0 && i < Blah::Input::max_controller_buttons)
return g_curr_state.controllers[controllerIndex].down[i];
return false;
}
bool Input::released(int controllerIndex, Button button)
{
int i = (int)button;
if (controllerIndex < Blah::Input::max_controllers && i >= 0 && i < Blah::Input::max_controller_buttons)
return g_curr_state.controllers[controllerIndex].released[i];
return false;
}
float Input::axis_check(int controllerIndex, Axis axis)
{
int i = (int)axis;
if (controllerIndex < Blah::Input::max_controllers && i >= 0 && i < Blah::Input::max_controller_axis)
return g_curr_state.controllers[controllerIndex].axis[i];
return 0;
}
int Input::axis_check(int fallback, Key negative, Key positive)
{
if (Input::pressed(positive))
return 1;
else if (Input::pressed(negative))
return -1;
else
{
bool pos = Input::down(positive);
bool neg = Input::down(negative);
if (pos && neg)
return fallback;
else if (pos)
return 1;
else if (neg)
return -1;
else
return 0;
}
}
int Input::axis_check(int fallback, int controllerIndex, Button negative, Button positive)
{
if (Input::pressed(controllerIndex, positive))
return 1;
else if (Input::pressed(controllerIndex, negative))
return -1;
else
{
bool pos = Input::down(controllerIndex, positive);
bool neg = Input::down(controllerIndex, negative);
if (pos && neg)
return fallback;
else if (pos)
return 1;
else if (neg)
return -1;
else
return 0;
}
}
const char* Input::name_of(Key key)
{
switch (key)
{
#define DEFINE_KEY(name, value) case Key::name: return #name;
BLAH_KEY_DEFINITIONS
#undef DEFINE_KEY
}
return "Unknown";
}
const char* Input::name_of(Button button)
{
switch (button)
{
#define DEFINE_BTN(name, value) case Button::name: return #name;
BLAH_BUTTON_DEFINITIONS
#undef DEFINE_BTN
}
return "Unknown";
}
InputBindingRef Input::register_binding(const InputBinding& binding)
{
auto result = std::make_shared<InputBinding>(binding);
g_bindings.push_back(WeakRef<InputBinding>(result));
return result;
}
AxisBindingRef Input::register_binding(const AxisBinding& binding)
{
auto result = std::make_shared<AxisBinding>(binding);
g_axes.push_back(WeakRef<AxisBinding>(result));
return result;
}
StickBindingRef Input::register_binding(const StickBinding& binding)
{
auto result = std::make_shared<StickBinding>(binding);
g_sticks.push_back(WeakRef<StickBinding>(result));
return result;
}
InputBinding::TriggerBind::TriggerBind(Axis axis)
: axis(axis)
{
}
InputBinding::TriggerBind::TriggerBind(int controller, Axis axis, float threshold, bool positive)
: controller(controller), axis(axis), threshold(threshold), positive(positive)
{
}
bool InputBinding::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;
}
InputBinding::ButtonBind::ButtonBind(Button button)
: button(button) {}
InputBinding::ButtonBind::ButtonBind(int controller, Button button)
: controller(controller), button(button) {}
bool InputBinding::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 InputBinding::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 InputBinding::down() const
{
return m_down;
}
float InputBinding::value() const
{
return m_value;
}
int InputBinding::sign() const
{
return (int)Calc::sign(m_value);
}
double InputBinding::timestamp() const
{
return m_last_timestamp;
}
void InputBinding::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 InputBinding::consume_press()
{
m_press_consumed = true;
m_last_press_time = -1;
}
void InputBinding::consume_release()
{
m_release_consumed = true;
m_last_release_time = -1;
}
InputBinding& InputBinding::add(Key key)
{
keys.push_back(key);
return *this;
}
InputBinding& InputBinding::add(ButtonBind button)
{
buttons.push_back(button);
return *this;
}
InputBinding& InputBinding::add(TriggerBind trigger)
{
triggers.push_back(trigger);
return *this;
}
InputBinding& InputBinding::add(MouseButton button)
{
mouse.push_back(button);
return *this;
}
InputBinding& InputBinding::add_left_trigger(int controller, float threshold)
{
triggers.push_back(TriggerBind(controller, Axis::LeftTrigger, threshold, true));
return *this;
}
InputBinding& InputBinding::add_right_trigger(int controller, float threshold)
{
triggers.push_back(TriggerBind(controller, Axis::RightTrigger, threshold, true));
return *this;
}
InputBinding& InputBinding::set_controller(int index)
{
for (auto& it : buttons)
it.controller = index;
for (auto& it : triggers)
it.controller = index;
return *this;
}
void InputBinding::clear()
{
keys.clear();
buttons.clear();
triggers.clear();
mouse.clear();
}
bool InputBinding::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 InputBinding::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 InputBinding::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 InputBinding::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(InputBinding::TriggerBind(controller, Axis::LeftX, threshold, false));
positive.add(InputBinding::TriggerBind(controller, Axis::LeftX, threshold, true));
return *this;
}
AxisBinding& AxisBinding::add_left_stick_y(int controller, float threshold)
{
negative.add(InputBinding::TriggerBind(controller, Axis::LeftY, threshold, false));
positive.add(InputBinding::TriggerBind(controller, Axis::LeftY, threshold, true));
return *this;
}
AxisBinding& AxisBinding::add_right_stick_x(int controller, float threshold)
{
negative.add(InputBinding::TriggerBind(controller, Axis::RightX, threshold, false));
positive.add(InputBinding::TriggerBind(controller, Axis::RightX, threshold, true));
return *this;
}
AxisBinding& AxisBinding::add_right_stick_y(int controller, float threshold)
{
negative.add(InputBinding::TriggerBind(controller, Axis::RightY, threshold, false));
positive.add(InputBinding::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(InputBinding::ButtonBind(controller, Button::Left));
x.positive.add(InputBinding::ButtonBind(controller, Button::Right));
y.negative.add(InputBinding::ButtonBind(controller, Button::Up));
y.positive.add(InputBinding::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();
}

View File

@ -1,469 +0,0 @@
#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();
}

View File

@ -1,70 +0,0 @@
#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();
}
}
}

View File

@ -1,406 +0,0 @@
#include <blah/input/input.h>
#include <blah/input/binding_registry.h>
#include <blah/core/app.h>
#include <blah/core/time.h>
#include <blah/core/common.h>
#include <blah/math/point.h>
#include "../internal/input_backend.h"
#include <cstring>
using namespace Blah;
namespace
{
InputState g_last_state;
InputState g_curr_state;
InputState g_next_state;
InputState g_empty_state;
ControllerState g_empty_controller;
}
void InputBackend::init()
{
g_empty_controller.name = "Disconnected";
for (int i = 0; i < Blah::Input::max_controllers; i++)
g_empty_state.controllers[i].name = g_empty_controller.name;
g_last_state = g_empty_state;
g_curr_state = g_empty_state;
g_next_state = g_empty_state;
}
void InputBackend::frame()
{
// cycle states
g_last_state = g_curr_state;
g_curr_state = g_next_state;
// copy state, clear pressed / released values
{
for (int i = 0; i < Blah::Input::max_keyboard_keys; i++)
{
g_next_state.keyboard.pressed[i] = false;
g_next_state.keyboard.released[i] = false;
}
for (int i = 0; i < Blah::Input::max_mouse_buttons; i++)
{
g_next_state.mouse.pressed[i] = false;
g_next_state.mouse.released[i] = false;
}
g_next_state.mouse.wheel = Point::zero;
g_next_state.keyboard.text.clear();
for (int i = 0; i < Blah::Input::max_controllers; i++)
{
ControllerState* controller = &(g_next_state.controllers[i]);
if (!controller->is_connected)
controller->name = nullptr;
for (int j = 0; j < Blah::Input::max_controller_buttons; j++)
{
controller->pressed[j] = false;
controller->released[j] = false;
}
}
}
// update bindings
BindingRegistry::update();
}
void InputBackend::on_mouse_move(float x, float y)
{
g_next_state.mouse.position.x = x;
g_next_state.mouse.position.y = y;
Point size = Point(App::width(), App::height());
Point draw = Point(App::draw_width(), App::draw_height());
g_next_state.mouse.draw_position.x = (x / (float)size.x) * draw.x;
g_next_state.mouse.draw_position.y = (y / (float)size.y) * draw.y;
}
void InputBackend::on_mouse_screen_move(float x, float y)
{
g_next_state.mouse.screen_position.x = x;
g_next_state.mouse.screen_position.y = y;
}
void InputBackend::on_mouse_down(MouseButton button)
{
int i = (int)button;
if (i >= 0 && i < Blah::Input::max_mouse_buttons)
{
g_next_state.mouse.down[i] = true;
g_next_state.mouse.pressed[i] = true;
g_next_state.mouse.timestamp[i] = Time::ticks;
}
}
void InputBackend::on_mouse_up(MouseButton button)
{
int i = (int)button;
if (i >= 0 && i < Blah::Input::max_mouse_buttons)
{
g_next_state.mouse.down[i] = false;
g_next_state.mouse.released[i] = true;
}
}
void InputBackend::on_key_down(Key key)
{
int i = (int)key;
if (i >= 0 && i < Blah::Input::max_keyboard_keys)
{
g_next_state.keyboard.down[i] = true;
g_next_state.keyboard.pressed[i] = true;
g_next_state.keyboard.timestamp[i] = Time::ticks;
}
}
void InputBackend::on_mouse_wheel(Point wheel)
{
g_next_state.mouse.wheel = wheel;
}
void InputBackend::on_key_up(Key key)
{
int i = (int)key;
if (i >= 0 && i < Blah::Input::max_keyboard_keys)
{
g_next_state.keyboard.down[i] = false;
g_next_state.keyboard.released[i] = true;
}
}
void InputBackend::on_text_utf8(const char* text)
{
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, u16 vendor, u16 product, u16 version)
{
if (index < Blah::Input::max_controllers)
{
ControllerState* controller = &(g_next_state.controllers[index]);
*controller = g_empty_controller;
controller->name = name;
controller->is_connected = true;
controller->is_gamepad = is_gamepad;
controller->button_count = button_count;
controller->axis_count = axis_count;
controller->vendor = vendor;
controller->product = product;
controller->version = version;
}
}
void InputBackend::on_controller_disconnect(int index)
{
if (index < Blah::Input::max_controllers)
g_next_state.controllers[index] = g_empty_controller;
}
void InputBackend::on_button_down(int index, int button)
{
if (index < Blah::Input::max_controllers &&
button < Blah::Input::max_controller_buttons &&
g_next_state.controllers[index].is_connected &&
button < g_next_state.controllers[index].button_count)
{
g_next_state.controllers[index].down[button] = true;
g_next_state.controllers[index].pressed[button] = true;
g_next_state.controllers[index].button_timestamp[button] = Time::ticks;
}
}
void InputBackend::on_button_up(int index, int button)
{
if (index < Blah::Input::max_controllers &&
button < Blah::Input::max_controller_buttons &&
g_next_state.controllers[index].is_connected &&
button < g_next_state.controllers[index].button_count)
{
g_next_state.controllers[index].down[button] = false;
g_next_state.controllers[index].released[button] = true;
}
}
void InputBackend::on_axis_move(int index, int axis, float value)
{
if (index < Blah::Input::max_controllers &&
axis < Blah::Input::max_controller_axis &&
g_next_state.controllers[index].is_connected &&
axis < g_next_state.controllers[index].axis_count)
{
g_next_state.controllers[index].axis[axis] = value;
g_next_state.controllers[index].axis_timestamp[axis] = Time::ticks;
}
}
const InputState* Input::state()
{
return &g_curr_state;
}
const InputState* Input::last_state()
{
return &g_last_state;
}
Vec2 Input::mouse()
{
return g_curr_state.mouse.position;
}
Vec2 Input::mouse_draw()
{
return Vec2(g_curr_state.mouse.draw_position);
}
Vec2 Input::mouse_screen()
{
return Vec2(g_curr_state.mouse.screen_position);
}
bool Input::pressed(MouseButton button)
{
int i = (int)button;
return i >= 0 && i < Blah::Input::max_mouse_buttons&& g_curr_state.mouse.pressed[i];
}
bool Input::down(MouseButton button)
{
int i = (int)button;
return i >= 0 && i < Blah::Input::max_mouse_buttons&& g_curr_state.mouse.down[i];
}
bool Input::released(MouseButton button)
{
int i = (int)button;
return i >= 0 && i < Blah::Input::max_mouse_buttons&& g_curr_state.mouse.released[i];
}
Point Input::mouse_wheel()
{
return g_curr_state.mouse.wheel;
}
bool Input::pressed(Key key)
{
int i = (int)key;
return i > 0 && i < Blah::Input::max_keyboard_keys&& g_curr_state.keyboard.pressed[i];
}
bool Input::down(Key key)
{
int i = (int)key;
return i > 0 && i < Blah::Input::max_keyboard_keys&& g_curr_state.keyboard.down[i];
}
bool Input::released(Key key)
{
int i = (int)key;
return i > 0 && i < Blah::Input::max_keyboard_keys&& g_curr_state.keyboard.released[i];
}
bool Input::ctrl()
{
return down(Key::LeftControl) || down(Key::RightControl);
}
bool Input::shift()
{
return down(Key::LeftShift) || down(Key::RightShift);
}
bool Input::alt()
{
return down(Key::LeftAlt) || down(Key::RightAlt);
}
const char* Input::text()
{
return g_curr_state.keyboard.text;
}
const ControllerState* Input::controller(int controllerIndex)
{
if (controllerIndex >= Blah::Input::max_controllers)
{
Log::warn("Trying to access a out-of-range controller at %i", controllerIndex);
return &g_empty_controller;
}
else if (!g_curr_state.controllers[controllerIndex].is_connected)
{
return &g_empty_controller;
}
else
{
return &g_curr_state.controllers[controllerIndex];
}
}
bool Input::pressed(int controllerIndex, Button button)
{
int i = (int)button;
if (controllerIndex < Blah::Input::max_controllers && i >= 0 && i < Blah::Input::max_controller_buttons)
return g_curr_state.controllers[controllerIndex].pressed[i];
return false;
}
bool Input::down(int controllerIndex, Button button)
{
int i = (int)button;
if (controllerIndex < Blah::Input::max_controllers && i >= 0 && i < Blah::Input::max_controller_buttons)
return g_curr_state.controllers[controllerIndex].down[i];
return false;
}
bool Input::released(int controllerIndex, Button button)
{
int i = (int)button;
if (controllerIndex < Blah::Input::max_controllers && i >= 0 && i < Blah::Input::max_controller_buttons)
return g_curr_state.controllers[controllerIndex].released[i];
return false;
}
float Input::axis_check(int controllerIndex, Axis axis)
{
int i = (int)axis;
if (controllerIndex < Blah::Input::max_controllers && i >= 0 && i < Blah::Input::max_controller_axis)
return g_curr_state.controllers[controllerIndex].axis[i];
return 0;
}
int Input::axis_check(int fallback, Key negative, Key positive)
{
if (Input::pressed(positive))
return 1;
else if (Input::pressed(negative))
return -1;
else
{
bool pos = Input::down(positive);
bool neg = Input::down(negative);
if (pos && neg)
return fallback;
else if (pos)
return 1;
else if (neg)
return -1;
else
return 0;
}
}
int Input::axis_check(int fallback, int controllerIndex, Button negative, Button positive)
{
if (Input::pressed(controllerIndex, positive))
return 1;
else if (Input::pressed(controllerIndex, negative))
return -1;
else
{
bool pos = Input::down(controllerIndex, positive);
bool neg = Input::down(controllerIndex, negative);
if (pos && neg)
return fallback;
else if (pos)
return 1;
else if (neg)
return -1;
else
return 0;
}
}
const char* Input::name_of(Key key)
{
switch (key)
{
#define DEFINE_KEY(name, value) case Key::name: return #name;
BLAH_KEY_DEFINITIONS
#undef DEFINE_KEY
}
return "Unknown";
}
const char* Input::name_of(Button button)
{
switch (button)
{
#define DEFINE_BTN(name, value) case Button::name: return #name;
BLAH_BUTTON_DEFINITIONS
#undef DEFINE_BTN
}
return "Unknown";
}

View File

@ -1,12 +1,12 @@
#pragma once #pragma once
#include <blah/core/app.h> #include <blah/app.h>
#include <blah/graphics/renderpass.h> #include <blah/graphics/renderpass.h>
#include <blah/graphics/texture.h> #include <blah/graphics/texture.h>
#include <blah/graphics/framebuffer.h> #include <blah/graphics/target.h>
#include <blah/graphics/shader.h> #include <blah/graphics/shader.h>
#include <blah/graphics/mesh.h> #include <blah/graphics/mesh.h>
#include <blah/graphics/material.h> #include <blah/graphics/material.h>
#include <blah/math/color.h> #include <blah/numerics/color.h>
namespace Blah namespace Blah
{ {
@ -45,9 +45,9 @@ namespace Blah
// if the Texture is invalid, this should return an empty reference. // if the Texture is invalid, this should return an empty reference.
TextureRef create_texture(int width, int height, TextureFormat format); TextureRef create_texture(int width, int height, TextureFormat format);
// Creates a new FrameBuffer. // Creates a new Target.
// if the FrameBuffer is invalid, this should return an empty reference. // if the Target is invalid, this should return an empty reference.
FrameBufferRef create_framebuffer(int width, int height, const TextureFormat* attachments, int attachment_count); TargetRef create_target(int width, int height, const TextureFormat* attachments, int attachment_count);
// Creates a new Shader. // Creates a new Shader.
// if the Shader is invalid, this should return an empty reference. // if the Shader is invalid, this should return an empty reference.

View File

@ -5,7 +5,7 @@
#include "../internal/graphics_backend.h" #include "../internal/graphics_backend.h"
#include "../internal/platform_backend.h" #include "../internal/platform_backend.h"
#include <blah/core/common.h> #include <blah/common.h>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <cstddef> #include <cstddef>
@ -252,7 +252,7 @@ namespace Blah
hr = state.device->CreateTexture2D(&desc, NULL, &staging); hr = state.device->CreateTexture2D(&desc, NULL, &staging);
if (!SUCCEEDED(hr)) if (!SUCCEEDED(hr))
{ {
BLAH_ERROR("Failed to create staging texture to get data"); BLAH_ASSERT(false, "Failed to create staging texture to get data");
return; return;
} }
} }
@ -270,7 +270,7 @@ namespace Blah
if (!SUCCEEDED(hr)) if (!SUCCEEDED(hr))
{ {
BLAH_ERROR("Failed to get texture data"); BLAH_ASSERT(false, "Failed to get texture data");
return; return;
} }
@ -285,16 +285,16 @@ namespace Blah
}; };
class D3D11_FrameBuffer : public FrameBuffer class D3D11_Target : public Target
{ {
private: private:
Attachments m_attachments; Attachments m_attachments;
public: public:
StackVector<ID3D11RenderTargetView*, Attachments::MaxCapacity - 1> color_views; StackVector<ID3D11RenderTargetView*, Attachments::capacity - 1> color_views;
ID3D11DepthStencilView* depth_view = nullptr; ID3D11DepthStencilView* depth_view = nullptr;
D3D11_FrameBuffer(int width, int height, const TextureFormat* attachments, int attachment_count) D3D11_Target(int width, int height, const TextureFormat* attachments, int attachment_count)
{ {
for (int i = 0; i < attachment_count; i++) for (int i = 0; i < attachment_count; i++)
{ {
@ -315,19 +315,19 @@ namespace Blah
} }
} }
~D3D11_FrameBuffer() ~D3D11_Target()
{ {
for (auto& it : color_views) for (auto& it : color_views)
it->Release(); it->Release();
color_views.clear(); color_views.clear();
} }
Attachments& attachments() override Attachments& textures() override
{ {
return m_attachments; return m_attachments;
} }
const Attachments& attachments() const override const Attachments& textures() const override
{ {
return m_attachments; return m_attachments;
} }
@ -841,9 +841,9 @@ namespace Blah
return TextureRef(); return TextureRef();
} }
FrameBufferRef GraphicsBackend::create_framebuffer(int width, int height, const TextureFormat* attachments, int attachment_count) TargetRef GraphicsBackend::create_target(int width, int height, const TextureFormat* attachments, int attachment_count)
{ {
return FrameBufferRef(new D3D11_FrameBuffer(width, height, attachments, attachment_count)); return TargetRef(new D3D11_Target(width, height, attachments, attachment_count));
} }
ShaderRef GraphicsBackend::create_shader(const ShaderData* data) ShaderRef GraphicsBackend::create_shader(const ShaderData* data)
@ -876,7 +876,7 @@ namespace Blah
} }
else else
{ {
auto target = (D3D11_FrameBuffer*)(pass.target.get()); auto target = (D3D11_Target*)(pass.target.get());
ctx->OMSetRenderTargets(target->color_views.size(), target->color_views.begin(), target->depth_view); ctx->OMSetRenderTargets(target->color_views.size(), target->color_views.begin(), target->depth_view);
} }

View File

@ -2,7 +2,7 @@
#include "../internal/graphics_backend.h" #include "../internal/graphics_backend.h"
#include "../internal/platform_backend.h" #include "../internal/platform_backend.h"
#include <blah/core/common.h> #include <blah/common.h>
namespace Blah namespace Blah
{ {
@ -56,14 +56,14 @@ namespace Blah
}; };
class Dummy_FrameBuffer : public FrameBuffer class Dummy_Target : public Target
{ {
private: private:
Attachments m_attachments; Attachments m_attachments;
public: public:
Dummy_FrameBuffer(int width, int height, const TextureFormat* attachments, int attachmentCount) Dummy_Target(int width, int height, const TextureFormat* attachments, int attachmentCount)
{ {
for (int i = 0; i < attachmentCount; i++) for (int i = 0; i < attachmentCount; i++)
{ {
@ -73,12 +73,12 @@ namespace Blah
} }
} }
virtual Attachments& attachments() override virtual Attachments& textures() override
{ {
return m_attachments; return m_attachments;
} }
virtual const Attachments& attachments() const override virtual const Attachments& textures() const override
{ {
return m_attachments; return m_attachments;
} }
@ -186,9 +186,9 @@ namespace Blah
return TextureRef(new Dummy_Texture(width, height, format, false)); return TextureRef(new Dummy_Texture(width, height, format, false));
} }
FrameBufferRef GraphicsBackend::create_framebuffer(int width, int height, const TextureFormat* attachments, int attachmentCount) TargetRef GraphicsBackend::create_target(int width, int height, const TextureFormat* attachments, int attachmentCount)
{ {
return FrameBufferRef(new Dummy_FrameBuffer(width, height, attachments, attachmentCount)); return TargetRef(new Dummy_Target(width, height, attachments, attachmentCount));
} }
ShaderRef GraphicsBackend::create_shader(const ShaderData* data) ShaderRef GraphicsBackend::create_shader(const ShaderData* data)

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <blah/input/input.h> #include <blah/input.h>
namespace Blah namespace Blah
{ {

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <blah/core/common.h> #include <blah/common.h>
#include <blah/core/filesystem.h> #include <blah/filesystem.h>
#include <blah/containers/vector.h> #include <blah/containers/vector.h>
namespace Blah namespace Blah
@ -66,6 +66,9 @@ namespace Blah
// Returns the absolute path to the user directory where save data and settings should be stored // Returns the absolute path to the user directory where save data and settings should be stored
const char* user_path(); const char* user_path();
// Opens a file and sets the handle, or returns an empty handle if it fails
FileRef file_open(const char* path, FileMode mode);
// Returns true if a file with the given path exists // Returns true if a file with the given path exists
bool file_exists(const char* path); bool file_exists(const char* path);
@ -87,27 +90,6 @@ namespace Blah
// opens a directory in the OS file explorer / finder // opens a directory in the OS file explorer / finder
void dir_explore(const char* path); void dir_explore(const char* path);
// Opens a file and sets the handle. returns true if the file was successfully opened
bool file_open(const char* path, FileHandle* handle, FileMode mode);
// Returns the length of the file
i64 file_length(FileHandle file);
// Returns the Position of the file
i64 file_position(FileHandle file);
// Seeks the Position of the file and returns the new position from the start of the file
i64 file_seek(FileHandle file, i64 seekTo);
// Reads a specific number of elements of a given size from the file into ptr
i64 file_read(FileHandle file, void* ptr, i64 size);
// Writes a specific number of elements of the given size from ptr to the file
i64 file_write(FileHandle file, const void* ptr, i64 size);
// Closes a file
void file_close(FileHandle file);
// OpenGL Methods // OpenGL Methods
void* gl_get_func(const char* name); void* gl_get_func(const char* name);
void* gl_context_create(); void* gl_context_create();

View File

@ -3,11 +3,11 @@
#include "../internal/platform_backend.h" #include "../internal/platform_backend.h"
#include "../internal/input_backend.h" #include "../internal/input_backend.h"
#include "../internal/graphics_backend.h" #include "../internal/graphics_backend.h"
#include <blah/input/input.h> #include <blah/input.h>
#include <blah/core/app.h> #include <blah/app.h>
#include <blah/core/filesystem.h> #include <blah/filesystem.h>
#include <blah/core/common.h> #include <blah/common.h>
#include <blah/core/time.h> #include <blah/time.h>
#include <SDL.h> #include <SDL.h>
@ -30,7 +30,7 @@ namespace fs = std::filesystem;
using namespace Blah; using namespace Blah;
namespace namespace Blah
{ {
SDL_Window* window = nullptr; SDL_Window* window = nullptr;
SDL_Joystick* joysticks[Blah::Input::max_controllers]; SDL_Joystick* joysticks[Blah::Input::max_controllers];
@ -70,15 +70,58 @@ namespace
} }
return -1; return -1;
} }
}
bool PlatformBackend::init(const Config* config) // Custom File class
{ class Blah_SDL2_File : public File
{
private:
SDL_RWops* m_handle;
public:
Blah_SDL2_File(SDL_RWops* handle)
{
m_handle = handle;
}
~Blah_SDL2_File()
{
if (m_handle)
SDL_RWclose(m_handle);
}
size_t length() override
{
return SDL_RWsize(m_handle);
}
size_t position() override
{
return SDL_RWtell(m_handle);
}
size_t seek(size_t position) override
{
return SDL_RWseek(m_handle, position, RW_SEEK_SET);
}
size_t read(unsigned char* buffer, size_t length) override
{
return SDL_RWread(m_handle, buffer, sizeof(char), length);
}
size_t write(const unsigned char* buffer, size_t length) override
{
return SDL_RWwrite(m_handle, buffer, sizeof(char), length);
}
};
bool PlatformBackend::init(const Config* config)
{
// Required to call this for Windows // Required to call this for Windows
// I'm not sure why SDL2 doesn't do this on Windows automatically? // I'm not sure why SDL2 doesn't do this on Windows automatically?
#if _WIN32 #if _WIN32
SetProcessDPIAware(); SetProcessDPIAware();
#endif #endif
// TODO: // TODO:
// control this via some kind of config flag // control this via some kind of config flag
@ -104,10 +147,10 @@ bool PlatformBackend::init(const Config* config)
{ {
flags |= SDL_WINDOW_OPENGL; flags |= SDL_WINDOW_OPENGL;
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#else #else
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
@ -120,7 +163,7 @@ bool PlatformBackend::init(const Config* config)
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
#endif #endif
} }
// enable DirectX // enable DirectX
else if (App::renderer() == Renderer::D3D11) else if (App::renderer() == Renderer::D3D11)
@ -138,7 +181,7 @@ bool PlatformBackend::init(const Config* config)
// Scale Window to monitor for High DPI displays // Scale Window to monitor for High DPI displays
// Other platforms do this automatically ... Windows we need to explitely do so // Other platforms do this automatically ... Windows we need to explitely do so
#if _WIN32 #if _WIN32
{ {
// find the display index // find the display index
int display = SDL_GetWindowDisplayIndex(window); int display = SDL_GetWindowDisplayIndex(window);
@ -157,28 +200,28 @@ bool PlatformBackend::init(const Config* config)
} }
} }
} }
#endif #endif
// set window properties // set window properties
SDL_SetWindowResizable(window, SDL_TRUE); SDL_SetWindowResizable(window, SDL_TRUE);
SDL_SetWindowMinimumSize(window, 256, 256); SDL_SetWindowMinimumSize(window, 256, 256);
return true; return true;
} }
void PlatformBackend::ready() void PlatformBackend::ready()
{ {
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
// enable V-Sync // enable V-Sync
// TODO: // TODO:
// This should be a toggle or controllable in some way // This should be a toggle or controllable in some way
if (App::renderer() == Renderer::OpenGL) if (App::renderer() == Renderer::OpenGL)
SDL_GL_SetSwapInterval(1); SDL_GL_SetSwapInterval(1);
#endif #endif
} }
void PlatformBackend::shutdown() void PlatformBackend::shutdown()
{ {
if (window != nullptr) if (window != nullptr)
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
window = nullptr; window = nullptr;
@ -191,20 +234,20 @@ void PlatformBackend::shutdown()
SDL_free(userPath); SDL_free(userPath);
SDL_Quit(); SDL_Quit();
} }
u64 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 (u64)(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
#undef None #undef None
void PlatformBackend::frame() void PlatformBackend::frame()
{ {
// update the mouse every frame // update the mouse every frame
{ {
int winX, winY, x, y; int winX, winY, x, y;
@ -398,16 +441,16 @@ void PlatformBackend::frame()
} }
} }
} }
} }
void PlatformBackend::sleep(int milliseconds) void PlatformBackend::sleep(int milliseconds)
{ {
if (milliseconds >= 0) if (milliseconds >= 0)
SDL_Delay((u32)milliseconds); SDL_Delay((u32)milliseconds);
} }
void PlatformBackend::present() void PlatformBackend::present()
{ {
if (App::renderer() == Renderer::OpenGL) if (App::renderer() == Renderer::OpenGL)
{ {
SDL_GL_SwapWindow(window); SDL_GL_SwapWindow(window);
@ -420,48 +463,48 @@ void PlatformBackend::present()
SDL_ShowWindow(window); SDL_ShowWindow(window);
displayed = true; displayed = true;
} }
} }
const char* PlatformBackend::get_title() const char* PlatformBackend::get_title()
{ {
return nullptr; return nullptr;
} }
void PlatformBackend::set_title(const char* title) void PlatformBackend::set_title(const char* title)
{ {
SDL_SetWindowTitle(window, title); SDL_SetWindowTitle(window, title);
} }
void PlatformBackend::get_position(int* x, int* y) void PlatformBackend::get_position(int* x, int* y)
{ {
SDL_GetWindowPosition(window, x, y); SDL_GetWindowPosition(window, x, y);
} }
void PlatformBackend::set_position(int x, int y) void PlatformBackend::set_position(int x, int y)
{ {
SDL_SetWindowPosition(window, x, y); SDL_SetWindowPosition(window, x, y);
} }
void PlatformBackend::set_fullscreen(bool enabled) void PlatformBackend::set_fullscreen(bool enabled)
{ {
if (enabled) if (enabled)
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
else else
SDL_SetWindowFullscreen(window, 0); SDL_SetWindowFullscreen(window, 0);
} }
void PlatformBackend::get_size(int* width, int* height) void PlatformBackend::get_size(int* width, int* height)
{ {
SDL_GetWindowSize(window, width, height); SDL_GetWindowSize(window, width, height);
} }
void PlatformBackend::set_size(int width, int height) void PlatformBackend::set_size(int width, int height)
{ {
SDL_SetWindowSize(window, width, height); SDL_SetWindowSize(window, width, height);
} }
void PlatformBackend::get_draw_size(int* width, int* height) void PlatformBackend::get_draw_size(int* width, int* height)
{ {
if (App::renderer() == Renderer::OpenGL) if (App::renderer() == Renderer::OpenGL)
{ {
SDL_GL_GetDrawableSize(window, width, height); SDL_GL_GetDrawableSize(window, width, height);
@ -470,22 +513,22 @@ void PlatformBackend::get_draw_size(int* width, int* height)
{ {
SDL_GetWindowSize(window, width, height); SDL_GetWindowSize(window, width, height);
} }
} }
float PlatformBackend::get_content_scale() float PlatformBackend::get_content_scale()
{ {
// TODO: // TODO:
// This is incorrect! but for some reason the scale // This is incorrect! but for some reason the scale
// is HUGE if I use the Display DPI on macOS :/ // is HUGE if I use the Display DPI on macOS :/
#if __APPLE__ #if __APPLE__
return 2.0f; return 2.0f;
#endif #endif
#if _WIN32 #if _WIN32
float hidpiRes = 96; float hidpiRes = 96;
#else #else
float hidpiRes = 72; float hidpiRes = 72;
#endif #endif
int index = SDL_GetWindowDisplayIndex(window); int index = SDL_GetWindowDisplayIndex(window);
if (index < 0) if (index < 0)
@ -496,19 +539,19 @@ float PlatformBackend::get_content_scale()
Log::error(SDL_GetError()); Log::error(SDL_GetError());
return (ddpi / hidpiRes); return (ddpi / hidpiRes);
} }
// FILE IO // FILE IO
const char* PlatformBackend::app_path() const char* PlatformBackend::app_path()
{ {
if (basePath == nullptr) if (basePath == nullptr)
basePath = SDL_GetBasePath(); basePath = SDL_GetBasePath();
return basePath; return basePath;
} }
const char* PlatformBackend::user_path() const char* PlatformBackend::user_path()
{ {
if (userPath == nullptr) if (userPath == nullptr)
{ {
const Config* config = App::config(); const Config* config = App::config();
@ -516,40 +559,40 @@ const char* PlatformBackend::user_path()
} }
return userPath; return userPath;
} }
// Windows File System methods // Windows File System methods
#if _WIN32 #if _WIN32
bool PlatformBackend::file_exists(const char* path) bool PlatformBackend::file_exists(const char* path)
{ {
return fs::is_regular_file(path); return fs::is_regular_file(path);
} }
bool PlatformBackend::file_delete(const char* path) bool PlatformBackend::file_delete(const char* path)
{ {
return fs::remove(path); return fs::remove(path);
} }
bool PlatformBackend::dir_create(const char* path) bool PlatformBackend::dir_create(const char* path)
{ {
std::error_code error; std::error_code error;
return fs::create_directories(path, error); return fs::create_directories(path, error);
} }
bool PlatformBackend::dir_exists(const char* path) bool PlatformBackend::dir_exists(const char* path)
{ {
return fs::is_directory(path); return fs::is_directory(path);
} }
bool PlatformBackend::dir_delete(const char* path) bool PlatformBackend::dir_delete(const char* path)
{ {
BLAH_ERROR("not implemented"); BLAH_ASSERT(false, "not implemented");
return false; return false;
} }
void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive) void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive)
{ {
if (fs::is_directory(path)) if (fs::is_directory(path))
{ {
if (recursive) if (recursive)
@ -563,30 +606,30 @@ void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bo
list.emplace_back(p.path().string().c_str()); list.emplace_back(p.path().string().c_str());
} }
} }
} }
void PlatformBackend::dir_explore(const char* path) void PlatformBackend::dir_explore(const char* path)
{ {
ShellExecute(NULL, "open", path, NULL, NULL, SW_SHOWDEFAULT); ShellExecute(NULL, "open", path, NULL, NULL, SW_SHOWDEFAULT);
} }
// Non-Windows File System Methods // Non-Windows File System Methods
#else #else
bool PlatformBackend::file_exists(const char* path) bool PlatformBackend::file_exists(const char* path)
{ {
struct stat buffer; struct stat buffer;
return (stat(path, &buffer) == 0) && S_ISREG(buffer.st_mode); return (stat(path, &buffer) == 0) && S_ISREG(buffer.st_mode);
} }
bool PlatformBackend::file_delete(const char* path) bool PlatformBackend::file_delete(const char* path)
{ {
BLAH_ERROR("not implemented"); BLAH_ASSERT(false, "not implemented");
return false; return false;
} }
bool PlatformBackend::dir_create(const char* path) bool PlatformBackend::dir_create(const char* path)
{ {
char tmp[265]; char tmp[265];
char* p = NULL; char* p = NULL;
size_t len; size_t len;
@ -602,22 +645,22 @@ bool PlatformBackend::dir_create(const char* path)
*p = '/'; *p = '/';
} }
return mkdir(tmp, S_IRWXU) == 0; return mkdir(tmp, S_IRWXU) == 0;
} }
bool PlatformBackend::dir_exists(const char* path) bool PlatformBackend::dir_exists(const char* path)
{ {
struct stat buffer; struct stat buffer;
return (stat(path, &buffer) == 0) && S_ISDIR(buffer.st_mode); return (stat(path, &buffer) == 0) && S_ISDIR(buffer.st_mode);
} }
bool PlatformBackend::dir_delete(const char* path) bool PlatformBackend::dir_delete(const char* path)
{ {
BLAH_ERROR("not implemented"); BLAH_ASSERT(false, "not implemented");
return false; return false;
} }
void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive) void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive)
{ {
DIR* dirp = opendir(path); DIR* dirp = opendir(path);
if (dirp != NULL) if (dirp != NULL)
{ {
@ -637,17 +680,17 @@ void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bo
} }
closedir(dirp); closedir(dirp);
} }
} }
void PlatformBackend::dir_explore(const char* path) void PlatformBackend::dir_explore(const char* path)
{ {
BLAH_ERROR("'dir_explore' Not Implemented"); BLAH_ASSERT(false, "'dir_explore' Not Implemented");
} }
#endif #endif
bool PlatformBackend::file_open(const char* path, PlatformBackend::FileHandle* handle, FileMode mode) FileRef PlatformBackend::file_open(const char* path, FileMode mode)
{ {
const char* sdl_mode = ""; const char* sdl_mode = "";
switch (mode) switch (mode)
@ -667,74 +710,47 @@ bool PlatformBackend::file_open(const char* path, PlatformBackend::FileHandle* h
} }
auto ptr = SDL_RWFromFile(path, sdl_mode); auto ptr = SDL_RWFromFile(path, sdl_mode);
*handle = (PlatformBackend::FileHandle)ptr; if (!ptr)
return ptr != nullptr; return FileRef();
}
i64 PlatformBackend::file_length(PlatformBackend::FileHandle stream) return FileRef(new Blah_SDL2_File(ptr));
{ }
return SDL_RWsize((SDL_RWops*)stream);
}
i64 PlatformBackend::file_position(PlatformBackend::FileHandle stream) void* PlatformBackend::gl_get_func(const char* name)
{ {
return SDL_RWtell((SDL_RWops*)stream);
}
i64 PlatformBackend::file_seek(PlatformBackend::FileHandle stream, i64 seekTo)
{
return SDL_RWseek((SDL_RWops*)stream, seekTo, RW_SEEK_SET);
}
i64 PlatformBackend::file_read(PlatformBackend::FileHandle stream, void* ptr, i64 length)
{
return SDL_RWread((SDL_RWops*)stream, ptr, sizeof(char), length);
}
i64 PlatformBackend::file_write(PlatformBackend::FileHandle stream, const void* ptr, i64 length)
{
return SDL_RWwrite((SDL_RWops*)stream, ptr, sizeof(char), length);
}
void PlatformBackend::file_close(PlatformBackend::FileHandle stream)
{
if (stream != nullptr)
SDL_RWclose((SDL_RWops*)stream);
}
void* PlatformBackend::gl_get_func(const char* name)
{
return SDL_GL_GetProcAddress(name); return SDL_GL_GetProcAddress(name);
} }
void* PlatformBackend::gl_context_create() void* PlatformBackend::gl_context_create()
{ {
void* pointer = SDL_GL_CreateContext(window); void* pointer = SDL_GL_CreateContext(window);
if (pointer == nullptr) if (pointer == nullptr)
Log::error("SDL_GL_CreateContext failed: %s", SDL_GetError()); Log::error("SDL_GL_CreateContext failed: %s", SDL_GetError());
return pointer; return pointer;
} }
void PlatformBackend::gl_context_make_current(void* context) void PlatformBackend::gl_context_make_current(void* context)
{ {
SDL_GL_MakeCurrent(window, context); SDL_GL_MakeCurrent(window, context);
} }
void PlatformBackend::gl_context_destroy(void* context) void PlatformBackend::gl_context_destroy(void* context)
{ {
SDL_GL_DeleteContext(context); SDL_GL_DeleteContext(context);
} }
void* PlatformBackend::d3d11_get_hwnd() void* PlatformBackend::d3d11_get_hwnd()
{ {
#if _WIN32 #if _WIN32
SDL_SysWMinfo info; SDL_SysWMinfo info;
SDL_VERSION(&info.version); SDL_VERSION(&info.version);
SDL_GetWindowWMInfo(window, &info); SDL_GetWindowWMInfo(window, &info);
return info.info.win.window; return info.info.win.window;
#else #else
return nullptr; return nullptr;
#endif #endif
}
} }
#endif // BLAH_PLATFORM_SDL2 #endif // BLAH_PLATFORM_SDL2

View File

@ -9,12 +9,11 @@
#include "../internal/platform_backend.h" #include "../internal/platform_backend.h"
#include "../internal/input_backend.h" #include "../internal/input_backend.h"
#include "../internal/graphics_backend.h" #include "../internal/graphics_backend.h"
#include <blah/input/input.h> #include <blah/input.h>
#include <blah/core/app.h> #include <blah/app.h>
#include <blah/core/filesystem.h> #include <blah/filesystem.h>
#include <blah/core/common.h> #include <blah/common.h>
#include <blah/core/time.h> #include <blah/time.h>
#include <blah/math/stopwatch.h>
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
@ -27,7 +26,7 @@
using namespace Blah; using namespace Blah;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace namespace Blah
{ {
// Primary Window // Primary Window
HWND g_hwnd; HWND g_hwnd;
@ -50,13 +49,116 @@ namespace
// fullscreen state // fullscreen state
RECT g_windowed_position; RECT g_windowed_position;
bool g_fullscreen = false; bool g_fullscreen = false;
}
Key blah_scancode_to_key(WPARAM wParam, LPARAM lParam); // Converts Windows scancode to Blah key
LRESULT CALLBACK blah_window_procedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); Key scancode_to_key(WPARAM wParam, LPARAM lParam);
bool PlatformBackend::init(const Config* config) // Main Windows Procedure callback
{ LRESULT CALLBACK window_procedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
// Custom File class
class Blah_Win32_File : public File
{
private:
HANDLE m_handle;
public:
Blah_Win32_File(HANDLE handle)
{
m_handle = handle;
}
~Blah_Win32_File()
{
CloseHandle(m_handle);
}
size_t length() override
{
// Todo: cache this value? not sure how performant it is
LARGE_INTEGER file_size;
if (GetFileSizeEx(m_handle, &file_size))
return file_size.QuadPart;
return 0;
}
size_t position() override
{
LARGE_INTEGER move;
LARGE_INTEGER result;
move.QuadPart = 0;
result.QuadPart = 0;
SetFilePointerEx(m_handle, move, &result, FILE_CURRENT);
return result.QuadPart;
}
size_t seek(size_t position) override
{
LARGE_INTEGER move;
LARGE_INTEGER result;
move.QuadPart = position;
result.QuadPart = 0;
SetFilePointerEx(m_handle, move, &result, FILE_BEGIN);
return result.QuadPart;
}
size_t read(unsigned char* buffer, size_t length) override
{
static const DWORD read_step = 65536;
size_t read = 0;
while (read < length)
{
DWORD to_read = read_step;
if (to_read > length - read)
to_read = (DWORD)(length - read);
DWORD moved = 0;
if (ReadFile(m_handle, buffer + read, to_read, &moved, NULL))
read += moved;
if (moved < to_read)
break;
}
return read;
}
size_t write(const unsigned char* buffer, size_t length) override
{
static const DWORD write_step = 65536;
size_t written = 0;
while (written < length)
{
DWORD to_write = write_step;
if (to_write > length - written)
to_write = (DWORD)(length - written);
DWORD moved = 0;
if (WriteFile(m_handle, buffer + written, to_write, &moved, NULL))
written += moved;
if (moved < to_write)
break;
}
return written;
}
};
bool PlatformBackend::init(const Config* config)
{
// Required to call this for Windows // Required to call this for Windows
SetProcessDPIAware(); SetProcessDPIAware();
@ -68,7 +170,7 @@ bool PlatformBackend::init(const Config* config)
wc.lpfnWndProc = DefWindowProc; wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = "BLAH WINDOW"; wc.lpszClassName = "BLAH WINDOW";
wc.hInstance = hInstance; wc.hInstance = hInstance;
wc.lpfnWndProc = blah_window_procedure; wc.lpfnWndProc = window_procedure;
wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = NULL; wc.hIcon = NULL;
wc.lpszMenuName = NULL; wc.lpszMenuName = NULL;
@ -101,7 +203,7 @@ bool PlatformBackend::init(const Config* config)
} }
// Get the Windows GL functions we need // Get the Windows GL functions we need
g_wglGetProcAddress = (void*(WINAPI*) (const char*))GetProcAddress(g_opengl_dll, "wglGetProcAddress"); g_wglGetProcAddress = (void* (WINAPI*)(const char*))GetProcAddress(g_opengl_dll, "wglGetProcAddress");
g_wglCreateContext = (HGLRC(WINAPI*) (HDC))GetProcAddress(g_opengl_dll, "wglCreateContext"); g_wglCreateContext = (HGLRC(WINAPI*) (HDC))GetProcAddress(g_opengl_dll, "wglCreateContext");
g_wglDeleteContext = (BOOL(WINAPI*) (HGLRC))GetProcAddress(g_opengl_dll, "wglDeleteContext"); g_wglDeleteContext = (BOOL(WINAPI*) (HGLRC))GetProcAddress(g_opengl_dll, "wglDeleteContext");
g_wglMakeCurrent = (BOOL(WINAPI*) (HDC, HGLRC))GetProcAddress(g_opengl_dll, "wglMakeCurrent"); g_wglMakeCurrent = (BOOL(WINAPI*) (HDC, HGLRC))GetProcAddress(g_opengl_dll, "wglMakeCurrent");
@ -179,10 +281,10 @@ bool PlatformBackend::init(const Config* config)
// Finished Platform Setup // Finished Platform Setup
return true; return true;
} }
void PlatformBackend::ready() void PlatformBackend::ready()
{ {
// Setup Window Size // Setup Window Size
{ {
auto scale = get_content_scale(); auto scale = get_content_scale();
@ -193,24 +295,24 @@ void PlatformBackend::ready()
// Display the game window // Display the game window
ShowWindow(g_hwnd, SW_SHOW); ShowWindow(g_hwnd, SW_SHOW);
} }
void PlatformBackend::shutdown() void PlatformBackend::shutdown()
{ {
DestroyWindow(g_hwnd); DestroyWindow(g_hwnd);
} }
u64 PlatformBackend::ticks() u64 PlatformBackend::ticks()
{ {
// Todo: // Todo:
// This should account for whatever Time::ticks_per_second is set to // This should account for whatever Time::ticks_per_second is set to
auto now = std::chrono::system_clock::now().time_since_epoch(); auto now = std::chrono::system_clock::now().time_since_epoch();
return std::chrono::duration_cast<std::chrono::microseconds>(now - g_start_time).count(); 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) LRESULT CALLBACK window_procedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
switch (msg) switch (msg)
{ {
case WM_CLOSE: case WM_CLOSE:
@ -278,7 +380,7 @@ LRESULT CALLBACK blah_window_procedure(HWND hwnd, UINT msg, WPARAM wParam, LPARA
auto is_repeat = ((lParam & (1 << 30)) >> 30) == 1; auto is_repeat = ((lParam & (1 << 30)) >> 30) == 1;
if (!is_repeat) if (!is_repeat)
{ {
auto key = blah_scancode_to_key(wParam, lParam); auto key = scancode_to_key(wParam, lParam);
if (key != Key::Unknown) if (key != Key::Unknown)
InputBackend::on_key_down(key); InputBackend::on_key_down(key);
} }
@ -288,7 +390,7 @@ LRESULT CALLBACK blah_window_procedure(HWND hwnd, UINT msg, WPARAM wParam, LPARA
case WM_KEYUP: case WM_KEYUP:
case WM_SYSKEYUP: case WM_SYSKEYUP:
{ {
auto key = blah_scancode_to_key(wParam, lParam); auto key = scancode_to_key(wParam, lParam);
if (key != Key::Unknown) if (key != Key::Unknown)
InputBackend::on_key_up(key); InputBackend::on_key_up(key);
return 0; return 0;
@ -296,10 +398,10 @@ LRESULT CALLBACK blah_window_procedure(HWND hwnd, UINT msg, WPARAM wParam, LPARA
} }
return DefWindowProc(hwnd, msg, wParam, lParam); return DefWindowProc(hwnd, msg, wParam, lParam);
} }
void PlatformBackend::frame() void PlatformBackend::frame()
{ {
// Catch & Dispatch Window Messages // Catch & Dispatch Window Messages
MSG msg; MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
@ -307,52 +409,52 @@ void PlatformBackend::frame()
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
} }
} }
void PlatformBackend::sleep(int milliseconds) void PlatformBackend::sleep(int milliseconds)
{ {
if (milliseconds > 0) if (milliseconds > 0)
Sleep(milliseconds); Sleep(milliseconds);
} }
void PlatformBackend::present() void PlatformBackend::present()
{ {
if (App::renderer() == Renderer::OpenGL) if (App::renderer() == Renderer::OpenGL)
{ {
HDC hdc = GetDC(g_hwnd); HDC hdc = GetDC(g_hwnd);
SwapBuffers(hdc); SwapBuffers(hdc);
} }
} }
const char* PlatformBackend::get_title() const char* PlatformBackend::get_title()
{ {
return nullptr; return nullptr;
} }
void PlatformBackend::set_title(const char* title) void PlatformBackend::set_title(const char* title)
{ {
SetWindowText(g_hwnd, title); SetWindowText(g_hwnd, title);
} }
void PlatformBackend::get_position(int* x, int* y) void PlatformBackend::get_position(int* x, int* y)
{ {
RECT rect; RECT rect;
if (GetWindowRect(g_hwnd, &rect)) if (GetWindowRect(g_hwnd, &rect))
{ {
*x = rect.left; *x = rect.left;
*y = rect.top; *y = rect.top;
} }
} }
void PlatformBackend::set_position(int x, int y) void PlatformBackend::set_position(int x, int y)
{ {
int w, h; int w, h;
get_size(&w, &h); get_size(&w, &h);
SetWindowPos(g_hwnd, NULL, x, y, w, h, 0); SetWindowPos(g_hwnd, NULL, x, y, w, h, 0);
} }
void PlatformBackend::set_fullscreen(bool enabled) void PlatformBackend::set_fullscreen(bool enabled)
{ {
if (g_fullscreen == enabled) if (g_fullscreen == enabled)
return; return;
@ -378,20 +480,20 @@ void PlatformBackend::set_fullscreen(bool enabled)
g_windowed_position.bottom - g_windowed_position.top, 0); g_windowed_position.bottom - g_windowed_position.top, 0);
ShowWindow(g_hwnd, SW_SHOW); ShowWindow(g_hwnd, SW_SHOW);
} }
} }
void PlatformBackend::get_size(int* width, int* height) void PlatformBackend::get_size(int* width, int* height)
{ {
RECT rect; RECT rect;
if (GetClientRect(g_hwnd, &rect)) if (GetClientRect(g_hwnd, &rect))
{ {
*width = rect.right - rect.left; *width = rect.right - rect.left;
*height = rect.bottom - rect.top; *height = rect.bottom - rect.top;
} }
} }
void PlatformBackend::set_size(int width, int height) void PlatformBackend::set_size(int width, int height)
{ {
RECT client_rect; RECT client_rect;
RECT border_rect; RECT border_rect;
@ -402,20 +504,20 @@ void PlatformBackend::set_size(int width, int height)
int border_height = (border_rect.bottom - border_rect.top) - (client_rect.bottom - client_rect.top); 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); 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) void PlatformBackend::get_draw_size(int* width, int* height)
{ {
RECT rect; RECT rect;
if (GetClientRect(g_hwnd, &rect)) if (GetClientRect(g_hwnd, &rect))
{ {
*width = rect.right - rect.left; *width = rect.right - rect.left;
*height = rect.bottom - rect.top; *height = rect.bottom - rect.top;
} }
} }
float PlatformBackend::get_content_scale() float PlatformBackend::get_content_scale()
{ {
// base value of Windows DPI // base value of Windows DPI
// as seen here: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforwindow // as seen here: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforwindow
constexpr float base_raw_value = 96.0f; constexpr float base_raw_value = 96.0f;
@ -423,47 +525,47 @@ float PlatformBackend::get_content_scale()
UINT raw_value = GetDpiForWindow(g_hwnd); UINT raw_value = GetDpiForWindow(g_hwnd);
return (raw_value / base_raw_value); return (raw_value / base_raw_value);
} }
const char* PlatformBackend::app_path() const char* PlatformBackend::app_path()
{ {
return g_working_directory.cstr(); return g_working_directory.cstr();
} }
const char* PlatformBackend::user_path() const char* PlatformBackend::user_path()
{ {
return g_user_directory.cstr(); return g_user_directory.cstr();
} }
bool PlatformBackend::file_exists(const char* path) bool PlatformBackend::file_exists(const char* path)
{ {
return fs::is_regular_file(path); return fs::is_regular_file(path);
} }
bool PlatformBackend::file_delete(const char* path) bool PlatformBackend::file_delete(const char* path)
{ {
return fs::remove(path); return fs::remove(path);
} }
bool PlatformBackend::dir_create(const char* path) bool PlatformBackend::dir_create(const char* path)
{ {
std::error_code error; std::error_code error;
return fs::create_directories(path, error); return fs::create_directories(path, error);
} }
bool PlatformBackend::dir_exists(const char* path) bool PlatformBackend::dir_exists(const char* path)
{ {
return fs::is_directory(path); return fs::is_directory(path);
} }
bool PlatformBackend::dir_delete(const char* path) bool PlatformBackend::dir_delete(const char* path)
{ {
BLAH_ERROR("not implemented"); BLAH_ASSERT(false, "not implemented");
return false; return false;
} }
void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive) void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive)
{ {
if (fs::is_directory(path)) if (fs::is_directory(path))
{ {
if (recursive) if (recursive)
@ -477,15 +579,15 @@ void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bo
list.emplace_back(p.path().string().c_str()); list.emplace_back(p.path().string().c_str());
} }
} }
} }
void PlatformBackend::dir_explore(const char* path) void PlatformBackend::dir_explore(const char* path)
{ {
ShellExecute(NULL, "open", path, NULL, NULL, SW_SHOWDEFAULT); ShellExecute(NULL, "open", path, NULL, NULL, SW_SHOWDEFAULT);
} }
bool PlatformBackend::file_open(const char* path, PlatformBackend::FileHandle* handle, FileMode mode) FileRef PlatformBackend::file_open(const char* path, FileMode mode)
{ {
int access = 0; int access = 0;
int creation = 0; int creation = 0;
@ -512,102 +614,13 @@ bool PlatformBackend::file_open(const char* path, PlatformBackend::FileHandle* h
auto result = CreateFile(path, access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL); auto result = CreateFile(path, access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
if (result == INVALID_HANDLE_VALUE) if (result == INVALID_HANDLE_VALUE)
return false; return FileRef();
*handle = result; return FileRef(new Blah_Win32_File(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)
{
LARGE_INTEGER move;
LARGE_INTEGER result;
move.QuadPart = 0;
result.QuadPart = 0;
SetFilePointerEx(handle, move, &result, FILE_CURRENT);
return result.QuadPart;
}
i64 PlatformBackend::file_seek(PlatformBackend::FileHandle handle, i64 seek_to)
{
LARGE_INTEGER move;
LARGE_INTEGER result;
move.QuadPart = seek_to;
result.QuadPart = 0;
SetFilePointerEx(handle, move, &result, FILE_BEGIN);
return result.QuadPart;
}
i64 PlatformBackend::file_read(PlatformBackend::FileHandle handle, void* ptr, i64 length)
{
static const DWORD read_step = 65536;
i64 read = 0;
while (read < length)
{
DWORD to_read = read_step;
if (to_read > length - read)
to_read = (DWORD)(length - read);
DWORD moved = 0;
if (ReadFile(handle, (unsigned char*)ptr + read, to_read, &moved, NULL))
read += moved;
if (moved < to_read)
break;
} }
return read; void* PlatformBackend::gl_get_func(const char* name)
}
i64 PlatformBackend::file_write(PlatformBackend::FileHandle handle, const void* ptr, i64 length)
{
static const DWORD write_step = 65536;
i64 written = 0;
while (written < length)
{ {
DWORD to_write = write_step;
if (to_write > length - written)
to_write = (DWORD)(length - written);
DWORD moved = 0;
if (WriteFile(handle, (unsigned char*)ptr + written, to_write, &moved, NULL))
written += moved;
if (moved < to_write)
break;
}
return written;
}
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 // 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? // wglGetProcAddress doesn't always return valid pointers for some specific methods?
@ -622,16 +635,16 @@ void* PlatformBackend::gl_get_func(const char* name)
} }
return p; return p;
} }
void* PlatformBackend::gl_context_create() void* PlatformBackend::gl_context_create()
{ {
HDC hdc = GetDC(g_hwnd); HDC hdc = GetDC(g_hwnd);
return g_wglCreateContext(hdc); return g_wglCreateContext(hdc);
} }
void PlatformBackend::gl_context_make_current(void* context) void PlatformBackend::gl_context_make_current(void* context)
{ {
if (context != nullptr) if (context != nullptr)
{ {
HDC hdc = GetDC(g_hwnd); HDC hdc = GetDC(g_hwnd);
@ -639,20 +652,20 @@ void PlatformBackend::gl_context_make_current(void* context)
} }
else else
g_wglMakeCurrent(NULL, NULL); g_wglMakeCurrent(NULL, NULL);
} }
void PlatformBackend::gl_context_destroy(void* context) void PlatformBackend::gl_context_destroy(void* context)
{ {
g_wglDeleteContext((HGLRC)context); g_wglDeleteContext((HGLRC)context);
} }
void* PlatformBackend::d3d11_get_hwnd() void* PlatformBackend::d3d11_get_hwnd()
{ {
return g_hwnd; return g_hwnd;
} }
Key blah_scancode_to_key(WPARAM wParam, LPARAM lParam) Key scancode_to_key(WPARAM wParam, LPARAM lParam)
{ {
Key key = Key::Unknown; Key key = Key::Unknown;
switch (wParam) switch (wParam)
@ -834,6 +847,7 @@ Key blah_scancode_to_key(WPARAM wParam, LPARAM lParam)
} }
return key; return key;
}
} }
#endif // BLAH_PLATFORM_WINDOWS #endif // BLAH_PLATFORM_WINDOWS

View File

@ -1,25 +0,0 @@
#include <blah/math/stopwatch.h>
#include <chrono>
using namespace std::chrono;
using namespace Blah;
Stopwatch::Stopwatch()
{
reset();
}
void Stopwatch::reset()
{
start_time = std::chrono::duration_cast<std::chrono::microseconds>(system_clock::now().time_since_epoch()).count();
}
u64 Stopwatch::milliseconds()
{
return microseconds() / 1000;
}
u64 Stopwatch::microseconds()
{
return std::chrono::duration_cast<std::chrono::microseconds>(system_clock::now().time_since_epoch()).count() - start_time;
}

View File

@ -1,4 +1,4 @@
#include <blah/math/calc.h> #include <blah/numerics/calc.h>
#include <cmath> #include <cmath>
#include <cstdlib> #include <cstdlib>

View File

@ -1,5 +1,5 @@
#include <blah/math/circle.h> #include <blah/numerics/circle.h>
#include <blah/math/calc.h> #include <blah/numerics/calc.h>
using namespace Blah; using namespace Blah;

View File

@ -1,6 +1,6 @@
#include <blah/math/color.h> #include <blah/numerics/color.h>
#include <blah/math/vec3.h> #include <blah/numerics/vec3.h>
#include <blah/math/vec4.h> #include <blah/numerics/vec4.h>
using namespace Blah; using namespace Blah;

View File

@ -1,7 +1,7 @@
#include <blah/math/line.h> #include <blah/numerics/line.h>
#include <blah/math/rect.h> #include <blah/numerics/rect.h>
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
#include <blah/math/calc.h> #include <blah/numerics/calc.h>
using namespace Blah; using namespace Blah;

View File

@ -1,7 +1,7 @@
#include <blah/math/mat3x2.h> #include <blah/numerics/mat3x2.h>
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
#include <blah/numerics/calc.h>
#include <cstring> #include <cstring>
#include <cmath>
using namespace Blah; using namespace Blah;
@ -132,8 +132,8 @@ Mat3x2 Mat3x2::create_scale(float scaleX, float scaleY, Vec2 centerPoint)
Mat3x2 Mat3x2::create_rotation(float radians) Mat3x2 Mat3x2::create_rotation(float radians)
{ {
float c = cosf(radians); float c = Calc::cos(radians);
float s = sinf(radians); float s = Calc::sin(radians);
return Mat3x2(c, s, -s, c, 0, 0); return Mat3x2(c, s, -s, c, 0, 0);
} }

View File

@ -1,5 +1,5 @@
#include <blah/math/mat4x4.h> #include <blah/numerics/mat4x4.h>
#include <blah/core/common.h> #include <blah/common.h>
using namespace Blah; using namespace Blah;

View File

@ -1,6 +1,6 @@
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
#include <blah/math/mat3x2.h> #include <blah/numerics/mat3x2.h>
#include <math.h> #include <blah/numerics/calc.h>
using namespace Blah; using namespace Blah;
@ -33,7 +33,7 @@ bool Point::operator !=(const Point& rhs) { return x != rhs.x || y != rhs.y; }
float Point::length() const float Point::length() const
{ {
return sqrtf((float)(x * x + y * y)); return Calc::sqrt((float)(x * x + y * y));
} }
int Point::length_squared() const int Point::length_squared() const

View File

@ -1,5 +1,5 @@
#include <blah/math/quad.h> #include <blah/numerics/quad.h>
#include <blah/math/calc.h> #include <blah/numerics/calc.h>
namespace Blah namespace Blah
{ {

View File

@ -1,9 +1,9 @@
#include <blah/math/rect.h> #include <blah/numerics/rect.h>
#include <blah/math/point.h> #include <blah/numerics/point.h>
#include <blah/math/rectI.h> #include <blah/numerics/rectI.h>
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
#include <blah/math/calc.h> #include <blah/numerics/calc.h>
#include <blah/math/mat3x2.h> #include <blah/numerics/mat3x2.h>
using namespace Blah; using namespace Blah;

View File

@ -1,8 +1,8 @@
#include <blah/math/rectI.h> #include <blah/numerics/rectI.h>
#include <blah/math/rect.h> #include <blah/numerics/rect.h>
#include <blah/math/point.h> #include <blah/numerics/point.h>
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
#include <blah/math/calc.h> #include <blah/numerics/calc.h>
using namespace Blah; using namespace Blah;

View File

@ -1,7 +1,6 @@
#include <blah/math/vec2.h> #include <blah/numerics/vec2.h>
#include <blah/math/mat3x2.h> #include <blah/numerics/mat3x2.h>
#include <blah/math/calc.h> #include <blah/numerics/calc.h>
#include <math.h>
using namespace Blah; using namespace Blah;

View File

@ -42,7 +42,7 @@ BufferStream::~BufferStream()
delete[] m_buffer; delete[] m_buffer;
} }
i64 BufferStream::read_into(void* ptr, i64 len) size_t BufferStream::read_into(void* ptr, size_t len)
{ {
if (m_buffer == nullptr || ptr == nullptr) if (m_buffer == nullptr || ptr == nullptr)
return 0; return 0;
@ -58,7 +58,7 @@ i64 BufferStream::read_into(void* ptr, i64 len)
return len; return len;
} }
i64 BufferStream::write_from(const void* ptr, i64 len) size_t BufferStream::write_from(const void* ptr, size_t len)
{ {
if (len < 0) if (len < 0)
return 0; return 0;
@ -78,7 +78,7 @@ i64 BufferStream::write_from(const void* ptr, i64 len)
return len; return len;
} }
void BufferStream::resize(i64 length) void BufferStream::resize(size_t length)
{ {
if (m_capacity > length) if (m_capacity > length)
{ {

View File

@ -1,5 +1,5 @@
#include <blah/streams/filestream.h> #include <blah/streams/filestream.h>
#include <blah/core/common.h> #include <blah/common.h>
#include "../internal/platform_backend.h" #include "../internal/platform_backend.h"
#include <cstring> #include <cstring>
@ -7,105 +7,90 @@ using namespace Blah;
FileStream::FileStream() FileStream::FileStream()
{ {
m_handle = nullptr;
m_mode = FileMode::OpenRead; m_mode = FileMode::OpenRead;
} }
FileStream::FileStream(const FilePath& path, FileMode mode) FileStream::FileStream(const FilePath& path, FileMode mode)
: m_mode(mode) : m_mode(mode)
, m_file(File::open(path, mode))
{ {
if (!PlatformBackend::file_open(path, &m_handle, mode))
m_handle = nullptr;
} }
FileStream::FileStream(FileStream&& src) noexcept FileStream::FileStream(FileStream&& src) noexcept
{ {
m_handle = src.m_handle; m_file = src.m_file;
m_mode = src.m_mode; m_mode = src.m_mode;
src.m_handle = nullptr;
} }
FileStream& FileStream::operator=(FileStream&& src) noexcept FileStream& FileStream::operator=(FileStream&& src) noexcept
{ {
m_handle = src.m_handle; m_file = src.m_file;
m_mode = src.m_mode; m_mode = src.m_mode;
src.m_handle = nullptr;
return *this; return *this;
} }
FileStream::~FileStream() size_t FileStream::length() const
{ {
if (m_handle != nullptr) if (m_file)
PlatformBackend::file_close(m_handle); return m_file->length();
return 0;
} }
i64 FileStream::length() const size_t FileStream::position() const
{ {
if (m_handle == nullptr) if (m_file)
return m_file->position();
return 0; return 0;
return PlatformBackend::file_length(m_handle);
} }
i64 FileStream::position() const size_t FileStream::seek(size_t seek_to)
{ {
if (m_handle == nullptr) if (m_file)
return m_file->seek(seek_to);
return 0; return 0;
return PlatformBackend::file_position(m_handle);
}
i64 FileStream::seek(i64 seek_to)
{
if (m_handle == nullptr)
return 0;
return PlatformBackend::file_seek(m_handle, seek_to);
} }
bool FileStream::is_open() const bool FileStream::is_open() const
{ {
return m_handle != nullptr; return m_file.get();
} }
bool FileStream::is_readable() const bool FileStream::is_readable() const
{ {
return m_handle != nullptr && (m_mode != FileMode::CreateWrite); return m_file.get() && (m_mode != FileMode::CreateWrite);
} }
bool FileStream::is_writable() const bool FileStream::is_writable() const
{ {
return m_handle != nullptr && (m_mode != FileMode::OpenRead); return m_file.get() && (m_mode != FileMode::OpenRead);
} }
i64 FileStream::read_into(void* ptr, i64 length) size_t FileStream::read_into(void* ptr, size_t length)
{
if (m_handle == nullptr)
{
BLAH_ERROR("Unable to read from Stream");
return 0;
}
return PlatformBackend::file_read(m_handle, ptr, length);
}
i64 FileStream::write_from(const void* ptr, i64 length)
{ {
if (length <= 0) if (length <= 0)
return 0; return 0;
if (m_handle == nullptr) if (m_file)
{ return m_file->read((unsigned char*)ptr, length);
BLAH_ERROR("Unable to write to Stream");
return 0;
}
return PlatformBackend::file_write(m_handle, ptr, length); BLAH_ASSERT(false, "Unable to read from Stream");
return 0;
}
size_t FileStream::write_from(const void* ptr, size_t length)
{
if (length <= 0)
return 0;
if (m_file)
return m_file->write((const unsigned char*)ptr, length);
BLAH_ASSERT(false, "Unable to write to Stream");
return 0;
} }
void FileStream::close() void FileStream::close()
{ {
if (m_handle != nullptr) m_file.reset();
PlatformBackend::file_close(m_handle);
m_handle = nullptr;
} }

View File

@ -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, i64 length) MemoryStream::MemoryStream(char* data, size_t 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;
} }
i64 MemoryStream::read_into(void* ptr, i64 len) size_t MemoryStream::read_into(void* ptr, size_t len)
{ {
if (len < 0 || ptr == nullptr) if (len < 0 || ptr == nullptr)
return 0; return 0;
@ -41,7 +41,7 @@ i64 MemoryStream::read_into(void* ptr, i64 len)
return len; return len;
} }
i64 MemoryStream::write_from(const void* ptr, i64 len) size_t MemoryStream::write_from(const void* ptr, size_t len)
{ {
if (len < 0 || ptr == nullptr) if (len < 0 || ptr == nullptr)
return 0; return 0;

View File

@ -4,10 +4,10 @@
using namespace Blah; using namespace Blah;
i64 Stream::pipe(Stream& stream, i64 length) size_t Stream::pipe(Stream& stream, size_t length)
{ {
const int BUFFER_LENGTH = 4096; const int BUFFER_LENGTH = 4096;
i64 result = 0; size_t 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;
} }
i64 Stream::write(const void* buffer, i64 length) size_t Stream::write(const void* buffer, size_t length)
{ {
return write_from(buffer, length); return write_from(buffer, length);
} }
i64 Stream::write(const String& string) size_t Stream::write(const String& string)
{ {
return write_from(string.begin(), string.length()); return write_from(string.begin(), string.length());
} }

View File

@ -1,14 +1,8 @@
#include <blah/core/time.h> #include <blah/time.h>
#include <chrono>
using namespace Blah; using namespace Blah;
using namespace std::chrono;
namespace
{
double modf(double x, double m)
{
return x - (int)(x / m) * m;
}
}
u64 Time::ticks = 0; u64 Time::ticks = 0;
u64 Time::previous_ticks = 0; u64 Time::previous_ticks = 0;
@ -48,6 +42,11 @@ bool Time::on_time(double time, double timestamp)
bool Time::between_interval(double time, float interval, float offset) bool Time::between_interval(double time, float interval, float offset)
{ {
static const auto modf = [](double x, double m)
{
return x - (int)(x / m) * m;
};
return modf(time - offset, ((double)interval) * 2) >= interval; return modf(time - offset, ((double)interval) * 2) >= interval;
} }
@ -55,3 +54,23 @@ bool Time::between_interval(float interval, float offset)
{ {
return between_interval(Time::seconds, interval, offset); return between_interval(Time::seconds, interval, offset);
} }
Stopwatch::Stopwatch()
{
reset();
}
void Stopwatch::reset()
{
start_time = std::chrono::duration_cast<std::chrono::microseconds>(system_clock::now().time_since_epoch()).count();
}
u64 Stopwatch::milliseconds()
{
return microseconds() / 1000;
}
u64 Stopwatch::microseconds()
{
return std::chrono::duration_cast<std::chrono::microseconds>(system_clock::now().time_since_epoch()).count() - start_time;
}