restructured project to match a more standard cmake setup

This commit is contained in:
Noel Berry
2020-12-31 13:43:23 -08:00
parent c841bd82a1
commit 241d863ac4
97 changed files with 233 additions and 264 deletions

54
include/blah.h Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include "blah/core/app.h"
#include "blah/core/filesystem.h"
#include "blah/core/log.h"
#include "blah/core/time.h"
#include "blah/containers/vector.h"
#include "blah/containers/stackvector.h"
#include "blah/containers/str.h"
#include "blah/drawing/batch.h"
#include "blah/drawing/spritefont.h"
#include "blah/drawing/subtexture.h"
#include "blah/graphics/blend.h"
#include "blah/graphics/framebuffer.h"
#include "blah/graphics/material.h"
#include "blah/graphics/mesh.h"
#include "blah/graphics/renderpass.h"
#include "blah/graphics/sampler.h"
#include "blah/graphics/shader.h"
#include "blah/graphics/texture.h"
#include "blah/images/aseprite.h"
#include "blah/images/font.h"
#include "blah/images/image.h"
#include "blah/images/packer.h"
#include "blah/input/input.h"
#include "blah/input/virtual_stick.h"
#include "blah/input/virtual_button.h"
#include "blah/input/virtual_axis.h"
#include "blah/math/calc.h"
#include "blah/math/circle.h"
#include "blah/math/color.h"
#include "blah/math/ease.h"
#include "blah/math/line.h"
#include "blah/math/mat3x2.h"
#include "blah/math/mat4x4.h"
#include "blah/math/point.h"
#include "blah/math/quad.h"
#include "blah/math/rect.h"
#include "blah/math/rectI.h"
#include "blah/math/stopwatch.h"
#include "blah/math/vec2.h"
#include "blah/math/vec4.h"
#include "blah/streams/bufferstream.h"
#include "blah/streams/filestream.h"
#include "blah/streams/memorystream.h"
#include "blah/streams/stream.h"
#include "blah/streams/endian.h"

View File

@ -0,0 +1,279 @@
#pragma once
#include <blah/core/log.h>
#include <new>
namespace Blah
{
// A mix between an std::vector and an std::array
// The goal is to have an std::vector implementation that lives
// on the stack instead of the heap
template<class T, size_t Capacity>
class StackVector
{
private:
char m_buffer[sizeof(T) * Capacity];
int m_count;
public:
static inline constexpr size_t MaxCapacity = Capacity;
StackVector();
StackVector(const std::initializer_list<T>& init);
StackVector(const StackVector& src);
StackVector(StackVector&& src) noexcept;
~StackVector();
StackVector& operator=(const StackVector& src);
StackVector& operator=(StackVector&& src) noexcept;
void clear();
int size() const;
constexpr int capacity() { return Capacity; }
T* expand(int amount = 1);
void push_back(const T& item);
void push_back(T&& item);
template<class ...Args>
void emplace_back(Args&&...args);
T& operator[](int index);
const T& operator[](int index) const;
T* data();
const T* data() const;
T* begin();
const T* begin() const;
T* end();
const T* end() const;
T& front();
const T& front() const;
T& back();
const T& back() const;
void erase(int index, int elements = 1);
T pop();
};
template<class T, size_t Capacity>
inline StackVector<T, Capacity>::StackVector()
{
m_count = 0;
}
template<class T, size_t Capacity>
inline StackVector<T, Capacity>::StackVector(const std::initializer_list<T>& init)
{
m_count = 0;
for (auto& it : init)
push_back(it);
}
template<class T, size_t Capacity>
inline StackVector<T, Capacity>::StackVector(const StackVector& src)
{
for (int i = 0; i < src.m_count; i++)
new (data() + i) T(src.data()[i]);
m_count = src.m_count;
}
template<class T, size_t Capacity>
inline StackVector<T, Capacity>::StackVector(StackVector&& src) noexcept
{
for (int i = 0; i < src.m_count; i++)
new (data() + i) T(std::move(src.data()[i]));
m_count = src.m_count;
}
template<class T, size_t Capacity>
inline StackVector<T, Capacity>::~StackVector()
{
clear();
}
template<class T, size_t Capacity>
inline StackVector<T, Capacity>& StackVector<T, Capacity>::operator=(const StackVector& src)
{
clear();
for (int i = 0; i < src.m_count; i++)
data()[i] = src.data()[i];
m_count = src.m_count;
return *this;
}
template<class T, size_t Capacity>
inline StackVector<T, Capacity>& StackVector<T, Capacity>::operator=(StackVector&& src) noexcept
{
clear();
for (int i = 0; i < src.m_count; i++)
data()[i] = std::move(src.data()[i]);
m_count = src.m_count;
return *this;
}
template<class T, size_t Capacity>
inline void StackVector<T, Capacity>::clear()
{
for (int i = 0; i < m_count; i++)
data()[i].~T();
m_count = 0;
}
template<class T, size_t Capacity>
inline int StackVector<T, Capacity>::size() const
{
return m_count;
}
template<class T, size_t Capacity>
inline T* StackVector<T, Capacity>::expand(int amount)
{
BLAH_ASSERT(m_count + amount <= Capacity, "Exceeded StackVector Capacity");
if (amount > 0)
{
int count = m_count;
for (int i = 0; i < amount; i++)
new (data() + count + i) T();
m_count += amount;
return &data()[count];
}
return m_buffer;
}
template<class T, size_t Capacity>
inline void StackVector<T, Capacity>::push_back(const T& item)
{
BLAH_ASSERT(m_count + 1 <= Capacity, "Exceeded StackVector Capacity");
new (data() + m_count) T(item);
m_count++;
}
template<class T, size_t Capacity>
inline void StackVector<T, Capacity>::push_back(T&& item)
{
BLAH_ASSERT(m_count + 1 <= Capacity, "Exceeded StackVector Capacity");
new (data() + m_count) T(std::move(item));
m_count++;
}
template<class T, size_t Capacity>
template<class ...Args>
inline void StackVector<T, Capacity>::emplace_back(Args && ...args)
{
BLAH_ASSERT(m_count + 1 <= Capacity, "Exceeded StackVector Capacity");
new (data() + m_count) T(std::forward<Args>(args)...);
m_count++;
}
template<class T, size_t Capacity>
inline T& StackVector<T, Capacity>::operator[](int index)
{
BLAH_ASSERT(index >= 0 && index < m_count, "Index out of range");
return data()[index];
}
template<class T, size_t Capacity>
inline const T& StackVector<T, Capacity>::operator[](int index) const
{
BLAH_ASSERT(index >= 0 && index < m_count, "Index out of range");
return data()[index];
}
template<class T, size_t Capacity>
inline T* StackVector<T, Capacity>::data()
{
return (T*)m_buffer;
}
template<class T, size_t Capacity>
inline const T* StackVector<T, Capacity>::data() const
{
return (T*)m_buffer;
}
template<class T, size_t Capacity>
inline T* StackVector<T, Capacity>::begin()
{
return (T*)m_buffer;
}
template<class T, size_t Capacity>
inline const T* StackVector<T, Capacity>::begin() const
{
return (T*)m_buffer;
}
template<class T, size_t Capacity>
inline T* StackVector<T, Capacity>::end()
{
return ((T*)m_buffer) + m_count;
}
template<class T, size_t Capacity>
inline const T* StackVector<T, Capacity>::end() const
{
return ((T*)m_buffer) + m_count;
}
template<class T, size_t Capacity>
inline T& StackVector<T, Capacity>::front()
{
BLAH_ASSERT(m_count > 0, "Index out of range");
return data()[0];
}
template<class T, size_t Capacity>
inline const T& StackVector<T, Capacity>::front() const
{
BLAH_ASSERT(m_count > 0, "Index out of range");
return data()[0];
}
template<class T, size_t Capacity>
inline T& StackVector<T, Capacity>::back()
{
BLAH_ASSERT(m_count > 0, "Index out of range");
return data()[m_count - 1];
}
template<class T, size_t Capacity>
inline const T& StackVector<T, Capacity>::back() const
{
BLAH_ASSERT(m_count > 0, "Index out of range");
return data()[m_count - 1];
}
template<class T, size_t Capacity>
inline void StackVector<T, Capacity>::erase(int index, int elements)
{
BLAH_ASSERT(index >= 0 && index + elements <= m_count, "Index out of range");
if (elements >= 1)
{
for (int i = index; i < (m_count - elements); i++)
data()[i] = std::move(data()[i + elements]);
for (int i = m_count - elements; i < m_count; i++)
data()[i].~T();
m_count -= elements;
}
}
template<class T, size_t Capacity>
inline T StackVector<T, Capacity>::pop()
{
BLAH_ASSERT(m_count > 0, "Index out of range");
T value = std::move(data()[m_count - 1]);
data()[m_count - 1].~T();
m_count--;
return value;
}
}

View File

@ -0,0 +1,228 @@
#pragma once
#include <inttypes.h>
#include <stdarg.h>
#include <blah/containers/vector.h>
namespace Blah
{
template<int T>
class StrOf;
using String = StrOf<64>;
class Str
{
public:
Str() { m_buffer = empty_buffer; m_length = m_capacity = m_local_size = 0; }
Str(const char* start, const char* end = nullptr) : Str() { set(start, end); }
Str(const Str& str) : Str() { set(str); }
char& operator[](int index) { return data()[index]; }
const char& operator[](int index) const { return data()[index]; }
// equality operators
bool operator==(const Str& rhs) const;
bool operator!=(const Str& rhs) const;
bool operator==(const char* rhs) const;
bool operator!=(const char* rhs) const;
// assignment operator
Str& operator=(const Str& rhs) { set(rhs.cstr(), rhs.cstr() + rhs.m_length); return *this; }
Str& operator=(const char* rhs) { set(rhs, nullptr); return *this; }
// append string
Str& operator+=(const Str& rhs) { return append(rhs); }
// append cstr
Str& operator+=(const char* rhs) { return append(rhs); }
// combine string
Str operator+(const Str& rhs) { Str str; str.append(*this).append(rhs); return str; }
// combine cstr
Str operator+(const char* rhs) { Str str; str.append(*this).append(rhs); return str; }
// implicit cast to cstr
operator char* () { return cstr(); }
// implicit cast to cstr
operator const char* () const { return cstr(); }
// returns a pointer to the null-terminated string buffer
char* cstr() { return data(); }
// returns a pointer to the null-terminated string buffer
const char* cstr() const { return data(); }
// returns a pointer to the start of the buffer
const char* begin() const { return data(); }
// returns a pointer to the end of the buffer
const char* end() const { return data() + m_length; }
// returns the length of the string
int length() const { return m_length; }
// returns the capacity of the string
int capacity() const { return m_capacity; }
// returns the capacity of the string's stack buffer
int stack_capacity() const { return m_local_size; }
// sets the length of the string.
// this does not set the value of the string!
void set_length(int length);
// ensures the string has the given capacity
void reserve(int capacity);
// appends the given character
Str& append(char c);
// appends the given unicode character
Str& append(uint32_t c);
// appends the given c string
Str& append(const char* start, const char* end = nullptr);
// appends the given string
Str& append(const Str& str, int start = 0, int end = -1);
// appends the given formatted string
Str& append_fmt(const char* fmt, ...);
// appends a utf16 string
Str& append_utf16(const uint16_t* start, const uint16_t* end = nullptr, bool swapEndian = false);
// trims whitespace
Str& trim();
// returns true if the string begins with the given string
bool starts_with(const Str& str, bool ignore_case = false) const { return starts_with(str.cstr(), ignore_case); }
// returns true if the string begins with the given string
bool equals(const Str& str, bool ignore_case = false) const { return str.length() == length() && starts_with(str.cstr(), ignore_case); }
// returns true if the string begins with the given string
bool starts_with(const char* str, bool ignore_case = false) const;
// returns true if the string contains with the given string
bool contains(const Str& str, bool ignore_case = false) const { return contains(str.cstr(), ignore_case); }
// returns true if the string contains with the given string
bool contains(const char* str, bool ignore_case = false) const;
// returns true if the string ends with the given string
bool ends_with(const Str& str, bool ignore_case = false) const { return ends_with(str.cstr(), ignore_case); }
// returns true if the string ends with the given string
bool ends_with(const char* str, bool ignore_case = false) const;
// returns the first index of the given character, or -1 if it isn't found
int first_index_of(char ch) const;
// returns the last index of the given character, or -1 if it isn't found
int last_index_of(char ch) const;
// returns a substring of the string
String substr(int start) const;
// returns a substring of the string
String substr(int start, int end) const;
Vector<String> split(char ch) const;
Str& replace(const Str& old_str, const Str& new_str);
// replaces all occurances of the given character in the string
Str& replace(char c, char r);
// checks if the string has a length of 0
bool empty() const { return m_length <= 0; }
// clears the string length to 0
void clear();
// clears and disposes the internal string buffer
void dispose();
~Str()
{
if (m_buffer != nullptr && m_buffer != empty_buffer)
delete[] m_buffer;
}
protected:
Str(int local_size)
{
m_buffer = nullptr;
m_length = 0;
m_capacity = local_size;
m_local_size = local_size;
}
// returns a pointer to the heap buffer or to our stack allocation
char* data() { return (m_buffer != nullptr ? m_buffer : ((char*)(this) + sizeof(Str))); }
const char* data() const { return (m_buffer != nullptr ? m_buffer : ((char*)(this) + sizeof(Str))); }
void set(const Str& str) { set(str.cstr(), str.cstr() + str.m_length); }
void set(const char* start, const char* end = nullptr);
private:
static char empty_buffer[1];
char* m_buffer;
int m_length;
int m_capacity;
int m_local_size;
};
// combine string
inline Str operator+(const Str& lhs, const Str& rhs) { Str str; str.append(lhs).append(rhs); return str; }
template<int T>
class StrOf : public Str
{
private:
char m_local_buffer[T];
public:
StrOf() : Str(T) { m_local_buffer[0] = '\0'; }
StrOf(const char* rhs, const char* end = nullptr) : Str(T) { m_local_buffer[0] = '\0'; set(rhs, end); }
StrOf(const Str& rhs) : Str(T) { m_local_buffer[0] = '\0'; set(rhs); }
StrOf(const StrOf& rhs) : Str(T) { m_local_buffer[0] = '\0'; set(rhs); }
// assignment operators
StrOf& operator=(const char* rhs) { set(rhs); return *this; }
StrOf& operator=(const Str& rhs) { set(rhs); return *this; }
StrOf& operator=(const StrOf& rhs) { set(rhs); return *this; }
// creates a string from the format
static StrOf fmt(const char* str, ...);
};
template<int T>
StrOf<T> StrOf<T>::fmt(const char* fmt, ...)
{
StrOf<T> str;
int add, diff;
// determine arg length
va_list args;
va_start(args, fmt);
add = vsnprintf(NULL, 0, fmt, args);
va_end(args);
// reserve
auto len = str.length();
str.set_length(len + add);
diff = str.capacity() - len;
if (diff <= 0) diff = 0;
// print out
va_start(args, fmt);
vsnprintf(str.cstr() + len, (size_t)diff, fmt, args);
va_end(args);
return str;
}
}

