mirror of
				https://github.com/NoelFB/blah.git
				synced 2025-11-04 01:41:34 +08:00 
			
		
		
		
	refactored graphics & streams into single files - easier to maintain & read
This commit is contained in:
		@ -1,7 +1,6 @@
 | 
			
		||||
#include <blah/app.h>
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include <blah/time.h>
 | 
			
		||||
#include <blah/graphics/target.h>
 | 
			
		||||
#include "internal/internal.h"
 | 
			
		||||
#include "internal/platform.h"
 | 
			
		||||
#include "internal/renderer.h"
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,7 @@
 | 
			
		||||
#include <blah/graphics/batch.h>
 | 
			
		||||
#include <blah/graphics/texture.h>
 | 
			
		||||
#include <blah/graphics/target.h>
 | 
			
		||||
#include <blah/graphics/mesh.h>
 | 
			
		||||
#include <blah/graphics/shader.h>
 | 
			
		||||
#include <blah/graphics/material.h>
 | 
			
		||||
#include <blah/drawing/batch.h>
 | 
			
		||||
#include <blah/math/calc.h>
 | 
			
		||||
#include <blah/app.h>
 | 
			
		||||
#include "../internal/internal.h"
 | 
			
		||||
#include <cmath>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
@ -296,7 +290,7 @@ void Batch::render(const TargetRef& target, const Mat4x4f& matrix)
 | 
			
		||||
	m_mesh->index_data(IndexFormat::UInt32, m_indices.data(), m_indices.size());
 | 
			
		||||
	m_mesh->vertex_data(format, m_vertices.data(), m_vertices.size());
 | 
			
		||||
 | 
			
		||||
	RenderPass pass;
 | 
			
		||||
	DrawCall pass;
 | 
			
		||||
	pass.target = target;
 | 
			
		||||
	pass.mesh = m_mesh;
 | 
			
		||||
	pass.has_viewport = false;
 | 
			
		||||
@ -321,7 +315,7 @@ void Batch::render(const TargetRef& target, const Mat4x4f& matrix)
 | 
			
		||||
		render_single_batch(pass, m_batch, matrix);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Batch::render_single_batch(RenderPass& pass, const DrawBatch& b, const Mat4x4f& matrix)
 | 
			
		||||
