Removed custom list class in favor of std::vector

This commit is contained in:
Noel Berry 2020-10-24 15:21:36 -07:00
parent 06052410f2
commit b4e1cd111e
32 changed files with 644 additions and 619 deletions

View File

@ -22,8 +22,8 @@ add_library(blah
public/blah/graphics/texture.h public/blah/graphics/texture.h
public/blah/graphics/framebuffer.h public/blah/graphics/framebuffer.h
public/blah/graphics/shader.h public/blah/graphics/shader.h
public/blah/graphics/mesh.cpp
public/blah/graphics/mesh.h public/blah/graphics/mesh.h
public/blah/graphics/mesh.cpp
public/blah/graphics/material.h public/blah/graphics/material.h
public/blah/graphics/material.cpp public/blah/graphics/material.cpp
@ -36,8 +36,7 @@ add_library(blah
public/blah/input/virtual_axis.cpp public/blah/input/virtual_axis.cpp
public/blah/input/virtual_axis.h public/blah/input/virtual_axis.h
public/blah/containers/list.h public/blah/containers/stackvector.h
public/blah/containers/stacklist.h
public/blah/containers/str.cpp public/blah/containers/str.cpp
public/blah/containers/str.h public/blah/containers/str.h
@ -100,8 +99,7 @@ add_library(blah
private/blah/internal/graphics_opengl.cpp private/blah/internal/graphics_opengl.cpp
private/blah/internal/input.h private/blah/internal/input.h
private/blah/internal/platform.h private/blah/internal/platform.h
private/blah/internal/platform_sdl2.cpp private/blah/internal/platform_sdl2.cpp "public/blah/containers/vector.h")
)
target_include_directories(blah target_include_directories(blah
PUBLIC PUBLIC

View File

@ -10,7 +10,7 @@ this will likely see breaking changes.
#### notes #### notes
- There are probably lots of small bugs as this is highly untested. Best used as a learning resource for now. - There are probably lots of small bugs as this is highly untested. Best used as a learning resource for now.
- There's a custom "vector" class which is called List and Stacklist which may later be replaced with std::vector - There's a custom "StackVector" class that tries to implement an std::vector on the stack, but it's probably bug-prone.
- There's no Shader abstraction, so the [Sprite Batcher](https://github.com/NoelFB/blah/blob/master/public/blah/drawing/batch.h) has hard-coded GLSL. This will need to change. - There's no Shader abstraction, so the [Sprite Batcher](https://github.com/NoelFB/blah/blob/master/public/blah/drawing/batch.h) has hard-coded GLSL. This will need to change.
- The rendering layer may be replaced with [FNA3D](https://github.com/FNA-XNA/FNA3D), [BGFX](https://github.com/bkaradzic/bgfx), [Sokol](https://github.com/floooh/sokol), or something else. - The rendering layer may be replaced with [FNA3D](https://github.com/FNA-XNA/FNA3D), [BGFX](https://github.com/bkaradzic/bgfx), [Sokol](https://github.com/floooh/sokol), or something else.
- There's no Audio layer implementation yet. - There's no Audio layer implementation yet.

View File

@ -9,11 +9,14 @@
#include <blah/graphics/mesh.h> #include <blah/graphics/mesh.h>
#include <blah/graphics/shader.h> #include <blah/graphics/shader.h>
#include <blah/graphics/material.h> #include <blah/graphics/material.h>
#include <blah/containers/stackvector.h>
#include <blah/log.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stddef.h> #include <stddef.h>
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#else #else
#define APIENTRY #define APIENTRY
@ -715,7 +718,7 @@ namespace Blah
GLuint m_id; GLuint m_id;
int m_width; int m_width;
int m_height; int m_height;
StackList<TextureRef, BLAH_ATTACHMENTS> m_attachments; StackVector<TextureRef, BLAH_ATTACHMENTS> m_attachments;
public: public:
@ -733,7 +736,7 @@ namespace Blah
auto gltex = ((OpenGL_Texture*)tex.get()); auto gltex = ((OpenGL_Texture*)tex.get());
gltex->framebuffer_parent = true; gltex->framebuffer_parent = true;
m_attachments.add(tex); m_attachments.push_back(tex);
if (attachments[i] != TextureFormat::DepthStencil) if (attachments[i] != TextureFormat::DepthStencil)
{ {
@ -896,11 +899,11 @@ namespace Blah
gl.GetActiveAttrib(id, i, BLAH_ATTRIBUTE_NAME - 1, &length, &size, &type, name); gl.GetActiveAttrib(id, i, BLAH_ATTRIBUTE_NAME - 1, &length, &size, &type, name);
name[length] = '\0'; name[length] = '\0';
auto attr = m_attributes.expand(); ShaderAttribute attr;
attr->name.append(name); attr.name = name;
// TOOD: set these? attr.semantic_name = "";
attr->semantic_name = ""; attr.semantic_location = 0;
attr->semantic_location = 0; m_attributes.push_back(attr);
} }
} }
@ -935,31 +938,33 @@ namespace Blah
} }
} }
auto uniform = m_uniforms.expand(); ShaderUniform uniform;
uniform->name = name; uniform.name = name;
uniform->type = UniformType::None; uniform.type = UniformType::None;
uniform->array_length = size; uniform.array_length = size;
uniforms_loc[i] = gl.GetUniformLocation(id, name); uniforms_loc[i] = gl.GetUniformLocation(id, name);
if (type == GL_FLOAT) if (type == GL_FLOAT)
uniform->type = UniformType::Float; uniform.type = UniformType::Float;
else if (type == GL_FLOAT_VEC2) else if (type == GL_FLOAT_VEC2)
uniform->type = UniformType::Float2; uniform.type = UniformType::Float2;
else if (type == GL_FLOAT_VEC3) else if (type == GL_FLOAT_VEC3)
uniform->type = UniformType::Float3; uniform.type = UniformType::Float3;
else if (type == GL_FLOAT_VEC4) else if (type == GL_FLOAT_VEC4)
uniform->type = UniformType::Float4; uniform.type = UniformType::Float4;
else if (type == GL_FLOAT_MAT3x2) else if (type == GL_FLOAT_MAT3x2)
uniform->type = UniformType::Mat3x2; uniform.type = UniformType::Mat3x2;
else if (type == GL_FLOAT_MAT4) else if (type == GL_FLOAT_MAT4)
uniform->type = UniformType::Mat4x4; uniform.type = UniformType::Mat4x4;
else if (type == GL_SAMPLER_2D) else if (type == GL_SAMPLER_2D)
uniform->type = UniformType::Texture; uniform.type = UniformType::Texture;
else else
{ {
Log::error("Unsupported Uniform Type. Must be either FLOAT, MAT3x2, MAT4, or SAMPLER_2D"); Log::error("Unsupported Uniform Type. Must be either FLOAT, MAT3x2, MAT4, or SAMPLER_2D");
break; break;
} }
m_uniforms.push_back(uniform);
} }
} }
} }
@ -1041,6 +1046,8 @@ namespace Blah
m_instance_size = 0; m_instance_size = 0;
m_vertex_attribs_enabled = 0; m_vertex_attribs_enabled = 0;
m_instance_attribs_enabled = 0; m_instance_attribs_enabled = 0;
m_vertex_attribs[0] = 0;
m_instance_attribs[0] = 0;
gl.GenVertexArrays(1, &m_id); gl.GenVertexArrays(1, &m_id);
} }
@ -1284,7 +1291,7 @@ namespace Blah
GLint texture_ids[64]; GLint texture_ids[64];
auto& uniforms = shader->uniforms(); auto& uniforms = shader->uniforms();
for (int i = 0; i < uniforms.count(); i++) for (int i = 0; i < uniforms.size(); i++)
{ {
auto location = shader->uniforms_loc[i]; auto location = shader->uniforms_loc[i];
auto& uniform = uniforms[i]; auto& uniform = uniforms[i];

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <inttypes.h> #include <inttypes.h>
#include <blah/filesystem.h> #include <blah/filesystem.h>
#include <blah/containers/list.h> #include <blah/containers/vector.h>
namespace Blah namespace Blah
{ {
@ -84,7 +84,7 @@ namespace Blah
bool dir_delete(const char* path); bool dir_delete(const char* path);
// enumerates a directory and appends each file to the given list // enumerates a directory and appends each file to the given list
void dir_enumerate(List<FilePath>& list, const char* path, bool recursive); void dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive);
// opens a directory in the OS file explorer / finder // opens a directory in the OS file explorer / finder
void dir_explore(const char* path); void dir_explore(const char* path);

View File

@ -12,6 +12,7 @@
#if _WIN32 #if _WIN32
// on Windows we're using the C++ <filesystem> API for now // on Windows we're using the C++ <filesystem> API for now
#define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <winuser.h> // for SetProcessDPIAware #include <winuser.h> // for SetProcessDPIAware
#include <filesystem> // for File Reading/Writing #include <filesystem> // for File Reading/Writing
@ -482,25 +483,19 @@ bool Platform::dir_delete(const char* path)
return false; return false;
} }
void Platform::dir_enumerate(List<FilePath>& list, const char* path, bool recursive) void Platform::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive)
{ {
if (fs::is_directory(path)) if (fs::is_directory(path))
{ {
if (recursive) if (recursive)
{ {
for (auto& p : fs::recursive_directory_iterator(path)) for (auto& p : fs::recursive_directory_iterator(path))
{ list.emplace_back(p.path().string().c_str());
FilePath str(p.path().string().c_str());
list.add(str);
}
} }
else else
{ {
for (auto& p : fs::directory_iterator(path)) for (auto& p : fs::directory_iterator(path))
{ list.emplace_back(p.path().string().c_str());
FilePath str(p.path().string().c_str());
list.add(str);
}
} }
} }
} }

View File

@ -6,8 +6,8 @@
#include <blah/log.h> #include <blah/log.h>
#include <blah/time.h> #include <blah/time.h>
#include <blah/containers/list.h> #include <blah/containers/vector.h>
#include <blah/containers/stacklist.h> #include <blah/containers/stackvector.h>
#include <blah/containers/str.h> #include <blah/containers/str.h>
#include <blah/drawing/batch.h> #include <blah/drawing/batch.h>

View File