View File

@ -0,0 +1,337 @@
#pragma once
#include <blah/core/log.h>
#include <type_traits>
#include <new>
namespace Blah
{
template<class T>
class Vector
{
private:
T* m_buffer;
int m_count;
int m_capacity;
public:
Vector();
Vector(int capacity);
Vector(const Vector& src);
Vector(Vector&& src) noexcept;
~Vector();
Vector& operator=(const Vector& src);
Vector& operator=(Vector&& src) noexcept;
void clear();
void dispose();
int size() const;
int capacity() const;
void reserve(int new_capacity);
void resize(int new_count);
T* expand(int amount = 1);
void push_back(const T& item);
void push_back(T&& item);
template<class ...Args>
void emplace_back(Args&&...args);
T& operator[](int index);
const T& operator[](int index) const;
T* data();
const T* data() const;
T* begin();
const T* begin() const;
T* end();
const T* end() const;
T& front();
const T& front() const;
T& back();
const T& back() const;
void erase(int index, int elements = 1);
T pop();
};
template<class T>
inline Vector<T>::Vector()
{
m_buffer = nullptr;
m_count = m_capacity = 0;
}
template<class T>
inline Vector<T>::Vector(int capacity)
{
m_buffer = nullptr;
m_count = m_capacity = 0;
reserve(capacity);
}
template<class T>
inline Vector<T>::Vector(const Vector& src)
{
m_buffer = nullptr;
m_count = m_capacity = 0;
reserve(src.m_capacity);
for (int i = 0; i < src.m_count; i++)
m_buffer[i] = src.m_buffer[i];
m_count = src.m_count;
}
template<class T>
inline Vector<T>::Vector(Vector&& src) noexcept
{
m_buffer = src.m_buffer;
m_capacity = src.m_capacity;
m_count = src.m_count;
src.m_buffer = nullptr;
src.m_capacity = 0;
src.m_count = 0;
}
template<class T>
inline Vector<T>::~Vector()
{
dispose();
}
template<class T>
inline Vector<T>& Vector<T>::operator=(const Vector& src)
{
clear();
reserve(src.m_capacity);
for (int i = 0; i < src.m_count; i++)
m_buffer[i] = src.m_buffer[i];
m_count = src.m_count;
return *this;
}
template<class T>
inline Vector<T>& Vector<T>::operator=(Vector&& src) noexcept
{
dispose();
m_buffer = src.m_buffer;
m_capacity = src.m_capacity;
m_count = src.m_count;
src.m_buffer = nullptr;
src.m_capacity = 0;
src.m_count = 0;
return *this;
}
template<class T>
inline void Vector<T>::clear()
{
for (int i = 0; i < m_count; i++)
m_buffer[i].~T();
m_count = 0;
}
template<class T>
inline void Vector<T>::dispose()
{
clear();
::operator delete (m_buffer, sizeof(T) * m_capacity);
m_capacity = 0;
m_buffer = nullptr;
}
template<class T>
inline int Vector<T>::size() const
{
return m_count;
}
template<class T>
inline int Vector<T>::capacity() const
{
return m_capacity;
}
template<class T>
inline void Vector<T>::reserve(int cap)
{
if (cap > m_capacity)
{
int new_capacity = m_capacity;
if (new_capacity <= 0)
new_capacity = 8;
while (new_capacity < cap)
new_capacity *= 2;
T* new_buffer = (T*)::operator new (sizeof(T) * new_capacity);
for (int i = 0; i < m_count; i++)
{
if (i < new_capacity)
new (new_buffer + i) T(std::move(m_buffer[i]));
m_buffer[i].~T();
}
::operator delete (m_buffer, sizeof(T)* m_capacity);
m_buffer = new_buffer;
m_capacity = new_capacity;
}
}
template<class T>
inline void Vector<T>::resize(int new_count)
{
if (new_count < m_count)
erase(new_count, m_count - new_count);
else
expand(new_count - m_count);
}
template<class T>
inline T* Vector<T>::expand(int amount)
{
if (amount > 0)
{
int count = m_count;
reserve(count + amount);
for (int i = 0; i < amount; i++)
new (m_buffer + count + i) T();
m_count += amount;
return &m_buffer[count];
}
return m_buffer;
}
template<class T>
inline void Vector<T>::push_back(const T& item)
{
emplace_back(item);
}
template<class T>
inline void Vector<T>::push_back(T&& item)
{
emplace_back(std::move(item));
}
template<class T>
template<class ...Args>
inline void Vector<T>::emplace_back(Args&& ...args)
{
reserve(m_count + 1);
new (m_buffer + m_count) T(std::forward<Args>(args)...);
m_count++;
}
template<class T>
inline T& Vector<T>::operator[](int index)
{
BLAH_ASSERT(index >= 0 && index < m_count, "Index out of range");
return m_buffer[index];
}
template<class T>
inline const T& Vector<T>::operator[](int index) const
{
BLAH_ASSERT(index >= 0 && index < m_count, "Index out of range");
return m_buffer[index];
}
template<class T>
inline T* Vector<T>::data()
{
return m_buffer;
}
template<class T>
inline const T* Vector<T>::data() const
{
return m_buffer;
}
template<class T>
inline T* Vector<T>::begin()
{
return m_buffer;
}
template<class T>
inline const T* Vector<T>::begin() const
{
return m_buffer;
}
template<class T>
inline T* Vector<T>::end()
{
return m_buffer + m_count;
}
template<class T>
inline const T* Vector<T>::end() const
{
return m_buffer + m_count;
}
template<class T>
inline T& Vector<T>::front()
{
BLAH_ASSERT(m_count > 0, "Index out of range");
return m_buffer[0];
}
template<class T>
inline const T& Vector<T>::front() const
{
BLAH_ASSERT(m_count > 0, "Index out of range");
return m_buffer[0];
}
template<class T>
inline T& Vector<T>::back()
{
BLAH_ASSERT(m_count > 0, "Index out of range");
return m_buffer[m_count - 1];
}
template<class T>
inline const T& Vector<T>::back() const
{
BLAH_ASSERT(m_count > 0, "Index out of range");
return m_buffer[m_count - 1];
}
template<class T>
inline void Vector<T>::erase(int index, int elements)
{
BLAH_ASSERT(index >= 0 && index + elements <= m_count, "Index out of range");
if (elements >= 1)
{
for (int i = index; i < (m_count - elements); i++)
m_buffer[i] = std::move(m_buffer[i + elements]);
for (int i = m_count - elements; i < m_count; i++)
m_buffer[i].~T();
m_count -= elements;
}
}
template<class T>
inline T Vector<T>::pop()
{
BLAH_ASSERT(m_count > 0, "Index out of range");
T value = std::move(m_buffer[m_count - 1]);
m_buffer[m_count - 1].~T();
m_count--;
return value;
}
}

93
include/blah/core/app.h Normal file
View File

@ -0,0 +1,93 @@
#pragma once
#include <memory>
namespace Blah
{
struct Config
{
const char* name;
int width;
int height;
int max_updates;
int target_framerate;
void (*on_startup)();
void (*on_shutdown)();
void (*on_update)();
void (*on_render)();
void (*on_exit_request)();
void (*on_info)(const char* text);
void (*on_warn)(const char* text);
void (*on_error)(const char* text);
Config();
};
enum class Renderer
{
None = -1,
OpenGL,
D3D11,
Metal,
Count
};
struct RendererFeatures
{
bool instancing = false;
bool origin_bottom_left = false;
int max_texture_size = 0;
};
class FrameBuffer;
using FrameBufferRef = std::shared_ptr<FrameBuffer>;
namespace App
{
// Runs the application
bool run(const Config* config);
// Returns whether the application is running
bool is_running();
// Exits the application
void exit();
// Gets the config data used to run the application
const Config* config();
// Gets the working path
const char* path();
// Gets the user path
const char* user_path();
// Gets the width of the window
int width();
// Gets the height of the window
int height();
// Gets the drawable width of the window
int draw_width();
// Gets the drawable height of the window
int draw_height();
// Gets the content scale based on the OS
float content_scale();
// Toggles fullscreen
void fullscreen(bool enabled);
// Returns the Rendering API in use
Renderer renderer();
// Retrieves the Renderer Features
const RendererFeatures& renderer_features();
// Reference to the window's back buffer
extern const FrameBufferRef backbuffer;
}
}

View File

@ -0,0 +1,41 @@
#pragma once
#include <blah/containers/str.h>
#include <blah/containers/vector.h>
namespace Blah
{
using FilePath = StrOf<265>;
enum class FileMode
{
None = 0,
Read = 1 << 1,
Write = 1 << 2,
ReadWrite = Read | Write,
};
namespace Directory
{
bool create(const FilePath& path);
bool exists(const FilePath& path);
bool remove(const FilePath& path);
Vector<FilePath> enumerate(const FilePath& str, bool recursive = true);
void explore(const FilePath& path);
}
namespace File
{
bool exists(const FilePath& path);
bool remove(const FilePath& path);
}
namespace Path
{
FilePath get_file_name(const FilePath& path);
FilePath get_file_name_no_ext(const FilePath& path);
FilePath get_path_no_ext(const FilePath& path);
FilePath get_path_after(const FilePath& path, const FilePath& after);
FilePath get_directory_name(const FilePath& path);
FilePath normalize(const FilePath& path);
}
}

39
include/blah/core/log.h Normal file
View File

@ -0,0 +1,39 @@
#pragma once
// error / abort
#ifdef DEBUG
#include <stdlib.h>
#define BLAH_ERROR(message) \
do { Log::error(message "\n\tin file: %s:%d", __FILE__, __LINE__); abort(); } while(0)
#define BLAH_ERROR_FMT(message, ...) \
do { Log::error(message "\n\tin file: %s:%d", __VA_ARGS__, __FILE__, __LINE__); abort(); } while(0)
#else
#define BLAH_ERROR(message) \
Log::error(message "\n\tin file: %s:%d", __FILE__, __LINE__)
#define BLAH_ERROR_FMT(message, ...) \
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)
// maximum length of a print/warn/error message
#ifndef BLAH_MESSAGE
#define BLAH_MESSAGE 1024
#endif
namespace Blah
{
namespace Log
{
void print(const char* info, ...);
void warn(const char* info, ...);
void error(const char* info, ...);
}
}

44
include/blah/core/time.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include <inttypes.h>
namespace Blah
{
struct Time
{
// uptime, in milliseconds
static uint64_t milliseconds;
// uptime, in seconds
static float elapsed;
// previous frame uptime, in seconds
static float previous_elapsed;
// delta time from last frame
static float delta;
// time the application should pause for
static float pause_timer;
// pauses the entire application for the given time
static void pause_for(float time);
// returns true on the given time interval
static bool on_interval(float time, float delta, float interval, float offset);
// returns true on the given time interval
static bool on_interval(float delta, float interval, float offset);
// returns true on the given time interval
static bool on_interval(float interval, float offset = 0);
// returns true when the given timestamp is passed
static bool on_time(float time, float timestamp);
// returns true between time intervals
static bool between_interval(float time, float interval, float offset);
// returns true between time intervals
static bool between_interval(float interval, float offset = 0);
};
}

View File

