mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-15 00:11:55 +07:00
render target first impl
This commit is contained in:
@@ -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_;
|
||||
|
||||
@@ -45,3 +45,4 @@ endfunction(add_e2d_sample)
|
||||
|
||||
add_e2d_sample(00)
|
||||
add_e2d_sample(01)
|
||||
add_e2d_sample(02)
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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));
|
||||
|
||||
243
samples/sources/sample_02/sample_02.cpp
Normal file
243
samples/sources/sample_02/sample_02.cpp
Normal 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;
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user