mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-15 00:11:55 +07:00
1259 lines
38 KiB
C++
1259 lines
38 KiB
C++
/*******************************************************************************
|
|
* This file is part of the "Enduro2D"
|
|
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
|
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
|
|
******************************************************************************/
|
|
|
|
#include "render_impl/render.hpp"
|
|
|
|
namespace
|
|
{
|
|
using namespace e2d;
|
|
|
|
struct pixel_type_description {
|
|
u32 bytes_per_block;
|
|
bool color;
|
|
bool depth;
|
|
bool stencil;
|
|
pixel_declaration::pixel_type type;
|
|
bool compressed;
|
|
v2u block_size;
|
|
};
|
|
|
|
const pixel_type_description pixel_type_descriptions[] = {
|
|
{2, false, true, false, pixel_declaration::pixel_type::depth16, false, v2u(1,1)},
|
|
{3, false, true, false, pixel_declaration::pixel_type::depth24, false, v2u(1,1)},
|
|
{4, false, true, true, pixel_declaration::pixel_type::depth24_stencil8, false, v2u(1,1)},
|
|
|
|
{1, true, false, false, pixel_declaration::pixel_type::a8, false, v2u(1,1)},
|
|
{1, true, false, false, pixel_declaration::pixel_type::l8, false, v2u(1,1)},
|
|
{2, true, false, false, pixel_declaration::pixel_type::la8, false, v2u(1,1)},
|
|
{3, true, false, false, pixel_declaration::pixel_type::rgb8, false, v2u(1,1)},
|
|
{4, true, false, false, pixel_declaration::pixel_type::rgba8, false, v2u(1,1)},
|
|
|
|
{8, true, false, false, pixel_declaration::pixel_type::rgba_dxt1, true, v2u(4,4)},
|
|
{16, true, false, false, pixel_declaration::pixel_type::rgba_dxt3, true, v2u(4,4)},
|
|
{16, true, false, false, pixel_declaration::pixel_type::rgba_dxt5, true, v2u(4,4)},
|
|
|
|
{8, true, false, false, pixel_declaration::pixel_type::rgb_etc1, true, v2u(4,4)},
|
|
{8, true, false, false, pixel_declaration::pixel_type::rgb_etc2, true, v2u(4,4)},
|
|
{16, true, false, false, pixel_declaration::pixel_type::rgba_etc2, true, v2u(4,4)},
|
|
{8, true, false, false, pixel_declaration::pixel_type::rgb_a1_etc2, true, v2u(4,4)},
|
|
|
|
{16, true, false, false, pixel_declaration::pixel_type::rgba_astc4x4, true, v2u(4,4)},
|
|
{16, true, false, false, pixel_declaration::pixel_type::rgba_astc5x5, true, v2u(5,5)},
|
|
{16, true, false, false, pixel_declaration::pixel_type::rgba_astc6x6, true, v2u(6,6)},
|
|
{16, true, false, false, pixel_declaration::pixel_type::rgba_astc8x8, true, v2u(8,8)},
|
|
{16, true, false, false, pixel_declaration::pixel_type::rgba_astc10x10, true, v2u(10,10)},
|
|
{16, true, false, false, pixel_declaration::pixel_type::rgba_astc12x12, true, v2u(12,12)},
|
|
|
|
{8, true, false, false, pixel_declaration::pixel_type::rgb_pvrtc2, true, v2u(8,4)},
|
|
{8, true, false, false, pixel_declaration::pixel_type::rgb_pvrtc4, true, v2u(4,4)},
|
|
{8, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc2, true, v2u(8,4)},
|
|
{8, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc4, true, v2u(4,4)},
|
|
|
|
{8, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc2_v2, true, v2u(8,4)},
|
|
{8, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc4_v2, true, v2u(4,4)}
|
|
};
|
|
|
|
const pixel_type_description& get_pixel_type_description(pixel_declaration::pixel_type type) noexcept {
|
|
const std::size_t index = math::numeric_cast<std::size_t>(utils::enum_to_underlying(type));
|
|
E2D_ASSERT(index < std::size(pixel_type_descriptions));
|
|
const pixel_type_description& desc = pixel_type_descriptions[index];
|
|
E2D_ASSERT(desc.type == type);
|
|
return desc;
|
|
}
|
|
|
|
std::size_t index_element_size(index_declaration::index_type it) noexcept {
|
|
#define DEFINE_CASE(x,y) case index_declaration::index_type::x: return y;
|
|
switch ( it ) {
|
|
DEFINE_CASE(unsigned_short, sizeof(u16));
|
|
DEFINE_CASE(unsigned_int, sizeof(u32));
|
|
default:
|
|
E2D_ASSERT_MSG(false, "unexpected index type");
|
|
return 0;
|
|
}
|
|
#undef DEFINE_CASE
|
|
}
|
|
|
|
std::size_t attribute_element_size(vertex_declaration::attribute_type at) noexcept {
|
|
#define DEFINE_CASE(x,y) case vertex_declaration::attribute_type::x: return y;
|
|
switch ( at ) {
|
|
DEFINE_CASE(signed_byte, sizeof(u8));
|
|
DEFINE_CASE(unsigned_byte, sizeof(u8));
|
|
DEFINE_CASE(signed_short, sizeof(u16));
|
|
DEFINE_CASE(unsigned_short, sizeof(u16));
|
|
DEFINE_CASE(floating_point, sizeof(u32));
|
|
default:
|
|
E2D_ASSERT_MSG(false, "unexpected attribute type");
|
|
return 0;
|
|
}
|
|
#undef DEFINE_CASE
|
|
}
|
|
|
|
class command_value_visitor final : private noncopyable {
|
|
public:
|
|
command_value_visitor(render& render) noexcept
|
|
: render_(render) {}
|
|
|
|
void operator()(const render::zero_command& command) const {
|
|
E2D_UNUSED(command);
|
|
}
|
|
|
|
void operator()(const render::draw_command& command) const {
|
|
render_.execute(command);
|
|
}
|
|
|
|
void operator()(const render::clear_command& command) const {
|
|
render_.execute(command);
|
|
}
|
|
|
|
void operator()(const render::target_command& command) const {
|
|
render_.execute(command);
|
|
}
|
|
|
|
void operator()(const render::viewport_command& command) const {
|
|
render_.execute(command);
|
|
}
|
|
private:
|
|
render& render_;
|
|
};
|
|
}
|
|
|
|
namespace e2d
|
|
{
|
|
//
|
|
// pixel_declaration
|
|
//
|
|
|
|
pixel_declaration::pixel_declaration(pixel_type type) noexcept
|
|
: type_(type) {}
|
|
|
|
pixel_declaration::pixel_type pixel_declaration::type() const noexcept {
|
|
return type_;
|
|
}
|
|
|
|
bool pixel_declaration::is_color() const noexcept {
|
|
return get_pixel_type_description(type_).color;
|
|
}
|
|
|
|
bool pixel_declaration::is_depth() const noexcept {
|
|
return get_pixel_type_description(type_).depth;
|
|
}
|
|
|
|
bool pixel_declaration::is_stencil() const noexcept {
|
|
return get_pixel_type_description(type_).stencil;
|
|
}
|
|
|
|
bool pixel_declaration::is_compressed() const noexcept {
|
|
return get_pixel_type_description(type_).compressed;
|
|
}
|
|
|
|
v2u pixel_declaration::block_size() const noexcept {
|
|
return get_pixel_type_description(type_).block_size;
|
|
}
|
|
|
|
std::size_t pixel_declaration::bytes_per_block() const noexcept {
|
|
return get_pixel_type_description(type_).bytes_per_block;
|
|
}
|
|
|
|
std::size_t pixel_declaration::data_size_for_dimension(v2u dim) const noexcept {
|
|
const v2u bs = block_size();
|
|
const std::size_t bpb = bytes_per_block();
|
|
return bs.x > 0 && bs.y > 0 && bpb > 0
|
|
? bpb * ((dim.x + bs.x - 1u) / bs.x) * ((dim.y + bs.y - 1u) / bs.y)
|
|
: 0u;
|
|
}
|
|
|
|
bool operator==(const pixel_declaration& l, const pixel_declaration& r) noexcept {
|
|
return l.type() == r.type();
|
|
}
|
|
|
|
bool operator!=(const pixel_declaration& l, const pixel_declaration& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
|
|
//
|
|
// index_declaration
|
|
//
|
|
|
|
index_declaration::index_declaration(index_type type) noexcept
|
|
: type_(type) {}
|
|
|
|
index_declaration::index_type index_declaration::type() const noexcept {
|
|
return type_;
|
|
}
|
|
|
|
std::size_t index_declaration::bytes_per_index() const noexcept {
|
|
return index_element_size(type_);
|
|
}
|
|
|
|
bool operator==(const index_declaration& l, const index_declaration& r) noexcept {
|
|
return l.type() == r.type();
|
|
}
|
|
|
|
bool operator!=(const index_declaration& l, const index_declaration& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
|
|
//
|
|
// vertex_declaration::attribute_info
|
|
//
|
|
|
|
vertex_declaration::attribute_info::attribute_info(
|
|
std::size_t nstride,
|
|
str_hash nname,
|
|
u8 nrows,
|
|
u8 ncolumns,
|
|
attribute_type ntype,
|
|
bool nnormalized) noexcept
|
|
: stride(nstride)
|
|
, name(std::move(nname))
|
|
, rows(nrows)
|
|
, columns(ncolumns)
|
|
, type(ntype)
|
|
, normalized(nnormalized) {}
|
|
|
|
std::size_t vertex_declaration::attribute_info::row_size() const noexcept {
|
|
return attribute_element_size(type) * columns;
|
|
}
|
|
|
|
//
|
|
// vertex_declaration
|
|
//
|
|
|
|
vertex_declaration& vertex_declaration::normalized() noexcept {
|
|
E2D_ASSERT(attribute_count_ > 0);
|
|
attributes_[attribute_count_ - 1].normalized = true;
|
|
return *this;
|
|
}
|
|
|
|
vertex_declaration& vertex_declaration::skip_bytes(std::size_t bytes) noexcept {
|
|
bytes_per_vertex_ += bytes;
|
|
return *this;
|
|
}
|
|
|
|
vertex_declaration& vertex_declaration::add_attribute(
|
|
str_hash name,
|
|
u8 rows,
|
|
u8 columns,
|
|
attribute_type type,
|
|
bool normalized) noexcept
|
|
{
|
|
E2D_ASSERT(attribute_count_ < attributes_.size());
|
|
const std::size_t stride = bytes_per_vertex_;
|
|
attributes_[attribute_count_] = attribute_info(
|
|
stride,
|
|
name,
|
|
rows,
|
|
columns,
|
|
type,
|
|
normalized);
|
|
bytes_per_vertex_ += attribute_element_size(type) * rows * columns;
|
|
++attribute_count_;
|
|
return *this;
|
|
}
|
|
|
|
const vertex_declaration::attribute_info& vertex_declaration::attribute(std::size_t index) const noexcept {
|
|
E2D_ASSERT(index < attribute_count_);
|
|
return attributes_[index];
|
|
}
|
|
|
|
std::size_t vertex_declaration::attribute_count() const noexcept {
|
|
return attribute_count_;
|
|
}
|
|
|
|
std::size_t vertex_declaration::bytes_per_vertex() const noexcept {
|
|
return bytes_per_vertex_;
|
|
}
|
|
|
|
bool operator==(const vertex_declaration& l, const vertex_declaration& r) noexcept {
|
|
if ( l.bytes_per_vertex() != r.bytes_per_vertex() ) {
|
|
return false;
|
|
}
|
|
if ( l.attribute_count() != r.attribute_count() ) {
|
|
return false;
|
|
}
|
|
for ( std::size_t i = 0, e = l.attribute_count(); i < e; ++i ) {
|
|
if ( l.attribute(i) != r.attribute(i) ) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool operator!=(const vertex_declaration& l, const vertex_declaration& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
|
|
bool operator==(
|
|
const vertex_declaration::attribute_info& l,
|
|
const vertex_declaration::attribute_info& r) noexcept
|
|
{
|
|
return l.stride == r.stride
|
|
&& l.name == r.name
|
|
&& l.rows == r.rows
|
|
&& l.columns == r.columns
|
|
&& l.type == r.type
|
|
&& l.normalized == r.normalized;
|
|
}
|
|
|
|
bool operator!=(
|
|
const vertex_declaration::attribute_info& l,
|
|
const vertex_declaration::attribute_info& r) noexcept
|
|
{
|
|
return !(l == r);
|
|
}
|
|
|
|
//
|
|
// depth_state
|
|
//
|
|
|
|
render::depth_state& render::depth_state::range(f32 near, f32 far) noexcept {
|
|
range_near_ = near;
|
|
range_far_ = far;
|
|
return *this;
|
|
}
|
|
|
|
render::depth_state& render::depth_state::write(bool enable) noexcept {
|
|
write_ = enable;
|
|
return *this;
|
|
}
|
|
|
|
render::depth_state& render::depth_state::func(compare_func func) noexcept {
|
|
func_ = func;
|
|
return *this;
|
|
}
|
|
|
|
f32 render::depth_state::range_near() const noexcept {
|
|
return range_near_;
|
|
}
|
|
|
|
f32 render::depth_state::range_far() const noexcept {
|
|
return range_far_;
|
|
}
|
|
|
|
bool render::depth_state::write() const noexcept {
|
|
return write_;
|
|
}
|
|
|
|
render::compare_func render::depth_state::func() const noexcept {
|
|
return func_;
|
|
}
|
|
|
|
//
|
|
// stencil_state
|
|
//
|
|
|
|
render::stencil_state& render::stencil_state::write(u8 mask) noexcept {
|
|
write_ = mask;
|
|
return *this;
|
|
}
|
|
|
|
render::stencil_state& render::stencil_state::func(compare_func func, u8 ref, u8 mask) noexcept {
|
|
func_ = func;
|
|
ref_ = ref;
|
|
read_ = mask;
|
|
return *this;
|
|
}
|
|
|
|
render::stencil_state& render::stencil_state::op(stencil_op pass, stencil_op sfail, stencil_op zfail) noexcept {
|
|
pass_ = pass;
|
|
sfail_ = sfail;
|
|
zfail_ = zfail;
|
|
return *this;
|
|
}
|
|
|
|
u8 render::stencil_state::write() const noexcept {
|
|
return write_;
|
|
}
|
|
|
|
render::compare_func render::stencil_state::func() const noexcept {
|
|
return func_;
|
|
}
|
|
|
|
u8 render::stencil_state::ref() const noexcept {
|
|
return ref_;
|
|
}
|
|
|
|
u8 render::stencil_state::mask() const noexcept {
|
|
return read_;
|
|
}
|
|
|
|
render::stencil_op render::stencil_state::pass() const noexcept {
|
|
return pass_;
|
|
}
|
|
|
|
render::stencil_op render::stencil_state::sfail() const noexcept {
|
|
return sfail_;
|
|
}
|
|
|
|
render::stencil_op render::stencil_state::zfail() const noexcept {
|
|
return zfail_;
|
|
}
|
|
|
|
//
|
|
// culling_state
|
|
//
|
|
|
|
render::culling_state& render::culling_state::mode(culling_mode mode) noexcept {
|
|
mode_ = mode;
|
|
return *this;
|
|
}
|
|
|
|
render::culling_state& render::culling_state::face(culling_face face) noexcept {
|
|
face_ = face;
|
|
return *this;
|
|
}
|
|
|
|
render::culling_mode render::culling_state::mode() const noexcept {
|
|
return mode_;
|
|
}
|
|
|
|
render::culling_face render::culling_state::face() const noexcept {
|
|
return face_;
|
|
}
|
|
|
|
//
|
|
// blending_state
|
|
//
|
|
|
|
render::blending_state& render::blending_state::constant_color(const color& c) noexcept {
|
|
constant_color_ = c;
|
|
return *this;
|
|
}
|
|
|
|
render::blending_state& render::blending_state::color_mask(blending_color_mask mask) noexcept {
|
|
color_mask_ = mask;
|
|
return *this;
|
|
}
|
|
|
|
render::blending_state& render::blending_state::factor(blending_factor src, blending_factor dst) noexcept {
|
|
rgb_factor(src, dst);
|
|
alpha_factor(src, dst);
|
|
return *this;
|
|
}
|
|
|
|
render::blending_state& render::blending_state::src_factor(blending_factor src) noexcept {
|
|
src_rgb_factor(src);
|
|
src_alpha_factor(src);
|
|
return *this;
|
|
}
|
|
|
|
render::blending_state& render::blending_state::dst_factor(blending_factor dst) noexcept {
|
|
dst_rgb_factor(dst);
|
|
dst_alpha_factor(dst);
|
|
return *this;
|
|
}
|
|
|
|
render::blending_state& render::blending_state::rgb_factor(blending_factor src, blending_factor dst) noexcept {
|
|
src_rgb_factor(src);
|
|
dst_rgb_factor(dst);
|
|
return *this;
|
|
}
|
|
|
|
render::blending_state& render::blending_state::src_rgb_factor(blending_factor src) noexcept {
|
|
src_rgb_factor_ = src;
|
|
return *this;
|
|
}
|
|
|
|
render::blending_state& render::blending_state::dst_rgb_factor(blending_factor dst) noexcept {
|
|
dst_rgb_factor_ = dst;
|
|
return *this;
|
|
}
|
|
|
|
render::blending_state& render::blending_state::alpha_factor(blending_factor src, blending_factor dst) noexcept {
|
|
src_alpha_factor(src);
|
|
dst_alpha_factor(dst);
|
|
return *this;
|
|
}
|
|
|
|
render::blending_state& render::blending_state::src_alpha_factor(blending_factor src) noexcept {
|
|
src_alpha_factor_ = src;
|
|
return *this;
|
|
}
|
|
|
|
render::blending_state& render::blending_state::dst_alpha_factor(blending_factor dst) noexcept {
|
|
dst_alpha_factor_ = dst;
|
|
return *this;
|
|
}
|
|
|
|
render::blending_state& render::blending_state::equation(blending_equation equation) noexcept {
|
|
rgb_equation(equation);
|
|
alpha_equation(equation);
|
|
return *this;
|
|
}
|
|
|
|
render::blending_state& render::blending_state::rgb_equation(blending_equation equation) noexcept {
|
|
rgb_equation_ = equation;
|
|
return *this;
|
|
}
|
|
|
|
render::blending_state& render::blending_state::alpha_equation(blending_equation equation) noexcept {
|
|
alpha_equation_ = equation;
|
|
return *this;
|
|
}
|
|
|
|
const color& render::blending_state::constant_color() const noexcept {
|
|
return constant_color_;
|
|
}
|
|
|
|
render::blending_color_mask render::blending_state::color_mask() const noexcept {
|
|
return color_mask_;
|
|
}
|
|
|
|
render::blending_factor render::blending_state::src_rgb_factor() const noexcept {
|
|
return src_rgb_factor_;
|
|
}
|
|
|
|
render::blending_factor render::blending_state::dst_rgb_factor() const noexcept {
|
|
return dst_rgb_factor_;
|
|
}
|
|
|
|
render::blending_factor render::blending_state::src_alpha_factor() const noexcept {
|
|
return src_alpha_factor_;
|
|
}
|
|
|
|
render::blending_factor render::blending_state::dst_alpha_factor() const noexcept {
|
|
return dst_alpha_factor_;
|
|
}
|
|
|
|
render::blending_equation render::blending_state::rgb_equation() const noexcept {
|
|
return rgb_equation_;
|
|
}
|
|
|
|
render::blending_equation render::blending_state::alpha_equation() const noexcept {
|
|
return alpha_equation_;
|
|
}
|
|
|
|
//
|
|
// capabilities_state
|
|
//
|
|
|
|
render::capabilities_state& render::capabilities_state::culling(bool enable) noexcept {
|
|
culling_ = enable;
|
|
return *this;
|
|
}
|
|
|
|
render::capabilities_state& render::capabilities_state::blending(bool enable) noexcept {
|
|
blending_ = enable;
|
|
return *this;
|
|
}
|
|
|
|
render::capabilities_state& render::capabilities_state::depth_test(bool enable) noexcept {
|
|
depth_test_ = enable;
|
|
return *this;
|
|
}
|
|
|
|
render::capabilities_state& render::capabilities_state::stencil_test(bool enable) noexcept {
|
|
stencil_test_ = enable;
|
|
return *this;
|
|
}
|
|
|
|
bool render::capabilities_state::culling() const noexcept {
|
|
return culling_;
|
|
}
|
|
|
|
bool render::capabilities_state::blending() const noexcept {
|
|
return blending_;
|
|
}
|
|
|
|
bool render::capabilities_state::depth_test() const noexcept {
|
|
return depth_test_;
|
|
}
|
|
|
|
bool render::capabilities_state::stencil_test() const noexcept {
|
|
return stencil_test_;
|
|
}
|
|
|
|
//
|
|
// render_state
|
|
//
|
|
|
|
render::state_block& render::state_block::depth(const depth_state& state) noexcept {
|
|
depth_ = state;
|
|
return *this;
|
|
}
|
|
|
|
render::state_block& render::state_block::stencil(const stencil_state& state) noexcept {
|
|
stencil_ = state;
|
|
return *this;
|
|
}
|
|
|
|
render::state_block& render::state_block::culling(const culling_state& state) noexcept {
|
|
culling_ = state;
|
|
return *this;
|
|
}
|
|
|
|
render::state_block& render::state_block::blending(const blending_state& state) noexcept {
|
|
blending_ = state;
|
|
return *this;
|
|
}
|
|
|
|
render::state_block& render::state_block::capabilities(const capabilities_state& state) noexcept {
|
|
capabilities_ = state;
|
|
return *this;
|
|
}
|
|
|
|
render::depth_state& render::state_block::depth() noexcept {
|
|
return depth_;
|
|
}
|
|
|
|
render::stencil_state& render::state_block::stencil() noexcept {
|
|
return stencil_;
|
|
}
|
|
|
|
render::culling_state& render::state_block::culling() noexcept {
|
|
return culling_;
|
|
}
|
|
|
|
render::blending_state& render::state_block::blending() noexcept {
|
|
return blending_;
|
|
}
|
|
|
|
render::capabilities_state& render::state_block::capabilities() noexcept {
|
|
return capabilities_;
|
|
}
|
|
|
|
const render::depth_state& render::state_block::depth() const noexcept {
|
|
return depth_;
|
|
}
|
|
|
|
const render::stencil_state& render::state_block::stencil() const noexcept {
|
|
return stencil_;
|
|
}
|
|
|
|
const render::culling_state& render::state_block::culling() const noexcept {
|
|
return culling_;
|
|
}
|
|
|
|
const render::blending_state& render::state_block::blending() const noexcept {
|
|
return blending_;
|
|
}
|
|
|
|
const render::capabilities_state& render::state_block::capabilities() const noexcept {
|
|
return capabilities_;
|
|
}
|
|
|
|
//
|
|
// render::property_block::sampler
|
|
//
|
|
|
|
render::sampler_state& render::sampler_state::texture(const texture_ptr& texture) noexcept {
|
|
texture_ = texture;
|
|
return *this;
|
|
}
|
|
|
|
render::sampler_state& render::sampler_state::wrap(sampler_wrap s, sampler_wrap t) noexcept {
|
|
s_wrap(s);
|
|
t_wrap(t);
|
|
return *this;
|
|
}
|
|
|
|
render::sampler_state& render::sampler_state::s_wrap(sampler_wrap s) noexcept {
|
|
s_wrap_ = s;
|
|
return *this;
|
|
}
|
|
|
|
render::sampler_state& render::sampler_state::t_wrap(sampler_wrap t) noexcept {
|
|
t_wrap_ = t;
|
|
return *this;
|
|
}
|
|
|
|
render::sampler_state& render::sampler_state::filter(sampler_min_filter min, sampler_mag_filter mag) noexcept {
|
|
min_filter(min);
|
|
mag_filter(mag);
|
|
return *this;
|
|
}
|
|
|
|
render::sampler_state& render::sampler_state::min_filter(sampler_min_filter min) noexcept {
|
|
min_filter_ = min;
|
|
return *this;
|
|
}
|
|
|
|
render::sampler_state& render::sampler_state::mag_filter(sampler_mag_filter mag) noexcept {
|
|
mag_filter_ = mag;
|
|
return *this;
|
|
}
|
|
|
|
const texture_ptr& render::sampler_state::texture() const noexcept {
|
|
return texture_;
|
|
}
|
|
|
|
render::sampler_wrap render::sampler_state::s_wrap() const noexcept {
|
|
return s_wrap_;
|
|
}
|
|
|
|
render::sampler_wrap render::sampler_state::t_wrap() const noexcept {
|
|
return t_wrap_;
|
|
}
|
|
|
|
render::sampler_min_filter render::sampler_state::min_filter() const noexcept {
|
|
return min_filter_;
|
|
}
|
|
|
|
render::sampler_mag_filter render::sampler_state::mag_filter() const noexcept {
|
|
return mag_filter_;
|
|
}
|
|
|
|
//
|
|
// render::property_block
|
|
//
|
|
|
|
render::property_block& render::property_block::clear() noexcept {
|
|
properties_.clear();
|
|
samplers_.clear();
|
|
return *this;
|
|
}
|
|
|
|
render::property_block& render::property_block::merge(const property_block& pb) {
|
|
properties_.merge(pb.properties_);
|
|
samplers_.merge(pb.samplers_);
|
|
return *this;
|
|
}
|
|
|
|
bool render::property_block::equals(const property_block& other) const noexcept {
|
|
if ( properties_.size() != other.properties_.size() ) {
|
|
return false;
|
|
}
|
|
if ( samplers_.size() != other.samplers_.size() ) {
|
|
return false;
|
|
}
|
|
return properties_.equals(other.properties_)
|
|
&& samplers_.equals(other.samplers_);
|
|
}
|
|
|
|
render::property_block& render::property_block::sampler(str_hash name, const sampler_state& s) {
|
|
samplers_.assign(name, s);
|
|
return *this;
|
|
}
|
|
|
|
render::sampler_state* render::property_block::sampler(str_hash name) noexcept {
|
|
return samplers_.find(name);
|
|
}
|
|
|
|
const render::sampler_state* render::property_block::sampler(str_hash name) const noexcept {
|
|
return samplers_.find(name);
|
|
}
|
|
|
|
render::property_block& render::property_block::property(str_hash name, const property_value& v) {
|
|
properties_.assign(name, v);
|
|
return *this;
|
|
}
|
|
|
|
render::property_value* render::property_block::property(str_hash name) noexcept {
|
|
return properties_.find(name);
|
|
}
|
|
|
|
const render::property_value* render::property_block::property(str_hash name) const noexcept {
|
|
return properties_.find(name);
|
|
}
|
|
|
|
std::size_t render::property_block::sampler_count() const noexcept {
|
|
return samplers_.size();
|
|
}
|
|
|
|
std::size_t render::property_block::property_count() const noexcept {
|
|
return properties_.size();
|
|
}
|
|
|
|
//
|
|
// pass_state
|
|
//
|
|
|
|
render::pass_state& render::pass_state::shader(const shader_ptr& shader) noexcept {
|
|
shader_ = shader;
|
|
return *this;
|
|
}
|
|
|
|
render::pass_state& render::pass_state::states(const state_block& render_state) noexcept {
|
|
states_ = render_state;
|
|
return *this;
|
|
}
|
|
|
|
render::pass_state& render::pass_state::properties(const property_block& properties) noexcept {
|
|
properties_ = properties;
|
|
return *this;
|
|
}
|
|
|
|
shader_ptr& render::pass_state::shader() noexcept {
|
|
return shader_;
|
|
}
|
|
|
|
render::state_block& render::pass_state::states() noexcept {
|
|
return states_;
|
|
}
|
|
|
|
render::property_block& render::pass_state::properties() noexcept {
|
|
return properties_;
|
|
}
|
|
|
|
const shader_ptr& render::pass_state::shader() const noexcept {
|
|
return shader_;
|
|
}
|
|
|
|
const render::state_block& render::pass_state::states() const noexcept {
|
|
return states_;
|
|
}
|
|
|
|
const render::property_block& render::pass_state::properties() const noexcept {
|
|
return properties_;
|
|
}
|
|
|
|
//
|
|
// material
|
|
//
|
|
|
|
render::material& render::material::clear() noexcept {
|
|
return *this = material();
|
|
}
|
|
|
|
bool render::material::equals(const material& other) const noexcept {
|
|
if ( pass_count_ != other.pass_count_ ) {
|
|
return false;
|
|
}
|
|
for ( std::size_t i = 0, e = pass_count_; i < e; ++i ) {
|
|
if ( passes_[i] != other.passes_[i] ) {
|
|
return false;
|
|
}
|
|
}
|
|
return properties_ == other.properties_;
|
|
}
|
|
|
|
render::material& render::material::add_pass(const pass_state& pass) noexcept {
|
|
E2D_ASSERT(pass_count_ < max_pass_count);
|
|
passes_[pass_count_] = pass;
|
|
++pass_count_;
|
|
return *this;
|
|
}
|
|
|
|
std::size_t render::material::pass_count() const noexcept {
|
|
return pass_count_;
|
|
}
|
|
|
|
render::material& render::material::properties(const property_block& properties) noexcept {
|
|
properties_ = properties;
|
|
return *this;
|
|
}
|
|
|
|
render::pass_state& render::material::pass(std::size_t index) noexcept {
|
|
return passes_[index];
|
|
}
|
|
|
|
const render::pass_state& render::material::pass(std::size_t index) const noexcept {
|
|
return passes_[index];
|
|
}
|
|
|
|
render::property_block& render::material::properties() noexcept {
|
|
return properties_;
|
|
}
|
|
|
|
const render::property_block& render::material::properties() const noexcept {
|
|
return properties_;
|
|
}
|
|
|
|
//
|
|
// geometry
|
|
//
|
|
|
|
render::geometry& render::geometry::clear() noexcept {
|
|
return *this = geometry();
|
|
}
|
|
|
|
bool render::geometry::equals(const geometry& other) const noexcept {
|
|
if ( topology_ != other.topology_ ) {
|
|
return false;
|
|
}
|
|
if ( indices_ != other.indices_ ) {
|
|
return false;
|
|
}
|
|
if ( vertices_count_ != other.vertices_count_ ) {
|
|
return false;
|
|
}
|
|
for ( std::size_t i = 0, e = vertices_count_; i < e; ++i ) {
|
|
if ( vertices_[i] != other.vertices_[i] ) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
render::geometry& render::geometry::add_vertices(const vertex_buffer_ptr& vb) noexcept {
|
|
E2D_ASSERT(vertices_count_ < max_vertices_count);
|
|
vertices_[vertices_count_] = vb;
|
|
++vertices_count_;
|
|
return *this;
|
|
}
|
|
|
|
std::size_t render::geometry::vertices_count() const noexcept {
|
|
return vertices_count_;
|
|
}
|
|
|
|
render::geometry& render::geometry::topo(topology tp) noexcept {
|
|
topology_ = tp;
|
|
return *this;
|
|
}
|
|
|
|
render::geometry& render::geometry::indices(const index_buffer_ptr& ib) noexcept {
|
|
indices_ = ib;
|
|
return *this;
|
|
}
|
|
|
|
render::geometry& render::geometry::vertices(std::size_t index, const vertex_buffer_ptr& vb) noexcept {
|
|
E2D_ASSERT(index < vertices_count_);
|
|
vertices_[index] = vb;
|
|
return *this;
|
|
}
|
|
|
|
render::topology& render::geometry::topo() noexcept {
|
|
return topology_;
|
|
}
|
|
|
|
index_buffer_ptr& render::geometry::indices() noexcept {
|
|
return indices_;
|
|
}
|
|
|
|
vertex_buffer_ptr& render::geometry::vertices(std::size_t index) noexcept {
|
|
E2D_ASSERT(index < vertices_count_);
|
|
return vertices_[index];
|
|
}
|
|
|
|
const render::topology& render::geometry::topo() const noexcept {
|
|
return topology_;
|
|
}
|
|
|
|
const index_buffer_ptr& render::geometry::indices() const noexcept {
|
|
return indices_;
|
|
}
|
|
|
|
const vertex_buffer_ptr& render::geometry::vertices(std::size_t index) const noexcept {
|
|
E2D_ASSERT(index < vertices_count_);
|
|
return vertices_[index];
|
|
}
|
|
|
|
//
|
|
// draw_command
|
|
//
|
|
|
|
render::draw_command::draw_command(const material& mat, const geometry& geo) noexcept
|
|
: material_(&mat)
|
|
, geometry_(&geo) {}
|
|
|
|
render::draw_command::draw_command(const material& mat, const geometry& geo, const property_block& props) noexcept
|
|
: material_(&mat)
|
|
, geometry_(&geo)
|
|
, properties_(&props) {}
|
|
|
|
render::draw_command& render::draw_command::index_range(std::size_t first, std::size_t count) noexcept {
|
|
first_index_ = first;
|
|
index_count_ = count;
|
|
return *this;
|
|
}
|
|
|
|
render::draw_command& render::draw_command::first_index(std::size_t value) noexcept {
|
|
first_index_ = value;
|
|
return *this;
|
|
}
|
|
|
|
render::draw_command& render::draw_command::index_count(std::size_t value) noexcept {
|
|
index_count_ = value;
|
|
return *this;
|
|
}
|
|
|
|
render::draw_command& render::draw_command::material_ref(const material& value) noexcept {
|
|
material_ = &value;
|
|
return *this;
|
|
}
|
|
|
|
render::draw_command& render::draw_command::geometry_ref(const geometry& value) noexcept {
|
|
geometry_ = &value;
|
|
return *this;
|
|
}
|
|
|
|
render::draw_command& render::draw_command::properties_ref(const property_block& value) {
|
|
properties_ = &value;
|
|
return *this;
|
|
}
|
|
|
|
std::size_t render::draw_command::first_index() const noexcept {
|
|
return first_index_;
|
|
}
|
|
|
|
std::size_t render::draw_command::index_count() const noexcept {
|
|
return index_count_;
|
|
}
|
|
|
|
const render::material& render::draw_command::material_ref() const noexcept {
|
|
E2D_ASSERT_MSG(material_, "draw command with empty material");
|
|
return *material_;
|
|
}
|
|
|
|
const render::geometry& render::draw_command::geometry_ref() const noexcept {
|
|
E2D_ASSERT_MSG(material_, "draw command with empty geometry");
|
|
return *geometry_;
|
|
}
|
|
|
|
const render::property_block& render::draw_command::properties_ref() const noexcept {
|
|
static property_block empty_property_block;
|
|
return properties_ ? *properties_ : empty_property_block;
|
|
}
|
|
|
|
//
|
|
// clear_command
|
|
//
|
|
|
|
render::clear_command::clear_command(buffer clear_buffer) noexcept
|
|
: clear_buffer_(clear_buffer) {}
|
|
|
|
render::clear_command& render::clear_command::color_value(const color& value) noexcept {
|
|
color_value_ = value;
|
|
return *this;
|
|
}
|
|
|
|
render::clear_command& render::clear_command::depth_value(f32 value) noexcept {
|
|
depth_value_ = value;
|
|
return *this;
|
|
}
|
|
|
|
render::clear_command& render::clear_command::stencil_value(u8 value) noexcept {
|
|
stencil_value_ = value;
|
|
return *this;
|
|
}
|
|
|
|
color& render::clear_command::color_value() noexcept {
|
|
return color_value_;
|
|
}
|
|
|
|
f32& render::clear_command::depth_value() noexcept {
|
|
return depth_value_;
|
|
}
|
|
|
|
u8& render::clear_command::stencil_value() noexcept {
|
|
return stencil_value_;
|
|
}
|
|
|
|
const color& render::clear_command::color_value() const noexcept {
|
|
return color_value_;
|
|
}
|
|
|
|
f32 render::clear_command::depth_value() const noexcept {
|
|
return depth_value_;
|
|
}
|
|
|
|
u8 render::clear_command::stencil_value() const noexcept {
|
|
return stencil_value_;
|
|
}
|
|
|
|
render::clear_command::buffer& render::clear_command::clear_buffer() noexcept {
|
|
return clear_buffer_;
|
|
}
|
|
|
|
render::clear_command::buffer render::clear_command::clear_buffer() const noexcept {
|
|
return clear_buffer_;
|
|
}
|
|
|
|
//
|
|
// target_command
|
|
//
|
|
|
|
render::target_command::target_command(const render_target_ptr& rt) noexcept
|
|
: target_(rt) {}
|
|
|
|
render::target_command& render::target_command::target(const render_target_ptr& value) noexcept {
|
|
target_ = value;
|
|
return *this;
|
|
}
|
|
|
|
render_target_ptr& render::target_command::target() noexcept {
|
|
return target_;
|
|
}
|
|
|
|
const render_target_ptr& render::target_command::target() const noexcept {
|
|
return target_;
|
|
}
|
|
|
|
//
|
|
// viewport_command
|
|
//
|
|
|
|
render::viewport_command::viewport_command(const b2i& viewport_rect) noexcept
|
|
: viewport_rect_(viewport_rect) {}
|
|
|
|
render::viewport_command::viewport_command(const b2i& viewport_rect, const b2i& scissor_rect) noexcept
|
|
: viewport_rect_(viewport_rect)
|
|
, scissor_rect_(scissor_rect)
|
|
, scissoring_(true) {}
|
|
|
|
render::viewport_command& render::viewport_command::viewport_rect(const b2i& value) noexcept {
|
|
viewport_rect_ = value;
|
|
return *this;
|
|
}
|
|
|
|
render::viewport_command& render::viewport_command::scissor_rect(const b2i& value) noexcept {
|
|
scissor_rect_ = value;
|
|
scissoring_ = true;
|
|
return *this;
|
|
}
|
|
|
|
render::viewport_command& render::viewport_command::scissoring(bool value) noexcept {
|
|
scissoring_ = value;
|
|
return *this;
|
|
}
|
|
|
|
b2i& render::viewport_command::viewport_rect() noexcept {
|
|
return viewport_rect_;
|
|
}
|
|
|
|
b2i& render::viewport_command::scissor_rect() noexcept {
|
|
return scissor_rect_;
|
|
}
|
|
|
|
bool& render::viewport_command::scissoring() noexcept {
|
|
return scissoring_;
|
|
}
|
|
|
|
const b2i& render::viewport_command::viewport_rect() const noexcept {
|
|
return viewport_rect_;
|
|
}
|
|
|
|
const b2i& render::viewport_command::scissor_rect() const noexcept {
|
|
return scissor_rect_;
|
|
}
|
|
|
|
bool render::viewport_command::scissoring() const noexcept {
|
|
return scissoring_;
|
|
}
|
|
|
|
//
|
|
// render
|
|
//
|
|
|
|
render& render::execute(const command_value& command) {
|
|
E2D_ASSERT(is_in_main_thread());
|
|
E2D_ASSERT(!command.valueless_by_exception());
|
|
std::visit(command_value_visitor(*this), command);
|
|
return *this;
|
|
}
|
|
}
|
|
|
|
namespace e2d
|
|
{
|
|
bool operator==(const render::state_block& l, const render::state_block& r) noexcept {
|
|
return l.depth() == r.depth()
|
|
&& l.stencil() == r.stencil()
|
|
&& l.culling() == r.culling()
|
|
&& l.blending() == r.blending()
|
|
&& l.capabilities() == r.capabilities();
|
|
}
|
|
|
|
bool operator!=(const render::state_block& l, const render::state_block& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
|
|
bool operator==(const render::depth_state& l, const render::depth_state& r) noexcept {
|
|
return math::approximately(l.range_near(), r.range_near())
|
|
&& math::approximately(l.range_far(), r.range_far())
|
|
&& l.write() == r.write()
|
|
&& l.func() == r.func();
|
|
}
|
|
|
|
bool operator!=(const render::depth_state& l, const render::depth_state& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
|
|
bool operator==(const render::stencil_state& l, const render::stencil_state& r) noexcept {
|
|
return l.write() == r.write()
|
|
&& l.ref() == r.ref()
|
|
&& l.mask() == r.mask()
|
|
&& l.pass() == r.pass()
|
|
&& l.sfail() == r.sfail()
|
|
&& l.zfail() == r.zfail()
|
|
&& l.func() == r.func();
|
|
}
|
|
|
|
bool operator!=(const render::stencil_state& l, const render::stencil_state& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
|
|
bool operator==(const render::culling_state& l, const render::culling_state& r) noexcept {
|
|
return l.mode() == r.mode()
|
|
&& l.face() == r.face();
|
|
}
|
|
|
|
bool operator!=(const render::culling_state& l, const render::culling_state& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
|
|
bool operator==(const render::blending_state& l, const render::blending_state& r) noexcept {
|
|
return l.constant_color() == r.constant_color()
|
|
&& l.color_mask() == r.color_mask()
|
|
&& l.src_rgb_factor() == r.src_rgb_factor()
|
|
&& l.dst_rgb_factor() == r.dst_rgb_factor()
|
|
&& l.rgb_equation() == r.rgb_equation()
|
|
&& l.src_alpha_factor() == r.src_alpha_factor()
|
|
&& l.dst_alpha_factor() == r.dst_alpha_factor()
|
|
&& l.alpha_equation() == r.alpha_equation();
|
|
}
|
|
|
|
bool operator!=(const render::blending_state& l, const render::blending_state& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
|
|
bool operator==(const render::capabilities_state& l, const render::capabilities_state& r) noexcept {
|
|
return l.culling() == r.culling()
|
|
&& l.blending() == r.blending()
|
|
&& l.depth_test() == r.depth_test()
|
|
&& l.stencil_test() == r.stencil_test();
|
|
}
|
|
|
|
bool operator!=(const render::capabilities_state& l, const render::capabilities_state& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
|
|
bool operator==(const render::property_block& l, const render::property_block& r) noexcept {
|
|
return l.equals(r);
|
|
}
|
|
|
|
bool operator!=(const render::property_block& l, const render::property_block& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
|
|
bool operator==(const render::sampler_state& l, const render::sampler_state& r) noexcept {
|
|
return l.texture() == r.texture()
|
|
&& l.s_wrap() == r.s_wrap()
|
|
&& l.t_wrap() == r.t_wrap()
|
|
&& l.min_filter() == r.min_filter()
|
|
&& l.mag_filter() == r.mag_filter();
|
|
}
|
|
|
|
bool operator!=(const render::sampler_state& l, const render::sampler_state& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
|
|
bool operator==(const render::material& l, const render::material& r) noexcept {
|
|
return l.equals(r);
|
|
}
|
|
|
|
bool operator!=(const render::material& l, const render::material& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
|
|
bool operator==(const render::pass_state& l, const render::pass_state& r) noexcept {
|
|
return l.shader() == r.shader()
|
|
&& l.states() == r.states()
|
|
&& l.properties() == r.properties();
|
|
}
|
|
|
|
bool operator!=(const render::pass_state& l, const render::pass_state& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
|
|
bool operator==(const render::geometry& l, const render::geometry& r) noexcept {
|
|
return l.equals(r);
|
|
}
|
|
|
|
bool operator!=(const render::geometry& l, const render::geometry& r) noexcept {
|
|
return !(l == r);
|
|
}
|
|
}
|