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/framebuffer.h
public/blah/graphics/shader.h
public/blah/graphics/mesh.cpp
public/blah/graphics/mesh.h
public/blah/graphics/mesh.cpp
public/blah/graphics/material.h
public/blah/graphics/material.cpp
@ -35,9 +35,8 @@ add_library(blah
public/blah/input/virtual_button.h
public/blah/input/virtual_axis.cpp
public/blah/input/virtual_axis.h
public/blah/containers/list.h
public/blah/containers/stacklist.h
public/blah/containers/stackvector.h
public/blah/containers/str.cpp
public/blah/containers/str.h
@ -100,8 +99,7 @@ add_library(blah
private/blah/internal/graphics_opengl.cpp
private/blah/internal/input.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
PUBLIC

View File

@ -10,7 +10,7 @@ this will likely see breaking changes.
#### notes
- 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.
- 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.

View File

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

View File

@ -1,7 +1,7 @@
#pragma once
#include <inttypes.h>
#include <blah/filesystem.h>
#include <blah/containers/list.h>
#include <blah/containers/vector.h>
namespace Blah
{
@ -84,7 +84,7 @@ namespace Blah
bool dir_delete(const char* path);
// 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
void dir_explore(const char* path);

View File

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

View File

@ -6,8 +6,8 @@
#include <blah/log.h>
#include <blah/time.h>
#include <blah/containers/list.h>
#include <blah/containers/stacklist.h>
#include <blah/containers/vector.h>
#include <blah/containers/stackvector.h>
#include <blah/containers/str.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;
}
Str Str::substr(int start) const
String Str::substr(int start) const
{
if (start < 0) start = 0;
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 > m_length) start = m_length;
@ -333,6 +333,30 @@ Str Str::substr(int start, int end) const
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)
{
char* ptr = data();

View File

@ -1,8 +1,13 @@
#pragma once
#include <inttypes.h>
#include <blah/containers/vector.h>
namespace Blah
{
template<int T>
class StrOf;
using String = StrOf<64>;
class Str
{
public:
@ -115,10 +120,12 @@ namespace Blah
int last_index_of(char ch) const;
// returns a substring of the string
Str substr(int start) const;
String substr(int start) const;
// 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
void replace(char c, char r);
@ -148,11 +155,10 @@ namespace Blah
}
// 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))); }
void set(const Str& str) { set(str.cstr(), str.cstr() + str.m_length); }
void set(const char* start, const char* end = nullptr);
private:
@ -180,6 +186,4 @@ namespace Blah
StrOf& operator=(const Str& 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) \
(vert)->pos.x = ((px) * mat.m11) + ((py) * mat.m21) + mat.m31; \
(vert)->pos.y = ((px) * mat.m12) + ((py) * mat.m22) + mat.m32; \
(vert)->tex.x = tx; \
if (m_batch.flip_vertically) \
(vert)->tex.y = 1.0f - ty; \
else \
(vert)->tex.y = ty; \
(vert)->col = c; \
(vert)->mult = m; \
(vert)->wash = w; \
(vert)->fill = f;
#define MAKE_VERTEX(mat, px, py, tx, ty, c, m, w, f) \
{ \
Vec2( \
((px)*mat.m11) + ((py)*mat.m21) + mat.m31, \
((px)*mat.m12) + ((py)*mat.m22) + mat.m32), \
Vec2(tx, (m_batch.flip_vertically ? 1.0f - ty : ty)), \
c, m, w, 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) \
{ \
const int __v = (int)m_vertices.size(); \
m_batch.elements += 2; \
int* _i = m_indices.expand(6); \
*_i++ = m_vertices.count() + 0; \
*_i++ = m_vertices.count() + 1; \
*_i++ = m_vertices.count() + 2; \
*_i++ = m_vertices.count() + 0; \
*_i++ = m_vertices.count() + 2; \
*_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); \
m_indices.insert(m_indices.end(), { __v + 0, __v + 1, __v + 2, __v + 0, __v + 2, __v + 3 }); \
m_vertices.insert(m_vertices.end(), { \
MAKE_VERTEX(m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash), \
MAKE_VERTEX(m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash), \
MAKE_VERTEX(m_matrix, px2, py2, tx2, ty2, col2, mult, fill, wash), \
MAKE_VERTEX(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) \
{ \
const int __v = (int)m_vertices.size(); \
m_batch.elements += 1; \
int* _i = m_indices.expand(3); \
*_i++ = m_vertices.count() + 0; \
*_i++ = m_vertices.count() + 1; \
*_i++ = m_vertices.count() + 2; \
Vertex* _v = m_vertices.expand(3); \
MAKE_VERTEX(_v, m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash); _v++; \
MAKE_VERTEX(_v, m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash); _v++; \
MAKE_VERTEX(_v, m_matrix, px2, py2, tx2, ty2, col2, mult, fill, wash); \
m_indices.insert(m_indices.end(), { __v + 0, __v + 1, __v + 2 }); \
m_vertices.insert(m_vertices.end(), { \
MAKE_VERTEX(m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash), \
MAKE_VERTEX(m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash), \
MAKE_VERTEX(m_matrix, px2, py2, tx2, ty2, col2, mult, fill, wash) \
}); \
}
// Compares a Batcher variable, and starts a new batch if it has changed
#define SET_BATCH_VAR(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.elements = 0; \
} \
@ -137,66 +128,71 @@ Batch::~Batch()
void Batch::push_matrix(const Mat3x2& matrix)
{
m_matrix_stack.add(m_matrix);
m_matrix_stack.push(m_matrix);
m_matrix = matrix * m_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)
{
m_scissor_stack.add(m_batch.scissor);
m_scissor_stack.push(m_batch.scissor);
SET_BATCH_VAR(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);
}
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);
}
void Batch::pop_blend()
{
BlendMode blend = m_blend_stack.pop();
BlendMode blend = m_blend_stack.top();
m_blend_stack.pop();
SET_BATCH_VAR(blend);
}
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);
}
void Batch::pop_material()
{
MaterialRef material = m_material_stack.pop();
MaterialRef material = m_material_stack.top();
m_material_stack.pop();
SET_BATCH_VAR(material);
}
void Batch::push_layer(int layer)
{
m_layer_stack.add(m_batch.layer);
m_layer_stack.push(m_batch.layer);
SET_BATCH_VAR(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);
}
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_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()
{
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_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())
{
m_batches.add(m_batch);
m_batches.push_back(m_batch);
m_batch.offset += m_batch.elements;
m_batch.elements = 0;
}
@ -240,7 +237,7 @@ void Batch::render(const FrameBufferRef& target)
void Batch::render(const FrameBufferRef& target, const Mat4x4& matrix)
{
// 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;
// define defaults
@ -259,8 +256,8 @@ void Batch::render(const FrameBufferRef& target, const Mat4x4& matrix)
}
// upload data
m_mesh->index_data(m_indices.begin(), m_indices.count());
m_mesh->vertex_data(m_vertices.begin(), m_vertices.count());
m_mesh->index_data(m_indices.data(), m_indices.size());
m_mesh->vertex_data(m_vertices.data(), m_vertices.size());
RenderCall call;
call.target = target;
@ -315,28 +312,20 @@ void Batch::clear()
m_batch.scissor.w = m_batch.scissor.h = -1;
m_batch.flip_vertically = false;
m_matrix_stack.clear();
m_scissor_stack.clear();
m_blend_stack.clear();
m_material_stack.clear();
m_color_mode_stack.clear();
m_layer_stack.clear();
m_matrix_stack = std::stack<Mat3x2>();
m_scissor_stack = std::stack<Rect>();
m_blend_stack = std::stack<BlendMode>();
m_material_stack = std::stack<MaterialRef>();
m_color_mode_stack = std::stack<ColorMode>();
m_layer_stack = std::stack<int>();
m_batches.clear();
}
void Batch::dispose()
{
m_matrix_stack.dispose();
m_scissor_stack.dispose();
m_blend_stack.dispose();
m_material_stack.dispose();
m_color_mode_stack.dispose();
m_layer_stack.dispose();
m_batches.dispose();
clear();
m_default_material.reset();
m_mesh.reset();
m_vertices.dispose();
m_indices.dispose();
}
void Batch::line(const Vec2& from, const Vec2& to, float t, Color color)