@ -1,212 +0,0 @@
#pragma once
#include <blah/log.h>
namespace Blah
{
template<class T, int Size>
class StackList
{
private:
// internal list buffer
T m_buffer[Size];
// total elements
int m_count;
public:
StackList();
StackList(const StackList& src);
StackList(StackList&& src) noexcept;
StackList& operator=(const StackList& src);
StackList& operator=(StackList&& src) noexcept;
// adds an element to the list
void add(const T& item);
// moves an element into the list
void add(T&& item);
// expands the list by the given amount, and returns a pointer to the first element
T* expand(int amount = 1);
// returns a reference to the element at the given index
T& operator[](int index);
// returns a reference to the element at the given index
const T& operator[](int index) const;
// returns a pointer to the first element
T* begin() { return m_buffer; }
// returns a pointer to the first element
const T* begin() const { return m_buffer; }
// returns a pointer to the last element
T* end() { return m_buffer + m_count; }
// returns a pointer to the last element
const T* end() const { return m_buffer + m_count; }
// clears all elements
void clear();
// removes the element at the index
void remove_at(int index);
// checks whether the given value is in the StackList (uses == operator)
bool contains(const T& item) const;
// returns the index of the given value in the list (uses == operator, -1 if not in list)
int index_of(const T& item) const;
// pops the top element off the list
T& pop();
// returns the total number of elements
int count() const { return m_count; }
// returns the internal buffer capacity of the list
int capacity() const { return Size; }
};
template<class T, int Size>
StackList<T, Size>::StackList()
{
m_count = 0;
}
template<class T, int Size>
StackList<T, Size>::StackList(const StackList<T, Size>& src)
{
m_count = src.m_count;
for (int n = 0; n < m_count; n++)
m_buffer[n] = src.m_buffer[n];
}
template<class T, int Size>
StackList<T, Size>::StackList(StackList<T, Size>&& src) noexcept
{
m_count = src.m_count;
for (int n = 0; n < m_count; n++)
m_buffer[n] = std::move(src.m_buffer[n]);
src.m_count = 0;
}
template<class T, int Size>
StackList<T, Size>& StackList<T, Size>::operator=(const StackList<T, Size>& src)
{
clear();
m_count = src.m_count;
for (int n = 0; n < m_count; n++)
m_buffer[n] = src.m_buffer[n];
return *this;
}
template<class T, int Size>
StackList<T, Size>& StackList<T, Size>::operator=(StackList<T, Size>&& src) noexcept
{
clear();
m_count = src.m_count;
for (int n = 0; n < m_count; n++)
m_buffer[n] = std::move(src.m_buffer[n]);
src.m_count = 0;
return *this;
}
template<class T, int Size>
T* StackList<T, Size>::expand(int amount)
{
BLAH_ASSERT(m_count + amount < Size, "Exceeded StackList capacity");
for (int n = m_count; n < m_count + amount; n++)
m_buffer[n] = T();
m_count += amount;
return (m_buffer + m_count - amount);
}
template<class T, int Size>
void StackList<T, Size>::add(const T& item)
{
BLAH_ASSERT(m_count < Size, "Exceeded StackList capacity");
m_buffer[m_count] = item;
m_count++;
}
template<class T, int Size>
void StackList<T, Size>::add(T&& item)
{
BLAH_ASSERT(m_count < Size, "Exceeded StackList capacity");
m_buffer[m_count] = std::move(item);
m_count++;
}
template<class T, int Size>
T& StackList<T, Size>::operator[](int index)
{
BLAH_ASSERT(index >= 0 && index < m_count, "Index is out of range");
return m_buffer[index];
}
template<class T, int Size>
const T& StackList<T, Size>::operator[](int index) const
{
BLAH_ASSERT(index >= 0 && index < m_count, "Index is out of range");
return m_buffer[index];
}
template<class T, int Size>
void StackList<T, Size>::clear()
{
m_count = 0;
}
template<class T, int Size>
void StackList<T, Size>::remove_at(int index)
{
BLAH_ASSERT(index >= 0 && index < m_count, "Index is out of range");
if (index < m_count - 1)
{
for (int n = index; n < m_count - 1; n++)
m_buffer[n] = m_buffer[n + 1];
m_buffer[m_count] = T();
}
m_count--;
}
template<class T, int Size>
bool StackList<T, Size>::contains(const T& item) const
{
for (int i = 0; i < m_count; i++)
if (*(m_buffer + i) == item)
return true;
return false;
}
template<class T, int Size>
int StackList<T, Size>::index_of(const T& item) const
{
for (int i = 0; i < m_count; i++)
if (*(m_buffer + i) == item)
return i;
return -1;
}
template<class T, int Size>
T& StackList<T, Size>::pop()
{
BLAH_ASSERT(m_count > 0, "There are no elements to pop");
m_count--;
return m_buffer[m_count];
}
}

View File

@ -0,0 +1,200 @@
#pragma once
#include <blah/log.h>
#include <string.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, int Capacity>
class StackVector
{
private:
// we avoid using an array of type T to make sure the default
// constructor/destructors are not called
char m_buffer[Capacity * sizeof(T)];
size_t m_size;
public:
StackVector();
StackVector(const StackVector& src);
StackVector(StackVector&& src) noexcept;
~StackVector();
StackVector& operator=(const StackVector& src);
StackVector& operator=(StackVector&& src) noexcept;
void push_back(const T& item);
void push_back(T&& item);
template<class ... Args>
void emplace_back(Args&&... args) { push_back(T(std::forward<Args>(args)...)); }
T& operator[](int index);
const T& operator[](int index) const;
T* begin() { return (T*)m_buffer; }
const T* begin() const { return (T*)m_buffer; }
T* end() { return ((T*)m_buffer) + m_size; }
const T* end() const { return ((T*)m_buffer) + m_size; }
T& front() { BLAH_ASSERT(m_size > 0, "Index out of range"); return *begin(); }
const T& front() const { BLAH_ASSERT(m_size > 0, "Index out of range"); return *begin(); }
T& back() { BLAH_ASSERT(m_size > 0, "Index out of range"); return *(end() - 1); }
const T& back() const { BLAH_ASSERT(m_size > 0, "Index out of range"); return *(end() - 1); }
void clear();
void erase(const T* position);
size_t size() const { return m_size; }
constexpr size_t capacity() const { return Capacity; }
};
template<class T, int Capacity>
StackVector<T, Capacity>::StackVector()
{
m_size = 0;
m_buffer[0] = 0;
}
template<class T, int Capacity>
StackVector<T, Capacity>::StackVector(const StackVector<T, Capacity>& src)
{
m_size = src.m_size;
for (int n = 0; n < m_size; n++)
new(begin() + n) T(*(src.begin() + n));
}
template<class T, int Capacity>
StackVector<T, Capacity>::StackVector(StackVector<T, Capacity>&& src) noexcept
{
m_size = src.m_size;
if (std::is_trivially_copyable<T>::value)
{
memcpy(m_buffer, src.m_buffer, sizeof(T) * m_size);
src.m_size = 0;
}
else
{
for (int n = 0; n < m_size; n++)
new(begin() + n) T(std::move(*(src.begin() + n)));
src.clear();
}
}
template<class T, int Capacity>
StackVector<T, Capacity>& StackVector<T, Capacity>::operator=(const StackVector<T, Capacity>& src)
{
clear();
m_size = src.m_size;
for (int n = 0; n < m_size; n++)
new(begin() + n) T(*(src.begin() + n));
return *this;
}
template<class T, int Capacity>
StackVector<T, Capacity>& StackVector<T, Capacity>::operator=(StackVector<T, Capacity>&& src) noexcept
{
clear();
m_size = src.m_size;
if (std::is_trivially_copyable<T>::value)
{
memcpy(m_buffer, src.m_buffer, sizeof(T) * m_size);
src.m_size = 0;
}
else
{
for (int n = 0; n < m_size; n++)
new(begin() + n) T(std::move(*(src.begin() + n)));
src.clear();
}
return *this;
}
template<class T, int Capacity>
StackVector<T, Capacity>::~StackVector()
{
clear();
}
template<class T, int Capacity>
void StackVector<T, Capacity>::push_back(const T& item)
{
BLAH_ASSERT(m_size < Capacity, "Exceeded StackVector Capacity");
new(begin() + m_size) T(item);
m_size++;
}
template<class T, int Capacity>
void StackVector<T, Capacity>::push_back(T&& item)
{
BLAH_ASSERT(m_size < Capacity, "Exceeded StackVector Capacity");
new(begin() + m_size) T(std::move(item));
m_size++;
}
template<class T, int Capacity>
T& StackVector<T, Capacity>::operator[](int index)
{
BLAH_ASSERT(index >= 0 && index < m_size, "Index is out of range");
return begin()[index];
}
template<class T, int Capacity>
const T& StackVector<T, Capacity>::operator[](int index) const
{
BLAH_ASSERT(index >= 0 && index < m_size, "Index is out of range");
return begin()[index];
}
template<class T, int Capacity>
void StackVector<T, Capacity>::clear()
{
for (T* it = begin(); it < begin() + m_size; it++)
it->~T();
m_size = 0;
}
template<class T, int Capacity>
void StackVector<T, Capacity>::erase(const T* position)
{
BLAH_ASSERT(position >= begin() && position < end(), "Index is out of range");
const size_t index = position - begin();
if (index < m_size - 1)
{
size_t diff = (m_size - index - 1);
if (diff <= 0) diff = 0;
if (std::is_trivially_copyable<T>::value)
{
begin()[index].~T();
memmove(begin() + index, begin() + index + 1, (size_t)diff * sizeof(T));
}
else
{
for (int i = index; i < m_size - 1; i++)
begin()[i] = std::move(begin()[i + 1]);
begin()[m_size - 1].~T();
}
}
else
{
begin()[index].~T();
}
m_size--;
}
}

View File

