render target first impl

This commit is contained in:
2018-10-19 14:40:54 +07:00
parent da29a9e456
commit b732d423ce
13 changed files with 1194 additions and 255 deletions

View File

@@ -17,6 +17,8 @@ namespace e2d
class texture;
class index_buffer;
class vertex_buffer;
class render_target;
class pixel_declaration;
class index_declaration;
class vertex_declaration;
@@ -24,6 +26,50 @@ namespace e2d
using texture_ptr = std::shared_ptr<texture>;
using index_buffer_ptr = std::shared_ptr<index_buffer>;
using vertex_buffer_ptr = std::shared_ptr<vertex_buffer>;
using render_target_ptr = std::shared_ptr<render_target>;
//
// pixel_declaration
//
class pixel_declaration final {
public:
enum class pixel_type : u8 {
rgba8,
depth24_stencil8,
dxt1,
dxt3,
dxt5,
rgb_pvrtc2,
rgb_pvrtc4,
rgba_pvrtc2,
rgba_pvrtc4
};
public:
pixel_declaration() = default;
~pixel_declaration() noexcept = default;
pixel_declaration(const pixel_declaration&) noexcept = default;
pixel_declaration& operator=(const pixel_declaration&) noexcept = default;
pixel_declaration(pixel_type type) noexcept;
pixel_type type() const noexcept;
bool is_compressed() const noexcept;
std::size_t bits_per_pixel() const noexcept;
private:
pixel_type type_ = pixel_type::rgba8;
};
bool operator==(
const pixel_declaration& l,
const pixel_declaration& r) noexcept;
bool operator!=(
const pixel_declaration& l,
const pixel_declaration& r) noexcept;
//
// index_declaration
@@ -35,19 +81,6 @@ namespace e2d
unsigned_byte,
unsigned_short
};
class index_info final {
public:
index_type type = index_type::unsigned_short;
public:
index_info() = default;
~index_info() noexcept = default;
index_info(const index_info&) noexcept = default;
index_info& operator=(const index_info&) noexcept = default;
explicit index_info(index_type type) noexcept;
};
public:
index_declaration() = default;
~index_declaration() noexcept = default;
@@ -55,12 +88,12 @@ namespace e2d
index_declaration(const index_declaration&) noexcept = default;
index_declaration& operator=(const index_declaration&) noexcept = default;
explicit index_declaration(index_type index_type) noexcept;
index_declaration(index_type type) noexcept;
const index_info& index() const noexcept;
std::size_t index_size() const noexcept;
index_type type() const noexcept;
std::size_t bytes_per_index() const noexcept;
private:
index_info index_;
index_type type_ = index_type::unsigned_short;
};
bool operator==(
@@ -69,12 +102,6 @@ namespace e2d
bool operator!=(
const index_declaration& l,
const index_declaration& r) noexcept;
bool operator==(
const index_declaration::index_info& l,
const index_declaration::index_info& r) noexcept;
bool operator!=(
const index_declaration::index_info& l,
const index_declaration::index_info& r) noexcept;
//
// vertex_declaration
@@ -138,12 +165,12 @@ namespace e2d
const attribute_info& attribute(std::size_t i) const noexcept;
std::size_t attribute_count() const noexcept;
std::size_t vertex_size() const noexcept;
std::size_t bytes_per_vertex() const noexcept;
private:
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;
std::size_t bytes_per_vertex_ = 0;
};
bool operator==(
@@ -187,8 +214,9 @@ namespace e2d
public:
explicit texture(internal_state_uptr);
~texture() noexcept;
public:
const v2u& size() const noexcept;
image_data_format format() const noexcept;
const pixel_declaration& decl() const noexcept;
private:
internal_state_uptr state_;
};
@@ -211,10 +239,11 @@ namespace e2d
public:
explicit index_buffer(internal_state_uptr);
~index_buffer() noexcept;
public:
void update(const buffer& indices, std::size_t offset) noexcept;
const index_declaration& decl() const noexcept;
std::size_t buffer_size() const noexcept;
std::size_t index_count() const noexcept;
const index_declaration& decl() const noexcept;
private:
internal_state_uptr state_;
};
@@ -229,7 +258,7 @@ namespace e2d
using internal_state_uptr = std::unique_ptr<internal_state>;
const internal_state& state() const noexcept;
public:
enum class usage : u8{
enum class usage : u8 {
static_draw,
stream_draw,
dynamic_draw
@@ -237,10 +266,37 @@ namespace e2d
public:
explicit vertex_buffer(internal_state_uptr);
~vertex_buffer() noexcept;
public:
void update(const buffer& vertices, std::size_t offset) noexcept;
const vertex_declaration& decl() const noexcept;
std::size_t buffer_size() const noexcept;
std::size_t vertex_count() const noexcept;
const vertex_declaration& decl() const noexcept;
private:
internal_state_uptr state_;
};
//
// render target
//
class render_target final : noncopyable {
public:
class internal_state;
using internal_state_uptr = std::unique_ptr<internal_state>;
const internal_state& state() const noexcept;
public:
enum class type : u8 {
color = (1 << 0),
depth = (1 << 1),
color_and_depth = color | depth
};
public:
explicit render_target(internal_state_uptr);
~render_target() noexcept;
public:
const v2u& size() const noexcept;
const texture_ptr& color() const noexcept;
const texture_ptr& depth() const noexcept;
private:
internal_state_uptr state_;
};
@@ -285,9 +341,9 @@ namespace e2d
};
enum class culling_face : u8 {
back,
front,
back_and_front
back = (1 << 0),
front = (1 << 1),
back_and_front = back | front
};
enum class blending_factor : u8 {
@@ -647,6 +703,10 @@ namespace e2d
texture_ptr create_texture(
const input_stream_uptr& image_stream);
texture_ptr create_texture(
const v2u& size,
const pixel_declaration& decl);
index_buffer_ptr create_index_buffer(
const buffer& indices,
const index_declaration& decl,
@@ -657,6 +717,10 @@ namespace e2d
const vertex_declaration& decl,
vertex_buffer::usage usage);
render_target_ptr create_render_target(
const v2u& size,
render_target::type type);
void draw(
const material& mat,
const geometry& geo);
@@ -670,6 +734,7 @@ namespace e2d
render& clear_stencil_buffer(u8 value) noexcept;
render& clear_color_buffer(const color& value) noexcept;
render& set_viewport(u32 x, u32 y, u32 w, u32 h) noexcept;
render& set_render_target(const render_target_ptr& rt) noexcept;
private:
class internal_state;
std::unique_ptr<internal_state> state_;

View File

@@ -45,3 +45,4 @@ endfunction(add_e2d_sample)
add_e2d_sample(00)
add_e2d_sample(01)
add_e2d_sample(02)

View File

@@ -9,44 +9,46 @@ using namespace e2d;
namespace
{
const char* vs_source_cstr =
"#version 120 \n"
" \n"
"attribute vec3 a_position; \n"
"attribute vec2 a_uv; \n"
"attribute vec4 a_color; \n"
" \n"
"uniform float u_time; \n"
"uniform mat4 u_MVP; \n"
" \n"
"varying vec4 v_color; \n"
"varying vec2 v_uv; \n"
" \n"
"void main(){ \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) * u_MVP; \n"
"} \n";
const char* vs_source_cstr = R"glsl(
#version 120
const char* fs_source_cstr =
"#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";
attribute vec3 a_position;
attribute vec2 a_uv;
attribute vec4 a_color;
uniform float u_time;
uniform mat4 u_MVP;
varying vec4 v_color;
varying vec2 v_uv;
void main(){
v_color = a_color;
v_uv = a_uv;
float s = 0.7 + 0.3 * (cos(u_time * 0.003) + 1);
gl_Position = vec4(a_position * s, 1.0) * u_MVP;
}
)glsl";
const char* fs_source_cstr = R"glsl(
#version 120
uniform float u_time;
uniform sampler2D u_texture1;
uniform sampler2D u_texture2;
varying vec4 v_color;
varying vec2 v_uv;
void main(){
vec2 uv = vec2(v_uv.s, 1.0 - v_uv.t);
if ( u_time > 2000 ) {
gl_FragColor = v_color * texture2D(u_texture2, uv);
} else {
gl_FragColor = v_color * texture2D(u_texture1, uv);
}
}
)glsl";
struct vertex1 {
v3f position;
@@ -124,7 +126,7 @@ int e2d_main() {
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_declaration::index_type::unsigned_byte,
index_buffer::usage::static_draw);
const auto vertices1 = generate_quad_vertices(texture1->size());

View File

@@ -9,36 +9,38 @@ using namespace e2d;
namespace
{
const char* vs_source_cstr =
"#version 120 \n"
" \n"
"attribute vec3 a_position; \n"
"attribute vec2 a_uv; \n"
"attribute vec4 a_color; \n"
" \n"
"uniform mat4 u_MVP; \n"
" \n"
"varying vec4 v_color; \n"
"varying vec2 v_uv; \n"
" \n"
"void main(){ \n"
" v_color = a_color; \n"
" v_uv = a_uv; \n"
" \n"
" gl_Position = vec4(a_position, 1.0) * u_MVP; \n"
"} \n";
const char* vs_source_cstr = R"glsl(
#version 120
const char* fs_source_cstr =
"#version 120 \n"
" \n"
"uniform sampler2D u_texture; \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"
" gl_FragColor = v_color * texture2D(u_texture, uv); \n"
"} \n";
attribute vec3 a_position;
attribute vec2 a_uv;
attribute vec4 a_color;
uniform mat4 u_MVP;
varying vec4 v_color;
varying vec2 v_uv;
void main(){
v_color = a_color;
v_uv = a_uv;
gl_Position = vec4(a_position, 1.0) * u_MVP;
}
)glsl";
const char* fs_source_cstr = R"glsl(
#version 120
uniform sampler2D u_texture;
varying vec4 v_color;
varying vec2 v_uv;
void main(){
vec2 uv = vec2(v_uv.s, 1.0 - v_uv.t);
gl_FragColor = v_color * texture2D(u_texture, uv);
}
)glsl";
struct vertex1 {
v3f position;
@@ -182,7 +184,7 @@ int e2d_main() {
const auto indices = generate_cube_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_declaration::index_type::unsigned_byte,
index_buffer::usage::static_draw);
const auto vertices1 = generate_cube_vertices(make_vec3(1.f));

View File

@@ -0,0 +1,243 @@
/*******************************************************************************
* 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 "../common.hpp"
using namespace e2d;
namespace
{
const char* vs_source_cstr = R"glsl(
#version 120
attribute vec3 a_position;
attribute vec2 a_uv;
uniform mat4 u_MVP;
varying vec2 v_uv;
void main(){
v_uv = a_uv;
gl_Position = vec4(a_position, 1.0) * u_MVP;
}
)glsl";
const char* fs_source_cstr = R"glsl(
#version 120
uniform sampler2D u_texture;
varying vec2 v_uv;
void main(){
vec2 uv = vec2(v_uv.s, 1.0 - v_uv.t);
gl_FragColor = texture2D(u_texture, uv);
}
)glsl";
struct vertex {
v3f position;
v2hu uv;
static vertex_declaration decl() noexcept {
return vertex_declaration()
.add_attribute<v3f>("a_position")
.add_attribute<v2hu>("a_uv");
}
};
array<u8,36> generate_cube_indices() noexcept {
return {
0, 1, 2,
2, 3, 0,
4, 5, 6,
6, 7, 4,
8, 9, 10,
10, 11, 8,
12, 13, 14,
14, 15, 12,
16, 17, 18,
18, 19, 16,
20, 21, 22,
22, 23, 20};
}
array<vertex,24> generate_cube_vertices(const v3f& size) noexcept {
f32 x = size.x * 0.5f;
f32 y = size.y * 0.5f;
f32 z = size.z * 0.5f;
return {
vertex{{-x, -y, -z}, {0, 1}},
vertex{{ x, -y, -z}, {1, 1}},
vertex{{ x, y, -z}, {1, 0}},
vertex{{-x, y, -z}, {0, 0}},
vertex{{-x, -y, z}, {0, 1}},
vertex{{ x, -y, z}, {1, 1}},
vertex{{ x, -y, -z}, {1, 0}},
vertex{{-x, -y, -z}, {0, 0}},
vertex{{ x, -y, z}, {0, 1}},
vertex{{-x, -y, z}, {1, 1}},
vertex{{-x, y, z}, {1, 0}},
vertex{{ x, y, z}, {0, 0}},
vertex{{-x, y, -z}, {0, 1}},
vertex{{ x, y, -z}, {1, 1}},
vertex{{ x, y, z}, {1, 0}},
vertex{{-x, y, z}, {0, 0}},
vertex{{ x, -y, -z}, {0, 1}},
vertex{{ x, -y, z}, {1, 1}},
vertex{{ x, y, z}, {1, 0}},
vertex{{ x, y, -z}, {0, 0}},
vertex{{-x, -y, z}, {0, 1}},
vertex{{-x, -y, -z}, {1, 1}},
vertex{{-x, y, -z}, {1, 0}},
vertex{{-x, y, z}, {0, 0}}};
}
}
int e2d_main() {
{
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 texture = the<render>().create_texture(
the<vfs>().open(url("ships://ship (3).png")));
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))));
const auto indices = generate_cube_indices();
const auto index_buffer = the<render>().create_index_buffer(
buffer(indices.data(), indices.size() * sizeof(indices[0])),
index_declaration::index_type::unsigned_byte,
index_buffer::usage::static_draw);
const auto vertices = generate_cube_vertices(make_vec3(1.f));
const auto vertex_buffer = the<render>().create_vertex_buffer(
buffer(vertices.data(), vertices.size() * sizeof(vertices[0])),
vertex::decl(),
vertex_buffer::usage::static_draw);
if ( !texture || !shader || !index_buffer || !vertex_buffer ) {
return 1;
}
auto material = render::material()
.add_pass(render::pass_state()
.states(render::state_block()
.capabilities(render::capabilities_state()
.blending(true)
.culling(true)
.depth_test(true))
.blending(render::blending_state()
.src_factor(render::blending_factor::src_alpha)
.dst_factor(render::blending_factor::one_minus_src_alpha))
.culling(render::culling_state()
.mode(render::culling_mode::ccw)
.face(render::culling_face::back)))
.shader(shader))
.properties(render::property_block()
.sampler("u_texture", render::sampler_state()
.texture(texture)
.min_filter(render::sampler_min_filter::linear)
.mag_filter(render::sampler_mag_filter::linear)));
auto geometry = render::geometry()
.indices(index_buffer)
.add_vertices(vertex_buffer);
const auto begin_game_time = time::now_ms();
const auto framebuffer_size = the<window>().real_size().cast_to<f32>();
const auto projection = math::make_perspective_lh_matrix4(
make_deg(45.f),
framebuffer_size.x / framebuffer_size.y,
0.1f,
100.f);
const auto rt = the<render>().create_render_target(
the<window>().real_size() / 10u,
render_target::type::color_and_depth);
const keyboard& k = the<input>().keyboard();
while ( !the<window>().should_close() && !k.is_key_just_released(keyboard_key::escape) ) {
const auto game_time = (time::now_ms() - begin_game_time).cast_to<f32>().value;
const auto MVP =
math::make_rotation_matrix4(make_rad(game_time) * 0.001f, 1.f, 0.f, 0.f) *
math::make_rotation_matrix4(make_rad(game_time) * 0.001f, 0.f, 1.f, 0.f) *
math::make_rotation_matrix4(make_rad(game_time) * 0.001f, 0.f, 0.f, 1.f) *
math::make_translation_matrix4(0.f, 0.f, 0.f) *
math::make_loot_at_lh_matrix4({0.f,0.f,-2.f}, v3f::zero(), v3f::unit_y()) *
projection;
material.properties()
.property("u_time", game_time)
.property("u_MVP", MVP);
material.properties()
.sampler("u_texture", render::sampler_state()
.texture(texture)
.min_filter(render::sampler_min_filter::linear)
.mag_filter(render::sampler_mag_filter::linear));
the<render>()
.set_render_target(rt)
.set_viewport(0, 0, rt->size().x, rt->size().y)
.clear_depth_buffer(1.f)
.clear_stencil_buffer(0)
.clear_color_buffer({0.f, 0.4f, 0.f, 1.f})
.draw(material, geometry);
material.properties()
.sampler("u_texture", render::sampler_state()
.texture(rt->color())
.min_filter(render::sampler_min_filter::linear)
.mag_filter(render::sampler_mag_filter::linear));
the<render>()
.set_render_target(nullptr)
.set_viewport(0, 0, the<window>().real_size().x, the<window>().real_size().y)
.clear_depth_buffer(1.f)
.clear_stencil_buffer(0)
.clear_color_buffer({1.f, 0.4f, 0.f, 1.f})
.draw(material, geometry);
std::this_thread::sleep_for(time::to_chrono(make_milliseconds(10)));
the<window>().swap_buffers(true);
the<input>().frame_tick();
window::poll_events();
}
return 0;
}

View File

@@ -10,6 +10,37 @@ namespace
{
using namespace e2d;
struct pixel_type_description {
u32 minimal_size;
u32 bits_per_pixel;
pixel_declaration::pixel_type type;
bool compressed;
bool must_be_square;
bool must_be_power_of_two;
};
const pixel_type_description pixel_type_descriptions[] = {
{1, 32, pixel_declaration::pixel_type::rgba8, false, false, false},
{1, 32, pixel_declaration::pixel_type::depth24_stencil8, false, false, false},
{4, 4, pixel_declaration::pixel_type::dxt1, true, false, true},
{4, 8, pixel_declaration::pixel_type::dxt3, true, false, true},
{4, 8, pixel_declaration::pixel_type::dxt5, true, false, true},
{8, 2, pixel_declaration::pixel_type::rgb_pvrtc2, true, true, true},
{8, 4, pixel_declaration::pixel_type::rgb_pvrtc4, true, true, true},
{8, 2, pixel_declaration::pixel_type::rgba_pvrtc2, true, true, true},
{8, 4, pixel_declaration::pixel_type::rgba_pvrtc4, true, true, true}
};
const pixel_type_description& get_pixel_type_description(pixel_declaration::pixel_type type) noexcept {
const std::size_t index = math::numeric_cast<std::size_t>(math::enum_to_number(type));
E2D_ASSERT(index < E2D_COUNTOF(pixel_type_descriptions));
const pixel_type_description& desc = pixel_type_descriptions[index];
E2D_ASSERT(desc.type == type);
return desc;
}
std::size_t index_element_size(index_declaration::index_type it) noexcept {
#define DEFINE_CASE(x,y) case index_declaration::index_type::x: return y;
switch ( it ) {
@@ -41,50 +72,55 @@ namespace
namespace e2d
{
//
// index_declaration::index_info
// pixel_declaration
//
index_declaration::index_info::index_info(index_type ntype) noexcept
: type(ntype) {}
pixel_declaration::pixel_declaration(pixel_type type) noexcept
: type_(type) {}
pixel_declaration::pixel_type pixel_declaration::type() const noexcept {
return type_;
}
bool pixel_declaration::is_compressed() const noexcept {
return get_pixel_type_description(type_).compressed;
}
std::size_t pixel_declaration::bits_per_pixel() const noexcept {
return get_pixel_type_description(type_).bits_per_pixel;
}
bool operator==(const pixel_declaration& l, const pixel_declaration& r) noexcept {
return l.type() == r.type();
}
bool operator!=(const pixel_declaration& l, const pixel_declaration& r) noexcept {
return !(l == r);
}
//
// index_declaration
//
index_declaration::index_declaration(index_type type) noexcept
: index_(type) {}
: type_(type) {}
const index_declaration::index_info& index_declaration::index() const noexcept {
return index_;
index_declaration::index_type index_declaration::type() const noexcept {
return type_;
}
std::size_t index_declaration::index_size() const noexcept {
return index_element_size(index_.type);
std::size_t index_declaration::bytes_per_index() const noexcept {
return index_element_size(type_);
}
bool operator==(const index_declaration& l, const index_declaration& r) noexcept {
return l.index_size() == r.index_size()
&& l.index() == r.index();
return l.type() == r.type();
}
bool operator!=(const index_declaration& l, const index_declaration& r) noexcept {
return !(l == r);
}
bool operator==(
const index_declaration::index_info& l,
const index_declaration::index_info& r) noexcept
{
return l.type == r.type;
}
bool operator!=(
const index_declaration::index_info& l,
const index_declaration::index_info& r) noexcept
{
return !(l == r);
}
//
// vertex_declaration::attribute_info
//
@@ -118,7 +154,7 @@ namespace e2d
}
vertex_declaration& vertex_declaration::skip_bytes(std::size_t bytes) noexcept {
vertex_size_ += bytes;
bytes_per_vertex_ += bytes;
return *this;
}
@@ -130,7 +166,7 @@ namespace e2d
bool normalized) noexcept
{
E2D_ASSERT(attribute_count_ < attributes_.size());
const std::size_t stride = vertex_size_;
const std::size_t stride = bytes_per_vertex_;
attributes_[attribute_count_] = attribute_info(
stride,
name,
@@ -138,7 +174,7 @@ namespace e2d
columns,
type,
normalized);
vertex_size_ += attribute_element_size(type) * rows * columns;
bytes_per_vertex_ += attribute_element_size(type) * rows * columns;
++attribute_count_;
return *this;
}
@@ -152,12 +188,12 @@ namespace e2d
return attribute_count_;
}
std::size_t vertex_declaration::vertex_size() const noexcept {
return vertex_size_;
std::size_t vertex_declaration::bytes_per_vertex() const noexcept {
return bytes_per_vertex_;
}
bool operator==(const vertex_declaration& l, const vertex_declaration& r) noexcept {
if ( l.vertex_size() != r.vertex_size() ) {
if ( l.bytes_per_vertex() != r.bytes_per_vertex() ) {
return false;
}
if ( l.attribute_count() != r.attribute_count() ) {
@@ -695,6 +731,11 @@ namespace e2d
return pass_count_;
}
render::material& render::material::properties(const property_block& properties) noexcept {
properties_ = properties;
return *this;
}
render::pass_state& render::material::pass(std::size_t index) noexcept {
return passes_[index];
}

View File

@@ -50,6 +50,16 @@ namespace e2d
~internal_state() noexcept = default;
};
//
// render_target::internal_state
//
class render_target::internal_state final : private e2d::noncopyable {
public:
internal_state() noexcept = default;
~internal_state() noexcept = default;
};
//
// render::internal_state
//
@@ -94,8 +104,9 @@ namespace e2d
return size;
}
image_data_format texture::format() const noexcept {
return image_data_format::rgba8;
const pixel_declaration& texture::decl() const noexcept {
static pixel_declaration decl;
return decl;
}
//
@@ -122,6 +133,29 @@ namespace e2d
: state_(std::move(state)) {}
vertex_buffer::~vertex_buffer() noexcept = default;
//
// render_target
//
render_target::render_target(internal_state_uptr state)
: state_(std::move(state)) {}
render_target::~render_target() noexcept = default;
const v2u& render_target::size() const noexcept {
static v2u size;
return size;
}
const texture_ptr& render_target::color() const noexcept {
static texture_ptr color;
return color;
}
const texture_ptr& render_target::depth() const noexcept {
static texture_ptr depth;
return depth;
}
//
// render
//
@@ -148,6 +182,11 @@ namespace e2d
return nullptr;
}
texture_ptr render::create_texture(const v2u& size, const pixel_declaration& decl) {
E2D_UNUSED(size, decl);
return nullptr;
}
index_buffer_ptr render::create_index_buffer(
const buffer& indices,
const index_declaration& decl,
@@ -166,6 +205,11 @@ namespace e2d
return nullptr;
}
render_target_ptr render::create_render_target(const v2u& size, render_target::type type) {
E2D_UNUSED(size, type);
return nullptr;
}
void render::draw(
const material& mat,
const geometry& geo)
@@ -200,6 +244,11 @@ namespace e2d
E2D_UNUSED(x, y, w, h);
return *this;
}
render& render::set_render_target(const render_target_ptr& rt) noexcept {
E2D_UNUSED(rt);
return *this;
}
}
#endif

View File

@@ -192,7 +192,7 @@ namespace
math::numeric_cast<GLint>(vai.columns),
convert_attribute_type(vai.type),
vai.normalized ? GL_TRUE : GL_FALSE,
math::numeric_cast<GLsizei>(decl.vertex_size()),
math::numeric_cast<GLsizei>(decl.bytes_per_vertex()),
reinterpret_cast<const GLvoid*>(vai.stride + row * vai.row_size())));
}
});
@@ -225,7 +225,7 @@ namespace
GL_CHECK_CODE(debug, glDrawElements(
convert_topology(tp),
math::numeric_cast<GLsizei>(ib->index_count()),
convert_index_type(decl.index().type),
convert_index_type(decl.type()),
nullptr));
});
}
@@ -321,8 +321,8 @@ namespace e2d
return state_->size();
}
image_data_format texture::format() const noexcept {
return state_->format();
const pixel_declaration& texture::decl() const noexcept {
return state_->decl();
}
//
@@ -340,9 +340,9 @@ namespace e2d
index_buffer::~index_buffer() noexcept = default;
void index_buffer::update(const buffer& indices, std::size_t offset) noexcept {
const std::size_t buffer_offset = offset * state_->decl().index_size();
const std::size_t buffer_offset = offset * state_->decl().bytes_per_index();
E2D_ASSERT(indices.size() + buffer_offset <= state_->size());
E2D_ASSERT(indices.size() % state_->decl().index_size() == 0);
E2D_ASSERT(indices.size() % state_->decl().bytes_per_index() == 0);
opengl::with_gl_bind_buffer(state_->dbg(), state_->id(),
[this, &indices, &buffer_offset]() noexcept {
GL_CHECK_CODE(state_->dbg(), glBufferSubData(
@@ -353,17 +353,17 @@ namespace e2d
});
}
const index_declaration& index_buffer::decl() const noexcept {
return state_->decl();
}
std::size_t index_buffer::buffer_size() const noexcept {
return state_->size();
}
std::size_t index_buffer::index_count() const noexcept {
E2D_ASSERT(state_->size() % state_->decl().index_size() == 0);
return state_->size() / state_->decl().index_size();
E2D_ASSERT(state_->size() % state_->decl().bytes_per_index() == 0);
return state_->size() / state_->decl().bytes_per_index();
}
const index_declaration& index_buffer::decl() const noexcept {
return state_->decl();
}
//
@@ -381,9 +381,9 @@ namespace e2d
vertex_buffer::~vertex_buffer() noexcept = default;
void vertex_buffer::update(const buffer& vertices, std::size_t offset) noexcept {
const std::size_t buffer_offset = offset * state_->decl().vertex_size();
const std::size_t buffer_offset = offset * state_->decl().bytes_per_vertex();
E2D_ASSERT(vertices.size() + buffer_offset <= state_->size());
E2D_ASSERT(vertices.size() % state_->decl().vertex_size() == 0);
E2D_ASSERT(vertices.size() % state_->decl().bytes_per_vertex() == 0);
opengl::with_gl_bind_buffer(state_->dbg(), state_->id(),
[this, &vertices, &buffer_offset]() noexcept {
GL_CHECK_CODE(state_->dbg(), glBufferSubData(
@@ -394,17 +394,43 @@ namespace e2d
});
}
const vertex_declaration& vertex_buffer::decl() const noexcept {
return state_->decl();
}
std::size_t vertex_buffer::buffer_size() const noexcept {
return state_->size();
}
std::size_t vertex_buffer::vertex_count() const noexcept {
E2D_ASSERT(state_->size() % state_->decl().vertex_size() == 0);
return state_->size() / state_->decl().vertex_size();
E2D_ASSERT(state_->size() % state_->decl().bytes_per_vertex() == 0);
return state_->size() / state_->decl().bytes_per_vertex();
}
const vertex_declaration& vertex_buffer::decl() const noexcept {
return state_->decl();
}
//
// render_target
//
const render_target::internal_state& render_target::state() const noexcept {
return *state_;
}
render_target::render_target(internal_state_uptr state)
: state_(std::move(state)) {
E2D_ASSERT(state_);
}
render_target::~render_target() noexcept = default;
const v2u& render_target::size() const noexcept {
return state_->size();
}
const texture_ptr& render_target::color() const noexcept {
return state_->color();
}
const texture_ptr& render_target::depth() const noexcept {
return state_->depth();
}
//
@@ -448,17 +474,54 @@ namespace e2d
state_->dbg(), std::move(ps)));
}
texture_ptr render::create_texture(const image& image) {
gl_texture_id id = gl_compile_texture(state_->dbg(), image);
texture_ptr render::create_texture(
const image& image)
{
gl_texture_id id = gl_texture_id::create(
state_->dbg(), GL_TEXTURE_2D);
if ( id.empty() ) {
state_->dbg().error("RENDER: Failed to create texture: %0",
"failed to create texture id");
return nullptr;
}
const pixel_declaration decl =
convert_image_data_format_to_pixel_declaration(image.format());
with_gl_bind_texture(state_->dbg(), id, [this, &id, &image, &decl]() noexcept {
if ( decl.is_compressed() ) {
GL_CHECK_CODE(state_->dbg(), glCompressedTexImage2D(
id.target(),
0,
convert_pixel_type_to_compressed_format(decl.type()),
math::numeric_cast<GLsizei>(image.size().x),
math::numeric_cast<GLsizei>(image.size().y),
0,
math::numeric_cast<GLsizei>(image.data().size()),
image.data().data()));
} else {
GL_CHECK_CODE(state_->dbg(), glTexImage2D(
id.target(),
0,
convert_pixel_type_to_internal_format(decl.type()),
math::numeric_cast<GLsizei>(image.size().x),
math::numeric_cast<GLsizei>(image.size().y),
0,
convert_image_data_format_to_external_format(image.format()),
convert_image_data_format_to_external_data_type(image.format()),
image.data().data()));
}
#if !defined(GL_ES_VERSION_2_0)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
#endif
});
return std::make_shared<texture>(
std::make_unique<texture::internal_state>(
state_->dbg(), std::move(id), image.size(), image.format()));
state_->dbg(), std::move(id), image.size(), decl));
}
texture_ptr render::create_texture(const input_stream_uptr& image_stream) {
texture_ptr render::create_texture(
const input_stream_uptr& image_stream)
{
image image;
if ( !images::try_load_image(image, image_stream) ) {
return nullptr;
@@ -466,13 +529,59 @@ namespace e2d
return create_texture(image);
}
texture_ptr render::create_texture(
const v2u& size,
const pixel_declaration& decl)
{
gl_texture_id id = gl_texture_id::create(
state_->dbg(), GL_TEXTURE_2D);
if ( id.empty() ) {
state_->dbg().error("RENDER: Failed to create texture: %0",
"failed to create texture id");
return nullptr;
}
with_gl_bind_texture(state_->dbg(), id, [this, &id, &size, &decl]() noexcept {
if ( decl.is_compressed() ) {
buffer empty_data(decl.bits_per_pixel() * size.x * size.y / 8);
GL_CHECK_CODE(state_->dbg(), glCompressedTexImage2D(
id.target(),
0,
convert_pixel_type_to_compressed_format(decl.type()),
math::numeric_cast<GLsizei>(size.x),
math::numeric_cast<GLsizei>(size.y),
0,
math::numeric_cast<GLsizei>(empty_data.size()),
empty_data.data()));
} else {
GL_CHECK_CODE(state_->dbg(), glTexImage2D(
id.target(),
0,
convert_pixel_type_to_internal_format(decl.type()),
math::numeric_cast<GLsizei>(size.x),
math::numeric_cast<GLsizei>(size.y),
0,
convert_pixel_type_to_external_format(decl.type()),
convert_pixel_type_to_external_data_type(decl.type()),
nullptr));
}
#if !defined(GL_ES_VERSION_2_0)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
#endif
});
return std::make_shared<texture>(
std::make_unique<texture::internal_state>(
state_->dbg(), std::move(id), size, decl));
}
index_buffer_ptr render::create_index_buffer(
const buffer& indices,
const index_declaration& decl,
index_buffer::usage usage)
{
E2D_ASSERT(indices.size() % decl.index_size() == 0);
gl_buffer_id id = gl_compile_index_buffer(state_->dbg(), indices, usage);
E2D_ASSERT(indices.size() % decl.bytes_per_index() == 0);
gl_buffer_id id = gl_compile_index_buffer(
state_->dbg(), indices, usage);
if ( id.empty() ) {
return nullptr;
}
@@ -486,8 +595,9 @@ namespace e2d
const vertex_declaration& decl,
vertex_buffer::usage usage)
{
E2D_ASSERT(vertices.size() % decl.vertex_size() == 0);
gl_buffer_id id = gl_compile_vertex_buffer(state_->dbg(), vertices, usage);
E2D_ASSERT(vertices.size() % decl.bytes_per_vertex() == 0);
gl_buffer_id id = gl_compile_vertex_buffer(
state_->dbg(), vertices, usage);
if ( id.empty() ) {
return nullptr;
}
@@ -496,6 +606,83 @@ namespace e2d
state_->dbg(), std::move(id), vertices.size(), decl));
}
render_target_ptr render::create_render_target(
const v2u& size,
render_target::type type)
{
gl_framebuffer_id id = gl_framebuffer_id::create(
state_->dbg(), GL_FRAMEBUFFER);
if ( id.empty() ) {
state_->dbg().error("RENDER: Failed to create framebuffer: %0",
"failed to create framebuffer id");
return nullptr;
}
bool need_color = math::enum_to_number(type) & math::enum_to_number(render_target::type::color);
bool need_depth = math::enum_to_number(type) & math::enum_to_number(render_target::type::depth);
texture_ptr color;
texture_ptr depth;
gl_renderbuffer_id color_rb(state_->dbg());
gl_renderbuffer_id depth_rb(state_->dbg());
if ( need_color ) {
color = create_texture(size, pixel_declaration::pixel_type::rgba8);
if ( !color ) {
state_->dbg().error("RENDER: Failed to create framebuffer: %0",
"failed to create color texture");
return nullptr;
}
gl_attach_texture(state_->dbg(), id, color->state().id(), GL_COLOR_ATTACHMENT0);
} else {
color_rb = gl_compile_renderbuffer(state_->dbg(), size, GL_RGBA8);
if ( color_rb.empty() ) {
state_->dbg().error("RENDER: Failed to create framebuffer: %0",
"failed to create color renderbuffer");
return nullptr;
}
gl_attach_renderbuffer(state_->dbg(), id, color_rb, GL_COLOR_ATTACHMENT0);
}
if ( need_depth ) {
depth = create_texture(size, pixel_declaration::pixel_type::depth24_stencil8);
if ( !depth ) {
state_->dbg().error("RENDER: Failed to create framebuffer: %0",
"failed to create depth texture");
return nullptr;
}
gl_attach_texture(state_->dbg(), id, depth->state().id(), GL_DEPTH_ATTACHMENT);
gl_attach_texture(state_->dbg(), id, depth->state().id(), GL_STENCIL_ATTACHMENT);
} else {
depth_rb = gl_compile_renderbuffer(state_->dbg(), size, GL_DEPTH24_STENCIL8);
if ( depth_rb.empty() ) {
state_->dbg().error("RENDER: Failed to create framebuffer: %0",
"failed to create depth renderbuffer");
return nullptr;
}
gl_attach_renderbuffer(state_->dbg(), id, depth_rb, GL_DEPTH_ATTACHMENT);
gl_attach_renderbuffer(state_->dbg(), id, depth_rb, GL_STENCIL_ATTACHMENT);
}
GLenum fb_status = GL_FRAMEBUFFER_COMPLETE;
if ( !gl_check_framebuffer(state_->dbg(), id, &fb_status) ) {
state_->dbg().error("RENDER: Failed to create framebuffer: %0",
gl_framebuffer_status_to_cstr(fb_status));
return nullptr;
}
return std::make_shared<render_target>(
std::make_unique<render_target::internal_state>(
state_->dbg(),
std::move(id),
size,
std::move(color),
std::move(depth),
std::move(color_rb),
std::move(depth_rb)));
}
void render::draw(
const material& mat,
const geometry& geo)
@@ -524,26 +711,35 @@ namespace e2d
}
render& render::clear_depth_buffer(f32 value) noexcept {
GL_CHECK_CODE(state_->dbg(), glClearDepth(
math::numeric_cast<GLclampd>(math::saturate(value))));
GL_CHECK_CODE(state_->dbg(), glClear(GL_DEPTH_BUFFER_BIT));
const render_target_ptr& rt = state_->render_target();
if ( !rt || rt->state().depth() || !rt->state().depth_rb().empty() ) {
GL_CHECK_CODE(state_->dbg(), glClearDepth(
math::numeric_cast<GLclampd>(math::saturate(value))));
GL_CHECK_CODE(state_->dbg(), glClear(GL_DEPTH_BUFFER_BIT));
}
return *this;
}
render& render::clear_stencil_buffer(u8 value) noexcept {
GL_CHECK_CODE(state_->dbg(), glClearStencil(
math::numeric_cast<GLint>(value)));
GL_CHECK_CODE(state_->dbg(), glClear(GL_STENCIL_BUFFER_BIT));
const render_target_ptr& rt = state_->render_target();
if ( !rt || rt->state().depth() || !rt->state().depth_rb().empty() ) {
GL_CHECK_CODE(state_->dbg(), glClearStencil(
math::numeric_cast<GLint>(value)));
GL_CHECK_CODE(state_->dbg(), glClear(GL_STENCIL_BUFFER_BIT));
}
return *this;
}
render& render::clear_color_buffer(const color& value) noexcept {
GL_CHECK_CODE(state_->dbg(), glClearColor(
math::numeric_cast<GLclampf>(math::saturate(value.r)),
math::numeric_cast<GLclampf>(math::saturate(value.g)),
math::numeric_cast<GLclampf>(math::saturate(value.b)),
math::numeric_cast<GLclampf>(math::saturate(value.a))));
GL_CHECK_CODE(state_->dbg(), glClear(GL_COLOR_BUFFER_BIT));
const render_target_ptr& rt = state_->render_target();
if ( !rt || rt->state().color() || !rt->state().color_rb().empty() ) {
GL_CHECK_CODE(state_->dbg(), glClearColor(
math::numeric_cast<GLclampf>(math::saturate(value.r)),
math::numeric_cast<GLclampf>(math::saturate(value.g)),
math::numeric_cast<GLclampf>(math::saturate(value.b)),
math::numeric_cast<GLclampf>(math::saturate(value.a))));
GL_CHECK_CODE(state_->dbg(), glClear(GL_COLOR_BUFFER_BIT));
}
return *this;
}
@@ -555,6 +751,11 @@ namespace e2d
math::numeric_cast<GLsizei>(h)));
return *this;
}
render& render::set_render_target(const render_target_ptr& rt) noexcept {
state_->set_render_target(rt);
return *this;
}
}
#endif

View File

@@ -38,6 +38,11 @@ namespace
*loc = glGetAttribLocation(program, name);
}
void gl_check_framebuffer_status(GLenum target, GLenum* res) noexcept {
E2D_ASSERT(res);
*res = glCheckFramebufferStatus(target);
}
bool process_shader_compilation_result(debug& debug, GLuint shader) noexcept {
E2D_ASSERT(glIsShader(shader));
GLint success = GL_FALSE;
@@ -169,12 +174,10 @@ namespace e2d { namespace opengl
}
GLuint gl_buffer_id::operator*() const noexcept {
E2D_ASSERT(!empty());
return id_;
}
GLenum gl_buffer_id::target() const noexcept {
E2D_ASSERT(!empty());
return target_;
}
@@ -247,12 +250,10 @@ namespace e2d { namespace opengl
}
GLuint gl_shader_id::operator*() const noexcept {
E2D_ASSERT(!empty());
return id_;
}
GLenum gl_shader_id::type() const noexcept {
E2D_ASSERT(!empty());
return type_;
}
@@ -325,7 +326,6 @@ namespace e2d { namespace opengl
}
GLuint gl_program_id::operator*() const noexcept {
E2D_ASSERT(!empty());
return id_;
}
@@ -405,12 +405,10 @@ namespace e2d { namespace opengl
}
GLuint gl_texture_id::operator*() const noexcept {
E2D_ASSERT(!empty());
return id_;
}
GLenum gl_texture_id::target() const noexcept {
E2D_ASSERT(!empty());
return target_;
}
@@ -489,12 +487,10 @@ namespace e2d { namespace opengl
}
GLuint gl_framebuffer_id::operator*() const noexcept {
E2D_ASSERT(!empty());
return id_;
}
GLenum gl_framebuffer_id::target() const noexcept {
E2D_ASSERT(!empty());
return target_;
}
@@ -573,12 +569,10 @@ namespace e2d { namespace opengl
}
GLuint gl_renderbuffer_id::operator*() const noexcept {
E2D_ASSERT(!empty());
return id_;
}
GLenum gl_renderbuffer_id::target() const noexcept {
E2D_ASSERT(!empty());
return target_;
}
@@ -693,44 +687,109 @@ namespace e2d { namespace opengl
namespace e2d { namespace opengl
{
GLint convert_format_to_internal_format(image_data_format idf) noexcept {
#define DEFINE_CASE(x,y) case image_data_format::x: return y;
switch ( idf ) {
DEFINE_CASE(g8, GL_ALPHA);
GLenum convert_image_data_format_to_external_format(image_data_format f) noexcept {
#define DEFINE_CASE(x,y) case image_data_format::x: return y
switch ( f ) {
DEFINE_CASE(g8, GL_LUMINANCE);
DEFINE_CASE(ga8, GL_LUMINANCE_ALPHA);
DEFINE_CASE(rgb8, GL_RGB);
DEFINE_CASE(rgba8, GL_RGBA);
default:
E2D_ASSERT_MSG(false, "unexpected image data format");
return 0;
return GL_RGBA;
}
#undef DEFINE_CASE
}
GLenum convert_format_to_external_format(image_data_format idf) noexcept {
#define DEFINE_CASE(x,y) case image_data_format::x: return y;
switch ( idf ) {
DEFINE_CASE(g8, GL_ALPHA);
DEFINE_CASE(ga8, GL_LUMINANCE_ALPHA);
DEFINE_CASE(rgb8, GL_RGB);
DEFINE_CASE(rgba8, GL_RGBA);
default:
E2D_ASSERT_MSG(false, "unexpected image data format");
return 0;
}
#undef DEFINE_CASE
}
GLenum convert_format_to_external_data_type(image_data_format idf) noexcept {
#define DEFINE_CASE(x,y) case image_data_format::x: return y;
switch ( idf ) {
GLenum convert_image_data_format_to_external_data_type(image_data_format f) noexcept {
#define DEFINE_CASE(x,y) case image_data_format::x: return y
switch ( f ) {
DEFINE_CASE(g8, GL_UNSIGNED_BYTE);
DEFINE_CASE(ga8, GL_UNSIGNED_BYTE);
DEFINE_CASE(rgb8, GL_UNSIGNED_BYTE);
DEFINE_CASE(rgba8, GL_UNSIGNED_BYTE);
default:
E2D_ASSERT_MSG(false, "unexpected image data format");
return 0;
return GL_UNSIGNED_BYTE;
}
#undef DEFINE_CASE
}
GLenum convert_pixel_type_to_external_format(pixel_declaration::pixel_type f) noexcept {
#define DEFINE_CASE(x,y) case pixel_declaration::pixel_type::x: return y
switch ( f ) {
DEFINE_CASE(rgba8, GL_RGBA);
DEFINE_CASE(depth24_stencil8, GL_DEPTH_STENCIL);
default:
E2D_ASSERT_MSG(false, "unexpected pixel type");
return GL_RGBA;
}
#undef DEFINE_CASE
}
GLenum convert_pixel_type_to_external_data_type(pixel_declaration::pixel_type f) noexcept {
#define DEFINE_CASE(x,y) case pixel_declaration::pixel_type::x: return y
switch ( f ) {
DEFINE_CASE(rgba8, GL_UNSIGNED_BYTE);
DEFINE_CASE(depth24_stencil8, GL_UNSIGNED_INT_24_8);
default:
E2D_ASSERT_MSG(false, "unexpected pixel type");
return GL_UNSIGNED_BYTE;
}
#undef DEFINE_CASE
}
GLint convert_pixel_type_to_internal_format(pixel_declaration::pixel_type f) noexcept {
#define DEFINE_CASE(x,y) case pixel_declaration::pixel_type::x: return y
switch ( f ) {
DEFINE_CASE(rgba8, GL_RGBA);
DEFINE_CASE(depth24_stencil8, GL_DEPTH24_STENCIL8);
default:
E2D_ASSERT_MSG(false, "unexpected pixel type");
return GL_RGBA;
}
#undef DEFINE_CASE
}
GLenum convert_pixel_type_to_compressed_format(pixel_declaration::pixel_type f) noexcept {
#define DEFINE_CASE(x,y) case pixel_declaration::pixel_type::x: return y
switch ( f ) {
DEFINE_CASE(dxt1, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
DEFINE_CASE(dxt3, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT);
DEFINE_CASE(dxt5, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT);
DEFINE_CASE(rgb_pvrtc2, GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG);
DEFINE_CASE(rgb_pvrtc4, GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG);
DEFINE_CASE(rgba_pvrtc2, GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG);
DEFINE_CASE(rgba_pvrtc4, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG);
default:
E2D_ASSERT_MSG(false, "unexpected pixel type");
return GL_RGBA;
}
#undef DEFINE_CASE
}
pixel_declaration convert_image_data_format_to_pixel_declaration(image_data_format f) noexcept {
#define DEFINE_CASE(x,y) case image_data_format::x: return pixel_declaration(pixel_declaration::pixel_type::y)
switch ( f ) {
DEFINE_CASE(g8, rgba8);
DEFINE_CASE(ga8, rgba8);
DEFINE_CASE(rgb8, rgba8);
DEFINE_CASE(rgba8, rgba8);
DEFINE_CASE(dxt1, dxt1);
DEFINE_CASE(dxt3, dxt3);
DEFINE_CASE(dxt5, dxt5);
DEFINE_CASE(rgb_pvrtc2, rgb_pvrtc2);
DEFINE_CASE(rgb_pvrtc4, rgb_pvrtc4);
DEFINE_CASE(rgba_pvrtc2, rgba_pvrtc2);
DEFINE_CASE(rgba_pvrtc4, rgba_pvrtc4);
default:
E2D_ASSERT_MSG(false, "unexpected image data format");
return pixel_declaration(pixel_declaration::pixel_type::rgba8);
}
#undef DEFINE_CASE
}
@@ -1071,6 +1130,19 @@ namespace e2d { namespace opengl
#undef DEFINE_CASE
}
const char* gl_framebuffer_status_to_cstr(GLenum s) noexcept {
#define DEFINE_CASE(x) case x: return #x
switch ( s ) {
DEFINE_CASE(GL_FRAMEBUFFER_COMPLETE);
DEFINE_CASE(GL_FRAMEBUFFER_UNSUPPORTED);
DEFINE_CASE(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
DEFINE_CASE(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
default:
return "GL_FRAMEBUFFER_UNKNOWN";
}
#undef DEFINE_CASE
}
GLenum gl_target_to_get_target(GLenum t) noexcept {
#define DEFINE_CASE(x,y) case x: return y
switch ( t ) {
@@ -1181,31 +1253,6 @@ namespace e2d { namespace opengl
: gl_program_id(debug);
}
gl_texture_id gl_compile_texture(debug& debug, const image& image) {
gl_texture_id id = gl_texture_id::create(
debug, GL_TEXTURE_2D);
if ( id.empty() ) {
return id;
}
with_gl_bind_texture(debug, id, [&debug, &id, &image]() noexcept {
GL_CHECK_CODE(debug, glTexImage2D(
id.target(),
0,
convert_format_to_internal_format(image.format()),
math::numeric_cast<GLsizei>(image.size().x),
math::numeric_cast<GLsizei>(image.size().y),
0,
convert_format_to_external_format(image.format()),
convert_format_to_external_data_type(image.format()),
image.data().data()));
#if !defined(GL_ES_VERSION_2_0)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
#endif
});
return id;
}
gl_buffer_id gl_compile_index_buffer(
debug& debug, const buffer& indices, index_buffer::usage usage)
{
@@ -1241,6 +1288,76 @@ namespace e2d { namespace opengl
});
return id;
}
bool gl_check_framebuffer(
debug& debug,
const gl_framebuffer_id& fb,
GLenum* out_status) noexcept
{
E2D_ASSERT(!fb.empty());
GLenum status = GL_FRAMEBUFFER_COMPLETE;
with_gl_bind_framebuffer(debug, fb, [&debug, &fb, &status]() noexcept {
GL_CHECK_CODE(debug, gl_check_framebuffer_status(
fb.target(), &status));
});
if ( out_status ) {
*out_status = status;
}
return status == GL_FRAMEBUFFER_COMPLETE;
}
void gl_attach_texture(
debug& debug,
const gl_framebuffer_id& fb,
const gl_texture_id& tex,
GLenum attachment) noexcept
{
E2D_ASSERT(!fb.empty() && !tex.empty());
with_gl_bind_framebuffer(debug, fb, [&debug, &fb, &tex, &attachment]() noexcept {
GL_CHECK_CODE(debug, glFramebufferTexture2D(
fb.target(),
attachment,
tex.target(),
*tex,
0));
});
}
void gl_attach_renderbuffer(
debug& debug,
const gl_framebuffer_id& fb,
const gl_renderbuffer_id& rb,
GLenum attachment) noexcept
{
E2D_ASSERT(!fb.empty() && !rb.empty());
with_gl_bind_framebuffer(debug, fb, [&debug, &fb, &rb, &attachment]() noexcept {
GL_CHECK_CODE(debug, glFramebufferRenderbuffer(
fb.target(),
attachment,
rb.target(),
*rb));
});
}
gl_renderbuffer_id gl_compile_renderbuffer(
debug& debug,
const v2u& size,
GLenum format)
{
gl_renderbuffer_id id = gl_renderbuffer_id::create(
debug, GL_RENDERBUFFER);
if ( id.empty() ) {
return id;
}
with_gl_bind_renderbuffer(debug, id, [&debug, &id, &size, &format]() noexcept {
GL_CHECK_CODE(debug, glRenderbufferStorage(
id.target(),
format,
math::numeric_cast<GLsizei>(size.x),
math::numeric_cast<GLsizei>(size.y)));
});
return id;
}
}}
namespace e2d { namespace opengl

View File

@@ -14,6 +14,91 @@
# include <OpenGL/gl.h>
#endif
//
// https://www.khronos.org/registry/OpenGL/extensions/
// OES/OES_rgb8_rgba8.txt
//
#ifndef GL_RGB8
# define GL_RGB8 0x8051
#endif
#ifndef GL_RGBA8
# define GL_RGBA8 0x8058
#endif
//
// https://www.khronos.org/registry/OpenGL/extensions/
// OES/OES_depth_texture.txt
//
#ifndef GL_UNSIGNED_INT
# define GL_UNSIGNED_INT 0x1405
#endif
#ifndef GL_UNSIGNED_SHORT
# define GL_UNSIGNED_SHORT 0x1403
#endif
#ifndef GL_DEPTH_COMPONENT
# define GL_DEPTH_COMPONENT 0x1902
#endif
//
// https://www.khronos.org/registry/OpenGL/extensions/
// OES/OES_packed_depth_stencil.txt
//
#ifndef GL_DEPTH_STENCIL
# define GL_DEPTH_STENCIL 0x84F9
#endif
#ifndef GL_DEPTH24_STENCIL8
# define GL_DEPTH24_STENCIL8 0x88F0
#endif
#ifndef GL_UNSIGNED_INT_24_8
# define GL_UNSIGNED_INT_24_8 0x84FA
#endif
//
// https://www.khronos.org/registry/OpenGL/extensions/
// EXT/EXT_texture_compression_s3tc.txt
//
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
# define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
# define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
#endif
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
# define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#endif
//
// https://www.khronos.org/registry/OpenGL/extensions/
// IMG/IMG_texture_compression_pvrtc.txt
//
#ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG
# define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
#endif
#ifndef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG
# define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
#endif
#ifndef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
# define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
#endif
#ifndef GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
# define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
#endif
#define GL_FLUSH_ERRORS(dbg)\
for ( GLenum err = glGetError(); err != GL_NO_ERROR; err = glGetError() ) {\
E2D_ASSERT_MSG(false, "RENDER: GL_FLUSH_ERRORS()");\
@@ -229,9 +314,15 @@ namespace e2d { namespace opengl
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_image_data_format_to_external_format(image_data_format f) noexcept;
GLenum convert_image_data_format_to_external_data_type(image_data_format f) noexcept;
GLenum convert_pixel_type_to_external_format(pixel_declaration::pixel_type f) noexcept;
GLenum convert_pixel_type_to_external_data_type(pixel_declaration::pixel_type f) noexcept;
GLint convert_pixel_type_to_internal_format(pixel_declaration::pixel_type f) noexcept;
GLenum convert_pixel_type_to_compressed_format(pixel_declaration::pixel_type f) noexcept;
pixel_declaration convert_image_data_format_to_pixel_declaration(image_data_format f) noexcept;
GLenum convert_index_type(index_declaration::index_type it) noexcept;
GLenum convert_attribute_type(vertex_declaration::attribute_type at) noexcept;
@@ -258,6 +349,7 @@ namespace e2d { namespace opengl
const char* glsl_type_to_cstr(GLenum t) noexcept;
const char* gl_error_code_to_cstr(GLenum e) noexcept;
const char* gl_framebuffer_status_to_cstr(GLenum s) noexcept;
GLenum gl_target_to_get_target(GLenum t) noexcept;
}}
@@ -267,9 +359,30 @@ namespace e2d { namespace opengl
void gl_trace_limits(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);
bool gl_check_framebuffer(
debug& debug,
const gl_framebuffer_id& fb,
GLenum* out_status) noexcept;
void gl_attach_texture(
debug& debug,
const gl_framebuffer_id& fb,
const gl_texture_id& tex,
GLenum attachment) noexcept;
void gl_attach_renderbuffer(
debug& debug,
const gl_framebuffer_id& fb,
const gl_renderbuffer_id& rb,
GLenum attachment) noexcept;
gl_renderbuffer_id gl_compile_renderbuffer(
debug& debug,
const v2u& size,
GLenum format);
}}
namespace e2d { namespace opengl

View File

@@ -76,11 +76,11 @@ namespace e2d
debug& debug,
gl_texture_id id,
const v2u& size,
image_data_format format)
const pixel_declaration& decl)
: debug_(debug)
, id_(std::move(id))
, size_(size)
, format_(format){
, decl_(decl){
E2D_ASSERT(!id_.empty());
}
@@ -96,8 +96,8 @@ namespace e2d
return size_;
}
image_data_format texture::internal_state::format() const noexcept {
return format_;
const pixel_declaration& texture::internal_state::decl() const noexcept {
return decl_;
}
//
@@ -164,13 +164,63 @@ namespace e2d
return decl_;
}
//
// render_target::internal_state
//
render_target::internal_state::internal_state(
debug& debug,
opengl::gl_framebuffer_id id,
const v2u& size,
texture_ptr color,
texture_ptr depth,
opengl::gl_renderbuffer_id color_rb,
opengl::gl_renderbuffer_id depth_rb)
: debug_(debug)
, id_(std::move(id))
, size_(size)
, color_(std::move(color))
, depth_(std::move(depth))
, color_rb_(std::move(color_rb))
, depth_rb_(std::move(depth_rb)){
E2D_ASSERT(!id_.empty());
}
debug& render_target::internal_state::dbg() const noexcept {
return debug_;
}
const gl_framebuffer_id& render_target::internal_state::id() const noexcept {
return id_;
}
const v2u& render_target::internal_state::size() const noexcept {
return size_;
}
const texture_ptr& render_target::internal_state::color() const noexcept {
return color_;
}
const texture_ptr& render_target::internal_state::depth() const noexcept {
return depth_;
}
const gl_renderbuffer_id& render_target::internal_state::color_rb() const noexcept {
return color_rb_;
}
const gl_renderbuffer_id& render_target::internal_state::depth_rb() const noexcept {
return depth_rb_;
}
//
// render::internal_state
//
render::internal_state::internal_state(debug& debug, window& window)
: debug_(debug)
, window_(window) {}
, window_(window)
, default_fb_(gl_framebuffer_id::current(debug, GL_FRAMEBUFFER)) {}
debug& render::internal_state::dbg() const noexcept {
return debug_;
@@ -180,6 +230,10 @@ namespace e2d
return window_;
}
const render_target_ptr& render::internal_state::render_target() const noexcept {
return render_target_;
}
render::internal_state& render::internal_state::set_states(const state_block& rs) noexcept {
set_depth_state(rs.depth());
set_stencil_state(rs.stencil());
@@ -258,5 +312,19 @@ namespace e2d
GL_CHECK_CODE(debug_, enable_or_disable(GL_STENCIL_TEST, cs.stencil_test()));
return *this;
}
render::internal_state& render::internal_state::set_render_target(const render_target_ptr& rt) noexcept {
if ( rt ) {
GL_CHECK_CODE(debug_, glBindFramebuffer(
rt->state().id().target(),
*rt->state().id()));
} else {
GL_CHECK_CODE(debug_, glBindFramebuffer(
default_fb_.target(),
*default_fb_));
}
render_target_ = rt;
return *this;
}
}
#endif

View File

@@ -64,18 +64,18 @@ namespace e2d
debug& debug,
opengl::gl_texture_id id,
const v2u& size,
image_data_format format);
const pixel_declaration& decl);
~internal_state() noexcept = default;
public:
debug& dbg() const noexcept;
const opengl::gl_texture_id& id() const noexcept;
const v2u& size() const noexcept;
image_data_format format() const noexcept;
const pixel_declaration& decl() const noexcept;
private:
debug& debug_;
opengl::gl_texture_id id_;
v2u size_;
image_data_format format_;
pixel_declaration decl_;
};
//
@@ -126,6 +126,39 @@ namespace e2d
vertex_declaration decl_;
};
//
// render_target::internal_state
//
class render_target::internal_state final : private e2d::noncopyable {
public:
internal_state(
debug& debug,
opengl::gl_framebuffer_id id,
const v2u& size,
texture_ptr color,
texture_ptr depth,
opengl::gl_renderbuffer_id color_rb,
opengl::gl_renderbuffer_id depth_rb);
~internal_state() noexcept = default;
public:
debug& dbg() const noexcept;
const opengl::gl_framebuffer_id& id() const noexcept;
const v2u& size() const noexcept;
const texture_ptr& color() const noexcept;
const texture_ptr& depth() const noexcept;
const opengl::gl_renderbuffer_id& color_rb() const noexcept;
const opengl::gl_renderbuffer_id& depth_rb() const noexcept;
private:
debug& debug_;
opengl::gl_framebuffer_id id_;
v2u size_;
texture_ptr color_;
texture_ptr depth_;
opengl::gl_renderbuffer_id color_rb_;
opengl::gl_renderbuffer_id depth_rb_;
};
//
// render::internal_state
//
@@ -139,6 +172,7 @@ namespace e2d
public:
debug& dbg() const noexcept;
window& wnd() const noexcept;
const render_target_ptr& render_target() const noexcept;
public:
internal_state& set_states(const state_block& rs) noexcept;
internal_state& set_depth_state(const depth_state& ds) noexcept;
@@ -146,9 +180,12 @@ namespace e2d
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;
internal_state& set_render_target(const render_target_ptr& rt) noexcept;
private:
debug& debug_;
window& window_;
render_target_ptr render_target_;
opengl::gl_framebuffer_id default_fb_;
};
}

View File

@@ -72,16 +72,16 @@ TEST_CASE("render"){
}
SECTION("index_declaration"){
index_declaration id;
REQUIRE(id.index().type == index_declaration::index_type::unsigned_short);
REQUIRE(id.index_size() == 2);
REQUIRE(id.type() == index_declaration::index_type::unsigned_short);
REQUIRE(id.bytes_per_index() == 2);
index_declaration id2(index_declaration::index_type::unsigned_short);
REQUIRE(id2.index().type == index_declaration::index_type::unsigned_short);
REQUIRE(id2.index_size() == 2);
REQUIRE(id2.type() == index_declaration::index_type::unsigned_short);
REQUIRE(id2.bytes_per_index() == 2);
index_declaration id3(index_declaration::index_type::unsigned_byte);
REQUIRE(id3.index().type == index_declaration::index_type::unsigned_byte);
REQUIRE(id3.index_size() == 1);
REQUIRE(id3.type() == index_declaration::index_type::unsigned_byte);
REQUIRE(id3.bytes_per_index() == 1);
REQUIRE(id == id2);
REQUIRE_FALSE(id == id3);
@@ -98,11 +98,11 @@ TEST_CASE("render"){
SECTION("vertex_declaration"){
vertex_declaration vd;
REQUIRE(vd.attribute_count() == 0);
REQUIRE(vd.vertex_size() == 0);
REQUIRE(vd.bytes_per_vertex() == 0);
REQUIRE(&vd == &vd.add_attribute<v2f>("hello"));
REQUIRE(vd.attribute_count() == 1);
REQUIRE(vd.vertex_size() == 8);
REQUIRE(vd.bytes_per_vertex() == 8);
vertex_declaration::attribute_info ai = vd.attribute(0);
REQUIRE(ai.name == make_hash("hello"));
@@ -112,11 +112,11 @@ TEST_CASE("render"){
REQUIRE_FALSE(ai.normalized);
REQUIRE(&vd == &vd.skip_bytes(4));
REQUIRE(vd.vertex_size() == 12);
REQUIRE(vd.bytes_per_vertex() == 12);
REQUIRE(&vd == &vd.add_attribute<u16>("world").normalized());
REQUIRE(vd.attribute_count() == 2);
REQUIRE(vd.vertex_size() == 14);
REQUIRE(vd.bytes_per_vertex() == 14);
vertex_declaration::attribute_info ai2 = vd.attribute(1);
REQUIRE(ai2.name == make_hash("world"));
@@ -138,9 +138,9 @@ TEST_CASE("render"){
REQUIRE_FALSE(vd == vd3);
REQUIRE(vd != vd3);
REQUIRE(vd3.vertex_size() == 16);
REQUIRE(vd3.bytes_per_vertex() == 16);
vd3.skip_bytes(4);
REQUIRE(vd3.vertex_size() == 20);
REQUIRE(vd3.bytes_per_vertex() == 20);
vertex_declaration vd4 = vd2;
REQUIRE(vd4 == vd);