View File

@ -1,6 +1,5 @@
#pragma once
#include <blah/graphics/graphics.h>
#include <blah/containers/list.h>
#include <blah/containers/str.h>
#include <blah/math/vec2.h>
#include <blah/math/rect.h>
@ -9,6 +8,8 @@
#include <blah/math/color.h>
#include <blah/drawing/subtexture.h>
#include <blah/drawing/spritefont.h>
#include <blah/containers/vector.h>
#include <stack>
namespace Blah
{
@ -145,24 +146,23 @@ namespace Blah
scissor(0, 0, -1, -1) {}
};
static ShaderRef m_default_shader;
MaterialRef m_default_material;
MeshRef m_mesh;
Mat3x2 m_matrix;
ColorMode m_color_mode;
uint8_t m_tex_mult;
uint8_t m_tex_wash;
DrawBatch m_batch;
List<Vertex> m_vertices;
List<int> m_indices;
List<Mat3x2> m_matrix_stack;
List<Rect> m_scissor_stack;
List<BlendMode> m_blend_stack;
List<MaterialRef> m_material_stack;
List<ColorMode> m_color_mode_stack;
List<int> m_layer_stack;
List<DrawBatch> m_batches;
static ShaderRef m_default_shader;
MaterialRef m_default_material;
MeshRef m_mesh;
Mat3x2 m_matrix;
ColorMode m_color_mode;
uint8_t m_tex_mult;
uint8_t m_tex_wash;
DrawBatch m_batch;
Vector<Vertex> m_vertices;
Vector<int> m_indices;
std::stack<Mat3x2> m_matrix_stack;
std::stack<Rect> m_scissor_stack;
std::stack<BlendMode> m_blend_stack;
std::stack<MaterialRef> m_material_stack;
std::stack<ColorMode> m_color_mode_stack;
std::stack<int> m_layer_stack;
Vector<DrawBatch> m_batches;
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/images/font.h>
#include <blah/images/packer.h>
#include <blah/log.h>
using namespace Blah;
@ -54,7 +55,7 @@ SpriteFont::~SpriteFont()
void SpriteFont::dispose()
{
m_atlas.dispose();
m_atlas.clear();
m_characters.clear();
m_kerning.clear();
name.dispose();
@ -133,7 +134,7 @@ void SpriteFont::build(const char* file, float sz, const uint32_t* charset)
dispose();
Font font(file);
if (font.IsValid())
if (font.is_valid())
build(font, sz, charset);
}
@ -141,12 +142,12 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset)
{
dispose();
float scale = font.GetScale(size);
float scale = font.get_scale(size);
name = font.FamilyName();
ascent = font.Ascent() * scale;
descent = font.Descent() * scale;
line_gap = font.LineGap() * scale;
name = font.family_name();
ascent = font.ascent() * scale;
descent = font.descent() * scale;
line_gap = font.line_gap() * scale;
this->size = size;
Packer packer;
@ -156,7 +157,7 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset)
packer.power_of_two = true;
std::unordered_map<uint32_t, int> glyphs;
List<Color> buffer;
Vector<Color> buffer;
auto ranges = charset;
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++)
{
auto glyph = font.GetGlyph(i);
auto glyph = font.get_glyph(i);
if (glyph <= 0)
continue;
glyphs[i] = glyph;
// 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].offset = Vec2(ch.offsetX, ch.offsetY);
m_characters[i].offset = Vec2(ch.offset_x, ch.offset_y);
// pack glyph
if (ch.hasGlyph)
if (ch.has_glyph)
{
if (buffer.count() < ch.width * ch.height)
buffer.expand(ch.width * ch.height - buffer.count());
if (buffer.size() < ch.width * ch.height)
buffer.resize(ch.width * ch.height);
if (font.GetBitmap(ch, buffer.begin()))
packer.add(i, ch.width, ch.height, buffer.begin());
if (font.get_image(ch, buffer.data()))
packer.add(i, ch.width, ch.height, buffer.data());
}
}
ranges += 2;
}
buffer.dispose();
buffer.clear();
packer.pack();
for (auto& it : packer.pages)
m_atlas.add(Graphics::create_texture(it));
m_atlas.push_back(Graphics::create_texture(it));
// add character subtextures
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 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)
set_kerning(a->first, b->first, kern);
}

