mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-14 16:09:06 +07:00
Merge pull request #84 from enduro2d/feature/update_buffer_and_image
buffer update moved to render class
This commit is contained in:
@@ -49,6 +49,8 @@ namespace e2d
|
||||
depth32,
|
||||
depth24_stencil8,
|
||||
|
||||
g8,
|
||||
ga8,
|
||||
rgb8,
|
||||
rgba8,
|
||||
|
||||
@@ -82,6 +84,7 @@ namespace e2d
|
||||
bool is_stencil() const noexcept;
|
||||
bool is_compressed() const noexcept;
|
||||
std::size_t bits_per_pixel() const noexcept;
|
||||
v2u compressed_block_size() const noexcept;
|
||||
private:
|
||||
pixel_type type_ = pixel_type::rgba8;
|
||||
};
|
||||
@@ -264,7 +267,6 @@ namespace e2d
|
||||
explicit index_buffer(internal_state_uptr);
|
||||
~index_buffer() noexcept;
|
||||
public:
|
||||
void update(buffer_view indices, std::size_t offset) noexcept;
|
||||
std::size_t buffer_size() const noexcept;
|
||||
std::size_t index_count() const noexcept;
|
||||
const index_declaration& decl() const noexcept;
|
||||
@@ -291,7 +293,6 @@ namespace e2d
|
||||
explicit vertex_buffer(internal_state_uptr);
|
||||
~vertex_buffer() noexcept;
|
||||
public:
|
||||
void update(buffer_view vertices, std::size_t offset) noexcept;
|
||||
std::size_t buffer_size() const noexcept;
|
||||
std::size_t vertex_count() const noexcept;
|
||||
const vertex_declaration& decl() const noexcept;
|
||||
@@ -940,6 +941,26 @@ namespace e2d
|
||||
render& execute(const target_command& command);
|
||||
render& execute(const viewport_command& command);
|
||||
|
||||
render& update_buffer(
|
||||
const index_buffer_ptr& ibuffer,
|
||||
buffer_view indices,
|
||||
std::size_t offset);
|
||||
|
||||
render& update_buffer(
|
||||
const vertex_buffer_ptr& vbuffer,
|
||||
buffer_view vertices,
|
||||
std::size_t offset);
|
||||
|
||||
render& update_texture(
|
||||
const texture_ptr& tex,
|
||||
const image& img,
|
||||
v2u offset);
|
||||
|
||||
render& update_texture(
|
||||
const texture_ptr& tex,
|
||||
buffer_view pixels,
|
||||
const b2u& region);
|
||||
|
||||
const device_caps& device_capabilities() const noexcept;
|
||||
bool is_pixel_supported(const pixel_declaration& decl) const noexcept;
|
||||
bool is_index_supported(const index_declaration& decl) const noexcept;
|
||||
|
||||
@@ -11,6 +11,18 @@
|
||||
namespace e2d
|
||||
{
|
||||
class buffer final {
|
||||
public:
|
||||
using value_type = u8;
|
||||
|
||||
using pointer = u8*;
|
||||
using const_pointer = const u8*;
|
||||
using reference = u8&;
|
||||
using const_reference = const u8&;
|
||||
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
public:
|
||||
buffer() = default;
|
||||
|
||||
@@ -23,6 +35,22 @@ namespace e2d
|
||||
explicit buffer(std::size_t size);
|
||||
buffer(const void* src, std::size_t size);
|
||||
|
||||
iterator begin() noexcept;
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator cbegin() const noexcept;
|
||||
|
||||
iterator end() noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
const_iterator cend() const noexcept;
|
||||
|
||||
reverse_iterator rbegin() noexcept;
|
||||
const_reverse_iterator rbegin() const noexcept;
|
||||
const_reverse_iterator crbegin() const noexcept;
|
||||
|
||||
reverse_iterator rend() noexcept;
|
||||
const_reverse_iterator rend() const noexcept;
|
||||
const_reverse_iterator crend() const noexcept;
|
||||
|
||||
buffer& fill(u8 ch) noexcept;
|
||||
buffer& resize(std::size_t nsize);
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@ namespace e2d
|
||||
template < typename T, std::size_t N >
|
||||
buffer_view(const std::array<T,N>& buffer) noexcept;
|
||||
|
||||
template < typename T, std::size_t N >
|
||||
buffer_view(const T (&buffer)[N]) noexcept;
|
||||
|
||||
const void* data() const noexcept;
|
||||
std::size_t size() const noexcept;
|
||||
bool empty() const noexcept;
|
||||
@@ -56,4 +59,9 @@ namespace e2d
|
||||
buffer_view::buffer_view(const std::array<T,N>& buffer) noexcept
|
||||
: data_(buffer.data())
|
||||
, size_(buffer.size() * sizeof(T)) {}
|
||||
|
||||
template < typename T, std::size_t N >
|
||||
buffer_view::buffer_view(const T (&buffer)[N]) noexcept
|
||||
: data_(&buffer[0])
|
||||
, size_(std::size(buffer) * sizeof(T)) {}
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ namespace e2d
|
||||
|
||||
void update_index_buffer(buffer_view indices) {
|
||||
if ( index_buffer_ && index_buffer_->buffer_size() >= indices.size() ) {
|
||||
index_buffer_->update(indices, 0);
|
||||
render_.update_buffer(index_buffer_, indices, 0u);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ namespace e2d
|
||||
|
||||
void update_vertex_buffer(buffer_view vertices) {
|
||||
if ( vertex_buffer_ && vertex_buffer_->buffer_size() >= vertices.size() ) {
|
||||
vertex_buffer_->update(vertices, 0);
|
||||
render_.update_buffer(vertex_buffer_, vertices, 0u);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,32 +18,35 @@ namespace
|
||||
bool stencil;
|
||||
pixel_declaration::pixel_type type;
|
||||
bool compressed;
|
||||
v2u block_size;
|
||||
};
|
||||
|
||||
const pixel_type_description pixel_type_descriptions[] = {
|
||||
{"depth16", 16, false, true, false, pixel_declaration::pixel_type::depth16, false},
|
||||
{"depth24", 24, false, true, false, pixel_declaration::pixel_type::depth24, false},
|
||||
{"depth32", 32, false, true, false, pixel_declaration::pixel_type::depth32, false},
|
||||
{"depth24_stencil8", 32, false, true, true, pixel_declaration::pixel_type::depth24_stencil8, false},
|
||||
{"depth16", 16, false, true, false, pixel_declaration::pixel_type::depth16, false, v2u(1)},
|
||||
{"depth24", 24, false, true, false, pixel_declaration::pixel_type::depth24, 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)},
|
||||
|
||||
{"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)},
|
||||
{"rgba8", 32, true, false, false, pixel_declaration::pixel_type::rgba8, false, v2u(1)},
|
||||
|
||||
{"rgb8", 24, true, false, false, pixel_declaration::pixel_type::rgb8, false},
|
||||
{"rgba8", 32, true, false, false, pixel_declaration::pixel_type::rgba8, false},
|
||||
{"rgb_dxt1", 4, true, false, false, pixel_declaration::pixel_type::rgb_dxt1, true, v2u(4,4)},
|
||||
{"rgba_dxt1", 4, true, false, false, pixel_declaration::pixel_type::rgba_dxt1, true, v2u(4,4)},
|
||||
{"rgba_dxt3", 8, true, false, false, pixel_declaration::pixel_type::rgba_dxt3, true, v2u(4,4)},
|
||||
{"rgba_dxt5", 8, true, false, false, pixel_declaration::pixel_type::rgba_dxt5, true, v2u(4,4)},
|
||||
|
||||
{"rgb_dxt1", 4, true, false, false, pixel_declaration::pixel_type::rgb_dxt1, true},
|
||||
{"rgba_dxt1", 4, true, false, false, pixel_declaration::pixel_type::rgba_dxt1, true},
|
||||
{"rgba_dxt3", 8, true, false, false, pixel_declaration::pixel_type::rgba_dxt3, true},
|
||||
{"rgba_dxt5", 8, true, false, false, pixel_declaration::pixel_type::rgba_dxt5, true},
|
||||
{"rgb_pvrtc2", 2, true, false, false, pixel_declaration::pixel_type::rgb_pvrtc2, true, v2u(8,4)},
|
||||
{"rgb_pvrtc4", 4, true, false, false, pixel_declaration::pixel_type::rgb_pvrtc4, true, v2u(4,4)},
|
||||
{"rgba_pvrtc2", 2, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc2, true, v2u(8,4)},
|
||||
{"rgba_pvrtc4", 4, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc4, true, v2u(4,4)},
|
||||
|
||||
{"rgb_pvrtc2", 2, true, false, false, pixel_declaration::pixel_type::rgb_pvrtc2, true},
|
||||
{"rgb_pvrtc4", 4, true, false, false, pixel_declaration::pixel_type::rgb_pvrtc4, true},
|
||||
{"rgba_pvrtc2", 2, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc2, true},
|
||||
{"rgba_pvrtc4", 4, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc4, true},
|
||||
{"rgba_pvrtc2", 2, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc2, true, v2u(8,4)},
|
||||
{"rgba_pvrtc4", 4, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc4, true, v2u(4,4)},
|
||||
|
||||
{"rgba_pvrtc2", 2, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc2, true},
|
||||
{"rgba_pvrtc4", 4, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc4, true},
|
||||
|
||||
{"rgba_pvrtc2_v2", 2, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc2_v2, true},
|
||||
{"rgba_pvrtc4_v2", 4, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc4_v2, true}
|
||||
{"rgba_pvrtc2_v2", 2, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc2_v2, true, v2u(8,4)},
|
||||
{"rgba_pvrtc4_v2", 4, true, false, false, pixel_declaration::pixel_type::rgba_pvrtc4_v2, true, v2u(4,4)}
|
||||
};
|
||||
|
||||
const pixel_type_description& get_pixel_type_description(pixel_declaration::pixel_type type) noexcept {
|
||||
@@ -160,6 +163,10 @@ namespace e2d
|
||||
std::size_t pixel_declaration::bits_per_pixel() const noexcept {
|
||||
return get_pixel_type_description(type_).bits_per_pixel;
|
||||
}
|
||||
|
||||
v2u pixel_declaration::compressed_block_size() const noexcept {
|
||||
return get_pixel_type_description(type_).block_size;
|
||||
}
|
||||
|
||||
bool operator==(const pixel_declaration& l, const pixel_declaration& r) noexcept {
|
||||
return l.type() == r.type();
|
||||
|
||||
@@ -121,10 +121,6 @@ namespace e2d
|
||||
: state_(std::move(state)) {}
|
||||
index_buffer::~index_buffer() noexcept = default;
|
||||
|
||||
void index_buffer::update(buffer_view indices, std::size_t offset) noexcept {
|
||||
E2D_UNUSED(indices, offset);
|
||||
}
|
||||
|
||||
std::size_t index_buffer::buffer_size() const noexcept {
|
||||
return 0u;
|
||||
}
|
||||
@@ -141,10 +137,6 @@ namespace e2d
|
||||
: state_(std::move(state)) {}
|
||||
vertex_buffer::~vertex_buffer() noexcept = default;
|
||||
|
||||
void vertex_buffer::update(buffer_view vertices, std::size_t offset) noexcept {
|
||||
E2D_UNUSED(vertices, offset);
|
||||
}
|
||||
|
||||
std::size_t vertex_buffer::buffer_size() const noexcept {
|
||||
return 0u;
|
||||
}
|
||||
@@ -258,6 +250,42 @@ namespace e2d
|
||||
E2D_UNUSED(command);
|
||||
return *this;
|
||||
}
|
||||
|
||||
render& render::update_buffer(
|
||||
const index_buffer_ptr& ibuffer,
|
||||
buffer_view indices,
|
||||
std::size_t offset)
|
||||
{
|
||||
E2D_UNUSED(ibuffer, indices, offset);
|
||||
return *this;
|
||||
}
|
||||
|
||||
render& render::update_buffer(
|
||||
const vertex_buffer_ptr& vbuffer,
|
||||
buffer_view vertices,
|
||||
std::size_t offset)
|
||||
{
|
||||
E2D_UNUSED(vbuffer, vertices, offset);
|
||||
return *this;
|
||||
}
|
||||
|
||||
render& render::update_texture(
|
||||
const texture_ptr& tex,
|
||||
const image& img,
|
||||
v2u offset)
|
||||
{
|
||||
E2D_UNUSED(tex, img, offset);
|
||||
return *this;
|
||||
}
|
||||
|
||||
render& render::update_texture(
|
||||
const texture_ptr& tex,
|
||||
buffer_view pixels,
|
||||
const b2u& region)
|
||||
{
|
||||
E2D_UNUSED(tex, pixels, region);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const render::device_caps& render::device_capabilities() const noexcept {
|
||||
static device_caps caps;
|
||||
|
||||
@@ -355,20 +355,6 @@ namespace e2d
|
||||
}
|
||||
index_buffer::~index_buffer() noexcept = default;
|
||||
|
||||
void index_buffer::update(buffer_view indices, std::size_t offset) noexcept {
|
||||
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().bytes_per_index() == 0);
|
||||
opengl::with_gl_bind_buffer(state_->dbg(), state_->id(),
|
||||
[this, &indices, &buffer_offset]() noexcept {
|
||||
GL_CHECK_CODE(state_->dbg(), glBufferSubData(
|
||||
state_->id().target(),
|
||||
math::numeric_cast<GLintptr>(buffer_offset),
|
||||
math::numeric_cast<GLsizeiptr>(indices.size()),
|
||||
indices.data()));
|
||||
});
|
||||
}
|
||||
|
||||
std::size_t index_buffer::buffer_size() const noexcept {
|
||||
return state_->size();
|
||||
}
|
||||
@@ -396,20 +382,6 @@ namespace e2d
|
||||
}
|
||||
vertex_buffer::~vertex_buffer() noexcept = default;
|
||||
|
||||
void vertex_buffer::update(buffer_view vertices, std::size_t offset) noexcept {
|
||||
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().bytes_per_vertex() == 0);
|
||||
opengl::with_gl_bind_buffer(state_->dbg(), state_->id(),
|
||||
[this, &vertices, &buffer_offset]() noexcept {
|
||||
GL_CHECK_CODE(state_->dbg(), glBufferSubData(
|
||||
state_->id().target(),
|
||||
math::numeric_cast<GLintptr>(buffer_offset),
|
||||
math::numeric_cast<GLsizeiptr>(vertices.size()),
|
||||
vertices.data()));
|
||||
});
|
||||
}
|
||||
|
||||
std::size_t vertex_buffer::buffer_size() const noexcept {
|
||||
return state_->size();
|
||||
}
|
||||
@@ -1000,6 +972,119 @@ namespace e2d
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
render& render::update_buffer(
|
||||
const index_buffer_ptr& ibuffer,
|
||||
buffer_view indices,
|
||||
std::size_t offset)
|
||||
{
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
E2D_ASSERT(ibuffer);
|
||||
const std::size_t buffer_offset = offset * ibuffer->state().decl().bytes_per_index();
|
||||
E2D_ASSERT(indices.size() + buffer_offset <= ibuffer->state().size());
|
||||
E2D_ASSERT(indices.size() % ibuffer->state().decl().bytes_per_index() == 0);
|
||||
opengl::with_gl_bind_buffer(ibuffer->state().dbg(), ibuffer->state().id(),
|
||||
[&ibuffer, &indices, &buffer_offset]() noexcept {
|
||||
GL_CHECK_CODE(ibuffer->state().dbg(), glBufferSubData(
|
||||
ibuffer->state().id().target(),
|
||||
math::numeric_cast<GLintptr>(buffer_offset),
|
||||
math::numeric_cast<GLsizeiptr>(indices.size()),
|
||||
indices.data()));
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
render& render::update_buffer(
|
||||
const vertex_buffer_ptr& vbuffer,
|
||||
buffer_view vertices,
|
||||
std::size_t offset)
|
||||
{
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
E2D_ASSERT(vbuffer);
|
||||
const std::size_t buffer_offset = offset * vbuffer->state().decl().bytes_per_vertex();
|
||||
E2D_ASSERT(vertices.size() + buffer_offset <= vbuffer->state().size());
|
||||
E2D_ASSERT(vertices.size() % vbuffer->state().decl().bytes_per_vertex() == 0);
|
||||
opengl::with_gl_bind_buffer(vbuffer->state().dbg(), vbuffer->state().id(),
|
||||
[&vbuffer, &vertices, &buffer_offset]() noexcept {
|
||||
GL_CHECK_CODE(vbuffer->state().dbg(), glBufferSubData(
|
||||
vbuffer->state().id().target(),
|
||||
math::numeric_cast<GLintptr>(buffer_offset),
|
||||
math::numeric_cast<GLsizeiptr>(vertices.size()),
|
||||
vertices.data()));
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
render& render::update_texture(
|
||||
const texture_ptr& tex,
|
||||
const image& img,
|
||||
v2u offset)
|
||||
{
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
E2D_ASSERT(tex);
|
||||
|
||||
const pixel_declaration decl =
|
||||
convert_image_data_format_to_pixel_declaration(img.format());
|
||||
if ( tex->decl() != decl ) {
|
||||
state_->dbg().error("RENDER: Failed to update texture:\n"
|
||||
"--> Info: incompatible pixel formats\n"
|
||||
"--> Texture format: %0\n"
|
||||
"--> Image format: %1",
|
||||
pixel_declaration::pixel_type_to_cstr(tex->decl().type()),
|
||||
pixel_declaration::pixel_type_to_cstr(decl.type()));
|
||||
throw bad_render_operation();
|
||||
}
|
||||
|
||||
return update_texture(tex, img.data(), b2u(offset, img.size()));
|
||||
}
|
||||
|
||||
render& render::update_texture(
|
||||
const texture_ptr& tex,
|
||||
buffer_view pixels,
|
||||
const b2u& region)
|
||||
{
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
E2D_ASSERT(tex);
|
||||
E2D_ASSERT(region.position.x < tex->size().x && region.position.y < tex->size().y);
|
||||
E2D_ASSERT(region.position.x + region.size.x <= tex->size().x);
|
||||
E2D_ASSERT(region.position.y + region.size.y <= tex->size().y);
|
||||
E2D_ASSERT(pixels.size() == region.size.y * ((region.size.x * tex->decl().bits_per_pixel()) / 8u));
|
||||
|
||||
if ( tex->decl().is_compressed() ) {
|
||||
const v2u block_size = tex->decl().compressed_block_size();
|
||||
E2D_ASSERT(region.position.x % block_size.x == 0 && region.position.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(),
|
||||
[&tex, &pixels, ®ion]() noexcept {
|
||||
GL_CHECK_CODE(tex->state().dbg(), glCompressedTexSubImage2D(
|
||||
tex->state().id().target(),
|
||||
0,
|
||||
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),
|
||||
convert_pixel_type_to_internal_format_e(tex->state().decl().type()),
|
||||
math::numeric_cast<GLsizei>(pixels.size()),
|
||||
pixels.data()));
|
||||
});
|
||||
} else {
|
||||
opengl::with_gl_bind_texture(state_->dbg(), tex->state().id(),
|
||||
[&tex, &pixels, ®ion]() noexcept {
|
||||
GL_CHECK_CODE(tex->state().dbg(), glTexSubImage2D(
|
||||
tex->state().id().target(),
|
||||
0,
|
||||
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),
|
||||
convert_pixel_type_to_external_format(tex->state().decl().type()),
|
||||
convert_pixel_type_to_external_data_type(tex->state().decl().type()),
|
||||
pixels.data()));
|
||||
});
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const render::device_caps& render::device_capabilities() const noexcept {
|
||||
E2D_ASSERT(is_in_main_thread());
|
||||
@@ -1018,6 +1103,8 @@ namespace e2d
|
||||
case pixel_declaration::pixel_type::depth24_stencil8:
|
||||
return GLEW_OES_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::rgba8:
|
||||
return true;
|
||||
|
||||
@@ -723,6 +723,8 @@ namespace e2d::opengl
|
||||
DEFINE_CASE(depth24, GL_DEPTH_COMPONENT);
|
||||
DEFINE_CASE(depth32, GL_DEPTH_COMPONENT);
|
||||
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(rgba8, GL_RGBA);
|
||||
default:
|
||||
@@ -739,6 +741,8 @@ namespace e2d::opengl
|
||||
DEFINE_CASE(depth24, GL_UNSIGNED_INT);
|
||||
DEFINE_CASE(depth32, GL_UNSIGNED_INT);
|
||||
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(rgba8, GL_UNSIGNED_BYTE);
|
||||
default:
|
||||
@@ -755,7 +759,9 @@ namespace e2d::opengl
|
||||
DEFINE_CASE(depth24, GL_DEPTH_COMPONENT24);
|
||||
DEFINE_CASE(depth32, GL_DEPTH_COMPONENT32);
|
||||
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(rgba8, GL_RGBA);
|
||||
|
||||
@@ -786,8 +792,8 @@ namespace e2d::opengl
|
||||
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
|
||||
switch ( f ) {
|
||||
DEFINE_CASE(g8, rgb8);
|
||||
DEFINE_CASE(ga8, rgba8);
|
||||
DEFINE_CASE(g8, g8);
|
||||
DEFINE_CASE(ga8, ga8);
|
||||
DEFINE_CASE(rgb8, rgb8);
|
||||
DEFINE_CASE(rgba8, rgba8);
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#if defined(E2D_BUILD_MODE) && E2D_BUILD_MODE == E2D_BUILD_MODE_DEBUG
|
||||
# define GL_FLUSH_ERRORS(dbg)\
|
||||
for ( GLenum err = glGetError(); err != GL_NO_ERROR; err = glGetError() ) {\
|
||||
E2D_ASSERT_MSG(false, "RENDER: GL_FLUSH_ERRORS()");\
|
||||
(dbg).log(err == GL_OUT_OF_MEMORY\
|
||||
? debug::level::fatal\
|
||||
: debug::level::error,\
|
||||
@@ -26,13 +25,13 @@
|
||||
"--> Line: %1\n"\
|
||||
"--> Code: %2",\
|
||||
__FILE__, __LINE__, e2d::opengl::gl_error_code_to_cstr(err));\
|
||||
E2D_ASSERT_MSG(false, "RENDER: GL_FLUSH_ERRORS()");\
|
||||
if ( err == GL_OUT_OF_MEMORY ) std::terminate();\
|
||||
}
|
||||
# define GL_CHECK_CODE(dbg, code)\
|
||||
GL_FLUSH_ERRORS(dbg);\
|
||||
code;\
|
||||
for ( GLenum err = glGetError(); err != GL_NO_ERROR; err = glGetError() ) {\
|
||||
E2D_ASSERT_MSG(false, #code);\
|
||||
(dbg).log(err == GL_OUT_OF_MEMORY\
|
||||
? debug::level::fatal\
|
||||
: debug::level::error,\
|
||||
@@ -41,6 +40,7 @@
|
||||
"--> Line: %2\n"\
|
||||
"--> Code: %3",\
|
||||
#code, __FILE__, __LINE__, e2d::opengl::gl_error_code_to_cstr(err));\
|
||||
E2D_ASSERT_MSG(false, #code);\
|
||||
if ( err == GL_OUT_OF_MEMORY ) std::terminate();\
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -217,9 +217,9 @@ namespace e2d
|
||||
GL_CHECK_CODE(debug_, glPixelStorei(GL_PACK_ALIGNMENT, 1));
|
||||
GL_CHECK_CODE(debug_, glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
||||
|
||||
set_states(state_block_);
|
||||
set_shader_program(shader_program_);
|
||||
set_render_target(render_target_);
|
||||
reset_states();
|
||||
reset_shader_program();
|
||||
reset_render_target();
|
||||
}
|
||||
|
||||
debug& render::internal_state::dbg() const noexcept {
|
||||
@@ -237,21 +237,90 @@ namespace e2d
|
||||
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& sb) noexcept {
|
||||
set_depth_state(sb.depth());
|
||||
set_stencil_state(sb.stencil());
|
||||
set_culling_state(sb.culling());
|
||||
set_blending_state(sb.blending());
|
||||
set_capabilities_state(sb.capabilities());
|
||||
|
||||
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_depth_state(const depth_state& ds) noexcept {
|
||||
if ( ds == state_block_.depth() ) {
|
||||
render::internal_state& render::internal_state::set_states(const state_block& sb) noexcept {
|
||||
if ( sb.depth() != state_block_.depth() ) {
|
||||
set_depth_state_(sb.depth());
|
||||
state_block_.depth(sb.depth());
|
||||
}
|
||||
|
||||
if ( sb.stencil() != state_block_.stencil() ) {
|
||||
set_stencil_state_(sb.stencil());
|
||||
state_block_.stencil(sb.stencil());
|
||||
}
|
||||
|
||||
if ( sb.culling() != state_block_.culling() ) {
|
||||
set_culling_state_(sb.culling());
|
||||
state_block_.culling(sb.culling());
|
||||
}
|
||||
|
||||
if ( sb.blending() != state_block_.blending() ) {
|
||||
set_blending_state_(sb.blending());
|
||||
state_block_.blending(sb.blending());
|
||||
}
|
||||
|
||||
if ( sb.capabilities() != state_block_.capabilities() ) {
|
||||
set_capabilities_state_(sb.capabilities());
|
||||
state_block_.capabilities(sb.capabilities());
|
||||
}
|
||||
|
||||
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_shader_program(const shader_ptr& sp) noexcept {
|
||||
if ( sp == shader_program_ ) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gl_program_id& sp_id = sp
|
||||
? sp->state().id()
|
||||
: default_sp_;
|
||||
GL_CHECK_CODE(debug_, glUseProgram(*sp_id));
|
||||
|
||||
shader_program_ = sp;
|
||||
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;
|
||||
}
|
||||
|
||||
render::internal_state& render::internal_state::set_render_target(const render_target_ptr& rt) noexcept {
|
||||
if ( rt == render_target_ ) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gl_framebuffer_id& rt_id = rt
|
||||
? rt->state().id()
|
||||
: default_fb_;
|
||||
GL_CHECK_CODE(debug_, glBindFramebuffer(rt_id.target(), *rt_id));
|
||||
|
||||
render_target_ = rt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void render::internal_state::set_depth_state_(const depth_state& ds) noexcept {
|
||||
GL_CHECK_CODE(debug_, glDepthRange(
|
||||
math::numeric_cast<GLclampd>(math::saturate(ds.range_near())),
|
||||
math::numeric_cast<GLclampd>(math::saturate(ds.range_far()))));
|
||||
@@ -259,16 +328,9 @@ namespace e2d
|
||||
ds.write() ? GL_TRUE : GL_FALSE));
|
||||
GL_CHECK_CODE(debug_, glDepthFunc(
|
||||
convert_compare_func(ds.func())));
|
||||
|
||||
state_block_.depth(ds);
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::internal_state& render::internal_state::set_stencil_state(const stencil_state& ss) noexcept {
|
||||
if ( ss == state_block_.stencil() ) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
void render::internal_state::set_stencil_state_(const stencil_state& ss) noexcept {
|
||||
GL_CHECK_CODE(debug_, glStencilMask(
|
||||
math::numeric_cast<GLuint>(ss.write())));
|
||||
GL_CHECK_CODE(debug_, glStencilFunc(
|
||||
@@ -279,30 +341,16 @@ namespace e2d
|
||||
convert_stencil_op(ss.sfail()),
|
||||
convert_stencil_op(ss.zfail()),
|
||||
convert_stencil_op(ss.pass())));
|
||||
|
||||
state_block_.stencil(ss);
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::internal_state& render::internal_state::set_culling_state(const culling_state& cs) noexcept {
|
||||
if ( cs == state_block_.culling() ) {
|
||||
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())));
|
||||
|
||||
state_block_.culling(cs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::internal_state& render::internal_state::set_blending_state(const blending_state& bs) noexcept {
|
||||
if ( bs == state_block_.blending() ) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
void render::internal_state::set_blending_state_(const blending_state& bs) noexcept {
|
||||
GL_CHECK_CODE(debug_, glBlendColor(
|
||||
math::numeric_cast<GLclampf>(math::saturate(bs.constant_color().r)),
|
||||
math::numeric_cast<GLclampf>(math::saturate(bs.constant_color().g)),
|
||||
@@ -321,12 +369,9 @@ 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::b)) != 0,
|
||||
(utils::enum_to_underlying(bs.color_mask()) & utils::enum_to_underlying(blending_color_mask::a)) != 0));
|
||||
|
||||
state_block_.blending(bs);
|
||||
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 {
|
||||
if ( enable ) {
|
||||
glEnable(cap);
|
||||
@@ -335,45 +380,10 @@ 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_BLEND, cs.blending()));
|
||||
GL_CHECK_CODE(debug_, enable_or_disable(GL_DEPTH_TEST, cs.depth_test()));
|
||||
GL_CHECK_CODE(debug_, enable_or_disable(GL_STENCIL_TEST, cs.stencil_test()));
|
||||
|
||||
state_block_.capabilities(cs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::internal_state& render::internal_state::set_shader_program(const shader_ptr& sp) noexcept {
|
||||
if ( sp == shader_program_ ) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gl_program_id& sp_id = sp
|
||||
? sp->state().id()
|
||||
: default_sp_;
|
||||
GL_CHECK_CODE(debug_, glUseProgram(*sp_id));
|
||||
|
||||
shader_program_ = sp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
render::internal_state& render::internal_state::set_render_target(const render_target_ptr& rt) noexcept {
|
||||
if ( rt == render_target_ ) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gl_framebuffer_id& rt_id = rt
|
||||
? rt->state().id()
|
||||
: default_fb_;
|
||||
GL_CHECK_CODE(debug_, glBindFramebuffer(rt_id.target(), *rt_id));
|
||||
|
||||
render_target_ = rt;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -176,15 +176,20 @@ namespace e2d
|
||||
const device_caps& device_capabilities() const noexcept;
|
||||
const render_target_ptr& render_target() const noexcept;
|
||||
public:
|
||||
internal_state& reset_states() noexcept;
|
||||
internal_state& set_states(const state_block& sb) noexcept;
|
||||
internal_state& set_depth_state(const depth_state& ds) noexcept;
|
||||
internal_state& set_stencil_state(const stencil_state& ss) noexcept;
|
||||
internal_state& set_culling_state(const culling_state& cs) noexcept;
|
||||
internal_state& set_blending_state(const blending_state& bs) noexcept;
|
||||
internal_state& set_capabilities_state(const capabilities_state& cs) noexcept;
|
||||
|
||||
|
||||
internal_state& reset_shader_program() 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;
|
||||
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:
|
||||
debug& debug_;
|
||||
window& window_;
|
||||
|
||||
@@ -203,7 +203,7 @@ namespace e2d::render_system_impl
|
||||
void batcher<Index, Vertex>::update_index_buffer_() {
|
||||
const std::size_t min_ib_size = indices_.size() * sizeof(indices_[0]);
|
||||
if ( index_buffer_ && index_buffer_->buffer_size() >= min_ib_size ) {
|
||||
index_buffer_->update(indices_, 0u);
|
||||
render_.update_buffer(index_buffer_, indices_, 0u);
|
||||
} else {
|
||||
const std::size_t new_ib_size = calculate_new_buffer_size(
|
||||
sizeof(Index),
|
||||
@@ -230,7 +230,7 @@ namespace e2d::render_system_impl
|
||||
void batcher<Index, Vertex>::update_vertex_buffer_() {
|
||||
const std::size_t min_vb_size = vertices_.size() * sizeof(vertices_[0]);
|
||||
if ( vertex_buffer_ && vertex_buffer_->buffer_size() >= min_vb_size ) {
|
||||
vertex_buffer_->update(vertices_, 0u);
|
||||
render_.update_buffer(vertex_buffer_, vertices_, 0u);
|
||||
} else {
|
||||
const std::size_t new_vb_size = calculate_new_buffer_size(
|
||||
sizeof(Vertex),
|
||||
|
||||
@@ -32,6 +32,54 @@ namespace e2d
|
||||
assign(src, size);
|
||||
}
|
||||
|
||||
buffer::iterator buffer::begin() noexcept {
|
||||
return data_.get();
|
||||
}
|
||||
|
||||
buffer::const_iterator buffer::begin() const noexcept {
|
||||
return data_.get();
|
||||
}
|
||||
|
||||
buffer::const_iterator buffer::cbegin() const noexcept {
|
||||
return data_.get();
|
||||
}
|
||||
|
||||
buffer::iterator buffer::end() noexcept {
|
||||
return data_.get() + size_;
|
||||
}
|
||||
|
||||
buffer::const_iterator buffer::end() const noexcept {
|
||||
return data_.get() + size_;
|
||||
}
|
||||
|
||||
buffer::const_iterator buffer::cend() const noexcept {
|
||||
return data_.get() + size_;
|
||||
}
|
||||
|
||||
buffer::reverse_iterator buffer::rbegin() noexcept {
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
buffer::const_reverse_iterator buffer::rbegin() const noexcept {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
buffer::const_reverse_iterator buffer::crbegin() const noexcept {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
buffer::reverse_iterator buffer::rend() noexcept {
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
buffer::const_reverse_iterator buffer::rend() const noexcept {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
buffer::const_reverse_iterator buffer::crend() const noexcept {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
buffer& buffer::fill(u8 ch) noexcept {
|
||||
if ( data_ && size_) {
|
||||
std::memset(data_.get(), ch, size_);
|
||||
|
||||
@@ -7,7 +7,26 @@
|
||||
#include "_core.hpp"
|
||||
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_graphics(true));
|
||||
}
|
||||
|
||||
~safe_engine_initializer() noexcept {
|
||||
modules::shutdown<engine>();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("render"){
|
||||
safe_engine_initializer initializer;
|
||||
|
||||
SECTION("sampler_state"){
|
||||
{
|
||||
const auto ss = render::sampler_state();
|
||||
@@ -169,4 +188,94 @@ TEST_CASE("render"){
|
||||
REQUIRE(vd4 != vd);
|
||||
REQUIRE(vd4 == vd3);
|
||||
}
|
||||
SECTION("update_texture"){
|
||||
if ( modules::is_initialized<render>() ) {
|
||||
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;
|
||||
}
|
||||
REQUIRE_NOTHROW(r.update_texture(tex, src, b2u(0, 0, 128, 128)));
|
||||
}
|
||||
{
|
||||
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;
|
||||
}
|
||||
REQUIRE_NOTHROW(r.update_texture(tex, src, b2u(0, 0, 128, 128)));
|
||||
}
|
||||
{
|
||||
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;
|
||||
}
|
||||
REQUIRE_NOTHROW(r.update_texture(tex, src, b2u(0, 0, 128, 128)));
|
||||
}
|
||||
{
|
||||
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;
|
||||
}
|
||||
REQUIRE_NOTHROW(r.update_texture(tex, src, b2u(0, 0, 57, 31)));
|
||||
}
|
||||
{
|
||||
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;
|
||||
}
|
||||
REQUIRE_NOTHROW(r.update_texture(tex, src, b2u(22, 17, 31, 44)));
|
||||
}
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
image img(v2u(31, 44), image_data_format::ga8, src);
|
||||
REQUIRE_THROWS_AS(
|
||||
r.update_texture(tex, img, v2u(11,27)),
|
||||
bad_render_operation);
|
||||
}
|
||||
|
||||
//if ( r.device_capabilities().dxt5_compression_supported ) // TODO: wait for android branch
|
||||
{
|
||||
str resources;
|
||||
REQUIRE(filesystem::extract_predef_path(
|
||||
resources,
|
||||
filesystem::predef_path::resources));
|
||||
|
||||
image src;
|
||||
REQUIRE(images::try_load_image(src, make_read_file(path::combine(resources, "bin/images/ship_rgba.dds"))));
|
||||
|
||||
texture_ptr tex = r.create_texture(src.size(), pixel_declaration::pixel_type::rgba_dxt5);
|
||||
REQUIRE(tex != nullptr);
|
||||
REQUIRE_NOTHROW(r.update_texture(tex, src, v2u(0,0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,6 +170,22 @@ TEST_CASE("buffer") {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
{
|
||||
const u8 data[] = {1,2,3};
|
||||
buffer b(data, std::size(data) * sizeof(data[0]));
|
||||
|
||||
const auto con_str = [](std::string acc, u8 ch){
|
||||
return acc + std::to_string(ch);
|
||||
};
|
||||
|
||||
REQUIRE(std::accumulate(b.begin(), b.end(), std::string(), con_str) == "123");
|
||||
REQUIRE(std::accumulate(std::as_const(b).begin(), std::as_const(b).end(), std::string(), con_str) == "123");
|
||||
REQUIRE(std::accumulate(b.cbegin(), b.cend(), std::string(), con_str) == "123");
|
||||
|
||||
REQUIRE(std::accumulate(b.rbegin(), b.rend(), std::string(), con_str) == "321");
|
||||
REQUIRE(std::accumulate(std::as_const(b).rbegin(), std::as_const(b).rend(), std::string(), con_str) == "321");
|
||||
REQUIRE(std::accumulate(b.crbegin(), b.crend(), std::string(), con_str) == "321");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("buffer_view") {
|
||||
|
||||
Reference in New Issue
Block a user