@ -0,0 +1,237 @@
#pragma once
#include <blah/containers/str.h>
#include <blah/math/vec2.h>
#include <blah/math/rect.h>
#include <blah/math/mat3x2.h>
#include <blah/math/mat4x4.h>
#include <blah/math/color.h>
#include <blah/drawing/subtexture.h>
#include <blah/drawing/spritefont.h>
#include <blah/containers/vector.h>
#include <blah/graphics/blend.h>
#include <blah/graphics/sampler.h>
#include <blah/graphics/renderpass.h>
#include <blah/core/app.h>
namespace Blah
{
enum class ColorMode
{
Normal,
Wash
};
enum class TextAlign : char
{
Center = 0,
Left = 1 << 1,
Right = 1 << 2,
Top = 1 << 3,
Bottom = 1 << 4,
TopLeft = Top | Left,
TopRight = Top | Right,
BottomLeft = Bottom | Left,
BottomRight = Bottom | Right
};
inline TextAlign operator|(TextAlign lhs, TextAlign rhs) { return static_cast<TextAlign>(static_cast<char>(lhs) | static_cast<char>(rhs)); }
inline TextAlign operator&(TextAlign lhs, TextAlign rhs) { return static_cast<TextAlign>(static_cast<char>(lhs) & static_cast<char>(rhs)); }
// A simple 2D sprite batcher, used for drawing shapes and textures
class Batch
{
public:
// The name of the Matrix Uniform in the Shader
const char* matrix_uniform;
// Default Sampler, set on clear
TextureSampler default_sampler;
Batch();
Batch(const Batch& other) = delete;
Batch& operator=(const Batch& other) = delete;
~Batch();
// Pushes a new matrix onto the stack, and uses it for transforming all drawing.
// `absolute` means the matrix provided will not be transformed by the current stack.
void push_matrix(const Mat3x2& matrix, bool absolute = false);
// Pops the matrix from the stack
Mat3x2 pop_matrix();
// Gets the current matrix from the top of the stackKO
Mat3x2 peek_matrix() const;
// Pushes a Scissor rectangle. Note this is not transformed by the matrix stack
// or other scissors. Each push is screen-space.
void push_scissor(const Rect& scissor);
// Pops a Scissor rectangle from the stack
Rect pop_scissor();
// Gets the current Scissor rectangle from the top of the stack
Rect peek_scissor() const;
// Pushes a blend mode
void push_blend(const BlendMode& blend);
// Pops a blend mode
BlendMode pop_blend();
// Gets the current BlendMode from the top of the stack
BlendMode peek_blend() const;
// Pushes a Material to use for all drawing. Note that the state of the Material
// is not copied - it will be drawn with the values of the Material at render.
void push_material(const MaterialRef& material);
// Pops a Material
MaterialRef pop_material();
// Gets the current Material from the top of the stack
MaterialRef peek_material() const;
// Pushes a render layer. Lower values are rendered first. This is not super optimized
// and should generally be avoided.
void push_layer(int layer);
// Pops a Layer
int pop_layer();
// Gets the current Layer from the top of the stack
int peek_layer() const;
// Pushes a Color Mode for drawing Textures
void push_color_mode(ColorMode mode);
// Pops a Color MOde
ColorMode pop_color_mode();
// Gets the current ColorMode from the top of the stack
ColorMode peek_color_mode() const;
// Sets the current texture used for drawing. Note that certain functions will override
// this (ex the `str` and `tex` methods)
void set_texture(const TextureRef& texture);
// Sets the current texture sampler for drawing.
void set_sampler(const TextureSampler& sampler);
// Draws the batch to the given target
void render(const FrameBufferRef& target = App::backbuffer);
// Draws the batch to the given target, with the provided matrix
void render(const FrameBufferRef& target, const Mat4x4& matrix);
// Clears the batch
void clear();
// Clears and disposes all resources that the batch is using
void dispose();
void line(const Vec2& from, const Vec2& to, float t, Color color);
void line(const Vec2& from, const Vec2& to, float t, Color fromColor, Color toColor);
void bezier_line(const Vec2& from, const Vec2& b, const Vec2& to, int steps, float t, Color color);
void bezier_line(const Vec2& from, const Vec2& b, const Vec2& c, const Vec2& to, int steps, float t, Color color);
void tri(const Vec2& pos0, const Vec2& pos1, const Vec2& pos2, Color color);
void tri(const Vec2& pos0, const Vec2& pos1, const Vec2& pos2, Color col0, Color col1, Color col2);
void tri(const Vec2& pos0, const Vec2& pos1, const Vec2& pos2, const Vec2& tex0, const Vec2& tex1, const Vec2& tex2, Color color);
void tri(const Vec2& pos0, const Vec2& pos1, const Vec2& pos2, const Vec2& tex0, const Vec2& tex1, const Vec2& tex2, Color col0, Color col1, Color col2);
void tri_line(const Vec2& a, const Vec2& b, const Vec2& c, float t, Color color);
void rect(const Rect& rect, Color color);
void rect_line(const Rect& rect, float t, Color color);
void rect_rounded(const Rect& rect, float radius, int steps, Color color);
void rect_rounded(const Rect& rect, float rtl, int rtl_steps, float rtr, int rtr_steps, float rbr, int rbr_steps, float rbl, int rbl_steps, Color color);
void rect_rounded_line(const Rect& rect, float radius, int steps, float t, Color color);
void rect_rounded_line(const Rect& rect, float rtl, int rtl_steps, float rtr, int rtr_steps, float rbr, int rbr_steps, float rbl, int rbl_steps, float t, Color color);
void semi_circle(Vec2 center, float start_radians, float end_radians, float radius, int steps, Color centerColor, Color edgeColor);
void semi_circle(Vec2 center, float start_radians, float end_radians, float radius, int steps, Color color);
void semi_circle_line(Vec2 center, float start_radians, float end_radians, float radius, int steps, float t, Color color);
void circle(const Vec2 center, float radius, int steps, Color color);
void circle(const Vec2 center, float radius, int steps, Color center_color, Color outer_color);
void circle_line(const Vec2 center, float raidus, float t, int steps, Color color);
void quad(const Vec2& pos0, const Vec2& pos1, const Vec2& pos2, const Vec2& pos3, Color color);
void quad(const Vec2& pos0, const Vec2& pos1, const Vec2& pos2, const Vec2& pos3, Color col0, Color col1, Color col2, Color col3);
void quad(const Vec2& pos0, const Vec2& pos1, const Vec2& pos2, const Vec2& pos3, const Vec2& tex0, const Vec2& tex1, const Vec2& tex2, const Vec2& tex3, Color color);
void quad(const Vec2& pos0, const Vec2& pos1, const Vec2& pos2, const Vec2& pos3, const Vec2& tex0, const Vec2& tex1, const Vec2& tex2, const Vec2& tex3, Color col0, Color col1, Color col2, Color col3);
void quad_line(const Vec2& a, const Vec2& b, const Vec2& c, const Vec2& d, float t, Color color);
void arrow_head(const Vec2& point_pos, float radians, float side_len, Color color);
void arrow_head(const Vec2& point_pos, const Vec2& from_pos, float side_len, Color color);
void tex(const TextureRef& texture, const Vec2& position = Vec2::zero, Color color = Color::white);
void tex(const TextureRef& texture, const Vec2& position, const Vec2& origin, const Vec2& scale, float rotation, Color color);
void tex(const TextureRef& texture, const Rect& clip, const Vec2& position, const Vec2& origin, const Vec2& scale, float rotation, Color color);
void tex(const Subtexture& subtexture, const Vec2& position = Vec2::zero, Color color = Color::white);
void tex(const Subtexture& subtexture, const Vec2& pos, const Vec2& origin, const Vec2& scale, float rotation, Color color);
void tex(const Subtexture& subtexture, const Rect& clip, const Vec2& pos, const Vec2& origin, const Vec2& scale, float rotation, Color color);
void str(const SpriteFont& font, const String& text, const Vec2& pos, Color color);
void str(const SpriteFont& font, const String& text, const Vec2& pos, TextAlign align, float size, Color color);
private:
struct Vertex
{
Vec2 pos;
Vec2 tex;
Color col;
uint8_t mult;
uint8_t wash;
uint8_t fill;
uint8_t pad;
};
struct DrawBatch
{
int layer;
int offset;
int elements;
MaterialRef material;
BlendMode blend;
TextureRef texture;
TextureSampler sampler;
bool flip_vertically;
Rect scissor;
DrawBatch() :
layer(0),
offset(0),
elements(0),
blend(BlendMode::Normal),
flip_vertically(false),
scissor(0, 0, -1, -1) {}
};
static ShaderRef m_default_shader;
MaterialRef m_default_material;
MeshRef m_mesh;
Mat3x2 m_matrix;
ColorMode m_color_mode;
uint8_t m_tex_mult;
uint8_t m_tex_wash;
DrawBatch m_batch;
Vector<Vertex> m_vertices;
Vector<uint32_t> m_indices;
Vector<Mat3x2> m_matrix_stack;
Vector<Rect> m_scissor_stack;
Vector<BlendMode> m_blend_stack;
Vector<MaterialRef> m_material_stack;
Vector<ColorMode> m_color_mode_stack;
Vector<int> m_layer_stack;
Vector<DrawBatch> m_batches;
void render_single_batch(RenderPass& pass, const DrawBatch& b, const Mat4x4& matrix);
};
}

View File

@ -0,0 +1,76 @@
#pragma once
#include <inttypes.h>
#include <blah/containers/str.h>
#include <blah/containers/vector.h>
#include <blah/drawing/subtexture.h>
#include <blah/math/vec2.h>
#include <unordered_map>
namespace Blah
{
class Font;
class SpriteFont
{
public:
struct Character
{
Subtexture subtexture;
float advance = 0;
Vec2 offset;
};
private:
// charset & kerning maps
std::unordered_map<uint32_t, Character> m_characters;
std::unordered_map<uint64_t, float> m_kerning;
// built texture
Vector<TextureRef> m_atlas;
public:
static const uint32_t* ASCII;
String name;
float size;
float ascent;
float descent;
float line_gap;
// Note:
// charset is a list of range pairs, until a 0 terminator (ex. 32,128,0)
SpriteFont();
SpriteFont(const char* file, float size);
SpriteFont(const char* file, float size, const uint32_t* charset);
SpriteFont(const Font& font, float size);
SpriteFont(const Font& font, float size, const uint32_t* charset);
SpriteFont(const SpriteFont&) = delete;
SpriteFont(SpriteFont&& src) noexcept;
~SpriteFont();
void dispose();
SpriteFont& operator=(const SpriteFont&) = delete;
SpriteFont& operator=(SpriteFont&& src) noexcept;
float height() const { return ascent - descent; }
float line_height() const { return ascent - descent + line_gap; }
const Vector<TextureRef>& textures() { return m_atlas; }
float width_of(const String& text) const;
float width_of_line(const String& text, int start = 0) const;
float height_of(const String& text) const;
void build(const char* file, float size, const uint32_t* charset);
void build(const Font& font, float size, const uint32_t* charset);
float get_kerning(uint32_t codepoint0, uint32_t codepoint1) const;
void set_kerning(uint32_t codepoint0, uint32_t codepoint1, float kerning);
Character& get_character(uint32_t codepoint) { return m_characters[codepoint]; }
const Character& get_character(uint32_t codepoint) const;
Character& operator[](uint32_t codepoint) { return m_characters[codepoint]; }
const Character& operator[](uint32_t codepoint) const;
};
}

View File

@ -0,0 +1,48 @@
#pragma once
#include <blah/graphics/texture.h>
#include <blah/math/rect.h>
namespace Blah
{
// Subtexture is a view into a texture, and can be used to
// easily represent sprites in a larger texture atlas.
struct Subtexture
{
// Reference to our Texture
TextureRef texture;
// Source rectangle, in pixels
Rect source;
// Frame rectangle, in pixels. This describes padding around the image.
// This is useful for drawing images that have been trimmed. Ex. if the source
// is 32,32, but the original image was 64,64, the frame could be -16,-16,64,64
Rect frame;
// `draw_coords` are automatically assigned through `update` method
Vec2 draw_coords[4];
// `tex_coords` are automatically assigned through the `update` method
Vec2 tex_coords[4];
Subtexture();
Subtexture(const TextureRef& texture);
Subtexture(const TextureRef& texture, Rect source);
Subtexture(const TextureRef& texture, Rect source, Rect frame);
// Returns the width of the image
float width() const { return frame.w; }
// Returns the height of the image
float height() const { return frame.h; }
// updates the `draw_coords` and `tex_coords`
void update();
// returns resulting source and frame rectangles based on the provided clip rectangle
void crop_info(const Rect& clip, Rect* dest_source, Rect* dest_frame) const;
// returns a subtexture cropped to the provided rectangle
Subtexture crop(const Rect& clip) const;
};
}

View File

@ -0,0 +1,104 @@
#pragma once
#include <inttypes.h>
namespace Blah
{
enum class BlendOp
{
Add,
Subtract,
ReverseSubtract,
Min,
Max
};
enum class BlendFactor
{
Zero,
One,
SrcColor,
OneMinusSrcColor,
DstColor,
OneMinusDstColor,
SrcAlpha,
OneMinusSrcAlpha,
DstAlpha,
OneMinusDstAlpha,
ConstantColor,
OneMinusConstantColor,
ConstantAlpha,
OneMinusConstantAlpha,
SrcAlphaSaturate,
Src1Color,
OneMinusSrc1Color,
Src1Alpha,
OneMinusSrc1Alpha
};
enum class BlendMask
{
None = 0,
Red = 1,
Green = 2,
Blue = 4,
Alpha = 8,
RGB = Red | Green | Blue,
RGBA = Red | Green | Blue | Alpha,
};
struct BlendMode
{
// Normal, pre-multiplied, Blend Mode
static const BlendMode Normal;
// Subtractive Blend Mode
static const BlendMode Subtract;
BlendOp color_op;
BlendFactor color_src;
BlendFactor color_dst;
BlendOp alpha_op;
BlendFactor alpha_src;
BlendFactor alpha_dst;
BlendMask mask;
uint32_t rgba;
BlendMode() = default;
BlendMode(BlendOp op, BlendFactor src, BlendFactor dst) :
color_op(op),
color_src(src),
color_dst(dst),
alpha_op(op),
alpha_src(src),
alpha_dst(dst),
mask(BlendMask::RGBA),
rgba(0xffffffff) {}
BlendMode(
BlendOp color_op, BlendFactor color_src, BlendFactor color_dst,
BlendOp alpha_op, BlendFactor alpha_src, BlendFactor alpha_dst,
BlendMask blend_mask, uint32_t blend_rgba) :
color_op(color_op),
color_src(color_src),
color_dst(color_dst),
alpha_op(alpha_op),
alpha_src(alpha_src),
alpha_dst(alpha_dst),
mask(blend_mask),
rgba(blend_rgba) {}
bool operator==(const BlendMode& rhs) const
{
return
color_op == rhs.color_op && color_src == rhs.color_src && color_dst == rhs.color_dst &&
alpha_op == rhs.alpha_op && alpha_src == rhs.alpha_src && alpha_dst == rhs.alpha_dst &&
mask == rhs.mask && rgba == rhs.rgba;
}
bool operator!=(const BlendMode& rhs) const
{
return !(*this == rhs);
}
};
}

View File

@ -0,0 +1,62 @@
#pragma once
#include <blah/graphics/texture.h>
#include <blah/containers/stackvector.h>
#include <blah/math/color.h>
#include <memory>
// 4 color attachments + 1 depth/stencil
#define BLAH_ATTACHMENTS 5
namespace Blah
{
typedef StackVector<TextureRef, BLAH_ATTACHMENTS> Attachments;
class FrameBuffer;
typedef std::shared_ptr<FrameBuffer> FrameBufferRef;
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 TextureFormat* attachments, int attachmentCount);
// 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
virtual TextureRef& attachment(int index) = 0;
// Gets the Attachment at a given index from the FrameBuffer
virtual const TextureRef& attachment(int index) const = 0;
// Gets the width of the FrameBuffer
virtual int width() const = 0;
// Gets the height of the FrameBuffer
virtual int height() const = 0;
// Clears the FrameBuffer
virtual void clear(Color color) = 0;
};
}

View File