View File

@ -1,7 +1,7 @@
#pragma once
#include <inttypes.h>
#include <blah/containers/list.h>
#include <blah/containers/str.h>
#include <blah/containers/vector.h>
#include <blah/drawing/subtexture.h>
#include <blah/math/vec2.h>
#include <unordered_map>
@ -25,7 +25,7 @@ namespace Blah
std::unordered_map<uint64_t, float> m_kerning;
// built texture
List<TextureRef> m_atlas;
Vector<TextureRef> m_atlas;
public:
static const uint32_t* ASCII;
@ -56,7 +56,7 @@ namespace Blah
float height() const { return ascent - descent; }
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_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());
}
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
Internal::Platform::dir_enumerate(list, path.cstr(), recursive);

View File

@ -1,6 +1,6 @@
#pragma once
#include <blah/containers/list.h>
#include <blah/containers/str.h>
#include <blah/containers/vector.h>
namespace Blah
{
@ -19,7 +19,7 @@ namespace Blah
bool create(const FilePath& path);
bool exists(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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
#include <blah/images/aseprite.h>
#include <blah/streams/filestream.h>
#include <blah/log.h>
#define STBI_NO_STDIO
#define STBI_NO_JPEG
@ -99,7 +100,7 @@ void Aseprite::Parse(Stream& stream)
return;
}
int frameCount = 0;
int frame_count = 0;
// header
{
@ -115,7 +116,7 @@ void Aseprite::Parse(Stream& stream)
}
// main info
frameCount = stream.read<uint16_t>(Endian::Little);
frame_count = stream.read<uint16_t>(Endian::Little);
width = 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);
@ -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<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<int8_t>(Endian::Little); // Pixel width
stream.read<int8_t>(Endian::Little); // Pixel height
stream.seek(stream.position() + 92); // For Future
stream.read<int8_t>(Endian::Little); // Pixel width
stream.read<int8_t>(Endian::Little); // Pixel height
stream.seek(stream.position() + 92); // For Future
}
frames.expand(frameCount);
frames.resize(frame_count);
// frames
for (int i = 0; i < frameCount; i++)
for (int i = 0; i < frame_count; i++)
{
auto frameStart = stream.position();
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)
{
auto layer = layers.expand(1);
layer->flag = static_cast<LayerFlags>(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);
layers.emplace_back();
auto& layer = layers.back();
layer.flag = static_cast<LayerFlags>(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); // height
layer->blendmode = stream.read<uint16_t>(Endian::Little);
layer->alpha = stream.read<uint8_t>(Endian::Little);
layer.blendmode = stream.read<uint16_t>(Endian::Little);
layer.alpha = stream.read<uint8_t>(Endian::Little);
stream.seek(stream.position() + 3); // for future
layer->name.set_length(stream.read<uint16_t>(Endian::Little));
stream.read(layer->name.cstr(), layer->name.length());
layer.name.set_length(stream.read<uint16_t>(Endian::Little));
stream.read(layer.name.cstr(), layer.name.length());
layer->userdata.color = 0xffffff;
layer->userdata.text = "";
last_userdata = &(layer->userdata);
layer.userdata.color = 0xffffff;
layer.userdata.text = "";
last_userdata = &(layer.userdata);
}
void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition)
{
Frame& frame = frames[frameIndex];
auto cel = frame.cels.expand(1);
cel->layer_index = stream.read<uint16_t>(Endian::Little);
cel->x = stream.read<uint16_t>(Endian::Little);
cel->y = stream.read<uint16_t>(Endian::Little);
cel->alpha = stream.read<uint8_t>(Endian::Little);
cel->linked_frame_index = -1;
frame.cels.emplace_back();
auto& cel = frame.cels.back();
cel.layer_index = stream.read<uint16_t>(Endian::Little);
cel.x = stream.read<uint16_t>(Endian::Little);
cel.y = stream.read<uint16_t>(Endian::Little);
cel.alpha = stream.read<uint8_t>(Endian::Little);
cel.linked_frame_index = -1;
auto celType = stream.read<uint16_t>(Endian::Little);
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 count = width * height * (int)mode;
cel->image = Image(width, height);
cel.image = Image(width, height);
// RAW
if (celType == 0)
{
stream.read(cel->image.pixels, count);
stream.read(cel.image.pixels, count);
}
// DEFLATE (zlib)
else
@ -252,7 +256,7 @@ void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition)
stream.read(buffer, size);
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;
@ -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
if (mode == Modes::Grayscale)
{
auto src = (unsigned char*)cel->image.pixels;
auto dst = cel->image.pixels;
auto src = (unsigned char*)cel.image.pixels;
auto dst = cel.image.pixels;
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]);
}
else if (mode == Modes::Indexed)
{
auto src = (unsigned char*)cel->image.pixels;
auto dst = cel->image.pixels;
auto src = (unsigned char*)cel.image.pixels;
auto dst = cel.image.pixels;
for (int i = width * height - 1; i >= 0; 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
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
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.text = "";
last_userdata = &(cel->userdata);
cel.userdata.color = 0xffffff;
cel.userdata.text = "";
last_userdata = &(cel.userdata);
}
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);
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++)
{
@ -348,17 +352,19 @@ void Aseprite::ParseTag(Stream& stream, int frame)
for (int t = 0; t < count; t++)
{
auto tag = tags.expand(1);
tag->from = 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 tag;
tag.from = 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));
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);
tag->name.set_length(stream.read<uint16_t>(Endian::Little));
stream.read(tag->name.cstr(), tag->name.length());
tag.name.set_length(stream.read<uint16_t>(Endian::Little));
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++)
{
auto slice = slices.expand(1);
slice->name = name;
slice->frame = stream.read<uint32_t>(Endian::Little);
slice->origin.x = stream.read<int32_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);
slices.emplace_back();
auto& slice = slices.back();
slice.name = name;
slice.frame = stream.read<uint32_t>(Endian::Little);
slice.origin.x = stream.read<int32_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)
if (flags & (1 << 0))
@ -392,17 +400,17 @@ void Aseprite::ParseSlice(Stream& stream, int frame)
}
// pivot point
slice->has_pivot = false;
slice.has_pivot = false;
if (flags & (1 << 1))
{
slice->has_pivot = true;
slice->pivot.x = stream.read<uint32_t>(Endian::Little);
slice->pivot.y = stream.read<uint32_t>(Endian::Little);
slice.has_pivot = true;
slice.pivot.x = stream.read<uint32_t>(Endian::Little);
slice.pivot.y = stream.read<uint32_t>(Endian::Little);
}
slice->userdata.color = 0xffffff;
slice->userdata.text = "";
last_userdata = &(slice->userdata);
slice.userdata.color = 0xffffff;
slice.userdata.text = "";
last_userdata = &(slice.userdata);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -23,9 +23,9 @@ void Time::pause_for(float 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)
@ -33,9 +33,9 @@ bool Time::on_interval(float delta, float interval, float 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)
@ -43,12 +43,12 @@ bool Time::on_time(float time, float 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)
{
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);
// 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
static bool on_interval(float delta, float interval, float offset);
// 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
static bool on_time(float time, float timestamp);
// 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
static bool between_interval(float time, float interval, float offset);
static bool between_interval(float interval, float offset = 0);
};
}