@ -314,15 +314,15 @@ int Str::last_index_of(char ch) const
return -1; return -1;
} }
Str Str::substr(int start) const String Str::substr(int start) const
{ {
if (start < 0) start = 0; if (start < 0) start = 0;
if (start > m_length) start = m_length; if (start > m_length) start = m_length;
return Str(data() + start); return String(data() + start);
} }
Str Str::substr(int start, int end) const String Str::substr(int start, int end) const
{ {
if (start < 0) start = 0; if (start < 0) start = 0;
if (start > m_length) start = m_length; if (start > m_length) start = m_length;
@ -333,6 +333,30 @@ Str Str::substr(int start, int end) const
return Str(data() + start, data() + end); return Str(data() + start, data() + end);
} }
Vector<String> Str::split(char ch) const
{
Vector<String> 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;
}
void Str::replace(char c, char r) void Str::replace(char c, char r)
{ {
char* ptr = data(); char* ptr = data();

View File

@ -1,8 +1,13 @@
#pragma once #pragma once
#include <inttypes.h> #include <inttypes.h>
#include <blah/containers/vector.h>
namespace Blah namespace Blah
{ {
template<int T>
class StrOf;
using String = StrOf<64>;
class Str class Str
{ {
public: public:
@ -115,10 +120,12 @@ namespace Blah
int last_index_of(char ch) const; int last_index_of(char ch) const;
// returns a substring of the string // returns a substring of the string
Str substr(int start) const; String substr(int start) const;
// returns a substring of the string // returns a substring of the string
Str substr(int start, int end) const; String substr(int start, int end) const;
Vector<String> split(char ch) const;
// replaces all occurances of the given character in the string // replaces all occurances of the given character in the string
void replace(char c, char r); void replace(char c, char r);
@ -148,11 +155,10 @@ namespace Blah
} }
// returns a pointer to the heap buffer or to our stack allocation // returns a pointer to the heap buffer or to our stack allocation
char* data() { return (m_buffer != nullptr ? m_buffer : ((char*)(this) + sizeof(Str))); } char* data() { return (m_buffer != nullptr ? m_buffer : ((char*)(this) + sizeof(Str))); }
const char* data() const { return (m_buffer != nullptr ? m_buffer : ((char*)(this) + sizeof(Str))); } const char* data() const { return (m_buffer != nullptr ? m_buffer : ((char*)(this) + sizeof(Str))); }
void set(const Str& str) { set(str.cstr(), str.cstr() + str.m_length); } void set(const Str& str) { set(str.cstr(), str.cstr() + str.m_length); }
void set(const char* start, const char* end = nullptr); void set(const char* start, const char* end = nullptr);
private: private:
@ -180,6 +186,4 @@ namespace Blah
StrOf& operator=(const Str& rhs) { set(rhs); return *this; } StrOf& operator=(const Str& rhs) { set(rhs); return *this; }
StrOf& operator=(const StrOf& rhs) { set(rhs); return *this; } StrOf& operator=(const StrOf& rhs) { set(rhs); return *this; }
}; };
using String = StrOf<64>;
} }

View File

@ -0,0 +1,8 @@
#pragma once
#include <vector>
namespace Blah
{
template<typename T>
using Vector = std::vector<T>;
}

View File

@ -67,54 +67,45 @@ namespace
} }
} }
#define MAKE_VERTEX(vert, mat, px, py, tx, ty, c, m, w, f) \ #define MAKE_VERTEX(mat, px, py, tx, ty, c, m, w, f) \
(vert)->pos.x = ((px) * mat.m11) + ((py) * mat.m21) + mat.m31; \ { \
(vert)->pos.y = ((px) * mat.m12) + ((py) * mat.m22) + mat.m32; \ Vec2( \
(vert)->tex.x = tx; \ ((px)*mat.m11) + ((py)*mat.m21) + mat.m31, \
if (m_batch.flip_vertically) \ ((px)*mat.m12) + ((py)*mat.m22) + mat.m32), \
(vert)->tex.y = 1.0f - ty; \ Vec2(tx, (m_batch.flip_vertically ? 1.0f - ty : ty)), \
else \ c, m, w, f \
(vert)->tex.y = ty; \ }
(vert)->col = c; \
(vert)->mult = m; \
(vert)->wash = w; \
(vert)->fill = f;
#define PUSH_QUAD(px0, py0, px1, py1, px2, py2, px3, py3, tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, col0, col1, col2, col3, mult, fill, wash) \ #define PUSH_QUAD(px0, py0, px1, py1, px2, py2, px3, py3, tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, col0, col1, col2, col3, mult, fill, wash) \
{ \ { \
const int __v = (int)m_vertices.size(); \
m_batch.elements += 2; \ m_batch.elements += 2; \
int* _i = m_indices.expand(6); \ m_indices.insert(m_indices.end(), { __v + 0, __v + 1, __v + 2, __v + 0, __v + 2, __v + 3 }); \
*_i++ = m_vertices.count() + 0; \ m_vertices.insert(m_vertices.end(), { \
*_i++ = m_vertices.count() + 1; \ MAKE_VERTEX(m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash), \
*_i++ = m_vertices.count() + 2; \ MAKE_VERTEX(m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash), \
*_i++ = m_vertices.count() + 0; \ MAKE_VERTEX(m_matrix, px2, py2, tx2, ty2, col2, mult, fill, wash), \
*_i++ = m_vertices.count() + 2; \ MAKE_VERTEX(m_matrix, px3, py3, tx3, ty3, col3, mult, fill, wash) \
*_i++ = m_vertices.count() + 3; \ }); \
Vertex* _v = m_vertices.expand(4); \
MAKE_VERTEX(_v, m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash); _v++; \
MAKE_VERTEX(_v, m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash); _v++; \
MAKE_VERTEX(_v, m_matrix, px2, py2, tx2, ty2, col2, mult, fill, wash); _v++; \
MAKE_VERTEX(_v, m_matrix, px3, py3, tx3, ty3, col3, mult, fill, wash); \
} }
#define PUSH_TRIANGLE(px0, py0, px1, py1, px2, py2, tx0, ty0, tx1, ty1, tx2, ty2, col0, col1, col2, mult, fill, wash) \ #define PUSH_TRIANGLE(px0, py0, px1, py1, px2, py2, tx0, ty0, tx1, ty1, tx2, ty2, col0, col1, col2, mult, fill, wash) \
{ \ { \
const int __v = (int)m_vertices.size(); \
m_batch.elements += 1; \ m_batch.elements += 1; \
int* _i = m_indices.expand(3); \ m_indices.insert(m_indices.end(), { __v + 0, __v + 1, __v + 2 }); \
*_i++ = m_vertices.count() + 0; \ m_vertices.insert(m_vertices.end(), { \
*_i++ = m_vertices.count() + 1; \ MAKE_VERTEX(m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash), \
*_i++ = m_vertices.count() + 2; \ MAKE_VERTEX(m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash), \
Vertex* _v = m_vertices.expand(3); \ MAKE_VERTEX(m_matrix, px2, py2, tx2, ty2, col2, mult, fill, wash) \
MAKE_VERTEX(_v, m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash); _v++; \ }); \
MAKE_VERTEX(_v, m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash); _v++; \
MAKE_VERTEX(_v, m_matrix, px2, py2, tx2, ty2, col2, mult, fill, wash); \
} }
// Compares a Batcher variable, and starts a new batch if it has changed // Compares a Batcher variable, and starts a new batch if it has changed
#define SET_BATCH_VAR(variable) \ #define SET_BATCH_VAR(variable) \
if (m_batch.elements > 0 && variable != m_batch.variable) \ if (m_batch.elements > 0 && variable != m_batch.variable) \
{ \ { \
m_batches.add(m_batch); \ m_batches.push_back(m_batch); \
m_batch.offset += m_batch.elements; \ m_batch.offset += m_batch.elements; \
m_batch.elements = 0; \ m_batch.elements = 0; \
} \ } \
@ -137,66 +128,71 @@ Batch::~Batch()
void Batch::push_matrix(const Mat3x2& matrix) void Batch::push_matrix(const Mat3x2& matrix)
{ {
m_matrix_stack.add(m_matrix); m_matrix_stack.push(m_matrix);
m_matrix = matrix * m_matrix; m_matrix = matrix * m_matrix;
} }
void Batch::pop_matrix() void Batch::pop_matrix()
{ {
m_matrix = m_matrix_stack.pop(); m_matrix = m_matrix_stack.top();
m_matrix_stack.pop();
} }
void Batch::push_scissor(const Rect& scissor) void Batch::push_scissor(const Rect& scissor)
{ {
m_scissor_stack.add(m_batch.scissor); m_scissor_stack.push(m_batch.scissor);
SET_BATCH_VAR(scissor); SET_BATCH_VAR(scissor);
} }
void Batch::pop_scissor() void Batch::pop_scissor()
{ {
Rect scissor = m_scissor_stack.pop(); Rect scissor = m_scissor_stack.top();
m_scissor_stack.pop();
SET_BATCH_VAR(scissor); SET_BATCH_VAR(scissor);
} }
void Batch::push_blend(const BlendMode& blend) void Batch::push_blend(const BlendMode& blend)
{ {
m_blend_stack.add(m_batch.blend); m_blend_stack.push(m_batch.blend);
SET_BATCH_VAR(blend); SET_BATCH_VAR(blend);
} }
void Batch::pop_blend() void Batch::pop_blend()
{ {
BlendMode blend = m_blend_stack.pop(); BlendMode blend = m_blend_stack.top();
m_blend_stack.pop();
SET_BATCH_VAR(blend); SET_BATCH_VAR(blend);
} }
void Batch::push_material(const MaterialRef& material) void Batch::push_material(const MaterialRef& material)
{ {
m_material_stack.add(m_batch.material); m_material_stack.push(m_batch.material);
SET_BATCH_VAR(material); SET_BATCH_VAR(material);
} }
void Batch::pop_material() void Batch::pop_material()
{ {
MaterialRef material = m_material_stack.pop(); MaterialRef material = m_material_stack.top();
m_material_stack.pop();
SET_BATCH_VAR(material); SET_BATCH_VAR(material);
} }
void Batch::push_layer(int layer) void Batch::push_layer(int layer)
{ {
m_layer_stack.add(m_batch.layer); m_layer_stack.push(m_batch.layer);
SET_BATCH_VAR(layer); SET_BATCH_VAR(layer);
} }
void Batch::pop_layer() void Batch::pop_layer()
{ {
int layer = m_layer_stack.pop(); int layer = m_layer_stack.top();
m_layer_stack.pop();
SET_BATCH_VAR(layer); SET_BATCH_VAR(layer);
} }
void Batch::push_color_mode(ColorMode mode) void Batch::push_color_mode(ColorMode mode)
{ {
m_color_mode_stack.add(m_color_mode); m_color_mode_stack.push(m_color_mode);
m_color_mode = mode; m_color_mode = mode;
m_tex_mult = (m_color_mode == ColorMode::Normal ? 255 : 0); m_tex_mult = (m_color_mode == ColorMode::Normal ? 255 : 0);
@ -205,7 +201,8 @@ void Batch::push_color_mode(ColorMode mode)
void Batch::pop_color_mode() void Batch::pop_color_mode()
{ {
m_color_mode = m_color_mode_stack.pop(); m_color_mode = m_color_mode_stack.top();
m_color_mode_stack.pop();
m_tex_mult = (m_color_mode == ColorMode::Normal ? 255 : 0); m_tex_mult = (m_color_mode == ColorMode::Normal ? 255 : 0);
m_tex_wash = (m_color_mode == ColorMode::Wash ? 255 : 0); m_tex_wash = (m_color_mode == ColorMode::Wash ? 255 : 0);
} }
@ -214,7 +211,7 @@ void Batch::set_texture(const TextureRef& texture)
{ {
if (m_batch.elements > 0 && texture != m_batch.texture && m_batch.texture && m_batch.texture->is_valid()) if (m_batch.elements > 0 && texture != m_batch.texture && m_batch.texture && m_batch.texture->is_valid())
{ {
m_batches.add(m_batch); m_batches.push_back(m_batch);
m_batch.offset += m_batch.elements; m_batch.offset += m_batch.elements;
m_batch.elements = 0; m_batch.elements = 0;
} }
@ -240,7 +237,7 @@ void Batch::render(const FrameBufferRef& target)
void Batch::render(const FrameBufferRef& target, const Mat4x4& matrix) void Batch::render(const FrameBufferRef& target, const Mat4x4& matrix)
{ {
// nothing to draw // nothing to draw
if ((m_batches.count() <= 0 && m_batch.elements <= 0) || m_indices.count() <= 0) if ((m_batches.size() <= 0 && m_batch.elements <= 0) || m_indices.size() <= 0)
return; return;
// define defaults // define defaults
@ -259,8 +256,8 @@ void Batch::render(const FrameBufferRef& target, const Mat4x4& matrix)
} }
// upload data // upload data
m_mesh->index_data(m_indices.begin(), m_indices.count()); m_mesh->index_data(m_indices.data(), m_indices.size());
m_mesh->vertex_data(m_vertices.begin(), m_vertices.count()); m_mesh->vertex_data(m_vertices.data(), m_vertices.size());
RenderCall call; RenderCall call;
call.target = target; call.target = target;
@ -315,28 +312,20 @@ void Batch::clear()
m_batch.scissor.w = m_batch.scissor.h = -1; m_batch.scissor.w = m_batch.scissor.h = -1;
m_batch.flip_vertically = false; m_batch.flip_vertically = false;
m_matrix_stack.clear(); m_matrix_stack = std::stack<Mat3x2>();
m_scissor_stack.clear(); m_scissor_stack = std::stack<Rect>();
m_blend_stack.clear(); m_blend_stack = std::stack<BlendMode>();
m_material_stack.clear(); m_material_stack = std::stack<MaterialRef>();
m_color_mode_stack.clear(); m_color_mode_stack = std::stack<ColorMode>();
m_layer_stack.clear(); m_layer_stack = std::stack<int>();
m_batches.clear(); m_batches.clear();
} }
void Batch::dispose() void Batch::dispose()
{ {
m_matrix_stack.dispose(); clear();
m_scissor_stack.dispose();
m_blend_stack.dispose();
m_material_stack.dispose();
m_color_mode_stack.dispose();
m_layer_stack.dispose();
m_batches.dispose();
m_default_material.reset(); m_default_material.reset();
m_mesh.reset(); m_mesh.reset();
m_vertices.dispose();
m_indices.dispose();
} }
void Batch::line(const Vec2& from, const Vec2& to, float t, Color color) void Batch::line(const Vec2& from, const Vec2& to, float t, Color color)

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <blah/graphics/graphics.h> #include <blah/graphics/graphics.h>
#include <blah/containers/list.h>
#include <blah/containers/str.h> #include <blah/containers/str.h>
#include <blah/math/vec2.h> #include <blah/math/vec2.h>
#include <blah/math/rect.h> #include <blah/math/rect.h>
@ -9,6 +8,8 @@
#include <blah/math/color.h> #include <blah/math/color.h>
#include <blah/drawing/subtexture.h> #include <blah/drawing/subtexture.h>
#include <blah/drawing/spritefont.h> #include <blah/drawing/spritefont.h>
#include <blah/containers/vector.h>
#include <stack>
namespace Blah namespace Blah
{ {
@ -145,24 +146,23 @@ namespace Blah
scissor(0, 0, -1, -1) {} scissor(0, 0, -1, -1) {}
}; };
static ShaderRef m_default_shader; static ShaderRef m_default_shader;
MaterialRef m_default_material; MaterialRef m_default_material;
MeshRef m_mesh; MeshRef m_mesh;
Mat3x2 m_matrix; Mat3x2 m_matrix;
ColorMode m_color_mode; ColorMode m_color_mode;
uint8_t m_tex_mult; uint8_t m_tex_mult;
uint8_t m_tex_wash; uint8_t m_tex_wash;
DrawBatch m_batch; DrawBatch m_batch;
List<Vertex> m_vertices; Vector<Vertex> m_vertices;
List<int> m_indices; Vector<int> m_indices;
std::stack<Mat3x2> m_matrix_stack;
List<Mat3x2> m_matrix_stack; std::stack<Rect> m_scissor_stack;
List<Rect> m_scissor_stack; std::stack<BlendMode> m_blend_stack;
List<BlendMode> m_blend_stack; std::stack<MaterialRef> m_material_stack;
List<MaterialRef> m_material_stack; std::stack<ColorMode> m_color_mode_stack;
List<ColorMode> m_color_mode_stack; std::stack<int> m_layer_stack;
List<int> m_layer_stack; Vector<DrawBatch> m_batches;
List<DrawBatch> m_batches;
void render_single_batch(RenderCall& call, const DrawBatch& b, const Mat4x4& matrix); void render_single_batch(RenderCall& call, const DrawBatch& b, const Mat4x4& matrix);
}; };

