render set_blend_equation. render create_shader.

This commit is contained in:
2018-09-30 00:53:23 +07:00
parent d5b3542f6e
commit 169a9a2398
5 changed files with 302 additions and 23 deletions

View File

@@ -10,11 +10,32 @@
namespace e2d
{
//
// shader
//
class shader final : noncopyable {
private:
friend class render;
class internal_state;
using internal_state_uptr = std::unique_ptr<internal_state>;
public:
shader(internal_state_uptr);
~shader() noexcept;
private:
internal_state_uptr state_;
};
using shader_ptr = std::shared_ptr<shader>;
//
// texture
//
class texture final : noncopyable {
private:
friend class render;
class internal_state;
using internal_state_uptr = std::unique_ptr<internal_state>;
public:
enum class wrap {
clamp,
@@ -26,7 +47,7 @@ namespace e2d
nearest
};
public:
texture();
texture(internal_state_uptr);
~texture() noexcept;
void set_wrap(wrap u, wrap v) noexcept;
@@ -35,8 +56,7 @@ namespace e2d
const v2u& native_size() const noexcept;
const v2u& original_size() const noexcept;
private:
class internal_state;
std::unique_ptr<internal_state> state_;
internal_state_uptr state_;
};
using texture_ptr = std::shared_ptr<texture>;
@@ -74,6 +94,11 @@ namespace e2d
one_minus_constant_alpha,
src_alpha_saturate
};
enum class blend_equation {
add,
subtract,
reverse_subtract
};
enum class depth_func {
never,
less,
@@ -105,11 +130,15 @@ namespace e2d
invert
};
public:
render();
render(debug& debug);
~render() noexcept;
texture_ptr create_texture(const image& image) noexcept;
texture_ptr create_texture(const v2u& size, image_data_format format) noexcept;
shader_ptr create_shader(
input_stream_uptr vertex,
input_stream_uptr fragment);
texture_ptr create_texture(const image& image);
texture_ptr create_texture(const v2u& size, image_data_format format);
void clear(bool color, bool depth, bool stencil) noexcept;
@@ -122,6 +151,7 @@ namespace e2d
void set_blend_func(blend_func src, blend_func dst) noexcept;
void set_blend_color(const color& color) noexcept;
void set_blend_equation(blend_equation blend_equation) noexcept;
void set_cull_face(cull_face cull_face) noexcept;
@@ -137,6 +167,7 @@ namespace e2d
void set_clear_color(const color& color) noexcept;
void set_color_mask(bool r, bool g, bool b, bool a);
private:
debug& debug_;
class internal_state;
std::unique_ptr<internal_state> state_;
};

View File

