mirror of
https://github.com/NoelFB/blah.git
synced 2024-11-25 16:18:57 +08:00
Removed custom list class in favor of std::vector
This commit is contained in:
parent
06052410f2
commit
b4e1cd111e
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
}
|
200
public/blah/containers/stackvector.h
Normal file
200
public/blah/containers/stackvector.h
Normal 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--;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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>;
|
||||
}
|
8
public/blah/containers/vector.h
Normal file
8
public/blah/containers/vector.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
|
||||
namespace Blah
|
||||
{
|
||||
template<typename T>
|
||||
using Vector = std::vector<T>;
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <blah/streams/filestream.h>
|
||||
#include <blah/internal/platform.h>
|
||||
#include <blah/log.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace Blah;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user