View File

@ -1,6 +1,7 @@
#include <blah/drawing/spritefont.h> #include <blah/drawing/spritefont.h>
#include <blah/images/font.h> #include <blah/images/font.h>
#include <blah/images/packer.h> #include <blah/images/packer.h>
#include <blah/log.h>
using namespace Blah; using namespace Blah;
@ -54,7 +55,7 @@ SpriteFont::~SpriteFont()
void SpriteFont::dispose() void SpriteFont::dispose()
{ {
m_atlas.dispose(); m_atlas.clear();
m_characters.clear(); m_characters.clear();
m_kerning.clear(); m_kerning.clear();
name.dispose(); name.dispose();
@ -133,7 +134,7 @@ void SpriteFont::build(const char* file, float sz, const uint32_t* charset)
dispose(); dispose();
Font font(file); Font font(file);
if (font.IsValid()) if (font.is_valid())
build(font, sz, charset); build(font, sz, charset);
} }
@ -141,12 +142,12 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset)
{ {
dispose(); dispose();
float scale = font.GetScale(size); float scale = font.get_scale(size);
name = font.FamilyName(); name = font.family_name();
ascent = font.Ascent() * scale; ascent = font.ascent() * scale;
descent = font.Descent() * scale; descent = font.descent() * scale;
line_gap = font.LineGap() * scale; line_gap = font.line_gap() * scale;
this->size = size; this->size = size;
Packer packer; Packer packer;
@ -156,7 +157,7 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset)
packer.power_of_two = true; packer.power_of_two = true;
std::unordered_map<uint32_t, int> glyphs; std::unordered_map<uint32_t, int> glyphs;
List<Color> buffer; Vector<Color> buffer;
auto ranges = charset; auto ranges = charset;
while (*ranges != 0) while (*ranges != 0)
@ -168,36 +169,36 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset)
for (auto i = from; i < to; i++) for (auto i = from; i < to; i++)
{ {
auto glyph = font.GetGlyph(i); auto glyph = font.get_glyph(i);
if (glyph <= 0) if (glyph <= 0)
continue; continue;
glyphs[i] = glyph; glyphs[i] = glyph;
// add character // add character
Font::Char ch = font.GetCharacter(glyph, scale); Font::Char ch = font.get_character(glyph, scale);
m_characters[i].advance = ch.advance; m_characters[i].advance = ch.advance;
m_characters[i].offset = Vec2(ch.offsetX, ch.offsetY); m_characters[i].offset = Vec2(ch.offset_x, ch.offset_y);
// pack glyph // pack glyph
if (ch.hasGlyph) if (ch.has_glyph)
{ {
if (buffer.count() < ch.width * ch.height) if (buffer.size() < ch.width * ch.height)
buffer.expand(ch.width * ch.height - buffer.count()); buffer.resize(ch.width * ch.height);
if (font.GetBitmap(ch, buffer.begin())) if (font.get_image(ch, buffer.data()))
packer.add(i, ch.width, ch.height, buffer.begin()); packer.add(i, ch.width, ch.height, buffer.data());
} }
} }
ranges += 2; ranges += 2;
} }
buffer.dispose(); buffer.clear();
packer.pack(); packer.pack();
for (auto& it : packer.pages) for (auto& it : packer.pages)
m_atlas.add(Graphics::create_texture(it)); m_atlas.push_back(Graphics::create_texture(it));
// add character subtextures // add character subtextures
for (auto& it : packer.entries) for (auto& it : packer.entries)
@ -208,7 +209,7 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset)
for (auto a = glyphs.begin(); a != glyphs.end(); a++) for (auto a = glyphs.begin(); a != glyphs.end(); a++)
for (auto b = glyphs.begin(); b != glyphs.end(); b++) for (auto b = glyphs.begin(); b != glyphs.end(); b++)
{ {
auto kern = font.GetKerning(a->second, b->second, scale); auto kern = font.get_kerning(a->second, b->second, scale);
if (kern != 0) if (kern != 0)
set_kerning(a->first, b->first, kern); set_kerning(a->first, b->first, kern);
} }

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <inttypes.h> #include <inttypes.h>
#include <blah/containers/list.h>
#include <blah/containers/str.h> #include <blah/containers/str.h>
#include <blah/containers/vector.h>
#include <blah/drawing/subtexture.h> #include <blah/drawing/subtexture.h>
#include <blah/math/vec2.h> #include <blah/math/vec2.h>
#include <unordered_map> #include <unordered_map>
@ -25,7 +25,7 @@ namespace Blah
std::unordered_map<uint64_t, float> m_kerning; std::unordered_map<uint64_t, float> m_kerning;
// built texture // built texture
List<TextureRef> m_atlas; Vector<TextureRef> m_atlas;
public: public:
static const uint32_t* ASCII; static const uint32_t* ASCII;
@ -56,7 +56,7 @@ namespace Blah
float height() const { return ascent - descent; } float height() const { return ascent - descent; }
float line_height() const { return ascent - descent + line_gap; } float line_height() const { return ascent - descent + line_gap; }
List<TextureRef>& textures() { return m_atlas; } const Vector<TextureRef>& textures() { return m_atlas; }
float width_of(const String& text) const; float width_of(const String& text) const;
float width_of_line(const String& text, int start = 0) const; float width_of_line(const String& text, int start = 0) const;