@@ -10,7 +10,7 @@ using namespace e2d;
int e2d_main() {
modules::initialize<debug>();
modules::initialize<input>();
modules::initialize<render>();
modules::initialize<render>(the<debug>());
modules::initialize<window>(v2u{640, 480}, "Enduro2D", false);
the<debug>().add_sink<debug_console_sink>();

View File

@@ -6,6 +6,7 @@
#pragma once
#include <enduro2d/core/debug.hpp>
#include <enduro2d/core/render.hpp>
#define E2D_RENDER_MODE_NONE 1

View File

@@ -10,6 +10,16 @@
namespace e2d
{
//
// shader::internal_state
//
class shader::internal_state final : private e2d::noncopyable {
public:
internal_state() {}
~internal_state() noexcept = default;
};
//
// texture::internal_state
//
@@ -30,12 +40,20 @@ namespace e2d
~internal_state() noexcept = default;
};
//
// shader
//
shader::shader(internal_state_uptr state)
: state_(std::move(state)) {}
shader::~shader() noexcept = default;
//
// texture
//
texture::texture()
: state_(new internal_state()) {}
texture::texture(internal_state_uptr state)
: state_(std::move(state)) {}
texture::~texture() noexcept = default;
void texture::set_wrap(wrap u, wrap v) noexcept {
@@ -50,10 +68,26 @@ namespace e2d
// render
//
render::render()
: state_(new internal_state()) {}
render::render(debug& debug)
: debug_(debug)
, state_(new internal_state()) {}
render::~render() noexcept = default;
shader_ptr render::create_shader(input_stream_uptr vertex, input_stream_uptr fragment) {
E2D_UNUSED(vertex, fragment);
return nullptr;
}
texture_ptr render::create_texture(const image& image) {
E2D_UNUSED(image);
return nullptr;
}
texture_ptr render::create_texture(const v2u& size, image_data_format format) {
E2D_UNUSED(size, format);
return nullptr;
}
void render::clear(bool color, bool depth, bool stencil) noexcept {
E2D_UNUSED(color, depth, stencil);
}
@@ -86,6 +120,10 @@ namespace e2d
E2D_UNUSED(color);
}
void render::set_blend_equation(blend_equation blend_equation) noexcept {
E2D_UNUSED(blend_equation);
}
void render::set_cull_face(cull_face cull_face) noexcept {
E2D_UNUSED(cull_face);
}

View File

@@ -93,6 +93,19 @@ namespace
#undef DEFINE_CASE
}
GLenum convert_blend_equation(render::blend_equation bf) noexcept {
#define DEFINE_CASE(x,y) case render::blend_equation::x: return y;
switch ( bf ) {
DEFINE_CASE(add, GL_FUNC_ADD);
DEFINE_CASE(subtract, GL_FUNC_SUBTRACT);
DEFINE_CASE(reverse_subtract, GL_FUNC_REVERSE_SUBTRACT);
default:
E2D_ASSERT_MSG(false, "unexpected render blend equation");
return 0;
}
#undef DEFINE_CASE
}
GLenum convert_depth_func(render::depth_func df) noexcept {
#define DEFINE_CASE(x,y) case render::depth_func::x: return y;
switch ( df ) {
@@ -146,21 +159,180 @@ namespace
}
#undef DEFINE_CASE
}
class gl_shader_id final : private noncopyable {
public:
gl_shader_id() noexcept
: id_(0) {}
gl_shader_id(GLuint id) noexcept
: id_(id) {
E2D_ASSERT(glIsShader(id));
}
~gl_shader_id() noexcept {
reset();
}
gl_shader_id(gl_shader_id&& other) noexcept {
reset();
std::swap(id_, other.id_);
}
void reset() noexcept {
if ( id_ ) {
glDeleteShader(id_);
id_ = 0;
}
}
bool empty() const noexcept {
return id_ == 0;
}
GLuint operator*() const noexcept {
return id_;
}
private:
GLuint id_;
};
class gl_program_id final : private noncopyable {
public:
gl_program_id() noexcept
: id_(0) {}
gl_program_id(GLuint id) noexcept
: id_(id) {
E2D_ASSERT(glIsProgram(id));
}
~gl_program_id() noexcept {
reset();
}
gl_program_id(gl_program_id&& other) noexcept {
reset();
std::swap(id_, other.id_);
}
void reset() noexcept {
if ( id_ ) {
glDeleteProgram(id_);
id_ = 0;
}
}
bool empty() const noexcept {
return id_ == 0;
}
GLuint operator*() const noexcept {
return id_;
}
private:
GLuint id_;
};
class gl_texture_id final : private noncopyable {
public:
gl_texture_id() noexcept
: id_(0) {}
gl_texture_id(GLuint id) noexcept
: id_(id) {
E2D_ASSERT(glIsTexture(id));
}
~gl_texture_id() noexcept {
reset();
}
gl_texture_id(gl_texture_id&& other) noexcept {
reset();
std::swap(id_, other.id_);
}
void reset() noexcept {
if ( id_ ) {
glDeleteTextures(1, &id_);
id_ = 0;
}
}
bool empty() const noexcept {
return id_ == 0;
}
GLuint operator*() const noexcept {
return id_;
}
private:
GLuint id_;
};
gl_shader_id compile_shader(debug& d, const char* const s, GLenum t) {
E2D_ASSERT(s);
E2D_ASSERT(t == GL_VERTEX_SHADER || t == GL_FRAGMENT_SHADER);
gl_shader_id id{glCreateShader(t)};
glShaderSource(*id, 1, &s, nullptr);
glCompileShader(*id);
GLint success = GL_FALSE;
glGetShaderiv(*id, GL_COMPILE_STATUS, &success);
if ( success ) {
return id;
}
char error_buffer[512] = {0};
glGetShaderInfoLog(*id, E2D_COUNTOF(error_buffer), nullptr, error_buffer);
d.error("RENDER: vertex shader compilation failed:\n-> %0", error_buffer);
return gl_shader_id{};
}
gl_program_id link_program(debug& d, gl_shader_id vs, gl_shader_id fs) {
E2D_ASSERT(!vs.empty() && !fs.empty());
gl_program_id id{glCreateProgram()};
glAttachShader(*id, *vs);
glAttachShader(*id, *fs);
glLinkProgram(*id);
GLint success = GL_FALSE;
glGetProgramiv(*id, GL_LINK_STATUS, &success);
if ( success ) {
return id;
}
char error_buffer[512] = {0};
glGetProgramInfoLog(*id, E2D_COUNTOF(error_buffer), nullptr, error_buffer);
d.error("RENDER: shader program linking failed:\n-> %0", error_buffer);
return gl_program_id{};
}
}
namespace e2d
{
//
// shader::internal_state
//
class shader::internal_state final : private e2d::noncopyable {
public:
gl_program_id id;
public:
internal_state(gl_program_id id)
: id(std::move(id)) {}
~internal_state() noexcept = default;
};
//
// texture::internal_state
//
class texture::internal_state final : private e2d::noncopyable {
public:
GLuint id = 0;
gl_texture_id id;
v2u native_size;
v2u original_size;
public:
internal_state() {}
internal_state(gl_texture_id id)
: id(std::move(id)) {}
~internal_state() noexcept = default;
};
@@ -178,25 +350,33 @@ namespace e2d
~internal_state() noexcept = default;
};
//
// shader
//
shader::shader(internal_state_uptr state)
: state_(std::move(state)) {}
shader::~shader() noexcept = default;
//
// texture
//
texture::texture()
: state_(new internal_state()) {}
texture::texture(internal_state_uptr state)
: state_(std::move(state)) {}
texture::~texture() noexcept = default;
void texture::set_wrap(wrap u, wrap v) noexcept {
E2D_ASSERT(state_->id);
glBindTexture(GL_TEXTURE_2D, state_->id);
E2D_ASSERT(!state_->id.empty());
glBindTexture(GL_TEXTURE_2D, *state_->id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, convert_wrap(u));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, convert_wrap(v));
glBindTexture(GL_TEXTURE_2D, 0);
}
void texture::set_filter(filter min, filter mag) noexcept {
E2D_ASSERT(state_->id);
glBindTexture(GL_TEXTURE_2D, state_->id);
E2D_ASSERT(!state_->id.empty());
glBindTexture(GL_TEXTURE_2D, *state_->id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, convert_filter(min));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, convert_filter(mag));
glBindTexture(GL_TEXTURE_2D, 0);
@@ -214,16 +394,40 @@ namespace e2d
// render
//
render::render()
: state_(new internal_state()) {}
render::render(debug& debug)
: debug_(debug)
, state_(new internal_state()) {}
render::~render() noexcept = default;
texture_ptr render::create_texture(const image& image) noexcept {
shader_ptr render::create_shader(input_stream_uptr vertex, input_stream_uptr fragment) {
str vertex_str;
gl_shader_id vs = streams::try_read_tail(vertex_str, vertex)
? compile_shader(debug_, vertex_str.c_str(), GL_VERTEX_SHADER)
: gl_shader_id();
if ( vs.empty() ) {
return nullptr;
}
str fragment_str;
gl_shader_id fs = streams::try_read_tail(fragment_str, fragment)
? compile_shader(debug_, fragment_str.c_str(), GL_FRAGMENT_SHADER)
: gl_shader_id();
if ( fs.empty() ) {
return nullptr;
}
gl_program_id ps = link_program(debug_, std::move(vs), std::move(fs));
if ( ps.empty() ) {
return nullptr;
}
return std::make_unique<shader>(
std::make_unique<shader::internal_state>(std::move(ps)));
}
texture_ptr render::create_texture(const image& image) {
E2D_UNUSED(image);
return nullptr;
}
texture_ptr render::create_texture(const v2u& size, image_data_format format) noexcept {
texture_ptr render::create_texture(const v2u& size, image_data_format format) {
E2D_UNUSED(size, format);
return nullptr;
}
@@ -286,6 +490,11 @@ namespace e2d
math::numeric_cast<GLclampf>(color.a));
}
void render::set_blend_equation(blend_equation blend_equation) noexcept {
std::lock_guard<std::mutex> guard(state_->mutex);
glBlendEquation(convert_blend_equation(blend_equation));
}
void render::set_cull_face(cull_face cull_face) noexcept {
std::lock_guard<std::mutex> guard(state_->mutex);
glCullFace(convert_cull_face(cull_face));