@ -0,0 +1,82 @@
#pragma once
#include <blah/graphics/texture.h>
#include <blah/graphics/shader.h>
#include <blah/graphics/sampler.h>
#include <blah/containers/vector.h>
#include <memory>
namespace Blah
{
class Material;
typedef std::shared_ptr<Material> MaterialRef;
class Material final
{
private:
Material(const ShaderRef& shader);
public:
// Copy / Moves not allowed
Material(const Material&) = delete;
Material(Material&&) = delete;
Material& operator=(const Material&) = delete;
Material& operator=(Material&&) = delete;
// Default destructor
~Material() = default;
// Creates a new Material from the given Shader.
// If the Shader is invalid, it will return an invalid MaterialRef.
static MaterialRef create(const ShaderRef& shader);
// Returns the Shader assigned to the Material.
const ShaderRef shader() const;
// Sets the texture
void set_texture(const char* name, const TextureRef& texture, int array_index = 0);
// Sets the texture
void set_texture(int slot, const TextureRef& texture, int array_index = 0);
// Gets the texture, or an empty reference if invalid
TextureRef get_texture(const char* name, int array_index = 0) const;
// Gets the texture, or an empty reference if invalid
TextureRef get_texture(int slot, int array_index = 0) const;
// Sets the sampler
void set_sampler(const char* name, const TextureSampler& sampler, int array_index = 0);
// Sets the sampler
void set_sampler(int slot, const TextureSampler& sampler, int array_index = 0);
// Gets the sampler
TextureSampler get_sampler(const char* name, int array_index = 0) const;
// Gets the sampler
TextureSampler get_sampler(int slot, int array_index = 0) const;
// Sets the value. `length` is the total number of floats to set
// For example if the uniform is a float2[4], a total of 8 float values
// can be set.
void set_value(const char* name, const float* value, int64_t length);
// Gets a pointer to the values of the given Uniform, or nullptr if it doesn't exist.
const float* get_value(const char* name, int64_t* length = nullptr) const;
// Returns the internal Texture buffer
const Vector<TextureRef>& textures() const;
// Returns the internal Sampler buffer
const Vector<TextureSampler>& samplers() const;
// Returns the interal float buffer of all the values
const float* data() const;
private:
ShaderRef m_shader;
Vector<TextureRef> m_textures;
Vector<TextureSampler> m_samplers;
Vector<float> m_data;
};
}

View File

@ -0,0 +1,93 @@
#pragma once
#include <inttypes.h>
#include <memory>
#include <blah/containers/stackvector.h>
namespace Blah
{
enum class VertexType
{
None,
Float,
Float2,
Float3,
Float4,
Byte4,
UByte4,
Short2,
UShort2,
Short4,
UShort4
};
struct VertexAttribute
{
// Location / Attribute Index
int index = 0;
// Vertex Type
VertexType type = VertexType::None;
// Whether the Vertex should be normalized (doesn't apply to Floats)
bool normalized = false;
};
struct VertexFormat
{
// List of Attributes
StackVector<VertexAttribute, 16> attributes;
// Total size in bytes of each Vertex element
int stride = 0;
VertexFormat() = default;
VertexFormat(std::initializer_list<VertexAttribute> attributes, int stride = 0);
};
enum class IndexFormat
{
UInt16,
UInt32
};
class Mesh;
typedef std::shared_ptr<Mesh> MeshRef;
class Mesh
{
protected:
Mesh() = default;
public:
// Copy / Moves not allowed
Mesh(const Mesh&) = delete;
Mesh(Mesh&&) = delete;
Mesh& operator=(const Mesh&) = delete;
Mesh& operator=(Mesh&&) = delete;
// Default Destructor
virtual ~Mesh() = default;
// Creates a new Mesh.
// If the Mesh creation fails, it will return an invalid Mesh.
static MeshRef create();
// Uploads the given index buffer to the Mesh
virtual void index_data(IndexFormat format, const void* indices, int64_t count) = 0;
// Uploads the given vertex buffer to the Mesh
virtual void vertex_data(const VertexFormat& format, const void* vertices, int64_t count) = 0;
// Uploads the given instance buffer to the Mesh
virtual void instance_data(const VertexFormat& format, const void* instances, int64_t count) = 0;
// Gets the index count of the Mesh
virtual int64_t index_count() const = 0;
// Gets the vertex count of the Mesh
virtual int64_t vertex_count() const = 0;
// Gets the instance count of the Mesh
virtual int64_t instance_count() const = 0;
};
}

View File

@ -0,0 +1,81 @@
#pragma once
#include <inttypes.h>
#include <blah/math/rect.h>
#include <blah/containers/str.h>
#include <blah/graphics/texture.h>
#include <blah/graphics/framebuffer.h>
#include <blah/graphics/mesh.h>
#include <blah/graphics/shader.h>
#include <blah/graphics/material.h>
#include <blah/graphics/blend.h>
namespace Blah
{
enum class Compare
{
None,
Always,
Never,
Less,
Equal,
LessOrEqual,
Greater,
NotEqual,
GreatorOrEqual
};
enum class Cull
{
None = 0,
Front = 1,
Back = 2,
};
struct RenderPass
{
// Framebuffer to draw to
FrameBufferRef target;
// Mesh to draw with
MeshRef mesh;
// Material to draw with
MaterialRef material;
// Whether the RenderPass should use a specific viewport
bool has_viewport;
// Whether the RenderPass should use a scissor rectangle
bool has_scissor;
// The viewport (only used if hasViewport is true)
Rect viewport;
// The scissor rectangle (only used if hasScissor is true)
Rect scissor;
// First index in the Mesh to draw from
int64_t index_start;
// Total amount of indices to draw from the Mesh
int64_t index_count;
// Total amount of instances to draw from the Mesh
int64_t instance_count;
// Depth Compare Function
Compare depth;
// Cull Mode
Cull cull;
// Blend Mode
BlendMode blend;
// Initializes a default RenderPass
RenderPass();
// Performs the render
void perform();
};
}

View File

@ -0,0 +1,53 @@
#pragma once
namespace Blah
{
enum class TextureFilter
{
None,
Linear,
Nearest
};
enum class TextureWrap
{
None,
Clamp,
Repeat
};
struct TextureSampler
{
TextureFilter filter;
TextureWrap wrap_x;
TextureWrap wrap_y;
TextureSampler() :
filter(TextureFilter::Linear),
wrap_x(TextureWrap::Repeat),
wrap_y(TextureWrap::Repeat) {}
TextureSampler(TextureFilter filter) :
filter(filter),
wrap_x(TextureWrap::Repeat),
wrap_y(TextureWrap::Repeat) {}
TextureSampler(TextureFilter filter, TextureWrap wrap_x, TextureWrap wrap_y) :
filter(filter),
wrap_x(wrap_x),
wrap_y(wrap_y) {}
bool operator==(const TextureSampler& rhs) const
{
return
filter == rhs.filter &&
wrap_x == rhs.wrap_x &&
wrap_y == rhs.wrap_y;
}
bool operator!=(const TextureSampler& rhs) const
{
return !(*this == rhs);
}
};
}

View File

@ -0,0 +1,101 @@
#pragma once
#include <blah/containers/stackvector.h>
#include <blah/containers/str.h>
#include <memory>
namespace Blah
{
// Supported Uniform Types
enum class UniformType
{
None,
Float,
Float2,
Float3,
Float4,
Mat3x2,
Mat4x4,
Texture2D,
Sampler2D
};
// Supported Shader Types
enum class ShaderType
{
None = 0,
Vertex = 1 << 0,
Fragment = 1 << 1
};
// Uniform Info, provided by the Shader
struct UniformInfo
{
// Name of the Uniform
String name;
// The Value type of the Uniform
UniformType type;
// The Shader type the Uniform is a part of
ShaderType shader;
// Some rendering APIs have uniform buffers. The `buffer_index`
// specifies which buffer the uniform belongs to
int buffer_index;
// Array length of the Uniform (ex. a vec2[4] would be 4)
int array_length;
};
// Data to be passed to the shader to construct it
struct ShaderData
{
struct HLSL_Attribute
{
// Semantic Name
const char* semantic_name = nullptr;
// (optional) Semantic Index
int semantic_index = 0;
};
// Vertex Shader Program data
String vertex;
// Fragment Shader Program data
String fragment;
// HLSL Attributes - required for D3D11
StackVector<HLSL_Attribute, 16> hlsl_attributes;
};
class Shader;
typedef std::shared_ptr<Shader> ShaderRef;
class Shader
{
protected:
Shader() = default;
public:
// Copy / Moves not allowed
Shader(const Shader&) = delete;
Shader(Shader&&) = delete;
Shader& operator=(const Shader&) = delete;
Shader& operator=(Shader&&) = delete;
// Default Destructor
virtual ~Shader() = default;
// Creates a Shader with the given Shader Data.
// If the Shader creation fails, it will return an invalid ShaderRef.
static ShaderRef create(const ShaderData& data);
// Gets a list of Shader Uniforms from Shader
virtual Vector<UniformInfo>& uniforms() = 0;
// Gets a list of Shader Uniforms from Shader
virtual const Vector<UniformInfo>& uniforms() const = 0;
};
}

View File

@ -0,0 +1,78 @@
#pragma once
#include <memory>
namespace Blah
{
enum class TextureFormat
{
None,
R,
RG,
RGBA,
DepthStencil,
Count
};
class Image;
class Stream;
class Texture;
typedef std::shared_ptr<Texture> TextureRef;
class Texture
{
protected:
Texture() = default;
public:
// Copy / Moves not allowed
Texture(const Texture&) = delete;
Texture(Texture&&) = delete;
Texture& operator=(const Texture&) = delete;
Texture& operator=(Texture&&) = delete;
// Default Destructor
virtual ~Texture() = default;
// Creates a new Texture.
// If the Texture creation fails, it will return an invalid TextureRef.
static TextureRef create(const Image& image);
// Creates a new Texture.
// If the Texture creation fails, it will return an invalid TextureRef.
static TextureRef create(int width, int height, unsigned char* rgba);
// Creates a new Texture.
// If the Texture creation fails, it will return an invalid TextureRef.
static TextureRef create(int width, int height, TextureFormat format);
// Creates a new Texture from a Stream.
// If the Texture creation fails, it will return an invalid TextureRef.
static TextureRef create(Stream& stream);
// Creates a new Texture from a File.
// If the Texture creation fails, it will return an invalid TextureRef.
static TextureRef create(const char* file);
// gets the width of the texture
virtual int width() const = 0;
// gets the height of the texture
virtual int height() const = 0;
// Gets the format of the Texture
virtual TextureFormat format() const = 0;
// Sets the data of the Texture.
// Note that the pixel buffer should be in the same format as the Texture. There is no row padding.
// If the pixel buffer isn't the same size as the texture, it will set the minimum available amount of data.
virtual void set_data(unsigned char* data) = 0;
// Gets the data of the Texture.
// Note that the pixel buffer will be written to in the same format as the Texture,
// and you should allocate enough space for the full texture. There is no row padding.
virtual void get_data(unsigned char* data) = 0;
// Returns true if the Texture is part of a FrameBuffer
virtual bool is_framebuffer() const = 0;
};
}

View File

@ -0,0 +1,153 @@
#pragma once
#include <blah/math/color.h>
#include <blah/images/image.h>
#include <blah/containers/str.h>
#include <blah/streams/stream.h>
namespace Blah
{
// A simple Aseprite file parser.
// This implementation does not support Aseprite blendmodes,
// besides the default blend mode.
class Aseprite
{
public:
enum class Modes
{
Indexed = 1,
Grayscale = 2,
RGBA = 4
};
enum class Chunks
{
OldPaletteA = 0x0004,
OldPaletteB = 0x0011,
Layer = 0x2004,
Cel = 0x2005,
CelExtra = 0x2006,
Mask = 0x2016,
Path = 0x2017,
FrameTags = 0x2018,
Palette = 0x2019,
UserData = 0x2020,
Slice = 0x2022
};
enum class LoopDirections
{
Forward = 0,
Reverse = 1,
PingPong = 2
};
enum class LayerFlags
{
Visible = 1,
Editable = 2,
LockMovement = 4,
Background = 8,
PreferLinkedCels = 16,
Collapsed = 32,
Reference = 64
};
enum class LayerTypes
{
Normal = 0,
Group = 1
};
struct UserData
{
String text;
Color color;
};
struct Layer;
struct Cel
{
int layer_index = 0;
int linked_frame_index = 0;
int x = 0;
int y = 0;
unsigned char alpha = 0;
Image image;
UserData userdata;
};
struct Frame
{
int duration = 0;
Image image;
Vector<Cel> cels;
};
struct Layer
{
LayerFlags flag = (LayerFlags)0;
LayerTypes type = LayerTypes::Normal;
String name;
int child_level = 0;
int blendmode = 0;
unsigned char alpha = 0;
bool visible = true;
UserData userdata;
};
struct Tag
{
String name;
LoopDirections loops = LoopDirections::Forward;
int from = 0;
int to = 0;
Color color;
UserData userdata;
};
struct Slice
{
int frame = 0;
String name;
Point origin;
int width = 0;
int height = 0;
bool has_pivot = false;
Point pivot;
UserData userdata;
};
Modes mode = Modes::RGBA;
int width = 0;
int height = 0;
Vector<Layer> layers;
Vector<Frame> frames;
Vector<Tag> tags;
Vector<Slice> slices;
Vector<Color> palette;
Aseprite();
Aseprite(const char* path);
Aseprite(Stream& stream);
Aseprite(const Aseprite& src);
Aseprite(Aseprite&& src) noexcept;
Aseprite& operator=(const Aseprite& src);
Aseprite& operator=(Aseprite&& src) noexcept;
~Aseprite();
private:
UserData* m_last_userdata = nullptr;
void parse(Stream& stream);
void parse_layer(Stream& stream, int frame);
void parse_cel(Stream& stream, int frame, size_t maxPosition);
void parse_palette(Stream& stream, int frame);
void parse_user_data(Stream& stream, int frame);
void parse_tag(Stream& stream, int frame);
void parse_slice(Stream& stream, int frame);
void render_cel(Cel* cel, Frame* frame);
};
}

View File

@ -0,0 +1,62 @@
#pragma once
#include <blah/streams/stream.h>
#include <blah/images/image.h>
#include <blah/containers/str.h>
namespace Blah
{
typedef uint32_t Codepoint;
class Font
{
public:
struct Char
{
int glyph = 0;
int width = 0;
int height = 0;
float advance = 0;
float offset_x = 0;
float offset_y = 0;
float scale = 0;
bool has_glyph = false;
};
Font();
Font(Stream& stream);
Font(const char* path);
Font(const Font&) = delete;
Font& operator=(const Font&) = delete;
Font(Font&& src) noexcept;
Font& operator=(Font&& src) noexcept;
~Font();
void dispose();
const char* family_name() const;
const char* style_name() const;
int ascent() const;
int descent() const;
int line_gap() const;
int height() const;
int line_height() const;
int get_glyph(Codepoint codepoint) const;
float get_scale(float size) const;
float get_kerning(int glyph1, int glyph2, float scale) const;
Char get_character(int glyph, float scale) const;
bool get_image(const Char& ch, Color* pixels) const;
bool is_valid() const;
private:
void load(Stream& stream);
void* m_font;
unsigned char* m_data;
String m_family_name;
String m_style_name;
int m_ascent;
int m_descent;
int m_line_gap;
bool m_valid;
};
}