View File

@ -28,9 +28,9 @@ bool Directory::remove(const FilePath& path)
return Internal::Platform::dir_delete(path.cstr()); return Internal::Platform::dir_delete(path.cstr());
} }
List<FilePath> Directory::enumerate(const FilePath& path, bool recursive) Vector<FilePath> Directory::enumerate(const FilePath& path, bool recursive)
{ {
List<FilePath> list; Vector<FilePath> list;
// get files // get files
Internal::Platform::dir_enumerate(list, path.cstr(), recursive); Internal::Platform::dir_enumerate(list, path.cstr(), recursive);

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <blah/containers/list.h>
#include <blah/containers/str.h> #include <blah/containers/str.h>
#include <blah/containers/vector.h>
namespace Blah namespace Blah
{ {
@ -19,7 +19,7 @@ namespace Blah
bool create(const FilePath& path); bool create(const FilePath& path);
bool exists(const FilePath& path); bool exists(const FilePath& path);
bool remove(const FilePath& path); bool remove(const FilePath& path);
List<FilePath> enumerate(const FilePath& str, bool recursive = true); Vector<FilePath> enumerate(const FilePath& str, bool recursive = true);
void explore(const FilePath& path); void explore(const FilePath& path);
} }

View File

@ -1,12 +1,12 @@
#pragma once #pragma once
#include <blah/graphics/graphics.h> #include <blah/graphics/graphics.h>
#include <blah/graphics/texture.h> #include <blah/graphics/texture.h>
#include <blah/containers/stacklist.h> #include <blah/containers/stackvector.h>
#include <memory> #include <memory>
namespace Blah namespace Blah
{ {
typedef StackList<TextureRef, BLAH_ATTACHMENTS> Attachments; typedef StackVector<TextureRef, BLAH_ATTACHMENTS> Attachments;
class FrameBuffer class FrameBuffer
{ {

View File

@ -15,7 +15,7 @@
namespace Blah namespace Blah
{ {
class Stream; class Stream;
struct Image; class Image;
class Texture; class Texture;
typedef std::shared_ptr<Texture> TextureRef; typedef std::shared_ptr<Texture> TextureRef;
@ -34,10 +34,10 @@ namespace Blah
struct GraphicsInfo struct GraphicsInfo
{ {
GfxAPI api; GfxAPI api = GfxAPI::Any;
bool instancing; bool instancing = false;
bool origin_bottom_left; bool origin_bottom_left = false;
int max_texture_size; int max_texture_size = 0;
}; };
enum class TextureFilter enum class TextureFilter

View File

@ -1,12 +1,13 @@
#include <blah/graphics/material.h> #include <blah/graphics/material.h>
#include <blah/log.h>
using namespace Blah; using namespace Blah;
namespace namespace
{ {
size_t calc_uniform_size(const ShaderUniform& uniform) int calc_uniform_size(const ShaderUniform& uniform)
{ {
size_t components = 0; int components = 0;
switch (uniform.type) switch (uniform.type)
{ {
@ -39,7 +40,7 @@ Material::Material(const ShaderRef& shader)
} }
Uniforms uniforms = shader->uniforms(); Uniforms uniforms = shader->uniforms();
StackList<size_t, BLAH_UNIFORMS> float_offsets; StackVector<size_t, BLAH_UNIFORMS> float_offsets;
size_t float_size = 0; size_t float_size = 0;
for (auto& uniform : uniforms) for (auto& uniform : uniforms)
@ -50,11 +51,11 @@ Material::Material(const ShaderRef& shader)
if (uniform.type == UniformType::Texture) if (uniform.type == UniformType::Texture)
{ {
for (int i = 0; i < uniform.array_length; i ++) for (int i = 0; i < uniform.array_length; i ++)
m_textures.add(TextureRef()); m_textures.push_back(TextureRef());
continue; continue;
} }
float_offsets.add(float_size); float_offsets.push_back(float_size);
float_size += calc_uniform_size(uniform); float_size += calc_uniform_size(uniform);
} }
@ -62,7 +63,7 @@ Material::Material(const ShaderRef& shader)
memset(m_data, 0, sizeof(float) * float_size); memset(m_data, 0, sizeof(float) * float_size);
for (auto& it : float_offsets) for (auto& it : float_offsets)
m_floats.add(m_data + it); m_floats.push_back(m_data + it);
} }
Material::~Material() Material::~Material()
@ -80,7 +81,7 @@ void Material::set_texture(const char* name, const TextureRef& texture, int inde
BLAH_ASSERT(!m_disposed, "Material has been disposed"); BLAH_ASSERT(!m_disposed, "Material has been disposed");
BLAH_ASSERT(m_shader && m_shader->is_valid(), "Material Shader is invalid"); BLAH_ASSERT(m_shader && m_shader->is_valid(), "Material Shader is invalid");
if (m_textures.count() > 0) if (m_textures.size() > 0)
{ {
int offset = 0; int offset = 0;
for (auto& uniform : m_shader->uniforms()) for (auto& uniform : m_shader->uniforms())
@ -95,7 +96,7 @@ void Material::set_texture(const char* name, const TextureRef& texture, int inde
} }
offset += uniform.array_length; offset += uniform.array_length;
if (offset + index >= m_textures.count()) if (offset + index >= m_textures.size())
break; break;
} }
} }
@ -118,7 +119,7 @@ TextureRef Material::get_texture(const char* name, int index) const
return m_textures[offset + index]; return m_textures[offset + index];
offset += uniform.array_length; offset += uniform.array_length;
if (offset + index >= m_textures.count()) if (offset + index >= m_textures.size())
break; break;
} }
@ -141,7 +142,7 @@ TextureRef Material::get_texture(int slot, int index) const
return m_textures[offset + index]; return m_textures[offset + index];
offset += uniform.array_length; offset += uniform.array_length;
if (offset + index >= m_textures.count()) if (offset + index >= m_textures.size())
break; break;
} }

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <blah/graphics/texture.h> #include <blah/graphics/texture.h>
#include <blah/graphics/shader.h> #include <blah/graphics/shader.h>
#include <blah/containers/list.h> #include <blah/containers/vector.h>
#include <memory> #include <memory>
namespace Blah namespace Blah
@ -56,8 +56,8 @@ namespace Blah
private: private:
ShaderRef m_shader; ShaderRef m_shader;
List<TextureRef> m_textures; Vector<TextureRef> m_textures;
List<float*> m_floats; Vector<float*> m_floats;
float* m_data; float* m_data;
bool m_disposed; bool m_disposed;
}; };

View File

