diff --git a/CMakeLists.txt b/CMakeLists.txt index ce2db97..5b7d640 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,25 +6,25 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_library(blah - src/app.cpp - src/filesystem.cpp - src/common.cpp - src/time.cpp - src/input.cpp - src/stream.cpp - src/graphics.cpp - src/containers/str.cpp - src/drawing/batch.cpp - src/drawing/spritefont.cpp - src/drawing/subtexture.cpp - src/images/aseprite.cpp - src/images/font.cpp - src/images/image.cpp - src/images/packer.cpp - src/internal/renderer_opengl.cpp - src/internal/renderer_d3d11.cpp - src/internal/platform_sdl2.cpp - src/internal/platform_win32.cpp + src/blah_app.cpp + src/blah_filesystem.cpp + src/blah_common.cpp + src/blah_time.cpp + src/blah_input.cpp + src/blah_stream.cpp + src/blah_graphics.cpp + src/blah_string.cpp + src/blah_batch.cpp + src/blah_spritefont.cpp + src/blah_subtexture.cpp + src/blah_aseprite.cpp + src/blah_font.cpp + src/blah_image.cpp + src/blah_packer.cpp + src/internal/blah_renderer_opengl.cpp + src/internal/blah_renderer_d3d11.cpp + src/internal/blah_platform_sdl2.cpp + src/internal/blah_platform_win32.cpp ) target_include_directories(blah diff --git a/include/blah.h b/include/blah.h index ed30ef0..554bae1 100644 --- a/include/blah.h +++ b/include/blah.h @@ -1,27 +1,22 @@ #pragma once - -#include "blah/common.h" -#include "blah/app.h" -#include "blah/filesystem.h" -#include "blah/time.h" -#include "blah/input.h" -#include "blah/stream.h" -#include "blah/graphics.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/images/aseprite.h" -#include "blah/images/font.h" -#include "blah/images/image.h" -#include "blah/images/packer.h" - -#include "blah/math/calc.h" -#include "blah/math/spatial.h" -#include "blah/math/color.h" -#include "blah/math/ease.h" \ No newline at end of file +#include "blah_app.h" +#include "blah_aseprite.h" +#include "blah_batch.h" +#include "blah_calc.h" +#include "blah_color.h" +#include "blah_common.h" +#include "blah_ease.h" +#include "blah_filesystem.h" +#include "blah_font.h" +#include "blah_graphics.h" +#include "blah_image.h" +#include "blah_input.h" +#include "blah_packer.h" +#include "blah_spatial.h" +#include "blah_spritefont.h" +#include "blah_stackvector.h" +#include "blah_string.h" +#include "blah_stream.h" +#include "blah_subtexture.h" +#include "blah_time.h" +#include "blah_vector.h" \ No newline at end of file diff --git a/include/blah/containers/str.h b/include/blah/containers/str.h deleted file mode 100644 index 873deda..0000000 --- a/include/blah/containers/str.h +++ /dev/null @@ -1,321 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace Blah -{ - template class StrOf; - using String = StrOf<64>; - using FilePath = StrOf<260>; - - // A simple String implementation - 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); } - - // append char - 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; } - - // combine char - 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); - - // Returns the unicode value at the given index. - // Assumes the index is a valid utf8 starting point. - u32 utf8_at(int index) const; - - // Returns the byte-length of the utf8 character. - // Assumes the index is a valid utf8 starting point. - int utf8_length(int index) const; - - // appends the given character - Str& append(char c); - - // appends the given unicode character - Str& append(u32 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 u16* start, const u16* 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; - - // Splits the string into a vector of strings - Vector split(char ch) const; - - // replaces all occurances of old string with the new string - Str& replace(const Str& old_str, const Str& new_str); - - // replaces all occurances of the given character in the string - 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(); - - virtual ~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 - virtual char* data() { return m_buffer; } - - // returns a pointer to the heap buffer or to our stack allocation - virtual const char* data() const { return m_buffer; } - - // assigns the contents of the string - void set(const Str& str) { set(str.cstr(), str.cstr() + str.m_length); } - - // assigns the contents of the string - void set(const char* start, const char* end = nullptr); - - char* m_buffer; - - private: - static char empty_buffer[1]; - 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; } - - // A string with a local stack buffer of size T - template - 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; } - - // either return stack or heap buffer depending on which is in-use - char* data() override { return m_buffer != nullptr ? m_buffer : m_local_buffer; } - const char* data() const override { return m_buffer != nullptr ? m_buffer : m_local_buffer; } - - // creates a string from the format - static StrOf fmt(const char* str, ...); - }; - - template - StrOf StrOf::fmt(const char* fmt, ...) - { - StrOf 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; - } - - struct CaseInsenstiveStringHash - { - std::size_t operator()(const Blah::Str& key) const - { - std::size_t result = 2166136261U; - - for (auto& it : key) - { - if (it >= 'A' && it <= 'Z') - result ^= (static_cast(it) - 'A' + 'a'); - else - result ^= static_cast(it); - result *= 16777619U; - } - - return result; - } - }; - - struct CaseInsenstiveStringCompare - { - bool operator() (const Str& lhs, const Str& rhs) const - { - return lhs.length() == rhs.length() && lhs.starts_with(rhs, true); - } - }; -} - -namespace std -{ - template <> - struct hash - { - std::size_t operator()(const Blah::Str& key) const - { - std::size_t result = 2166136261U; - - for (auto& it : key) - { - result ^= static_cast(it); - result *= 16777619U; - } - - return result; - } - }; - - template - struct hash> - { - std::size_t operator()(const Blah::StrOf& key) const - { - std::size_t result = 2166136261U; - - for (auto& it : key) - { - result ^= static_cast(it); - result *= 16777619U; - } - - return result; - } - }; -} \ No newline at end of file diff --git a/include/blah/app.h b/include/blah_app.h similarity index 98% rename from include/blah/app.h rename to include/blah_app.h index 16b8347..27b370a 100644 --- a/include/blah/app.h +++ b/include/blah_app.h @@ -1,7 +1,7 @@ #pragma once -#include -#include -#include +#include +#include +#include namespace Blah { diff --git a/include/blah/images/aseprite.h b/include/blah_aseprite.h similarity index 94% rename from include/blah/images/aseprite.h rename to include/blah_aseprite.h index 8cf2a3b..ced8a1f 100644 --- a/include/blah/images/aseprite.h +++ b/include/blah_aseprite.h @@ -1,9 +1,9 @@ #pragma once -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace Blah { diff --git a/include/blah/drawing/batch.h b/include/blah_batch.h similarity index 97% rename from include/blah/drawing/batch.h rename to include/blah_batch.h index e0c08d1..5874101 100644 --- a/include/blah/drawing/batch.h +++ b/include/blah_batch.h @@ -1,11 +1,11 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace Blah { diff --git a/include/blah/math/calc.h b/include/blah_calc.h similarity index 98% rename from include/blah/math/calc.h rename to include/blah_calc.h index 4cce4f1..807f1ec 100644 --- a/include/blah/math/calc.h +++ b/include/blah_calc.h @@ -1,6 +1,5 @@ #pragma once -#include -#include +#include namespace Blah { diff --git a/include/blah/math/color.h b/include/blah_color.h similarity index 98% rename from include/blah/math/color.h rename to include/blah_color.h index 424f319..0b82d1a 100644 --- a/include/blah/math/color.h +++ b/include/blah_color.h @@ -1,7 +1,7 @@ #pragma once -#include -#include -#include +#include +#include +#include #define BLAH_HEX_VALUE(n) ((n >= '0' && n <= '9') ? (n - '0') : ((n >= 'A' && n <= 'F') ? (10 + n - 'A') : ((n >= 'a' && n <= 'f') ? (10 + n - 'a') : 0))) diff --git a/include/blah/common.h b/include/blah_common.h similarity index 84% rename from include/blah/common.h rename to include/blah_common.h index d24a9fe..88b7125 100644 --- a/include/blah/common.h +++ b/include/blah_common.h @@ -1,10 +1,29 @@ #pragma once +#include // for in-place constructors, for Vector/StackVector +#include // for std::move, std::forward +#include // for integer types +#include // for std::size_t +#include // for abort +#include // for string format methods +#include // for standard lib math functions used in blah_calc.h -#include // for in-place constructors, for Vector/StackVector -#include // for std::move +// Numeric Types +namespace Blah +{ + using i8 = int8_t; + using i16 = int16_t; + using i32 = int32_t; + using i64 = int64_t; + using u8 = uint8_t; + using u16 = uint16_t; + using u32 = uint32_t; + using u64 = uint64_t; + using f32 = float; + using f64 = double; + using size_t = std::size_t; +} // Aborts -#include // for abort #ifdef _WIN32 #define BLAH_ABORT() do { __debugbreak(); ::exit(1); } while(0) #else @@ -34,24 +53,6 @@ } \ } while(0) -// Numeric Types -#include // for integer types -#include // for size_t type -namespace Blah -{ - using i8 = int8_t; - using i16 = int16_t; - using i32 = int32_t; - using i64 = int64_t; - using u8 = uint8_t; - using u16 = uint16_t; - using u32 = uint32_t; - using u64 = uint64_t; - using f32 = float; - using f64 = double; - using size_t = std::size_t; -} - // Logging namespace Blah { diff --git a/include/blah/math/ease.h b/include/blah_ease.h similarity index 99% rename from include/blah/math/ease.h rename to include/blah_ease.h index 09028d5..dca067c 100644 --- a/include/blah/math/ease.h +++ b/include/blah_ease.h @@ -1,6 +1,6 @@ #pragma once -#include -#include +#include +#include namespace Blah { diff --git a/include/blah/filesystem.h b/include/blah_filesystem.h similarity index 96% rename from include/blah/filesystem.h rename to include/blah_filesystem.h index bca774d..6c5c01a 100644 --- a/include/blah/filesystem.h +++ b/include/blah_filesystem.h @@ -1,7 +1,7 @@ #pragma once -#include -#include -#include +#include +#include +#include namespace Blah { diff --git a/include/blah/images/font.h b/include/blah_font.h similarity index 93% rename from include/blah/images/font.h rename to include/blah_font.h index 0aedcec..d66d4f9 100644 --- a/include/blah/images/font.h +++ b/include/blah_font.h @@ -1,10 +1,10 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace Blah { diff --git a/include/blah/graphics.h b/include/blah_graphics.h similarity index 98% rename from include/blah/graphics.h rename to include/blah_graphics.h index 1cc752b..7514be9 100644 --- a/include/blah/graphics.h +++ b/include/blah_graphics.h @@ -1,14 +1,15 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace Blah { + class Stream; + class Shader; using ShaderRef = Ref; class Texture; using TextureRef = Ref; class Target; using TargetRef = Ref; diff --git a/include/blah/images/image.h b/include/blah_image.h similarity index 94% rename from include/blah/images/image.h rename to include/blah_image.h index 49c53be..1e04314 100644 --- a/include/blah/images/image.h +++ b/include/blah_image.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include namespace Blah { diff --git a/include/blah/input.h b/include/blah_input.h similarity index 99% rename from include/blah/input.h rename to include/blah_input.h index 5ec2f03..768d7c2 100644 --- a/include/blah/input.h +++ b/include/blah_input.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include // These are generally copied from the SDL2 Scancode Keys, // which are in turn based on the USB standards: diff --git a/include/blah/images/packer.h b/include/blah_packer.h similarity index 91% rename from include/blah/images/packer.h rename to include/blah_packer.h index 638354c..6e57c40 100644 --- a/include/blah/images/packer.h +++ b/include/blah_packer.h @@ -1,12 +1,12 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace Blah { diff --git a/include/blah/math/spatial.h b/include/blah_spatial.h similarity index 99% rename from include/blah/math/spatial.h rename to include/blah_spatial.h index 0c92ee4..aaea9cd 100644 --- a/include/blah/math/spatial.h +++ b/include/blah_spatial.h @@ -1,6 +1,6 @@ #pragma once -#include -#include +#include +#include namespace Blah { diff --git a/include/blah/drawing/spritefont.h b/include/blah_spritefont.h similarity index 95% rename from include/blah/drawing/spritefont.h rename to include/blah_spritefont.h index fd404a6..8e0fb42 100644 --- a/include/blah/drawing/spritefont.h +++ b/include/blah_spritefont.h @@ -1,9 +1,9 @@ #pragma once -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace Blah { diff --git a/include/blah/containers/stackvector.h b/include/blah_stackvector.h similarity index 99% rename from include/blah/containers/stackvector.h rename to include/blah_stackvector.h index 594d3d6..2e58d04 100644 --- a/include/blah/containers/stackvector.h +++ b/include/blah_stackvector.h @@ -1,5 +1,5 @@ #pragma once -#include +#include namespace Blah { @@ -10,7 +10,7 @@ namespace Blah class StackVector { private: - char m_buffer[sizeof(T) * Capacity]; + u8 m_buffer[sizeof(T) * Capacity]; int m_count; public: diff --git a/include/blah/stream.h b/include/blah_stream.h similarity index 97% rename from include/blah/stream.h rename to include/blah_stream.h index 434483a..5fc5cf2 100644 --- a/include/blah/stream.h +++ b/include/blah_stream.h @@ -1,9 +1,9 @@ #pragma once -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace Blah { diff --git a/include/blah_string.h b/include/blah_string.h new file mode 100644 index 0000000..55d27a0 --- /dev/null +++ b/include/blah_string.h @@ -0,0 +1,371 @@ +#pragma once +#include +#include +#include + +namespace Blah +{ + class BaseString + { + public: + const char* cstr() const { return s_ptr(); } + char* cstr() { return s_ptr(); } + const char* begin() const { return s_ptr(); } + char* begin() { return s_ptr(); } + const char* end() const { return s_ptr() + length(); } + char* end() { return s_ptr() + length(); } + + char& operator[](int index) + { + BLAH_ASSERT(index >= 0 && index < length(), "Index out of range"); + return s_ptr()[index]; + } + + const char& operator[](int index) const + { + BLAH_ASSERT(index >= 0 && index < length(), "Index out of range"); + return s_ptr()[index]; + } + + operator char* () { return cstr(); } + operator const char* () const { return cstr(); } + + void assign(const char* cstr, const char* cstr_end = nullptr); + void append(const char* cstr, const char* cstr_end = nullptr); + void append(const u16* u16_cstr, const u16* u16_cstr_end = nullptr, bool swap_endian = false); + void append(char ch, int count = 1); + void append(u32 unicode); + void append_fmt(const char* fmt, ...); + + bool starts_with(const char* cstr, bool ignore_case = false) const; + bool ends_with(const char* cstr, bool ignore_case = false) const; + bool contains(const char* cstr, bool ignore_case = false) const; + + int first_index_of(char ch) const; + int last_index_of(char ch) const; + + int length() const + { + int n = s_len() - 1; // reduce by 1 for null-terminator + return (n > 0 ? n : 0); // safety, although due to how StackString is implemented s_len shouldn't ever be less than 1 + } + + bool equals(const char* other, bool ignore_case = false) const; + bool empty() const { return length() == 0; } + void clear() { s_clear(); } + + bool operator==(const char* rhs) const { return equals(rhs); } + bool operator!=(const char* rhs) const { return !(*this == rhs); } + bool operator==(const BaseString& rhs) const { return s_len() == rhs.s_len() && *this == rhs.cstr(); } + bool operator!=(const BaseString& rhs) const { return !(*this == rhs); } + + protected: + virtual void s_clear() = 0; + virtual void s_ensure(int capacity) = 0; + virtual char* s_ptr() = 0; + virtual const char* s_ptr() const = 0; + virtual int s_len() const = 0; + }; + + template + class StackString final : public BaseString + { + public: + StackString() { assign(""); } + StackString(const char* cstr, const char* cstr_end = nullptr) { assign(cstr, cstr_end); } + StackString(const BaseString& other) { assign(other.cstr()); } + + StackString& operator=(const BaseString& rhs) + { + assign(rhs.cstr(), rhs.cstr() + rhs.length()); + return *this; + } + + StackString& operator=(const char* rhs) + { + assign(rhs, nullptr); + return *this; + } + + StackString& operator+=(const BaseString& rhs) + { + append(rhs.cstr()); + return *this; + } + + StackString& operator+=(const char* rhs) + { + append(rhs); + return *this; + } + + StackString& operator+=(const char& rhs) + { + append(rhs); + return *this; + } + + StackString operator+(const BaseString& rhs) + { + StackString str(*this); + str += rhs; + return str; + } + + StackString operator+(const char* rhs) + { + StackString str(*this); + str += rhs; + return str; + } + + StackString operator+(const char& rhs) + { + StackString str(*this); + str += rhs; + return str; + } + + StackString substr(int start, int len = 0) const + { + if (len == 0) len = length() - start; + return StackString(cstr() + start, cstr() + start + len); + } + + StackString trim() const + { + if (length() > 0) + { + const char* s = begin(); + const char* e = end() - 1; + + while (s < e && (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n' || *s == '\v' || *s == '\f')) s++; + while (e > s && (*e == ' ' || *e == '\t' || *e == '\r' || *e == '\n' || *e == '\v' || *e == '\f')) e--; + + return StackString(s, e + 1); + } + + return StackString(); + } + + Vector split(char ch) const + { + Vector result; + + const char* ptr = s_ptr(); + const char* end = ptr + length(); + const char* last = ptr; + + while (ptr < end) + { + if (*ptr == ch) + { + result.emplace_back(last, ptr); + last = ptr + 1; + } + ptr++; + } + + if (last < ptr) + result.emplace_back(last, ptr); + + return result; + } + + static StackString fmt(const char* fmt, ...) + { + StackString str; + + va_list args; + + // determine arg m_length + va_start(args, fmt); + auto add = vsnprintf(nullptr, 0, fmt, args); + va_end(args); + + if (add <= 0) + return str; + + // reserve (+1 for null-terminator) + auto len = str.length(); + str.s_ensure(len + add + 1); + + // print out + va_start(args, fmt); + vsnprintf(str.s_ptr() + len, add + 1, fmt, args); + va_end(args); + + return str; + } + + protected: + void s_clear() override + { + m_stack_buffer.clear(); + m_heap_buffer.clear(); + s_ensure(1); + } + + void s_ensure(int capacity) override + { + int count = capacity - s_len(); + if (count <= 0) + return; + + // expand heap buffer + if (m_heap_buffer.size() > 0) + { + m_heap_buffer.expand(count); + } + // switch from stack to heap + else if (capacity > StackSize) + { + m_heap_buffer.expand(capacity); + + char* src = m_stack_buffer.data(); + char* len = src + m_stack_buffer.size(); + char* dst = m_heap_buffer.data(); + while (src < len) *(dst++) = *(src++); + } + // expand stack buffer + else + { + m_stack_buffer.expand(count); + } + + *(s_ptr() + s_len() - 1) = '\0'; + } + + char* s_ptr() override + { + return m_heap_buffer.size() > 0 ? m_heap_buffer.data() : m_stack_buffer.data(); + } + + const char* s_ptr() const override + { + return m_heap_buffer.size() > 0 ? m_heap_buffer.data() : m_stack_buffer.data(); + } + + int s_len() const override + { + return m_heap_buffer.size() > 0 ? m_heap_buffer.size() : m_stack_buffer.size(); + } + + private: + Vector m_heap_buffer; + StackVector m_stack_buffer; + }; + + template + StackString operator+(const StackString& lhs, const BaseString& rhs) + { + StackString str(lhs); + str += rhs; + return str; + } + + template + StackString operator+(const StackString& lhs, const char* rhs) + { + StackString str(lhs); + str += rhs; + return str; + } + + template + StackString operator+(const StackString& lhs, const char& rhs) + { + StackString str(lhs); + str += rhs; + return str; + } + + // Stores enough for an empty string on the stack, and afterwards allocates on the heap + using HeapString = StackString<1>; + + // Standard String with a fair amount of stack storage + using String = StackString<64>; + + // Large String with enough stack storage to store FilePaths without allocating. + using FilePath = StackString<260>; + + // Utf8 Utility, to iterate over a string and read utf-8 characters + struct Utf8 + { + const char* str = nullptr; + u32 character = 0; + u32 character_size = 0; + + Utf8() = default; + Utf8(const char* cstr); + + // moves to the next character, returns false if at end of string or an invalid character + bool next(); + }; + + struct CaseInsenstiveStringHash + { + std::size_t operator()(const Blah::BaseString& key) const + { + std::size_t result = 2166136261U; + + for (auto& it : key) + { + if (it >= 'A' && it <= 'Z') + result ^= (static_cast(it) - 'A' + 'a'); + else + result ^= static_cast(it); + result *= 16777619U; + } + + return result; + } + }; + + struct CaseInsenstiveStringCompare + { + bool operator() (const BaseString& lhs, const BaseString& rhs) const + { + return lhs.length() == rhs.length() && lhs.starts_with(rhs, true); + } + }; +} + +// STD Hash Utility, so the String can be used in a set / unordered_map / map + +namespace std +{ + template <> + struct hash + { + std::size_t operator()(const Blah::BaseString& key) const + { + std::size_t result = 2166136261U; + + for (auto& it : key) + { + result ^= static_cast(it); + result *= 16777619U; + } + + return result; + } + }; + + template + struct hash> + { + std::size_t operator()(const Blah::StackString& key) const + { + std::size_t result = 2166136261U; + + for (auto& it : key) + { + result ^= static_cast(it); + result *= 16777619U; + } + + return result; + } + }; +} \ No newline at end of file diff --git a/include/blah/drawing/subtexture.h b/include/blah_subtexture.h similarity index 96% rename from include/blah/drawing/subtexture.h rename to include/blah_subtexture.h index 15211b5..8f1d990 100644 --- a/include/blah/drawing/subtexture.h +++ b/include/blah_subtexture.h @@ -1,6 +1,6 @@ #pragma once -#include -#include +#include +#include namespace Blah { diff --git a/include/blah/time.h b/include/blah_time.h similarity index 98% rename from include/blah/time.h rename to include/blah_time.h index 937a4cd..133e1aa 100644 --- a/include/blah/time.h +++ b/include/blah_time.h @@ -1,5 +1,5 @@ #pragma once -#include +#include namespace Blah { diff --git a/include/blah/containers/vector.h b/include/blah_vector.h similarity index 97% rename from include/blah/containers/vector.h rename to include/blah_vector.h index 0004058..986ec0d 100644 --- a/include/blah/containers/vector.h +++ b/include/blah_vector.h @@ -1,6 +1,5 @@ #pragma once -#include -#include +#include namespace Blah { @@ -182,7 +181,10 @@ namespace Blah if constexpr (std::is_trivially_copyable()) { - memcpy(new_buffer, m_buffer, m_count * sizeof(T)); + u8* src = (u8*)m_buffer; + u8* len = src + m_count * sizeof(T); + u8* dst = (u8*)new_buffer; + while (src < len) *(dst++) = *(src++); } else { @@ -356,4 +358,4 @@ namespace Blah m_count--; return value; } -} +} \ No newline at end of file diff --git a/src/app.cpp b/src/blah_app.cpp similarity index 96% rename from src/app.cpp rename to src/blah_app.cpp index 5b20e90..04f814b 100644 --- a/src/app.cpp +++ b/src/blah_app.cpp @@ -1,9 +1,9 @@ -#include -#include -#include -#include "internal/internal.h" -#include "internal/platform.h" -#include "internal/renderer.h" +#include +#include +#include +#include "internal/blah_internal.h" +#include "internal/blah_platform.h" +#include "internal/blah_renderer.h" #ifdef __EMSCRIPTEN__ #include @@ -400,8 +400,10 @@ void App::set_flag(u32 flag, bool enabled) if (was != app_flags) { - Internal::platform->set_app_flags(app_flags); - Internal::renderer->set_app_flags(app_flags); + if (Internal::platform) + Internal::platform->set_app_flags(app_flags); + if (Internal::renderer) + Internal::renderer->set_app_flags(app_flags); } } diff --git a/src/images/aseprite.cpp b/src/blah_aseprite.cpp similarity index 96% rename from src/images/aseprite.cpp rename to src/blah_aseprite.cpp index ceeabc3..f6f5012 100644 --- a/src/images/aseprite.cpp +++ b/src/blah_aseprite.cpp @@ -1,10 +1,10 @@ -#include -#include -#include +#include +#include +#include #define STBI_NO_STDIO #define STBI_ONLY_ZLIB -#include "../third_party/stb_image.h" +#include "third_party/stb_image.h" using namespace Blah; @@ -133,7 +133,7 @@ void Aseprite::parse_layer(Stream& stream, int frame) layer.alpha = stream.read_u8(Endian::Little); stream.seek(stream.position() + 3); // for future - layer.name.set_length(stream.read_u16(Endian::Little)); + layer.name.append('\0', stream.read_u16(Endian::Little)); stream.read(layer.name.cstr(), layer.name.length()); layer.userdata.color = 0xffffff; @@ -261,7 +261,7 @@ void Aseprite::parse_user_data(Stream& stream, int frame) // has text if (flags & (1 << 0)) { - m_last_userdata->text.set_length(stream.read_u16(Endian::Little)); + m_last_userdata->text.append('\0', stream.read_u16(Endian::Little)); stream.read(m_last_userdata->text.cstr(), m_last_userdata->text.length()); } @@ -287,7 +287,7 @@ void Aseprite::parse_tag(Stream& stream, int frame) tag.color = Color(stream.read_i8(), stream.read_i8(), stream.read_i8(Endian::Little), 255); stream.seek(stream.position() + 1); - tag.name.set_length(stream.read_u16(Endian::Little)); + tag.name.append('\0', stream.read_u16(Endian::Little)); stream.read(tag.name.cstr(), tag.name.length()); tags.push_back(tag); @@ -301,7 +301,7 @@ void Aseprite::parse_slice(Stream& stream, int frame) stream.read_u32(Endian::Little); // reserved String name; - name.set_length(stream.read_u16(Endian::Little)); + name.append('\0', stream.read_u16(Endian::Little)); stream.read(name.cstr(), name.length()); for (int s = 0; s < count; s++) diff --git a/src/drawing/batch.cpp b/src/blah_batch.cpp similarity index 98% rename from src/drawing/batch.cpp rename to src/blah_batch.cpp index 5b07d31..5c4ee3e 100644 --- a/src/drawing/batch.cpp +++ b/src/blah_batch.cpp @@ -1,7 +1,7 @@ -#include -#include -#include -#include "../internal/internal.h" +#include +#include +#include +#include "internal/blah_internal.h" using namespace Blah; @@ -969,11 +969,11 @@ void Batch::str(const SpriteFont& font, const String& text, const Vec2f& pos, co offset.y -= font.height_of(text) * justify.y; u32 last = 0; - for (int i = 0, l = text.length(); i < l; i += text.utf8_length(i)) + Utf8 utf8(text.cstr()); + int i = 0; + while (utf8.character) { - u32 next = text.utf8_at(i); - - if (next == '\n') + if (utf8.character == '\n') { offset.x = 0; offset.y += font.line_height(); @@ -982,22 +982,24 @@ void Batch::str(const SpriteFont& font, const String& text, const Vec2f& pos, co offset.x -= font.width_of_line(text, i + 1) * justify.x; last = 0; - continue; } - - const auto& ch = font[next]; - if (ch.subtexture.texture) + else { - Vec2f at = offset + ch.offset; + const auto& ch = font[utf8.character]; + if (ch.subtexture.texture) + { + Vec2f at = offset + ch.offset; + if (last) + at.x += font.get_kerning(last, utf8.character); + tex(ch.subtexture, at, color); + } - if (i > 0 && text[i - 1] != '\n') - at.x += font.get_kerning(last, next); - - tex(ch.subtexture, at, color); + offset.x += ch.advance; + last = utf8.character; } - offset.x += ch.advance; - last = next; + i += utf8.character_size; + utf8.next(); } pop_matrix(); diff --git a/src/common.cpp b/src/blah_common.cpp similarity index 88% rename from src/common.cpp rename to src/blah_common.cpp index 768d5ea..d3bc55c 100644 --- a/src/common.cpp +++ b/src/blah_common.cpp @@ -1,7 +1,5 @@ -#include -#include -#include // for logging methods -#include // for sprintf +#include +#include using namespace Blah; diff --git a/src/filesystem.cpp b/src/blah_filesystem.cpp similarity index 90% rename from src/filesystem.cpp rename to src/blah_filesystem.cpp index 76db0b5..f1fc66b 100644 --- a/src/filesystem.cpp +++ b/src/blah_filesystem.cpp @@ -1,5 +1,5 @@ -#include -#include "internal/internal.h" +#include +#include "internal/blah_internal.h" using namespace Blah; @@ -70,7 +70,10 @@ Vector Directory::enumerate(const FilePath& path, bool recursive) { App::Internal::platform->dir_enumerate(list, path.cstr(), recursive); for (auto& it : list) - it.replace('\\', '/'); + { + for (int n = 0; n < it.length(); n ++) + if (it[n] == '\\') it[n] = '/'; + } } return list; @@ -114,10 +117,10 @@ FilePath Path::get_directory_name(const FilePath& path) { FilePath directory = path; while (directory.ends_with("/")) - directory = directory.substr(0, -1); + directory = FilePath(directory.begin(), directory.end() - 1); auto last = directory.last_index_of('/'); if (last >= 0) - directory = directory.substr(0, last + 1); + directory = FilePath(directory.begin(), directory.begin() + last + 1); return directory; } @@ -156,7 +159,7 @@ FilePath Path::normalize(const FilePath& path) for (auto k = normalized.length() - 1; k > 0; k--) if (normalized[k - 1] == '/') { - normalized = normalized.substr(0, k - 1); + normalized = FilePath(normalized.begin(), normalized.begin() + k - 1); could_move_up = true; break; } @@ -181,5 +184,5 @@ FilePath Path::join(const FilePath& a, const FilePath& b) else if (b.length() <= 0) return normalize(a); else - return normalize(FilePath(a).append("/").append(b)); + return normalize(a + "/" + b); } \ No newline at end of file diff --git a/src/images/font.cpp b/src/blah_font.cpp similarity index 91% rename from src/images/font.cpp rename to src/blah_font.cpp index 5ada39e..138ad0f 100644 --- a/src/images/font.cpp +++ b/src/blah_font.cpp @@ -1,15 +1,15 @@ -#include -#include +#include +#include using namespace Blah; #define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION -#include "../third_party/stb_truetype.h" +#include "third_party/stb_truetype.h" namespace { - String get_font_name(stbtt_fontinfo* font, int nameId) + String blah_get_font_name(stbtt_fontinfo* font, int name_id) { int length = 0; @@ -18,14 +18,14 @@ namespace STBTT_PLATFORM_ID_MICROSOFT, STBTT_MS_EID_UNICODE_BMP, STBTT_MS_LANG_ENGLISH, - nameId); + name_id); // we want the size in wide chars length /= 2; String str; if (length > 0) - str.append_utf16(ptr, ptr + length, Calc::is_little_endian()); + str.append(ptr, ptr + length, Calc::is_little_endian()); return str; } } @@ -56,8 +56,8 @@ FontRef Font::create(Stream& stream) auto font = FontRef(new Font()); font->m_font = stbtt; font->m_buffer = std::move(buffer); - font->m_family_name = get_font_name(fn, 1); - font->m_style_name = get_font_name(fn, 2); + font->m_family_name = blah_get_font_name(fn, 1); + font->m_style_name = blah_get_font_name(fn, 2); stbtt_GetFontVMetrics(fn, &font->m_ascent, &font->m_descent, &font->m_line_gap); return font; } diff --git a/src/graphics.cpp b/src/blah_graphics.cpp similarity index 99% rename from src/graphics.cpp rename to src/blah_graphics.cpp index c451964..437d87f 100644 --- a/src/graphics.cpp +++ b/src/blah_graphics.cpp @@ -1,5 +1,6 @@ -#include -#include "internal/internal.h" +#include +#include +#include "internal/blah_internal.h" using namespace Blah; diff --git a/src/images/image.cpp b/src/blah_image.cpp similarity index 98% rename from src/images/image.cpp rename to src/blah_image.cpp index 83b5c03..30bf35c 100644 --- a/src/images/image.cpp +++ b/src/blah_image.cpp @@ -1,14 +1,14 @@ -#include +#include using namespace Blah; #define STB_IMAGE_IMPLEMENTATION #define STBI_ONLY_JPEG #define STBI_ONLY_PNG -#include "../third_party/stb_image.h" +#include "third_party/stb_image.h" #define STB_IMAGE_WRITE_IMPLEMENTATION -#include "../third_party/stb_image_write.h" +#include "third_party/stb_image_write.h" namespace { diff --git a/src/input.cpp b/src/blah_input.cpp similarity index 98% rename from src/input.cpp rename to src/blah_input.cpp index e0228ef..aeb5c82 100644 --- a/src/input.cpp +++ b/src/blah_input.cpp @@ -1,11 +1,10 @@ -#include -#include -#include -#include -#include -#include "internal/internal.h" -#include "internal/platform.h" -#include +#include +#include +#include +#include +#include +#include "internal/blah_internal.h" +#include "internal/blah_platform.h" using namespace Blah; @@ -33,9 +32,9 @@ void Input::Internal::init() Input::last_state = g_empty_state; Input::state = g_empty_state; - g_buttons.dispose(); - g_axes.dispose(); - g_sticks.dispose(); + g_buttons = Vector>(); + g_axes = Vector>(); + g_sticks = Vector>(); } void Input::Internal::shutdown() diff --git a/src/images/packer.cpp b/src/blah_packer.cpp similarity index 99% rename from src/images/packer.cpp rename to src/blah_packer.cpp index e0e83be..029f3bc 100644 --- a/src/images/packer.cpp +++ b/src/blah_packer.cpp @@ -1,6 +1,5 @@ -#include +#include #include -#include using namespace Blah; diff --git a/src/drawing/spritefont.cpp b/src/blah_spritefont.cpp similarity index 89% rename from src/drawing/spritefont.cpp rename to src/blah_spritefont.cpp index 00e9a43..9421ae4 100644 --- a/src/drawing/spritefont.cpp +++ b/src/blah_spritefont.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include using namespace Blah; @@ -46,21 +46,25 @@ float SpriteFont::width_of(const String& text) const float line_width = 0; Codepoint last = 0; - for (int i = 0; i < text.length(); i += text.utf8_length(i)) + + Utf8 utf8(text.cstr()); + while (utf8.character) { - if (text[i] == '\n') + if (utf8.character == '\n') { line_width = 0; - continue; + } + else + { + line_width += get_character(utf8.character).advance; + if (last) + line_width += get_kerning(last, utf8.character); + if (line_width > width) + width = line_width; + last = utf8.character; } - auto next = text.utf8_at(i); - line_width += get_character(next).advance; - if (i > 0) - line_width += get_kerning(last, next); - if (line_width > width) - width = line_width; - last = next; + utf8.next(); } return width; @@ -72,18 +76,19 @@ float SpriteFont::width_of_line(const String& text, int start) const if (start >= text.length()) return 0; float width = 0; - Codepoint last = 0; - for (auto i = start; i < text.length(); i += text.utf8_length(i)) - { - if (text[i] == '\n') - return width; - auto next = text.utf8_at(i); - width += get_character(next).advance; - if (i > 0) - width += get_kerning(last, next); - last = next; + Utf8 utf8(text.cstr()); + while (utf8.character) + { + if (utf8.character == '\n') + break; + + width += get_character(utf8.character).advance; + if (last) + width += get_kerning(last, utf8.character); + last = utf8.character; + utf8.next(); } return width; @@ -95,10 +100,13 @@ float SpriteFont::height_of(const String& text) const return 0; float height = line_height(); - for (auto i = 0; i < text.length(); i += text.utf8_length(i)) + + Utf8 utf8(text.cstr()); + while (utf8.character) { - if (text[i] == '\n') + if (utf8.character == '\n') height += line_height(); + utf8.next(); } return height - line_gap; diff --git a/src/stream.cpp b/src/blah_stream.cpp similarity index 98% rename from src/stream.cpp rename to src/blah_stream.cpp index c794f31..5efb744 100644 --- a/src/stream.cpp +++ b/src/blah_stream.cpp @@ -1,6 +1,5 @@ -#include -#include -#include +#include +#include using namespace Blah; @@ -47,7 +46,7 @@ String Stream::read_string(int length) } else { - result.set_length(length); + result.append('\0', length); read(result.cstr(), length); } diff --git a/src/blah_string.cpp b/src/blah_string.cpp new file mode 100644 index 0000000..b24dc9f --- /dev/null +++ b/src/blah_string.cpp @@ -0,0 +1,360 @@ +#include + +using namespace Blah; + +namespace +{ + char blah_to_lower(char c) + { + if (c >= 'A' && c <= 'Z') return c - 'A' + 'a'; + return c; + } + + int blah_strlen(const char* cstr) + { + int len = 0; + if (cstr) + while (*(cstr + len) != '\0' && len < INT32_MAX) len++; + return len; + } +} + +void BaseString::assign(const char* cstr, const char* cstr_end) +{ + s_clear(); + append(cstr, cstr_end); +} + +void BaseString::append(const char* cstr, const char* cstr_end) +{ + // make sure values are valid + if (cstr == nullptr || *cstr == '\0') + return; + if (cstr_end == nullptr) + cstr_end = cstr + blah_strlen(cstr); + + // reserve (+1 for null-terminator) + auto len = length(); + s_ensure(len + (cstr_end - cstr) + 1); + + // copy value over to our buffer + char* dst = s_ptr() + len; + while (cstr < cstr_end) + *(dst++) = *(cstr++); +} + +void BaseString::append(const u16* u16_cstr, const u16* u16_cstr_end, bool swap_endian) +{ + // converts utf16 into utf8 + // more info: https://en.wikipedia.org/wiki/UTF-16#Description + + const u16 surrogate_min = 0xd800u; + const u16 surrogate_max = 0xdbffu; + + while ((u16_cstr_end == nullptr && *u16_cstr != 0) || (u16_cstr_end != nullptr && u16_cstr != u16_cstr_end)) + { + u16 next = (*u16_cstr++); + if (swap_endian) + next = ((next & 0xff) << 8 | ((next & 0xff00) >> 8)); + + u32 cp = 0xffff & next; + + if ((cp >= surrogate_min && cp <= surrogate_max)) + { + next = (*u16_cstr++); + if (swap_endian) + next = ((next & 0xff) << 8 | ((next & 0xff00) >> 8)); + + u32 trail = 0xffff & next; + cp = (cp << 10) + trail + 0x10000u - (surrogate_min << 10) - 0xdc00u; + } + + append(cp); + } +} + +void BaseString::append(char ch, int count) +{ + // reserve (+1 for null-terminator) + auto len = length(); + s_ensure(len + count + 1); + + // copy value over to our buffer + char* dst = s_ptr() + len; + char* end = dst + count; + while (dst < end) + *(dst++) = ch; +} + +void BaseString::append(u32 c) +{ + // one octet + if (c < 0x80) + { + append((char)c); + } + // two octets + else if (c < 0x800) + { + append((char)((c >> 6) | 0xc0)); + append((char)((c & 0x3f) | 0x80)); + } + // three octets + else if (c < 0x10000) + { + append((char)((c >> 12) | 0xe0)); + append((char)(((c >> 6) & 0x3f) | 0x80)); + append((char)((c & 0x3f) | 0x80)); + } + // four octets + else + { + append((char)((c >> 18) | 0xf0)); + append((char)(((c >> 12) & 0x3f) | 0x80)); + append((char)(((c >> 6) & 0x3f) | 0x80)); + append((char)((c & 0x3f) | 0x80)); + } +} + +void BaseString::append_fmt(const char* fmt, ...) +{ + va_list args; + + // determine arg m_length + va_start(args, fmt); + auto add = vsnprintf(nullptr, 0, fmt, args); + va_end(args); + + if (add <= 0) + return; + + // reserve (+1 for null-terminator) + auto len = length(); + s_ensure(len + add + 1); + + // print out + va_start(args, fmt); + vsnprintf(s_ptr() + len, add + 1, fmt, args); + va_end(args); +} + +bool BaseString::starts_with(const char* cstr, bool ignore_case) const +{ + if (cstr == nullptr || *cstr == '\0') + return length() == 0; + + const char* ptr = s_ptr(); + + if (ignore_case) + { + while (*cstr != '\0') + { + if (blah_to_lower(*cstr) != blah_to_lower(*ptr)) + return false; + cstr++; ptr++; + } + } + else + { + while (*cstr != '\0') + { + if (*cstr != *ptr) + return false; + cstr++; ptr++; + } + } + + return true; +} + +bool BaseString::ends_with(const char* cstr, bool ignore_case) const +{ + if (cstr == nullptr || *cstr == '\0') + return length() == 0; + + int len = blah_strlen(cstr); + if (len > length()) + return false; + + const char* ptr = s_ptr() + length() - len; + + if (ignore_case) + { + while (*cstr != '\0') + { + if (blah_to_lower(*cstr) != blah_to_lower(*ptr)) + return false; + cstr++; ptr++; + } + } + else + { + while (*cstr != '\0') + { + if (*cstr != *ptr) + return false; + cstr++; ptr++; + } + } + + return true; +} + +bool BaseString::contains(const char* cstr, bool ignore_case) const +{ + if (cstr == nullptr || *cstr == '\0') + return length() == 0; + + int len = blah_strlen(cstr); + if (len > length()) + return false; + + const char* ptr = s_ptr(); + const char* end = s_ptr() + len; + + while (ptr < end) + { + const char* at = ptr; + bool match = true; + + if (ignore_case) + { + while (*cstr != '\0') + { + if (blah_to_lower(*cstr) != blah_to_lower(*at)) + { + match = false; + break; + } + cstr++; at++; + } + } + else + { + while (*cstr != '\0') + { + if (*cstr != *at) + { + match = false; + break; + } + cstr++; at++; + } + } + + if (match) + return true; + } + + return false; +} + +int BaseString::first_index_of(char ch) const +{ + const char* ptr = s_ptr(); + const char* end = ptr + length(); + + while (ptr < end) + { + if (*ptr == ch) + return ptr - s_ptr(); + ptr++; + } + + return -1; +} + +int BaseString::last_index_of(char ch) const +{ + const char* ptr = s_ptr(); + const char* end = ptr + length() - 1; + + while (end >= ptr) + { + if (*end == ch) + return end - s_ptr(); + end--; + } + + return -1; +} + +bool BaseString::equals(const char* other, bool ignore_case) const +{ + const char* a = s_ptr(); const char* b = other; + + if (ignore_case) + { + while (blah_to_lower(*a) == blah_to_lower(*b) && *a != '\0') { a++; b++; } + return blah_to_lower(*a) == blah_to_lower(*b); + } + else + { + while (*a == *b && *a != '\0') { a++; b++; } + return *a == *b; + } +} + +namespace +{ + u32 utf8_character_at(const char* str) + { + u32 charcode = 0; + + int t = (unsigned char)(*(str++)); + if (t < 128) + return t; + + int high_bit_mask = (1 << 6) - 1; + int high_bit_shift = 0; + int total_bits = 0; + int other_bits = 6; + + while ((t & 0xC0) == 0xC0) + { + t <<= 1; + t &= 0xff; + total_bits += 6; + high_bit_mask >>= 1; + high_bit_shift++; + charcode <<= other_bits; + charcode |= ((unsigned char)(*(str++))) & ((1 << other_bits) - 1); + } + charcode |= ((t >> high_bit_shift) & high_bit_mask) << total_bits; + + return charcode; + } + + u32 utf8_character_size(const char* str) + { + char c = *str; + if (c == '\0') + return 0; + if ((c & 0xFE) == 0xFC) + return 6; + if ((c & 0xFC) == 0xF8) + return 5; + if ((c & 0xF8) == 0xF0) + return 4; + if ((c & 0xF0) == 0xE0) + return 3; + if ((c & 0xE0) == 0xC0) + return 2; + return 1; + } +} + +Utf8::Utf8(const char* cstr) + : str(cstr) +{ + character = utf8_character_at(str); + character_size = utf8_character_size(str); +} + +bool Utf8::next() +{ + str += character_size; + character = utf8_character_at(str); + character_size = utf8_character_size(str); + return character_size > 0; +} \ No newline at end of file diff --git a/src/drawing/subtexture.cpp b/src/blah_subtexture.cpp similarity index 96% rename from src/drawing/subtexture.cpp rename to src/blah_subtexture.cpp index 77a9dc5..23e6d07 100644 --- a/src/drawing/subtexture.cpp +++ b/src/blah_subtexture.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include using namespace Blah; diff --git a/src/time.cpp b/src/blah_time.cpp similarity index 96% rename from src/time.cpp rename to src/blah_time.cpp index 417c044..918676c 100644 --- a/src/time.cpp +++ b/src/blah_time.cpp @@ -1,5 +1,5 @@ -#include -#include "internal/internal.h" +#include +#include "internal/blah_internal.h" using namespace Blah; diff --git a/src/containers/str.cpp b/src/containers/str.cpp deleted file mode 100644 index d4421a7..0000000 --- a/src/containers/str.cpp +++ /dev/null @@ -1,492 +0,0 @@ -#include -#include // for strcpy etc -#include // for format methods -#include // for sprintf -#include // toupper - -using namespace Blah; - -char Str::empty_buffer[1] = { '\0' }; - -bool Str::operator==(const Str& rhs) const -{ - return strcmp(cstr(), rhs.cstr()) == 0; -} - -bool Str::operator!=(const Str& rhs) const -{ - return strcmp(cstr(), rhs.cstr()) != 0; -} - -bool Str::operator==(const char* rhs) const -{ - return strcmp(cstr(), rhs) == 0; -} - -bool Str::operator!=(const char* rhs) const -{ - return strcmp(cstr(), rhs) != 0; -} - -void Str::reserve(int size) -{ - int buffer_length = size + 1; - if (buffer_length > m_capacity) - { - if (m_capacity <= 0) - m_capacity = 16; - - while (m_capacity < buffer_length) - m_capacity *= 2; - - // expand from local buffer - if (m_buffer == nullptr) - { - char* local = data(); - m_buffer = new char[m_capacity]; - memcpy(m_buffer, local, m_local_size); - m_buffer[m_local_size] = '\0'; - } - // expand from empty buffer - else if (m_buffer == empty_buffer) - { - m_buffer = new char[m_capacity]; - m_buffer[0] = '\0'; - } - // expand from existing heap buffer - else - { - char* new_buffer = new char[m_capacity]; - memcpy(new_buffer, m_buffer, m_length); - new_buffer[m_length] = '\0'; - delete[] m_buffer; - m_buffer = new_buffer; - } - } -} - -void Str::set_length(int len) -{ - reserve(len); - data()[len] = '\0'; - m_length = len; -} - -u32 Str::utf8_at(int index) const -{ - u32 charcode = 0; - - int t = (unsigned char)(this->operator[](index++)); - if (t < 128) - return t; - - int high_bit_mask = (1 << 6) - 1; - int high_bit_shift = 0; - int total_bits = 0; - int other_bits = 6; - - while ((t & 0xC0) == 0xC0) - { - t <<= 1; - t &= 0xff; - total_bits += 6; - high_bit_mask >>= 1; - high_bit_shift++; - charcode <<= other_bits; - charcode |= ((unsigned char)(this->operator[](index++))) & ((1 << other_bits) - 1); - } - charcode |= ((t >> high_bit_shift) & high_bit_mask) << total_bits; - - return charcode; -} - -int Str::utf8_length(int index) const -{ - auto c = this->operator[](index); - if ((c & 0xFE) == 0xFC) - return 6; - if ((c & 0xFC) == 0xF8) - return 5; - if ((c & 0xF8) == 0xF0) - return 4; - else if ((c & 0xF0) == 0xE0) - return 3; - else if ((c & 0xE0) == 0xC0) - return 2; - return 1; -} - -Str& Str::append(char c) -{ - reserve(m_length + 1); - data()[m_length++] = c; - data()[m_length] = '\0'; - return *this; -} - -Str& Str::append(u32 c) -{ - // one octet - if (c < 0x80) - { - append((char)c); - } - // two octets - else if (c < 0x800) - { - append((char)((c >> 6) | 0xc0)); - append((char)((c & 0x3f) | 0x80)); - } - // three octets - else if (c < 0x10000) - { - append((char)((c >> 12) | 0xe0)); - append((char)(((c >> 6) & 0x3f) | 0x80)); - append((char)((c & 0x3f) | 0x80)); - } - // four octets - else - { - append((char)((c >> 18) | 0xf0)); - append((char)(((c >> 12) & 0x3f) | 0x80)); - append((char)(((c >> 6) & 0x3f) | 0x80)); - append((char)((c & 0x3f) | 0x80)); - } - - return *this; -} - -Str& Str::append(const char* start, const char* end) -{ - if (end == nullptr) - end = start + strlen(start); - - int add = (int)(end - start); - if (add <= 0) - return *this; - - reserve(m_length + add); - memcpy(data() + m_length, start, add); - m_length += add; - data()[m_length] = '\0'; - - return *this; -} - -Str& Str::append(const Str& str, int start, int end) -{ - if (end < 0) end = str.m_length; - if (end > str.m_length) end = str.m_length; - if (start < 0) start = 0; - if (start > end) start = end; - - return append(str.begin() + start, str.begin() + end); -} - -Str& Str::append_fmt(const char* fmt, ...) -{ - int add, diff; - - // determine arg m_length - va_list args; - va_start(args, fmt); - add = vsnprintf(NULL, 0, fmt, args); - va_end(args); - - // reserve - reserve(m_length + add); - diff = m_capacity - m_length; - if (diff <= 0) diff = 0; - - // print out - va_start(args, fmt); - vsnprintf(data() + m_length, (size_t)diff, fmt, args); - va_end(args); - - // increment size - m_length += add; - data()[m_length] = '\0'; - - return *this; -} - -Str& Str::append_utf16(const u16* start, const u16* end, bool swap_endian) -{ - // converts utf16 into utf8 - // more info: https://en.wikipedia.org/wiki/UTF-16#Description - - const u16 surrogate_min = 0xd800u; - const u16 surrogate_max = 0xdbffu; - - while ((end == nullptr && *start != 0) || (end != nullptr && start != end)) - { - u16 next = (*start++); - if (swap_endian) - next = ((next & 0xff) << 8 | ((next & 0xff00) >> 8)); - - u32 cp = 0xffff & next; - - if ((cp >= surrogate_min && cp <= surrogate_max)) - { - next = (*start++); - if (swap_endian) - next = ((next & 0xff) << 8 | ((next & 0xff00) >> 8)); - - u32 trail = 0xffff & next; - cp = (cp << 10) + trail + 0x10000u - (surrogate_min << 10) - 0xdc00u; - } - - append(cp); - } - - return *this; -} - -Str& Str::trim() -{ - if (m_length > 0) - { - const char* s = begin(); - const char* e = end() - 1; - - while (isspace(*s) && s != e) - s++; - while (isspace(*e) && s != e) - e--; - - set(s, e + 1); - } - - return *this; -} - -bool Str::starts_with(const char* str, bool ignoreCase) const -{ - if (str == nullptr) - return m_length == 0; - - int len = (int)strlen(str); - if (len > m_length) - return false; - - const char* a = data(); - const char* b = str; - - if (ignoreCase) - { - for (int n = 0; n < len; n++) - if (tolower(a[n]) != tolower(b[n])) - return false; - } - else - { - for (int n = 0; n < len; n++) - if (a[n] != b[n]) - return false; - } - - return true; -} - -bool Str::contains(const char* str, bool ignoreCase) const -{ - int len = (int)strlen(str); - if (len > m_length || len <= 0) - return false; - - const char* a = data(); - const char* b = str; - - for (int start = 0; start < m_length - len + 1; start++) - { - bool match = true; - - if (ignoreCase) - { - for (int n = 0; n < len && match; n++) - if (tolower(a[start + n]) != tolower(b[n])) - match = false; - } - else - { - for (int n = 0; n < len && match; n++) - if (a[start + n] != b[n]) - match = false; - } - - if (match) - return true; - } - - return false; -} - -bool Str::ends_with(const char* str, bool ignoreCase) const -{ - if (str == nullptr) - return m_length == 0; - - int len = (int)strlen(str); - if (len > m_length || len <= 0) - return false; - - const char* a = data(); - const char* b = str; - - if (ignoreCase) - { - for (int n = m_length - len, i = 0; n < m_length; n++, i++) - if (tolower(a[n]) != tolower(b[i])) - return false; - } - else - { - for (int n = m_length - len, i = 0; n < m_length; n++, i++) - if (a[n] != b[i]) - return false; - } - - return true; -} - -int Str::first_index_of(char ch) const -{ - const char* ptr = data(); - for (int n = 0; n < m_length; n++) - if (ptr[n] == ch) - return n; - return -1; -} - -int Str::last_index_of(char ch) const -{ - const char* ptr = data(); - for (int n = m_length - 1; n >= 0; n--) - if (ptr[n] == ch) - return n; - return -1; -} - -String Str::substr(int start) const -{ - if (start < 0) start = 0; - if (start > m_length) start = m_length; - - return String(data() + start); -} - -String Str::substr(int start, int end) const -{ - if (start < 0) start = 0; - if (start > m_length) start = m_length; - if (end < 0) end = m_length + end; - if (end < start) end = start; - if (end > m_length) end = m_length; - - return Str(data() + start, data() + end); -} - -Vector Str::split(char ch) const -{ - Vector result; - - const char* ptr = data(); - int last = 0; - int index = 1; - - while (index < m_length) - { - if (ptr[index] == ch) - { - result.push_back(substr(last, index)); - last = index + 1; - } - index++; - } - - if (last < index) - result.push_back(substr(last, index)); - - return result; -} - -Str& Str::replace(const Str& os, const Str& ns) -{ - for (int i = 0; i < m_length - os.m_length + 1; i++) - { - if (strncmp(data() + i, os.data(), os.m_length) == 0) - { - if (ns.m_length > os.m_length) - reserve(ns.m_length - os.m_length); - - memmove(data() + i + ns.m_length, data() + i + os.m_length, m_length - i - os.m_length); - memcpy(data() + i, ns.cstr(), ns.m_length); - set_length(m_length + ns.m_length - os.m_length); - i += os.m_length - 1; - } - } - - return *this; -} - -Str& Str::replace(char c, char r) -{ - char* ptr = data(); - for (int n = 0; n < m_length; n++) - if (ptr[n] == c) - ptr[n] = r; - return *this; -} - -void Str::clear() -{ - if (m_capacity > 0) - data()[0] = '\0'; - m_length = 0; -} - -void Str::dispose() -{ - if (m_buffer != nullptr && m_buffer != empty_buffer) - delete[] m_buffer; - - if (m_local_size > 0) - { - m_buffer = nullptr; - m_capacity = m_local_size; - data()[0] = '\0'; - } - else - { - m_buffer = empty_buffer; - m_capacity = 0; - } - - m_length = 0; -} - -void Str::set(const char* start, const char* end) -{ - // find the end - if (end == nullptr) - end = start + strlen(start); - - // make sure it actually contains characters - int len = (int)(end - start); - if (len <= 0) - { - clear(); - } - else - { - m_length = len; - - // reserve - reserve(m_length); - - // copy the data over - char* ptr = data(); - memcpy(ptr, start, m_length); - ptr[m_length] = '\0'; - } -} \ No newline at end of file diff --git a/src/internal/internal.h b/src/internal/blah_internal.h similarity index 92% rename from src/internal/internal.h rename to src/internal/blah_internal.h index fb3e0b5..a856014 100644 --- a/src/internal/internal.h +++ b/src/internal/blah_internal.h @@ -1,6 +1,6 @@ #pragma once -#include "renderer.h" -#include "platform.h" +#include "blah_renderer.h" +#include "blah_platform.h" #define BLAH_ASSERT_RENDERER() BLAH_ASSERT(App::Internal::renderer, "Renderer has not been created") #define BLAH_ASSERT_PLATFORM() BLAH_ASSERT(App::Internal::platform, "Platform has not been created") diff --git a/src/internal/platform.h b/src/internal/blah_platform.h similarity index 97% rename from src/internal/platform.h rename to src/internal/blah_platform.h index 2a25250..e57279c 100644 --- a/src/internal/platform.h +++ b/src/internal/blah_platform.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include namespace Blah { diff --git a/src/internal/platform_sdl2.cpp b/src/internal/blah_platform_sdl2.cpp similarity index 98% rename from src/internal/platform_sdl2.cpp rename to src/internal/blah_platform_sdl2.cpp index d2f3b16..440e354 100644 --- a/src/internal/platform_sdl2.cpp +++ b/src/internal/blah_platform_sdl2.cpp @@ -1,13 +1,13 @@ #ifdef BLAH_PLATFORM_SDL2 -#include "platform.h" -#include "renderer.h" -#include "internal.h" -#include -#include -#include -#include -#include +#include "blah_platform.h" +#include "blah_renderer.h" +#include "blah_internal.h" +#include +#include +#include +#include +#include #include diff --git a/src/internal/platform_win32.cpp b/src/internal/blah_platform_win32.cpp similarity index 99% rename from src/internal/platform_win32.cpp rename to src/internal/blah_platform_win32.cpp index 9f8ead6..2408578 100644 --- a/src/internal/platform_win32.cpp +++ b/src/internal/blah_platform_win32.cpp @@ -3,13 +3,13 @@ // Note: // This is unfinished! It is missing Controller Support! -#include "platform.h" -#include "internal.h" -#include -#include -#include -#include -#include +#include "blah_platform.h" +#include "blah_internal.h" +#include +#include +#include +#include +#include #define WIN32_LEAN_AND_MEAN #include diff --git a/src/internal/renderer.h b/src/internal/blah_renderer.h similarity index 96% rename from src/internal/renderer.h rename to src/internal/blah_renderer.h index 77df783..84e5f92 100644 --- a/src/internal/renderer.h +++ b/src/internal/blah_renderer.h @@ -1,7 +1,7 @@ #pragma once -#include -#include -#include +#include +#include +#include namespace Blah { diff --git a/src/internal/renderer_d3d11.cpp b/src/internal/blah_renderer_d3d11.cpp similarity index 99% rename from src/internal/renderer_d3d11.cpp rename to src/internal/blah_renderer_d3d11.cpp index ac1f215..9521ffe 100644 --- a/src/internal/renderer_d3d11.cpp +++ b/src/internal/blah_renderer_d3d11.cpp @@ -3,10 +3,10 @@ // TODO: // Note the D3D11 Implementation is still a work-in-progress -#include "renderer.h" -#include "internal.h" -#include "platform.h" -#include +#include "blah_renderer.h" +#include "blah_internal.h" +#include "blah_platform.h" +#include #include #include #include diff --git a/src/internal/renderer_opengl.cpp b/src/internal/blah_renderer_opengl.cpp similarity index 99% rename from src/internal/renderer_opengl.cpp rename to src/internal/blah_renderer_opengl.cpp index 71559a7..f2966c3 100644 --- a/src/internal/renderer_opengl.cpp +++ b/src/internal/blah_renderer_opengl.cpp @@ -1,9 +1,9 @@ #ifdef BLAH_RENDERER_OPENGL -#include "renderer.h" -#include "internal.h" -#include "platform.h" -#include +#include "blah_renderer.h" +#include "blah_internal.h" +#include "blah_platform.h" +#include #include #include #include @@ -942,7 +942,7 @@ namespace Blah m_uniforms.push_back(tex_uniform); UniformInfo sampler_uniform; - sampler_uniform.name = String(name).append("_sampler"); + sampler_uniform.name = String(name) + "_sampler"; sampler_uniform.register_index = sampler_uniforms; sampler_uniform.buffer_index = 0; sampler_uniform.array_length = size;