View File

@ -0,0 +1,42 @@
#pragma once
#include <blah/math/color.h>
#include <blah/math/rectI.h>
#include <blah/math/point.h>
namespace Blah
{
class Stream;
class Image
{
public:
int width = 0;
int height = 0;
Color* pixels = nullptr;
Image();
Image(Stream& stream);
Image(const char* file);
Image(int width, int height);
Image(const Image& src);
Image& operator=(const Image& src);
Image(Image&& src) noexcept;
Image& operator=(Image&& src) noexcept;
~Image();
void from_stream(Stream& stream);
void dispose();
void premultiply();
void set_pixels(const RectI& rect, Color* data);
bool save_png(const char* file) const;
bool save_png(Stream& stream) const;
bool save_jpg(const char* file, int quality) const;
bool save_jpg(Stream& stream, int quality) const;
void get_pixels(Color* dest, const Point& destPos, const Point& destSize, RectI sourceRect);
Image get_sub_image(const RectI& sourceRect);
private:
bool m_stbi_ownership;
};
}

View File

@ -0,0 +1,75 @@
#pragma once
#include <blah/images/image.h>
#include <blah/math/color.h>
#include <blah/math/rectI.h>
#include <blah/math/point.h>
#include <blah/containers/str.h>
#include <blah/containers/vector.h>
#include <blah/streams/bufferstream.h>
namespace Blah
{
// Texture Packer, which takes source images and combines
// them into a single large texture.
class Packer
{
public:
class Entry
{
friend class Packer;
private:
int64_t memory_index;
public:
uint64_t id;
int page;
bool empty;
RectI frame;
RectI packed;
Entry(uint64_t id, const RectI& frame)
: memory_index(0), id(id), page(0), empty(true), frame(frame), packed(0, 0, 0, 0) {}
};
int max_size;
bool power_of_two;
int spacing;
int padding;
Vector<Image> pages;
Vector<Entry> entries;
Packer();
Packer(int max_size, int spacing, bool power_of_two);
Packer(const Packer&) = delete;
Packer& operator=(const Packer&) = delete;
Packer(Packer&& src) noexcept;
Packer& operator=(Packer&& src) noexcept;
~Packer();
void add(uint64_t id, int width, int height, const Color* pixels);
void add(uint64_t id, const Image& bitmap);
void add(uint64_t id, const String& path);
void pack();
void clear();
void dispose();
private:
struct Node
{
bool used;
RectI rect;
Node* right;
Node* down;
Node();
Node* Find(int w, int h);
Node* Reset(const RectI& rect);
};
bool m_dirty;
BufferStream m_buffer;
void add_entry(uint64_t id, int w, int h, const Color* pixels);
};
}

467
include/blah/input/input.h Normal file
View File

@ -0,0 +1,467 @@
#pragma once
#include <inttypes.h>
#include <blah/math/vec2.h>
// These are generally copied from the SDL2 Scancode Keys
#define BLAH_KEY_DEFINITIONS \
DEFINE_KEY(Unknown, 0) \
DEFINE_KEY(A, 4) \
DEFINE_KEY(B, 5) \
DEFINE_KEY(C, 6) \
DEFINE_KEY(D, 7) \
DEFINE_KEY(E, 8) \
DEFINE_KEY(F, 9) \
DEFINE_KEY(G, 10) \
DEFINE_KEY(H, 11) \
DEFINE_KEY(I, 12) \
DEFINE_KEY(J, 13) \
DEFINE_KEY(K, 14) \
DEFINE_KEY(L, 15) \
DEFINE_KEY(M, 16) \
DEFINE_KEY(N, 17) \
DEFINE_KEY(O, 18) \
DEFINE_KEY(P, 19) \
DEFINE_KEY(Q, 20) \
DEFINE_KEY(R, 21) \
DEFINE_KEY(S, 22) \
DEFINE_KEY(T, 23) \
DEFINE_KEY(U, 24) \
DEFINE_KEY(V, 25) \
DEFINE_KEY(W, 26) \
DEFINE_KEY(X, 27) \
DEFINE_KEY(Y, 28) \
DEFINE_KEY(Z, 29) \
DEFINE_KEY(D1, 30) \
DEFINE_KEY(D2, 31) \
DEFINE_KEY(D3, 32) \
DEFINE_KEY(D4, 33) \
DEFINE_KEY(D5, 34) \
DEFINE_KEY(D6, 35) \
DEFINE_KEY(D7, 36) \
DEFINE_KEY(D8, 37) \
DEFINE_KEY(D9, 38) \
DEFINE_KEY(D0, 39) \
DEFINE_KEY(Enter, 40) \
DEFINE_KEY(Escape, 41) \
DEFINE_KEY(Backspace, 42) \
DEFINE_KEY(Tab, 43) \
DEFINE_KEY(Space, 44) \
DEFINE_KEY(Minus, 45) \
DEFINE_KEY(Equals, 46) \
DEFINE_KEY(LeftBracket, 47) \
DEFINE_KEY(RightBracket, 48) \
DEFINE_KEY(BackSlash, 49) \
DEFINE_KEY(NonUSHash, 50) \
DEFINE_KEY(Semicolon, 51) \
DEFINE_KEY(Apostrophe, 52) \
DEFINE_KEY(Grave, 53) \
DEFINE_KEY(Comma, 54) \
DEFINE_KEY(Period, 55) \
DEFINE_KEY(Slash, 56) \
DEFINE_KEY(Capslock, 57) \
DEFINE_KEY(F1, 58) \
DEFINE_KEY(F2, 59) \
DEFINE_KEY(F3, 60) \
DEFINE_KEY(F4, 61) \
DEFINE_KEY(F5, 62) \
DEFINE_KEY(F6, 63) \
DEFINE_KEY(F7, 64) \
DEFINE_KEY(F8, 65) \
DEFINE_KEY(F9, 66) \
DEFINE_KEY(F10, 67) \
DEFINE_KEY(F11, 68) \
DEFINE_KEY(F12, 69) \
DEFINE_KEY(PrintScreen, 70) \
DEFINE_KEY(ScrollLock, 71) \
DEFINE_KEY(Pause, 72) \
DEFINE_KEY(Insert, 73) \
DEFINE_KEY(Home, 74) \
DEFINE_KEY(PageUp, 75) \
DEFINE_KEY(Delete, 76) \
DEFINE_KEY(End, 77) \
DEFINE_KEY(PageDown, 78) \
DEFINE_KEY(Right, 79) \
DEFINE_KEY(Left, 80) \
DEFINE_KEY(Down, 81) \
DEFINE_KEY(Up, 82) \
DEFINE_KEY(NumlockClear, 83) \
DEFINE_KEY(KP_Divide, 84) \
DEFINE_KEY(KP_Multiply, 85) \
DEFINE_KEY(KP_Minus, 86) \
DEFINE_KEY(KP_Plus, 87) \
DEFINE_KEY(KP_Enter, 88) \
DEFINE_KEY(KP_1, 89) \
DEFINE_KEY(KP_2, 90) \
DEFINE_KEY(KP_3, 91) \
DEFINE_KEY(KP_4, 92) \
DEFINE_KEY(KP_5, 93) \
DEFINE_KEY(KP_6, 94) \
DEFINE_KEY(KP_7, 95) \
DEFINE_KEY(KP_8, 96) \
DEFINE_KEY(KP_9, 97) \
DEFINE_KEY(KP_0, 98) \
DEFINE_KEY(KP_Period, 99) \
DEFINE_KEY(NonUSBackSlash, 100) \
DEFINE_KEY(Application, 101) \
DEFINE_KEY(Power, 102) \
DEFINE_KEY(KP_Equals, 103) \
DEFINE_KEY(F13, 104) \
DEFINE_KEY(F14, 105) \
DEFINE_KEY(F15, 106) \
DEFINE_KEY(F16, 107) \
DEFINE_KEY(F17, 108) \
DEFINE_KEY(F18, 109) \
DEFINE_KEY(F19, 110) \
DEFINE_KEY(F20, 111) \
DEFINE_KEY(F21, 112) \
DEFINE_KEY(F22, 113) \
DEFINE_KEY(F23, 114) \
DEFINE_KEY(F24, 115) \
DEFINE_KEY(Execute, 116) \
DEFINE_KEY(Help, 117) \
DEFINE_KEY(Menu, 118) \
DEFINE_KEY(Select, 119) \
DEFINE_KEY(Stop, 120) \
DEFINE_KEY(Again, 121) \
DEFINE_KEY(Undo, 122) \
DEFINE_KEY(Cut, 123) \
DEFINE_KEY(Copy, 124) \
DEFINE_KEY(Paste, 125) \
DEFINE_KEY(Find, 126) \
DEFINE_KEY(Mute, 127) \
DEFINE_KEY(VolumeUp, 128) \
DEFINE_KEY(VolumeDown, 129) \
DEFINE_KEY(KP_Comma, 133) \
DEFINE_KEY(KP_EqualsAs400, 134) \
DEFINE_KEY(International1, 135) \
DEFINE_KEY(International2, 136) \
DEFINE_KEY(International3, 137) \
DEFINE_KEY(International4, 138) \
DEFINE_KEY(International5, 139) \
DEFINE_KEY(International6, 140) \
DEFINE_KEY(International7, 141) \
DEFINE_KEY(International8, 142) \
DEFINE_KEY(International9, 143) \
DEFINE_KEY(Language1, 144) \
DEFINE_KEY(Language2, 145) \
DEFINE_KEY(Language3, 146) \
DEFINE_KEY(Language4, 147) \
DEFINE_KEY(Language5, 148) \
DEFINE_KEY(Language6, 149) \
DEFINE_KEY(Language7, 150) \
DEFINE_KEY(Language8, 151) \
DEFINE_KEY(Language9, 152) \
DEFINE_KEY(AltErase, 153) \
DEFINE_KEY(SysReq, 154) \
DEFINE_KEY(Cancel, 155) \
DEFINE_KEY(clear, 156) \
DEFINE_KEY(Prior, 157) \
DEFINE_KEY(Return2, 158) \
DEFINE_KEY(Separator, 159) \
DEFINE_KEY(Out, 160) \
DEFINE_KEY(Oper, 161) \
DEFINE_KEY(ClearAgain, 162) \
DEFINE_KEY(CRSEL, 163) \
DEFINE_KEY(EXSEL, 164) \
DEFINE_KEY(KP_00, 176) \
DEFINE_KEY(KP_000, 177) \
DEFINE_KEY(ThousandsSeparator, 178) \
DEFINE_KEY(DecimalSeparator, 179) \
DEFINE_KEY(CurrencyUnit, 180) \
DEFINE_KEY(CurrencySubUnit, 181) \
DEFINE_KEY(KP_LeftParen, 182) \
DEFINE_KEY(KP_RightParent, 183) \
DEFINE_KEY(KP_LeftBrace, 184) \
DEFINE_KEY(KP_RightBrace, 185) \
DEFINE_KEY(KP_Tab, 186) \
DEFINE_KEY(KP_BackSpace, 187) \
DEFINE_KEY(KP_A, 188) \
DEFINE_KEY(KP_B, 189) \
DEFINE_KEY(KP_C, 190) \
DEFINE_KEY(KP_D, 191) \
DEFINE_KEY(KP_E, 192) \
DEFINE_KEY(KP_F, 193) \
DEFINE_KEY(KP_XOR, 194) \
DEFINE_KEY(KP_Power, 195) \
DEFINE_KEY(KP_Percent, 196) \
DEFINE_KEY(KP_Less, 197) \
DEFINE_KEY(KP_Greater, 198) \
DEFINE_KEY(KP_Ampersand, 199) \
DEFINE_KEY(KP_DoubleAmpersand, 200) \
DEFINE_KEY(KP_VerticalBar, 201) \
DEFINE_KEY(KP_DoubleVerticalBar, 202) \
DEFINE_KEY(KP_Colon, 203) \
DEFINE_KEY(KP_Hash, 204) \
DEFINE_KEY(KP_Space, 205) \
DEFINE_KEY(KP_At, 206) \
DEFINE_KEY(KP_EXCLAM, 207) \
DEFINE_KEY(KP_MemStore, 208) \
DEFINE_KEY(KP_MemRecall, 209) \
DEFINE_KEY(KP_MemClear, 210) \
DEFINE_KEY(KP_MemAdd, 211) \
DEFINE_KEY(KP_MemSubstract, 212) \
DEFINE_KEY(KP_MemMultiply, 213) \
DEFINE_KEY(KP_MemDivide, 214) \
DEFINE_KEY(KP_PlusMinus, 215) \
DEFINE_KEY(KP_Clear, 216) \
DEFINE_KEY(KP_ClearEntry, 217) \
DEFINE_KEY(KP_Binary, 218) \
DEFINE_KEY(KP_Octal, 219) \
DEFINE_KEY(KP_Decimal, 220) \
DEFINE_KEY(KP_Hexadecimal, 221) \
DEFINE_KEY(LeftControl, 224) \
DEFINE_KEY(LeftShift, 225) \
DEFINE_KEY(LeftAlt, 226) \
DEFINE_KEY(LeftGui, 227) \
DEFINE_KEY(RightControl, 228) \
DEFINE_KEY(RightShift, 229) \
DEFINE_KEY(RightAlt, 230) \
DEFINE_KEY(RightGui, 231)
#define BLAH_BUTTON_DEFINITIONS \
DEFINE_BTN(None, -1) \
DEFINE_BTN(A, 0) \
DEFINE_BTN(B, 1) \
DEFINE_BTN(X, 2) \
DEFINE_BTN(Y, 3) \
DEFINE_BTN(Back, 4) \
DEFINE_BTN(Select, 5) \
DEFINE_BTN(Start, 6) \
DEFINE_BTN(LeftStick, 7) \
DEFINE_BTN(RightStick, 8) \
DEFINE_BTN(LeftShoulder, 9) \
DEFINE_BTN(RightShoulder, 10) \
DEFINE_BTN(Up, 11) \
DEFINE_BTN(Down, 12) \
DEFINE_BTN(Left, 13) \
DEFINE_BTN(Right, 14)
namespace Blah
{
namespace Input
{
// maximum number of controllers the input can handle
constexpr int max_controllers = 8;
// maximum number of buttons the input will track
constexpr int max_controller_buttons = 64;
// maximum number of controller axis the input will track
constexpr int max_controller_axis = 16;
// maximum number of mouse buttons the input will track
constexpr int max_mouse_buttons = 16;
// maximum number of keys the input will track
constexpr int max_keyboard_keys = 512;
// maximum length of text input that can be received per-frame
constexpr int max_text_input = 256;
// maximum number of nodes within a virtual input device
constexpr int max_virtual_nodes = 32;
}
struct ControllerState
{
// The name of the gamepad, or NULL if not connected
const char* name;
// Whether this gamepad is connected
bool is_connected;
// Whether this gamepad is a standard Game Controller
bool is_gamepad;
// The total button count for this controller
int button_count;
// The total axis count for this controller
int axis_count;
// An array holding the pressed state of each button
bool pressed[Input::max_controller_buttons];
// An array holding the down state of each button
bool down[Input::max_controller_buttons];
// An array holding the released state of each button
bool released[Input::max_controller_buttons];
// An array holding the value state of each axis
float axis[Input::max_controller_axis];
// Timestamp, in milliseconds, since each button was last pressed
uint64_t button_timestamp[Input::max_controller_buttons];
// Timestamp, in milliseconds, since each axis last had a value set
uint64_t axis_timestamp[Input::max_controller_axis];
// The USB Vendor ID
uint16_t vendor;
// The USB Product ID
uint16_t product;
// the Product Version
uint16_t version;
};
struct KeyboardState
{
bool pressed[Input::max_keyboard_keys];
bool down[Input::max_keyboard_keys];
bool released[Input::max_keyboard_keys];
uint64_t timestamp[Input::max_keyboard_keys];
char text[Input::max_text_input];
};
struct MouseState
{
bool pressed[Input::max_mouse_buttons];
bool down[Input::max_mouse_buttons];
bool released[Input::max_mouse_buttons];
uint64_t timestamp[Input::max_mouse_buttons];
Vec2 screen_position;
Vec2 draw_position;
Vec2 position;
Point wheel;
};
// An Input State, which stores the state for gamepads, keyboard, and mouse
struct InputState
{
// All the Gamepads. Note that not all gamepads are necessarily connected,
// and each one must be checked before use.
ControllerState controllers[Input::max_controllers];
// The current Keyboard state
KeyboardState keyboard;
// The current Mouse state
MouseState mouse;
};
// Keyboard Keys
enum class Key
{
#define DEFINE_KEY(name, value) name = value,
BLAH_KEY_DEFINITIONS
#undef DEFINE_KEY
};
// Game Controller Buttons
enum class Button
{
#define DEFINE_BTN(name, value) name = value,
BLAH_BUTTON_DEFINITIONS
#undef DEFINE_BTN
};
// Game Controller Axes
enum class Axis
{
None = -1,
LeftX = 0,
LeftY = 1,
RightX = 2,
RightY = 3,
LeftTrigger = 4,
RightTrigger = 5
};
// Mouse Buttons
enum class MouseButton
{
None = -1,
Left = 0,
Middle = 1,
Right = 2,
};
namespace Input
{
// Returns the Input State of the current frame.
// This pointer is only valid for the current frame and should not be stored.
const InputState* state();
// Returns the Input State of the previous frame.
// This pointer is only valid for the current frame and should not be stored.
const InputState* last_state();
// Gets the Mouse Position
Vec2 mouse();
// Gets the Draw Mouse Position (Mouse Position / Window Size * Draw Size)
Vec2 mouse_draw();
// Gets the Mouse Position in Screen Coordinates
Vec2 mouse_screen();
// Checks if the given Mouse Button is pressed
bool pressed(MouseButton button);
// Checks if the given Mouse Button is down
bool down(MouseButton button);
// Checks if the given Mouse Button is released
bool released(MouseButton button);
// Gets the Mouse Wheel
Point mouse_wheel();
// Checks if the keyboard key was pressed this frame
bool pressed(Key key);
// Checks if the keyboard key was held this frame
bool down(Key key);
// Checks if the keyboard key was released this frame
bool released(Key key);
// Checks if the Left or Right Ctrl Key is down
bool ctrl();
// Checks if the Left or Right Shift Key is down
bool shift();
// Checks if the Left or Right Alt Key is down
bool alt();
// Get the current Text Input
const char* text();
// Gets the controller info for the current controller index.
// If the controller is not connected or the index it out of range, this will set an unconnected controller.
const ControllerState* controller(int controller_index);
// Checks if the button on the controller was pressed this frame.
// If the controller is not connected, or the index is out of range, this will return false.
bool pressed(int controller_index, Button button);
// Checks if the button on the controller was held this frame.
// If the controller is not connected, or the index is out of range, this will return false.
bool down(int controller_index, Button button);
// Checks if the button on the controller was released this frame.
// If the controller is not connected, or the index is out of range, this will return false.
bool released(int controller_index, Button button);
// returns the value of the given axis
float axis_check(int controller_index, Axis axis);
// checks the given virtual axis, described by 2 keys. `fallback` is returned if both keys are held
int axis_check(int fallback, Key negative, Key positive);
// checks the given virtual axis, described by 2 buttons. `fallback` is returned if both buttons are held
int axis_check(int fallback, int controller_index, Button negative, Button positive);
// returns a string name of the given key
const char* name_of(Key key);
// returns a string name of the given button
const char* name_of(Button button);
}
}