@ -1,12 +1,12 @@
#pragma once #pragma once
#include <blah/graphics/graphics.h> #include <blah/graphics/graphics.h>
#include <blah/containers/stacklist.h> #include <blah/containers/stackvector.h>
#include <memory> #include <memory>
namespace Blah namespace Blah
{ {
typedef StackList<ShaderUniform, BLAH_UNIFORMS> Uniforms; typedef StackVector<ShaderUniform, BLAH_UNIFORMS> Uniforms;
typedef StackList<ShaderAttribute, BLAH_ATTRIBUTES> Attributes; typedef StackVector<ShaderAttribute, BLAH_ATTRIBUTES> Attributes;
class Shader class Shader
{ {

View File

@ -1,5 +1,6 @@
#include <blah/images/aseprite.h> #include <blah/images/aseprite.h>
#include <blah/streams/filestream.h> #include <blah/streams/filestream.h>
#include <blah/log.h>
#define STBI_NO_STDIO #define STBI_NO_STDIO
#define STBI_NO_JPEG #define STBI_NO_JPEG
@ -99,7 +100,7 @@ void Aseprite::Parse(Stream& stream)
return; return;
} }
int frameCount = 0; int frame_count = 0;
// header // header
{ {
@ -115,7 +116,7 @@ void Aseprite::Parse(Stream& stream)
} }
// main info // main info
frameCount = stream.read<uint16_t>(Endian::Little); frame_count = stream.read<uint16_t>(Endian::Little);
width = stream.read<uint16_t>(Endian::Little); width = stream.read<uint16_t>(Endian::Little);
height = stream.read<uint16_t>(Endian::Little); height = stream.read<uint16_t>(Endian::Little);
mode = static_cast<Aseprite::Modes>(stream.read<uint16_t>(Endian::Little) / 8); mode = static_cast<Aseprite::Modes>(stream.read<uint16_t>(Endian::Little) / 8);
@ -126,17 +127,17 @@ void Aseprite::Parse(Stream& stream)
stream.read<uint32_t>(Endian::Little); // Should be 0 stream.read<uint32_t>(Endian::Little); // Should be 0
stream.read<uint32_t>(Endian::Little); // Should be 0 stream.read<uint32_t>(Endian::Little); // Should be 0
stream.read<uint8_t>(Endian::Little); // Palette entry stream.read<uint8_t>(Endian::Little); // Palette entry
stream.seek(stream.position() + 3); // Ignore these bytes stream.seek(stream.position() + 3); // Ignore these bytes
stream.read<uint16_t>(Endian::Little); // Number of colors (0 means 256 for old sprites) stream.read<uint16_t>(Endian::Little); // Number of colors (0 means 256 for old sprites)
stream.read<int8_t>(Endian::Little); // Pixel width stream.read<int8_t>(Endian::Little); // Pixel width
stream.read<int8_t>(Endian::Little); // Pixel height stream.read<int8_t>(Endian::Little); // Pixel height
stream.seek(stream.position() + 92); // For Future stream.seek(stream.position() + 92); // For Future
} }
frames.expand(frameCount); frames.resize(frame_count);
// frames // frames
for (int i = 0; i < frameCount; i++) for (int i = 0; i < frame_count; i++)
{ {
auto frameStart = stream.position(); auto frameStart = stream.position();
auto frameEnd = frameStart + stream.read<uint32_t>(Endian::Little); auto frameEnd = frameStart + stream.read<uint32_t>(Endian::Little);
@ -192,35 +193,38 @@ void Aseprite::Parse(Stream& stream)
void Aseprite::ParseLayer(Stream& stream, int frame) void Aseprite::ParseLayer(Stream& stream, int frame)
{ {
auto layer = layers.expand(1); layers.emplace_back();
layer->flag = static_cast<LayerFlags>(stream.read<uint16_t>(Endian::Little));
layer->visible = ((int)layer->flag & (int)LayerFlags::Visible) == (int)LayerFlags::Visible; auto& layer = layers.back();
layer->type = static_cast<LayerTypes>(stream.read<uint16_t>(Endian::Little)); layer.flag = static_cast<LayerFlags>(stream.read<uint16_t>(Endian::Little));
layer->child_level = stream.read<uint16_t>(Endian::Little); layer.visible = ((int)layer.flag & (int)LayerFlags::Visible) == (int)LayerFlags::Visible;
layer.type = static_cast<LayerTypes>(stream.read<uint16_t>(Endian::Little));
layer.child_level = stream.read<uint16_t>(Endian::Little);
stream.read<uint16_t>(Endian::Little); // width stream.read<uint16_t>(Endian::Little); // width
stream.read<uint16_t>(Endian::Little); // height stream.read<uint16_t>(Endian::Little); // height
layer->blendmode = stream.read<uint16_t>(Endian::Little); layer.blendmode = stream.read<uint16_t>(Endian::Little);
layer->alpha = stream.read<uint8_t>(Endian::Little); layer.alpha = stream.read<uint8_t>(Endian::Little);
stream.seek(stream.position() + 3); // for future stream.seek(stream.position() + 3); // for future
layer->name.set_length(stream.read<uint16_t>(Endian::Little)); layer.name.set_length(stream.read<uint16_t>(Endian::Little));
stream.read(layer->name.cstr(), layer->name.length()); stream.read(layer.name.cstr(), layer.name.length());
layer->userdata.color = 0xffffff; layer.userdata.color = 0xffffff;
layer->userdata.text = ""; layer.userdata.text = "";
last_userdata = &(layer->userdata); last_userdata = &(layer.userdata);
} }
void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition) void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition)
{ {
Frame& frame = frames[frameIndex]; Frame& frame = frames[frameIndex];
auto cel = frame.cels.expand(1); frame.cels.emplace_back();
cel->layer_index = stream.read<uint16_t>(Endian::Little); auto& cel = frame.cels.back();
cel->x = stream.read<uint16_t>(Endian::Little); cel.layer_index = stream.read<uint16_t>(Endian::Little);
cel->y = stream.read<uint16_t>(Endian::Little); cel.x = stream.read<uint16_t>(Endian::Little);
cel->alpha = stream.read<uint8_t>(Endian::Little); cel.y = stream.read<uint16_t>(Endian::Little);
cel->linked_frame_index = -1; cel.alpha = stream.read<uint8_t>(Endian::Little);
cel.linked_frame_index = -1;
auto celType = stream.read<uint16_t>(Endian::Little); auto celType = stream.read<uint16_t>(Endian::Little);
stream.seek(stream.position() + 7); stream.seek(stream.position() + 7);
@ -232,12 +236,12 @@ void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition)
auto height = stream.read<uint16_t>(Endian::Little); auto height = stream.read<uint16_t>(Endian::Little);
auto count = width * height * (int)mode; auto count = width * height * (int)mode;
cel->image = Image(width, height); cel.image = Image(width, height);
// RAW // RAW
if (celType == 0) if (celType == 0)
{ {
stream.read(cel->image.pixels, count); stream.read(cel.image.pixels, count);
} }
// DEFLATE (zlib) // DEFLATE (zlib)
else else
@ -252,7 +256,7 @@ void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition)
stream.read(buffer, size); stream.read(buffer, size);
int olen = width * height * sizeof(Color); int olen = width * height * sizeof(Color);
int res = stbi_zlib_decode_buffer((char*)cel->image.pixels, olen, buffer, (int)size); int res = stbi_zlib_decode_buffer((char*)cel.image.pixels, olen, buffer, (int)size);
delete[] buffer; delete[] buffer;
@ -267,15 +271,15 @@ void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition)
// note: we work in-place to save having to store stuff in a buffer // note: we work in-place to save having to store stuff in a buffer
if (mode == Modes::Grayscale) if (mode == Modes::Grayscale)
{ {
auto src = (unsigned char*)cel->image.pixels; auto src = (unsigned char*)cel.image.pixels;
auto dst = cel->image.pixels; auto dst = cel.image.pixels;
for (int d = width * height - 1, s = (width * height - 1) * 2; d >= 0; d--, s -= 2) for (int d = width * height - 1, s = (width * height - 1) * 2; d >= 0; d--, s -= 2)
dst[d] = Color(src[s], src[s], src[s], src[s + 1]); dst[d] = Color(src[s], src[s], src[s], src[s + 1]);
} }
else if (mode == Modes::Indexed) else if (mode == Modes::Indexed)
{ {
auto src = (unsigned char*)cel->image.pixels; auto src = (unsigned char*)cel.image.pixels;
auto dst = cel->image.pixels; auto dst = cel.image.pixels;
for (int i = width * height - 1; i >= 0; i--) for (int i = width * height - 1; i >= 0; i--)
dst[i] = palette[src[i]]; dst[i] = palette[src[i]];
} }
@ -285,18 +289,18 @@ void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition)
// this cel directly references a previous cel // this cel directly references a previous cel
else if (celType == 1) else if (celType == 1)
{ {
cel->linked_frame_index = stream.read<uint16_t>(Endian::Little); cel.linked_frame_index = stream.read<uint16_t>(Endian::Little);
} }
// draw to frame if visible // draw to frame if visible
if ((int)layers[cel->layer_index].flag & (int)LayerFlags::Visible) if ((int)layers[cel.layer_index].flag & (int)LayerFlags::Visible)
{ {
RenderCel(cel, &frame); RenderCel(&cel, &frame);
} }
cel->userdata.color = 0xffffff; cel.userdata.color = 0xffffff;
cel->userdata.text = ""; cel.userdata.text = "";
last_userdata = &(cel->userdata); last_userdata = &(cel.userdata);
} }
void Aseprite::ParsePalette(Stream& stream, int frame) void Aseprite::ParsePalette(Stream& stream, int frame)
@ -306,7 +310,7 @@ void Aseprite::ParsePalette(Stream& stream, int frame)
auto end = stream.read<uint32_t>(Endian::Little); auto end = stream.read<uint32_t>(Endian::Little);
stream.seek(stream.position() + 8); stream.seek(stream.position() + 8);
palette.expand(palette.count() + (end - start + 1)); palette.resize(palette.size() + (end - start + 1));
for (int p = 0, len = static_cast<int>(end - start) + 1; p < len; p++) for (int p = 0, len = static_cast<int>(end - start) + 1; p < len; p++)
{ {
@ -348,17 +352,19 @@ void Aseprite::ParseTag(Stream& stream, int frame)
for (int t = 0; t < count; t++) for (int t = 0; t < count; t++)
{ {
auto tag = tags.expand(1); Tag tag;
tag->from = stream.read<uint16_t>(Endian::Little); tag.from = stream.read<uint16_t>(Endian::Little);
tag->to = stream.read<uint16_t>(Endian::Little); tag.to = stream.read<uint16_t>(Endian::Little);
tag->loops = static_cast<LoopDirections>(stream.read<int8_t>(Endian::Little)); tag.loops = static_cast<LoopDirections>(stream.read<int8_t>(Endian::Little));
stream.seek(stream.position() + 8); stream.seek(stream.position() + 8);
tag->color = Color(stream.read<int8_t>(), stream.read<int8_t>(), stream.read<int8_t>(Endian::Little), 255); tag.color = Color(stream.read<int8_t>(), stream.read<int8_t>(), stream.read<int8_t>(Endian::Little), 255);
stream.seek(stream.position() + 1); stream.seek(stream.position() + 1);
tag->name.set_length(stream.read<uint16_t>(Endian::Little)); tag.name.set_length(stream.read<uint16_t>(Endian::Little));
stream.read(tag->name.cstr(), tag->name.length()); stream.read(tag.name.cstr(), tag.name.length());
tags.push_back(tag);
} }
} }
@ -374,13 +380,15 @@ void Aseprite::ParseSlice(Stream& stream, int frame)
for (int s = 0; s < count; s++) for (int s = 0; s < count; s++)
{ {
auto slice = slices.expand(1); slices.emplace_back();
slice->name = name;
slice->frame = stream.read<uint32_t>(Endian::Little); auto& slice = slices.back();
slice->origin.x = stream.read<int32_t>(Endian::Little); slice.name = name;
slice->origin.y = stream.read<int32_t>(Endian::Little); slice.frame = stream.read<uint32_t>(Endian::Little);
slice->width = stream.read<uint32_t>(Endian::Little); slice.origin.x = stream.read<int32_t>(Endian::Little);
slice->height = stream.read<uint32_t>(Endian::Little); slice.origin.y = stream.read<int32_t>(Endian::Little);
slice.width = stream.read<uint32_t>(Endian::Little);
slice.height = stream.read<uint32_t>(Endian::Little);
// 9 slice (ignored atm) // 9 slice (ignored atm)
if (flags & (1 << 0)) if (flags & (1 << 0))
@ -392,17 +400,17 @@ void Aseprite::ParseSlice(Stream& stream, int frame)
} }
// pivot point // pivot point
slice->has_pivot = false; slice.has_pivot = false;
if (flags & (1 << 1)) if (flags & (1 << 1))
{ {
slice->has_pivot = true; slice.has_pivot = true;
slice->pivot.x = stream.read<uint32_t>(Endian::Little); slice.pivot.x = stream.read<uint32_t>(Endian::Little);
slice->pivot.y = stream.read<uint32_t>(Endian::Little); slice.pivot.y = stream.read<uint32_t>(Endian::Little);
} }
slice->userdata.color = 0xffffff; slice.userdata.color = 0xffffff;
slice->userdata.text = ""; slice.userdata.text = "";
last_userdata = &(slice->userdata); last_userdata = &(slice.userdata);
} }
} }

View File

