render: materials, properties, states, geometry

This commit is contained in:
2018-10-15 12:53:34 +07:00
parent 3b167a1c60
commit 7f65cf5196
10 changed files with 3108 additions and 1477 deletions

View File

@@ -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_;

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View File

@@ -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);