mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-14 16:09:06 +07:00
render: materials, properties, states, geometry
This commit is contained in:
@@ -92,55 +92,55 @@ namespace e2d
|
||||
|
||||
class attribute_info final {
|
||||
public:
|
||||
str name;
|
||||
std::size_t rows = 0;
|
||||
std::size_t columns = 0;
|
||||
std::size_t stride = 0;
|
||||
str_hash name;
|
||||
u8 rows = 0;
|
||||
u8 columns = 0;
|
||||
attribute_type type = attribute_type::floating_point;
|
||||
bool normalized = false;
|
||||
public:
|
||||
attribute_info();
|
||||
attribute_info() noexcept;
|
||||
~attribute_info() noexcept;
|
||||
|
||||
attribute_info(const attribute_info&);
|
||||
attribute_info& operator=(const attribute_info&);
|
||||
attribute_info(const attribute_info&) noexcept;
|
||||
attribute_info& operator=(const attribute_info&) noexcept;
|
||||
|
||||
attribute_info(
|
||||
str_view name,
|
||||
std::size_t rows,
|
||||
std::size_t columns,
|
||||
std::size_t stride,
|
||||
str_hash name,
|
||||
u8 rows,
|
||||
u8 columns,
|
||||
attribute_type type,
|
||||
bool normalized);
|
||||
bool normalized) noexcept;
|
||||
|
||||
std::size_t row_size() const noexcept;
|
||||
};
|
||||
public:
|
||||
vertex_declaration();
|
||||
vertex_declaration() noexcept;
|
||||
~vertex_declaration() noexcept;
|
||||
|
||||
vertex_declaration(const vertex_declaration&);
|
||||
vertex_declaration& operator=(const vertex_declaration&);
|
||||
vertex_declaration(const vertex_declaration&) noexcept;
|
||||
vertex_declaration& operator=(const vertex_declaration&) noexcept;
|
||||
|
||||
template < typename T >
|
||||
vertex_declaration& add_attribute(str_view name);
|
||||
vertex_declaration& add_attribute(str_hash name) noexcept;
|
||||
vertex_declaration& normalized() noexcept;
|
||||
|
||||
vertex_declaration& skip_bytes(
|
||||
std::size_t bytes) noexcept;
|
||||
|
||||
vertex_declaration& add_attribute(
|
||||
str_view name,
|
||||
std::size_t rows,
|
||||
std::size_t columns,
|
||||
str_hash name,
|
||||
u8 rows,
|
||||
u8 columns,
|
||||
attribute_type type,
|
||||
bool normalized);
|
||||
bool normalized) noexcept;
|
||||
|
||||
const attribute_info& attribute(std::size_t i) const noexcept;
|
||||
std::size_t attribute_count() const noexcept;
|
||||
std::size_t vertex_size() const noexcept;
|
||||
private:
|
||||
constexpr static std::size_t max_attribute_count = 16;
|
||||
constexpr static std::size_t max_attribute_count = 8;
|
||||
array<attribute_info, max_attribute_count> attributes_;
|
||||
std::size_t attribute_count_ = 0;
|
||||
std::size_t vertex_size_ = 0;
|
||||
@@ -168,54 +168,9 @@ namespace e2d
|
||||
class internal_state;
|
||||
using internal_state_uptr = std::unique_ptr<internal_state>;
|
||||
const internal_state& state() const noexcept;
|
||||
public:
|
||||
enum class uniform_type : u8 {
|
||||
signed_integer,
|
||||
floating_point,
|
||||
|
||||
v2i,
|
||||
v3i,
|
||||
v4i,
|
||||
|
||||
v2f,
|
||||
v3f,
|
||||
v4f,
|
||||
|
||||
m2f,
|
||||
m3f,
|
||||
m4f,
|
||||
|
||||
sampler_2d,
|
||||
sampler_cube
|
||||
};
|
||||
|
||||
enum class attribute_type : u8 {
|
||||
floating_point,
|
||||
|
||||
v2f,
|
||||
v3f,
|
||||
v4f,
|
||||
|
||||
m2f,
|
||||
m3f,
|
||||
m4f
|
||||
};
|
||||
public:
|
||||
explicit shader(internal_state_uptr);
|
||||
~shader() noexcept;
|
||||
const vertex_declaration& decl() const noexcept;
|
||||
void set_uniform(str_view name, i32 value) const noexcept;
|
||||
void set_uniform(str_view name, f32 value) const noexcept;
|
||||
void set_uniform(str_view name, const v2i& value) const noexcept;
|
||||
void set_uniform(str_view name, const v3i& value) const noexcept;
|
||||
void set_uniform(str_view name, const v4i& value) const noexcept;
|
||||
void set_uniform(str_view name, const v2f& value) const noexcept;
|
||||
void set_uniform(str_view name, const v3f& value) const noexcept;
|
||||
void set_uniform(str_view name, const v4f& value) const noexcept;
|
||||
void set_uniform(str_view name, const m2f& value) const noexcept;
|
||||
void set_uniform(str_view name, const m3f& value) const noexcept;
|
||||
void set_uniform(str_view name, const m4f& value) const noexcept;
|
||||
void set_uniform(str_view name, const texture_ptr& value) const noexcept;
|
||||
private:
|
||||
internal_state_uptr state_;
|
||||
};
|
||||
@@ -229,23 +184,9 @@ namespace e2d
|
||||
class internal_state;
|
||||
using internal_state_uptr = std::unique_ptr<internal_state>;
|
||||
const internal_state& state() const noexcept;
|
||||
public:
|
||||
enum class wrap : u8 {
|
||||
clamp,
|
||||
repeat,
|
||||
mirror
|
||||
};
|
||||
|
||||
enum class filter : u8 {
|
||||
linear,
|
||||
nearest
|
||||
};
|
||||
public:
|
||||
explicit texture(internal_state_uptr);
|
||||
~texture() noexcept;
|
||||
|
||||
void set_wrap(wrap u, wrap v) noexcept;
|
||||
void set_filter(filter min, filter mag) noexcept;
|
||||
private:
|
||||
internal_state_uptr state_;
|
||||
};
|
||||
@@ -270,7 +211,6 @@ namespace e2d
|
||||
~index_buffer() noexcept;
|
||||
void update(const buffer& indices, std::size_t offset) noexcept;
|
||||
const index_declaration& decl() const noexcept;
|
||||
usage buffer_usage() const noexcept;
|
||||
std::size_t buffer_size() const noexcept;
|
||||
std::size_t index_count() const noexcept;
|
||||
private:
|
||||
@@ -297,7 +237,6 @@ namespace e2d
|
||||
~vertex_buffer() noexcept;
|
||||
void update(const buffer& vertices, std::size_t offset) noexcept;
|
||||
const vertex_declaration& decl() const noexcept;
|
||||
usage buffer_usage() const noexcept;
|
||||
std::size_t buffer_size() const noexcept;
|
||||
std::size_t vertex_count() const noexcept;
|
||||
private:
|
||||
@@ -396,7 +335,27 @@ namespace e2d
|
||||
rgba = r | g | b | a
|
||||
};
|
||||
|
||||
class depth_state {
|
||||
enum class sampler_wrap : u8 {
|
||||
clamp,
|
||||
repeat,
|
||||
mirror
|
||||
};
|
||||
|
||||
enum class sampler_min_filter : u8 {
|
||||
nearest,
|
||||
linear,
|
||||
nearest_mipmap_nearest,
|
||||
linear_mipmap_nearest,
|
||||
nearest_mipmap_linear,
|
||||
linear_mipmap_linear
|
||||
};
|
||||
|
||||
enum class sampler_mag_filter : u8 {
|
||||
nearest,
|
||||
linear
|
||||
};
|
||||
|
||||
class depth_state final {
|
||||
public:
|
||||
depth_state& range(f32 near, f32 far) noexcept;
|
||||
depth_state& write(bool enable) noexcept;
|
||||
@@ -410,7 +369,7 @@ namespace e2d
|
||||
u8 _pad[2] = {0};
|
||||
};
|
||||
|
||||
class stencil_state {
|
||||
class stencil_state final {
|
||||
public:
|
||||
stencil_state& write(u8 mask) noexcept;
|
||||
stencil_state& func(compare_func func, u8 ref, u8 mask) noexcept;
|
||||
@@ -427,7 +386,7 @@ namespace e2d
|
||||
u8 _pad[1] = {0};
|
||||
};
|
||||
|
||||
class culling_state {
|
||||
class culling_state final {
|
||||
public:
|
||||
culling_state& mode(culling_mode mode) noexcept;
|
||||
culling_state& face(culling_face face) noexcept;
|
||||
@@ -438,30 +397,40 @@ namespace e2d
|
||||
u8 _pad[2] = {0};
|
||||
};
|
||||
|
||||
class blending_state {
|
||||
class blending_state final {
|
||||
public:
|
||||
blending_state& constant_color(const color& c) noexcept;
|
||||
blending_state& color_mask(blending_color_mask mask) noexcept;
|
||||
|
||||
blending_state& factor(blending_factor src, blending_factor dst) noexcept;
|
||||
blending_state& src_factor(blending_factor src) noexcept;
|
||||
blending_state& dst_factor(blending_factor dst) noexcept;
|
||||
|
||||
blending_state& rgb_factor(blending_factor src, blending_factor dst) noexcept;
|
||||
blending_state& src_rgb_factor(blending_factor src) noexcept;
|
||||
blending_state& dst_rgb_factor(blending_factor dst) noexcept;
|
||||
|
||||
blending_state& alpha_factor(blending_factor src, blending_factor dst) noexcept;
|
||||
blending_state& src_alpha_factor(blending_factor src) noexcept;
|
||||
blending_state& dst_alpha_factor(blending_factor dst) noexcept;
|
||||
|
||||
blending_state& equation(blending_equation equation) noexcept;
|
||||
blending_state& rgb_equation(blending_equation equation) noexcept;
|
||||
blending_state& alpha_equation(blending_equation equation) noexcept;
|
||||
blending_state& color_mask(blending_color_mask mask) noexcept;
|
||||
private:
|
||||
friend class render;
|
||||
color constant_color_ = color::clear();
|
||||
blending_color_mask color_mask_ = blending_color_mask::rgba;
|
||||
blending_factor src_rgb_factor_ = blending_factor::one;
|
||||
blending_factor dst_rgb_factor_ = blending_factor::zero;
|
||||
blending_equation rgb_equation_ = blending_equation::add;
|
||||
blending_factor src_alpha_factor_ = blending_factor::one;
|
||||
blending_factor dst_alpha_factor_ = blending_factor::zero;
|
||||
blending_equation alpha_equation_ = blending_equation::add;
|
||||
blending_color_mask color_mask_ = blending_color_mask::rgba;
|
||||
u8 _pad[1] = {0};
|
||||
};
|
||||
|
||||
class capabilities_state {
|
||||
class capabilities_state final {
|
||||
public:
|
||||
capabilities_state& culling(bool enable) noexcept;
|
||||
capabilities_state& blending(bool enable) noexcept;
|
||||
@@ -474,21 +443,182 @@ namespace e2d
|
||||
bool depth_test_ = false;
|
||||
bool stencil_test_ = false;
|
||||
};
|
||||
|
||||
class state_block final {
|
||||
public:
|
||||
state_block& depth(const depth_state& state_block) noexcept;
|
||||
state_block& stencil(const stencil_state& state_block) noexcept;
|
||||
state_block& culling(const culling_state& state_block) noexcept;
|
||||
state_block& blending(const blending_state& state_block) noexcept;
|
||||
state_block& capabilities(const capabilities_state& state_block) noexcept;
|
||||
|
||||
depth_state& depth() noexcept;
|
||||
stencil_state& stencil() noexcept;
|
||||
culling_state& culling() noexcept;
|
||||
blending_state& blending() noexcept;
|
||||
capabilities_state& capabilities() noexcept;
|
||||
|
||||
const depth_state& depth() const noexcept;
|
||||
const stencil_state& stencil() const noexcept;
|
||||
const culling_state& culling() const noexcept;
|
||||
const blending_state& blending() const noexcept;
|
||||
const capabilities_state& capabilities() const noexcept;
|
||||
private:
|
||||
depth_state depth_;
|
||||
stencil_state stencil_;
|
||||
culling_state culling_;
|
||||
blending_state blending_;
|
||||
capabilities_state capabilities_;
|
||||
};
|
||||
|
||||
class sampler_state {
|
||||
public:
|
||||
sampler_state& texture(const texture_ptr& texture) noexcept;
|
||||
|
||||
sampler_state& wrap(sampler_wrap st) noexcept;
|
||||
sampler_state& s_wrap(sampler_wrap s) noexcept;
|
||||
sampler_state& t_wrap(sampler_wrap t) noexcept;
|
||||
|
||||
sampler_state& filter(sampler_min_filter min, sampler_mag_filter mag) noexcept;
|
||||
sampler_state& min_filter(sampler_min_filter min) noexcept;
|
||||
sampler_state& mag_filter(sampler_mag_filter mag) noexcept;
|
||||
|
||||
const texture_ptr& texture() const noexcept;
|
||||
|
||||
sampler_wrap s_wrap() const noexcept;
|
||||
sampler_wrap t_wrap() const noexcept;
|
||||
|
||||
sampler_min_filter min_filter() const noexcept;
|
||||
sampler_mag_filter mag_filter() const noexcept;
|
||||
private:
|
||||
texture_ptr texture_;
|
||||
sampler_wrap s_wrap_;
|
||||
sampler_wrap t_wrap_;
|
||||
sampler_min_filter min_filter_;
|
||||
sampler_mag_filter mag_filter_;
|
||||
u8 _pad[4] = {0};
|
||||
};
|
||||
|
||||
using property_value = stdex::variant<
|
||||
i32, f32,
|
||||
v2i, v3i, v4i,
|
||||
v2f, v3f, v4f,
|
||||
m2f, m3f, m4f>;
|
||||
|
||||
class property_block final {
|
||||
public:
|
||||
property_block() noexcept;
|
||||
~property_block() noexcept;
|
||||
|
||||
property_block(property_block&&) noexcept;
|
||||
property_block& operator=(property_block&&) noexcept;
|
||||
|
||||
property_block(const property_block&);
|
||||
property_block& operator=(const property_block&);
|
||||
|
||||
property_block& clear() noexcept;
|
||||
property_block& merge(const property_block& pb);
|
||||
|
||||
property_block& sampler(str_hash name, const sampler_state& s);
|
||||
const sampler_state* sampler(str_hash name) const noexcept;
|
||||
|
||||
template < typename T >
|
||||
property_block& property(str_hash name, T&& v);
|
||||
template < typename T >
|
||||
const T* property(str_hash name) const noexcept;
|
||||
|
||||
property_block& property(str_hash name, const property_value& v);
|
||||
const property_value* property(str_hash name) const noexcept;
|
||||
|
||||
template < typename F >
|
||||
void foreach_by_samplers(F&& f) const;
|
||||
|
||||
template < typename F >
|
||||
void foreach_by_properties(F&& f) const;
|
||||
|
||||
std::size_t sampler_count() const noexcept;
|
||||
std::size_t property_count() const noexcept;
|
||||
private:
|
||||
hash_map<str_hash, sampler_state> samplers_;
|
||||
hash_map<str_hash, property_value> properties_;
|
||||
};
|
||||
|
||||
class pass_state final {
|
||||
public:
|
||||
pass_state& shader(const shader_ptr& shader) noexcept;
|
||||
pass_state& states(const state_block& states) noexcept;
|
||||
pass_state& properties(const property_block& properties) noexcept;
|
||||
|
||||
shader_ptr& shader() noexcept;
|
||||
state_block& states() noexcept;
|
||||
property_block& properties() noexcept;
|
||||
|
||||
const shader_ptr& shader() const noexcept;
|
||||
const state_block& states() const noexcept;
|
||||
const property_block& properties() const noexcept;
|
||||
private:
|
||||
property_block properties_;
|
||||
shader_ptr shader_;
|
||||
state_block states_;
|
||||
u8 _pad[4] = {0};
|
||||
};
|
||||
|
||||
class material final {
|
||||
public:
|
||||
material& add_pass(const pass_state& pass) noexcept;
|
||||
std::size_t pass_count() const noexcept;
|
||||
|
||||
material& properties(const property_block& properties) noexcept;
|
||||
|
||||
pass_state& pass(std::size_t index) noexcept;
|
||||
const pass_state& pass(std::size_t index) const noexcept;
|
||||
|
||||
property_block& properties() noexcept;
|
||||
const property_block& properties() const noexcept;
|
||||
private:
|
||||
constexpr static std::size_t max_pass_count = 8;
|
||||
array<pass_state, max_pass_count> passes_;
|
||||
std::size_t pass_count_ = 0;
|
||||
property_block properties_;
|
||||
};
|
||||
|
||||
class geometry final {
|
||||
public:
|
||||
geometry& add_vertices(const vertex_buffer_ptr& vb) noexcept;
|
||||
std::size_t vertices_count() const noexcept;
|
||||
|
||||
geometry& topo(topology tp) noexcept;
|
||||
geometry& indices(const index_buffer_ptr& ib) noexcept;
|
||||
geometry& vertices(std::size_t index, const vertex_buffer_ptr& vb) noexcept;
|
||||
|
||||
topology& topo() noexcept;
|
||||
index_buffer_ptr& indices() noexcept;
|
||||
vertex_buffer_ptr& vertices(std::size_t index) noexcept;
|
||||
|
||||
const topology& topo() const noexcept;
|
||||
const index_buffer_ptr& indices() const noexcept;
|
||||
const vertex_buffer_ptr& vertices(std::size_t index) const noexcept;
|
||||
private:
|
||||
constexpr static std::size_t max_vertices_count = 8;
|
||||
index_buffer_ptr indices_;
|
||||
array<vertex_buffer_ptr, max_vertices_count> vertices_;
|
||||
std::size_t vertices_count_ = 0;
|
||||
topology topology_ = topology::triangles;
|
||||
u8 _pad[7] = {0};
|
||||
};
|
||||
public:
|
||||
render(debug& d, window& w);
|
||||
~render() noexcept final;
|
||||
|
||||
shader_ptr create_shader(
|
||||
input_stream_uptr vertex,
|
||||
input_stream_uptr fragment,
|
||||
const vertex_declaration& decl);
|
||||
input_stream_uptr vertex_stream,
|
||||
input_stream_uptr fragment_stream);
|
||||
|
||||
texture_ptr create_texture(
|
||||
const image& image);
|
||||
|
||||
texture_ptr create_texture(
|
||||
const v2u& size,
|
||||
image_data_format format);
|
||||
const input_stream_uptr& image_stream);
|
||||
|
||||
index_buffer_ptr create_index_buffer(
|
||||
const buffer& indices,
|
||||
@@ -501,25 +631,18 @@ namespace e2d
|
||||
vertex_buffer::usage usage);
|
||||
|
||||
void draw(
|
||||
topology tp,
|
||||
const shader_ptr& ps,
|
||||
const index_buffer_ptr& ib,
|
||||
const vertex_buffer_ptr& vb) noexcept;
|
||||
const material& mat,
|
||||
const geometry& geo);
|
||||
|
||||
void draw(
|
||||
const material& mat,
|
||||
const geometry& geo,
|
||||
const property_block& props);
|
||||
|
||||
render& clear_depth_buffer(f32 value) noexcept;
|
||||
render& clear_stencil_buffer(u8 value) noexcept;
|
||||
render& clear_color_buffer(const color& value) noexcept;
|
||||
|
||||
render& set_model(const m4f& model) noexcept;
|
||||
render& set_view(const m4f& view) noexcept;
|
||||
render& set_projection(const m4f& projection) noexcept;
|
||||
render& set_viewport(u32 x, u32 y, u32 w, u32 h) noexcept;
|
||||
|
||||
render& set_depth_state(const depth_state& ds) noexcept;
|
||||
render& set_stencil_state(const stencil_state& ss) noexcept;
|
||||
render& set_culling_state(const culling_state& cs) noexcept;
|
||||
render& set_blending_state(const blending_state& bs) noexcept;
|
||||
render& set_capabilities_state(const capabilities_state& cs) noexcept;
|
||||
private:
|
||||
class internal_state;
|
||||
std::unique_ptr<internal_state> state_;
|
||||
|
||||
@@ -13,8 +13,12 @@
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
//
|
||||
// vertex_declaration
|
||||
//
|
||||
|
||||
template < typename T >
|
||||
vertex_declaration& vertex_declaration::add_attribute(str_view name) {
|
||||
vertex_declaration& vertex_declaration::add_attribute(str_hash name) noexcept {
|
||||
E2D_UNUSED(name);
|
||||
static_assert(sizeof(T) == 0, "not implemented for this type");
|
||||
return *this;
|
||||
@@ -22,7 +26,7 @@ namespace e2d
|
||||
|
||||
#define DEFINE_ADD_ATTRIBUTE_SPECIALIZATION(t, rows, columns, type)\
|
||||
template <>\
|
||||
inline vertex_declaration& vertex_declaration::add_attribute<t>(str_view name) {\
|
||||
inline vertex_declaration& vertex_declaration::add_attribute<t>(str_hash name) noexcept {\
|
||||
return add_attribute(name, (rows), (columns), attribute_type::type, false);\
|
||||
}
|
||||
|
||||
@@ -70,6 +74,38 @@ namespace e2d
|
||||
DEFINE_ADD_ATTRIBUTE_SPECIALIZATION(color32, 1, 4, unsigned_byte)
|
||||
|
||||
#undef DEFINE_ADD_ATTRIBUTE_SPECIALIZATION
|
||||
|
||||
//
|
||||
// render::property_block
|
||||
//
|
||||
|
||||
template < typename T >
|
||||
render::property_block& render::property_block::property(str_hash name, T&& v) {
|
||||
properties_[name] = std::forward<T>(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
const T* render::property_block::property(str_hash name) const noexcept {
|
||||
const auto iter = properties_.find(name);
|
||||
return iter != properties_.end()
|
||||
? stdex::get_if<T>(&iter->second)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
template < typename F >
|
||||
void render::property_block::foreach_by_samplers(F&& f) const {
|
||||
for ( const auto& p : samplers_ ) {
|
||||
stdex::invoke(f, p.first, p.second);
|
||||
}
|
||||
}
|
||||
|
||||
template < typename F >
|
||||
void render::property_block::foreach_by_properties(F&& f) const {
|
||||
for ( const auto& p : properties_ ) {
|
||||
stdex::invoke(f, p.first, p.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,91 +13,181 @@ namespace
|
||||
"#version 120 \n"
|
||||
" \n"
|
||||
"attribute vec3 a_position; \n"
|
||||
"attribute vec2 a_uv; \n"
|
||||
"attribute vec4 a_color; \n"
|
||||
" \n"
|
||||
"uniform float u_time = 0.0; \n"
|
||||
"uniform float u_time; \n"
|
||||
"uniform mat4 u_MVP; \n"
|
||||
" \n"
|
||||
"varying vec4 color; \n"
|
||||
"varying vec4 v_color; \n"
|
||||
"varying vec2 v_uv; \n"
|
||||
" \n"
|
||||
"void main(){ \n"
|
||||
" color = a_color; \n"
|
||||
" v_color = a_color; \n"
|
||||
" v_uv = a_uv; \n"
|
||||
" \n"
|
||||
" float s = 0.7 + 0.3 * (cos(u_time * 0.003) + 1); \n"
|
||||
" gl_Position = vec4(a_position * s, 1.0); \n"
|
||||
"}";
|
||||
" gl_Position = vec4(a_position * s, 1.0) * u_MVP; \n"
|
||||
"} \n";
|
||||
|
||||
const char* fs_source_cstr =
|
||||
"#version 120 \n"
|
||||
" \n"
|
||||
"varying vec4 color; \n"
|
||||
" \n"
|
||||
"void main(){ \n"
|
||||
" gl_FragColor = color; \n"
|
||||
"}";
|
||||
"#version 120 \n"
|
||||
" \n"
|
||||
"uniform float u_time; \n"
|
||||
"uniform sampler2D u_texture1; \n"
|
||||
"uniform sampler2D u_texture2; \n"
|
||||
"varying vec4 v_color; \n"
|
||||
"varying vec2 v_uv; \n"
|
||||
" \n"
|
||||
"void main(){ \n"
|
||||
" vec2 uv = vec2(v_uv.s, 1.0 - v_uv.t); \n"
|
||||
" if ( u_time > 2000 ) { \n"
|
||||
" gl_FragColor = v_color * texture2D(u_texture2, uv); \n"
|
||||
" } else { \n"
|
||||
" gl_FragColor = v_color * texture2D(u_texture1, uv); \n"
|
||||
" } \n"
|
||||
"} \n";
|
||||
|
||||
struct vertex {
|
||||
struct vertex1 {
|
||||
v3f position;
|
||||
color32 color;
|
||||
v2hu uv;
|
||||
static vertex_declaration decl() noexcept {
|
||||
return vertex_declaration()
|
||||
.add_attribute<v3f>("a_position")
|
||||
.add_attribute<v2hu>("a_uv");
|
||||
}
|
||||
};
|
||||
|
||||
u8 indices[] = {
|
||||
0, 1, 2, 2, 1, 3};
|
||||
struct vertex2 {
|
||||
color32 color;
|
||||
static vertex_declaration decl() noexcept {
|
||||
return vertex_declaration()
|
||||
.add_attribute<color32>("a_color").normalized();
|
||||
}
|
||||
};
|
||||
|
||||
const vertex vertices[] = {
|
||||
{{-0.5f, 0.5f, 0.0f}, color32::red()},
|
||||
{{-0.5f, -0.5f, 0.0f}, color32::green()},
|
||||
{{ 0.5f, 0.5f, 0.0f}, color32::blue()},
|
||||
{{ 0.5f, -0.5f, 0.0f}, color32::white()}};
|
||||
array<u8,6> generate_quad_indices() noexcept {
|
||||
return {0, 1, 2, 2, 1, 3};
|
||||
}
|
||||
|
||||
array<vertex1,4> generate_quad_vertices(f32 w, f32 h) noexcept {
|
||||
f32 hw = w * 0.5f;
|
||||
f32 hh = h * 0.5f;
|
||||
return {
|
||||
vertex1{{-hw, hh, 0.f}, {0, 1}},
|
||||
vertex1{{-hw, -hh, 0.f}, {0, 0}},
|
||||
vertex1{{ hw, hh, 0.f}, {1, 1}},
|
||||
vertex1{{ hw, -hh, 0.f}, {1, 0}}};
|
||||
}
|
||||
|
||||
array<vertex2,4> generate_quad_colors() noexcept {
|
||||
return {
|
||||
vertex2{color32::red()},
|
||||
vertex2{color32::green()},
|
||||
vertex2{color32::blue()},
|
||||
vertex2{color32::yellow()}};
|
||||
}
|
||||
}
|
||||
|
||||
int e2d_main() {
|
||||
modules::initialize<debug>()
|
||||
.register_sink<debug_console_sink>();
|
||||
modules::initialize<input>();
|
||||
modules::initialize<window>(v2u{640, 480}, "Enduro2D", false)
|
||||
.register_event_listener<window_input_source>(the<input>());
|
||||
modules::initialize<render>(the<debug>(), the<window>());
|
||||
{
|
||||
modules::initialize<vfs>()
|
||||
.register_scheme<filesystem_file_source>("file");
|
||||
modules::initialize<debug>()
|
||||
.register_sink<debug_console_sink>();
|
||||
modules::initialize<input>();
|
||||
modules::initialize<window>(v2u{640, 480}, "Enduro2D", false)
|
||||
.register_event_listener<window_input_source>(the<input>());
|
||||
modules::initialize<render>(the<debug>(), the<window>());
|
||||
}
|
||||
{
|
||||
str resources;
|
||||
filesystem::extract_predef_path(resources, filesystem::predef_path::resources);
|
||||
the<vfs>().register_scheme_alias(
|
||||
"resources",
|
||||
url{"file", resources});
|
||||
the<vfs>().register_scheme<archive_file_source>(
|
||||
"piratepack",
|
||||
the<vfs>().open(url("resources://bin/kenney_piratepack.zip")));
|
||||
the<vfs>().register_scheme_alias("ships", url("piratepack://PNG/Retina/Ships"));
|
||||
}
|
||||
|
||||
auto index_decl = index_declaration(
|
||||
index_declaration::index_type::unsigned_byte);
|
||||
auto texture1 = the<render>().create_texture(
|
||||
the<vfs>().open(url("ships://ship (2).png")));
|
||||
auto texture2 = the<render>().create_texture(
|
||||
the<vfs>().open(url("ships://ship (19).png")));
|
||||
|
||||
auto vertex_decl = vertex_declaration()
|
||||
.add_attribute<v3f>("a_position")
|
||||
.add_attribute<color32>("a_color").normalized();
|
||||
|
||||
const auto ps = the<render>().create_shader(
|
||||
const auto shader = the<render>().create_shader(
|
||||
make_memory_stream(buffer(vs_source_cstr, std::strlen(vs_source_cstr))),
|
||||
make_memory_stream(buffer(fs_source_cstr, std::strlen(fs_source_cstr))),
|
||||
vertex_decl);
|
||||
make_memory_stream(buffer(fs_source_cstr, std::strlen(fs_source_cstr))));
|
||||
|
||||
const auto ib = the<render>().create_index_buffer(
|
||||
buffer(indices, E2D_COUNTOF(indices) * sizeof(indices[0])),
|
||||
index_decl,
|
||||
const auto indices = generate_quad_indices();
|
||||
const auto index_buffer = the<render>().create_index_buffer(
|
||||
buffer(indices.data(), indices.size() * sizeof(indices[0])),
|
||||
index_declaration(index_declaration::index_type::unsigned_byte),
|
||||
index_buffer::usage::static_draw);
|
||||
|
||||
const auto vb = the<render>().create_vertex_buffer(
|
||||
buffer(vertices, E2D_COUNTOF(vertices) * sizeof(vertices[0])),
|
||||
vertex_decl,
|
||||
const auto vertices1 = generate_quad_vertices(66.f, 113.f);
|
||||
const auto vertex_buffer1 = the<render>().create_vertex_buffer(
|
||||
buffer(vertices1.data(), vertices1.size() * sizeof(vertices1[0])),
|
||||
vertex1::decl(),
|
||||
vertex_buffer::usage::static_draw);
|
||||
|
||||
const auto begin_time = time::now_ms();
|
||||
const auto vertices2 = generate_quad_colors();
|
||||
const auto vertex_buffer2 = the<render>().create_vertex_buffer(
|
||||
buffer(vertices2.data(), vertices2.size() * sizeof(vertices2[0])),
|
||||
vertex2::decl(),
|
||||
vertex_buffer::usage::static_draw);
|
||||
|
||||
if ( !texture1 || !texture2 || !shader || !index_buffer || !vertex_buffer1 || !vertex_buffer2 ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto material = render::material()
|
||||
.add_pass(render::pass_state()
|
||||
.states(render::state_block()
|
||||
.capabilities(render::capabilities_state()
|
||||
.blending(true))
|
||||
.blending(render::blending_state()
|
||||
.src_factor(render::blending_factor::src_alpha)
|
||||
.dst_factor(render::blending_factor::one_minus_src_alpha)))
|
||||
.shader(shader)
|
||||
.properties(render::property_block()
|
||||
.sampler("u_texture1", render::sampler_state()
|
||||
.texture(texture1)
|
||||
.min_filter(render::sampler_min_filter::linear)
|
||||
.mag_filter(render::sampler_mag_filter::linear))
|
||||
.sampler("u_texture2", render::sampler_state()
|
||||
.texture(texture2)
|
||||
.min_filter(render::sampler_min_filter::linear)
|
||||
.mag_filter(render::sampler_mag_filter::linear))));
|
||||
|
||||
auto geometry = render::geometry()
|
||||
.indices(index_buffer)
|
||||
.add_vertices(vertex_buffer1)
|
||||
.add_vertices(vertex_buffer2);
|
||||
|
||||
const auto begin_game_time = time::now_ms();
|
||||
const auto framebuffer_size = the<window>().real_size().cast_to<f32>();
|
||||
const auto projection = math::make_orthogonal_matrix4(framebuffer_size.x, framebuffer_size.y, 0.f, 1.f);
|
||||
|
||||
const keyboard& k = the<input>().keyboard();
|
||||
while ( !the<window>().should_close() && !k.is_key_just_released(keyboard_key::escape) ) {
|
||||
{
|
||||
f32 t = (time::now_ms() - begin_time).cast_to<f32>().value;
|
||||
ps->set_uniform("u_time", t);
|
||||
}
|
||||
{
|
||||
the<render>()
|
||||
.clear_depth_buffer(1.f)
|
||||
.clear_stencil_buffer(0)
|
||||
.clear_color_buffer({1.f, 0.4f, 0.f, 1.f})
|
||||
.draw(render::topology::triangles, ps, ib, vb);
|
||||
}
|
||||
|
||||
material.properties()
|
||||
.property("u_time", (time::now_ms() - begin_game_time).cast_to<f32>().value)
|
||||
.property("u_MVP", projection);
|
||||
|
||||
the<render>()
|
||||
.clear_depth_buffer(1.f)
|
||||
.clear_stencil_buffer(0)
|
||||
.clear_color_buffer({1.f, 0.4f, 0.f, 1.f})
|
||||
.draw(material, geometry);
|
||||
|
||||
the<window>().swap_buffers(true);
|
||||
the<input>().frame_tick();
|
||||
window::poll_events();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -105,25 +105,25 @@ namespace e2d
|
||||
// vertex_declaration::attribute_info
|
||||
//
|
||||
|
||||
vertex_declaration::attribute_info::attribute_info() = default;
|
||||
vertex_declaration::attribute_info::attribute_info() noexcept = default;
|
||||
vertex_declaration::attribute_info::~attribute_info() noexcept = default;
|
||||
|
||||
vertex_declaration::attribute_info::attribute_info(
|
||||
const attribute_info&) = default;
|
||||
const attribute_info&) noexcept = default;
|
||||
vertex_declaration::attribute_info& vertex_declaration::attribute_info::operator=(
|
||||
const attribute_info&) = default;
|
||||
const attribute_info&) noexcept = default;
|
||||
|
||||
vertex_declaration::attribute_info::attribute_info(
|
||||
str_view nname,
|
||||
std::size_t nrows,
|
||||
std::size_t ncolumns,
|
||||
std::size_t nstride,
|
||||
str_hash nname,
|
||||
u8 nrows,
|
||||
u8 ncolumns,
|
||||
attribute_type ntype,
|
||||
bool nnormalized)
|
||||
: name(nname)
|
||||
bool nnormalized) noexcept
|
||||
: stride(nstride)
|
||||
, name(std::move(nname))
|
||||
, rows(nrows)
|
||||
, columns(ncolumns)
|
||||
, stride(nstride)
|
||||
, type(ntype)
|
||||
, normalized(nnormalized) {}
|
||||
|
||||
@@ -135,13 +135,13 @@ namespace e2d
|
||||
// vertex_declaration
|
||||
//
|
||||
|
||||
vertex_declaration::vertex_declaration() = default;
|
||||
vertex_declaration::vertex_declaration() noexcept = default;
|
||||
vertex_declaration::~vertex_declaration() noexcept = default;
|
||||
|
||||
vertex_declaration::vertex_declaration(
|
||||
const vertex_declaration&) = default;
|
||||
const vertex_declaration&) noexcept = default;
|
||||
vertex_declaration& vertex_declaration::operator=(
|
||||
const vertex_declaration&) = default;
|
||||
const vertex_declaration&) noexcept = default;
|
||||
|
||||
vertex_declaration& vertex_declaration::normalized() noexcept {
|
||||
E2D_ASSERT(attribute_count_ > 0);
|
||||
@@ -155,19 +155,19 @@ namespace e2d
|
||||
}
|
||||
|
||||
vertex_declaration& vertex_declaration::add_attribute(
|
||||
str_view name,
|
||||
std::size_t rows,
|
||||
std::size_t columns,
|
||||
str_hash name,
|
||||
u8 rows,
|
||||
u8 columns,
|
||||
attribute_type type,
|
||||
bool normalized)
|
||||
bool normalized) noexcept
|
||||
{
|
||||
E2D_ASSERT(attribute_count_ < attributes_.size());
|
||||
const std::size_t stride = vertex_size_;
|
||||
attributes_[attribute_count_] = attribute_info(
|
||||
stride,
|
||||
name,
|
||||
rows,
|
||||
columns,
|
||||
stride,
|
||||
type,
|
||||
normalized);
|
||||
vertex_size_ += attribute_element_size(type) * rows * columns;
|
||||
@@ -211,10 +211,10 @@ namespace e2d
|
||||
const vertex_declaration::attribute_info& l,
|
||||
const vertex_declaration::attribute_info& r) noexcept
|
||||
{
|
||||
return l.name == r.name
|
||||
return l.stride == r.stride
|
||||
&& l.name == r.name
|
||||
&& l.rows == r.rows
|
||||
&& l.columns == r.columns
|
||||
&& l.stride == r.stride
|
||||
&& l.type == r.type
|
||||
&& l.normalized == r.normalized;
|
||||
}
|
||||
@@ -246,30 +246,6 @@ namespace e2d
|
||||
return *this;
|
||||
}
|
||||
|
||||
//
|
||||
// render_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;
|
||||
}
|
||||
|
||||
//
|
||||
// stencil_state
|
||||
//
|
||||
@@ -316,20 +292,57 @@ namespace e2d
|
||||
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;
|
||||
}
|
||||
@@ -350,8 +363,349 @@ namespace e2d
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::blending_state& render::blending_state::color_mask(blending_color_mask mask) noexcept {
|
||||
color_mask_ = mask;
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
|
||||
//
|
||||
// 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 st) noexcept {
|
||||
s_wrap(st);
|
||||
t_wrap(st);
|
||||
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::property_block() noexcept = default;
|
||||
render::property_block::~property_block() noexcept = default;
|
||||
|
||||
render::property_block::property_block(property_block&&) noexcept = default;
|
||||
render::property_block& render::property_block::operator=(property_block&&) noexcept = default;
|
||||
|
||||
render::property_block::property_block(const property_block&) = default;
|
||||
render::property_block& render::property_block::operator=(const property_block&) = default;
|
||||
|
||||
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) {
|
||||
pb.foreach_by_properties([this](str_hash name, const property_value& v){
|
||||
property(name, v);
|
||||
});
|
||||
pb.foreach_by_samplers([this](str_hash name, const sampler_state& s){
|
||||
sampler(name, s);
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::property_block& render::property_block::sampler(str_hash name, const sampler_state& s) {
|
||||
samplers_[name] = s;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const render::sampler_state* render::property_block::sampler(str_hash name) const noexcept {
|
||||
const auto iter = samplers_.find(name);
|
||||
return iter != samplers_.end()
|
||||
? &iter->second
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
render::property_block& render::property_block::property(str_hash name, const property_value& v) {
|
||||
properties_[name] = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const render::property_value* render::property_block::property(str_hash name) const noexcept {
|
||||
const auto iter = properties_.find(name);
|
||||
return iter != properties_.end()
|
||||
? &iter->second
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
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::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::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::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];
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1090
sources/enduro2d/core/render_impl/render_opengl_base.cpp
Normal file
1090
sources/enduro2d/core/render_impl/render_opengl_base.cpp
Normal file
File diff suppressed because it is too large
Load Diff
395
sources/enduro2d/core/render_impl/render_opengl_base.hpp
Normal file
395
sources/enduro2d/core/render_impl/render_opengl_base.hpp
Normal file
@@ -0,0 +1,395 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018 Matvey Cherevko
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "render.hpp"
|
||||
|
||||
#if defined(E2D_RENDER_MODE) && E2D_RENDER_MODE == E2D_RENDER_MODE_OPENGL
|
||||
|
||||
#if defined(E2D_PLATFORM) && E2D_PLATFORM == E2D_PLATFORM_MACOSX
|
||||
# include <OpenGL/gl.h>
|
||||
#endif
|
||||
|
||||
#define GL_FLUSH_ERRORS(dbg)\
|
||||
for ( GLenum err = glGetError(); err != GL_NO_ERROR; err = glGetError() ) {\
|
||||
E2D_ASSERT_MSG(false, "RENDER: GL_FLUSH_ERRORS()");\
|
||||
(dbg).error("RENDER: GL_FLUSH_ERRORS():\n"\
|
||||
"--> File: %0\n"\
|
||||
"--> Line: %1\n"\
|
||||
"--> Code: %2",\
|
||||
__FILE__, __LINE__, e2d::opengl::gl_error_code_to_cstr(err));\
|
||||
if ( err == GL_OUT_OF_MEMORY ) throw std::bad_alloc();\
|
||||
}
|
||||
|
||||
#define GL_CHECK_CODE(dbg, code)\
|
||||
GL_FLUSH_ERRORS(dbg);\
|
||||
code;\
|
||||
for ( GLenum err = glGetError(); err != GL_NO_ERROR; err = glGetError() ) {\
|
||||
E2D_ASSERT_MSG(false, #code);\
|
||||
(dbg).error(\
|
||||
"RENDER: GL_CHECK(%0):\n"\
|
||||
"--> File: %1\n"\
|
||||
"--> Line: %2\n"\
|
||||
"--> Code: %3",\
|
||||
#code, __FILE__, __LINE__, e2d::opengl::gl_error_code_to_cstr(err));\
|
||||
if ( err == GL_OUT_OF_MEMORY ) throw std::bad_alloc();\
|
||||
}
|
||||
|
||||
namespace e2d { namespace opengl
|
||||
{
|
||||
class gl_buffer_id final : private noncopyable {
|
||||
gl_buffer_id(debug& debug, GLuint id, GLenum target, bool owned) noexcept;
|
||||
public:
|
||||
static gl_buffer_id create(debug& debug, GLenum target) noexcept;
|
||||
static gl_buffer_id current(debug& debug, GLenum target) noexcept;
|
||||
public:
|
||||
explicit gl_buffer_id(debug& debug) noexcept;
|
||||
~gl_buffer_id() noexcept;
|
||||
gl_buffer_id(gl_buffer_id&& other) noexcept;
|
||||
bool empty() const noexcept;
|
||||
GLuint operator*() const noexcept;
|
||||
GLenum target() const noexcept;
|
||||
private:
|
||||
debug& debug_;
|
||||
GLuint id_ = 0;
|
||||
GLenum target_ = 0;
|
||||
bool owned_ = false;
|
||||
};
|
||||
|
||||
class gl_shader_id final : private noncopyable {
|
||||
gl_shader_id(debug& debug, GLuint id, GLenum type, bool owned) noexcept;
|
||||
public:
|
||||
static gl_shader_id create(debug& debug, GLenum type) noexcept;
|
||||
public:
|
||||
explicit gl_shader_id(debug& debug) noexcept;
|
||||
~gl_shader_id() noexcept;
|
||||
gl_shader_id(gl_shader_id&& other) noexcept;
|
||||
bool empty() const noexcept;
|
||||
GLuint operator*() const noexcept;
|
||||
GLenum type() const noexcept;
|
||||
private:
|
||||
debug& debug_;
|
||||
GLuint id_ = 0;
|
||||
GLenum type_ = 0;
|
||||
bool owned_ = false;
|
||||
};
|
||||
|
||||
class gl_program_id final : private noncopyable {
|
||||
gl_program_id(debug& debug, GLuint id, bool owned) noexcept;
|
||||
public:
|
||||
static gl_program_id create(debug& debug) noexcept;
|
||||
static gl_program_id current(debug& debug) noexcept;
|
||||
public:
|
||||
explicit gl_program_id(debug& debug) noexcept;
|
||||
~gl_program_id() noexcept;
|
||||
gl_program_id(gl_program_id&& other) noexcept;
|
||||
bool empty() const noexcept;
|
||||
GLuint operator*() const noexcept;
|
||||
private:
|
||||
debug& debug_;
|
||||
GLuint id_ = 0;
|
||||
bool owned_ = false;
|
||||
};
|
||||
|
||||
class gl_texture_id final : private noncopyable {
|
||||
gl_texture_id(debug& debug, GLuint id, GLenum target, bool owned) noexcept;
|
||||
public:
|
||||
static gl_texture_id create(debug& debug, GLenum target) noexcept;
|
||||
static gl_texture_id current(debug& debug, GLenum target) noexcept;
|
||||
public:
|
||||
explicit gl_texture_id(debug& debug) noexcept;
|
||||
~gl_texture_id() noexcept;
|
||||
gl_texture_id(gl_texture_id&& other) noexcept;
|
||||
bool empty() const noexcept;
|
||||
GLuint operator*() const noexcept;
|
||||
GLenum target() const noexcept;
|
||||
private:
|
||||
debug& debug_;
|
||||
GLuint id_ = 0;
|
||||
GLenum target_ = 0;
|
||||
bool owned_ = false;
|
||||
};
|
||||
|
||||
class gl_framebuffer_id final : private noncopyable {
|
||||
gl_framebuffer_id(debug& debug, GLuint id, GLenum target, bool owned) noexcept;
|
||||
public:
|
||||
static gl_framebuffer_id create(debug& debug, GLenum target) noexcept;
|
||||
static gl_framebuffer_id current(debug& debug, GLenum target) noexcept;
|
||||
public:
|
||||
explicit gl_framebuffer_id(debug& debug) noexcept;
|
||||
~gl_framebuffer_id() noexcept;
|
||||
gl_framebuffer_id(gl_framebuffer_id&& other) noexcept;
|
||||
bool empty() const noexcept;
|
||||
GLuint operator*() const noexcept;
|
||||
GLenum target() const noexcept;
|
||||
private:
|
||||
debug& debug_;
|
||||
GLuint id_ = 0;
|
||||
GLenum target_ = 0;
|
||||
bool owned_ = false;
|
||||
};
|
||||
|
||||
bool operator==(const gl_buffer_id& l, const gl_buffer_id& r) noexcept;
|
||||
bool operator==(const gl_shader_id& l, const gl_shader_id& r) noexcept;
|
||||
bool operator==(const gl_program_id& l, const gl_program_id& r) noexcept;
|
||||
bool operator==(const gl_texture_id& l, const gl_texture_id& r) noexcept;
|
||||
bool operator==(const gl_framebuffer_id& l, const gl_framebuffer_id& r) noexcept;
|
||||
|
||||
bool operator!=(const gl_buffer_id& l, const gl_buffer_id& r) noexcept;
|
||||
bool operator!=(const gl_shader_id& l, const gl_shader_id& r) noexcept;
|
||||
bool operator!=(const gl_program_id& l, const gl_program_id& r) noexcept;
|
||||
bool operator!=(const gl_texture_id& l, const gl_texture_id& r) noexcept;
|
||||
bool operator!=(const gl_framebuffer_id& l, const gl_framebuffer_id& r) noexcept;
|
||||
}}
|
||||
|
||||
namespace e2d { namespace opengl
|
||||
{
|
||||
enum class uniform_type : u8 {
|
||||
signed_integer,
|
||||
floating_point,
|
||||
|
||||
v2i,
|
||||
v3i,
|
||||
v4i,
|
||||
|
||||
v2f,
|
||||
v3f,
|
||||
v4f,
|
||||
|
||||
m2f,
|
||||
m3f,
|
||||
m4f,
|
||||
|
||||
sampler_2d,
|
||||
sampler_cube,
|
||||
|
||||
unknown
|
||||
};
|
||||
|
||||
enum class attribute_type : u8 {
|
||||
floating_point,
|
||||
|
||||
v2f,
|
||||
v3f,
|
||||
v4f,
|
||||
|
||||
m2f,
|
||||
m3f,
|
||||
m4f,
|
||||
|
||||
unknown
|
||||
};
|
||||
|
||||
const char* uniform_type_to_cstr(uniform_type ut) noexcept;
|
||||
const char* attribute_type_to_cstr(attribute_type at) noexcept;
|
||||
}}
|
||||
|
||||
namespace e2d { namespace opengl
|
||||
{
|
||||
GLint convert_format_to_internal_format(image_data_format idf) noexcept;
|
||||
GLenum convert_format_to_external_format(image_data_format idf) noexcept;
|
||||
GLenum convert_format_to_external_data_type(image_data_format idf) noexcept;
|
||||
|
||||
GLenum convert_index_type(index_declaration::index_type it) noexcept;
|
||||
GLenum convert_attribute_type(vertex_declaration::attribute_type at) noexcept;
|
||||
|
||||
GLint convert_uniform_type(uniform_type ut) noexcept;
|
||||
GLint convert_attribute_type(attribute_type at) noexcept;
|
||||
|
||||
GLint convert_sampler_wrap(render::sampler_wrap w) noexcept;
|
||||
GLint convert_sampler_filter(render::sampler_min_filter f) noexcept;
|
||||
GLint convert_sampler_filter(render::sampler_mag_filter f) noexcept;
|
||||
|
||||
GLenum convert_buffer_usage(index_buffer::usage u) noexcept;
|
||||
GLenum convert_buffer_usage(vertex_buffer::usage u) noexcept;
|
||||
GLenum convert_topology(render::topology t) noexcept;
|
||||
GLenum convert_stencil_op(render::stencil_op sa) noexcept;
|
||||
GLenum convert_compare_func(render::compare_func cf) noexcept;
|
||||
GLenum convert_culling_mode(render::culling_mode cm) noexcept;
|
||||
GLenum convert_culling_face(render::culling_face cf) noexcept;
|
||||
GLenum convert_blending_factor(render::blending_factor bf) noexcept;
|
||||
GLenum convert_blending_equation(render::blending_equation be) noexcept;
|
||||
|
||||
uniform_type glsl_type_to_uniform_type(GLenum t) noexcept;
|
||||
attribute_type glsl_type_to_attribute_type(GLenum t) noexcept;
|
||||
|
||||
const char* glsl_type_to_cstr(GLenum t) noexcept;
|
||||
const char* gl_error_code_to_cstr(GLenum e) noexcept;
|
||||
GLenum gl_target_to_get_target(GLenum t) noexcept;
|
||||
}}
|
||||
|
||||
namespace e2d { namespace opengl
|
||||
{
|
||||
void gl_trace_info(debug& debug) noexcept;
|
||||
gl_shader_id gl_compile_shader(debug& debug, const str& source, GLenum type) noexcept;
|
||||
gl_program_id gl_link_program(debug& debug, gl_shader_id vs, gl_shader_id fs) noexcept;
|
||||
gl_texture_id gl_compile_texture(debug& debug, const image& image);
|
||||
gl_buffer_id gl_compile_index_buffer(debug& debug, const buffer& indices, index_buffer::usage usage);
|
||||
gl_buffer_id gl_compile_vertex_buffer(debug& debug, const buffer& vertices, vertex_buffer::usage usage);
|
||||
}}
|
||||
|
||||
namespace e2d { namespace opengl
|
||||
{
|
||||
struct uniform_info {
|
||||
str_hash name;
|
||||
GLint size = 0;
|
||||
GLint location = -1;
|
||||
uniform_type type = uniform_type::floating_point;
|
||||
u8 _pad[3] = {0};
|
||||
public:
|
||||
uniform_info(
|
||||
str_hash nname,
|
||||
GLint nsize,
|
||||
GLint nlocation,
|
||||
uniform_type ntype) noexcept
|
||||
: name(std::move(nname))
|
||||
, size(nsize)
|
||||
, location(nlocation)
|
||||
, type(ntype) {}
|
||||
};
|
||||
|
||||
struct attribute_info {
|
||||
str_hash name;
|
||||
GLint size = 0;
|
||||
GLint location = -1;
|
||||
attribute_type type = attribute_type::floating_point;
|
||||
u8 _pad[3] = {0};
|
||||
public:
|
||||
attribute_info(
|
||||
str_hash nname,
|
||||
GLint nsize,
|
||||
GLint nlocation,
|
||||
attribute_type ntype) noexcept
|
||||
: name(std::move(nname))
|
||||
, size(nsize)
|
||||
, location(nlocation)
|
||||
, type(ntype) {}
|
||||
};
|
||||
|
||||
void grab_program_uniforms(
|
||||
debug& debug,
|
||||
GLuint program,
|
||||
vector<uniform_info>& uniforms);
|
||||
|
||||
void grab_program_attributes(
|
||||
debug& debug,
|
||||
GLuint program,
|
||||
vector<attribute_info>& attributes);
|
||||
}}
|
||||
|
||||
namespace e2d { namespace opengl
|
||||
{
|
||||
//
|
||||
// with_gl_use_program
|
||||
//
|
||||
|
||||
template < typename F, typename... Args >
|
||||
void with_gl_use_program(debug& debug, GLuint program, F&& f, Args&&... args) {
|
||||
GLint prev_program = 0;
|
||||
GL_CHECK_CODE(debug, glGetIntegerv(
|
||||
GL_CURRENT_PROGRAM, &prev_program));
|
||||
GL_CHECK_CODE(debug, glUseProgram(
|
||||
program));
|
||||
try {
|
||||
stdex::invoke(std::forward<F>(f), std::forward<Args>(args)...);
|
||||
} catch (...) {
|
||||
GL_CHECK_CODE(debug, glUseProgram(
|
||||
math::numeric_cast<GLuint>(prev_program)));
|
||||
throw;
|
||||
}
|
||||
GL_CHECK_CODE(debug, glUseProgram(
|
||||
math::numeric_cast<GLuint>(prev_program)));
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
void with_gl_use_program(debug& debug, const gl_program_id& program, F&& f, Args&&... args) {
|
||||
with_gl_use_program(debug, *program, std::forward<F>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
//
|
||||
// with_gl_bind_buffer
|
||||
//
|
||||
|
||||
template < typename F, typename... Args >
|
||||
void with_gl_bind_buffer(debug& debug, GLenum target, GLuint buffer, F&& f, Args&&... args) {
|
||||
GLint prev_buffer = 0;
|
||||
GL_CHECK_CODE(debug, glGetIntegerv(
|
||||
gl_target_to_get_target(target), &prev_buffer));
|
||||
GL_CHECK_CODE(debug, glBindBuffer(
|
||||
target, buffer));
|
||||
try {
|
||||
stdex::invoke(std::forward<F>(f), std::forward<Args>(args)...);
|
||||
} catch (...) {
|
||||
GL_CHECK_CODE(debug, glBindBuffer(
|
||||
target, math::numeric_cast<GLuint>(prev_buffer)));
|
||||
throw;
|
||||
}
|
||||
GL_CHECK_CODE(debug, glBindBuffer(
|
||||
target, math::numeric_cast<GLuint>(prev_buffer)));
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
void with_gl_bind_buffer(debug& debug, const gl_buffer_id& buffer, F&& f, Args&&... args) {
|
||||
with_gl_bind_buffer(debug, buffer.target(), *buffer, std::forward<F>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
//
|
||||
// with_gl_bind_texture
|
||||
//
|
||||
|
||||
template < typename F, typename... Args >
|
||||
void with_gl_bind_texture(debug& debug, GLenum target, GLuint texture, F&& f, Args&&... args) {
|
||||
GLint prev_texture = 0;
|
||||
GL_CHECK_CODE(debug, glGetIntegerv(
|
||||
gl_target_to_get_target(target), &prev_texture));
|
||||
GL_CHECK_CODE(debug, glBindTexture(
|
||||
target, texture));
|
||||
try {
|
||||
stdex::invoke(std::forward<F>(f), std::forward<Args>(args)...);
|
||||
} catch (...) {
|
||||
GL_CHECK_CODE(debug, glBindTexture(
|
||||
target, math::numeric_cast<GLuint>(prev_texture)));
|
||||
throw;
|
||||
}
|
||||
GL_CHECK_CODE(debug, glBindTexture(
|
||||
target, math::numeric_cast<GLuint>(prev_texture)));
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
void with_gl_bind_texture(debug& debug, const gl_texture_id& texture, F&& f, Args&&... args) {
|
||||
with_gl_bind_texture(debug, texture.target(), *texture, std::forward<F>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
//
|
||||
// with_gl_bind_framebuffer
|
||||
//
|
||||
|
||||
template < typename F, typename... Args >
|
||||
void with_gl_bind_framebuffer(debug& debug, GLenum target, GLuint framebuffer, F&& f, Args&&... args) {
|
||||
GLint prev_framebuffer = 0;
|
||||
GL_CHECK_CODE(debug, glGetIntegerv(
|
||||
gl_target_to_get_target(target), &prev_framebuffer));
|
||||
GL_CHECK_CODE(debug, glBindFramebuffer(
|
||||
target, framebuffer));
|
||||
try {
|
||||
stdex::invoke(std::forward<F>(f), std::forward<Args>(args)...);
|
||||
} catch (...) {
|
||||
GL_CHECK_CODE(debug, glBindFramebuffer(
|
||||
target, math::numeric_cast<GLuint>(prev_framebuffer)));
|
||||
throw;
|
||||
}
|
||||
GL_CHECK_CODE(debug, glBindFramebuffer(
|
||||
target, math::numeric_cast<GLuint>(prev_framebuffer)));
|
||||
}
|
||||
|
||||
template < typename F, typename... Args >
|
||||
void with_gl_bind_framebuffer(debug& debug, const gl_framebuffer_id& framebuffer, F&& f, Args&&... args) {
|
||||
with_gl_bind_framebuffer(debug, framebuffer.target(), *framebuffer, std::forward<F>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
||||
248
sources/enduro2d/core/render_impl/render_opengl_impl.cpp
Normal file
248
sources/enduro2d/core/render_impl/render_opengl_impl.cpp
Normal file
@@ -0,0 +1,248 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018 Matvey Cherevko
|
||||
******************************************************************************/
|
||||
|
||||
#include "render_opengl_impl.hpp"
|
||||
|
||||
#if defined(E2D_RENDER_MODE) && E2D_RENDER_MODE == E2D_RENDER_MODE_OPENGL
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace e2d;
|
||||
using namespace e2d::opengl;
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
//
|
||||
// shader::internal_state
|
||||
//
|
||||
|
||||
shader::internal_state::internal_state(
|
||||
debug& debug,
|
||||
gl_program_id id)
|
||||
: debug_(debug)
|
||||
, id_(std::move(id)){
|
||||
E2D_ASSERT(!id_.empty());
|
||||
|
||||
vector<uniform_info> uniforms;
|
||||
grab_program_uniforms(debug_, *id_, uniforms);
|
||||
|
||||
vector<attribute_info> attributes;
|
||||
grab_program_attributes(debug_, *id_, attributes);
|
||||
|
||||
debug.trace("RENDER: Program info:\n"
|
||||
"--> active uniforms: %0\n"
|
||||
"--> active attributes: %1",
|
||||
uniforms.size(),
|
||||
attributes.size());
|
||||
|
||||
for ( const auto& info : uniforms ) {
|
||||
debug.trace(
|
||||
"uniform: size: %0, type: %1, location: %2, name: %3",
|
||||
info.size,
|
||||
uniform_type_to_cstr(info.type),
|
||||
info.location,
|
||||
info.name.hash());
|
||||
uniforms_.emplace(info.name, info);
|
||||
}
|
||||
|
||||
for ( const auto& info : attributes ) {
|
||||
debug.trace(
|
||||
"attribute: size: %0, type: %1, location: %2, name: %3",
|
||||
info.size,
|
||||
attribute_type_to_cstr(info.type),
|
||||
info.location,
|
||||
info.name.hash());
|
||||
attributes_.emplace(info.name, info);
|
||||
}
|
||||
}
|
||||
|
||||
debug& shader::internal_state::dbg() const noexcept {
|
||||
return debug_;
|
||||
}
|
||||
|
||||
const gl_program_id& shader::internal_state::id() const noexcept {
|
||||
return id_;
|
||||
}
|
||||
|
||||
//
|
||||
// texture::internal_state
|
||||
//
|
||||
|
||||
texture::internal_state::internal_state(debug& debug, gl_texture_id id)
|
||||
: debug_(debug)
|
||||
, id_(std::move(id)) {
|
||||
E2D_ASSERT(!id_.empty());
|
||||
}
|
||||
|
||||
debug& texture::internal_state::dbg() const noexcept {
|
||||
return debug_;
|
||||
}
|
||||
|
||||
const gl_texture_id& texture::internal_state::id() const noexcept {
|
||||
return id_;
|
||||
}
|
||||
|
||||
//
|
||||
// index_buffer::internal_state
|
||||
//
|
||||
|
||||
index_buffer::internal_state::internal_state(
|
||||
debug& debug,
|
||||
gl_buffer_id id,
|
||||
std::size_t size,
|
||||
const index_declaration& decl)
|
||||
: debug_(debug)
|
||||
, id_(std::move(id))
|
||||
, size_(size)
|
||||
, decl_(decl) {
|
||||
E2D_ASSERT(!id_.empty());
|
||||
}
|
||||
|
||||
debug& index_buffer::internal_state::dbg() const noexcept {
|
||||
return debug_;
|
||||
}
|
||||
|
||||
const gl_buffer_id& index_buffer::internal_state::id() const noexcept {
|
||||
return id_;
|
||||
}
|
||||
|
||||
std::size_t index_buffer::internal_state::size() const noexcept {
|
||||
return size_;
|
||||
}
|
||||
|
||||
const index_declaration& index_buffer::internal_state::decl() const noexcept {
|
||||
return decl_;
|
||||
}
|
||||
|
||||
//
|
||||
// vertex_buffer::internal_state
|
||||
//
|
||||
|
||||
vertex_buffer::internal_state::internal_state(
|
||||
debug& debug,
|
||||
gl_buffer_id id,
|
||||
std::size_t size,
|
||||
const vertex_declaration& decl)
|
||||
: debug_(debug)
|
||||
, id_(std::move(id))
|
||||
, size_(size)
|
||||
, decl_(decl) {
|
||||
E2D_ASSERT(!id_.empty());
|
||||
}
|
||||
|
||||
debug& vertex_buffer::internal_state::dbg() const noexcept {
|
||||
return debug_;
|
||||
}
|
||||
|
||||
const gl_buffer_id& vertex_buffer::internal_state::id() const noexcept {
|
||||
return id_;
|
||||
}
|
||||
|
||||
std::size_t vertex_buffer::internal_state::size() const noexcept {
|
||||
return size_;
|
||||
}
|
||||
|
||||
const vertex_declaration& vertex_buffer::internal_state::decl() const noexcept {
|
||||
return decl_;
|
||||
}
|
||||
|
||||
//
|
||||
// render::internal_state
|
||||
//
|
||||
|
||||
render::internal_state::internal_state(debug& debug, window& window)
|
||||
: debug_(debug)
|
||||
, window_(window) {}
|
||||
|
||||
debug& render::internal_state::dbg() const noexcept {
|
||||
return debug_;
|
||||
}
|
||||
|
||||
window& render::internal_state::wnd() const noexcept {
|
||||
return window_;
|
||||
}
|
||||
|
||||
render::internal_state& render::internal_state::set_states(const state_block& rs) noexcept {
|
||||
set_depth_state(rs.depth());
|
||||
set_stencil_state(rs.stencil());
|
||||
set_culling_state(rs.culling());
|
||||
set_blending_state(rs.blending());
|
||||
set_capabilities_state(rs.capabilities());
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::internal_state& render::internal_state::set_depth_state(const depth_state& ds) noexcept {
|
||||
GL_CHECK_CODE(debug_, glDepthRange(
|
||||
math::numeric_cast<GLclampd>(math::saturate(ds.near_)),
|
||||
math::numeric_cast<GLclampd>(math::saturate(ds.far_))));
|
||||
GL_CHECK_CODE(debug_, glDepthMask(
|
||||
ds.write_ ? GL_TRUE : GL_FALSE));
|
||||
GL_CHECK_CODE(debug_, glDepthFunc(
|
||||
convert_compare_func(ds.func_)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::internal_state& render::internal_state::set_stencil_state(const stencil_state& ss) noexcept {
|
||||
GL_CHECK_CODE(debug_, glStencilMask(
|
||||
math::numeric_cast<GLuint>(ss.write_)));
|
||||
GL_CHECK_CODE(debug_, glStencilFunc(
|
||||
convert_compare_func(ss.func_),
|
||||
math::numeric_cast<GLint>(ss.ref_),
|
||||
math::numeric_cast<GLuint>(ss.read_)));
|
||||
GL_CHECK_CODE(debug_, glStencilOp(
|
||||
convert_stencil_op(ss.sfail_),
|
||||
convert_stencil_op(ss.zfail_),
|
||||
convert_stencil_op(ss.pass_)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::internal_state& render::internal_state::set_culling_state(const culling_state& cs) noexcept {
|
||||
GL_CHECK_CODE(debug_, glFrontFace(
|
||||
convert_culling_mode(cs.mode_)));
|
||||
GL_CHECK_CODE(debug_, glCullFace(
|
||||
convert_culling_face(cs.face_)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::internal_state& render::internal_state::set_blending_state(const blending_state& bs) noexcept {
|
||||
GL_CHECK_CODE(debug_, glBlendColor(
|
||||
math::numeric_cast<GLclampf>(math::saturate(bs.constant_color_.r)),
|
||||
math::numeric_cast<GLclampf>(math::saturate(bs.constant_color_.g)),
|
||||
math::numeric_cast<GLclampf>(math::saturate(bs.constant_color_.b)),
|
||||
math::numeric_cast<GLclampf>(math::saturate(bs.constant_color_.a))));
|
||||
GL_CHECK_CODE(debug_, glBlendFuncSeparate(
|
||||
convert_blending_factor(bs.src_rgb_factor_),
|
||||
convert_blending_factor(bs.dst_rgb_factor_),
|
||||
convert_blending_factor(bs.src_alpha_factor_),
|
||||
convert_blending_factor(bs.dst_alpha_factor_)));
|
||||
GL_CHECK_CODE(debug_, glBlendEquationSeparate(
|
||||
convert_blending_equation(bs.rgb_equation_),
|
||||
convert_blending_equation(bs.alpha_equation_)));
|
||||
GL_CHECK_CODE(debug_, glColorMask(
|
||||
(math::enum_to_number(bs.color_mask_) & math::enum_to_number(blending_color_mask::r)) != 0,
|
||||
(math::enum_to_number(bs.color_mask_) & math::enum_to_number(blending_color_mask::g)) != 0,
|
||||
(math::enum_to_number(bs.color_mask_) & math::enum_to_number(blending_color_mask::b)) != 0,
|
||||
(math::enum_to_number(bs.color_mask_) & math::enum_to_number(blending_color_mask::a)) != 0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::internal_state& render::internal_state::set_capabilities_state(const capabilities_state& cs) noexcept {
|
||||
const auto enable_or_disable = [](GLenum cap, bool enable) noexcept {
|
||||
if ( enable ) {
|
||||
glEnable(cap);
|
||||
} else {
|
||||
glDisable(cap);
|
||||
}
|
||||
};
|
||||
GL_CHECK_CODE(debug_, enable_or_disable(GL_CULL_FACE, cs.culling_));
|
||||
GL_CHECK_CODE(debug_, enable_or_disable(GL_BLEND, cs.blending_));
|
||||
GL_CHECK_CODE(debug_, enable_or_disable(GL_DEPTH_TEST, cs.depth_test_));
|
||||
GL_CHECK_CODE(debug_, enable_or_disable(GL_STENCIL_TEST, cs.stencil_test_));
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
149
sources/enduro2d/core/render_impl/render_opengl_impl.hpp
Normal file
149
sources/enduro2d/core/render_impl/render_opengl_impl.hpp
Normal file
@@ -0,0 +1,149 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018 Matvey Cherevko
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "render.hpp"
|
||||
#include "render_opengl_base.hpp"
|
||||
|
||||
#if defined(E2D_RENDER_MODE) && E2D_RENDER_MODE == E2D_RENDER_MODE_OPENGL
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
//
|
||||
// shader::internal_state
|
||||
//
|
||||
|
||||
class shader::internal_state final : private e2d::noncopyable {
|
||||
public:
|
||||
internal_state(
|
||||
debug& debug,
|
||||
opengl::gl_program_id id);
|
||||
~internal_state() noexcept = default;
|
||||
public:
|
||||
debug& dbg() const noexcept;
|
||||
const opengl::gl_program_id& id() const noexcept;
|
||||
public:
|
||||
template < typename F >
|
||||
void with_uniform_location(str_hash name, F&& f) const;
|
||||
template < typename F >
|
||||
void with_attribute_location(str_hash name, F&& f) const;
|
||||
private:
|
||||
debug& debug_;
|
||||
opengl::gl_program_id id_;
|
||||
hash_map<str_hash, opengl::uniform_info> uniforms_;
|
||||
hash_map<str_hash, opengl::attribute_info> attributes_;
|
||||
};
|
||||
|
||||
template < typename F >
|
||||
void shader::internal_state::with_uniform_location(str_hash name, F&& f) const {
|
||||
const auto iter = uniforms_.find(name);
|
||||
if ( iter != uniforms_.end() ) {
|
||||
stdex::invoke(std::forward<F>(f), iter->second);
|
||||
}
|
||||
}
|
||||
|
||||
template < typename F >
|
||||
void shader::internal_state::with_attribute_location(str_hash name, F&& f) const {
|
||||
const auto iter = attributes_.find(name);
|
||||
if ( iter != attributes_.end() ) {
|
||||
stdex::invoke(std::forward<F>(f), iter->second);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// texture::internal_state
|
||||
//
|
||||
|
||||
class texture::internal_state final : private e2d::noncopyable {
|
||||
public:
|
||||
internal_state(
|
||||
debug& debug,
|
||||
opengl::gl_texture_id id);
|
||||
~internal_state() noexcept = default;
|
||||
public:
|
||||
debug& dbg() const noexcept;
|
||||
const opengl::gl_texture_id& id() const noexcept;
|
||||
private:
|
||||
debug& debug_;
|
||||
opengl::gl_texture_id id_;
|
||||
};
|
||||
|
||||
//
|
||||
// index_buffer::internal_state
|
||||
//
|
||||
|
||||
class index_buffer::internal_state final : private e2d::noncopyable {
|
||||
public:
|
||||
internal_state(
|
||||
debug& debug,
|
||||
opengl::gl_buffer_id id,
|
||||
std::size_t size,
|
||||
const index_declaration& decl);
|
||||
~internal_state() noexcept = default;
|
||||
public:
|
||||
debug& dbg() const noexcept;
|
||||
const opengl::gl_buffer_id& id() const noexcept;
|
||||
std::size_t size() const noexcept;
|
||||
const index_declaration& decl() const noexcept;
|
||||
private:
|
||||
debug& debug_;
|
||||
opengl::gl_buffer_id id_;
|
||||
std::size_t size_ = 0;
|
||||
index_declaration decl_;
|
||||
};
|
||||
|
||||
//
|
||||
// vertex_buffer::internal_state
|
||||
//
|
||||
|
||||
class vertex_buffer::internal_state final : private e2d::noncopyable {
|
||||
public:
|
||||
internal_state(
|
||||
debug& debug,
|
||||
opengl::gl_buffer_id id,
|
||||
std::size_t size,
|
||||
const vertex_declaration& decl);
|
||||
~internal_state() noexcept = default;
|
||||
public:
|
||||
debug& dbg() const noexcept;
|
||||
const opengl::gl_buffer_id& id() const noexcept;
|
||||
std::size_t size() const noexcept;
|
||||
const vertex_declaration& decl() const noexcept;
|
||||
private:
|
||||
debug& debug_;
|
||||
opengl::gl_buffer_id id_;
|
||||
std::size_t size_ = 0;
|
||||
vertex_declaration decl_;
|
||||
};
|
||||
|
||||
//
|
||||
// render::internal_state
|
||||
//
|
||||
|
||||
class render::internal_state final : private e2d::noncopyable {
|
||||
public:
|
||||
internal_state(
|
||||
debug& debug,
|
||||
window& window);
|
||||
~internal_state() noexcept = default;
|
||||
public:
|
||||
debug& dbg() const noexcept;
|
||||
window& wnd() const noexcept;
|
||||
public:
|
||||
internal_state& set_states(const state_block& rs) noexcept;
|
||||
internal_state& set_depth_state(const depth_state& ds) noexcept;
|
||||
internal_state& set_stencil_state(const stencil_state& ss) noexcept;
|
||||
internal_state& set_culling_state(const culling_state& cs) noexcept;
|
||||
internal_state& set_blending_state(const blending_state& bs) noexcept;
|
||||
internal_state& set_capabilities_state(const capabilities_state& cs) noexcept;
|
||||
private:
|
||||
debug& debug_;
|
||||
window& window_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -8,6 +8,68 @@
|
||||
using namespace e2d;
|
||||
|
||||
TEST_CASE("render"){
|
||||
SECTION("property_block"){
|
||||
{
|
||||
const auto pb1 = render::property_block()
|
||||
.property("f", 1.f)
|
||||
.property("i", 42);
|
||||
REQUIRE(*pb1.property<f32>("f") == 1.f);
|
||||
REQUIRE(*pb1.property<i32>("i") == 42);
|
||||
REQUIRE_FALSE(pb1.property<f32>("i"));
|
||||
REQUIRE_FALSE(pb1.property<i32>("f"));
|
||||
REQUIRE(pb1.property("i"));
|
||||
REQUIRE(pb1.property("f"));
|
||||
REQUIRE(stdex::get<i32>(*pb1.property("i")) == 42);
|
||||
REQUIRE(stdex::get<f32>(*pb1.property("f")) == 1.f);
|
||||
{
|
||||
f32 acc = 0.f;
|
||||
pb1.foreach_by_properties([&acc](str_hash n, const render::property_value& v){
|
||||
if ( n == make_hash("f") ) {
|
||||
acc += stdex::get<f32>(v);
|
||||
}
|
||||
if ( n == make_hash("i") ) {
|
||||
acc += stdex::get<i32>(v);
|
||||
}
|
||||
});
|
||||
REQUIRE(math::approximately(acc, 43.f));
|
||||
}
|
||||
}
|
||||
{
|
||||
const auto pb1 = render::property_block()
|
||||
.property("f", 1.f)
|
||||
.property("i", 42);
|
||||
const auto pb2 = render::property_block()
|
||||
.property("ff", 2.f)
|
||||
.property("ii", 84);
|
||||
auto pb3 = render::property_block()
|
||||
.merge(pb1)
|
||||
.merge(pb2);
|
||||
REQUIRE(pb3.property_count() == 4);
|
||||
REQUIRE(pb3.property("i"));
|
||||
REQUIRE(pb3.property("f"));
|
||||
REQUIRE(pb3.property("ii"));
|
||||
REQUIRE(pb3.property("ff"));
|
||||
pb3.clear();
|
||||
REQUIRE(pb3.property_count() == 0);
|
||||
REQUIRE_FALSE(pb3.property("i"));
|
||||
REQUIRE_FALSE(pb3.property("f"));
|
||||
REQUIRE_FALSE(pb3.property("ii"));
|
||||
REQUIRE_FALSE(pb3.property("ff"));
|
||||
}
|
||||
{
|
||||
const auto pb1 = render::property_block()
|
||||
.property("i", 42)
|
||||
.property("f", 1.f);
|
||||
const auto pb2 = render::property_block()
|
||||
.property("i", 40)
|
||||
.property("ii", 20)
|
||||
.merge(pb1);
|
||||
REQUIRE(pb2.property_count() == 3);
|
||||
REQUIRE(*pb2.property<i32>("i") == 42);
|
||||
REQUIRE(*pb2.property<i32>("ii") == 20);
|
||||
REQUIRE(*pb2.property<f32>("f") == 1.f);
|
||||
}
|
||||
}
|
||||
SECTION("index_declaration"){
|
||||
index_declaration id;
|
||||
REQUIRE(id.index().type == index_declaration::index_type::unsigned_short);
|
||||
@@ -43,7 +105,7 @@ TEST_CASE("render"){
|
||||
REQUIRE(vd.vertex_size() == 8);
|
||||
|
||||
vertex_declaration::attribute_info ai = vd.attribute(0);
|
||||
REQUIRE(ai.name == "hello");
|
||||
REQUIRE(ai.name == make_hash("hello"));
|
||||
REQUIRE(ai.columns == 2);
|
||||
REQUIRE(ai.stride == 0);
|
||||
REQUIRE(ai.type == vertex_declaration::attribute_type::floating_point);
|
||||
@@ -57,7 +119,7 @@ TEST_CASE("render"){
|
||||
REQUIRE(vd.vertex_size() == 14);
|
||||
|
||||
vertex_declaration::attribute_info ai2 = vd.attribute(1);
|
||||
REQUIRE(ai2.name == "world");
|
||||
REQUIRE(ai2.name == make_hash("world"));
|
||||
REQUIRE(ai2.columns == 1);
|
||||
REQUIRE(ai2.stride == 12);
|
||||
REQUIRE(ai2.type == vertex_declaration::attribute_type::unsigned_short);
|
||||
|
||||
Reference in New Issue
Block a user