@ -2,7 +2,6 @@
#include <blah/math/color.h> #include <blah/math/color.h>
#include <blah/images/image.h> #include <blah/images/image.h>
#include <blah/containers/str.h> #include <blah/containers/str.h>
#include <blah/containers/list.h>
#include <blah/streams/stream.h> #include <blah/streams/stream.h>
namespace Blah namespace Blah
@ -80,7 +79,7 @@ namespace Blah
{ {
int duration = 0; int duration = 0;
Image image; Image image;
List<Cel> cels; Vector<Cel> cels;
}; };
struct Layer struct Layer
@ -121,11 +120,11 @@ namespace Blah
int width = 0; int width = 0;
int height = 0; int height = 0;
List<Layer> layers; Vector<Layer> layers;
List<Frame> frames; Vector<Frame> frames;
List<Tag> tags; Vector<Tag> tags;
List<Slice> slices; Vector<Slice> slices;
List<Color> palette; Vector<Color> palette;
Aseprite(); Aseprite();
Aseprite(const char* path); Aseprite(const char* path);

View File

@ -31,60 +31,60 @@ String GetName(stbtt_fontinfo* font, int nameId)
Font::Font() Font::Font()
{ {
font = nullptr; m_font = nullptr;
data = nullptr; m_data = nullptr;
ascent = 0; m_ascent = 0;
descent = 0; m_descent = 0;
lineGap = 0; m_line_gap = 0;
valid = false; m_valid = false;
} }
Font::Font(Stream& stream) : Font() Font::Font(Stream& stream) : Font()
{ {
Load(stream); load(stream);
} }
Font::Font(const char* path) : Font() Font::Font(const char* path) : Font()
{ {
FileStream fs(path, FileMode::Read); FileStream fs(path, FileMode::Read);
if (fs.is_readable()) if (fs.is_readable())
Load(fs); load(fs);
} }
Font::Font(Font&& src) noexcept Font::Font(Font&& src) noexcept
{ {
font = src.font; m_font = src.m_font;
data = src.data; m_data = src.m_data;
familyName = src.familyName; m_family_name = src.m_family_name;
styleName = src.styleName; m_style_name = src.m_style_name;
ascent = src.ascent; m_ascent = src.m_ascent;
descent = src.descent; m_descent = src.m_descent;
lineGap = src.lineGap; m_line_gap = src.m_line_gap;
valid = src.valid; m_valid = src.m_valid;
src.familyName.clear(); src.m_family_name.clear();
src.styleName.clear(); src.m_style_name.clear();
src.valid = false; src.m_valid = false;
src.font = nullptr; src.m_font = nullptr;
src.data = nullptr; src.m_data = nullptr;
} }
Font& Font::operator=(Font&& src) noexcept Font& Font::operator=(Font&& src) noexcept
{ {
font = src.font; m_font = src.m_font;
data = src.data; m_data = src.m_data;
familyName = src.familyName; m_family_name = src.m_family_name;
styleName = src.styleName; m_style_name = src.m_style_name;
ascent = src.ascent; m_ascent = src.m_ascent;
descent = src.descent; m_descent = src.m_descent;
lineGap = src.lineGap; m_line_gap = src.m_line_gap;
valid = src.valid; m_valid = src.m_valid;
src.familyName.clear(); src.m_family_name.clear();
src.styleName.clear(); src.m_style_name.clear();
src.valid = false; src.m_valid = false;
src.font = nullptr; src.m_font = nullptr;
src.data = nullptr; src.m_data = nullptr;
return *this; return *this;
} }
@ -93,7 +93,7 @@ Font::~Font()
dispose(); dispose();
} }
void Font::Load(Stream& stream) void Font::load(Stream& stream)
{ {
dispose(); dispose();
@ -105,98 +105,99 @@ void Font::Load(Stream& stream)
// create data buffer // create data buffer
auto size = stream.length(); auto size = stream.length();
data = new unsigned char[size]; m_data = new unsigned char[size];
stream.read(data, size); stream.read(m_data, size);
// init font // init font
font = new stbtt_fontinfo(); m_font = new stbtt_fontinfo();
auto fn = (stbtt_fontinfo*)font; auto fn = (stbtt_fontinfo*)m_font;
stbtt_InitFont(fn, data, 0); stbtt_InitFont(fn, m_data, 0);
familyName = GetName(fn, 1); m_family_name = GetName(fn, 1);
styleName = GetName(fn, 2); m_style_name = GetName(fn, 2);
// properties // properties
stbtt_GetFontVMetrics(fn, &ascent, &descent, &lineGap); stbtt_GetFontVMetrics(fn, &m_ascent, &m_descent, &m_line_gap);
valid = true; m_valid = true;
} }
void Font::dispose() void Font::dispose()
{ {
delete (stbtt_fontinfo*)font; delete (stbtt_fontinfo*)m_font;
delete[] data; delete[] m_data;
font = nullptr; m_font = nullptr;
data = nullptr; m_data = nullptr;
familyName.dispose(); m_family_name.dispose();
styleName.dispose(); m_style_name.dispose();
} }
const char* Font::FamilyName() const const char* Font::family_name() const
{ {
return familyName.cstr(); return m_family_name.cstr();
} }
const char* Font::StyleName() const const char* Font::style_name() const
{ {
return styleName.cstr(); return m_style_name.cstr();
} }
int Font::Ascent() const int Font::ascent() const
{ {
return ascent; return m_ascent;
} }
int Font::Descent() const int Font::descent() const
{ {
return descent; return m_descent;
} }
int Font::LineGap() const int Font::line_gap() const
{ {
return lineGap; return m_line_gap;
} }
int Font::Height() const int Font::height() const
{ {
return ascent - descent; return m_ascent - m_descent;
} }
int Font::LineHeight() const int Font::line_height() const
{ {
return ascent - descent + lineGap; return m_ascent - m_descent + m_line_gap;
} }
int Font::GetGlyph(Codepoint codepoint) const int Font::get_glyph(Codepoint codepoint) const
{ {
if (font == nullptr) if (!m_font)
return 0; return 0;
return stbtt_FindGlyphIndex((stbtt_fontinfo*)font, codepoint); return stbtt_FindGlyphIndex((stbtt_fontinfo*)m_font, codepoint);
} }
float Font::GetScale(float size) const float Font::get_scale(float size) const
{ {
if (font == nullptr) if (!m_font)
return 0; return 0;
return stbtt_ScaleForPixelHeight((stbtt_fontinfo*)font, size);
return stbtt_ScaleForMappingEmToPixels((stbtt_fontinfo*)m_font, size);
} }
float Font::GetKerning(int glyph1, int glyph2, float scale) const float Font::get_kerning(int glyph1, int glyph2, float scale) const
{ {
if (font == nullptr) if (!m_font)
return 0; return 0;
return stbtt_GetGlyphKernAdvance((stbtt_fontinfo*)font, glyph1, glyph2) * scale; return stbtt_GetGlyphKernAdvance((stbtt_fontinfo*)m_font, glyph1, glyph2) * scale;
} }
Font::Char Font::GetCharacter(int glyph, float scale) const Font::Char Font::get_character(int glyph, float scale) const
{ {
Char ch; Char ch;
if (font == nullptr) if (!m_font)
return ch; return ch;
int advance, offsetX, x0, y0, x1, y1; int advance, offsetX, x0, y0, x1, y1;
stbtt_GetGlyphHMetrics((stbtt_fontinfo*)font, glyph, &advance, &offsetX); stbtt_GetGlyphHMetrics((stbtt_fontinfo*)m_font, glyph, &advance, &offsetX);
stbtt_GetGlyphBitmapBox((stbtt_fontinfo*)font, glyph, scale, scale, &x0, &y0, &x1, &y1); stbtt_GetGlyphBitmapBox((stbtt_fontinfo*)m_font, glyph, scale, scale, &x0, &y0, &x1, &y1);
int w = (x1 - x0); int w = (x1 - x0);
int h = (y1 - y0); int h = (y1 - y0);
@ -206,22 +207,22 @@ Font::Char Font::GetCharacter(int glyph, float scale) const
ch.width = w; ch.width = w;
ch.height = h; ch.height = h;
ch.advance = advance * scale; ch.advance = advance * scale;
ch.offsetX = offsetX * scale; ch.offset_x = offsetX * scale;
ch.offsetY = (float)y0; ch.offset_y = (float)y0;
ch.scale = scale; ch.scale = scale;
ch.hasGlyph = (w > 0 && h > 0 && stbtt_IsGlyphEmpty((stbtt_fontinfo*)font, glyph) == 0); ch.has_glyph = (w > 0 && h > 0 && stbtt_IsGlyphEmpty((stbtt_fontinfo*)m_font, glyph) == 0);
return ch; return ch;
} }
bool Font::GetBitmap(const Font::Char& ch, Color* pixels) const bool Font::get_image(const Font::Char& ch, Color* pixels) const
{ {
if (ch.hasGlyph) if (ch.has_glyph)
{ {
// we actually use the image buffer as our temporary buffer, and fill the pixels out backwards after // we actually use the image buffer as our temporary buffer, and fill the pixels out backwards after
// kinda weird but it works & saves creating more memory // kinda weird but it works & saves creating more memory
unsigned char* src = (unsigned char*)pixels; unsigned char* src = (unsigned char*)pixels;
stbtt_MakeGlyphBitmap((stbtt_fontinfo*)font, src, ch.width, ch.height, ch.width, ch.scale, ch.scale, ch.glyph); stbtt_MakeGlyphBitmap((stbtt_fontinfo*)m_font, src, ch.width, ch.height, ch.width, ch.scale, ch.scale, ch.glyph);
int len = ch.width * ch.height; int len = ch.width * ch.height;
for (int a = (len - 1) * 4, b = (len - 1); b >= 0; a -= 4, b -= 1) for (int a = (len - 1) * 4, b = (len - 1); b >= 0; a -= 4, b -= 1)
@ -238,7 +239,7 @@ bool Font::GetBitmap(const Font::Char& ch, Color* pixels) const
return false; return false;
} }
bool Font::IsValid() const bool Font::is_valid() const
{ {
return valid; return m_valid;
} }

View File

@ -16,10 +16,10 @@ namespace Blah
int width = 0; int width = 0;
int height = 0; int height = 0;
float advance = 0; float advance = 0;
float offsetX = 0; float offset_x = 0;
float offsetY = 0; float offset_y = 0;
float scale = 0; float scale = 0;
bool hasGlyph = false; bool has_glyph = false;
}; };
Font(); Font();
@ -33,30 +33,30 @@ namespace Blah
void dispose(); void dispose();
const char* FamilyName() const; const char* family_name() const;
const char* StyleName() const; const char* style_name() const;
int Ascent() const; int ascent() const;
int Descent() const; int descent() const;
int LineGap() const; int line_gap() const;
int Height() const; int height() const;
int LineHeight() const; int line_height() const;
int GetGlyph(Codepoint codepoint) const; int get_glyph(Codepoint codepoint) const;
float GetScale(float size) const; float get_scale(float size) const;
float GetKerning(int glyph1, int glyph2, float scale) const; float get_kerning(int glyph1, int glyph2, float scale) const;
Char GetCharacter(int glyph, float scale) const; Char get_character(int glyph, float scale) const;
bool GetBitmap(const Char& ch, Color* pixels) const; bool get_image(const Char& ch, Color* pixels) const;
bool IsValid() const; bool is_valid() const;
private: private:
void Load(Stream& stream); void load(Stream& stream);
void* font; void* m_font;
unsigned char* data; unsigned char* m_data;
String familyName; String m_family_name;
String styleName; String m_style_name;
int ascent; int m_ascent;
int descent; int m_descent;
int lineGap; int m_line_gap;
bool valid; bool m_valid;
}; };
} }

