|
@@ -77,15 +77,6 @@ void ogl_buffer_proxy::download(sp_image &img) {
|
|
|
down_res->unmap();
|
|
down_res->unmap();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void Texture2DSP::setImageSP(const sp_image &img) {
|
|
|
|
|
- assert(getTextureWidth() == img.width());
|
|
|
|
|
- assert(getTextureHeight() == img.height());
|
|
|
|
|
- if (!pbo) { pbo.emplace(); }
|
|
|
|
|
- pbo->upload(img);
|
|
|
|
|
- setSourceFormat(get_tex_format(img.cv_type()));
|
|
|
|
|
- setSourceType(get_tex_type(img.cv_type()));
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
namespace {
|
|
namespace {
|
|
|
auto get_tex_format_channels(const GLenum format) {
|
|
auto get_tex_format_channels(const GLenum format) {
|
|
|
switch (format) {
|
|
switch (format) {
|
|
@@ -115,40 +106,86 @@ namespace {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-sp_image Texture2DSP::asImageSP(GLenum format, GLenum type) {
|
|
|
|
|
- const auto channels = get_tex_format_channels(format);
|
|
|
|
|
- const auto cv_depth = get_date_type_cv_depth(type);
|
|
|
|
|
- const auto cv_type = CV_MAKE_TYPE(cv_depth, channels);
|
|
|
|
|
- const auto img_size = cv::Size(getTextureWidth(), getTextureHeight());
|
|
|
|
|
- auto img = sp_image::create(cv_type, img_size);
|
|
|
|
|
-
|
|
|
|
|
- if (!pbo) [[unlikely]] { pbo.emplace(); }
|
|
|
|
|
- if (pbo->modify_ts < draw_ts) {
|
|
|
|
|
- pbo->create(img.byte_size());
|
|
|
|
|
- glBindTexture(getTextureTarget(), getTextureObject(0)->id());
|
|
|
|
|
- glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo->id);
|
|
|
|
|
|
|
+struct Texture2DSP::impl {
|
|
|
|
|
+ Texture2DSP *q_this;
|
|
|
|
|
+ std::optional<ogl_buffer_proxy> pbo_down; // tex -> PBO
|
|
|
|
|
+ std::optional<ogl_buffer_proxy> pbo_up; // PBO -> tex
|
|
|
|
|
+ timestamp_type download_ts = {}; // tex -> PBO
|
|
|
|
|
+
|
|
|
|
|
+ explicit impl(Texture2DSP *_q_this)
|
|
|
|
|
+ : q_this(_q_this) { (void) 0; }
|
|
|
|
|
+
|
|
|
|
|
+ void set_image(const sp_image &img) {
|
|
|
|
|
+ assert(q_this->getTextureWidth() == img.width());
|
|
|
|
|
+ assert(q_this->getTextureHeight() == img.height());
|
|
|
|
|
+ if (!pbo_up) { pbo_up.emplace(); }
|
|
|
|
|
+ pbo_up->upload(img);
|
|
|
|
|
+ q_this->setSourceFormat(get_tex_format(img.cv_type()));
|
|
|
|
|
+ q_this->setSourceType(get_tex_type(img.cv_type()));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ sp_image as_image(const GLenum format, const GLenum type) {
|
|
|
|
|
+ const auto channels = get_tex_format_channels(format);
|
|
|
|
|
+ const auto cv_depth = get_date_type_cv_depth(type);
|
|
|
|
|
+ const auto cv_type = CV_MAKE_TYPE(cv_depth, channels);
|
|
|
|
|
+ const auto img_size = cv::Size(q_this->getTextureWidth(), q_this->getTextureHeight());
|
|
|
|
|
+ auto img = sp_image::create(cv_type, img_size);
|
|
|
|
|
+
|
|
|
|
|
+ if (!pbo_down) [[unlikely]] { pbo_down.emplace(); }
|
|
|
|
|
+ pbo_down->create(img.byte_size());
|
|
|
|
|
+ const auto tex_target = q_this->getTextureTarget();
|
|
|
|
|
+ glBindTexture(tex_target, q_this->getTextureObject(0)->id());
|
|
|
|
|
+ glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_down->id);
|
|
|
glReadPixels(0, 0, img.width(), img.height(), format, type, (void *) 0);
|
|
glReadPixels(0, 0, img.width(), img.height(), format, type, (void *) 0);
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
|
|
- glBindTexture(getTextureTarget(), 0);
|
|
|
|
|
- pbo->modify_ts = current_timestamp();
|
|
|
|
|
|
|
+ glBindTexture(tex_target, 0);
|
|
|
|
|
+ pbo_down->modify_ts = current_timestamp();
|
|
|
|
|
+ return img;
|
|
|
}
|
|
}
|
|
|
- pbo->download(img);
|
|
|
|
|
- return img;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ void try_fill_from_pbo() {
|
|
|
|
|
+ if (!pbo_up) return;
|
|
|
|
|
+ if (download_ts < pbo_up->modify_ts) {
|
|
|
|
|
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_up->id);
|
|
|
|
|
+ glTexSubImage2D(q_this->getTextureTarget(), 0, 0, 0,
|
|
|
|
|
+ q_this->getTextureWidth(), q_this->getTextureHeight(),
|
|
|
|
|
+ q_this->getSourceFormat(), q_this->getSourceType(), nullptr);
|
|
|
|
|
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
|
|
|
|
+ download_ts = current_timestamp();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+Texture2DSP::Texture2DSP()
|
|
|
|
|
+ : pimpl(std::make_unique<impl>(this)) {
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+Texture2DSP::~Texture2DSP() = default;
|
|
|
|
|
+
|
|
|
|
|
+void Texture2DSP::setImageSP(const sp_image &img) const {
|
|
|
|
|
+ pimpl->set_image(img);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+sp_image Texture2DSP::asImageSP(const GLenum format, const GLenum type) const {
|
|
|
|
|
+ return pimpl->as_image(format, type);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Texture2DSP::apply(osg::State &state) const {
|
|
void Texture2DSP::apply(osg::State &state) const {
|
|
|
setNumMipmapLevels(1);
|
|
setNumMipmapLevels(1);
|
|
|
Texture2D::apply(state);
|
|
Texture2D::apply(state);
|
|
|
|
|
+
|
|
|
// texture has already been bind
|
|
// texture has already been bind
|
|
|
|
|
+ pimpl->try_fill_from_pbo();
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- if (!pbo) return;
|
|
|
|
|
- if (download_ts < pbo->modify_ts) {
|
|
|
|
|
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo->id);
|
|
|
|
|
- glTexSubImage2D(getTextureTarget(), 0, 0, 0,
|
|
|
|
|
- getTextureWidth(), getTextureHeight(),
|
|
|
|
|
- getSourceFormat(), getSourceType(), nullptr);
|
|
|
|
|
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
|
|
|
|
- download_ts = current_timestamp();
|
|
|
|
|
|
|
+void setupTextureHelper(osg::ref_ptr<Texture2DSP> &tex, const cv::Size size) {
|
|
|
|
|
+ if (tex == nullptr
|
|
|
|
|
+ || tex->getTextureWidth() != size.width
|
|
|
|
|
+ || tex->getTextureHeight() != size.height) [[unlikely]] {
|
|
|
|
|
+ const auto next_tex = new Texture2DSP();
|
|
|
|
|
+ next_tex->setTextureSize(size.width, size.height);
|
|
|
|
|
+ next_tex->setInternalFormat(GL_RGBA);
|
|
|
|
|
+ tex = next_tex;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -206,9 +243,21 @@ namespace {
|
|
|
std::optional<prog_image_default_type> prog_image_default;
|
|
std::optional<prog_image_default_type> prog_image_default;
|
|
|
std::optional<prog_image_remap_type> prog_image_remap;
|
|
std::optional<prog_image_remap_type> prog_image_remap;
|
|
|
|
|
|
|
|
- void setup_program(ImageGeomSP *img) {
|
|
|
|
|
|
|
+ void upload_image_to_texture(const sp_image &img, ref_ptr<Texture2DSP> &tex) {
|
|
|
|
|
+ setupTextureHelper(tex, img.cv_size());
|
|
|
|
|
+ tex->setImageSP(img);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+struct ImageGeomSP::impl {
|
|
|
|
|
+ ImageGeomSP *q_this = nullptr;
|
|
|
|
|
+ ref_ptr<Texture2DSP> tex;
|
|
|
|
|
+ ref_ptr<Texture2DSP> remap_tex;
|
|
|
|
|
+ simple_rect last_rect = {};
|
|
|
|
|
+
|
|
|
|
|
+ void setup_program(ImageGeomSP *img) const {
|
|
|
assert(img != nullptr);
|
|
assert(img != nullptr);
|
|
|
- if (img->remap_tex) {
|
|
|
|
|
|
|
+ if (remap_tex) {
|
|
|
if (!prog_image_remap) [[unlikely]] {
|
|
if (!prog_image_remap) [[unlikely]] {
|
|
|
prog_image_remap.emplace();
|
|
prog_image_remap.emplace();
|
|
|
}
|
|
}
|
|
@@ -221,94 +270,108 @@ namespace {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void upload_image_to_texture(const sp_image &img, ref_ptr<Texture2DSP> &tex) {
|
|
|
|
|
- if (tex == nullptr
|
|
|
|
|
- || tex->getTextureWidth() != img.width()
|
|
|
|
|
- || tex->getTextureHeight() != img.height()) {
|
|
|
|
|
- const auto next_tex = new Texture2DSP();
|
|
|
|
|
- next_tex->setTextureSize(img.width(), img.height());
|
|
|
|
|
- next_tex->setInternalFormat(GL_RGBA);
|
|
|
|
|
- tex = next_tex;
|
|
|
|
|
|
|
+ explicit impl(ImageGeomSP *_q_this) : q_this(_q_this) {
|
|
|
|
|
+ const ref_ptr vertex = new Vec3Array(image_vertex_num);
|
|
|
|
|
+ vertex->setName("vertex");
|
|
|
|
|
+ q_this->setVertexArray(vertex);
|
|
|
|
|
+ set_viewport_range({-1, -1, 2, 2});
|
|
|
|
|
+
|
|
|
|
|
+ const ref_ptr tex_uv = new Vec2Array();
|
|
|
|
|
+ tex_uv->setName("vertex_uv");
|
|
|
|
|
+ tex_uv->push_back({0, 0});
|
|
|
|
|
+ tex_uv->push_back({1, 0});
|
|
|
|
|
+ tex_uv->push_back({1, 1});
|
|
|
|
|
+ tex_uv->push_back({0, 1});
|
|
|
|
|
+ q_this->setVertexAttribArray(1, tex_uv, Array::BIND_PER_VERTEX);
|
|
|
|
|
+
|
|
|
|
|
+ q_this->addPrimitiveSet(new DrawArrays(
|
|
|
|
|
+ PrimitiveSet::QUADS, 0, 4));
|
|
|
|
|
+ setup_program(q_this);
|
|
|
|
|
+
|
|
|
|
|
+ // enable depth test
|
|
|
|
|
+ q_this->getOrCreateStateSet()->setMode(
|
|
|
|
|
+ GL_DEPTH_TEST, StateAttribute::OFF);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void reset_vertex() const {
|
|
|
|
|
+ const auto vertex = (Vec3Array *) q_this->getVertexArray();
|
|
|
|
|
+ assert(vertex->size() == image_vertex_num);
|
|
|
|
|
+ auto [x, y, w, h] = last_rect;
|
|
|
|
|
+ vertex->at(0) = {x + 0, y + 0, 0};
|
|
|
|
|
+ vertex->at(1) = {x + w, y + 0, 0};
|
|
|
|
|
+ vertex->at(2) = {x + w, y + h, 0};
|
|
|
|
|
+ vertex->at(3) = {x + 0, y + h, 0};
|
|
|
|
|
+ vertex->dirty();
|
|
|
|
|
+ q_this->dirtyBound();
|
|
|
|
|
+ q_this->dirtyGLObjects();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void set_viewport_range(const simple_rect rect) {
|
|
|
|
|
+ if (rect == last_rect) [[likely]] return;
|
|
|
|
|
+ last_rect = rect;
|
|
|
|
|
+ reset_vertex();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void set_viewport_range(const float viewport_aspect, const bool flip_y) {
|
|
|
|
|
+ if (tex == nullptr) return;
|
|
|
|
|
+ simple_rect rect = {-1, -1, 2, 2};
|
|
|
|
|
+ auto img_aspect = 1.f * tex->getTextureWidth()
|
|
|
|
|
+ / tex->getTextureHeight();
|
|
|
|
|
+ rect = rect.fit_aspect(img_aspect / viewport_aspect);
|
|
|
|
|
+ if (flip_y) {
|
|
|
|
|
+ rect.y *= -1;
|
|
|
|
|
+ rect.height *= -1;
|
|
|
}
|
|
}
|
|
|
- tex->setImageSP(img);
|
|
|
|
|
|
|
+ set_viewport_range(rect);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void set_image(const sp_image &img) {
|
|
|
|
|
+ upload_image_to_texture(img, tex);
|
|
|
|
|
+ q_this->getOrCreateStateSet()->setTextureAttributeAndModes(
|
|
|
|
|
+ 0, tex, StateAttribute::ON);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void set_image_tex(Texture2DSP *_tex) const {
|
|
|
|
|
+ q_this->getOrCreateStateSet()->setTextureAttributeAndModes(
|
|
|
|
|
+ 0, _tex, StateAttribute::ON);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ void set_remap_image(const sp_image &img) {
|
|
|
|
|
+ upload_image_to_texture(img, remap_tex);
|
|
|
|
|
+ if (remap_tex) {
|
|
|
|
|
+ q_this->getOrCreateStateSet()->setTextureAttributeAndModes(
|
|
|
|
|
+ 1, remap_tex, StateAttribute::ON);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ q_this->getOrCreateStateSet()->setTextureAttributeAndModes(
|
|
|
|
|
+ 1, 0, StateAttribute::OFF);
|
|
|
|
|
+ }
|
|
|
|
|
+ setup_program(q_this);
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+ImageGeomSP::ImageGeomSP()
|
|
|
|
|
+ : pimpl(std::make_unique<impl>(this)) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-ImageGeomSP::ImageGeomSP() {
|
|
|
|
|
- const ref_ptr vertex = new Vec3Array(image_vertex_num);
|
|
|
|
|
- vertex->setName("vertex");
|
|
|
|
|
- setVertexArray(vertex);
|
|
|
|
|
- setViewportRange({-1, -1, 2, 2});
|
|
|
|
|
-
|
|
|
|
|
- const ref_ptr tex_uv = new Vec2Array();
|
|
|
|
|
- tex_uv->setName("vertex_uv");
|
|
|
|
|
- tex_uv->push_back({0, 0});
|
|
|
|
|
- tex_uv->push_back({1, 0});
|
|
|
|
|
- tex_uv->push_back({1, 1});
|
|
|
|
|
- tex_uv->push_back({0, 1});
|
|
|
|
|
- setVertexAttribArray(1, tex_uv, Array::BIND_PER_VERTEX);
|
|
|
|
|
-
|
|
|
|
|
- const ref_ptr colors = new Vec4Array();
|
|
|
|
|
- colors->setName("color");
|
|
|
|
|
- colors->push_back({1, 1, 1, 1});
|
|
|
|
|
- setColorArray(colors, Array::BIND_OVERALL);
|
|
|
|
|
-
|
|
|
|
|
- addPrimitiveSet(new DrawArrays(
|
|
|
|
|
- PrimitiveSet::QUADS, 0, 4));
|
|
|
|
|
- setup_program(this);
|
|
|
|
|
-
|
|
|
|
|
- ArrayList array_list;
|
|
|
|
|
- getArrayList(array_list);
|
|
|
|
|
- array_list.clear();
|
|
|
|
|
|
|
+ImageGeomSP::~ImageGeomSP() = default;
|
|
|
|
|
+
|
|
|
|
|
+void ImageGeomSP::setViewportRange(const simple_rect rect) const {
|
|
|
|
|
+ pimpl->set_viewport_range(rect);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void ImageGeomSP::setViewportRange(simple_rect rect) {
|
|
|
|
|
- if (rect == last_rect) [[likely]] return;
|
|
|
|
|
- last_rect = rect;
|
|
|
|
|
- const auto vertex = (Vec3Array *) getVertexArray();
|
|
|
|
|
- assert(vertex->size() == image_vertex_num);
|
|
|
|
|
- auto [x, y, w, h] = rect;
|
|
|
|
|
- vertex->at(0) = {x + 0, y + 0, 0};
|
|
|
|
|
- vertex->at(1) = {x + w, y + 0, 0};
|
|
|
|
|
- vertex->at(2) = {x + w, y + h, 0};
|
|
|
|
|
- vertex->at(3) = {x + 0, y + h, 0};
|
|
|
|
|
- vertex->dirty();
|
|
|
|
|
- dirtyBound();
|
|
|
|
|
- dirtyGLObjects();
|
|
|
|
|
-
|
|
|
|
|
- // disable depth test
|
|
|
|
|
- getOrCreateStateSet()->setMode(GL_DEPTH_TEST,
|
|
|
|
|
- StateAttribute::OVERRIDE | StateAttribute::OFF);
|
|
|
|
|
|
|
+void ImageGeomSP::setViewportRange(const float viewport_aspect,
|
|
|
|
|
+ const bool flip_y) const {
|
|
|
|
|
+ pimpl->set_viewport_range(viewport_aspect, flip_y);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void ImageGeomSP::setImageSP(const sp_image &img) {
|
|
|
|
|
- upload_image_to_texture(img, tex);
|
|
|
|
|
- getOrCreateStateSet()->setTextureAttributeAndModes(
|
|
|
|
|
- 0, tex, StateAttribute::ON);
|
|
|
|
|
|
|
+void ImageGeomSP::setImageSP(const sp_image &img) const {
|
|
|
|
|
+ pimpl->set_image(img);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void ImageGeomSP::setRemapImage(const sp_image &img) {
|
|
|
|
|
- upload_image_to_texture(img, remap_tex);
|
|
|
|
|
- if (remap_tex) {
|
|
|
|
|
- getOrCreateStateSet()->setTextureAttributeAndModes(
|
|
|
|
|
- 1, remap_tex, StateAttribute::ON);
|
|
|
|
|
- } else {
|
|
|
|
|
- getOrCreateStateSet()->setTextureAttributeAndModes(
|
|
|
|
|
- 1, 0, StateAttribute::OFF);
|
|
|
|
|
- }
|
|
|
|
|
- setup_program(this);
|
|
|
|
|
|
|
+void ImageGeomSP::setImageTex(Texture2DSP *tex) const {
|
|
|
|
|
+ pimpl->set_image_tex(tex);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void ImageGeomSP::setViewportRange(const float viewport_aspect,
|
|
|
|
|
- const bool flip_y) {
|
|
|
|
|
- if (tex == nullptr) return;
|
|
|
|
|
- simple_rect rect = {-1, -1, 2, 2};
|
|
|
|
|
- auto img_aspect = 1.f * tex->getTextureWidth()
|
|
|
|
|
- / tex->getTextureHeight();
|
|
|
|
|
- rect = rect.fit_aspect(img_aspect / viewport_aspect);
|
|
|
|
|
- if (flip_y) {
|
|
|
|
|
- rect.y *= -1;
|
|
|
|
|
- rect.height *= -1;
|
|
|
|
|
- }
|
|
|
|
|
- setViewportRange(rect);
|
|
|
|
|
|
|
+void ImageGeomSP::setRemapImage(const sp_image &img) const {
|
|
|
|
|
+ pimpl->set_remap_image(img);
|
|
|
}
|
|
}
|