mirror of
https://github.com/enduro2d/enduro2d.git
synced 2026-01-04 17:21:01 +07:00
added ability to read texture and render_target; added region instead of size and offset to update_texture, added g8 and ga8 pixel_type
This commit is contained in:
@@ -49,6 +49,8 @@ namespace e2d
|
|||||||
depth32,
|
depth32,
|
||||||
depth24_stencil8,
|
depth24_stencil8,
|
||||||
|
|
||||||
|
g8,
|
||||||
|
ga8,
|
||||||
rgb8,
|
rgb8,
|
||||||
rgba8,
|
rgba8,
|
||||||
|
|
||||||
@@ -956,9 +958,25 @@ namespace e2d
|
|||||||
|
|
||||||
render& update_texture(
|
render& update_texture(
|
||||||
const texture_ptr& tex,
|
const texture_ptr& tex,
|
||||||
buffer_view data,
|
buffer_view pixels,
|
||||||
v2u size,
|
const b2u& region);
|
||||||
v2u offset);
|
|
||||||
|
// very slow
|
||||||
|
render& grab_texture(
|
||||||
|
const texture_ptr& tex,
|
||||||
|
const b2u& region,
|
||||||
|
image& result);
|
||||||
|
|
||||||
|
// very slow
|
||||||
|
render& grab_render_target(
|
||||||
|
const render_target_ptr& rt,
|
||||||
|
const b2u& region,
|
||||||
|
image& result);
|
||||||
|
|
||||||
|
// very slow
|
||||||
|
render& grab_screen(
|
||||||
|
const b2u& region,
|
||||||
|
image& result);
|
||||||
|
|
||||||
const device_caps& device_capabilities() const noexcept;
|
const device_caps& device_capabilities() const noexcept;
|
||||||
bool is_pixel_supported(const pixel_declaration& decl) const noexcept;
|
bool is_pixel_supported(const pixel_declaration& decl) const noexcept;
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ namespace e2d
|
|||||||
u8* data() noexcept;
|
u8* data() noexcept;
|
||||||
const u8* data() const noexcept;
|
const u8* data() const noexcept;
|
||||||
std::size_t size() const noexcept;
|
std::size_t size() const noexcept;
|
||||||
|
|
||||||
|
const u8* begin() const noexcept;
|
||||||
|
const u8* end() const noexcept;
|
||||||
|
u8* begin() noexcept;
|
||||||
|
u8* end() noexcept;
|
||||||
private:
|
private:
|
||||||
using data_t = std::unique_ptr<u8[]>;
|
using data_t = std::unique_ptr<u8[]>;
|
||||||
data_t data_;
|
data_t data_;
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ namespace
|
|||||||
{"depth32", 32, false, true, false, pixel_declaration::pixel_type::depth32, false, v2u(1)},
|
{"depth32", 32, false, true, false, pixel_declaration::pixel_type::depth32, false, v2u(1)},
|
||||||
{"depth24_stencil8", 32, false, true, true, pixel_declaration::pixel_type::depth24_stencil8, false, v2u(1)},
|
{"depth24_stencil8", 32, false, true, true, pixel_declaration::pixel_type::depth24_stencil8, false, v2u(1)},
|
||||||
|
|
||||||
|
{"g8", 8, true, false, false, pixel_declaration::pixel_type::g8, false, v2u(1)},
|
||||||
|
{"ga8", 16, true, false, false, pixel_declaration::pixel_type::ga8, false, v2u(1)},
|
||||||
{"rgb8", 24, true, false, false, pixel_declaration::pixel_type::rgb8, false, v2u(1)},
|
{"rgb8", 24, true, false, false, pixel_declaration::pixel_type::rgb8, false, v2u(1)},
|
||||||
{"rgba8", 32, true, false, false, pixel_declaration::pixel_type::rgba8, false, v2u(1)},
|
{"rgba8", 32, true, false, false, pixel_declaration::pixel_type::rgba8, false, v2u(1)},
|
||||||
|
|
||||||
|
|||||||
@@ -280,11 +280,39 @@ namespace e2d
|
|||||||
|
|
||||||
render& render::update_texture(
|
render& render::update_texture(
|
||||||
const texture_ptr& tex,
|
const texture_ptr& tex,
|
||||||
buffer_view data,
|
buffer_view pixels,
|
||||||
v2u size,
|
const b2u& region)
|
||||||
v2u offset)
|
|
||||||
{
|
{
|
||||||
E2D_UNUSED(tex, img, size, offset);
|
E2D_UNUSED(tex, pixels, region);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
render& render::grab_texture(
|
||||||
|
const texture_ptr& tex,
|
||||||
|
const b2u& region,
|
||||||
|
image& result)
|
||||||
|
{
|
||||||
|
E2D_UNUSED(tex, region);
|
||||||
|
result.clear();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
render& render::grab_render_target(
|
||||||
|
const render_target_ptr& rt,
|
||||||
|
const b2u& region,
|
||||||
|
image& result)
|
||||||
|
{
|
||||||
|
E2D_UNUSED(rt, region);
|
||||||
|
result.clear();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
render& render::grab_screen(
|
||||||
|
const b2u& region,
|
||||||
|
image& result)
|
||||||
|
{
|
||||||
|
E2D_UNUSED(tex);
|
||||||
|
result.clear();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1032,57 +1032,161 @@ namespace e2d
|
|||||||
pixel_declaration::pixel_type_to_cstr(decl.type()));
|
pixel_declaration::pixel_type_to_cstr(decl.type()));
|
||||||
throw bad_render_operation();
|
throw bad_render_operation();
|
||||||
}
|
}
|
||||||
return update_texture(tex, img.data(), img.size(), offset);
|
return update_texture(tex, img.data(), b2u(offset, img.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
render& render::update_texture(
|
render& render::update_texture(
|
||||||
const texture_ptr& tex,
|
const texture_ptr& tex,
|
||||||
buffer_view data,
|
buffer_view pixels,
|
||||||
v2u size,
|
const b2u& region)
|
||||||
v2u offset)
|
|
||||||
{
|
{
|
||||||
E2D_ASSERT(is_in_main_thread());
|
E2D_ASSERT(is_in_main_thread());
|
||||||
E2D_ASSERT(tex);
|
E2D_ASSERT(tex);
|
||||||
E2D_ASSERT(offset.x < tex->size().x && offset.y < tex->size().y);
|
E2D_ASSERT(region.position.x < tex->size().x && region.position.y < tex->size().y);
|
||||||
E2D_ASSERT(offset.x + size.x <= tex->size().x);
|
E2D_ASSERT(region.position.x + region.size.x <= tex->size().x);
|
||||||
E2D_ASSERT(offset.y + size.y <= tex->size().y);
|
E2D_ASSERT(region.position.y + region.size.y <= tex->size().y);
|
||||||
E2D_ASSERT(data.size() * 8u == size.y * size.x * tex->decl().bits_per_pixel());
|
E2D_ASSERT(pixels.size() == region.size.y * ((region.size.x * tex->decl().bits_per_pixel()) / 8u));
|
||||||
|
|
||||||
if ( tex->decl().is_compressed() ) {
|
if ( tex->decl().is_compressed() ) {
|
||||||
const v2u block_size = tex->decl().compressed_block_size();
|
const v2u block_size = tex->decl().compressed_block_size();
|
||||||
E2D_ASSERT(offset.x % block_size.x == 0 && offset.y % block_size.y == 0);
|
E2D_ASSERT(region.position.x % block_size.x == 0 && region.position.y % block_size.y == 0);
|
||||||
E2D_ASSERT(size.x % block_size.x == 0 && size.y % block_size.y == 0);
|
E2D_ASSERT(region.size.x % block_size.x == 0 && region.size.y % block_size.y == 0);
|
||||||
opengl::with_gl_bind_texture(state_->dbg(), tex->state().id(),
|
opengl::with_gl_bind_texture(state_->dbg(), tex->state().id(),
|
||||||
[&tex, &data, &size, &offset]() noexcept {
|
[&tex, &pixels, ®ion]() noexcept {
|
||||||
GL_CHECK_CODE(tex->state().dbg(), glCompressedTexSubImage2D(
|
GL_CHECK_CODE(tex->state().dbg(), glCompressedTexSubImage2D(
|
||||||
tex->state().id().target(),
|
tex->state().id().target(),
|
||||||
0,
|
0,
|
||||||
math::numeric_cast<GLint>(offset.x),
|
math::numeric_cast<GLint>(region.position.x),
|
||||||
math::numeric_cast<GLint>(offset.y),
|
math::numeric_cast<GLint>(region.position.y),
|
||||||
math::numeric_cast<GLsizei>(size.x),
|
math::numeric_cast<GLsizei>(region.size.x),
|
||||||
math::numeric_cast<GLsizei>(size.y),
|
math::numeric_cast<GLsizei>(region.size.y),
|
||||||
convert_pixel_type_to_external_format(tex->state().decl().type()),
|
convert_pixel_type_to_external_format(tex->state().decl().type()),
|
||||||
math::numeric_cast<GLsizei>(data.size()),
|
math::numeric_cast<GLsizei>(pixels.size()),
|
||||||
data.data()));
|
pixels.data()));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
opengl::with_gl_bind_texture(state_->dbg(), tex->state().id(),
|
opengl::with_gl_bind_texture(state_->dbg(), tex->state().id(),
|
||||||
[&tex, &data, &size, &offset]() noexcept {
|
[&tex, &pixels, ®ion]() noexcept {
|
||||||
GL_CHECK_CODE(tex->state().dbg(), glTexSubImage2D(
|
GL_CHECK_CODE(tex->state().dbg(), glTexSubImage2D(
|
||||||
tex->state().id().target(),
|
tex->state().id().target(),
|
||||||
0,
|
0,
|
||||||
math::numeric_cast<GLint>(offset.x),
|
math::numeric_cast<GLint>(region.position.x),
|
||||||
math::numeric_cast<GLint>(offset.y),
|
math::numeric_cast<GLint>(region.position.y),
|
||||||
math::numeric_cast<GLsizei>(size.x),
|
math::numeric_cast<GLsizei>(region.size.x),
|
||||||
math::numeric_cast<GLsizei>(size.y),
|
math::numeric_cast<GLsizei>(region.size.y),
|
||||||
convert_pixel_type_to_external_format(tex->state().decl().type()),
|
convert_pixel_type_to_external_format(tex->state().decl().type()),
|
||||||
convert_pixel_type_to_external_data_type(tex->state().decl().type()),
|
convert_pixel_type_to_external_data_type(tex->state().decl().type()),
|
||||||
data.data()));
|
pixels.data()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void grab_framebuffer_content(
|
||||||
|
debug& debug,
|
||||||
|
const opengl::gl_framebuffer_id& fb,
|
||||||
|
const b2u& region,
|
||||||
|
image& result)
|
||||||
|
{
|
||||||
|
with_gl_bind_framebuffer(debug, fb,
|
||||||
|
[&debug, ®ion, &result]() {
|
||||||
|
GLint format;
|
||||||
|
GLint type;
|
||||||
|
GL_CHECK_CODE(debug, glGetIntegerv(
|
||||||
|
GL_IMPLEMENTATION_COLOR_READ_FORMAT,
|
||||||
|
&format));
|
||||||
|
GL_CHECK_CODE(debug, glGetIntegerv(
|
||||||
|
GL_IMPLEMENTATION_COLOR_READ_TYPE,
|
||||||
|
&type));
|
||||||
|
|
||||||
|
image_data_format img_format;
|
||||||
|
if ( (format == GL_ALPHA || format == GL_LUMINANCE) && type == GL_UNSIGNED_BYTE ) {
|
||||||
|
img_format = image_data_format::g8;
|
||||||
|
} else if ( format == GL_RGB && type == GL_UNSIGNED_BYTE ) {
|
||||||
|
img_format = image_data_format::rgb8;
|
||||||
|
} else if ( format == GL_RGBA && type == GL_UNSIGNED_BYTE ) {
|
||||||
|
img_format = image_data_format::rgba8;
|
||||||
|
} else {
|
||||||
|
E2D_ASSERT_MSG(false, "unsupported pixel format");
|
||||||
|
// OpenGL ES 2 already supports RGBA8 format for glReadPixels
|
||||||
|
format = GL_RGBA;
|
||||||
|
type = GL_UNSIGNED_BYTE;
|
||||||
|
img_format = image_data_format::rgba8;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixel_declaration decl = convert_image_data_format_to_pixel_declaration(img_format);
|
||||||
|
buffer pixels;
|
||||||
|
pixels.resize(((decl.bits_per_pixel() * region.size.x) / 8u) * region.size.y);
|
||||||
|
|
||||||
|
GL_CHECK_CODE(debug, glReadPixels(
|
||||||
|
math::numeric_cast<GLint>(region.position.x),
|
||||||
|
math::numeric_cast<GLint>(region.position.y),
|
||||||
|
math::numeric_cast<GLsizei>(region.size.x),
|
||||||
|
math::numeric_cast<GLsizei>(region.size.y),
|
||||||
|
format,
|
||||||
|
type,
|
||||||
|
pixels.data()));
|
||||||
|
result = image(region.size, img_format, std::move(pixels));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render& render::grab_texture(
|
||||||
|
const texture_ptr& tex,
|
||||||
|
const b2u& region,
|
||||||
|
image& result)
|
||||||
|
{
|
||||||
|
E2D_ASSERT(tex);
|
||||||
|
E2D_ASSERT(tex->decl().is_color() && !tex->decl().is_compressed());
|
||||||
|
E2D_ASSERT(region.position.x + region.size.x <= tex->size().x);
|
||||||
|
E2D_ASSERT(region.position.y + region.size.y <= tex->size().y);
|
||||||
|
|
||||||
|
gl_framebuffer_id id = gl_framebuffer_id::create(state_->dbg(), GL_FRAMEBUFFER);
|
||||||
|
if ( id.empty() ) {
|
||||||
|
throw bad_render_operation();
|
||||||
|
}
|
||||||
|
gl_attach_texture(state_->dbg(), id, tex->state().id(), GL_COLOR_ATTACHMENT0);
|
||||||
|
GLenum fb_status = GL_FRAMEBUFFER_COMPLETE;
|
||||||
|
if ( !gl_check_framebuffer(state_->dbg(), id, &fb_status) ) {
|
||||||
|
throw bad_render_operation();
|
||||||
|
}
|
||||||
|
grab_framebuffer_content(
|
||||||
|
state_->dbg(),
|
||||||
|
id,
|
||||||
|
region,
|
||||||
|
result);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
render& render::grab_render_target(
|
||||||
|
const render_target_ptr& rt,
|
||||||
|
const b2u& region,
|
||||||
|
image& result)
|
||||||
|
{
|
||||||
|
E2D_ASSERT(rt);
|
||||||
|
E2D_ASSERT(region.position.x + region.size.x <= rt->size().x);
|
||||||
|
E2D_ASSERT(region.position.y + region.size.y <= rt->size().y);
|
||||||
|
grab_framebuffer_content(
|
||||||
|
state_->dbg(),
|
||||||
|
rt->state().id(),
|
||||||
|
region,
|
||||||
|
result);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
render& render::grab_screen(
|
||||||
|
const b2u& region,
|
||||||
|
image& result)
|
||||||
|
{
|
||||||
|
E2D_ASSERT(region.position.x + region.size.x <= state_->wnd().real_size().x);
|
||||||
|
E2D_ASSERT(region.position.y + region.size.y <= state_->wnd().real_size().y);
|
||||||
|
grab_framebuffer_content(
|
||||||
|
state_->dbg(),
|
||||||
|
state_->default_fb(),
|
||||||
|
region,
|
||||||
|
result);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
const render::device_caps& render::device_capabilities() const noexcept {
|
const render::device_caps& render::device_capabilities() const noexcept {
|
||||||
E2D_ASSERT(is_in_main_thread());
|
E2D_ASSERT(is_in_main_thread());
|
||||||
return state_->device_capabilities();
|
return state_->device_capabilities();
|
||||||
@@ -1100,6 +1204,8 @@ namespace e2d
|
|||||||
case pixel_declaration::pixel_type::depth24_stencil8:
|
case pixel_declaration::pixel_type::depth24_stencil8:
|
||||||
return GLEW_OES_packed_depth_stencil
|
return GLEW_OES_packed_depth_stencil
|
||||||
|| GLEW_EXT_packed_depth_stencil;
|
|| GLEW_EXT_packed_depth_stencil;
|
||||||
|
case pixel_declaration::pixel_type::g8:
|
||||||
|
case pixel_declaration::pixel_type::ga8:
|
||||||
case pixel_declaration::pixel_type::rgb8:
|
case pixel_declaration::pixel_type::rgb8:
|
||||||
case pixel_declaration::pixel_type::rgba8:
|
case pixel_declaration::pixel_type::rgba8:
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -723,6 +723,8 @@ namespace e2d::opengl
|
|||||||
DEFINE_CASE(depth24, GL_DEPTH_COMPONENT);
|
DEFINE_CASE(depth24, GL_DEPTH_COMPONENT);
|
||||||
DEFINE_CASE(depth32, GL_DEPTH_COMPONENT);
|
DEFINE_CASE(depth32, GL_DEPTH_COMPONENT);
|
||||||
DEFINE_CASE(depth24_stencil8, GL_DEPTH_STENCIL);
|
DEFINE_CASE(depth24_stencil8, GL_DEPTH_STENCIL);
|
||||||
|
DEFINE_CASE(g8, GL_ALPHA);
|
||||||
|
DEFINE_CASE(ga8, GL_LUMINANCE_ALPHA);
|
||||||
DEFINE_CASE(rgb8, GL_RGB);
|
DEFINE_CASE(rgb8, GL_RGB);
|
||||||
DEFINE_CASE(rgba8, GL_RGBA);
|
DEFINE_CASE(rgba8, GL_RGBA);
|
||||||
default:
|
default:
|
||||||
@@ -739,6 +741,8 @@ namespace e2d::opengl
|
|||||||
DEFINE_CASE(depth24, GL_UNSIGNED_INT);
|
DEFINE_CASE(depth24, GL_UNSIGNED_INT);
|
||||||
DEFINE_CASE(depth32, GL_UNSIGNED_INT);
|
DEFINE_CASE(depth32, GL_UNSIGNED_INT);
|
||||||
DEFINE_CASE(depth24_stencil8, GL_UNSIGNED_INT_24_8);
|
DEFINE_CASE(depth24_stencil8, GL_UNSIGNED_INT_24_8);
|
||||||
|
DEFINE_CASE(g8, GL_UNSIGNED_BYTE);
|
||||||
|
DEFINE_CASE(ga8, GL_UNSIGNED_BYTE);
|
||||||
DEFINE_CASE(rgb8, GL_UNSIGNED_BYTE);
|
DEFINE_CASE(rgb8, GL_UNSIGNED_BYTE);
|
||||||
DEFINE_CASE(rgba8, GL_UNSIGNED_BYTE);
|
DEFINE_CASE(rgba8, GL_UNSIGNED_BYTE);
|
||||||
default:
|
default:
|
||||||
@@ -756,6 +760,8 @@ namespace e2d::opengl
|
|||||||
DEFINE_CASE(depth32, GL_DEPTH_COMPONENT32);
|
DEFINE_CASE(depth32, GL_DEPTH_COMPONENT32);
|
||||||
DEFINE_CASE(depth24_stencil8, GL_DEPTH24_STENCIL8);
|
DEFINE_CASE(depth24_stencil8, GL_DEPTH24_STENCIL8);
|
||||||
|
|
||||||
|
DEFINE_CASE(g8, GL_ALPHA);
|
||||||
|
DEFINE_CASE(ga8, GL_LUMINANCE_ALPHA);
|
||||||
DEFINE_CASE(rgb8, GL_RGB);
|
DEFINE_CASE(rgb8, GL_RGB);
|
||||||
DEFINE_CASE(rgba8, GL_RGBA);
|
DEFINE_CASE(rgba8, GL_RGBA);
|
||||||
|
|
||||||
@@ -786,8 +792,8 @@ namespace e2d::opengl
|
|||||||
pixel_declaration convert_image_data_format_to_pixel_declaration(image_data_format f) noexcept {
|
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_type::y
|
#define DEFINE_CASE(x,y) case image_data_format::x: return pixel_declaration::pixel_type::y
|
||||||
switch ( f ) {
|
switch ( f ) {
|
||||||
DEFINE_CASE(g8, rgb8);
|
DEFINE_CASE(g8, g8);
|
||||||
DEFINE_CASE(ga8, rgba8);
|
DEFINE_CASE(ga8, ga8);
|
||||||
DEFINE_CASE(rgb8, rgb8);
|
DEFINE_CASE(rgb8, rgb8);
|
||||||
DEFINE_CASE(rgba8, rgba8);
|
DEFINE_CASE(rgba8, rgba8);
|
||||||
|
|
||||||
|
|||||||
@@ -217,9 +217,7 @@ namespace e2d
|
|||||||
GL_CHECK_CODE(debug_, glPixelStorei(GL_PACK_ALIGNMENT, 1));
|
GL_CHECK_CODE(debug_, glPixelStorei(GL_PACK_ALIGNMENT, 1));
|
||||||
GL_CHECK_CODE(debug_, glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
GL_CHECK_CODE(debug_, glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
||||||
|
|
||||||
set_states(state_block_);
|
reset_states();
|
||||||
set_shader_program(shader_program_);
|
|
||||||
set_render_target(render_target_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug& render::internal_state::dbg() const noexcept {
|
debug& render::internal_state::dbg() const noexcept {
|
||||||
@@ -238,6 +236,19 @@ namespace e2d
|
|||||||
return render_target_;
|
return render_target_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const opengl::gl_framebuffer_id& render::internal_state::default_fb() const noexcept {
|
||||||
|
return default_fb_;
|
||||||
|
}
|
||||||
|
|
||||||
|
render::internal_state& render::internal_state::reset_states() noexcept {
|
||||||
|
set_depth_state_(state_block_.depth());
|
||||||
|
set_stencil_state_(state_block_.stencil());
|
||||||
|
set_culling_state_(state_block_.culling());
|
||||||
|
set_blending_state_(state_block_.blending());
|
||||||
|
set_capabilities_state_(state_block_.capabilities());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
render::internal_state& render::internal_state::set_states(const state_block& sb) noexcept {
|
render::internal_state& render::internal_state::set_states(const state_block& sb) noexcept {
|
||||||
set_depth_state(sb.depth());
|
set_depth_state(sb.depth());
|
||||||
set_stencil_state(sb.stencil());
|
set_stencil_state(sb.stencil());
|
||||||
@@ -247,11 +258,7 @@ namespace e2d
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
render::internal_state& render::internal_state::set_depth_state(const depth_state& ds) noexcept {
|
void render::internal_state::set_depth_state_(const depth_state& ds) noexcept {
|
||||||
if ( ds == state_block_.depth() ) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
GL_CHECK_CODE(debug_, glDepthRange(
|
GL_CHECK_CODE(debug_, glDepthRange(
|
||||||
math::numeric_cast<GLclampd>(math::saturate(ds.range_near())),
|
math::numeric_cast<GLclampd>(math::saturate(ds.range_near())),
|
||||||
math::numeric_cast<GLclampd>(math::saturate(ds.range_far()))));
|
math::numeric_cast<GLclampd>(math::saturate(ds.range_far()))));
|
||||||
@@ -259,16 +266,19 @@ namespace e2d
|
|||||||
ds.write() ? GL_TRUE : GL_FALSE));
|
ds.write() ? GL_TRUE : GL_FALSE));
|
||||||
GL_CHECK_CODE(debug_, glDepthFunc(
|
GL_CHECK_CODE(debug_, glDepthFunc(
|
||||||
convert_compare_func(ds.func())));
|
convert_compare_func(ds.func())));
|
||||||
|
}
|
||||||
|
|
||||||
|
render::internal_state& render::internal_state::set_depth_state(const depth_state& ds) noexcept {
|
||||||
|
if ( ds == state_block_.depth() ) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_depth_state_(ds);
|
||||||
state_block_.depth(ds);
|
state_block_.depth(ds);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
render::internal_state& render::internal_state::set_stencil_state(const stencil_state& ss) noexcept {
|
void render::internal_state::set_stencil_state_(const stencil_state& ss) noexcept {
|
||||||
if ( ss == state_block_.stencil() ) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
GL_CHECK_CODE(debug_, glStencilMask(
|
GL_CHECK_CODE(debug_, glStencilMask(
|
||||||
math::numeric_cast<GLuint>(ss.write())));
|
math::numeric_cast<GLuint>(ss.write())));
|
||||||
GL_CHECK_CODE(debug_, glStencilFunc(
|
GL_CHECK_CODE(debug_, glStencilFunc(
|
||||||
@@ -279,30 +289,36 @@ namespace e2d
|
|||||||
convert_stencil_op(ss.sfail()),
|
convert_stencil_op(ss.sfail()),
|
||||||
convert_stencil_op(ss.zfail()),
|
convert_stencil_op(ss.zfail()),
|
||||||
convert_stencil_op(ss.pass())));
|
convert_stencil_op(ss.pass())));
|
||||||
|
}
|
||||||
|
|
||||||
|
render::internal_state& render::internal_state::set_stencil_state(const stencil_state& ss) noexcept {
|
||||||
|
if ( ss == state_block_.stencil() ) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_stencil_state_(ss);
|
||||||
state_block_.stencil(ss);
|
state_block_.stencil(ss);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void render::internal_state::set_culling_state_(const culling_state& cs) noexcept {
|
||||||
|
GL_CHECK_CODE(debug_, glFrontFace(
|
||||||
|
convert_culling_mode(cs.mode())));
|
||||||
|
GL_CHECK_CODE(debug_, glCullFace(
|
||||||
|
convert_culling_face(cs.face())));
|
||||||
|
}
|
||||||
|
|
||||||
render::internal_state& render::internal_state::set_culling_state(const culling_state& cs) noexcept {
|
render::internal_state& render::internal_state::set_culling_state(const culling_state& cs) noexcept {
|
||||||
if ( cs == state_block_.culling() ) {
|
if ( cs == state_block_.culling() ) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
GL_CHECK_CODE(debug_, glFrontFace(
|
set_culling_state_(cs);
|
||||||
convert_culling_mode(cs.mode())));
|
|
||||||
GL_CHECK_CODE(debug_, glCullFace(
|
|
||||||
convert_culling_face(cs.face())));
|
|
||||||
|
|
||||||
state_block_.culling(cs);
|
state_block_.culling(cs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
render::internal_state& render::internal_state::set_blending_state(const blending_state& bs) noexcept {
|
void render::internal_state::set_blending_state_(const blending_state& bs) noexcept {
|
||||||
if ( bs == state_block_.blending() ) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
GL_CHECK_CODE(debug_, glBlendColor(
|
GL_CHECK_CODE(debug_, glBlendColor(
|
||||||
math::numeric_cast<GLclampf>(math::saturate(bs.constant_color().r)),
|
math::numeric_cast<GLclampf>(math::saturate(bs.constant_color().r)),
|
||||||
math::numeric_cast<GLclampf>(math::saturate(bs.constant_color().g)),
|
math::numeric_cast<GLclampf>(math::saturate(bs.constant_color().g)),
|
||||||
@@ -321,12 +337,19 @@ namespace e2d
|
|||||||
(utils::enum_to_underlying(bs.color_mask()) & utils::enum_to_underlying(blending_color_mask::g)) != 0,
|
(utils::enum_to_underlying(bs.color_mask()) & utils::enum_to_underlying(blending_color_mask::g)) != 0,
|
||||||
(utils::enum_to_underlying(bs.color_mask()) & utils::enum_to_underlying(blending_color_mask::b)) != 0,
|
(utils::enum_to_underlying(bs.color_mask()) & utils::enum_to_underlying(blending_color_mask::b)) != 0,
|
||||||
(utils::enum_to_underlying(bs.color_mask()) & utils::enum_to_underlying(blending_color_mask::a)) != 0));
|
(utils::enum_to_underlying(bs.color_mask()) & utils::enum_to_underlying(blending_color_mask::a)) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
render::internal_state& render::internal_state::set_blending_state(const blending_state& bs) noexcept {
|
||||||
|
if ( bs == state_block_.blending() ) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_blending_state_(bs);
|
||||||
state_block_.blending(bs);
|
state_block_.blending(bs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
render::internal_state& render::internal_state::set_capabilities_state(const capabilities_state& cs) noexcept {
|
void render::internal_state::set_capabilities_state_(const capabilities_state& cs) noexcept {
|
||||||
const auto enable_or_disable = [](GLenum cap, bool enable) noexcept {
|
const auto enable_or_disable = [](GLenum cap, bool enable) noexcept {
|
||||||
if ( enable ) {
|
if ( enable ) {
|
||||||
glEnable(cap);
|
glEnable(cap);
|
||||||
@@ -335,15 +358,18 @@ namespace e2d
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if ( cs == state_block_.capabilities() ) {
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
GL_CHECK_CODE(debug_, enable_or_disable(GL_CULL_FACE, cs.culling()));
|
GL_CHECK_CODE(debug_, enable_or_disable(GL_CULL_FACE, cs.culling()));
|
||||||
GL_CHECK_CODE(debug_, enable_or_disable(GL_BLEND, cs.blending()));
|
GL_CHECK_CODE(debug_, enable_or_disable(GL_BLEND, cs.blending()));
|
||||||
GL_CHECK_CODE(debug_, enable_or_disable(GL_DEPTH_TEST, cs.depth_test()));
|
GL_CHECK_CODE(debug_, enable_or_disable(GL_DEPTH_TEST, cs.depth_test()));
|
||||||
GL_CHECK_CODE(debug_, enable_or_disable(GL_STENCIL_TEST, cs.stencil_test()));
|
GL_CHECK_CODE(debug_, enable_or_disable(GL_STENCIL_TEST, cs.stencil_test()));
|
||||||
|
}
|
||||||
|
|
||||||
|
render::internal_state& render::internal_state::set_capabilities_state(const capabilities_state& cs) noexcept {
|
||||||
|
if ( cs == state_block_.capabilities() ) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_capabilities_state_(cs);
|
||||||
state_block_.capabilities(cs);
|
state_block_.capabilities(cs);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -362,6 +388,14 @@ namespace e2d
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render::internal_state& render::internal_state::reset_shader_program() noexcept {
|
||||||
|
const gl_program_id& sp_id = shader_program_
|
||||||
|
? shader_program_->state().id()
|
||||||
|
: default_sp_;
|
||||||
|
GL_CHECK_CODE(debug_, glUseProgram(*sp_id));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
render::internal_state& render::internal_state::set_render_target(const render_target_ptr& rt) noexcept {
|
render::internal_state& render::internal_state::set_render_target(const render_target_ptr& rt) noexcept {
|
||||||
if ( rt == render_target_ ) {
|
if ( rt == render_target_ ) {
|
||||||
return *this;
|
return *this;
|
||||||
@@ -375,6 +409,14 @@ namespace e2d
|
|||||||
render_target_ = rt;
|
render_target_ = rt;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render::internal_state& render::internal_state::reset_render_target() noexcept {
|
||||||
|
const gl_framebuffer_id& rt_id = render_target_
|
||||||
|
? render_target_->state().id()
|
||||||
|
: default_fb_;
|
||||||
|
GL_CHECK_CODE(debug_, glBindFramebuffer(rt_id.target(), *rt_id));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -175,7 +175,9 @@ namespace e2d
|
|||||||
window& wnd() const noexcept;
|
window& wnd() const noexcept;
|
||||||
const device_caps& device_capabilities() const noexcept;
|
const device_caps& device_capabilities() const noexcept;
|
||||||
const render_target_ptr& render_target() const noexcept;
|
const render_target_ptr& render_target() const noexcept;
|
||||||
|
const opengl::gl_framebuffer_id& default_fb() const noexcept;
|
||||||
public:
|
public:
|
||||||
|
internal_state& reset_states() noexcept;
|
||||||
internal_state& set_states(const state_block& sb) noexcept;
|
internal_state& set_states(const state_block& sb) noexcept;
|
||||||
internal_state& set_depth_state(const depth_state& ds) noexcept;
|
internal_state& set_depth_state(const depth_state& ds) noexcept;
|
||||||
internal_state& set_stencil_state(const stencil_state& ss) noexcept;
|
internal_state& set_stencil_state(const stencil_state& ss) noexcept;
|
||||||
@@ -183,8 +185,17 @@ namespace e2d
|
|||||||
internal_state& set_blending_state(const blending_state& bs) noexcept;
|
internal_state& set_blending_state(const blending_state& bs) noexcept;
|
||||||
internal_state& set_capabilities_state(const capabilities_state& cs) noexcept;
|
internal_state& set_capabilities_state(const capabilities_state& cs) noexcept;
|
||||||
|
|
||||||
|
internal_state& reset_shader_program() noexcept;
|
||||||
internal_state& set_shader_program(const shader_ptr& sp) noexcept;
|
internal_state& set_shader_program(const shader_ptr& sp) noexcept;
|
||||||
|
|
||||||
|
internal_state& reset_render_target() noexcept;
|
||||||
internal_state& set_render_target(const render_target_ptr& rt) noexcept;
|
internal_state& set_render_target(const render_target_ptr& rt) noexcept;
|
||||||
|
private:
|
||||||
|
void set_depth_state_(const depth_state& ds) noexcept;
|
||||||
|
void set_stencil_state_(const stencil_state& ss) noexcept;
|
||||||
|
void set_culling_state_(const culling_state& cs) noexcept;
|
||||||
|
void set_blending_state_(const blending_state& bs) noexcept;
|
||||||
|
void set_capabilities_state_(const capabilities_state& cs) noexcept;
|
||||||
private:
|
private:
|
||||||
debug& debug_;
|
debug& debug_;
|
||||||
window& window_;
|
window& window_;
|
||||||
|
|||||||
@@ -107,6 +107,22 @@ namespace e2d
|
|||||||
std::size_t buffer::size() const noexcept {
|
std::size_t buffer::size() const noexcept {
|
||||||
return size_;
|
return size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const u8* buffer::begin() const noexcept {
|
||||||
|
return data_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8* buffer::end() const noexcept {
|
||||||
|
return data_.get() + size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* buffer::begin() noexcept {
|
||||||
|
return data_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* buffer::end() noexcept {
|
||||||
|
return data_.get() + size_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace e2d
|
namespace e2d
|
||||||
|
|||||||
@@ -7,6 +7,23 @@
|
|||||||
#include "_core.hpp"
|
#include "_core.hpp"
|
||||||
using namespace e2d;
|
using namespace e2d;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class safe_engine_initializer final : private noncopyable {
|
||||||
|
public:
|
||||||
|
safe_engine_initializer() {
|
||||||
|
modules::initialize<engine>(0, nullptr,
|
||||||
|
engine::parameters("renderer_untests", "enduro2d")
|
||||||
|
.without_audio(true)
|
||||||
|
.without_network(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
~safe_engine_initializer() noexcept {
|
||||||
|
modules::shutdown<engine>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("render"){
|
TEST_CASE("render"){
|
||||||
SECTION("sampler_state"){
|
SECTION("sampler_state"){
|
||||||
{
|
{
|
||||||
@@ -169,4 +186,125 @@ TEST_CASE("render"){
|
|||||||
REQUIRE(vd4 != vd);
|
REQUIRE(vd4 != vd);
|
||||||
REQUIRE(vd4 == vd3);
|
REQUIRE(vd4 == vd3);
|
||||||
}
|
}
|
||||||
|
SECTION("update_texture"){
|
||||||
|
safe_engine_initializer initializer;
|
||||||
|
render& r = the<render>();
|
||||||
|
{
|
||||||
|
texture_ptr tex = r.create_texture(v2u(128,128), pixel_declaration::pixel_type::rgba8);
|
||||||
|
REQUIRE(tex != nullptr);
|
||||||
|
|
||||||
|
buffer src;
|
||||||
|
src.resize(((tex->size().x * tex->decl().bits_per_pixel()) / 8u) * tex->size().y);
|
||||||
|
for (auto& c : src) {
|
||||||
|
c = rand() % 255;
|
||||||
|
}
|
||||||
|
r.update_texture(tex, src, b2u(0, 0, 128, 128));
|
||||||
|
|
||||||
|
image dst;
|
||||||
|
r.grab_texture(tex, b2u(0, 0, 128, 128), dst);
|
||||||
|
REQUIRE(dst.format() == image_data_format::rgba8);
|
||||||
|
REQUIRE(src == dst.data());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
texture_ptr tex = r.create_texture(v2u(128,128), pixel_declaration::pixel_type::g8);
|
||||||
|
REQUIRE(tex != nullptr);
|
||||||
|
|
||||||
|
buffer src;
|
||||||
|
src.resize(((tex->size().x * tex->decl().bits_per_pixel()) / 8u) * tex->size().y);
|
||||||
|
for (auto& c : src) {
|
||||||
|
c = rand() % 255;
|
||||||
|
}
|
||||||
|
r.update_texture(tex, src, b2u(0, 0, 128, 128));
|
||||||
|
|
||||||
|
image dst;
|
||||||
|
r.grab_texture(tex, b2u(0, 0, 128, 128), dst);
|
||||||
|
if ( dst.format() == image_data_format::g8 ) {
|
||||||
|
REQUIRE(src == dst.data());
|
||||||
|
} else {
|
||||||
|
// OpenGL ES 2 may not support Alpha8 format
|
||||||
|
REQUIRE(dst.format() == image_data_format::rgba8);
|
||||||
|
REQUIRE(dst.data().size() == src.size()*4);
|
||||||
|
bool equal = true;
|
||||||
|
for (size_t i = 0; i < src.size(); ++i) {
|
||||||
|
equal &= (src.data()[i] == dst.data().data()[i*4+3]);
|
||||||
|
}
|
||||||
|
REQUIRE(equal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
texture_ptr tex = r.create_texture(v2u(128,128), pixel_declaration::pixel_type::rgb8);
|
||||||
|
REQUIRE(tex != nullptr);
|
||||||
|
|
||||||
|
buffer src;
|
||||||
|
src.resize(((tex->size().x * tex->decl().bits_per_pixel()) / 8u) * tex->size().y);
|
||||||
|
for (auto& c : src) {
|
||||||
|
c = rand() % 255;
|
||||||
|
}
|
||||||
|
r.update_texture(tex, src, b2u(0, 0, 128, 128));
|
||||||
|
|
||||||
|
image dst;
|
||||||
|
r.grab_texture(tex, b2u(0, 0, 128, 128), dst);
|
||||||
|
if ( dst.format() == image_data_format::rgb8 ) {
|
||||||
|
REQUIRE(src == dst.data());
|
||||||
|
} else {
|
||||||
|
// OpenGL ES 2 may not support Alpha8 format
|
||||||
|
REQUIRE(dst.format() == image_data_format::rgba8);
|
||||||
|
REQUIRE(dst.data().size() == src.size()*4/3);
|
||||||
|
bool equal = true;
|
||||||
|
for (size_t i = 0, j = 0; i < src.size(); i += 3, j += 4) {
|
||||||
|
equal &= (src.data()[i+0] == dst.data().data()[j+0]);
|
||||||
|
equal &= (src.data()[i+1] == dst.data().data()[j+1]);
|
||||||
|
equal &= (src.data()[i+2] == dst.data().data()[j+2]);
|
||||||
|
}
|
||||||
|
REQUIRE(equal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
texture_ptr tex = r.create_texture(v2u(57,31), pixel_declaration::pixel_type::rgba8);
|
||||||
|
REQUIRE(tex != nullptr);
|
||||||
|
|
||||||
|
buffer src;
|
||||||
|
src.resize(((tex->size().x * tex->decl().bits_per_pixel()) / 8u) * tex->size().y);
|
||||||
|
for (auto& c : src) {
|
||||||
|
c = rand() % 255;
|
||||||
|
}
|
||||||
|
r.update_texture(tex, src, b2u(0, 0, 57, 31));
|
||||||
|
|
||||||
|
image dst;
|
||||||
|
r.grab_texture(tex, b2u(0, 0, 57, 31), dst);
|
||||||
|
REQUIRE(dst.format() == image_data_format::rgba8);
|
||||||
|
REQUIRE(src == dst.data());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
texture_ptr tex = r.create_texture(v2u(128,128), pixel_declaration::pixel_type::rgba8);
|
||||||
|
REQUIRE(tex != nullptr);
|
||||||
|
|
||||||
|
buffer src;
|
||||||
|
src.resize(((31 * tex->decl().bits_per_pixel()) / 8u) * 44);
|
||||||
|
for (auto& c : src) {
|
||||||
|
c = rand() % 255;
|
||||||
|
}
|
||||||
|
r.update_texture(tex, src, b2u(22, 17, 31, 44));
|
||||||
|
|
||||||
|
image dst;
|
||||||
|
r.grab_texture(tex, b2u(0, 0, 128, 128), dst);
|
||||||
|
REQUIRE(dst.format() == image_data_format::rgba8);
|
||||||
|
|
||||||
|
const size_t data_size = ((tex->size().x * tex->decl().bits_per_pixel()) / 8u) * tex->size().y;
|
||||||
|
REQUIRE(data_size == dst.data().size());
|
||||||
|
|
||||||
|
bool equal = true;
|
||||||
|
const size_t bpp = tex->decl().bits_per_pixel() / 8;
|
||||||
|
for (u32 y = 0; y < 44; ++y) {
|
||||||
|
const u8* dst_row = dst.data().data() + ((y + 17) * 128 + 22) * bpp;
|
||||||
|
const u8* src_row = src.data() + (y * 31 * bpp);
|
||||||
|
for (u32 x = 0; x < 31 * bpp; ++x) {
|
||||||
|
auto s = src_row[x];
|
||||||
|
auto d = dst_row[x];
|
||||||
|
equal &= (s == d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
REQUIRE(equal);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user