View File

@ -1,4 +1,5 @@
#include <blah/images/packer.h> #include <blah/images/packer.h>
#include <blah/log.h>
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
@ -59,12 +60,7 @@ void Packer::add_entry(uint64_t id, int w, int h, const Color* pixels)
{ {
dirty = true; dirty = true;
Entry* entry = entries.expand(1); Entry entry(id, RectI(0, 0, w, h));
entry->id = id;
entry->page = 0;
entry->empty = true;
entry->frame = RectI(0, 0, w, h);
entry->packed = RectI(0, 0, 0, 0);
// trim // trim
int top = 0, left = 0, right = w, bottom = h; int top = 0, left = 0, right = w, bottom = h;
@ -106,28 +102,30 @@ void Packer::add_entry(uint64_t id, int w, int h, const Color* pixels)
// pixels actually exist in this source // pixels actually exist in this source
if (right >= left && bottom >= top) if (right >= left && bottom >= top)
{ {
entry->empty = false; entry.empty = false;
// store size // store size
entry->frame.x = -left; entry.frame.x = -left;
entry->frame.y = -top; entry.frame.y = -top;
entry->packed.w = (right - left); entry.packed.w = (right - left);
entry->packed.h = (bottom - top); entry.packed.h = (bottom - top);
// create pixel data // create pixel data
entry->memoryIndex = buffer.position(); entry.memory_index = buffer.position();
// copy pixels over // copy pixels over
if (entry->packed.w == w && entry->packed.h == h) if (entry.packed.w == w && entry.packed.h == h)
{ {
buffer.write((char*)pixels, sizeof(Color) * w * h); buffer.write((char*)pixels, sizeof(Color) * w * h);
} }
else else
{ {
for (int i = 0; i < entry->packed.h; i++) for (int i = 0; i < entry.packed.h; i++)
buffer.write((char*)(pixels + left + (top + i) * entry->frame.w), sizeof(Color) * entry->packed.w); buffer.write((char*)(pixels + left + (top + i) * entry.frame.w), sizeof(Color) * entry.packed.w);
} }
} }
entries.push_back(entry);
} }
void Packer::pack() void Packer::pack()
@ -139,16 +137,16 @@ void Packer::pack()
pages.clear(); pages.clear();
// only if we have stuff to pack // only if we have stuff to pack
auto count = entries.count(); auto count = entries.size();
if (count > 0) if (count > 0)
{ {
// get all the sources sorted largest -> smallest // get all the sources sorted largest -> smallest
List<Entry*> sources; Vector<Entry*> sources;
{ {
sources.expand(count); sources.resize(count);
int index = 0; int index = 0;
for (int i = 0; i < entries.count(); i++) for (int i = 0; i < entries.size(); i++)
sources[index++] = &entries[i]; sources[index++] = &entries[i];
std::sort(sources.begin(), sources.end(), [](Packer::Entry* a, Packer::Entry* b) std::sort(sources.begin(), sources.end(), [](Packer::Entry* a, Packer::Entry* b)
@ -166,8 +164,8 @@ void Packer::pack()
// we should never need more nodes than source images * 3 // we should never need more nodes than source images * 3
// if this causes problems we could change it to use push_back I suppose // if this causes problems we could change it to use push_back I suppose
List<Node> nodes; Vector<Node> nodes;
nodes.expand(count * 4); nodes.resize(count * 4);
int packed = 0, page = 0; int packed = 0, page = 0;
while (packed < count) while (packed < count)
@ -259,7 +257,7 @@ void Packer::pack()
// create each page // create each page
{ {
pages.add(Image(pageWidth, pageHeight)); pages.emplace_back(pageWidth, pageHeight);
// copy image data to image // copy image data to image
for (int i = from; i < packed; i++) for (int i = from; i < packed; i++)
@ -268,7 +266,7 @@ void Packer::pack()
if (!sources[i]->empty) if (!sources[i]->empty)
{ {
RectI dst = sources[i]->packed; RectI dst = sources[i]->packed;
Color* src = (Color*)(buffer.data() + sources[i]->memoryIndex); Color* src = (Color*)(buffer.data() + sources[i]->memory_index);
// TODO: // TODO:
// Optimize this? // Optimize this?
@ -300,8 +298,8 @@ void Packer::clear()
void Packer::dispose() void Packer::dispose()
{ {
pages.dispose(); pages.clear();
entries.dispose(); entries.clear();
buffer.close(); buffer.close();
max_size = 0; max_size = 0;
power_of_two = 0; power_of_two = 0;

View File

@ -3,8 +3,8 @@
#include <blah/math/color.h> #include <blah/math/color.h>
#include <blah/math/rectI.h> #include <blah/math/rectI.h>
#include <blah/math/point.h> #include <blah/math/point.h>
#include <blah/containers/list.h>
#include <blah/containers/str.h> #include <blah/containers/str.h>
#include <blah/containers/vector.h>
#include <blah/streams/bufferstream.h> #include <blah/streams/bufferstream.h>
namespace Blah namespace Blah
@ -17,13 +17,16 @@ namespace Blah
{ {
friend class Packer; friend class Packer;
private: private:
int64_t memoryIndex = 0; int64_t memory_index;
public: public:
int page = 0;
uint64_t id; uint64_t id;
bool empty = true; int page;
RectI packed; bool empty;
RectI frame; 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; int max_size;
@ -31,8 +34,8 @@ namespace Blah
int spacing; int spacing;
int padding; int padding;
List<Image> pages; Vector<Image> pages;
List<Entry> entries; Vector<Entry> entries;
Packer(); Packer();
Packer(int max_size, int spacing, bool power_of_two); Packer(int max_size, int spacing, bool power_of_two);

View File

@ -36,11 +36,11 @@ namespace Blah
float abs(float x); float abs(float x);
template<class T> template<class T, class U>
T min(T a, T b) { return a < b ? a : b; } T min(T a, U b) { return a < b ? a : b; }
template<class T> template<class T, class U>
T max(T a, T b) { return a > b ? a : b; } T max(T a, U b) { return a > b ? a : b; }
float floor(float x); float floor(float x);

View File

@ -1,5 +1,6 @@
#include <blah/streams/filestream.h> #include <blah/streams/filestream.h>
#include <blah/internal/platform.h> #include <blah/internal/platform.h>
#include <blah/log.h>
#include <string.h> #include <string.h>
using namespace Blah; using namespace Blah;

View File

@ -23,9 +23,9 @@ void Time::pause_for(float time)
pause_timer = time; pause_timer = time;
} }
bool Time::on_interval(float interval, float offset) bool Time::on_interval(float time, float delta, float interval, float offset)
{ {
return Time::on_interval(Time::elapsed, Time::delta, interval, offset); return floor((time - offset - delta) / interval) < floor((time - offset) / interval);
} }
bool Time::on_interval(float delta, float interval, float offset) bool Time::on_interval(float delta, float interval, float offset)
@ -33,9 +33,9 @@ bool Time::on_interval(float delta, float interval, float offset)
return Time::on_interval(Time::elapsed, delta, interval, offset); return Time::on_interval(Time::elapsed, delta, interval, offset);
} }
bool Time::on_interval(float time, float delta, float interval, float offset) bool Time::on_interval(float interval, float offset)
{ {
return floor((time - offset - delta) / interval) < floor((time - offset) / interval); return Time::on_interval(Time::elapsed, Time::delta, interval, offset);
} }
bool Time::on_time(float time, float timestamp) bool Time::on_time(float time, float timestamp)
@ -43,12 +43,12 @@ bool Time::on_time(float time, float timestamp)
return time >= timestamp && time - Time::delta < timestamp; return time >= timestamp && time - Time::delta < timestamp;
} }
bool Time::between_interval(float interval, float offset)
{
return between_interval(Time::elapsed, interval, offset);
}
bool Time::between_interval(float time, float interval, float offset) bool Time::between_interval(float time, float interval, float offset)
{ {
return modf(time - offset, interval * 2) >= interval; return modf(time - offset, interval * 2) >= interval;
} }
bool Time::between_interval(float interval, float offset)
{
return between_interval(Time::elapsed, interval, offset);
}

View File

@ -24,21 +24,21 @@ namespace Blah
static void pause_for(float time); static void pause_for(float time);
// returns true on the given time interval // returns true on the given time interval
static bool on_interval(float interval, float offset = 0); static bool on_interval(float time, float delta, float interval, float offset);
// returns true on the given time interval // returns true on the given time interval
static bool on_interval(float delta, float interval, float offset); static bool on_interval(float delta, float interval, float offset);
// returns true on the given time interval // returns true on the given time interval
static bool on_interval(float time, float delta, float interval, float offset); static bool on_interval(float interval, float offset = 0);
// returns true when the given timestamp is passed // returns true when the given timestamp is passed
static bool on_time(float time, float timestamp); static bool on_time(float time, float timestamp);
// returns true between time intervals // returns true between time intervals
static bool between_interval(float interval, float offset = 0); static bool between_interval(float time, float interval, float offset);
// returns true between time intervals // returns true between time intervals
static bool between_interval(float time, float interval, float offset); static bool between_interval(float interval, float offset = 0);
}; };
} }