void Batch::render_single_batch(DrawCall& pass, const DrawBatch& b, const Mat4x4f& matrix)
 | 
			
		||||
{
 | 
			
		||||
	// get the material
 | 
			
		||||
	pass.material = b.material;
 | 
			
		||||
@ -1,7 +1,5 @@
 | 
			
		||||
#include <blah/graphics/spritefont.h>
 | 
			
		||||
#include <blah/images/font.h>
 | 
			
		||||
#include <blah/drawing/spritefont.h>
 | 
			
		||||
#include <blah/images/packer.h>
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
#include <blah/graphics/subtexture.h>
 | 
			
		||||
#include <blah/drawing/subtexture.h>
 | 
			
		||||
#include <blah/math/calc.h>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
#include <blah/filesystem.h>
 | 
			
		||||
#include <blah/streams/filestream.h>
 | 
			
		||||
#include "internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
@ -7,9 +6,13 @@ using namespace Blah;
 | 
			
		||||
FileRef File::open(const FilePath& path, FileMode mode)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_PLATFORM();
 | 
			
		||||
 | 
			
		||||
	FileRef ref;
 | 
			
		||||
	if (App::Internal::platform)
 | 
			
		||||
		return App::Internal::platform->file_open(path.cstr(), mode);
 | 
			
		||||
	return FileRef();
 | 
			
		||||
		ref = App::Internal::platform->file_open(path.cstr(), mode);
 | 
			
		||||
	if (ref)
 | 
			
		||||
		ref->m_mode = mode;
 | 
			
		||||
	return ref;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool File::exists(const FilePath& path)
 | 
			
		||||
@ -28,6 +31,11 @@ bool File::destroy(const FilePath& path)
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FileMode File::mode() const
 | 
			
		||||
{
 | 
			
		||||
	return m_mode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Directory::create(const FilePath& path)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_PLATFORM();
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,211 @@
 | 
			
		||||
#include <blah/graphics/material.h>
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <blah/graphics.h>
 | 
			
		||||
#include "internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
const BlendMode BlendMode::Normal = BlendMode(
 | 
			
		||||
	BlendOp::Add,
 | 
			
		||||
	BlendFactor::One,
 | 
			
		||||
	BlendFactor::OneMinusSrcAlpha,
 | 
			
		||||
	BlendOp::Add,
 | 
			
		||||
	BlendFactor::One,
 | 
			
		||||
	BlendFactor::OneMinusSrcAlpha,
 | 
			
		||||
	BlendMask::RGBA,
 | 
			
		||||
	0xffffffff
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const BlendMode BlendMode::Subtract = BlendMode(
 | 
			
		||||
	BlendOp::ReverseSubtract,
 | 
			
		||||
	BlendFactor::One,
 | 
			
		||||
	BlendFactor::One,
 | 
			
		||||
	BlendOp::Add,
 | 
			
		||||
	BlendFactor::One,
 | 
			
		||||
	BlendFactor::One,
 | 
			
		||||
	BlendMask::RGBA,
 | 
			
		||||
	0xffffffff
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
VertexFormat::VertexFormat(const StackVector<VertexAttribute, 16>& attr, int str)
 | 
			
		||||
{
 | 
			
		||||
	attributes = attr;
 | 
			
		||||
	stride = str;
 | 
			
		||||
 | 
			
		||||
	if (stride <= 0)
 | 
			
		||||
	{
 | 
			
		||||
		stride = 0;
 | 
			
		||||
 | 
			
		||||
		for (auto& it : attributes)
 | 
			
		||||
		{
 | 
			
		||||
			switch (it.type)
 | 
			
		||||
			{
 | 
			
		||||
			case VertexType::None: break;
 | 
			
		||||
			case VertexType::Float: stride += 4; break;
 | 
			
		||||
			case VertexType::Float2: stride += 8; break;
 | 
			
		||||
			case VertexType::Float3: stride += 12; break;
 | 
			
		||||
			case VertexType::Float4: stride += 16; break;
 | 
			
		||||
			case VertexType::Byte4: stride += 4; break;
 | 
			
		||||
			case VertexType::UByte4: stride += 4; break;
 | 
			
		||||
			case VertexType::Short2: stride += 4; break;
 | 
			
		||||
			case VertexType::UShort2: stride += 4; break;
 | 
			
		||||
			case VertexType::Short4: stride += 8; break;
 | 
			
		||||
			case VertexType::UShort4: stride += 8; break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ShaderRef Shader::create(const ShaderData& data)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RENDERER();
 | 
			
		||||
	BLAH_ASSERT(data.vertex.length() > 0, "Must provide a Vertex Shader");
 | 
			
		||||
	BLAH_ASSERT(data.fragment.length() > 0, "Must provide a Fragment Shader");
 | 
			
		||||
	BLAH_ASSERT(data.hlsl_attributes.size() > 0 || App::renderer().type != RendererType::D3D11, "D3D11 Shaders must have hlsl_attributes assigned");
 | 
			
		||||
 | 
			
		||||
	ShaderRef shader;
 | 
			
		||||
 | 
			
		||||
	if (App::Internal::renderer)
 | 
			
		||||
		shader = App::Internal::renderer->create_shader(&data);
 | 
			
		||||
 | 
			
		||||
	// validate the shader
 | 
			
		||||
	if (shader)
 | 
			
		||||
	{
 | 
			
		||||
		auto& uniforms = shader->uniforms();
 | 
			
		||||
 | 
			
		||||
		// make sure its uniforms are valid
 | 
			
		||||
		for (auto& it : uniforms)
 | 
			
		||||
			if (it.type == UniformType::None)
 | 
			
		||||
			{
 | 
			
		||||
				auto error = String::fmt("Uniform '%s' has an invalid type!\n\tOnly Float/Float2/Float3/Float4/Mat3x2/Mat4x4/Texture are allowed!", it.name.cstr());
 | 
			
		||||
				BLAH_ASSERT(false, error.cstr());
 | 
			
		||||
				return ShaderRef();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		// make sure uniform names don't overlap
 | 
			
		||||
		for (int i = 0; i < uniforms.size(); i++)
 | 
			
		||||
			for (int j = i + 1; j < uniforms.size(); j++)
 | 
			
		||||
				if (uniforms[i].name == uniforms[j].name)
 | 
			
		||||
				{
 | 
			
		||||
					auto error = String::fmt("Shader Uniform names '%s' overlap! All Names must be unique.", uniforms[0].name.cstr());
 | 
			
		||||
					BLAH_ASSERT(false, error.cstr());
 | 
			
		||||
					return ShaderRef();
 | 
			
		||||
				}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return shader;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TextureRef Texture::create(const Image& image)
 | 
			
		||||
{
 | 
			
		||||
	return create(image.width, image.height, TextureFormat::RGBA, (unsigned char*)image.pixels);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TextureRef Texture::create(int width, int height, TextureFormat format, unsigned char* data)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RENDERER();
 | 
			
		||||
	BLAH_ASSERT(width > 0 && height > 0, "Texture width and height must be larger than 0");
 | 
			
		||||
	BLAH_ASSERT((int)format > (int)TextureFormat::None && (int)format < (int)TextureFormat::Count, "Invalid texture format");
 | 
			
		||||
 | 
			
		||||
	if (App::Internal::renderer)
 | 
			
		||||
	{
 | 
			
		||||
		auto tex = App::Internal::renderer->create_texture(width, height, format);
 | 
			
		||||
 | 
			
		||||
		if (tex && data != nullptr)
 | 
			
		||||
			tex->set_data(data);
 | 
			
		||||
 | 
			
		||||
		return tex;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return TextureRef();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TextureRef Texture::create(Stream& stream)
 | 
			
		||||
{
 | 
			
		||||
	return create(Image(stream));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TextureRef Texture::create(const FilePath& file)
 | 
			
		||||
{
 | 
			
		||||
	return create(Image(file));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Texture::set_data(const Color* data)
 | 
			
		||||
{
 | 
			
		||||
	if (format() == TextureFormat::RGBA)
 | 
			
		||||
		set_data((u8*)data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Texture::get_data(Color* data)
 | 
			
		||||
{
 | 
			
		||||
	if (format() == TextureFormat::RGBA)
 | 
			
		||||
		get_data((u8*)data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TargetRef Target::create(int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	AttachmentFormats formats;
 | 
			
		||||
	formats.push_back(TextureFormat::RGBA);
 | 
			
		||||
	return create(width, height, formats);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TargetRef Target::create(int width, int height, const AttachmentFormats& textures)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RENDERER();
 | 
			
		||||
	BLAH_ASSERT(width > 0 && height > 0, "Target width and height must be larger than 0");
 | 
			
		||||
	BLAH_ASSERT(textures.size() > 0, "At least one texture must be provided");
 | 
			
		||||
 | 
			
		||||
	int color_count = 0;
 | 
			
		||||
	int depth_count = 0;
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < textures.size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		BLAH_ASSERT((int)textures[i] > (int)TextureFormat::None && (int)textures[i] < (int)TextureFormat::Count, "Invalid texture format");
 | 
			
		||||
 | 
			
		||||
		if (textures[i] == TextureFormat::DepthStencil)
 | 
			
		||||
			depth_count++;
 | 
			
		||||
		else
 | 
			
		||||
			color_count++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BLAH_ASSERT(depth_count <= 1, "Target can only have 1 Depth/Stencil Texture");
 | 
			
		||||
	BLAH_ASSERT(color_count <= Attachments::capacity - 1, "Exceeded maximum Color texture count");
 | 
			
		||||
 | 
			
		||||
	if (App::Internal::renderer)
 | 
			
		||||
		return App::Internal::renderer->create_target(width, height, textures.data(), textures.size());
 | 
			
		||||
 | 
			
		||||
	return TargetRef();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TextureRef& Target::texture(int index)
 | 
			
		||||
{
 | 
			
		||||
	return textures()[index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const TextureRef& Target::texture(int index) const
 | 
			
		||||
{
 | 
			
		||||
	return textures()[index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Target::width() const
 | 
			
		||||
{
 | 
			
		||||
	return textures()[0]->width();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Target::height() const
 | 
			
		||||
{
 | 
			
		||||
	return textures()[0]->height();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MeshRef Mesh::create()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RENDERER();
 | 
			
		||||
 | 
			
		||||
	if (App::Internal::renderer)
 | 
			
		||||
		return App::Internal::renderer->create_mesh();
 | 
			
		||||
 | 
			
		||||
	return MeshRef();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
	int blah_calc_uniform_size(const UniformInfo& uniform)
 | 
			
		||||
@ -42,7 +244,7 @@ Material::Material(const ShaderRef& shader)
 | 
			
		||||
 | 
			
		||||
		if (uniform.type == UniformType::Texture2D)
 | 
			
		||||
		{
 | 
			
		||||
			for (int i = 0; i < uniform.array_length; i ++)
 | 
			
		||||
			for (int i = 0; i < uniform.array_length; i++)
 | 
			
		||||
				m_textures.push_back(TextureRef());
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
@ -412,7 +614,7 @@ const float* Material::get_value(const char* name, i64* length) const
 | 
			
		||||
bool Material::has_value(const char* name) const
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT(m_shader, "Material Shader is invalid");
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	if (name != nullptr && name[0] != '\0')
 | 
			
		||||
	{
 | 
			
		||||
		for (auto& uniform : m_shader->uniforms())
 | 
			
		||||
@ -437,3 +639,93 @@ const float* Material::data() const
 | 
			
		||||
{
 | 
			
		||||
	return m_data.begin();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DrawCall::DrawCall()
 | 
			
		||||
{
 | 
			
		||||
	blend = BlendMode::Normal;
 | 
			
		||||
	target = App::backbuffer();
 | 
			
		||||
	mesh = MeshRef();
 | 
			
		||||
	material = MaterialRef();
 | 
			
		||||
	has_viewport = false;
 | 
			
		||||
	has_scissor = false;
 | 
			
		||||
	viewport = Rectf();
 | 
			
		||||
	scissor = Rectf();
 | 
			
		||||
	index_start = 0;
 | 
			
		||||
	index_count = 0;
 | 
			
		||||
	instance_count = 0;
 | 
			
		||||
	depth = Compare::None;
 | 
			
		||||
	cull = Cull::None;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DrawCall::perform()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RENDERER();
 | 
			
		||||
	BLAH_ASSERT(material, "Trying to draw with an invalid Material");
 | 
			
		||||
	BLAH_ASSERT(material->shader(), "Trying to draw with an invalid Shader");
 | 
			
		||||
	BLAH_ASSERT(mesh, "Trying to draw with an invalid Mesh");
 | 
			
		||||
 | 
			
		||||
	if (!App::Internal::renderer)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	// copy call
 | 
			
		||||
	DrawCall pass = *this;
 | 
			
		||||
 | 
			
		||||
	// Validate Backbuffer
 | 
			
		||||
	if (!pass.target)
 | 
			
		||||
	{
 | 
			
		||||
		pass.target = App::backbuffer();
 | 
			
		||||
		Log::warn("Trying to draw with an invalid Target; falling back to Back Buffer");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Validate Index Count
 | 
			
		||||
	i64 index_count = pass.mesh->index_count();
 | 
			
		||||
	if (pass.index_start + pass.index_count > index_count)
 | 
			
		||||
	{
 | 
			
		||||
		Log::warn(
 | 
			
		||||
			"Trying to draw more indices than exist in the index buffer (%i-%i / %i); trimming extra indices",
 | 
			
		||||
			pass.index_start,
 | 
			
		||||
			pass.index_start + pass.index_count,
 | 
			
		||||
			index_count);
 | 
			
		||||
 | 
			
		||||
		if (pass.index_start > pass.index_count)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		pass.index_count = pass.index_count - pass.index_start;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Validate Instance Count
 | 
			
		||||
	i64 instance_count = pass.mesh->instance_count();
 | 
			
		||||
	if (pass.instance_count > instance_count)
 | 
			
		||||
	{
 | 
			
		||||
		Log::warn(
 | 
			
		||||
			"Trying to draw more instances than exist in the index buffer (%i / %i); trimming extra instances",
 | 
			
		||||
			pass.instance_count,
 | 
			
		||||
			instance_count);
 | 
			
		||||
 | 
			
		||||
		pass.instance_count = instance_count;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// get the total drawable size
 | 
			
		||||
	auto draw_size = Vec2f(pass.target->width(), pass.target->height());
 | 
			
		||||
 | 
			
		||||
	// Validate Viewport
 | 
			
		||||
	if (!pass.has_viewport)
 | 
			
		||||
	{
 | 
			
		||||
		pass.viewport.x = 0;
 | 
			
		||||
		pass.viewport.y = 0;
 | 
			
		||||
		pass.viewport.w = draw_size.x;
 | 
			
		||||
		pass.viewport.h = draw_size.y;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		pass.viewport = pass.viewport.overlap_rect(Rectf(0, 0, draw_size.x, draw_size.y));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Validate Scissor
 | 
			
		||||
	if (pass.has_scissor)
 | 
			
		||||
		pass.scissor = pass.scissor.overlap_rect(Rectf(0, 0, draw_size.x, draw_size.y));
 | 
			
		||||
 | 
			
		||||
	// perform render
 | 
			
		||||
	App::Internal::renderer->render(pass);
 | 
			
		||||
}
 | 
			
		||||
@ -1,25 +0,0 @@
 | 
			
		||||
#include <blah/graphics/blend.h>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
const BlendMode BlendMode::Normal = BlendMode(
 | 
			
		||||
	BlendOp::Add,
 | 
			
		||||
	BlendFactor::One,
 | 
			
		||||
	BlendFactor::OneMinusSrcAlpha,
 | 
			
		||||
	BlendOp::Add,
 | 
			
		||||
	BlendFactor::One,
 | 
			
		||||
	BlendFactor::OneMinusSrcAlpha,
 | 
			
		||||
	BlendMask::RGBA,
 | 
			
		||||
	0xffffffff
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const BlendMode BlendMode::Subtract = BlendMode(
 | 
			
		||||
	BlendOp::ReverseSubtract,
 | 
			
		||||
	BlendFactor::One,
 | 
			
		||||
	BlendFactor::One,
 | 
			
		||||
	BlendOp::Add,
 | 
			
		||||
	BlendFactor::One,
 | 
			
		||||
	BlendFactor::One,
 | 
			
		||||
	BlendMask::RGBA,
 | 
			
		||||
	0xffffffff
 | 
			
		||||
);
 | 
			
		||||
@ -1,44 +0,0 @@
 | 
			
		||||
#include <blah/graphics/mesh.h>
 | 
			
		||||
#include "../internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
MeshRef Mesh::create()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RENDERER();
 | 
			
		||||
 | 
			
		||||
	if (App::Internal::renderer)
 | 
			
		||||
		return App::Internal::renderer->create_mesh();
 | 
			
		||||
 | 
			
		||||
	return MeshRef();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VertexFormat::VertexFormat(const StackVector<VertexAttribute, 16>& attr, int stride)
 | 
			
		||||
{
 | 
			
		||||
	attributes = attr;
 | 
			
		||||
 | 
			
		||||
	if (stride <= 0)
 | 
			
		||||
	{
 | 
			
		||||
		stride = 0;
 | 
			
		||||
 | 
			
		||||
		for (auto& it : attributes)
 | 
			
		||||
		{
 | 
			
		||||
			switch (it.type)
 | 
			
		||||
			{
 | 
			
		||||
			case VertexType::None: break;
 | 
			
		||||
			case VertexType::Float: stride += 4; break;
 | 
			
		||||
			case VertexType::Float2: stride += 8; break;
 | 
			
		||||
			case VertexType::Float3: stride += 12; break;
 | 
			
		||||
			case VertexType::Float4: stride += 16; break;
 | 
			
		||||
			case VertexType::Byte4: stride += 4; break;
 | 
			
		||||
			case VertexType::UByte4: stride += 4; break;
 | 
			
		||||
			case VertexType::Short2: stride += 4; break;
 | 
			
		||||
			case VertexType::UShort2: stride += 4; break;
 | 
			
		||||
			case VertexType::Short4: stride += 8; break;
 | 
			
		||||
			case VertexType::UShort4: stride += 8; break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this->stride = stride;
 | 
			
		||||
}
 | 
			
		||||
@ -1,94 +0,0 @@
 | 
			
		||||
#include <blah/graphics/renderpass.h>
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include "../internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
RenderPass::RenderPass()
 | 
			
		||||
{
 | 
			
		||||
	blend = BlendMode::Normal;
 | 
			
		||||
	target = App::backbuffer();
 | 
			
		||||
	mesh = MeshRef();
 | 
			
		||||
	material = MaterialRef();
 | 
			
		||||
	has_viewport = false;
 | 
			
		||||
	has_scissor = false;
 | 
			
		||||
	viewport = Rectf();
 | 
			
		||||
	scissor = Rectf();
 | 
			
		||||
	index_start = 0;
 | 
			
		||||
	index_count = 0;
 | 
			
		||||
	instance_count = 0;
 | 
			
		||||
	depth = Compare::None;
 | 
			
		||||
	cull = Cull::None;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RenderPass::perform()
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RENDERER();
 | 
			
		||||
	BLAH_ASSERT(material, "Trying to draw with an invalid Material");
 | 
			
		||||
	BLAH_ASSERT(material->shader(), "Trying to draw with an invalid Shader");
 | 
			
		||||
	BLAH_ASSERT(mesh, "Trying to draw with an invalid Mesh");
 | 
			
		||||
 | 
			
		||||
	if (!App::Internal::renderer)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	// copy call
 | 
			
		||||
	RenderPass pass = *this;
 | 
			
		||||
 | 
			
		||||
	// Validate Backbuffer
 | 
			
		||||
	if (!pass.target)
 | 
			
		||||
	{
 | 
			
		||||
		pass.target = App::backbuffer();
 | 
			
		||||
		Log::warn("Trying to draw with an invalid Target; falling back to Back Buffer");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Validate Index Count
 | 
			
		||||
	i64 index_count = pass.mesh->index_count();
 | 
			
		||||
	if (pass.index_start + pass.index_count > index_count)
 | 
			
		||||
	{
 | 
			
		||||
		Log::warn(
 | 
			
		||||
			"Trying to draw more indices than exist in the index buffer (%i-%i / %i); trimming extra indices",
 | 
			
		||||
			pass.index_start,
 | 
			
		||||
			pass.index_start + pass.index_count,
 | 
			
		||||
			index_count);
 | 
			
		||||
 | 
			
		||||
		if (pass.index_start > pass.index_count)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		pass.index_count = pass.index_count - pass.index_start;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Validate Instance Count
 | 
			
		||||
	i64 instance_count = pass.mesh->instance_count();
 | 
			
		||||
	if (pass.instance_count > instance_count)
 | 
			
		||||
	{
 | 
			
		||||
		Log::warn(
 | 
			
		||||
			"Trying to draw more instances than exist in the index buffer (%i / %i); trimming extra instances",
 | 
			
		||||
			pass.instance_count,
 | 
			
		||||
			instance_count);
 | 
			
		||||
 | 
			
		||||
		pass.instance_count = instance_count;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// get the total drawable size
 | 
			
		||||
	auto draw_size = Vec2f(pass.target->width(), pass.target->height());
 | 
			
		||||
 | 
			
		||||
	// Validate Viewport
 | 
			
		||||
	if (!pass.has_viewport)
 | 
			
		||||
	{
 | 
			
		||||
		pass.viewport.x = 0;
 | 
			
		||||
		pass.viewport.y = 0;
 | 
			
		||||
		pass.viewport.w = draw_size.x;
 | 
			
		||||
		pass.viewport.h = draw_size.y;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		pass.viewport = pass.viewport.overlap_rect(Rectf(0, 0, draw_size.x, draw_size.y));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Validate Scissor
 | 
			
		||||
	if (pass.has_scissor)
 | 
			
		||||
		pass.scissor = pass.scissor.overlap_rect(Rectf(0, 0, draw_size.x, draw_size.y));
 | 
			
		||||
 | 
			
		||||
	// perform render
 | 
			
		||||
	App::Internal::renderer->render(pass);
 | 
			
		||||
}
 | 
			
		||||
@ -1,45 +0,0 @@
 | 
			
		||||
#include <blah/graphics/shader.h>
 | 
			
		||||
#include <blah/app.h>
 | 
			
		||||
#include "../internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
ShaderRef Shader::create(const ShaderData& data)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RENDERER();
 | 
			
		||||
	BLAH_ASSERT(data.vertex.length() > 0, "Must provide a Vertex Shader");
 | 
			
		||||
	BLAH_ASSERT(data.fragment.length() > 0, "Must provide a Fragment Shader");
 | 
			
		||||
	BLAH_ASSERT(data.hlsl_attributes.size() > 0 || App::renderer().type != RendererType::D3D11, "D3D11 Shaders must have hlsl_attributes assigned");
 | 
			
		||||
 | 
			
		||||
	ShaderRef shader;
 | 
			
		||||
 | 
			
		||||
	if (App::Internal::renderer)
 | 
			
		||||
		shader = App::Internal::renderer->create_shader(&data);
 | 
			
		||||
	
 | 
			
		||||
	// validate the shader
 | 
			
		||||
	if (shader)
 | 
			
		||||
	{
 | 
			
		||||
		auto& uniforms = shader->uniforms();
 | 
			
		||||
 | 
			
		||||
		// make sure its uniforms are valid
 | 
			
		||||
		for (auto& it : uniforms)
 | 
			
		||||
			if (it.type == UniformType::None)
 | 
			
		||||
			{
 | 
			
		||||
				auto error = String::fmt("Uniform '%s' has an invalid type!\n\tOnly Float/Float2/Float3/Float4/Mat3x2/Mat4x4/Texture are allowed!", it.name.cstr());
 | 
			
		||||
				BLAH_ASSERT(false, error.cstr());
 | 
			
		||||
				return ShaderRef();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		// make sure uniform names don't overlap
 | 
			
		||||
		for (int i = 0; i < uniforms.size(); i ++)
 | 
			
		||||
			for (int j = i + 1; j < uniforms.size(); j ++)
 | 
			
		||||
				if (uniforms[i].name == uniforms[j].name)
 | 
			
		||||
				{
 | 
			
		||||
					auto error = String::fmt("Shader Uniform names '%s' overlap! All Names must be unique.", uniforms[0].name.cstr());
 | 
			
		||||
					BLAH_ASSERT(false, error.cstr());
 | 
			
		||||
					return ShaderRef();
 | 
			
		||||
				}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return shader;
 | 
			
		||||
}
 | 
			
		||||
@ -1,59 +0,0 @@
 | 
			
		||||
#include <blah/graphics/target.h>
 | 
			
		||||
#include "../internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
TargetRef Target::create(int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	AttachmentFormats formats;
 | 
			
		||||
	formats.push_back(TextureFormat::RGBA);
 | 
			
		||||
	return create(width, height, formats);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TargetRef Target::create(int width, int height, const AttachmentFormats& textures)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RENDERER();
 | 
			
		||||
	BLAH_ASSERT(width > 0 && height > 0, "Target width and height must be larger than 0");
 | 
			
		||||
	BLAH_ASSERT(textures.size() > 0, "At least one texture must be provided");
 | 
			
		||||
 | 
			
		||||
	int color_count = 0;
 | 
			
		||||
	int depth_count = 0;
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < textures.size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		BLAH_ASSERT((int)textures[i] > (int)TextureFormat::None && (int)textures[i] < (int)TextureFormat::Count, "Invalid texture format");
 | 
			
		||||
 | 
			
		||||
		if (textures[i] == TextureFormat::DepthStencil)
 | 
			
		||||
			depth_count++;
 | 
			
		||||
		else
 | 
			
		||||
			color_count++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BLAH_ASSERT(depth_count <= 1, "Target can only have 1 Depth/Stencil Texture");
 | 
			
		||||
	BLAH_ASSERT(color_count <= Attachments::capacity - 1, "Exceeded maximum Color texture count");
 | 
			
		||||
 | 
			
		||||
	if (App::Internal::renderer)
 | 
			
		||||
		return App::Internal::renderer->create_target(width, height, textures.data(), textures.size());
 | 
			
		||||
 | 
			
		||||
	return TargetRef();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TextureRef& Target::texture(int index)
 | 
			
		||||
{
 | 
			
		||||
	return textures()[index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const TextureRef& Target::texture(int index) const
 | 
			
		||||
{
 | 
			
		||||
	return textures()[index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Target::width() const
 | 
			
		||||
{
 | 
			
		||||
	return textures()[0]->width();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Target::height() const
 | 
			
		||||
{
 | 
			
		||||
	return textures()[0]->height();
 | 
			
		||||
}
 | 
			
		||||
@ -1,53 +0,0 @@
 | 
			
		||||
#include <blah/graphics/texture.h>
 | 
			
		||||
#include <blah/images/image.h>
 | 
			
		||||
#include <blah/streams/stream.h>
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include "../internal/internal.h"
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
TextureRef Texture::create(const Image& image)
 | 
			
		||||
{
 | 
			
		||||
	return create(image.width, image.height, TextureFormat::RGBA, (unsigned char*)image.pixels);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TextureRef Texture::create(int width, int height, TextureFormat format, unsigned char* data)
 | 
			
		||||
{
 | 
			
		||||
	BLAH_ASSERT_RENDERER();
 | 
			
		||||
	BLAH_ASSERT(width > 0 && height > 0, "Texture width and height must be larger than 0");
 | 
			
		||||
	BLAH_ASSERT((int)format > (int)TextureFormat::None && (int)format < (int)TextureFormat::Count, "Invalid texture format");
 | 
			
		||||
 | 
			
		||||
	if (App::Internal::renderer)
 | 
			
		||||
	{
 | 
			
		||||
		auto tex = App::Internal::renderer->create_texture(width, height, format);
 | 
			
		||||
 | 
			
		||||
		if (tex && data != nullptr)
 | 
			
		||||
			tex->set_data(data);
 | 
			
		||||
 | 
			
		||||
		return tex;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return TextureRef();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TextureRef Texture::create(Stream& stream)
 | 
			
		||||
{
 | 
			
		||||
	return create(Image(stream));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TextureRef Texture::create(const FilePath& file)
 | 
			
		||||
{
 | 
			
		||||
	return create(Image(file));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Texture::set_data(const Color* data)
 | 
			
		||||
{
 | 
			
		||||
	if (format() == TextureFormat::RGBA)
 | 
			
		||||
		set_data((u8*)data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Texture::get_data(Color* data)
 | 
			
		||||
{
 | 
			
		||||
	if (format() == TextureFormat::RGBA)
 | 
			
		||||
		get_data((u8*)data);
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,5 @@
 | 
			
		||||
#include <blah/images/aseprite.h>
 | 
			
		||||
#include <blah/streams/filestream.h>
 | 
			
		||||
#include <blah/filesystem.h>
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include <blah/math/calc.h>
 | 
			
		||||
 | 
			
		||||
#define STBI_NO_STDIO
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,5 @@
 | 
			
		||||
#include <blah/images/font.h>
 | 
			
		||||
#include <blah/streams/filestream.h>
 | 
			
		||||
#include <blah/math/calc.h>
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,4 @@
 | 
			
		||||
#include <blah/images/image.h>
 | 
			
		||||
#include <blah/streams/stream.h>
 | 
			
		||||
#include <blah/streams/filestream.h>
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
#include <blah/images/packer.h>
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,6 @@
 | 
			
		||||
#include <blah/math/calc.h>
 | 
			
		||||
#include "internal/internal.h"
 | 
			
		||||
#include "internal/platform.h"
 | 
			
		||||
#include <blah/graphics/target.h>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include <blah/filesystem.h>
 | 
			
		||||
#include <blah/input.h>
 | 
			
		||||
#include <blah/filesystem.h>
 | 
			
		||||
#include <blah/containers/vector.h>
 | 
			
		||||
 | 
			
		||||
namespace Blah
 | 
			
		||||
 | 
			
		||||
@ -67,8 +67,8 @@ namespace Blah
 | 
			
		||||
		size_t length() override { return SDL_RWsize(handle); }
 | 
			
		||||
		size_t position() override { return SDL_RWtell(handle); }
 | 
			
		||||
		size_t seek(size_t position) override { return SDL_RWseek(handle, position, RW_SEEK_SET); }
 | 
			
		||||
		size_t read(unsigned char* buffer, size_t length) override { return SDL_RWread(handle, buffer, sizeof(char), length); }
 | 
			
		||||
		size_t write(const unsigned char* buffer, size_t length) override { return SDL_RWwrite(handle, buffer, sizeof(char), length); }
 | 
			
		||||
		size_t read(void* buffer, size_t length) override { return SDL_RWread(handle, buffer, sizeof(char), length); }
 | 
			
		||||
		size_t write(const void* buffer, size_t length) override { return SDL_RWwrite(handle, buffer, sizeof(char), length); }
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct SDL2_Platform : public Platform
 | 
			
		||||
 | 
			
		||||
@ -44,8 +44,8 @@ namespace Blah
 | 
			
		||||
		size_t length() override;
 | 
			
		||||
		size_t position() override;
 | 
			
		||||
		size_t seek(size_t position) override;
 | 
			
		||||
		size_t read(unsigned char* buffer, size_t length) override;
 | 
			
		||||
		size_t write(const unsigned char* buffer, size_t length) override;
 | 
			
		||||
		size_t read(void* buffer, size_t length) override;
 | 
			
		||||
		size_t write(const void* buffer, size_t length) override;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct Win32_Platform : public Platform
 | 
			
		||||
@ -181,7 +181,7 @@ size_t Win32File::seek(size_t position)
 | 
			
		||||
	return result.QuadPart;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t Win32File::read(unsigned char* buffer, size_t length)
 | 
			
		||||
size_t Win32File::read(void* buffer, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	static const DWORD read_step = 65536;
 | 
			
		||||
 | 
			
		||||
@ -204,7 +204,7 @@ size_t Win32File::read(unsigned char* buffer, size_t length)
 | 
			
		||||
	return read;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t Win32File::write(const unsigned char* buffer, size_t length)
 | 
			
		||||
size_t Win32File::write(const void* buffer, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	static const DWORD write_step = 65536;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,6 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <blah/app.h>
 | 
			
		||||
#include <blah/graphics/renderpass.h>
 | 
			
		||||
#include <blah/graphics/texture.h>
 | 
			
		||||
#include <blah/graphics/target.h>
 | 
			
		||||
#include <blah/graphics/shader.h>
 | 
			
		||||
#include <blah/graphics/mesh.h>
 | 
			
		||||
#include <blah/graphics/material.h>
 | 
			
		||||
#include <blah/graphics.h>
 | 
			
		||||
#include <blah/math/color.h>
 | 
			
		||||
 | 
			
		||||
namespace Blah
 | 
			
		||||
@ -38,7 +33,7 @@ namespace Blah
 | 
			
		||||
		virtual void after_render() = 0;
 | 
			
		||||
 | 
			
		||||
		// Performs a draw call
 | 
			
		||||
		virtual void render(const RenderPass& pass) = 0;
 | 
			
		||||
		virtual void render(const DrawCall& pass) = 0;
 | 
			
		||||
 | 
			
		||||
		// Clears the backbuffer
 | 
			
		||||
		virtual void clear_backbuffer(Color color, float depth, u8 stencil, ClearMask mask) = 0;
 | 
			
		||||
 | 
			
		||||
@ -136,7 +136,7 @@ namespace Blah
 | 
			
		||||
		void update() override;
 | 
			
		||||
		void before_render() override;
 | 
			
		||||
		void after_render() override;
 | 
			
		||||
		void render(const RenderPass& pass) override;
 | 
			
		||||
		void render(const DrawCall& pass) override;
 | 
			
		||||
		void clear_backbuffer(Color color, float depth, u8 stencil, ClearMask mask) override;
 | 
			
		||||
		TextureRef create_texture(int width, int height, TextureFormat format) override;
 | 
			
		||||
		TargetRef create_target(int width, int height, const TextureFormat* attachments, int attachment_count) override;
 | 
			
		||||
@ -145,9 +145,9 @@ namespace Blah
 | 
			
		||||
 | 
			
		||||
		ID3D11InputLayout* get_layout(D3D11_Shader* shader, const VertexFormat& format);
 | 
			
		||||
		ID3D11BlendState* get_blend(const BlendMode& blend);
 | 
			
		||||
		ID3D11RasterizerState* get_rasterizer(const RenderPass& pass);
 | 
			
		||||
		ID3D11RasterizerState* get_rasterizer(const DrawCall& pass);
 | 
			
		||||
		ID3D11SamplerState* get_sampler(const TextureSampler& sampler);
 | 
			
		||||
		ID3D11DepthStencilState* get_depthstencil(const RenderPass& pass);
 | 
			
		||||
		ID3D11DepthStencilState* get_depthstencil(const DrawCall& pass);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Utility Methods
 | 
			
		||||
@ -947,7 +947,7 @@ namespace Blah
 | 
			
		||||
		return MeshRef(new D3D11_Mesh());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void Renderer_D3D11::render(const RenderPass& pass)
 | 
			
		||||
	void Renderer_D3D11::render(const DrawCall& pass)
 | 
			
		||||
	{
 | 
			
		||||
		auto ctx = context;
 | 
			
		||||
		auto mesh = (D3D11_Mesh*)pass.mesh.get();
 | 
			
		||||
@ -1531,7 +1531,7 @@ namespace Blah
 | 
			
		||||
		return nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ID3D11RasterizerState* Renderer_D3D11::get_rasterizer(const RenderPass& pass)
 | 
			
		||||
	ID3D11RasterizerState* Renderer_D3D11::get_rasterizer(const DrawCall& pass)
 | 
			
		||||
	{
 | 
			
		||||
		for (auto& it : rasterizer_cache)
 | 
			
		||||
			if (it.cull == pass.cull && it.has_scissor == pass.has_scissor)
 | 
			
		||||
@ -1572,7 +1572,7 @@ namespace Blah
 | 
			
		||||
		return nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ID3D11DepthStencilState* Renderer_D3D11::get_depthstencil(const RenderPass& pass)
 | 
			
		||||
	ID3D11DepthStencilState* Renderer_D3D11::get_depthstencil(const DrawCall& pass)
 | 
			
		||||
	{
 | 
			
		||||
		for (auto& it : depthstencil_cache)
 | 
			
		||||
			if (it.depth == pass.depth)
 | 
			
		||||
 | 
			
		||||
@ -418,7 +418,7 @@ namespace Blah
 | 
			
		||||
		void update() override;
 | 
			
		||||
		void before_render() override;
 | 
			
		||||
		void after_render() override;
 | 
			
		||||
		void render(const RenderPass& pass) override;
 | 
			
		||||
		void render(const DrawCall& pass) override;
 | 
			
		||||
		void clear_backbuffer(Color color, float depth, u8 stencil, ClearMask mask) override;
 | 
			
		||||
		TextureRef create_texture(int width, int height, TextureFormat format) override;
 | 
			
		||||
		TargetRef create_target(int width, int height, const TextureFormat* attachments, int attachment_count) override;
 | 
			
		||||
@ -1272,7 +1272,7 @@ namespace Blah
 | 
			
		||||
		return MeshRef(resource);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void Renderer_OpenGL::render(const RenderPass& pass)
 | 
			
		||||
	void Renderer_OpenGL::render(const DrawCall& pass)
 | 
			
		||||
	{
 | 
			
		||||
		// Bind the Target
 | 
			
		||||
		if (pass.target == App::backbuffer())
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,11 @@
 | 
			
		||||
#include <blah/streams/stream.h>
 | 
			
		||||
#include <blah/stream.h>
 | 
			
		||||
#include <blah/containers/str.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
// Stream Base Class Implementation
 | 
			
		||||
 | 
			
		||||
size_t Stream::pipe(Stream& stream, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	const int BUFFER_LENGTH = 4096;
 | 
			
		||||
@ -33,7 +35,6 @@ size_t Stream::read(void* buffer, size_t length)
 | 
			
		||||
	return read_data(buffer, length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// reads a string. if length < 0, assumes null-terminated
 | 
			
		||||
String Stream::read_string(int length)
 | 
			
		||||
{
 | 
			
		||||
	String result;
 | 
			
		||||
@ -204,3 +205,190 @@ size_t Stream::write_f64(double value, Endian endian)
 | 
			
		||||
	return write_data(&value, sizeof(double));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// File Stream Implementation
 | 
			
		||||
 | 
			
		||||
FileStream::FileStream(const FilePath& path, FileMode mode)
 | 
			
		||||
	: m_file(File::open(path, mode)) {}
 | 
			
		||||
 | 
			
		||||
FileStream::FileStream(const FileRef& file)
 | 
			
		||||
	: m_file(file) {}
 | 
			
		||||
 | 
			
		||||
size_t FileStream::length() const
 | 
			
		||||
{
 | 
			
		||||
	return (m_file ? m_file->length() : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t FileStream::position() const
 | 
			
		||||
{
 | 
			
		||||
	return (m_file ? m_file->position() : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t FileStream::seek(size_t seek_to)
 | 
			
		||||
{
 | 
			
		||||
	return (m_file ? m_file->seek(seek_to) : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t FileStream::read_data(void* ptr, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	return (m_file ? m_file->read(ptr, length) : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t FileStream::write_data(const void* ptr, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	return (m_file ? m_file->write(ptr, length) : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FileStream::is_open() const
 | 
			
		||||
{
 | 
			
		||||
	return m_file ? true : false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FileStream::is_readable() const
 | 
			
		||||
{
 | 
			
		||||
	return m_file && m_file->mode() != FileMode::CreateWrite;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FileStream::is_writable() const
 | 
			
		||||
{
 | 
			
		||||
	return m_file && m_file->mode() != FileMode::OpenRead;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Memory Stream Implementation
 | 
			
		||||
 | 
			
		||||
MemoryStream::MemoryStream(u8* data, size_t length)
 | 
			
		||||
	: m_data(data), m_const_data(nullptr), m_length(length), m_position(0) {}
 | 
			
		||||
 | 
			
		||||
MemoryStream::MemoryStream(const u8* data, size_t length)
 | 
			
		||||
	: m_data(nullptr), m_const_data(data), m_length(length), m_position(0) {}
 | 
			
		||||
 | 
			
		||||
size_t MemoryStream::length() const
 | 
			
		||||
{
 | 
			
		||||
	return m_length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t MemoryStream::position() const
 | 
			
		||||
{
 | 
			
		||||
	return m_position;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t MemoryStream::seek(size_t seek_to)
 | 
			
		||||
{
 | 
			
		||||
	return m_position = (seek_to < 0 ? 0 : (seek_to > m_length ? m_length : seek_to));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t MemoryStream::read_data(void* ptr, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	const u8* src = (m_data ? m_data : m_const_data);
 | 
			
		||||
 | 
			
		||||
	if (src == nullptr || ptr == nullptr || len <= 0 || m_length <= 0 || m_position >= m_length)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (len > m_length - m_position)
 | 
			
		||||
		len = m_length - m_position;
 | 
			
		||||
 | 
			
		||||
	memcpy(ptr, src + m_position, len);
 | 
			
		||||
	m_position += len;
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t MemoryStream::write_data(const void* ptr, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	if (m_data == nullptr || ptr == nullptr || len <= 0 || m_length <= 0 || m_position >= m_length)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (len > m_length - m_position)
 | 
			
		||||
		len = m_length - m_position;
 | 
			
		||||
 | 
			
		||||
	memcpy(m_data + m_position, ptr, len);
 | 
			
		||||
	m_position += len;
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MemoryStream::is_open() const { return (m_data || m_const_data) && m_length > 0; }
 | 
			
		||||
bool MemoryStream::is_readable() const { return (m_data || m_const_data) && m_length > 0; }
 | 
			
		||||
bool MemoryStream::is_writable() const { return m_data != nullptr && m_length > 0; }
 | 
			
		||||
u8* MemoryStream::data() { return m_data; }
 | 
			
		||||
const u8* MemoryStream::data() const { return (m_data ? m_data : m_const_data); }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Buffer Stream Implementation
 | 
			
		||||
 | 
			
		||||
BufferStream::BufferStream(int capacity)
 | 
			
		||||
{
 | 
			
		||||
	m_buffer.resize(capacity);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t BufferStream::length() const
 | 
			
		||||
{
 | 
			
		||||
	return m_buffer.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t BufferStream::position() const
 | 
			
		||||
{
 | 
			
		||||
	return m_position;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t BufferStream::seek(size_t seek_to)
 | 
			
		||||
{
 | 
			
		||||
	return m_position = (seek_to < 0 ? 0 : (seek_to > m_buffer.size() ? m_buffer.size() : seek_to));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t BufferStream::read_data(void* ptr, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	if (ptr == nullptr || len <= 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (len > m_buffer.size() - m_position)
 | 
			
		||||
		len = m_buffer.size() - m_position;
 | 
			
		||||
 | 
			
		||||
	memcpy(ptr, m_buffer.data() + m_position, (size_t)len);
 | 
			
		||||
	m_position += len;
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t BufferStream::write_data(const void* ptr, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	if (len < 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	// resize
 | 
			
		||||
	if (m_position + len > m_buffer.size())
 | 
			
		||||
		resize(m_position + len);
 | 
			
		||||
 | 
			
		||||
	// copy data
 | 
			
		||||
	if (ptr != nullptr)
 | 
			
		||||
		memcpy(m_buffer.data() + m_position, ptr, (size_t)len);
 | 
			
		||||
 | 
			
		||||
	// increment position
 | 
			
		||||
	m_position += len;
 | 
			
		||||
 | 
			
		||||
	// return the amount we wrote
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool BufferStream::is_open() const { return true; }
 | 
			
		||||
bool BufferStream::is_readable() const { return true; }
 | 
			
		||||
bool BufferStream::is_writable() const { return true; }
 | 
			
		||||
 | 
			
		||||
void BufferStream::resize(size_t length)
 | 
			
		||||
{
 | 
			
		||||
	m_buffer.resize(length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BufferStream::clear()
 | 
			
		||||
{
 | 
			
		||||
	m_buffer.clear();
 | 
			
		||||
	m_position = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u8* BufferStream::data()
 | 
			
		||||
{
 | 
			
		||||
	return m_buffer.data();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const u8* BufferStream::data() const
 | 
			
		||||
{
 | 
			
		||||
	return m_buffer.data();
 | 
			
		||||
}
 | 
			
		||||
@ -1,82 +0,0 @@
 | 
			
		||||
#include "blah/streams/bufferstream.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
BufferStream::BufferStream(int capacity)
 | 
			
		||||
{
 | 
			
		||||
	m_buffer.resize(capacity);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t BufferStream::length() const
 | 
			
		||||
{
 | 
			
		||||
	return m_buffer.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t BufferStream::position() const
 | 
			
		||||
{
 | 
			
		||||
	return m_position;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t BufferStream::seek(size_t seek_to)
 | 
			
		||||
{
 | 
			
		||||
	return m_position = (seek_to < 0 ? 0 : (seek_to > m_buffer.size() ? m_buffer.size() : seek_to));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t BufferStream::read_data(void* ptr, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	if (ptr == nullptr || len <= 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (len > m_buffer.size() - m_position)
 | 
			
		||||
		len = m_buffer.size() - m_position;
 | 
			
		||||
 | 
			
		||||
	memcpy(ptr, m_buffer.data() + m_position, (size_t)len);
 | 
			
		||||
	m_position += len;
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t BufferStream::write_data(const void* ptr, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	if (len < 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	// resize
 | 
			
		||||
	if (m_position + len > m_buffer.size())
 | 
			
		||||
		resize(m_position + len);
 | 
			
		||||
 | 
			
		||||
	// copy data
 | 
			
		||||
	if (ptr != nullptr)
 | 
			
		||||
		memcpy(m_buffer.data() + m_position, ptr, (size_t)len);
 | 
			
		||||
 | 
			
		||||
	// increment position
 | 
			
		||||
	m_position += len;
 | 
			
		||||
 | 
			
		||||
	// return the amount we wrote
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool BufferStream::is_open() const { return true; }
 | 
			
		||||
bool BufferStream::is_readable() const { return true; }
 | 
			
		||||
bool BufferStream::is_writable() const { return true; }
 | 
			
		||||
 | 
			
		||||
void BufferStream::resize(size_t length)
 | 
			
		||||
{
 | 
			
		||||
	m_buffer.resize(length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BufferStream::clear()
 | 
			
		||||
{
 | 
			
		||||
	m_buffer.clear();
 | 
			
		||||
	m_position = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u8* BufferStream::data()
 | 
			
		||||
{
 | 
			
		||||
	return m_buffer.data();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const u8* BufferStream::data() const
 | 
			
		||||
{
 | 
			
		||||
	return m_buffer.data();
 | 
			
		||||
}
 | 
			
		||||
@ -1,82 +0,0 @@
 | 
			
		||||
#include <blah/streams/filestream.h>
 | 
			
		||||
#include <blah/common.h>
 | 
			
		||||
#include "../internal/platform.h"
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
FileStream::FileStream(const FilePath& path, FileMode mode)
 | 
			
		||||
	: m_mode(mode)
 | 
			
		||||
	, m_file(File::open(path, mode))
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FileStream::FileStream(FileStream&& src) noexcept
 | 
			
		||||
{
 | 
			
		||||
	m_file = src.m_file;
 | 
			
		||||
	m_mode = src.m_mode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FileStream& FileStream::operator=(FileStream&& src) noexcept
 | 
			
		||||
{
 | 
			
		||||
	m_file = src.m_file;
 | 
			
		||||
	m_mode = src.m_mode;
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t FileStream::length() const
 | 
			
		||||
{
 | 
			
		||||
	if (m_file)
 | 
			
		||||
		return m_file->length();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t FileStream::position() const
 | 
			
		||||
{
 | 
			
		||||
	if (m_file)
 | 
			
		||||
		return m_file->position();
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t FileStream::seek(size_t seek_to)
 | 
			
		||||
{
 | 
			
		||||
	if (m_file)
 | 
			
		||||
		return m_file->seek(seek_to);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t FileStream::read_data(void* ptr, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	if (length <= 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (m_file)
 | 
			
		||||
		return m_file->read((unsigned char*)ptr, length);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t FileStream::write_data(const void* ptr, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	if (length <= 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (m_file)
 | 
			
		||||
		return m_file->write((const unsigned char*)ptr, length);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FileStream::is_open() const
 | 
			
		||||
{
 | 
			
		||||
	return m_file.get();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FileStream::is_readable() const
 | 
			
		||||
{
 | 
			
		||||
	return m_file.get() && (m_mode != FileMode::CreateWrite);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FileStream::is_writable() const
 | 
			
		||||
{
 | 
			
		||||
	return m_file.get() && (m_mode != FileMode::OpenRead);
 | 
			
		||||
}
 | 
			
		||||
@ -1,78 +0,0 @@
 | 
			
		||||
#include <blah/streams/memorystream.h>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
using namespace Blah;
 | 
			
		||||
 | 
			
		||||
MemoryStream::MemoryStream(u8* data, size_t length)
 | 
			
		||||
	: m_data(data), m_const_data(nullptr), m_length(length), m_position(0) {}
 | 
			
		||||
 | 
			
		||||
MemoryStream::MemoryStream(const u8* data, size_t length)
 | 
			
		||||
	: m_data(nullptr), m_const_data(data), m_length(length), m_position(0) {}
 | 
			
		||||
 | 
			
		||||
size_t MemoryStream::length() const
 | 
			
		||||
{
 | 
			
		||||
	return m_length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t MemoryStream::position() const
 | 
			
		||||
{
 | 
			
		||||
	return m_position;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t MemoryStream::seek(size_t seek_to)
 | 
			
		||||
{
 | 
			
		||||
	return m_position = (seek_to < 0 ? 0 : (seek_to > m_length ? m_length : seek_to));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t MemoryStream::read_data(void* ptr, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	const u8* src = (m_data ? m_data : m_const_data);
 | 
			
		||||
 | 
			
		||||
	if (src == nullptr || ptr == nullptr || len <= 0 || m_length <= 0 || m_position >= m_length)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (len > m_length - m_position)
 | 
			
		||||
		len = m_length - m_position;
 | 
			
		||||
 | 
			
		||||
	memcpy(ptr, src + m_position, len);
 | 
			
		||||
	m_position += len;
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t MemoryStream::write_data(const void* ptr, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	if (m_data == nullptr || ptr == nullptr || len <= 0 || m_length <= 0 || m_position >= m_length)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (len > m_length - m_position)
 | 
			
		||||
		len = m_length - m_position;
 | 
			
		||||
 | 
			
		||||
	memcpy(m_data + m_position, ptr, len);
 | 
			
		||||
	m_position += len;
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MemoryStream::is_open() const
 | 
			
		||||
{
 | 
			
		||||
	return (m_data || m_const_data) && m_length > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MemoryStream::is_readable() const
 | 
			
		||||
{
 | 
			
		||||
	return (m_data || m_const_data) && m_length > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MemoryStream::is_writable() const
 | 
			
		||||
{
 | 
			
		||||
	return m_data != nullptr && m_length > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u8* MemoryStream::data()
 | 
			
		||||
{
 | 
			
		||||
	return m_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const u8* MemoryStream::data() const
 | 
			
		||||
{
 | 
			
		||||
	return (m_data ? m_data : m_const_data);
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user