mirror of
https://github.com/NoelFB/blah.git
synced 2024-11-25 16:18:57 +08:00
dcd3e11b16
1) Over time the total amount of files has decreased, and so it made sense to just simplify the folder structure and remove all of the subfolders. 2) Refactor the String class to utilize the existing Vector and StackVector classes instead of managing everything itself.
668 lines
17 KiB
C++
668 lines
17 KiB
C++
#pragma once
|
|
#include <blah_common.h>
|
|
#include <blah_vector.h>
|
|
#include <blah_stackvector.h>
|
|
#include <blah_string.h>
|
|
#include <blah_spatial.h>
|
|
#include <blah_image.h>
|
|
|
|
namespace Blah
|
|
{
|
|
class Stream;
|
|
|
|
class Shader; using ShaderRef = Ref<Shader>;
|
|
class Texture; using TextureRef = Ref<Texture>;
|
|
class Target; using TargetRef = Ref<Target>;
|
|
class Mesh; using MeshRef = Ref<Mesh>;
|
|
class Material; using MaterialRef = Ref<Material>;
|
|
|
|
// Type of Renderer the Application is using
|
|
enum class RendererType
|
|
{
|
|
None = -1,
|
|
OpenGL,
|
|
D3D11,
|
|
};
|
|
|
|
// Renderer Information
|
|
struct RendererInfo
|
|
{
|
|
// The type of Renderer being used
|
|
RendererType type = RendererType::None;
|
|
|
|
// Whether Mesh Instancing is available
|
|
bool instancing = false;
|
|
|
|
// Whether the Texture origin is the bottom left.
|
|
// This is true for OpenGL.
|
|
bool origin_bottom_left = false;
|
|
|
|
// Maximum Texture Size available
|
|
int max_texture_size = 0;
|
|
};
|
|
|
|
// Depth comparison function to use during a draw call
|
|
enum class Compare
|
|
{
|
|
None,
|
|
Always,
|
|
Never,
|
|
Less,
|
|
Equal,
|
|
LessOrEqual,
|
|
Greater,
|
|
NotEqual,
|
|
GreatorOrEqual
|
|
};
|
|
|
|
// Cull mode during a draw call
|
|
enum class Cull
|
|
{
|
|
// No Culling enabled
|
|
None = 0,
|
|
|
|
// Cull front faces
|
|
Front = 1,
|
|
|
|
// Cull back faces
|
|
Back = 2,
|
|
};
|
|
|
|
enum class BlendOp
|
|
{
|
|
Add,
|
|
Subtract,
|
|
ReverseSubtract,
|
|
Min,
|
|
Max
|
|
};
|
|
|
|
enum class BlendFactor
|
|
{
|
|
Zero,
|
|
One,
|
|
SrcColor,
|
|
OneMinusSrcColor,
|
|
DstColor,
|
|
OneMinusDstColor,
|
|
SrcAlpha,
|
|
OneMinusSrcAlpha,
|
|
DstAlpha,
|
|
OneMinusDstAlpha,
|
|
ConstantColor,
|
|
OneMinusConstantColor,
|
|
ConstantAlpha,
|
|
OneMinusConstantAlpha,
|
|
SrcAlphaSaturate,
|
|
Src1Color,
|
|
OneMinusSrc1Color,
|
|
Src1Alpha,
|
|
OneMinusSrc1Alpha
|
|
};
|
|
|
|
enum class BlendMask
|
|
{
|
|
None = 0,
|
|
Red = 1,
|
|
Green = 2,
|
|
Blue = 4,
|
|
Alpha = 8,
|
|
RGB = Red | Green | Blue,
|
|
RGBA = Red | Green | Blue | Alpha,
|
|
};
|
|
|
|
// BlendMode using for rendering
|
|
struct BlendMode
|
|
{
|
|
// Normal is Premultipled Alpha
|
|
// TODO: potentially rename normal to match that it is for Premultiplied Alpha?
|
|
static const BlendMode Normal;
|
|
static const BlendMode NonPremultiplied;
|
|
static const BlendMode Subtract;
|
|
static const BlendMode Additive;
|
|
|
|
BlendOp color_op;
|
|
BlendFactor color_src;
|
|
BlendFactor color_dst;
|
|
BlendOp alpha_op;
|
|
BlendFactor alpha_src;
|
|
BlendFactor alpha_dst;
|
|
BlendMask mask;
|
|
u32 rgba;
|
|
|
|
BlendMode() = default;
|
|
|
|
BlendMode(BlendOp op, BlendFactor src, BlendFactor dst) :
|
|
color_op(op), color_src(src), color_dst(dst),
|
|
alpha_op(op), alpha_src(src), alpha_dst(dst),
|
|
mask(BlendMask::RGBA), rgba(0xffffffff) {}
|
|
|
|
BlendMode(
|
|
BlendOp color_op, BlendFactor color_src, BlendFactor color_dst,
|
|
BlendOp alpha_op, BlendFactor alpha_src, BlendFactor alpha_dst,
|
|
BlendMask blend_mask, u32 blend_rgba) :
|
|
color_op(color_op), color_src(color_src), color_dst(color_dst),
|
|
alpha_op(alpha_op), alpha_src(alpha_src), alpha_dst(alpha_dst),
|
|
mask(blend_mask), rgba(blend_rgba) {}
|
|
|
|
constexpr bool operator==(const BlendMode& rhs) const
|
|
{
|
|
return
|
|
color_op == rhs.color_op && color_src == rhs.color_src && color_dst == rhs.color_dst &&
|
|
alpha_op == rhs.alpha_op && alpha_src == rhs.alpha_src && alpha_dst == rhs.alpha_dst &&
|
|
mask == rhs.mask && rgba == rhs.rgba;
|
|
}
|
|
|
|
constexpr bool operator!=(const BlendMode& rhs) const
|
|
{
|
|
return !(*this == rhs);
|
|
}
|
|
};
|
|
|
|
// Texture filter
|
|
enum class TextureFilter
|
|
{
|
|
None, // Will fallback to whatever default the driver sets
|
|
Linear, // Linear interpolation
|
|
Nearest // Nearest Neighbour interpolation
|
|
};
|
|
|
|
// Texture Wrap Mode
|
|
enum class TextureWrap
|
|
{
|
|
None, // Will fallback to whatever default the driver sets
|
|
Clamp, // Clamps the texture to the edges
|
|
Repeat // Repeats the texture
|
|
};
|
|
|
|
// Texture Sampler State, applied during rendering
|
|
struct TextureSampler
|
|
{
|
|
// Filter Mode
|
|
TextureFilter filter;
|
|
|
|
// Wrap X Mode
|
|
TextureWrap wrap_x;
|
|
|
|
// Wrap Y Mode
|
|
TextureWrap wrap_y;
|
|
|
|
TextureSampler() :
|
|
filter(TextureFilter::Linear), wrap_x(TextureWrap::Repeat), wrap_y(TextureWrap::Repeat) {}
|
|
|
|
TextureSampler(TextureFilter filter) :
|
|
filter(filter), wrap_x(TextureWrap::Repeat), wrap_y(TextureWrap::Repeat) {}
|
|
|
|
TextureSampler(TextureFilter filter, TextureWrap wrap_x, TextureWrap wrap_y) :
|
|
filter(filter), wrap_x(wrap_x), wrap_y(wrap_y) {}
|
|
|
|
bool operator==(const TextureSampler& rhs) const
|
|
{
|
|
return filter == rhs.filter && wrap_x == rhs.wrap_x && wrap_y == rhs.wrap_y;
|
|
}
|
|
|
|
bool operator!=(const TextureSampler& rhs) const
|
|
{
|
|
return !(*this == rhs);
|
|
}
|
|
};
|
|
|
|
enum class TextureFormat
|
|
{
|
|
None, // Invalid Format
|
|
R, // Single 8-bit channe;
|
|
RG, // 2 8-bit channels
|
|
RGBA, // 4 8-bit channels
|
|
DepthStencil, // Depth 24, Stencil 8
|
|
Count // Total Formats
|
|
};
|
|
|
|
enum class ClearMask
|
|
{
|
|
None = 0,
|
|
Color = 1,
|
|
Depth = 2,
|
|
Stencil = 4,
|
|
All = (int)Color | (int)Depth | (int)Stencil
|
|
};
|
|
|
|
// Supported Uniform Types
|
|
enum class UniformType
|
|
{
|
|
None,
|
|
Float,
|
|
Float2,
|
|
Float3,
|
|
Float4,
|
|
Mat3x2,
|
|
Mat4x4,
|
|
Texture2D,
|
|
Sampler2D
|
|
};
|
|
|
|
// Supported Shader Types
|
|
enum class ShaderType
|
|
{
|
|
None = 0,
|
|
Vertex = 1 << 0,
|
|
Fragment = 1 << 1
|
|
};
|
|
|
|
// Uniform Info, provided by the Shader
|
|
struct UniformInfo
|
|
{
|
|
// Name of the Uniform
|
|
String name;
|
|
|
|
// The Value type of the Uniform
|
|
UniformType type;
|
|
|
|
// The Shader type the Uniform is a part of
|
|
ShaderType shader;
|
|
|
|
// Texture / Sampler register index, which shaders can manually assign
|
|
int register_index = 0;
|
|
|
|
// Some rendering APIs have uniform buffers. The `buffer_index`
|
|
// specifies which buffer the uniform belongs to
|
|
int buffer_index = 0;
|
|
|
|
// Array length of the Uniform (ex. a vec2[4] would be 4)
|
|
int array_length = 0;
|
|
};
|
|
|
|
// Supported Vertex value types
|
|
enum class VertexType
|
|
{
|
|
None,
|
|
Float,
|
|
Float2,
|
|
Float3,
|
|
Float4,
|
|
Byte4,
|
|
UByte4,
|
|
Short2,
|
|
UShort2,
|
|
Short4,
|
|
UShort4
|
|
};
|
|
|
|
// Vertex Attribute information
|
|
struct VertexAttribute
|
|
{
|
|
// Location / Attribute Index
|
|
int index = 0;
|
|
|
|
// Vertex Type
|
|
VertexType type = VertexType::None;
|
|
|
|
// Whether the Vertex should be normalized (doesn't apply to Floats)
|
|
bool normalized = false;
|
|
};
|
|
|
|
// Vertex Format information.
|
|
// Holds a list of attributes and total stride per-vertex.
|
|
struct VertexFormat
|
|
{
|
|
// List of Attributes
|
|
StackVector<VertexAttribute, 16> attributes;
|
|
|
|
// Total size in bytes of each Vertex element
|
|
int stride = 0;
|
|
|
|
VertexFormat() = default;
|
|
VertexFormat(const StackVector<VertexAttribute, 16>& attributes, int stride = 0);
|
|
};
|
|
|
|
// Supported Vertex Index formats
|
|
enum class IndexFormat
|
|
{
|
|
// Indices are 16 bit unsigned integers
|
|
UInt16,
|
|
|
|
// Indices are 32 bit unsigned integers
|
|
UInt32
|
|
};
|
|
|
|
// Data to be passed to the shader to construct it
|
|
struct ShaderData
|
|
{
|
|
struct HLSL_Attribute
|
|
{
|
|
// Semantic Name
|
|
const char* semantic_name = nullptr;
|
|
|
|
// (optional) Semantic Index
|
|
int semantic_index = 0;
|
|
};
|
|
|
|
// Vertex Shader Program data
|
|
String vertex;
|
|
|
|
// Fragment Shader Program data
|
|
String fragment;
|
|
|
|
// HLSL Attributes - required for D3D11
|
|
StackVector<HLSL_Attribute, 16> hlsl_attributes;
|
|
};
|
|
|
|
// A shader used during Rendering
|
|
class Shader
|
|
{
|
|
protected:
|
|
Shader() = default;
|
|
|
|
public:
|
|
// Copy / Moves not allowed
|
|
Shader(const Shader&) = delete;
|
|
Shader(Shader&&) = delete;
|
|
Shader& operator=(const Shader&) = delete;
|
|
Shader& operator=(Shader&&) = delete;
|
|
|
|
// Default Destructor
|
|
virtual ~Shader() = default;
|
|
|
|
// Creates a Shader with the given Shader Data.
|
|
// If the Shader creation fails, it will return an invalid ShaderRef.
|
|
static ShaderRef create(const ShaderData& data);
|
|
|
|
// Gets a list of Shader Uniforms from Shader
|
|
virtual Vector<UniformInfo>& uniforms() = 0;
|
|
|
|
// Gets a list of Shader Uniforms from Shader
|
|
virtual const Vector<UniformInfo>& uniforms() const = 0;
|
|
};
|
|
|
|
// A 2D Texture held by the GPU to be used during rendering
|
|
class Texture
|
|
{
|
|
protected:
|
|
Texture() = default;
|
|
|
|
public:
|
|
// Copy / Moves not allowed
|
|
Texture(const Texture&) = delete;
|
|
Texture(Texture&&) = delete;
|
|
Texture& operator=(const Texture&) = delete;
|
|
Texture& operator=(Texture&&) = delete;
|
|
|
|
// Default Destructor
|
|
virtual ~Texture() = default;
|
|
|
|
// Creates a new Texture.
|
|
// If the Texture creation fails, it will return an invalid TextureRef.
|
|
static TextureRef create(const Image& image);
|
|
|
|
// Creates a new Texture.
|
|
// If image data is provided, it should be the full size of the texture.
|
|
// If the Texture creation fails, it will return an invalid TextureRef.
|
|
static TextureRef create(int width, int height, TextureFormat format, unsigned char* data = nullptr);
|
|
|
|
// Creates a new Texture from a Stream.
|
|
// If the Texture creation fails, it will return an invalid TextureRef.
|
|
static TextureRef create(Stream& stream);
|
|
|
|
// Creates a new Texture from a File.
|
|
// If the Texture creation fails, it will return an invalid TextureRef.
|
|
static TextureRef create(const FilePath& file);
|
|
|
|
// gets the width of the texture
|
|
virtual int width() const = 0;
|
|
|
|
// gets the height of the texture
|
|
virtual int height() const = 0;
|
|
|
|
// Gets the format of the Texture
|
|
virtual TextureFormat format() const = 0;
|
|
|
|
// Sets the data of the Texture.
|
|
// Note that the data should be the same format and size as the Texture. There is no row padding.
|
|
virtual void set_data(const u8* data) = 0;
|
|
|
|
// Sets the data of the Texture to the provided Color buffer.
|
|
// If the Texture Format is not RGBA, this won't do anything.
|
|
void set_data(const Color* data);
|
|
|
|
// Gets the data of the Texture.
|
|
// Note that the data will be written to in the same format as the Texture,
|
|
// and you should allocate enough space for the full texture. There is no row padding.
|
|
virtual void get_data(u8* data) = 0;
|
|
|
|
// Gets the data of the Texture.
|
|
// If the Texture Format is not RGBA, this won't do anything.
|
|
void get_data(Color* data);
|
|
|
|
// Returns true if the Texture is part of a FrameBuffer
|
|
virtual bool is_framebuffer() const = 0;
|
|
};
|
|
|
|
// Up to 4 color textures + 1 depth/stencil
|
|
using Attachments = StackVector<TextureRef, 5>;
|
|
using AttachmentFormats = StackVector<TextureFormat, 5>;
|
|
|
|
// Target is a 2D Buffer that can be drawn to.
|
|
// It can hold up to 4 color Textures, and 1 Depth/Stencil Texture.
|
|
class Target
|
|
{
|
|
protected:
|
|
Target() = default;
|
|
|
|
public:
|
|
// Copy / Moves not allowed
|
|
Target(const Target&) = delete;
|
|
Target(Target&&) = delete;
|
|
Target& operator=(const Target&) = delete;
|
|
Target& operator=(Target&&) = delete;
|
|
|
|
// Default Destructor
|
|
virtual ~Target() = default;
|
|
|
|
// Creates a new Target with a single Color texture
|
|
// If the Target creation fails, it will return an invalid TargetRef.
|
|
static TargetRef create(int width, int height);
|
|
|
|
// Creates a new Target with the given Texture Attachments. You must provide at least one Attachment.
|
|
// If the Target creation fails, it will return an invalid TargetRef.
|
|
static TargetRef create(int width, int height, const AttachmentFormats& textures);
|
|
|
|
// Gets the list of Attachments from the Target
|
|
virtual Attachments& textures() = 0;
|
|
|
|
// Gets the list of Attachments from the Target
|
|
virtual const Attachments& textures() const = 0;
|
|
|
|
// Gets the Attachment at a given index from the Target
|
|
TextureRef& texture(int index);
|
|
|
|
// Gets the Attachment at a given index from the Target
|
|
const TextureRef& texture(int index) const;
|
|
|
|
// Gets the width of the Target
|
|
virtual int width() const;
|
|
|
|
// Gets the height of the Target
|
|
virtual int height() const;
|
|
|
|
// Clears the Target
|
|
virtual void clear(Color color = Color::black, float depth = 1.0f, u8 stencil = 0, ClearMask mask = ClearMask::All) = 0;
|
|
};
|
|
|
|
// A Mesh is a set of Indices and Vertices which are used for drawing
|
|
class Mesh
|
|
{
|
|
protected:
|
|
Mesh() = default;
|
|
|
|
public:
|
|
// Copy / Moves not allowed
|
|
Mesh(const Mesh&) = delete;
|
|
Mesh(Mesh&&) = delete;
|
|
Mesh& operator=(const Mesh&) = delete;
|
|
Mesh& operator=(Mesh&&) = delete;
|
|
|
|
// Default Destructor
|
|
virtual ~Mesh() = default;
|
|
|
|
// Creates a new Mesh.
|
|
// If the Mesh creation fails, it will return an invalid Mesh.
|
|
static MeshRef create();
|
|
|
|
// Uploads the given index buffer to the Mesh
|
|
virtual void index_data(IndexFormat format, const void* indices, i64 count) = 0;
|
|
|
|
// Uploads the given vertex buffer to the Mesh
|
|
virtual void vertex_data(const VertexFormat& format, const void* vertices, i64 count) = 0;
|
|
|
|
// Uploads the given instance buffer to the Mesh
|
|
virtual void instance_data(const VertexFormat& format, const void* instances, i64 count) = 0;
|
|
|
|
// Gets the index count of the Mesh
|
|
virtual i64 index_count() const = 0;
|
|
|
|
// Gets the vertex count of the Mesh
|
|
virtual i64 vertex_count() const = 0;
|
|
|
|
// Gets the instance count of the Mesh
|
|
virtual i64 instance_count() const = 0;
|
|
};
|
|
|
|
// Materials hold values that can be assigned to a shader during rendering
|
|
class Material final
|
|
{
|
|
private:
|
|
Material(const ShaderRef& shader);
|
|
|
|
public:
|
|
// Copy / Moves not allowed
|
|
Material(const Material&) = delete;
|
|
Material(Material&&) = delete;
|
|
Material& operator=(const Material&) = delete;
|
|
Material& operator=(Material&&) = delete;
|
|
|
|
// Default destructor
|
|
~Material() = default;
|
|
|
|
// Creates a new Material from the given Shader.
|
|
// If the Shader is invalid, it will return an invalid MaterialRef.
|
|
static MaterialRef create(const ShaderRef& shader);
|
|
|
|
// Clones the material and returns a new one
|
|
MaterialRef clone() const;
|
|
|
|
// Returns the Shader assigned to the Material.
|
|
ShaderRef shader() const;
|
|
|
|
// Sets the texture
|
|
void set_texture(const char* name, const TextureRef& texture, int array_index = 0);
|
|
|
|
// Sets the texture
|
|
void set_texture(int register_index, const TextureRef& texture);
|
|
|
|
// Gets the texture, or an empty reference if invalid
|
|
TextureRef get_texture(const char* name, int array_index = 0) const;
|
|
|
|
// Gets the texture, or an empty reference if invalid
|
|
TextureRef get_texture(int register_index) const;
|
|
|
|
// Sets the sampler
|
|
void set_sampler(const char* name, const TextureSampler& sampler, int array_index = 0);
|
|
|
|
// Sets the sampler
|
|
void set_sampler(int register_index, const TextureSampler& sampler);
|
|
|
|
// Gets the sampler
|
|
TextureSampler get_sampler(const char* name, int array_index = 0) const;
|
|
|
|
// Gets the sampler
|
|
TextureSampler get_sampler(int register_index) const;
|
|
|
|
// Sets the value. `length` is the total number of floats to set
|
|
// For example if the uniform is a float2[4], a total of 8 float values
|
|
// can be set.
|
|
void set_value(const char* name, const float* value, i64 length);
|
|
|
|
// Shorthands to more easily assign uniform values
|
|
void set_value(const char* name, float value);
|
|
void set_value(const char* name, const Vec2f& value);
|
|
void set_value(const char* name, const Vec3f& value);
|
|
void set_value(const char* name, const Vec4f& value);
|
|
void set_value(const char* name, const Mat3x2f& value);
|
|
void set_value(const char* name, const Mat4x4f& value);
|
|
void set_value(const char* name, const Vector<float>& value);
|
|
void set_value(const char* name, const Vector<Vec2f>& value);
|
|
void set_value(const char* name, const Vector<Vec3f>& value);
|
|
void set_value(const char* name, const Vector<Vec4f>& value);
|
|
void set_value(const char* name, const Vector<Mat3x2f>& value);
|
|
void set_value(const char* name, const Vector<Mat4x4f>& value);
|
|
|
|
// Gets a pointer to the values of the given Uniform, or nullptr if it doesn't exist.
|
|
const float* get_value(const char* name, i64* length = nullptr) const;
|
|
|
|
// Checks if the shader attached to the material has a uniform value with the given name
|
|
bool has_value(const char* name) const;
|
|
|
|
// Returns the internal Texture buffer
|
|
const Vector<TextureRef>& textures() const;
|
|
|
|
// Returns the internal Sampler buffer
|
|
const Vector<TextureSampler>& samplers() const;
|
|
|
|
// Returns the interal float buffer of all the values
|
|
const float* data() const;
|
|
|
|
private:
|
|
ShaderRef m_shader;
|
|
Vector<TextureRef> m_textures;
|
|
Vector<TextureSampler> m_samplers;
|
|
Vector<float> m_data;
|
|
};
|
|
|
|
// A single draw call
|
|
struct DrawCall
|
|
{
|
|
// Framebuffer to draw to
|
|
TargetRef target;
|
|
|
|
// Mesh to draw with
|
|
MeshRef mesh;
|
|
|
|
// Material to draw with
|
|
MaterialRef material;
|
|
|
|
// Whether the DrawCall should use a specific viewport
|
|
bool has_viewport;
|
|
|
|
// Whether the DrawCall should use a scissor rectangle
|
|
bool has_scissor;
|
|
|
|
// The viewport (only used if hasViewport is true)
|
|
Rectf viewport;
|
|
|
|
// The scissor rectangle (only used if hasScissor is true)
|
|
Rectf scissor;
|
|
|
|
// First index in the Mesh to draw from
|
|
i64 index_start;
|
|
|
|
// Total amount of indices to draw from the Mesh
|
|
i64 index_count;
|
|
|
|
// Total amount of instances to draw from the Mesh
|
|
i64 instance_count;
|
|
|
|
// Depth Compare Function
|
|
Compare depth;
|
|
|
|
// Cull Mode
|
|
Cull cull;
|
|
|
|
// Blend Mode
|
|
BlendMode blend;
|
|
|
|
// Initializes a default DrawCall
|
|
DrawCall();
|
|
|
|
// Performs the render
|
|
void perform();
|
|
};
|
|
} |