View File

@ -0,0 +1,86 @@
#pragma once
#include <blah/input/input.h>
namespace Blah
{
// A virtual controller axis, which can be used to map multiple
// inputs to an axis. Note that you must call `update` every frame!
class VirtualAxis
{
private:
struct KeysNode
{
Key positive = Key::Unknown;
Key negative = Key::Unknown;
int value = 0;
void init(Key negative, Key positive);
void update();
};
struct ButtonsNode
{
int gamepad_id = 0;
Button positive = Button::None;
Button negative = Button::None;
int value = 0;
void init(int gamepad_id, Button negative, Button positive);
void update();
};
struct AxisNode
{
int gamepad_id = 0;
Axis axis = Axis::None;
float deadzone = 0;
float value = 0;
void init(int gamepad_id, Axis axis, float deadzone);
void update();
};
KeysNode m_keys[Input::max_virtual_nodes];
ButtonsNode m_buttons[Input::max_virtual_nodes];
AxisNode m_axes[Input::max_virtual_nodes];
int m_keys_len = 0;
int m_buttons_len = 0;
int m_axes_len = 0;
float m_press_buffer = 0;
float m_release_buffer = 0;
float m_repeat_delay = 0;
float m_repeat_interval = 0;
float m_value = 0;
int m_value_i = 0;
float m_last_value = 0;
int m_last_value_i = 0;
bool m_pressed = false;
bool m_released = false;
float m_last_press_time = -1;
float m_last_release_time = -1;
float m_repeat_press_time = -1;
public:
VirtualAxis& add_keys(Key negative, Key positive);
VirtualAxis& add_buttons(int gamepad_id, Button negative, Button positive);
VirtualAxis& add_axis(int gamepad_id, Axis axis, float deadzone);
VirtualAxis& repeat(float m_repeat_delay, float m_repeat_interval);
VirtualAxis& press_buffer(float duration);
VirtualAxis& release_buffer(float duration);
void update();
float value() const { return m_value; }
int value_i() const { return m_value_i; }
float last_value() const { return m_last_value; }
int last_value_i() const { return m_last_value_i; }
bool pressed() const { return m_pressed; }
bool released() const { return m_released; }
void clear_press_buffer() { m_last_press_time = -1; m_pressed = false; }
void clear_release_buffer() { m_last_release_time = -1; m_released = false; }
};
}

View File

@ -0,0 +1,83 @@
#pragma once
#include <blah/input/input.h>
namespace Blah
{
class VirtualButton
{
private:
struct KeyNode
{
Key key = Key::Unknown;
bool down = false;
bool pressed = false;
bool released = false;
void init(Key key);
void update();
};
struct ButtonNode
{
int gamepad_id = 0;
Button button = Button::None;
bool down = false;
bool pressed = false;
bool released = false;
void init(int gamepad_id, Button button);
void update();
};
struct AxisNode
{
int gamepad_id = 0;
Axis axis = Axis::None;
float threshold = 0;
bool greater_than = false;
bool down = false;
bool pressed = false;
bool released = false;
void init(int gamepad_id, Axis axis, float threshold, bool greater_than);
void update();
};
KeyNode m_keys[Input::max_virtual_nodes];
ButtonNode m_buttons[Input::max_virtual_nodes];
AxisNode m_axes[Input::max_virtual_nodes];
int m_keys_len = 0;
int m_buttons_len = 0;
int m_axes_len = 0;
float m_press_buffer = 0;
float m_release_buffer = 0;
float m_repeat_delay = 0;
float m_repeat_interval = 0;
bool m_down = false;
bool m_pressed = false;
bool m_released = false;
float m_last_press_time = -1;
float m_last_release_time = -1;
float m_repeat_press_time = -1;
public:
VirtualButton& add_key(Key key);
VirtualButton& add_button(int gamepad_id, Button button);
VirtualButton& add_axis(int gamepad_id, Axis axis, float threshold, bool greater_than);
VirtualButton& repeat(float m_repeat_delay, float m_repeat_interval);
VirtualButton& press_buffer(float duration);
VirtualButton& release_buffer(float duration);
void update();
bool down() const { return m_down; }
bool pressed() const { return m_pressed; }
bool released() const { return m_released; }
void clear_press_buffer() { m_last_press_time = -1; m_pressed = false; }
void clear_release_buffer() { m_last_release_time = -1; m_released = false; }
};
}

View File

@ -0,0 +1,97 @@
#pragma once
#include <blah/input/input.h>
#include <blah/math/vec2.h>
#include <blah/math/point.h>
namespace Blah
{
// A virtual controller stick, which can be used to map multiple
// inputs to a stick. Note that you must call `update` every frame!
class VirtualStick
{
private:
struct KeysNode
{
Key left;
Key right;
Key up;
Key down;
Point value;
void init(Key left, Key right, Key up, Key down);
void update();
};
struct ButtonsNode
{
int gamepad_id;
Button left;
Button right;
Button up;
Button down;
Point value;
void init(int gamepad_id, Button left, Button right, Button up, Button down);
void update();
};
struct AxesNode
{
int gamepad_id;
Axis horizontal;
Axis vertical;
float deadzone;
Vec2 value;
void init(int gamepad_id, Axis horizontal, Axis vertical, float deadzone);
void update();
};
KeysNode m_keys[Input::max_virtual_nodes];
ButtonsNode m_buttons[Input::max_virtual_nodes];
AxesNode m_axes[Input::max_virtual_nodes];
int m_keys_len = 0;
int m_buttons_len = 0;
int m_axes_len = 0;
float m_press_buffer = 0;
float m_release_buffer = 0;
float m_repeat_delay = 0;
float m_repeat_interval = 0;
Vec2 m_value = Vec2();
Point m_value_i = Point();
Vec2 m_last_value = Vec2();
Point m_last_value_i = Point();
bool m_pressed = false;
bool m_released = false;
float m_i_deadzone;
float m_last_press_time = -1;
float m_last_release_time = -1;
float m_repeat_press_time = -1;
public:
VirtualStick();
VirtualStick(float iDeadzone);
VirtualStick& add_keys(Key left, Key right, Key up, Key down);
VirtualStick& add_buttons(int gamepad_id, Button left, Button right, Button up, Button down);
VirtualStick& add_axes(int gamepad_id, Axis horizontal, Axis vertical, float deadzone);
VirtualStick& repeat(float m_repeat_delay, float m_repeat_interval);
VirtualStick& press_buffer(float duration);
VirtualStick& release_buffer(float duration);
void update();
const Vec2& value() const { return m_value; }
const Point& value_i() const { return m_value_i; }
const Vec2& last_value() const { return m_last_value; }
const Point& last_value_i() const { return m_last_value_i; }
bool pressed() const { return m_pressed; }
bool released() const { return m_released; }
void clear_press_buffer() { m_last_press_time = 0; }
void clear_release_buffer() { m_last_release_time = 0; }
};
}

79
include/blah/math/calc.h Normal file
View File

@ -0,0 +1,79 @@
#pragma once
#include <inttypes.h>
namespace Blah
{
namespace Calc
{
constexpr float PI = 3.141592653f;
constexpr float TAU = PI * 2.0f;
constexpr float RIGHT = 0;
constexpr float LEFT = PI;
constexpr float UP = PI / -2;
constexpr float DOWN = PI / 2;
float rand_float(float min, float maxExc);
float rand_float(float maxExc);
int rand_int(int min, int maxExc);
int rand_int(int maxExc);
int rand_int();
float approach(float t, float target, float maxDelta);
float clamp(float t, float min, float max);
int clamp_int(int t, int min, int max);
float map(float t, float old_min, float old_max, float new_min, float new_max);
float clamped_map(float t, float old_min, float old_max, float new_min, float new_max);
int sign(int x);
float sign(float x);
int abs(int x);
float abs(float x);
template<class T, class U>
T min(T a, U b) { return (T)(a < b ? a : b); }
template<class T, class U>
T max(T a, U b) { return (T)(a > b ? a : b); }
float round(float x);
float floor(float x);
float ceiling(float x);
float mod(float x, float m);
float sin(float x);
float cos(float x);
float atan2(float y, float x);
float pow(float x, float n);
float sqrt(float x);
float snap(float val, float interval);
float angle_diff(float radians_a, float radians_b);
float angle_lerp(float radians_a, float radians_b, float p);
float lerp(float a, float b, float t);
bool is_big_endian();
bool is_little_endian();
};
}

View File

@ -0,0 +1,22 @@
#pragma once
#include <blah/math/vec2.h>
namespace Blah
{
struct Circle
{
Vec2 center;
float radius;
Circle()
: center(), radius(0) {}
Circle(Vec2 center, float radius)
: center(center), radius(radius) {}
Circle(float x, float y, float radius)
: center(x, y), radius(radius) {}
void project(const Vec2& axis, float* min, float* max) const;
};
}

