mirror of
https://github.com/NoelFB/blah.git
synced 2025-04-08 00:56:04 +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/texture.h
|
||||||
public/blah/graphics/framebuffer.h
|
public/blah/graphics/framebuffer.h
|
||||||
public/blah/graphics/shader.h
|
public/blah/graphics/shader.h
|
||||||
public/blah/graphics/mesh.cpp
|
|
||||||
public/blah/graphics/mesh.h
|
public/blah/graphics/mesh.h
|
||||||
|
public/blah/graphics/mesh.cpp
|
||||||
public/blah/graphics/material.h
|
public/blah/graphics/material.h
|
||||||
public/blah/graphics/material.cpp
|
public/blah/graphics/material.cpp
|
||||||
|
|
||||||
@ -36,8 +36,7 @@ add_library(blah
|
|||||||
public/blah/input/virtual_axis.cpp
|
public/blah/input/virtual_axis.cpp
|
||||||
public/blah/input/virtual_axis.h
|
public/blah/input/virtual_axis.h
|
||||||
|
|
||||||
public/blah/containers/list.h
|
public/blah/containers/stackvector.h
|
||||||
public/blah/containers/stacklist.h
|
|
||||||
public/blah/containers/str.cpp
|
public/blah/containers/str.cpp
|
||||||
public/blah/containers/str.h
|
public/blah/containers/str.h
|
||||||
|
|
||||||
@ -100,8 +99,7 @@ add_library(blah
|
|||||||
private/blah/internal/graphics_opengl.cpp
|
private/blah/internal/graphics_opengl.cpp
|
||||||
private/blah/internal/input.h
|
private/blah/internal/input.h
|
||||||
private/blah/internal/platform.h
|
private/blah/internal/platform.h
|
||||||
private/blah/internal/platform_sdl2.cpp
|
private/blah/internal/platform_sdl2.cpp "public/blah/containers/vector.h")
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(blah
|
target_include_directories(blah
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
@ -10,7 +10,7 @@ this will likely see breaking changes.
|
|||||||
|
|
||||||
#### notes
|
#### notes
|
||||||
- There are probably lots of small bugs as this is highly untested. Best used as a learning resource for now.
|
- There are probably lots of small bugs as this is highly untested. Best used as a learning resource for now.
|
||||||
- There's a custom "vector" class which is called List and Stacklist which may later be replaced with std::vector
|
- There's a custom "StackVector" class that tries to implement an std::vector on the stack, but it's probably bug-prone.
|
||||||
- There's no Shader abstraction, so the [Sprite Batcher](https://github.com/NoelFB/blah/blob/master/public/blah/drawing/batch.h) has hard-coded GLSL. This will need to change.
|
- There's no Shader abstraction, so the [Sprite Batcher](https://github.com/NoelFB/blah/blob/master/public/blah/drawing/batch.h) has hard-coded GLSL. This will need to change.
|
||||||
- The rendering layer may be replaced with [FNA3D](https://github.com/FNA-XNA/FNA3D), [BGFX](https://github.com/bkaradzic/bgfx), [Sokol](https://github.com/floooh/sokol), or something else.
|
- The rendering layer may be replaced with [FNA3D](https://github.com/FNA-XNA/FNA3D), [BGFX](https://github.com/bkaradzic/bgfx), [Sokol](https://github.com/floooh/sokol), or something else.
|
||||||
- There's no Audio layer implementation yet.
|
- There's no Audio layer implementation yet.
|
||||||
|
@ -9,11 +9,14 @@
|
|||||||
#include <blah/graphics/mesh.h>
|
#include <blah/graphics/mesh.h>
|
||||||
#include <blah/graphics/shader.h>
|
#include <blah/graphics/shader.h>
|
||||||
#include <blah/graphics/material.h>
|
#include <blah/graphics/material.h>
|
||||||
|
#include <blah/containers/stackvector.h>
|
||||||
|
#include <blah/log.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
#define APIENTRY
|
#define APIENTRY
|
||||||
@ -715,7 +718,7 @@ namespace Blah
|
|||||||
GLuint m_id;
|
GLuint m_id;
|
||||||
int m_width;
|
int m_width;
|
||||||
int m_height;
|
int m_height;
|
||||||
StackList<TextureRef, BLAH_ATTACHMENTS> m_attachments;
|
StackVector<TextureRef, BLAH_ATTACHMENTS> m_attachments;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -733,7 +736,7 @@ namespace Blah
|
|||||||
auto gltex = ((OpenGL_Texture*)tex.get());
|
auto gltex = ((OpenGL_Texture*)tex.get());
|
||||||
|
|
||||||
gltex->framebuffer_parent = true;
|
gltex->framebuffer_parent = true;
|
||||||
m_attachments.add(tex);
|
m_attachments.push_back(tex);
|
||||||
|
|
||||||
if (attachments[i] != TextureFormat::DepthStencil)
|
if (attachments[i] != TextureFormat::DepthStencil)
|
||||||
{
|
{
|
||||||
@ -896,11 +899,11 @@ namespace Blah
|
|||||||
gl.GetActiveAttrib(id, i, BLAH_ATTRIBUTE_NAME - 1, &length, &size, &type, name);
|
gl.GetActiveAttrib(id, i, BLAH_ATTRIBUTE_NAME - 1, &length, &size, &type, name);
|
||||||
name[length] = '\0';
|
name[length] = '\0';
|
||||||
|
|
||||||
auto attr = m_attributes.expand();
|
ShaderAttribute attr;
|
||||||
attr->name.append(name);
|
attr.name = name;
|
||||||
// TOOD: set these?
|
attr.semantic_name = "";
|
||||||
attr->semantic_name = "";
|
attr.semantic_location = 0;
|
||||||
attr->semantic_location = 0;
|
m_attributes.push_back(attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -935,31 +938,33 @@ namespace Blah
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto uniform = m_uniforms.expand();
|
ShaderUniform uniform;
|
||||||
uniform->name = name;
|
uniform.name = name;
|
||||||
uniform->type = UniformType::None;
|
uniform.type = UniformType::None;
|
||||||
uniform->array_length = size;
|
uniform.array_length = size;
|
||||||
uniforms_loc[i] = gl.GetUniformLocation(id, name);
|
uniforms_loc[i] = gl.GetUniformLocation(id, name);
|
||||||
|
|
||||||
if (type == GL_FLOAT)
|
if (type == GL_FLOAT)
|
||||||
uniform->type = UniformType::Float;
|
uniform.type = UniformType::Float;
|
||||||
else if (type == GL_FLOAT_VEC2)
|
else if (type == GL_FLOAT_VEC2)
|
||||||
uniform->type = UniformType::Float2;
|
uniform.type = UniformType::Float2;
|
||||||
else if (type == GL_FLOAT_VEC3)
|
else if (type == GL_FLOAT_VEC3)
|
||||||
uniform->type = UniformType::Float3;
|
uniform.type = UniformType::Float3;
|
||||||
else if (type == GL_FLOAT_VEC4)
|
else if (type == GL_FLOAT_VEC4)
|
||||||
uniform->type = UniformType::Float4;
|
uniform.type = UniformType::Float4;
|
||||||
else if (type == GL_FLOAT_MAT3x2)
|
else if (type == GL_FLOAT_MAT3x2)
|
||||||
uniform->type = UniformType::Mat3x2;
|
uniform.type = UniformType::Mat3x2;
|
||||||
else if (type == GL_FLOAT_MAT4)
|
else if (type == GL_FLOAT_MAT4)
|
||||||
uniform->type = UniformType::Mat4x4;
|
uniform.type = UniformType::Mat4x4;
|
||||||
else if (type == GL_SAMPLER_2D)
|
else if (type == GL_SAMPLER_2D)
|
||||||
uniform->type = UniformType::Texture;
|
uniform.type = UniformType::Texture;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log::error("Unsupported Uniform Type. Must be either FLOAT, MAT3x2, MAT4, or SAMPLER_2D");
|
Log::error("Unsupported Uniform Type. Must be either FLOAT, MAT3x2, MAT4, or SAMPLER_2D");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_uniforms.push_back(uniform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1041,6 +1046,8 @@ namespace Blah
|
|||||||
m_instance_size = 0;
|
m_instance_size = 0;
|
||||||
m_vertex_attribs_enabled = 0;
|
m_vertex_attribs_enabled = 0;
|
||||||
m_instance_attribs_enabled = 0;
|
m_instance_attribs_enabled = 0;
|
||||||
|
m_vertex_attribs[0] = 0;
|
||||||
|
m_instance_attribs[0] = 0;
|
||||||
|
|
||||||
gl.GenVertexArrays(1, &m_id);
|
gl.GenVertexArrays(1, &m_id);
|
||||||
}
|
}
|
||||||
@ -1284,7 +1291,7 @@ namespace Blah
|
|||||||
GLint texture_ids[64];
|
GLint texture_ids[64];
|
||||||
|
|
||||||
auto& uniforms = shader->uniforms();
|
auto& uniforms = shader->uniforms();
|
||||||
for (int i = 0; i < uniforms.count(); i++)
|
for (int i = 0; i < uniforms.size(); i++)
|
||||||
{
|
{
|
||||||
auto location = shader->uniforms_loc[i];
|
auto location = shader->uniforms_loc[i];
|
||||||
auto& uniform = uniforms[i];
|
auto& uniform = uniforms[i];
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <blah/filesystem.h>
|
#include <blah/filesystem.h>
|
||||||
#include <blah/containers/list.h>
|
#include <blah/containers/vector.h>
|
||||||
|
|
||||||
namespace Blah
|
namespace Blah
|
||||||
{
|
{
|
||||||
@ -84,7 +84,7 @@ namespace Blah
|
|||||||
bool dir_delete(const char* path);
|
bool dir_delete(const char* path);
|
||||||
|
|
||||||
// enumerates a directory and appends each file to the given list
|
// enumerates a directory and appends each file to the given list
|
||||||
void dir_enumerate(List<FilePath>& list, const char* path, bool recursive);
|
void dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive);
|
||||||
|
|
||||||
// opens a directory in the OS file explorer / finder
|
// opens a directory in the OS file explorer / finder
|
||||||
void dir_explore(const char* path);
|
void dir_explore(const char* path);
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
// on Windows we're using the C++ <filesystem> API for now
|
// on Windows we're using the C++ <filesystem> API for now
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <winuser.h> // for SetProcessDPIAware
|
#include <winuser.h> // for SetProcessDPIAware
|
||||||
#include <filesystem> // for File Reading/Writing
|
#include <filesystem> // for File Reading/Writing
|
||||||
@ -482,25 +483,19 @@ bool Platform::dir_delete(const char* path)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Platform::dir_enumerate(List<FilePath>& list, const char* path, bool recursive)
|
void Platform::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive)
|
||||||
{
|
{
|
||||||
if (fs::is_directory(path))
|
if (fs::is_directory(path))
|
||||||
{
|
{
|
||||||
if (recursive)
|
if (recursive)
|
||||||
{
|
{
|
||||||
for (auto& p : fs::recursive_directory_iterator(path))
|
for (auto& p : fs::recursive_directory_iterator(path))
|
||||||
{
|
list.emplace_back(p.path().string().c_str());
|
||||||
FilePath str(p.path().string().c_str());
|
|
||||||
list.add(str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (auto& p : fs::directory_iterator(path))
|
for (auto& p : fs::directory_iterator(path))
|
||||||
{
|
list.emplace_back(p.path().string().c_str());
|
||||||
FilePath str(p.path().string().c_str());
|
|
||||||
list.add(str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
#include <blah/log.h>
|
#include <blah/log.h>
|
||||||
#include <blah/time.h>
|
#include <blah/time.h>
|
||||||
|
|
||||||
#include <blah/containers/list.h>
|
#include <blah/containers/vector.h>
|
||||||
#include <blah/containers/stacklist.h>
|
#include <blah/containers/stackvector.h>
|
||||||
#include <blah/containers/str.h>
|
#include <blah/containers/str.h>
|
||||||
|
|
||||||
#include <blah/drawing/batch.h>
|
#include <blah/drawing/batch.h>
|
||||||
|
@ -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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Str Str::substr(int start) const
|
String Str::substr(int start) const
|
||||||
{
|
{
|
||||||
if (start < 0) start = 0;
|
if (start < 0) start = 0;
|
||||||
if (start > m_length) start = m_length;
|
if (start > m_length) start = m_length;
|
||||||
|
|
||||||
return Str(data() + start);
|
return String(data() + start);
|
||||||
}
|
}
|
||||||
|
|
||||||
Str Str::substr(int start, int end) const
|
String Str::substr(int start, int end) const
|
||||||
{
|
{
|
||||||
if (start < 0) start = 0;
|
if (start < 0) start = 0;
|
||||||
if (start > m_length) start = m_length;
|
if (start > m_length) start = m_length;
|
||||||
@ -333,6 +333,30 @@ Str Str::substr(int start, int end) const
|
|||||||
return Str(data() + start, data() + end);
|
return Str(data() + start, data() + end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<String> Str::split(char ch) const
|
||||||
|
{
|
||||||
|
Vector<String> result;
|
||||||
|
|
||||||
|
const char* ptr = data();
|
||||||
|
int last = 0;
|
||||||
|
int index = 1;
|
||||||
|
|
||||||
|
while (index < m_length)
|
||||||
|
{
|
||||||
|
if (ptr[index] == ch)
|
||||||
|
{
|
||||||
|
result.push_back(substr(last, index));
|
||||||
|
last = index + 1;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last < index)
|
||||||
|
result.push_back(substr(last, index));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void Str::replace(char c, char r)
|
void Str::replace(char c, char r)
|
||||||
{
|
{
|
||||||
char* ptr = data();
|
char* ptr = data();
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <blah/containers/vector.h>
|
||||||
|
|
||||||
namespace Blah
|
namespace Blah
|
||||||
{
|
{
|
||||||
|
template<int T>
|
||||||
|
class StrOf;
|
||||||
|
using String = StrOf<64>;
|
||||||
|
|
||||||
class Str
|
class Str
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -115,10 +120,12 @@ namespace Blah
|
|||||||
int last_index_of(char ch) const;
|
int last_index_of(char ch) const;
|
||||||
|
|
||||||
// returns a substring of the string
|
// returns a substring of the string
|
||||||
Str substr(int start) const;
|
String substr(int start) const;
|
||||||
|
|
||||||
// returns a substring of the string
|
// returns a substring of the string
|
||||||
Str substr(int start, int end) const;
|
String substr(int start, int end) const;
|
||||||
|
|
||||||
|
Vector<String> split(char ch) const;
|
||||||
|
|
||||||
// replaces all occurances of the given character in the string
|
// replaces all occurances of the given character in the string
|
||||||
void replace(char c, char r);
|
void replace(char c, char r);
|
||||||
@ -152,7 +159,6 @@ namespace Blah
|
|||||||
const char* data() const { return (m_buffer != nullptr ? m_buffer : ((char*)(this) + sizeof(Str))); }
|
const char* data() const { return (m_buffer != nullptr ? m_buffer : ((char*)(this) + sizeof(Str))); }
|
||||||
|
|
||||||
void set(const Str& str) { set(str.cstr(), str.cstr() + str.m_length); }
|
void set(const Str& str) { set(str.cstr(), str.cstr() + str.m_length); }
|
||||||
|
|
||||||
void set(const char* start, const char* end = nullptr);
|
void set(const char* start, const char* end = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -180,6 +186,4 @@ namespace Blah
|
|||||||
StrOf& operator=(const Str& rhs) { set(rhs); return *this; }
|
StrOf& operator=(const Str& rhs) { set(rhs); return *this; }
|
||||||
StrOf& operator=(const StrOf& rhs) { set(rhs); return *this; }
|
StrOf& operator=(const StrOf& rhs) { set(rhs); return *this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
using String = StrOf<64>;
|
|
||||||
}
|
}
|
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) \
|
#define MAKE_VERTEX(mat, px, py, tx, ty, c, m, w, f) \
|
||||||
(vert)->pos.x = ((px) * mat.m11) + ((py) * mat.m21) + mat.m31; \
|
{ \
|
||||||
(vert)->pos.y = ((px) * mat.m12) + ((py) * mat.m22) + mat.m32; \
|
Vec2( \
|
||||||
(vert)->tex.x = tx; \
|
((px)*mat.m11) + ((py)*mat.m21) + mat.m31, \
|
||||||
if (m_batch.flip_vertically) \
|
((px)*mat.m12) + ((py)*mat.m22) + mat.m32), \
|
||||||
(vert)->tex.y = 1.0f - ty; \
|
Vec2(tx, (m_batch.flip_vertically ? 1.0f - ty : ty)), \
|
||||||
else \
|
c, m, w, f \
|
||||||
(vert)->tex.y = ty; \
|
}
|
||||||
(vert)->col = c; \
|
|
||||||
(vert)->mult = m; \
|
|
||||||
(vert)->wash = w; \
|
|
||||||
(vert)->fill = f;
|
|
||||||
|
|
||||||
#define PUSH_QUAD(px0, py0, px1, py1, px2, py2, px3, py3, tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, col0, col1, col2, col3, mult, fill, wash) \
|
#define PUSH_QUAD(px0, py0, px1, py1, px2, py2, px3, py3, tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, col0, col1, col2, col3, mult, fill, wash) \
|
||||||
{ \
|
{ \
|
||||||
|
const int __v = (int)m_vertices.size(); \
|
||||||
m_batch.elements += 2; \
|
m_batch.elements += 2; \
|
||||||
int* _i = m_indices.expand(6); \
|
m_indices.insert(m_indices.end(), { __v + 0, __v + 1, __v + 2, __v + 0, __v + 2, __v + 3 }); \
|
||||||
*_i++ = m_vertices.count() + 0; \
|
m_vertices.insert(m_vertices.end(), { \
|
||||||
*_i++ = m_vertices.count() + 1; \
|
MAKE_VERTEX(m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash), \
|
||||||
*_i++ = m_vertices.count() + 2; \
|
MAKE_VERTEX(m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash), \
|
||||||
*_i++ = m_vertices.count() + 0; \
|
MAKE_VERTEX(m_matrix, px2, py2, tx2, ty2, col2, mult, fill, wash), \
|
||||||
*_i++ = m_vertices.count() + 2; \
|
MAKE_VERTEX(m_matrix, px3, py3, tx3, ty3, col3, mult, fill, wash) \
|
||||||
*_i++ = m_vertices.count() + 3; \
|
}); \
|
||||||
Vertex* _v = m_vertices.expand(4); \
|
|
||||||
MAKE_VERTEX(_v, m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash); _v++; \
|
|
||||||
MAKE_VERTEX(_v, m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash); _v++; \
|
|
||||||
MAKE_VERTEX(_v, m_matrix, px2, py2, tx2, ty2, col2, mult, fill, wash); _v++; \
|
|
||||||
MAKE_VERTEX(_v, m_matrix, px3, py3, tx3, ty3, col3, mult, fill, wash); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PUSH_TRIANGLE(px0, py0, px1, py1, px2, py2, tx0, ty0, tx1, ty1, tx2, ty2, col0, col1, col2, mult, fill, wash) \
|
#define PUSH_TRIANGLE(px0, py0, px1, py1, px2, py2, tx0, ty0, tx1, ty1, tx2, ty2, col0, col1, col2, mult, fill, wash) \
|
||||||
{ \
|
{ \
|
||||||
|
const int __v = (int)m_vertices.size(); \
|
||||||
m_batch.elements += 1; \
|
m_batch.elements += 1; \
|
||||||
int* _i = m_indices.expand(3); \
|
m_indices.insert(m_indices.end(), { __v + 0, __v + 1, __v + 2 }); \
|
||||||
*_i++ = m_vertices.count() + 0; \
|
m_vertices.insert(m_vertices.end(), { \
|
||||||
*_i++ = m_vertices.count() + 1; \
|
MAKE_VERTEX(m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash), \
|
||||||
*_i++ = m_vertices.count() + 2; \
|
MAKE_VERTEX(m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash), \
|
||||||
Vertex* _v = m_vertices.expand(3); \
|
MAKE_VERTEX(m_matrix, px2, py2, tx2, ty2, col2, mult, fill, wash) \
|
||||||
MAKE_VERTEX(_v, m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash); _v++; \
|
}); \
|
||||||
MAKE_VERTEX(_v, m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash); _v++; \
|
|
||||||
MAKE_VERTEX(_v, m_matrix, px2, py2, tx2, ty2, col2, mult, fill, wash); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compares a Batcher variable, and starts a new batch if it has changed
|
// Compares a Batcher variable, and starts a new batch if it has changed
|
||||||
#define SET_BATCH_VAR(variable) \
|
#define SET_BATCH_VAR(variable) \
|
||||||
if (m_batch.elements > 0 && variable != m_batch.variable) \
|
if (m_batch.elements > 0 && variable != m_batch.variable) \
|
||||||
{ \
|
{ \
|
||||||
m_batches.add(m_batch); \
|
m_batches.push_back(m_batch); \
|
||||||
m_batch.offset += m_batch.elements; \
|
m_batch.offset += m_batch.elements; \
|
||||||
m_batch.elements = 0; \
|
m_batch.elements = 0; \
|
||||||
} \
|
} \
|
||||||
@ -137,66 +128,71 @@ Batch::~Batch()
|
|||||||
|
|
||||||
void Batch::push_matrix(const Mat3x2& matrix)
|
void Batch::push_matrix(const Mat3x2& matrix)
|
||||||
{
|
{
|
||||||
m_matrix_stack.add(m_matrix);
|
m_matrix_stack.push(m_matrix);
|
||||||
m_matrix = matrix * m_matrix;
|
m_matrix = matrix * m_matrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::pop_matrix()
|
void Batch::pop_matrix()
|
||||||
{
|
{
|
||||||
m_matrix = m_matrix_stack.pop();
|
m_matrix = m_matrix_stack.top();
|
||||||
|
m_matrix_stack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::push_scissor(const Rect& scissor)
|
void Batch::push_scissor(const Rect& scissor)
|
||||||
{
|
{
|
||||||
m_scissor_stack.add(m_batch.scissor);
|
m_scissor_stack.push(m_batch.scissor);
|
||||||
SET_BATCH_VAR(scissor);
|
SET_BATCH_VAR(scissor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::pop_scissor()
|
void Batch::pop_scissor()
|
||||||
{
|
{
|
||||||
Rect scissor = m_scissor_stack.pop();
|
Rect scissor = m_scissor_stack.top();
|
||||||
|
m_scissor_stack.pop();
|
||||||
SET_BATCH_VAR(scissor);
|
SET_BATCH_VAR(scissor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::push_blend(const BlendMode& blend)
|
void Batch::push_blend(const BlendMode& blend)
|
||||||
{
|
{
|
||||||
m_blend_stack.add(m_batch.blend);
|
m_blend_stack.push(m_batch.blend);
|
||||||
SET_BATCH_VAR(blend);
|
SET_BATCH_VAR(blend);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::pop_blend()
|
void Batch::pop_blend()
|
||||||
{
|
{
|
||||||
BlendMode blend = m_blend_stack.pop();
|
BlendMode blend = m_blend_stack.top();
|
||||||
|
m_blend_stack.pop();
|
||||||
SET_BATCH_VAR(blend);
|
SET_BATCH_VAR(blend);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::push_material(const MaterialRef& material)
|
void Batch::push_material(const MaterialRef& material)
|
||||||
{
|
{
|
||||||
m_material_stack.add(m_batch.material);
|
m_material_stack.push(m_batch.material);
|
||||||
SET_BATCH_VAR(material);
|
SET_BATCH_VAR(material);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::pop_material()
|
void Batch::pop_material()
|
||||||
{
|
{
|
||||||
MaterialRef material = m_material_stack.pop();
|
MaterialRef material = m_material_stack.top();
|
||||||
|
m_material_stack.pop();
|
||||||
SET_BATCH_VAR(material);
|
SET_BATCH_VAR(material);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::push_layer(int layer)
|
void Batch::push_layer(int layer)
|
||||||
{
|
{
|
||||||
m_layer_stack.add(m_batch.layer);
|
m_layer_stack.push(m_batch.layer);
|
||||||
SET_BATCH_VAR(layer);
|
SET_BATCH_VAR(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::pop_layer()
|
void Batch::pop_layer()
|
||||||
{
|
{
|
||||||
int layer = m_layer_stack.pop();
|
int layer = m_layer_stack.top();
|
||||||
|
m_layer_stack.pop();
|
||||||
SET_BATCH_VAR(layer);
|
SET_BATCH_VAR(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::push_color_mode(ColorMode mode)
|
void Batch::push_color_mode(ColorMode mode)
|
||||||
{
|
{
|
||||||
m_color_mode_stack.add(m_color_mode);
|
m_color_mode_stack.push(m_color_mode);
|
||||||
m_color_mode = mode;
|
m_color_mode = mode;
|
||||||
|
|
||||||
m_tex_mult = (m_color_mode == ColorMode::Normal ? 255 : 0);
|
m_tex_mult = (m_color_mode == ColorMode::Normal ? 255 : 0);
|
||||||
@ -205,7 +201,8 @@ void Batch::push_color_mode(ColorMode mode)
|
|||||||
|
|
||||||
void Batch::pop_color_mode()
|
void Batch::pop_color_mode()
|
||||||
{
|
{
|
||||||
m_color_mode = m_color_mode_stack.pop();
|
m_color_mode = m_color_mode_stack.top();
|
||||||
|
m_color_mode_stack.pop();
|
||||||
m_tex_mult = (m_color_mode == ColorMode::Normal ? 255 : 0);
|
m_tex_mult = (m_color_mode == ColorMode::Normal ? 255 : 0);
|
||||||
m_tex_wash = (m_color_mode == ColorMode::Wash ? 255 : 0);
|
m_tex_wash = (m_color_mode == ColorMode::Wash ? 255 : 0);
|
||||||
}
|
}
|
||||||
@ -214,7 +211,7 @@ void Batch::set_texture(const TextureRef& texture)
|
|||||||
{
|
{
|
||||||
if (m_batch.elements > 0 && texture != m_batch.texture && m_batch.texture && m_batch.texture->is_valid())
|
if (m_batch.elements > 0 && texture != m_batch.texture && m_batch.texture && m_batch.texture->is_valid())
|
||||||
{
|
{
|
||||||
m_batches.add(m_batch);
|
m_batches.push_back(m_batch);
|
||||||
m_batch.offset += m_batch.elements;
|
m_batch.offset += m_batch.elements;
|
||||||
m_batch.elements = 0;
|
m_batch.elements = 0;
|
||||||
}
|
}
|
||||||
@ -240,7 +237,7 @@ void Batch::render(const FrameBufferRef& target)
|
|||||||
void Batch::render(const FrameBufferRef& target, const Mat4x4& matrix)
|
void Batch::render(const FrameBufferRef& target, const Mat4x4& matrix)
|
||||||
{
|
{
|
||||||
// nothing to draw
|
// nothing to draw
|
||||||
if ((m_batches.count() <= 0 && m_batch.elements <= 0) || m_indices.count() <= 0)
|
if ((m_batches.size() <= 0 && m_batch.elements <= 0) || m_indices.size() <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// define defaults
|
// define defaults
|
||||||
@ -259,8 +256,8 @@ void Batch::render(const FrameBufferRef& target, const Mat4x4& matrix)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// upload data
|
// upload data
|
||||||
m_mesh->index_data(m_indices.begin(), m_indices.count());
|
m_mesh->index_data(m_indices.data(), m_indices.size());
|
||||||
m_mesh->vertex_data(m_vertices.begin(), m_vertices.count());
|
m_mesh->vertex_data(m_vertices.data(), m_vertices.size());
|
||||||
|
|
||||||
RenderCall call;
|
RenderCall call;
|
||||||
call.target = target;
|
call.target = target;
|
||||||
@ -315,28 +312,20 @@ void Batch::clear()
|
|||||||
m_batch.scissor.w = m_batch.scissor.h = -1;
|
m_batch.scissor.w = m_batch.scissor.h = -1;
|
||||||
m_batch.flip_vertically = false;
|
m_batch.flip_vertically = false;
|
||||||
|
|
||||||
m_matrix_stack.clear();
|
m_matrix_stack = std::stack<Mat3x2>();
|
||||||
m_scissor_stack.clear();
|
m_scissor_stack = std::stack<Rect>();
|
||||||
m_blend_stack.clear();
|
m_blend_stack = std::stack<BlendMode>();
|
||||||
m_material_stack.clear();
|
m_material_stack = std::stack<MaterialRef>();
|
||||||
m_color_mode_stack.clear();
|
m_color_mode_stack = std::stack<ColorMode>();
|
||||||
m_layer_stack.clear();
|
m_layer_stack = std::stack<int>();
|
||||||
m_batches.clear();
|
m_batches.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::dispose()
|
void Batch::dispose()
|
||||||
{
|
{
|
||||||
m_matrix_stack.dispose();
|
clear();
|
||||||
m_scissor_stack.dispose();
|
|
||||||
m_blend_stack.dispose();
|
|
||||||
m_material_stack.dispose();
|
|
||||||
m_color_mode_stack.dispose();
|
|
||||||
m_layer_stack.dispose();
|
|
||||||
m_batches.dispose();
|
|
||||||
m_default_material.reset();
|
m_default_material.reset();
|
||||||
m_mesh.reset();
|
m_mesh.reset();
|
||||||
m_vertices.dispose();
|
|
||||||
m_indices.dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Batch::line(const Vec2& from, const Vec2& to, float t, Color color)
|
void Batch::line(const Vec2& from, const Vec2& to, float t, Color color)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <blah/graphics/graphics.h>
|
#include <blah/graphics/graphics.h>
|
||||||
#include <blah/containers/list.h>
|
|
||||||
#include <blah/containers/str.h>
|
#include <blah/containers/str.h>
|
||||||
#include <blah/math/vec2.h>
|
#include <blah/math/vec2.h>
|
||||||
#include <blah/math/rect.h>
|
#include <blah/math/rect.h>
|
||||||
@ -9,6 +8,8 @@
|
|||||||
#include <blah/math/color.h>
|
#include <blah/math/color.h>
|
||||||
#include <blah/drawing/subtexture.h>
|
#include <blah/drawing/subtexture.h>
|
||||||
#include <blah/drawing/spritefont.h>
|
#include <blah/drawing/spritefont.h>
|
||||||
|
#include <blah/containers/vector.h>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
namespace Blah
|
namespace Blah
|
||||||
{
|
{
|
||||||
@ -153,16 +154,15 @@ namespace Blah
|
|||||||
uint8_t m_tex_mult;
|
uint8_t m_tex_mult;
|
||||||
uint8_t m_tex_wash;
|
uint8_t m_tex_wash;
|
||||||
DrawBatch m_batch;
|
DrawBatch m_batch;
|
||||||
List<Vertex> m_vertices;
|
Vector<Vertex> m_vertices;
|
||||||
List<int> m_indices;
|
Vector<int> m_indices;
|
||||||
|
std::stack<Mat3x2> m_matrix_stack;
|
||||||
List<Mat3x2> m_matrix_stack;
|
std::stack<Rect> m_scissor_stack;
|
||||||
List<Rect> m_scissor_stack;
|
std::stack<BlendMode> m_blend_stack;
|
||||||
List<BlendMode> m_blend_stack;
|
std::stack<MaterialRef> m_material_stack;
|
||||||
List<MaterialRef> m_material_stack;
|
std::stack<ColorMode> m_color_mode_stack;
|
||||||
List<ColorMode> m_color_mode_stack;
|
std::stack<int> m_layer_stack;
|
||||||
List<int> m_layer_stack;
|
Vector<DrawBatch> m_batches;
|
||||||
List<DrawBatch> m_batches;
|
|
||||||
|
|
||||||
void render_single_batch(RenderCall& call, const DrawBatch& b, const Mat4x4& matrix);
|
void render_single_batch(RenderCall& call, const DrawBatch& b, const Mat4x4& matrix);
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <blah/drawing/spritefont.h>
|
#include <blah/drawing/spritefont.h>
|
||||||
#include <blah/images/font.h>
|
#include <blah/images/font.h>
|
||||||
#include <blah/images/packer.h>
|
#include <blah/images/packer.h>
|
||||||
|
#include <blah/log.h>
|
||||||
|
|
||||||
using namespace Blah;
|
using namespace Blah;
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ SpriteFont::~SpriteFont()
|
|||||||
|
|
||||||
void SpriteFont::dispose()
|
void SpriteFont::dispose()
|
||||||
{
|
{
|
||||||
m_atlas.dispose();
|
m_atlas.clear();
|
||||||
m_characters.clear();
|
m_characters.clear();
|
||||||
m_kerning.clear();
|
m_kerning.clear();
|
||||||
name.dispose();
|
name.dispose();
|
||||||
@ -133,7 +134,7 @@ void SpriteFont::build(const char* file, float sz, const uint32_t* charset)
|
|||||||
dispose();
|
dispose();
|
||||||
|
|
||||||
Font font(file);
|
Font font(file);
|
||||||
if (font.IsValid())
|
if (font.is_valid())
|
||||||
build(font, sz, charset);
|
build(font, sz, charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,12 +142,12 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset)
|
|||||||
{
|
{
|
||||||
dispose();
|
dispose();
|
||||||
|
|
||||||
float scale = font.GetScale(size);
|
float scale = font.get_scale(size);
|
||||||
|
|
||||||
name = font.FamilyName();
|
name = font.family_name();
|
||||||
ascent = font.Ascent() * scale;
|
ascent = font.ascent() * scale;
|
||||||
descent = font.Descent() * scale;
|
descent = font.descent() * scale;
|
||||||
line_gap = font.LineGap() * scale;
|
line_gap = font.line_gap() * scale;
|
||||||
this->size = size;
|
this->size = size;
|
||||||
|
|
||||||
Packer packer;
|
Packer packer;
|
||||||
@ -156,7 +157,7 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset)
|
|||||||
packer.power_of_two = true;
|
packer.power_of_two = true;
|
||||||
|
|
||||||
std::unordered_map<uint32_t, int> glyphs;
|
std::unordered_map<uint32_t, int> glyphs;
|
||||||
List<Color> buffer;
|
Vector<Color> buffer;
|
||||||
|
|
||||||
auto ranges = charset;
|
auto ranges = charset;
|
||||||
while (*ranges != 0)
|
while (*ranges != 0)
|
||||||
@ -168,36 +169,36 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset)
|
|||||||
|
|
||||||
for (auto i = from; i < to; i++)
|
for (auto i = from; i < to; i++)
|
||||||
{
|
{
|
||||||
auto glyph = font.GetGlyph(i);
|
auto glyph = font.get_glyph(i);
|
||||||
if (glyph <= 0)
|
if (glyph <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
glyphs[i] = glyph;
|
glyphs[i] = glyph;
|
||||||
|
|
||||||
// add character
|
// add character
|
||||||
Font::Char ch = font.GetCharacter(glyph, scale);
|
Font::Char ch = font.get_character(glyph, scale);
|
||||||
m_characters[i].advance = ch.advance;
|
m_characters[i].advance = ch.advance;
|
||||||
m_characters[i].offset = Vec2(ch.offsetX, ch.offsetY);
|
m_characters[i].offset = Vec2(ch.offset_x, ch.offset_y);
|
||||||
|
|
||||||
// pack glyph
|
// pack glyph
|
||||||
if (ch.hasGlyph)
|
if (ch.has_glyph)
|
||||||
{
|
{
|
||||||
if (buffer.count() < ch.width * ch.height)
|
if (buffer.size() < ch.width * ch.height)
|
||||||
buffer.expand(ch.width * ch.height - buffer.count());
|
buffer.resize(ch.width * ch.height);
|
||||||
|
|
||||||
if (font.GetBitmap(ch, buffer.begin()))
|
if (font.get_image(ch, buffer.data()))
|
||||||
packer.add(i, ch.width, ch.height, buffer.begin());
|
packer.add(i, ch.width, ch.height, buffer.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ranges += 2;
|
ranges += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.dispose();
|
buffer.clear();
|
||||||
packer.pack();
|
packer.pack();
|
||||||
|
|
||||||
for (auto& it : packer.pages)
|
for (auto& it : packer.pages)
|
||||||
m_atlas.add(Graphics::create_texture(it));
|
m_atlas.push_back(Graphics::create_texture(it));
|
||||||
|
|
||||||
// add character subtextures
|
// add character subtextures
|
||||||
for (auto& it : packer.entries)
|
for (auto& it : packer.entries)
|
||||||
@ -208,7 +209,7 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset)
|
|||||||
for (auto a = glyphs.begin(); a != glyphs.end(); a++)
|
for (auto a = glyphs.begin(); a != glyphs.end(); a++)
|
||||||
for (auto b = glyphs.begin(); b != glyphs.end(); b++)
|
for (auto b = glyphs.begin(); b != glyphs.end(); b++)
|
||||||
{
|
{
|
||||||
auto kern = font.GetKerning(a->second, b->second, scale);
|
auto kern = font.get_kerning(a->second, b->second, scale);
|
||||||
if (kern != 0)
|
if (kern != 0)
|
||||||
set_kerning(a->first, b->first, kern);
|
set_kerning(a->first, b->first, kern);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <blah/containers/list.h>
|
|
||||||
#include <blah/containers/str.h>
|
#include <blah/containers/str.h>
|
||||||
|
#include <blah/containers/vector.h>
|
||||||
#include <blah/drawing/subtexture.h>
|
#include <blah/drawing/subtexture.h>
|
||||||
#include <blah/math/vec2.h>
|
#include <blah/math/vec2.h>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -25,7 +25,7 @@ namespace Blah
|
|||||||
std::unordered_map<uint64_t, float> m_kerning;
|
std::unordered_map<uint64_t, float> m_kerning;
|
||||||
|
|
||||||
// built texture
|
// built texture
|
||||||
List<TextureRef> m_atlas;
|
Vector<TextureRef> m_atlas;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const uint32_t* ASCII;
|
static const uint32_t* ASCII;
|
||||||
@ -56,7 +56,7 @@ namespace Blah
|
|||||||
float height() const { return ascent - descent; }
|
float height() const { return ascent - descent; }
|
||||||
float line_height() const { return ascent - descent + line_gap; }
|
float line_height() const { return ascent - descent + line_gap; }
|
||||||
|
|
||||||
List<TextureRef>& textures() { return m_atlas; }
|
const Vector<TextureRef>& textures() { return m_atlas; }
|
||||||
|
|
||||||
float width_of(const String& text) const;
|
float width_of(const String& text) const;
|
||||||
float width_of_line(const String& text, int start = 0) const;
|
float width_of_line(const String& text, int start = 0) const;
|
||||||
|
@ -28,9 +28,9 @@ bool Directory::remove(const FilePath& path)
|
|||||||
return Internal::Platform::dir_delete(path.cstr());
|
return Internal::Platform::dir_delete(path.cstr());
|
||||||
}
|
}
|
||||||
|
|
||||||
List<FilePath> Directory::enumerate(const FilePath& path, bool recursive)
|
Vector<FilePath> Directory::enumerate(const FilePath& path, bool recursive)
|
||||||
{
|
{
|
||||||
List<FilePath> list;
|
Vector<FilePath> list;
|
||||||
|
|
||||||
// get files
|
// get files
|
||||||
Internal::Platform::dir_enumerate(list, path.cstr(), recursive);
|
Internal::Platform::dir_enumerate(list, path.cstr(), recursive);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <blah/containers/list.h>
|
|
||||||
#include <blah/containers/str.h>
|
#include <blah/containers/str.h>
|
||||||
|
#include <blah/containers/vector.h>
|
||||||
|
|
||||||
namespace Blah
|
namespace Blah
|
||||||
{
|
{
|
||||||
@ -19,7 +19,7 @@ namespace Blah
|
|||||||
bool create(const FilePath& path);
|
bool create(const FilePath& path);
|
||||||
bool exists(const FilePath& path);
|
bool exists(const FilePath& path);
|
||||||
bool remove(const FilePath& path);
|
bool remove(const FilePath& path);
|
||||||
List<FilePath> enumerate(const FilePath& str, bool recursive = true);
|
Vector<FilePath> enumerate(const FilePath& str, bool recursive = true);
|
||||||
void explore(const FilePath& path);
|
void explore(const FilePath& path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <blah/graphics/graphics.h>
|
#include <blah/graphics/graphics.h>
|
||||||
#include <blah/graphics/texture.h>
|
#include <blah/graphics/texture.h>
|
||||||
#include <blah/containers/stacklist.h>
|
#include <blah/containers/stackvector.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace Blah
|
namespace Blah
|
||||||
{
|
{
|
||||||
typedef StackList<TextureRef, BLAH_ATTACHMENTS> Attachments;
|
typedef StackVector<TextureRef, BLAH_ATTACHMENTS> Attachments;
|
||||||
|
|
||||||
class FrameBuffer
|
class FrameBuffer
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
namespace Blah
|
namespace Blah
|
||||||
{
|
{
|
||||||
class Stream;
|
class Stream;
|
||||||
struct Image;
|
class Image;
|
||||||
|
|
||||||
class Texture;
|
class Texture;
|
||||||
typedef std::shared_ptr<Texture> TextureRef;
|
typedef std::shared_ptr<Texture> TextureRef;
|
||||||
@ -34,10 +34,10 @@ namespace Blah
|
|||||||
|
|
||||||
struct GraphicsInfo
|
struct GraphicsInfo
|
||||||
{
|
{
|
||||||
GfxAPI api;
|
GfxAPI api = GfxAPI::Any;
|
||||||
bool instancing;
|
bool instancing = false;
|
||||||
bool origin_bottom_left;
|
bool origin_bottom_left = false;
|
||||||
int max_texture_size;
|
int max_texture_size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class TextureFilter
|
enum class TextureFilter
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
#include <blah/graphics/material.h>
|
#include <blah/graphics/material.h>
|
||||||
|
#include <blah/log.h>
|
||||||
|
|
||||||
using namespace Blah;
|
using namespace Blah;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
size_t calc_uniform_size(const ShaderUniform& uniform)
|
int calc_uniform_size(const ShaderUniform& uniform)
|
||||||
{
|
{
|
||||||
size_t components = 0;
|
int components = 0;
|
||||||
|
|
||||||
switch (uniform.type)
|
switch (uniform.type)
|
||||||
{
|
{
|
||||||
@ -39,7 +40,7 @@ Material::Material(const ShaderRef& shader)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Uniforms uniforms = shader->uniforms();
|
Uniforms uniforms = shader->uniforms();
|
||||||
StackList<size_t, BLAH_UNIFORMS> float_offsets;
|
StackVector<size_t, BLAH_UNIFORMS> float_offsets;
|
||||||
size_t float_size = 0;
|
size_t float_size = 0;
|
||||||
|
|
||||||
for (auto& uniform : uniforms)
|
for (auto& uniform : uniforms)
|
||||||
@ -50,11 +51,11 @@ Material::Material(const ShaderRef& shader)
|
|||||||
if (uniform.type == UniformType::Texture)
|
if (uniform.type == UniformType::Texture)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < uniform.array_length; i ++)
|
for (int i = 0; i < uniform.array_length; i ++)
|
||||||
m_textures.add(TextureRef());
|
m_textures.push_back(TextureRef());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float_offsets.add(float_size);
|
float_offsets.push_back(float_size);
|
||||||
float_size += calc_uniform_size(uniform);
|
float_size += calc_uniform_size(uniform);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ Material::Material(const ShaderRef& shader)
|
|||||||
memset(m_data, 0, sizeof(float) * float_size);
|
memset(m_data, 0, sizeof(float) * float_size);
|
||||||
|
|
||||||
for (auto& it : float_offsets)
|
for (auto& it : float_offsets)
|
||||||
m_floats.add(m_data + it);
|
m_floats.push_back(m_data + it);
|
||||||
}
|
}
|
||||||
|
|
||||||
Material::~Material()
|
Material::~Material()
|
||||||
@ -80,7 +81,7 @@ void Material::set_texture(const char* name, const TextureRef& texture, int inde
|
|||||||
BLAH_ASSERT(!m_disposed, "Material has been disposed");
|
BLAH_ASSERT(!m_disposed, "Material has been disposed");
|
||||||
BLAH_ASSERT(m_shader && m_shader->is_valid(), "Material Shader is invalid");
|
BLAH_ASSERT(m_shader && m_shader->is_valid(), "Material Shader is invalid");
|
||||||
|
|
||||||
if (m_textures.count() > 0)
|
if (m_textures.size() > 0)
|
||||||
{
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for (auto& uniform : m_shader->uniforms())
|
for (auto& uniform : m_shader->uniforms())
|
||||||
@ -95,7 +96,7 @@ void Material::set_texture(const char* name, const TextureRef& texture, int inde
|
|||||||
}
|
}
|
||||||
|
|
||||||
offset += uniform.array_length;
|
offset += uniform.array_length;
|
||||||
if (offset + index >= m_textures.count())
|
if (offset + index >= m_textures.size())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,7 +119,7 @@ TextureRef Material::get_texture(const char* name, int index) const
|
|||||||
return m_textures[offset + index];
|
return m_textures[offset + index];
|
||||||
|
|
||||||
offset += uniform.array_length;
|
offset += uniform.array_length;
|
||||||
if (offset + index >= m_textures.count())
|
if (offset + index >= m_textures.size())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +142,7 @@ TextureRef Material::get_texture(int slot, int index) const
|
|||||||
return m_textures[offset + index];
|
return m_textures[offset + index];
|
||||||
|
|
||||||
offset += uniform.array_length;
|
offset += uniform.array_length;
|
||||||
if (offset + index >= m_textures.count())
|
if (offset + index >= m_textures.size())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <blah/graphics/texture.h>
|
#include <blah/graphics/texture.h>
|
||||||
#include <blah/graphics/shader.h>
|
#include <blah/graphics/shader.h>
|
||||||
#include <blah/containers/list.h>
|
#include <blah/containers/vector.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace Blah
|
namespace Blah
|
||||||
@ -56,8 +56,8 @@ namespace Blah
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ShaderRef m_shader;
|
ShaderRef m_shader;
|
||||||
List<TextureRef> m_textures;
|
Vector<TextureRef> m_textures;
|
||||||
List<float*> m_floats;
|
Vector<float*> m_floats;
|
||||||
float* m_data;
|
float* m_data;
|
||||||
bool m_disposed;
|
bool m_disposed;
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <blah/graphics/graphics.h>
|
#include <blah/graphics/graphics.h>
|
||||||
#include <blah/containers/stacklist.h>
|
#include <blah/containers/stackvector.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace Blah
|
namespace Blah
|
||||||
{
|
{
|
||||||
typedef StackList<ShaderUniform, BLAH_UNIFORMS> Uniforms;
|
typedef StackVector<ShaderUniform, BLAH_UNIFORMS> Uniforms;
|
||||||
typedef StackList<ShaderAttribute, BLAH_ATTRIBUTES> Attributes;
|
typedef StackVector<ShaderAttribute, BLAH_ATTRIBUTES> Attributes;
|
||||||
|
|
||||||
class Shader
|
class Shader
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <blah/images/aseprite.h>
|
#include <blah/images/aseprite.h>
|
||||||
#include <blah/streams/filestream.h>
|
#include <blah/streams/filestream.h>
|
||||||
|
#include <blah/log.h>
|
||||||
|
|
||||||
#define STBI_NO_STDIO
|
#define STBI_NO_STDIO
|
||||||
#define STBI_NO_JPEG
|
#define STBI_NO_JPEG
|
||||||
@ -99,7 +100,7 @@ void Aseprite::Parse(Stream& stream)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int frameCount = 0;
|
int frame_count = 0;
|
||||||
|
|
||||||
// header
|
// header
|
||||||
{
|
{
|
||||||
@ -115,7 +116,7 @@ void Aseprite::Parse(Stream& stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// main info
|
// main info
|
||||||
frameCount = stream.read<uint16_t>(Endian::Little);
|
frame_count = stream.read<uint16_t>(Endian::Little);
|
||||||
width = stream.read<uint16_t>(Endian::Little);
|
width = stream.read<uint16_t>(Endian::Little);
|
||||||
height = stream.read<uint16_t>(Endian::Little);
|
height = stream.read<uint16_t>(Endian::Little);
|
||||||
mode = static_cast<Aseprite::Modes>(stream.read<uint16_t>(Endian::Little) / 8);
|
mode = static_cast<Aseprite::Modes>(stream.read<uint16_t>(Endian::Little) / 8);
|
||||||
@ -133,10 +134,10 @@ void Aseprite::Parse(Stream& stream)
|
|||||||
stream.seek(stream.position() + 92); // For Future
|
stream.seek(stream.position() + 92); // For Future
|
||||||
}
|
}
|
||||||
|
|
||||||
frames.expand(frameCount);
|
frames.resize(frame_count);
|
||||||
|
|
||||||
// frames
|
// frames
|
||||||
for (int i = 0; i < frameCount; i++)
|
for (int i = 0; i < frame_count; i++)
|
||||||
{
|
{
|
||||||
auto frameStart = stream.position();
|
auto frameStart = stream.position();
|
||||||
auto frameEnd = frameStart + stream.read<uint32_t>(Endian::Little);
|
auto frameEnd = frameStart + stream.read<uint32_t>(Endian::Little);
|
||||||
@ -192,35 +193,38 @@ void Aseprite::Parse(Stream& stream)
|
|||||||
|
|
||||||
void Aseprite::ParseLayer(Stream& stream, int frame)
|
void Aseprite::ParseLayer(Stream& stream, int frame)
|
||||||
{
|
{
|
||||||
auto layer = layers.expand(1);
|
layers.emplace_back();
|
||||||
layer->flag = static_cast<LayerFlags>(stream.read<uint16_t>(Endian::Little));
|
|
||||||
layer->visible = ((int)layer->flag & (int)LayerFlags::Visible) == (int)LayerFlags::Visible;
|
auto& layer = layers.back();
|
||||||
layer->type = static_cast<LayerTypes>(stream.read<uint16_t>(Endian::Little));
|
layer.flag = static_cast<LayerFlags>(stream.read<uint16_t>(Endian::Little));
|
||||||
layer->child_level = stream.read<uint16_t>(Endian::Little);
|
layer.visible = ((int)layer.flag & (int)LayerFlags::Visible) == (int)LayerFlags::Visible;
|
||||||
|
layer.type = static_cast<LayerTypes>(stream.read<uint16_t>(Endian::Little));
|
||||||
|
layer.child_level = stream.read<uint16_t>(Endian::Little);
|
||||||
stream.read<uint16_t>(Endian::Little); // width
|
stream.read<uint16_t>(Endian::Little); // width
|
||||||
stream.read<uint16_t>(Endian::Little); // height
|
stream.read<uint16_t>(Endian::Little); // height
|
||||||
layer->blendmode = stream.read<uint16_t>(Endian::Little);
|
layer.blendmode = stream.read<uint16_t>(Endian::Little);
|
||||||
layer->alpha = stream.read<uint8_t>(Endian::Little);
|
layer.alpha = stream.read<uint8_t>(Endian::Little);
|
||||||
stream.seek(stream.position() + 3); // for future
|
stream.seek(stream.position() + 3); // for future
|
||||||
|
|
||||||
layer->name.set_length(stream.read<uint16_t>(Endian::Little));
|
layer.name.set_length(stream.read<uint16_t>(Endian::Little));
|
||||||
stream.read(layer->name.cstr(), layer->name.length());
|
stream.read(layer.name.cstr(), layer.name.length());
|
||||||
|
|
||||||
layer->userdata.color = 0xffffff;
|
layer.userdata.color = 0xffffff;
|
||||||
layer->userdata.text = "";
|
layer.userdata.text = "";
|
||||||
last_userdata = &(layer->userdata);
|
last_userdata = &(layer.userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition)
|
void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition)
|
||||||
{
|
{
|
||||||
Frame& frame = frames[frameIndex];
|
Frame& frame = frames[frameIndex];
|
||||||
|
|
||||||
auto cel = frame.cels.expand(1);
|
frame.cels.emplace_back();
|
||||||
cel->layer_index = stream.read<uint16_t>(Endian::Little);
|
auto& cel = frame.cels.back();
|
||||||
cel->x = stream.read<uint16_t>(Endian::Little);
|
cel.layer_index = stream.read<uint16_t>(Endian::Little);
|
||||||
cel->y = stream.read<uint16_t>(Endian::Little);
|
cel.x = stream.read<uint16_t>(Endian::Little);
|
||||||
cel->alpha = stream.read<uint8_t>(Endian::Little);
|
cel.y = stream.read<uint16_t>(Endian::Little);
|
||||||
cel->linked_frame_index = -1;
|
cel.alpha = stream.read<uint8_t>(Endian::Little);
|
||||||
|
cel.linked_frame_index = -1;
|
||||||
|
|
||||||
auto celType = stream.read<uint16_t>(Endian::Little);
|
auto celType = stream.read<uint16_t>(Endian::Little);
|
||||||
stream.seek(stream.position() + 7);
|
stream.seek(stream.position() + 7);
|
||||||
@ -232,12 +236,12 @@ void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition)
|
|||||||
auto height = stream.read<uint16_t>(Endian::Little);
|
auto height = stream.read<uint16_t>(Endian::Little);
|
||||||
auto count = width * height * (int)mode;
|
auto count = width * height * (int)mode;
|
||||||
|
|
||||||
cel->image = Image(width, height);
|
cel.image = Image(width, height);
|
||||||
|
|
||||||
// RAW
|
// RAW
|
||||||
if (celType == 0)
|
if (celType == 0)
|
||||||
{
|
{
|
||||||
stream.read(cel->image.pixels, count);
|
stream.read(cel.image.pixels, count);
|
||||||
}
|
}
|
||||||
// DEFLATE (zlib)
|
// DEFLATE (zlib)
|
||||||
else
|
else
|
||||||
@ -252,7 +256,7 @@ void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition)
|
|||||||
stream.read(buffer, size);
|
stream.read(buffer, size);
|
||||||
|
|
||||||
int olen = width * height * sizeof(Color);
|
int olen = width * height * sizeof(Color);
|
||||||
int res = stbi_zlib_decode_buffer((char*)cel->image.pixels, olen, buffer, (int)size);
|
int res = stbi_zlib_decode_buffer((char*)cel.image.pixels, olen, buffer, (int)size);
|
||||||
|
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
|
|
||||||
@ -267,15 +271,15 @@ void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition)
|
|||||||
// note: we work in-place to save having to store stuff in a buffer
|
// note: we work in-place to save having to store stuff in a buffer
|
||||||
if (mode == Modes::Grayscale)
|
if (mode == Modes::Grayscale)
|
||||||
{
|
{
|
||||||
auto src = (unsigned char*)cel->image.pixels;
|
auto src = (unsigned char*)cel.image.pixels;
|
||||||
auto dst = cel->image.pixels;
|
auto dst = cel.image.pixels;
|
||||||
for (int d = width * height - 1, s = (width * height - 1) * 2; d >= 0; d--, s -= 2)
|
for (int d = width * height - 1, s = (width * height - 1) * 2; d >= 0; d--, s -= 2)
|
||||||
dst[d] = Color(src[s], src[s], src[s], src[s + 1]);
|
dst[d] = Color(src[s], src[s], src[s], src[s + 1]);
|
||||||
}
|
}
|
||||||
else if (mode == Modes::Indexed)
|
else if (mode == Modes::Indexed)
|
||||||
{
|
{
|
||||||
auto src = (unsigned char*)cel->image.pixels;
|
auto src = (unsigned char*)cel.image.pixels;
|
||||||
auto dst = cel->image.pixels;
|
auto dst = cel.image.pixels;
|
||||||
for (int i = width * height - 1; i >= 0; i--)
|
for (int i = width * height - 1; i >= 0; i--)
|
||||||
dst[i] = palette[src[i]];
|
dst[i] = palette[src[i]];
|
||||||
}
|
}
|
||||||
@ -285,18 +289,18 @@ void Aseprite::ParseCel(Stream& stream, int frameIndex, size_t maxPosition)
|
|||||||
// this cel directly references a previous cel
|
// this cel directly references a previous cel
|
||||||
else if (celType == 1)
|
else if (celType == 1)
|
||||||
{
|
{
|
||||||
cel->linked_frame_index = stream.read<uint16_t>(Endian::Little);
|
cel.linked_frame_index = stream.read<uint16_t>(Endian::Little);
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw to frame if visible
|
// draw to frame if visible
|
||||||
if ((int)layers[cel->layer_index].flag & (int)LayerFlags::Visible)
|
if ((int)layers[cel.layer_index].flag & (int)LayerFlags::Visible)
|
||||||
{
|
{
|
||||||
RenderCel(cel, &frame);
|
RenderCel(&cel, &frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
cel->userdata.color = 0xffffff;
|
cel.userdata.color = 0xffffff;
|
||||||
cel->userdata.text = "";
|
cel.userdata.text = "";
|
||||||
last_userdata = &(cel->userdata);
|
last_userdata = &(cel.userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Aseprite::ParsePalette(Stream& stream, int frame)
|
void Aseprite::ParsePalette(Stream& stream, int frame)
|
||||||
@ -306,7 +310,7 @@ void Aseprite::ParsePalette(Stream& stream, int frame)
|
|||||||
auto end = stream.read<uint32_t>(Endian::Little);
|
auto end = stream.read<uint32_t>(Endian::Little);
|
||||||
stream.seek(stream.position() + 8);
|
stream.seek(stream.position() + 8);
|
||||||
|
|
||||||
palette.expand(palette.count() + (end - start + 1));
|
palette.resize(palette.size() + (end - start + 1));
|
||||||
|
|
||||||
for (int p = 0, len = static_cast<int>(end - start) + 1; p < len; p++)
|
for (int p = 0, len = static_cast<int>(end - start) + 1; p < len; p++)
|
||||||
{
|
{
|
||||||
@ -348,17 +352,19 @@ void Aseprite::ParseTag(Stream& stream, int frame)
|
|||||||
|
|
||||||
for (int t = 0; t < count; t++)
|
for (int t = 0; t < count; t++)
|
||||||
{
|
{
|
||||||
auto tag = tags.expand(1);
|
Tag tag;
|
||||||
tag->from = stream.read<uint16_t>(Endian::Little);
|
tag.from = stream.read<uint16_t>(Endian::Little);
|
||||||
tag->to = stream.read<uint16_t>(Endian::Little);
|
tag.to = stream.read<uint16_t>(Endian::Little);
|
||||||
tag->loops = static_cast<LoopDirections>(stream.read<int8_t>(Endian::Little));
|
tag.loops = static_cast<LoopDirections>(stream.read<int8_t>(Endian::Little));
|
||||||
|
|
||||||
stream.seek(stream.position() + 8);
|
stream.seek(stream.position() + 8);
|
||||||
tag->color = Color(stream.read<int8_t>(), stream.read<int8_t>(), stream.read<int8_t>(Endian::Little), 255);
|
tag.color = Color(stream.read<int8_t>(), stream.read<int8_t>(), stream.read<int8_t>(Endian::Little), 255);
|
||||||
stream.seek(stream.position() + 1);
|
stream.seek(stream.position() + 1);
|
||||||
|
|
||||||
tag->name.set_length(stream.read<uint16_t>(Endian::Little));
|
tag.name.set_length(stream.read<uint16_t>(Endian::Little));
|
||||||
stream.read(tag->name.cstr(), tag->name.length());
|
stream.read(tag.name.cstr(), tag.name.length());
|
||||||
|
|
||||||
|
tags.push_back(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,13 +380,15 @@ void Aseprite::ParseSlice(Stream& stream, int frame)
|
|||||||
|
|
||||||
for (int s = 0; s < count; s++)
|
for (int s = 0; s < count; s++)
|
||||||
{
|
{
|
||||||
auto slice = slices.expand(1);
|
slices.emplace_back();
|
||||||
slice->name = name;
|
|
||||||
slice->frame = stream.read<uint32_t>(Endian::Little);
|
auto& slice = slices.back();
|
||||||
slice->origin.x = stream.read<int32_t>(Endian::Little);
|
slice.name = name;
|
||||||
slice->origin.y = stream.read<int32_t>(Endian::Little);
|
slice.frame = stream.read<uint32_t>(Endian::Little);
|
||||||
slice->width = stream.read<uint32_t>(Endian::Little);
|
slice.origin.x = stream.read<int32_t>(Endian::Little);
|
||||||
slice->height = stream.read<uint32_t>(Endian::Little);
|
slice.origin.y = stream.read<int32_t>(Endian::Little);
|
||||||
|
slice.width = stream.read<uint32_t>(Endian::Little);
|
||||||
|
slice.height = stream.read<uint32_t>(Endian::Little);
|
||||||
|
|
||||||
// 9 slice (ignored atm)
|
// 9 slice (ignored atm)
|
||||||
if (flags & (1 << 0))
|
if (flags & (1 << 0))
|
||||||
@ -392,17 +400,17 @@ void Aseprite::ParseSlice(Stream& stream, int frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// pivot point
|
// pivot point
|
||||||
slice->has_pivot = false;
|
slice.has_pivot = false;
|
||||||
if (flags & (1 << 1))
|
if (flags & (1 << 1))
|
||||||
{
|
{
|
||||||
slice->has_pivot = true;
|
slice.has_pivot = true;
|
||||||
slice->pivot.x = stream.read<uint32_t>(Endian::Little);
|
slice.pivot.x = stream.read<uint32_t>(Endian::Little);
|
||||||
slice->pivot.y = stream.read<uint32_t>(Endian::Little);
|
slice.pivot.y = stream.read<uint32_t>(Endian::Little);
|
||||||
}
|
}
|
||||||
|
|
||||||
slice->userdata.color = 0xffffff;
|
slice.userdata.color = 0xffffff;
|
||||||
slice->userdata.text = "";
|
slice.userdata.text = "";
|
||||||
last_userdata = &(slice->userdata);
|
last_userdata = &(slice.userdata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include <blah/math/color.h>
|
#include <blah/math/color.h>
|
||||||
#include <blah/images/image.h>
|
#include <blah/images/image.h>
|
||||||
#include <blah/containers/str.h>
|
#include <blah/containers/str.h>
|
||||||
#include <blah/containers/list.h>
|
|
||||||
#include <blah/streams/stream.h>
|
#include <blah/streams/stream.h>
|
||||||
|
|
||||||
namespace Blah
|
namespace Blah
|
||||||
@ -80,7 +79,7 @@ namespace Blah
|
|||||||
{
|
{
|
||||||
int duration = 0;
|
int duration = 0;
|
||||||
Image image;
|
Image image;
|
||||||
List<Cel> cels;
|
Vector<Cel> cels;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Layer
|
struct Layer
|
||||||
@ -121,11 +120,11 @@ namespace Blah
|
|||||||
int width = 0;
|
int width = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
|
|
||||||
List<Layer> layers;
|
Vector<Layer> layers;
|
||||||
List<Frame> frames;
|
Vector<Frame> frames;
|
||||||
List<Tag> tags;
|
Vector<Tag> tags;
|
||||||
List<Slice> slices;
|
Vector<Slice> slices;
|
||||||
List<Color> palette;
|
Vector<Color> palette;
|
||||||
|
|
||||||
Aseprite();
|
Aseprite();
|
||||||
Aseprite(const char* path);
|
Aseprite(const char* path);
|
||||||
|
@ -31,60 +31,60 @@ String GetName(stbtt_fontinfo* font, int nameId)
|
|||||||
|
|
||||||
Font::Font()
|
Font::Font()
|
||||||
{
|
{
|
||||||
font = nullptr;
|
m_font = nullptr;
|
||||||
data = nullptr;
|
m_data = nullptr;
|
||||||
ascent = 0;
|
m_ascent = 0;
|
||||||
descent = 0;
|
m_descent = 0;
|
||||||
lineGap = 0;
|
m_line_gap = 0;
|
||||||
valid = false;
|
m_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::Font(Stream& stream) : Font()
|
Font::Font(Stream& stream) : Font()
|
||||||
{
|
{
|
||||||
Load(stream);
|
load(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::Font(const char* path) : Font()
|
Font::Font(const char* path) : Font()
|
||||||
{
|
{
|
||||||
FileStream fs(path, FileMode::Read);
|
FileStream fs(path, FileMode::Read);
|
||||||
if (fs.is_readable())
|
if (fs.is_readable())
|
||||||
Load(fs);
|
load(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::Font(Font&& src) noexcept
|
Font::Font(Font&& src) noexcept
|
||||||
{
|
{
|
||||||
font = src.font;
|
m_font = src.m_font;
|
||||||
data = src.data;
|
m_data = src.m_data;
|
||||||
familyName = src.familyName;
|
m_family_name = src.m_family_name;
|
||||||
styleName = src.styleName;
|
m_style_name = src.m_style_name;
|
||||||
ascent = src.ascent;
|
m_ascent = src.m_ascent;
|
||||||
descent = src.descent;
|
m_descent = src.m_descent;
|
||||||
lineGap = src.lineGap;
|
m_line_gap = src.m_line_gap;
|
||||||
valid = src.valid;
|
m_valid = src.m_valid;
|
||||||
|
|
||||||
src.familyName.clear();
|
src.m_family_name.clear();
|
||||||
src.styleName.clear();
|
src.m_style_name.clear();
|
||||||
src.valid = false;
|
src.m_valid = false;
|
||||||
src.font = nullptr;
|
src.m_font = nullptr;
|
||||||
src.data = nullptr;
|
src.m_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Font& Font::operator=(Font&& src) noexcept
|
Font& Font::operator=(Font&& src) noexcept
|
||||||
{
|
{
|
||||||
font = src.font;
|
m_font = src.m_font;
|
||||||
data = src.data;
|
m_data = src.m_data;
|
||||||
familyName = src.familyName;
|
m_family_name = src.m_family_name;
|
||||||
styleName = src.styleName;
|
m_style_name = src.m_style_name;
|
||||||
ascent = src.ascent;
|
m_ascent = src.m_ascent;
|
||||||
descent = src.descent;
|
m_descent = src.m_descent;
|
||||||
lineGap = src.lineGap;
|
m_line_gap = src.m_line_gap;
|
||||||
valid = src.valid;
|
m_valid = src.m_valid;
|
||||||
|
|
||||||
src.familyName.clear();
|
src.m_family_name.clear();
|
||||||
src.styleName.clear();
|
src.m_style_name.clear();
|
||||||
src.valid = false;
|
src.m_valid = false;
|
||||||
src.font = nullptr;
|
src.m_font = nullptr;
|
||||||
src.data = nullptr;
|
src.m_data = nullptr;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ Font::~Font()
|
|||||||
dispose();
|
dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::Load(Stream& stream)
|
void Font::load(Stream& stream)
|
||||||
{
|
{
|
||||||
dispose();
|
dispose();
|
||||||
|
|
||||||
@ -105,98 +105,99 @@ void Font::Load(Stream& stream)
|
|||||||
|
|
||||||
// create data buffer
|
// create data buffer
|
||||||
auto size = stream.length();
|
auto size = stream.length();
|
||||||
data = new unsigned char[size];
|
m_data = new unsigned char[size];
|
||||||
stream.read(data, size);
|
stream.read(m_data, size);
|
||||||
|
|
||||||
// init font
|
// init font
|
||||||
font = new stbtt_fontinfo();
|
m_font = new stbtt_fontinfo();
|
||||||
auto fn = (stbtt_fontinfo*)font;
|
auto fn = (stbtt_fontinfo*)m_font;
|
||||||
stbtt_InitFont(fn, data, 0);
|
stbtt_InitFont(fn, m_data, 0);
|
||||||
familyName = GetName(fn, 1);
|
m_family_name = GetName(fn, 1);
|
||||||
styleName = GetName(fn, 2);
|
m_style_name = GetName(fn, 2);
|
||||||
|
|
||||||
// properties
|
// properties
|
||||||
stbtt_GetFontVMetrics(fn, &ascent, &descent, &lineGap);
|
stbtt_GetFontVMetrics(fn, &m_ascent, &m_descent, &m_line_gap);
|
||||||
valid = true;
|
m_valid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::dispose()
|
void Font::dispose()
|
||||||
{
|
{
|
||||||
delete (stbtt_fontinfo*)font;
|
delete (stbtt_fontinfo*)m_font;
|
||||||
delete[] data;
|
delete[] m_data;
|
||||||
font = nullptr;
|
m_font = nullptr;
|
||||||
data = nullptr;
|
m_data = nullptr;
|
||||||
familyName.dispose();
|
m_family_name.dispose();
|
||||||
styleName.dispose();
|
m_style_name.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Font::FamilyName() const
|
const char* Font::family_name() const
|
||||||
{
|
{
|
||||||
return familyName.cstr();
|
return m_family_name.cstr();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Font::StyleName() const
|
const char* Font::style_name() const
|
||||||
{
|
{
|
||||||
return styleName.cstr();
|
return m_style_name.cstr();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Font::Ascent() const
|
int Font::ascent() const
|
||||||
{
|
{
|
||||||
return ascent;
|
return m_ascent;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Font::Descent() const
|
int Font::descent() const
|
||||||
{
|
{
|
||||||
return descent;
|
return m_descent;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Font::LineGap() const
|
int Font::line_gap() const
|
||||||
{
|
{
|
||||||
return lineGap;
|
return m_line_gap;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Font::Height() const
|
int Font::height() const
|
||||||
{
|
{
|
||||||
return ascent - descent;
|
return m_ascent - m_descent;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Font::LineHeight() const
|
int Font::line_height() const
|
||||||
{
|
{
|
||||||
return ascent - descent + lineGap;
|
return m_ascent - m_descent + m_line_gap;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Font::GetGlyph(Codepoint codepoint) const
|
int Font::get_glyph(Codepoint codepoint) const
|
||||||
{
|
{
|
||||||
if (font == nullptr)
|
if (!m_font)
|
||||||
return 0;
|
return 0;
|
||||||
return stbtt_FindGlyphIndex((stbtt_fontinfo*)font, codepoint);
|
return stbtt_FindGlyphIndex((stbtt_fontinfo*)m_font, codepoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Font::GetScale(float size) const
|
float Font::get_scale(float size) const
|
||||||
{
|
{
|
||||||
if (font == nullptr)
|
if (!m_font)
|
||||||
return 0;
|
return 0;
|
||||||
return stbtt_ScaleForPixelHeight((stbtt_fontinfo*)font, size);
|
|
||||||
|
return stbtt_ScaleForMappingEmToPixels((stbtt_fontinfo*)m_font, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Font::GetKerning(int glyph1, int glyph2, float scale) const
|
float Font::get_kerning(int glyph1, int glyph2, float scale) const
|
||||||
{
|
{
|
||||||
if (font == nullptr)
|
if (!m_font)
|
||||||
return 0;
|
return 0;
|
||||||
return stbtt_GetGlyphKernAdvance((stbtt_fontinfo*)font, glyph1, glyph2) * scale;
|
return stbtt_GetGlyphKernAdvance((stbtt_fontinfo*)m_font, glyph1, glyph2) * scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::Char Font::GetCharacter(int glyph, float scale) const
|
Font::Char Font::get_character(int glyph, float scale) const
|
||||||
{
|
{
|
||||||
Char ch;
|
Char ch;
|
||||||
|
|
||||||
if (font == nullptr)
|
if (!m_font)
|
||||||
return ch;
|
return ch;
|
||||||
|
|
||||||
int advance, offsetX, x0, y0, x1, y1;
|
int advance, offsetX, x0, y0, x1, y1;
|
||||||
|
|
||||||
stbtt_GetGlyphHMetrics((stbtt_fontinfo*)font, glyph, &advance, &offsetX);
|
stbtt_GetGlyphHMetrics((stbtt_fontinfo*)m_font, glyph, &advance, &offsetX);
|
||||||
stbtt_GetGlyphBitmapBox((stbtt_fontinfo*)font, glyph, scale, scale, &x0, &y0, &x1, &y1);
|
stbtt_GetGlyphBitmapBox((stbtt_fontinfo*)m_font, glyph, scale, scale, &x0, &y0, &x1, &y1);
|
||||||
|
|
||||||
int w = (x1 - x0);
|
int w = (x1 - x0);
|
||||||
int h = (y1 - y0);
|
int h = (y1 - y0);
|
||||||
@ -206,22 +207,22 @@ Font::Char Font::GetCharacter(int glyph, float scale) const
|
|||||||
ch.width = w;
|
ch.width = w;
|
||||||
ch.height = h;
|
ch.height = h;
|
||||||
ch.advance = advance * scale;
|
ch.advance = advance * scale;
|
||||||
ch.offsetX = offsetX * scale;
|
ch.offset_x = offsetX * scale;
|
||||||
ch.offsetY = (float)y0;
|
ch.offset_y = (float)y0;
|
||||||
ch.scale = scale;
|
ch.scale = scale;
|
||||||
ch.hasGlyph = (w > 0 && h > 0 && stbtt_IsGlyphEmpty((stbtt_fontinfo*)font, glyph) == 0);
|
ch.has_glyph = (w > 0 && h > 0 && stbtt_IsGlyphEmpty((stbtt_fontinfo*)m_font, glyph) == 0);
|
||||||
|
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Font::GetBitmap(const Font::Char& ch, Color* pixels) const
|
bool Font::get_image(const Font::Char& ch, Color* pixels) const
|
||||||
{
|
{
|
||||||
if (ch.hasGlyph)
|
if (ch.has_glyph)
|
||||||
{
|
{
|
||||||
// we actually use the image buffer as our temporary buffer, and fill the pixels out backwards after
|
// we actually use the image buffer as our temporary buffer, and fill the pixels out backwards after
|
||||||
// kinda weird but it works & saves creating more memory
|
// kinda weird but it works & saves creating more memory
|
||||||
unsigned char* src = (unsigned char*)pixels;
|
unsigned char* src = (unsigned char*)pixels;
|
||||||
stbtt_MakeGlyphBitmap((stbtt_fontinfo*)font, src, ch.width, ch.height, ch.width, ch.scale, ch.scale, ch.glyph);
|
stbtt_MakeGlyphBitmap((stbtt_fontinfo*)m_font, src, ch.width, ch.height, ch.width, ch.scale, ch.scale, ch.glyph);
|
||||||
|
|
||||||
int len = ch.width * ch.height;
|
int len = ch.width * ch.height;
|
||||||
for (int a = (len - 1) * 4, b = (len - 1); b >= 0; a -= 4, b -= 1)
|
for (int a = (len - 1) * 4, b = (len - 1); b >= 0; a -= 4, b -= 1)
|
||||||
@ -238,7 +239,7 @@ bool Font::GetBitmap(const Font::Char& ch, Color* pixels) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Font::IsValid() const
|
bool Font::is_valid() const
|
||||||
{
|
{
|
||||||
return valid;
|
return m_valid;
|
||||||
}
|
}
|
@ -16,10 +16,10 @@ namespace Blah
|
|||||||
int width = 0;
|
int width = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
float advance = 0;
|
float advance = 0;
|
||||||
float offsetX = 0;
|
float offset_x = 0;
|
||||||
float offsetY = 0;
|
float offset_y = 0;
|
||||||
float scale = 0;
|
float scale = 0;
|
||||||
bool hasGlyph = false;
|
bool has_glyph = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Font();
|
Font();
|
||||||
@ -33,30 +33,30 @@ namespace Blah
|
|||||||
|
|
||||||
void dispose();
|
void dispose();
|
||||||
|
|
||||||
const char* FamilyName() const;
|
const char* family_name() const;
|
||||||
const char* StyleName() const;
|
const char* style_name() const;
|
||||||
int Ascent() const;
|
int ascent() const;
|
||||||
int Descent() const;
|
int descent() const;
|
||||||
int LineGap() const;
|
int line_gap() const;
|
||||||
int Height() const;
|
int height() const;
|
||||||
int LineHeight() const;
|
int line_height() const;
|
||||||
|
|
||||||
int GetGlyph(Codepoint codepoint) const;
|
int get_glyph(Codepoint codepoint) const;
|
||||||
float GetScale(float size) const;
|
float get_scale(float size) const;
|
||||||
float GetKerning(int glyph1, int glyph2, float scale) const;
|
float get_kerning(int glyph1, int glyph2, float scale) const;
|
||||||
Char GetCharacter(int glyph, float scale) const;
|
Char get_character(int glyph, float scale) const;
|
||||||
bool GetBitmap(const Char& ch, Color* pixels) const;
|
bool get_image(const Char& ch, Color* pixels) const;
|
||||||
bool IsValid() const;
|
bool is_valid() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Load(Stream& stream);
|
void load(Stream& stream);
|
||||||
void* font;
|
void* m_font;
|
||||||
unsigned char* data;
|
unsigned char* m_data;
|
||||||
String familyName;
|
String m_family_name;
|
||||||
String styleName;
|
String m_style_name;
|
||||||
int ascent;
|
int m_ascent;
|
||||||
int descent;
|
int m_descent;
|
||||||
int lineGap;
|
int m_line_gap;
|
||||||
bool valid;
|
bool m_valid;
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
#include <blah/images/packer.h>
|
#include <blah/images/packer.h>
|
||||||
|
#include <blah/log.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
@ -59,12 +60,7 @@ void Packer::add_entry(uint64_t id, int w, int h, const Color* pixels)
|
|||||||
{
|
{
|
||||||
dirty = true;
|
dirty = true;
|
||||||
|
|
||||||
Entry* entry = entries.expand(1);
|
Entry entry(id, RectI(0, 0, w, h));
|
||||||
entry->id = id;
|
|
||||||
entry->page = 0;
|
|
||||||
entry->empty = true;
|
|
||||||
entry->frame = RectI(0, 0, w, h);
|
|
||||||
entry->packed = RectI(0, 0, 0, 0);
|
|
||||||
|
|
||||||
// trim
|
// trim
|
||||||
int top = 0, left = 0, right = w, bottom = h;
|
int top = 0, left = 0, right = w, bottom = h;
|
||||||
@ -106,28 +102,30 @@ void Packer::add_entry(uint64_t id, int w, int h, const Color* pixels)
|
|||||||
// pixels actually exist in this source
|
// pixels actually exist in this source
|
||||||
if (right >= left && bottom >= top)
|
if (right >= left && bottom >= top)
|
||||||
{
|
{
|
||||||
entry->empty = false;
|
entry.empty = false;
|
||||||
|
|
||||||
// store size
|
// store size
|
||||||
entry->frame.x = -left;
|
entry.frame.x = -left;
|
||||||
entry->frame.y = -top;
|
entry.frame.y = -top;
|
||||||
entry->packed.w = (right - left);
|
entry.packed.w = (right - left);
|
||||||
entry->packed.h = (bottom - top);
|
entry.packed.h = (bottom - top);
|
||||||
|
|
||||||
// create pixel data
|
// create pixel data
|
||||||
entry->memoryIndex = buffer.position();
|
entry.memory_index = buffer.position();
|
||||||
|
|
||||||
// copy pixels over
|
// copy pixels over
|
||||||
if (entry->packed.w == w && entry->packed.h == h)
|
if (entry.packed.w == w && entry.packed.h == h)
|
||||||
{
|
{
|
||||||
buffer.write((char*)pixels, sizeof(Color) * w * h);
|
buffer.write((char*)pixels, sizeof(Color) * w * h);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = 0; i < entry->packed.h; i++)
|
for (int i = 0; i < entry.packed.h; i++)
|
||||||
buffer.write((char*)(pixels + left + (top + i) * entry->frame.w), sizeof(Color) * entry->packed.w);
|
buffer.write((char*)(pixels + left + (top + i) * entry.frame.w), sizeof(Color) * entry.packed.w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entries.push_back(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Packer::pack()
|
void Packer::pack()
|
||||||
@ -139,16 +137,16 @@ void Packer::pack()
|
|||||||
pages.clear();
|
pages.clear();
|
||||||
|
|
||||||
// only if we have stuff to pack
|
// only if we have stuff to pack
|
||||||
auto count = entries.count();
|
auto count = entries.size();
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
{
|
{
|
||||||
// get all the sources sorted largest -> smallest
|
// get all the sources sorted largest -> smallest
|
||||||
List<Entry*> sources;
|
Vector<Entry*> sources;
|
||||||
{
|
{
|
||||||
sources.expand(count);
|
sources.resize(count);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
for (int i = 0; i < entries.count(); i++)
|
for (int i = 0; i < entries.size(); i++)
|
||||||
sources[index++] = &entries[i];
|
sources[index++] = &entries[i];
|
||||||
|
|
||||||
std::sort(sources.begin(), sources.end(), [](Packer::Entry* a, Packer::Entry* b)
|
std::sort(sources.begin(), sources.end(), [](Packer::Entry* a, Packer::Entry* b)
|
||||||
@ -166,8 +164,8 @@ void Packer::pack()
|
|||||||
|
|
||||||
// we should never need more nodes than source images * 3
|
// we should never need more nodes than source images * 3
|
||||||
// if this causes problems we could change it to use push_back I suppose
|
// if this causes problems we could change it to use push_back I suppose
|
||||||
List<Node> nodes;
|
Vector<Node> nodes;
|
||||||
nodes.expand(count * 4);
|
nodes.resize(count * 4);
|
||||||
|
|
||||||
int packed = 0, page = 0;
|
int packed = 0, page = 0;
|
||||||
while (packed < count)
|
while (packed < count)
|
||||||
@ -259,7 +257,7 @@ void Packer::pack()
|
|||||||
|
|
||||||
// create each page
|
// create each page
|
||||||
{
|
{
|
||||||
pages.add(Image(pageWidth, pageHeight));
|
pages.emplace_back(pageWidth, pageHeight);
|
||||||
|
|
||||||
// copy image data to image
|
// copy image data to image
|
||||||
for (int i = from; i < packed; i++)
|
for (int i = from; i < packed; i++)
|
||||||
@ -268,7 +266,7 @@ void Packer::pack()
|
|||||||
if (!sources[i]->empty)
|
if (!sources[i]->empty)
|
||||||
{
|
{
|
||||||
RectI dst = sources[i]->packed;
|
RectI dst = sources[i]->packed;
|
||||||
Color* src = (Color*)(buffer.data() + sources[i]->memoryIndex);
|
Color* src = (Color*)(buffer.data() + sources[i]->memory_index);
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// Optimize this?
|
// Optimize this?
|
||||||
@ -300,8 +298,8 @@ void Packer::clear()
|
|||||||
|
|
||||||
void Packer::dispose()
|
void Packer::dispose()
|
||||||
{
|
{
|
||||||
pages.dispose();
|
pages.clear();
|
||||||
entries.dispose();
|
entries.clear();
|
||||||
buffer.close();
|
buffer.close();
|
||||||
max_size = 0;
|
max_size = 0;
|
||||||
power_of_two = 0;
|
power_of_two = 0;
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
#include <blah/math/color.h>
|
#include <blah/math/color.h>
|
||||||
#include <blah/math/rectI.h>
|
#include <blah/math/rectI.h>
|
||||||
#include <blah/math/point.h>
|
#include <blah/math/point.h>
|
||||||
#include <blah/containers/list.h>
|
|
||||||
#include <blah/containers/str.h>
|
#include <blah/containers/str.h>
|
||||||
|
#include <blah/containers/vector.h>
|
||||||
#include <blah/streams/bufferstream.h>
|
#include <blah/streams/bufferstream.h>
|
||||||
|
|
||||||
namespace Blah
|
namespace Blah
|
||||||
@ -17,13 +17,16 @@ namespace Blah
|
|||||||
{
|
{
|
||||||
friend class Packer;
|
friend class Packer;
|
||||||
private:
|
private:
|
||||||
int64_t memoryIndex = 0;
|
int64_t memory_index;
|
||||||
public:
|
public:
|
||||||
int page = 0;
|
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
bool empty = true;
|
int page;
|
||||||
RectI packed;
|
bool empty;
|
||||||
RectI frame;
|
RectI frame;
|
||||||
|
RectI packed;
|
||||||
|
|
||||||
|
Entry(uint64_t id, const RectI& frame)
|
||||||
|
: memory_index(0), id(id), page(0), empty(true), frame(frame), packed(0, 0, 0, 0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
int max_size;
|
int max_size;
|
||||||
@ -31,8 +34,8 @@ namespace Blah
|
|||||||
int spacing;
|
int spacing;
|
||||||
int padding;
|
int padding;
|
||||||
|
|
||||||
List<Image> pages;
|
Vector<Image> pages;
|
||||||
List<Entry> entries;
|
Vector<Entry> entries;
|
||||||
|
|
||||||
Packer();
|
Packer();
|
||||||
Packer(int max_size, int spacing, bool power_of_two);
|
Packer(int max_size, int spacing, bool power_of_two);
|
||||||
|
@ -36,11 +36,11 @@ namespace Blah
|
|||||||
|
|
||||||
float abs(float x);
|
float abs(float x);
|
||||||
|
|
||||||
template<class T>
|
template<class T, class U>
|
||||||
T min(T a, T b) { return a < b ? a : b; }
|
T min(T a, U b) { return a < b ? a : b; }
|
||||||
|
|
||||||
template<class T>
|
template<class T, class U>
|
||||||
T max(T a, T b) { return a > b ? a : b; }
|
T max(T a, U b) { return a > b ? a : b; }
|
||||||
|
|
||||||
float floor(float x);
|
float floor(float x);
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <blah/streams/filestream.h>
|
#include <blah/streams/filestream.h>
|
||||||
#include <blah/internal/platform.h>
|
#include <blah/internal/platform.h>
|
||||||
|
#include <blah/log.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
using namespace Blah;
|
using namespace Blah;
|
||||||
|
@ -23,9 +23,9 @@ void Time::pause_for(float time)
|
|||||||
pause_timer = time;
|
pause_timer = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Time::on_interval(float interval, float offset)
|
bool Time::on_interval(float time, float delta, float interval, float offset)
|
||||||
{
|
{
|
||||||
return Time::on_interval(Time::elapsed, Time::delta, interval, offset);
|
return floor((time - offset - delta) / interval) < floor((time - offset) / interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Time::on_interval(float delta, float interval, float offset)
|
bool Time::on_interval(float delta, float interval, float offset)
|
||||||
@ -33,9 +33,9 @@ bool Time::on_interval(float delta, float interval, float offset)
|
|||||||
return Time::on_interval(Time::elapsed, delta, interval, offset);
|
return Time::on_interval(Time::elapsed, delta, interval, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Time::on_interval(float time, float delta, float interval, float offset)
|
bool Time::on_interval(float interval, float offset)
|
||||||
{
|
{
|
||||||
return floor((time - offset - delta) / interval) < floor((time - offset) / interval);
|
return Time::on_interval(Time::elapsed, Time::delta, interval, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Time::on_time(float time, float timestamp)
|
bool Time::on_time(float time, float timestamp)
|
||||||
@ -43,12 +43,12 @@ bool Time::on_time(float time, float timestamp)
|
|||||||
return time >= timestamp && time - Time::delta < timestamp;
|
return time >= timestamp && time - Time::delta < timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Time::between_interval(float interval, float offset)
|
|
||||||
{
|
|
||||||
return between_interval(Time::elapsed, interval, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Time::between_interval(float time, float interval, float offset)
|
bool Time::between_interval(float time, float interval, float offset)
|
||||||
{
|
{
|
||||||
return modf(time - offset, interval * 2) >= interval;
|
return modf(time - offset, interval * 2) >= interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Time::between_interval(float interval, float offset)
|
||||||
|
{
|
||||||
|
return between_interval(Time::elapsed, interval, offset);
|
||||||
|
}
|
||||||
|
@ -24,21 +24,21 @@ namespace Blah
|
|||||||
static void pause_for(float time);
|
static void pause_for(float time);
|
||||||
|
|
||||||
// returns true on the given time interval
|
// returns true on the given time interval
|
||||||
static bool on_interval(float interval, float offset = 0);
|
static bool on_interval(float time, float delta, float interval, float offset);
|
||||||
|
|
||||||
// returns true on the given time interval
|
// returns true on the given time interval
|
||||||
static bool on_interval(float delta, float interval, float offset);
|
static bool on_interval(float delta, float interval, float offset);
|
||||||
|
|
||||||
// returns true on the given time interval
|
// returns true on the given time interval
|
||||||
static bool on_interval(float time, float delta, float interval, float offset);
|
static bool on_interval(float interval, float offset = 0);
|
||||||
|
|
||||||
// returns true when the given timestamp is passed
|
// returns true when the given timestamp is passed
|
||||||
static bool on_time(float time, float timestamp);
|
static bool on_time(float time, float timestamp);
|
||||||
|
|
||||||
// returns true between time intervals
|
// returns true between time intervals
|
||||||
static bool between_interval(float interval, float offset = 0);
|
static bool between_interval(float time, float interval, float offset);
|
||||||
|
|
||||||
// returns true between time intervals
|
// returns true between time intervals
|
||||||
static bool between_interval(float time, float interval, float offset);
|
static bool between_interval(float interval, float offset = 0);
|
||||||
};
|
};
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user