64
include/blah/math/color.h Normal file
View File

@ -0,0 +1,64 @@
#pragma once
#include <inttypes.h>
namespace Blah
{
struct Vec4;
struct Color
{
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
Color();
Color(int rgb);
Color(int rgb, float alpha);
Color(uint8_t r, uint8_t g, uint8_t b);
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
// Parses a Hex string in the format of "#00000000" or "0x00000000" or "00000000"
Color(const char* hexCstr);
// Premultiplies the Color
void premultiply();
// Sets a Hex string to the given buffer, in the format of RRGGBBAA
// The buffer must be at least 8 bytes long
void to_hex_rgba(char* buffer) const;
// Sets a Hex string to the given buffer, in the format of RRGGBB
// The buffer must be at least 6 bytes long
void to_hex_rgb(char* buffer) const;
uint32_t to_rgba() const;
Vec4 to_vec4() const;
// Returns a RGBA Color representation of the integer value
static Color from_rgba(uint32_t value);
// Returns a RGB Color representation of the integer value, with Alpha = 255
static Color from_rgb(uint32_t value);
static Color lerp(Color a, Color b, float amount);
// Mutliplties the Color
Color operator*(float multiply) const;
// assignment from int
Color& operator= (const int rgb);
static const Color transparent;
static const Color white;
static const Color black;
static const Color red;
static const Color green;
static const Color blue;
static const Color yellow;
static const Color orange;
static const Color purple;
static const Color teal;
};
}

336
include/blah/math/ease.h Normal file
View File

@ -0,0 +1,336 @@
#pragma once
#include <blah/math/calc.h>
#include <blah/core/log.h>
namespace Blah
{
using Easer = float (*)(float);
enum class Easers
{
QuadIn, QuadOut, QuadInOut,
CubeIn, CubeOut, CubeInOut,
QuartIn, QuartOut, QuartInOut,
QuintIn, QuintOut, QuintInOut,
SineIn, SineOut, SineInOut,
CircIn, CircOut, CircInOut,
ExpIn, ExpOut, ExpInOut,
ElasticIn, ElasticOut, ElasticInOut,
BackIn, BackOut, BackInOut,
BounceIn, BounceOut, BounceInOut,
_Count
};
namespace Ease
{
/*
Adapted from functions here: https://github.com/warrenm/AHEasing/blob/master/AHEasing/easing.c
For previews go here: https://easings.net/
*/
inline float linear(float t)
{
return t;
}
inline float quad_in(float t)
{
return t * t;
}
inline float quad_out(float t)
{
return -(t * (t - 2));
}
inline float quad_in_out(float t)
{
if (t < 0.5f)
return 2 * t * t;
else
{
return (-2 * t * t) + (4 * t) - 1;
}
}
inline float cube_in(float t)
{
return t * t * t;
}
inline float cube_out(float t)
{
float f = (t - 1);
return f * f * f + 1;
}
inline float cube_in_out(float t)
{
if (t < 0.5f)
return 4 * t * t * t;
else
{
float f = ((2 * t) - 2);
return 0.5f * f * f * f + 1;
}
}
inline float quart_in(float t)
{
return t * t * t * t;
}
inline float quart_out(float t)
{
float f = (t - 1);
return f * f * f * (1 - t) + 1;
}
inline float quart_in_out(float t)
{
if (t < 0.5f)
return 8 * t * t * t * t;
else
{
float f = (t - 1);
return -8 * f * f * f * f + 1;
}
}
inline float quint_in(float t)
{
return t * t * t * t * t;
}
inline float quint_out(float t)
{
float f = (t - 1);
return f * f * f * f * f + 1;
}
inline float quint_in_out(float t)
{
if (t < 0.5f)
return 16 * t * t * t * t * t;
else
{
float f = ((2 * t) - 2);
return 0.5f * f * f * f * f * f + 1;
}
}
inline float sine_in(float t)
{
return Calc::sin((t - 1) * Calc::PI * 0.5f) + 1;
}
inline float sine_out(float t)
{
return Calc::sin(t * (Calc::PI * 0.5f));
}
inline float sine_in_out(float t)
{
return 0.5f * (1 - Calc::cos(t * Calc::PI));
}
inline float circ_in(float t)
{
return 1 - Calc::sqrt(1 - (t * t));
}
inline float circ_out(float t)
{
return Calc::sqrt((2 - t) * t);
}
inline float circ_in_out(float t)
{
if (t < 0.5f)
return 0.5f * (1 - Calc::sqrt(1 - 4 * (t * t)));
else
return 0.5f * (Calc::sqrt(-((2 * t) - 3) * ((2 * t) - 1)) + 1);
}
inline float exp_in(float t)
{
return (t == 0) ? 0 : Calc::pow(2, 10 * (t - 1));
}
inline float exp_out(float t)
{
return (t == 1) ? 1 : 1 - Calc::pow(2, -10 * t);
}
inline float exp_in_out(float t)
{
if (t == 0 || t == 1)
return t;
if (t < 0.5f)
return 0.5f * Calc::pow(2, (20 * t) - 10);
else
return -0.5f * Calc::pow(2, (-20 * t) + 10) + 1;
}
inline float elastic_in(float t)
{
return Calc::sin(13 * (Calc::PI * 0.5f) * t) * Calc::pow(2, 10 * (t - 1));
}
inline float elastic_out(float t)
{
return Calc::sin(-13 * (Calc::PI * 0.5f) * (t + 1)) * Calc::pow(2, -10 * t) + 1;
}
inline float elastic_in_out(float t)
{
if (t < 0.5f)
return 0.5f * Calc::sin(13 * (Calc::PI * 0.5f) * (2 * t)) * Calc::pow(2, 10 * ((2 * t) - 1));
else
return 0.5f * (Calc::sin(-13 * (Calc::PI * 0.5f) * ((2 * t - 1) + 1)) * Calc::pow(2, -10 * (2 * t - 1)) + 2);
}
inline float back_in(float t)
{
return t * t * t - t * Calc::sin(t * Calc::PI);
}
inline float back_out(float t)
{
float f = (1 - t);
return 1 - (f * f * f - f * Calc::sin(f * Calc::PI));
}
inline float back_in_out(float t)
{
if (t < 0.5f)
{
float f = 2 * t;
return 0.5f * (f * f * f - f * Calc::sin(f * Calc::PI));
}
else
{
float f = (1 - (2 * t - 1));
return 0.5f * (1 - (f * f * f - f * Calc::sin(f * Calc::PI))) + 0.5f;
}
}
inline float bounce_out(float t)
{
if (t < 4 / 11.0f)
return (121 * t * t) / 16.0f;
else if (t < 8 / 11.0f)
return (363 / 40.0f * t * t) - (99 / 10.0f * t) + 17 / 5.0f;
else if (t < 9 / 10.0f)
return (4356 / 361.0f * t * t) - (35442 / 1805.0f * t) + 16061 / 1805.0f;
else
return (54 / 5.0f * t * t) - (513 / 25.0f * t) + 268 / 25.0f;
}
inline float bounce_in(float t)
{
return 1 - bounce_out(1 - t);
}
inline float bounce_in_out(float t)
{
if (t < 0.5f)
return 0.5f * bounce_in(t * 2);
else
return 0.5f * bounce_out(t * 2 - 1) + 0.5f;
}
inline Easer get(Easers e)
{
switch (e)
{
case Easers::CubeIn: return &cube_in;
case Easers::CubeOut: return &cube_out;
case Easers::CubeInOut: return &cube_in_out;
case Easers::QuadIn: return &quad_in;
case Easers::QuadOut: return &quad_out;
case Easers::QuadInOut: return &quad_in_out;
case Easers::QuartIn: return &quart_in;
case Easers::QuartOut: return &quart_out;
case Easers::QuartInOut: return &quart_in_out;
case Easers::QuintIn: return &quint_in;
case Easers::QuintOut: return &quint_out;
case Easers::QuintInOut: return &quint_in_out;
case Easers::SineIn: return &sine_in;
case Easers::SineOut: return &sine_out;
case Easers::SineInOut: return &sine_in_out;
case Easers::CircIn: return &circ_in;
case Easers::CircOut: return &circ_out;
case Easers::CircInOut: return &circ_in_out;
case Easers::ExpIn: return &exp_in;
case Easers::ExpOut: return &exp_out;
case Easers::ExpInOut: return &exp_in_out;
case Easers::ElasticIn: return &elastic_in;
case Easers::ElasticOut: return &elastic_out;
case Easers::ElasticInOut: return &elastic_in_out;
case Easers::BackIn: return &back_in;
case Easers::BackOut: return &back_out;
case Easers::BackInOut: return &back_in_out;
case Easers::BounceIn: return &bounce_in;
case Easers::BounceOut: return &bounce_out;
case Easers::BounceInOut: return &bounce_in_out;
case Easers::_Count:
break;
}
BLAH_ERROR("Invalid Easer Type");
return nullptr;
}
inline const char* name(Easers e)
{
switch (e)
{
case Easers::CubeIn: return "CubeIn";
case Easers::CubeOut: return "CubeOut";
case Easers::CubeInOut: return "CubeInOut";
case Easers::QuadIn: return "QuadIn";
case Easers::QuadOut: return "QuadOut";
case Easers::QuadInOut: return "QuadInOut";
case Easers::QuartIn: return "QuartIn";
case Easers::QuartOut: return "QuartOut";
case Easers::QuartInOut: return "QuartInOut";
case Easers::QuintIn: return "QuintIn";
case Easers::QuintOut: return "QuintOut";
case Easers::QuintInOut: return "QuintInOut";
case Easers::SineIn: return "SineIn";
case Easers::SineOut: return "SineOut";
case Easers::SineInOut: return "SineInOut";
case Easers::CircIn: return "CircIn";
case Easers::CircOut: return "CircOut";
case Easers::CircInOut: return "CircInOut";
case Easers::ExpIn: return "ExpIn";
case Easers::ExpOut: return "ExpOut";
case Easers::ExpInOut: return "ExpInOut";
case Easers::ElasticIn: return "ElasticIn";
case Easers::ElasticOut: return "ElasticOut";
case Easers::ElasticInOut: return "ElasticInOut";
case Easers::BackIn: return "BackIn";
case Easers::BackOut: return "BackOut";
case Easers::BackInOut: return "BackInOut";
case Easers::BounceIn: return "BounceIn";
case Easers::BounceOut: return "BounceOut";
case Easers::BounceInOut: return "BounceInOut";
case Easers::_Count:
break;
}
return "<Invalid>";
}
}
}

30
include/blah/math/line.h Normal file
View File

@ -0,0 +1,30 @@
#pragma once
#include <blah/math/vec2.h>
namespace Blah
{
struct Rect;
struct Line
{
Vec2 a;
Vec2 b;
Line() {}
Line(float x0, float y0, float x1, float y1);
Line(const Vec2& start, const Vec2& end);
Rect bounds() const;
Vec2 closest_point(const Vec2& pt) const;
bool intersects(const Rect& rect) const;
bool intersects(const Rect& rect, Vec2* out_intersection_point) const;
bool intersects(const Line& line) const;
bool intersects(const Line& line, Vec2* out_intersection_point) const;
void project(const Vec2& axis, float* min, float* max) const;
Line operator +(const Vec2& rhs) const;
Line operator -(const Vec2& rhs) const;
};
}

View File

@ -0,0 +1,47 @@
#pragma once
namespace Blah
{
struct Vec2;
struct Mat3x2
{
float m11;
float m12;
float m21;
float m22;
float m31;
float m32;
Mat3x2();
Mat3x2(float m11, float m12, float m21, float m22, float m31, float m32);
Mat3x2 invert() const;
float scaling_factor() const;
Mat3x2 operator *(const Mat3x2& rhs) const;
Mat3x2 operator +(const Mat3x2& rhs) const;
Mat3x2 operator -(const Mat3x2& rhs) const;
Mat3x2& operator *=(const Mat3x2& rhs);
bool operator==(const Mat3x2& rhs);
bool operator!=(const Mat3x2& rhs);
static const Mat3x2 identity;
static Mat3x2 create_translation(const Vec2& position);
static Mat3x2 create_translation(float x, float y);
static Mat3x2 create_scale(float scale);
static Mat3x2 create_scale(Vec2 scale);
static Mat3x2 create_scale(float x, float y);
static Mat3x2 create_scale(float scale, Vec2 centerPoint);
static Mat3x2 create_scale(Vec2 scale, Vec2 centerPoint);
static Mat3x2 create_scale(float scaleX, float scaleY, Vec2 centerPoint);
static Mat3x2 create_rotation(float radians);
static Mat3x2 create_transform(const Vec2& position, const Vec2& origin, const Vec2& scale, float rotation);
static Mat3x2 add(const Mat3x2& a, const Mat3x2& b);
static Mat3x2 subtract(const Mat3x2& a, const Mat3x2& b);
static Mat3x2 multiply(const Mat3x2& a, const Mat3x2& b);
};
}

View File

@ -0,0 +1,44 @@
#pragma once
namespace Blah
{
struct Mat4x4
{
float m11;
float m12;
float m13;
float m14;
float m21;
float m22;
float m23;
float m24;
float m31;
float m32;
float m33;
float m34;
float m41;
float m42;
float m43;
float m44;
Mat4x4();
Mat4x4(
float m11, float m12, float m13, float m14,
float m21, float m22, float m23, float m24,
float m31, float m32, float m33, float m34,
float m41, float m42, float m43, float m44);
static const Mat4x4 identity;
static Mat4x4 create_ortho(float width, float height, float z_near_plane, float z_far_plane);
static Mat4x4 create_ortho_offcenter(float left, float right, float bottom, float top, float z_near_plane, float z_far_plane);
static Mat4x4 create_translation(float x, float y, float z);
static Mat4x4 create_scale(float x, float y, float z);
Mat4x4 operator* (const Mat4x4& rhs);
};
}

41
include/blah/math/point.h Normal file
View File

@ -0,0 +1,41 @@
#pragma once
namespace Blah
{
struct Point
{
int x;
int y;
Point();
Point(int px, int py);
Point operator +(const Point rhs) const;
Point operator -(const Point rhs) const;
Point operator /(const int rhs) const;
Point operator *(const int rhs) const;
Point operator -() const;
Point& operator +=(const Point& rhs);
Point& operator -=(const Point& rhs);
Point& operator /=(const Point& rhs);
Point& operator *=(const Point& rhs);
Point& operator /=(int rhs);
Point& operator *=(int rhs);
bool operator ==(const Point& rhs);
bool operator !=(const Point& rhs);
float length() const;
int length_squared() const;
static const Point unitX;
static const Point unitY;
static const Point right;
static const Point up;
static const Point down;
static const Point left;
static const Point zero;
static const Point one;
};
}

19
include/blah/math/quad.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include <blah/math/vec2.h>
namespace Blah
{
struct Quad
{
Vec2 a;
Vec2 b;
Vec2 c;
Vec2 d;
Quad() {}
Quad(const Vec2& a, const Vec2& b, const Vec2& c, const Vec2& d)
: a(a), b(b), c(c), d(d) {}
void project(const Vec2& axis, float* min, float* max) const;
};
}

87
include/blah/math/rect.h Normal file
View File

@ -0,0 +1,87 @@
#pragma once
#include <blah/math/point.h>
#include <blah/math/vec2.h>
#include <blah/math/rectI.h>
#include <blah/math/line.h>
namespace Blah
{
struct Mat3x2;
struct Rect
{
float x;
float y;
float w;
float h;
Rect();
Rect(float rx, float ry, float rw, float rh);
Rect(Vec2 pos, Vec2 size);
Rect(RectI r);
Rect scale(float s);
Rect scale(float sx, float sy);
float left() const;
float right() const;
float top() const;
float bottom() const;
Vec2 center() const;
float center_x() const;
float center_y() const;
Vec2 top_left() const;
Vec2 top_right() const;
Vec2 bottom_right() const;
Vec2 bottom_left() const;
Vec2 center_left() const;
Vec2 center_right() const;
Vec2 middle_top() const;
Vec2 middle_bottom() const;
Line left_line() const;
Line right_line() const;
Line top_line() const;
Line bottom_line() const;
bool contains(const Point& pt) const;
bool contains(const Vec2& pt) const;
bool overlaps(const Rect& rect) const;
Rect overlap_rect(const Rect& other) const;
bool intersects(const Line& line) const;
bool intersects(const Line& line, Vec2* out_intersection_point) const;
bool intersects(const Vec2& line_from, const Vec2& line_to) const;
bool intersects(const Vec2& line_from, const Vec2& line_to, Vec2* out_intersection_point) const;
Vec2 intersection_point(const Line& line) const;
Vec2 intersection_point(const Vec2& line_from, const Vec2& line_to) const;
Rect inflate(float amount) const;
/*
Rect Sectors:
0101 0100 0110
0001 0000 0010
1001 1000 1010
0000 = inside rectangle, all others refer to sectors relative to the rectangle
*/
char get_sector(const Vec2& pt) const;
bool operator==(const Rect& rhs) const { return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h; }
bool operator!=(const Rect& rhs) const { return !(*this == rhs); }
Rect operator+(const Vec2& rhs) const;
Rect operator-(const Vec2& rhs) const;
Rect& operator+=(const Vec2& rhs);
Rect& operator-=(const Vec2& rhs);
static Rect transform(const Rect& vec, const Mat3x2& matrix);
static Rect transform(float x, float y, float w, float h, const Mat3x2& matrix);
static Rect from_points(Vec2& from, Vec2& to);
};
}

64
include/blah/math/rectI.h Normal file
View File

@ -0,0 +1,64 @@
#pragma once
namespace Blah
{
struct Point;
struct Rect;
struct Vec2;
struct RectI
{
int x;
int y;
int w;
int h;
RectI();
RectI(int rx, int ry, int rw, int rh);
RectI(Point pos, Point size);
int left() const { return x; }
int right() const { return x + w; }
int top() const { return y; }
int bottom() const { return y + h; }
int centerX() const { return x + w / 2; }
int centerY() const { return y + h / 2; }
Point center() const;
Point top_left() const;
Point top_right() const;
Point bottom_left() const;
Point bottom_right() const;
bool overlaps(const RectI& other) const
{
return x < other.x + other.w
&& other.x < x + w
&& y < other.y + other.h
&& other.y < y + h;
}
bool contains(const Point& pt) const;
bool contains(const Vec2& pt) const;
/*
Rect Sectors:
0101 0100 0110
0001 0000 0010
1001 1000 1010
0000 = inside rectangle, all others refer to sectors relative to the rectangle
*/
char get_sector(const Point& pt) const;
char get_sector(const Vec2& pt) const;
bool operator==(const RectI& rhs) const { return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h; }
bool operator!=(const RectI& rhs) const { return !(*this == rhs); }
RectI operator+(const Point& rhs) const;
RectI operator-(const Point& rhs) const;
RectI& operator+=(const Point& rhs);
RectI& operator-=(const Point& rhs);
RectI operator*(const int& rhs) const { return RectI(x * rhs, y * rhs, w * rhs, h * rhs); }
};
}

View File

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

72
include/blah/math/vec2.h Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include <blah/math/point.h>
namespace Blah
{
struct Mat3x2;
struct Vec2
{
float x;
float y;
Vec2();
Vec2(float vx, float vy);
Vec2(int vx, float vy);
Vec2(float vx, int vy);
Vec2(int vx, int vy);
Vec2(Point p);
Vec2 operator +(const Vec2 rhs) const;
Vec2 operator -(const Vec2 rhs) const;
Vec2 operator /(const float rhs) const;
Vec2 operator *(const float rhs) const;
Vec2 operator -() const;
Vec2& operator +=(const Vec2& rhs);
Vec2& operator -=(const Vec2& rhs);
Vec2& operator /=(const Vec2& rhs);
Vec2& operator *=(const Vec2& rhs);
Vec2& operator /=(float rhs);
Vec2& operator *=(float rhs);
bool operator ==(const Vec2& rhs);
bool operator !=(const Vec2& rhs);
Vec2 normal() const;
Vec2 turn_right() const;
Vec2 turn_left() const;
float length() const;
float length_squared() const;
Vec2 perpendicular() const;
float angle() const;
static float dot(Vec2 a, Vec2 b);
static float dot(float x, float y, Vec2 b);
static float dot(float x1, float y1, float x2, float y2);
static Vec2 transform(const Vec2& vec, const Mat3x2& matrix);
static Vec2 transform(float x, float y, const Mat3x2& matrix);
static Vec2 from_angle(float radians, float length);
static Vec2 from_angle(float radians);
static Vec2 lerp(Vec2 start, Vec2 end, float t);
static Vec2 bezier_lerp(Vec2 start, Vec2 b, Vec2 end, float t);
static Vec2 bezier_lerp(Vec2 start, Vec2 b, Vec2 c, Vec2 end, float t);
static Vec2 reflect(const Vec2& vector, const Vec2& normal);
static const Vec2 unit_x;
static const Vec2 unit_y;
static const Vec2 right;
static const Vec2 up;
static const Vec2 down;
static const Vec2 left;
static const Vec2 zero;
static const Vec2 one;
static const Vec2 up_right;
static const Vec2 up_left;
static const Vec2 down_right;
static const Vec2 down_left;
};
}

15
include/blah/math/vec4.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
namespace Blah
{
struct Vec4
{
float x;
float y;
float z;
float w;
Vec4() : x(0), y(0), z(0), w(0) {}
Vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
};
}

View File

@ -0,0 +1,37 @@
#pragma once
#include <blah/streams/stream.h>
namespace Blah
{
class BufferStream : public Stream
{
public:
BufferStream();
BufferStream(int capacity);
BufferStream(BufferStream&& bs) noexcept;
BufferStream& operator=(BufferStream&& bs) noexcept;
~BufferStream();
virtual int64_t length() const override { return m_length; }
virtual int64_t position() const override { return m_position; }
virtual int64_t seek(int64_t seekTo) override { return m_position = (seekTo < 0 ? 0 : (seekTo > m_length ? m_length : seekTo)); }
virtual bool is_open() const override { return m_buffer != nullptr; }
virtual bool is_readable() const override { return true; }
virtual bool is_writable() const override { return true; }
virtual void close() override;
void clear() { m_length = m_position = 0; }
char* data() { return m_buffer; }
const char* data() const { return m_buffer; }
protected:
virtual int64_t read_into(void* ptr, int64_t length) override;
virtual int64_t write_from(const void* ptr, int64_t length) override;
private:
char* m_buffer;
int64_t m_capacity;
int64_t m_length;
int64_t m_position;
};
}

View File

@ -0,0 +1,39 @@
#pragma once
namespace Blah
{
enum class Endian
{
Little,
Big
};
template<class T>
inline void swap_endian(T* value)
{
for (int i = 0; i < sizeof(T) / 2; i++)
{
char* _ptr = (char*)&value;
char _temp = *(_ptr + i);
*(_ptr + i) = *(_ptr + sizeof(T) - i - 1);
*(_ptr + sizeof(T) - i - 1) = _temp;
}
}
inline bool is_big_endian()
{
return (*((short*)"AB") == 0x4243);
}
inline bool is_little_endian()
{
return (*((short*)"AB") != 0x4243);
}
inline bool is_endian(const Endian& endian)
{
return
(endian == Endian::Little && is_little_endian()) ||
(endian == Endian::Big && is_big_endian());
}
}

View File

@ -0,0 +1,32 @@
#pragma once
#include <blah/streams/stream.h>
#include <blah/core/filesystem.h>
namespace Blah
{
class FileStream : public Stream
{
public:
FileStream();
FileStream(const char* path, FileMode mode = FileMode::ReadWrite);
FileStream(FileStream&& fs) noexcept;
FileStream& operator=(FileStream&& fs) noexcept;
~FileStream();
virtual int64_t length() const override;
virtual int64_t position() const override;
virtual int64_t seek(int64_t seekTo) override;
virtual bool is_open() const override { return m_handle != nullptr; }
virtual bool is_readable() const override { return m_handle != nullptr && (m_mode == FileMode::ReadWrite || m_mode == FileMode::Read); }
virtual bool is_writable() const override { return m_handle != nullptr && (m_mode == FileMode::ReadWrite || m_mode == FileMode::Write); }
virtual void close() override;
protected:
virtual int64_t read_into(void* ptr, int64_t length) override;
virtual int64_t write_from(const void* ptr, int64_t length) override;
private:
FileMode m_mode;
void* m_handle;
};
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <blah/streams/stream.h>
namespace Blah
{
class MemoryStream : public Stream
{
public:
MemoryStream();
MemoryStream(char* data, int64_t length);
MemoryStream(MemoryStream&& ms) noexcept;
MemoryStream& operator=(MemoryStream&& ms) noexcept;
~MemoryStream() { m_data = nullptr; m_length = m_position = 0; }
virtual int64_t length() const override { return m_length; }
virtual int64_t position() const override { return m_position; }
virtual int64_t seek(int64_t seekTo) override { return m_position = (seekTo < 0 ? 0 : (seekTo > m_length ? m_length : seekTo)); }
virtual bool is_open() const override { return m_data != nullptr; }
virtual bool is_readable() const override { return true; }
virtual bool is_writable() const override { return true; }
virtual void close() override { m_data = nullptr; m_length = m_position = 0; }
char* data() { return m_data; }
const char* data() const { return m_data; }
protected:
virtual int64_t read_into(void* ptr, int64_t length) override;
virtual int64_t write_from(const void* ptr, int64_t length) override;
private:
char* m_data;
int64_t m_length;
int64_t m_position;
};
}

View File

@ -0,0 +1,141 @@
#pragma once
#include <inttypes.h>
#include <blah/containers/str.h>
#include <blah/streams/endian.h>
#include <string.h>
namespace Blah
{
class Stream
{
public:
Stream() = default;
Stream(const Stream&) = delete;
Stream& operator=(const Stream&) = delete;
virtual ~Stream() = default;
// returns the length of the stream
virtual int64_t length() const = 0;
// returns the position of the stream
virtual int64_t position() const = 0;
// seeks the position of the stream
virtual int64_t seek(int64_t seek_to) = 0;
// returns true of the stream is open
virtual bool is_open() const = 0;
// returns true of the stream is readable
virtual bool is_readable() const = 0;
// returns true of the stream is writable
virtual bool is_writable() const = 0;
// closes the stream
virtual void close() = 0;
// pipes the contents of this tream to another stream
int64_t pipe(Stream& to, int64_t length);
// reads the amount of bytes into the given buffer, and returns the amount read
int64_t read(void* buffer, int64_t length) { return read_into(buffer, length); }
// reads a string. if length < 0, assumes null-terminated
String read_string(int length = -1)
{
String result;
if (length < 0)
{
char next;
while (read(&next, 1) && next != '\0')
result.append(next);
}
else
{
result.set_length(length);
read_into(result.cstr(), length);
}
return result;
}
String read_line()
{
String result;
char next;
while (read(&next, 1) && next != '\n' && next != '\0')
result.append(next);
return result;
}
// reads a number
template<class T>
T read()
{
return read<T>(Endian::Little);
}
// reads a number
template<class T>
T read(Endian endian)
{
T result;
read(&result, sizeof(T));
if (!Blah::is_endian(endian))
Blah::swap_endian(&result);
return result;
}
// writes the amount of bytes to the stream from the given buffer, and returns the amount written
int64_t write(const void* buffer, int64_t length)
{
return write_from(buffer, length);
}
// writes a null-terminated string, and returns the amount written
int64_t write_cstr(const Str& string)
{
return write(string.cstr(), string.length() + 1);
}
// writes a null-terminated string, and returns the amount written
int64_t write_cstr(const char* cstr)
{
return write(cstr, strlen(cstr) + 1);
}
// writes a number
template<class T>
int64_t write(const T& value)
{
return write<T>(value, Endian::Little);
}
// writes a number
template<class T>
int64_t write(const T& value, Endian endian)
{
T writing = value;
if (!Blah::is_endian(endian))
Blah::swap_endian(&writing);
return write(&writing, sizeof(T));
}
protected:
// reads from the stream into the given buffer, and returns the number of bytes read
virtual int64_t read_into(void* buffer, int64_t length) = 0;
// writes from the stream from the given buffer, and returns the number of bytes written
virtual int64_t write_from(const void* buffer, int64_t length) = 0;
};
}
#undef BLAH_SWAP_ENDIAN
#undef BLAH_BIG_ENDIAN