For placefile icons, only buffer texture data on texture atlas update

This commit is contained in:
Dan Paulat 2023-09-01 23:35:30 -05:00
parent 854d4a43db
commit 44030fdf87
2 changed files with 200 additions and 78 deletions

View file

@ -25,9 +25,12 @@ static constexpr std::size_t kNumRectangles = 1;
static constexpr std::size_t kNumTriangles = kNumRectangles * 2; static constexpr std::size_t kNumTriangles = kNumRectangles * 2;
static constexpr std::size_t kVerticesPerTriangle = 3; static constexpr std::size_t kVerticesPerTriangle = 3;
static constexpr std::size_t kVerticesPerRectangle = kVerticesPerTriangle * 2; static constexpr std::size_t kVerticesPerRectangle = kVerticesPerTriangle * 2;
static constexpr std::size_t kPointsPerVertex = 11; static constexpr std::size_t kPointsPerVertex = 9;
static constexpr std::size_t kBufferLength = static constexpr std::size_t kPointsPerTexCoord = 2;
static constexpr std::size_t kIconBufferLength =
kNumTriangles * kVerticesPerTriangle * kPointsPerVertex; kNumTriangles * kVerticesPerTriangle * kPointsPerVertex;
static constexpr std::size_t kTextureBufferLength =
kNumTriangles * kVerticesPerTriangle * kPointsPerTexCoord;
struct PlacefileIconInfo struct PlacefileIconInfo
{ {
@ -84,6 +87,7 @@ public:
~Impl() {} ~Impl() {}
void UpdateBuffers(); void UpdateBuffers();
void UpdateTextureBuffer();
void Update(bool textureAtlasChanged); void Update(bool textureAtlasChanged);
std::shared_ptr<GlContext> context_; std::shared_ptr<GlContext> context_;
@ -101,11 +105,18 @@ public:
currentIconList_ {}; currentIconList_ {};
std::vector<std::shared_ptr<const gr::Placefile::IconDrawItem>> std::vector<std::shared_ptr<const gr::Placefile::IconDrawItem>>
newIconList_ {}; newIconList_ {};
std::vector<std::shared_ptr<const gr::Placefile::IconDrawItem>>
newValidIconList_ {};
std::vector<IconHoverEntry> hoverIcons_ {}; std::vector<float> currentIconBuffer_ {};
std::vector<GLint> currentThresholdBuffer_ {};
std::vector<float> newIconBuffer_ {};
std::vector<GLint> newThresholdBuffer_ {};
std::vector<float> iconBuffer_ {}; std::vector<float> textureBuffer_ {};
std::vector<GLint> thresholdBuffer_ {};
std::vector<IconHoverEntry> currentHoverIcons_ {};
std::vector<IconHoverEntry> newHoverIcons_ {};
std::shared_ptr<ShaderProgram> shaderProgram_; std::shared_ptr<ShaderProgram> shaderProgram_;
GLint uMVPMatrixLocation_; GLint uMVPMatrixLocation_;
@ -114,7 +125,7 @@ public:
GLint uMapDistanceLocation_; GLint uMapDistanceLocation_;
GLuint vao_; GLuint vao_;
std::array<GLuint, 2> vbo_; std::array<GLuint, 3> vbo_;
GLsizei numVertices_; GLsizei numVertices_;
}; };
@ -150,7 +161,7 @@ void PlacefileIcons::Initialize()
p->shaderProgram_->GetUniformLocation("uMapDistance"); p->shaderProgram_->GetUniformLocation("uMapDistance");
gl.glGenVertexArrays(1, &p->vao_); gl.glGenVertexArrays(1, &p->vao_);
gl.glGenBuffers(2, p->vbo_.data()); gl.glGenBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
gl.glBindVertexArray(p->vao_); gl.glBindVertexArray(p->vao_);
gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]);
@ -174,22 +185,13 @@ void PlacefileIcons::Initialize()
reinterpret_cast<void*>(2 * sizeof(float))); reinterpret_cast<void*>(2 * sizeof(float)));
gl.glEnableVertexAttribArray(1); gl.glEnableVertexAttribArray(1);
// aTexCoord
gl.glVertexAttribPointer(2,
2,
GL_FLOAT,
GL_FALSE,
kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(4 * sizeof(float)));
gl.glEnableVertexAttribArray(2);
// aModulate // aModulate
gl.glVertexAttribPointer(3, gl.glVertexAttribPointer(3,
4, 4,
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(6 * sizeof(float))); reinterpret_cast<void*>(4 * sizeof(float)));
gl.glEnableVertexAttribArray(3); gl.glEnableVertexAttribArray(3);
// aAngle // aAngle
@ -198,12 +200,24 @@ void PlacefileIcons::Initialize()
GL_FLOAT, GL_FLOAT,
GL_FALSE, GL_FALSE,
kPointsPerVertex * sizeof(float), kPointsPerVertex * sizeof(float),
reinterpret_cast<void*>(10 * sizeof(float))); reinterpret_cast<void*>(8 * sizeof(float)));
gl.glEnableVertexAttribArray(4); gl.glEnableVertexAttribArray(4);
gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]);
gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// aTexCoord
gl.glVertexAttribPointer(2,
2,
GL_FLOAT,
GL_FALSE,
kPointsPerTexCoord * sizeof(float),
static_cast<void*>(0));
gl.glEnableVertexAttribArray(2);
gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[2]);
gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW);
// aThreshold // aThreshold
gl.glVertexAttribIPointer(5, // gl.glVertexAttribIPointer(5, //
1, 1,
@ -260,15 +274,16 @@ void PlacefileIcons::Deinitialize()
gl::OpenGLFunctions& gl = p->context_->gl(); gl::OpenGLFunctions& gl = p->context_->gl();
gl.glDeleteVertexArrays(1, &p->vao_); gl.glDeleteVertexArrays(1, &p->vao_);
gl.glDeleteBuffers(2, p->vbo_.data()); gl.glDeleteBuffers(static_cast<GLsizei>(p->vbo_.size()), p->vbo_.data());
std::unique_lock lock {p->iconMutex_}; std::unique_lock lock {p->iconMutex_};
p->currentIconList_.clear(); p->currentIconList_.clear();
p->currentIconFiles_.clear(); p->currentIconFiles_.clear();
p->hoverIcons_.clear(); p->currentHoverIcons_.clear();
p->iconBuffer_.clear(); p->currentIconBuffer_.clear();
p->thresholdBuffer_.clear(); p->currentThresholdBuffer_.clear();
p->textureBuffer_.clear();
} }
void PlacefileIconInfo::UpdateTextureInfo() void PlacefileIconInfo::UpdateTextureInfo()
@ -306,7 +321,11 @@ void PlacefileIcons::StartIcons()
{ {
// Clear the new buffer // Clear the new buffer
p->newIconList_.clear(); p->newIconList_.clear();
p->newValidIconList_.clear();
p->newIconFiles_.clear(); p->newIconFiles_.clear();
p->newIconBuffer_.clear();
p->newThresholdBuffer_.clear();
p->newHoverIcons_.clear();
} }
void PlacefileIcons::SetIconFiles( void PlacefileIcons::SetIconFiles(
@ -334,15 +353,31 @@ void PlacefileIcons::AddIcon(
void PlacefileIcons::FinishIcons() void PlacefileIcons::FinishIcons()
{ {
// Update icon files
for (auto& iconFile : p->newIconFiles_)
{
iconFile.second.UpdateTextureInfo();
}
// Update buffers
p->UpdateBuffers();
std::unique_lock lock {p->iconMutex_}; std::unique_lock lock {p->iconMutex_};
// Swap buffers // Swap buffers
p->currentIconList_.swap(p->newIconList_); p->currentIconList_.swap(p->newValidIconList_);
p->currentIconFiles_.swap(p->newIconFiles_); p->currentIconFiles_.swap(p->newIconFiles_);
p->currentIconBuffer_.swap(p->newIconBuffer_);
p->currentThresholdBuffer_.swap(p->newThresholdBuffer_);
p->currentHoverIcons_.swap(p->newHoverIcons_);
// Clear the new buffers // Clear the new buffers
p->newIconList_.clear(); p->newIconList_.clear();
p->newValidIconList_.clear();
p->newIconFiles_.clear(); p->newIconFiles_.clear();
p->newIconBuffer_.clear();
p->newThresholdBuffer_.clear();
p->newHoverIcons_.clear();
// Mark the draw item dirty // Mark the draw item dirty
p->dirty_ = true; p->dirty_ = true;
@ -350,17 +385,15 @@ void PlacefileIcons::FinishIcons()
void PlacefileIcons::Impl::UpdateBuffers() void PlacefileIcons::Impl::UpdateBuffers()
{ {
iconBuffer_.clear(); newIconBuffer_.clear();
iconBuffer_.reserve(currentIconList_.size() * kBufferLength); newIconBuffer_.reserve(newIconList_.size() * kIconBufferLength);
thresholdBuffer_.clear(); newThresholdBuffer_.clear();
thresholdBuffer_.reserve(currentIconList_.size() * kVerticesPerRectangle); newThresholdBuffer_.reserve(newIconList_.size() * kVerticesPerRectangle);
hoverIcons_.clear();
numVertices_ = 0;
for (auto& di : currentIconList_) for (auto& di : newIconList_)
{ {
auto it = currentIconFiles_.find(di->fileNumber_); auto it = newIconFiles_.find(di->fileNumber_);
if (it == currentIconFiles_.cend()) if (it == newIconFiles_.cend())
{ {
// No file found // No file found
logger_->trace("Could not find file number: {}", di->fileNumber_); logger_->trace("Could not find file number: {}", di->fileNumber_);
@ -377,6 +410,9 @@ void PlacefileIcons::Impl::UpdateBuffers()
continue; continue;
} }
// Icon is valid, add to valid icon list
newValidIconList_.push_back(di);
// Threshold value // Threshold value
units::length::nautical_miles<double> threshold = di->threshold_; units::length::nautical_miles<double> threshold = di->threshold_;
GLint thresholdValue = static_cast<GLint>(std::round(threshold.value())); GLint thresholdValue = static_cast<GLint>(std::round(threshold.value()));
@ -407,42 +443,29 @@ void PlacefileIcons::Impl::UpdateBuffers()
units::angle::degrees<float> angle = di->angle_; units::angle::degrees<float> angle = di->angle_;
const float a = angle.value(); const float a = angle.value();
// Texture coordinates
const std::size_t iconRow = (di->iconNumber_ - 1) / icon.columns_;
const std::size_t iconColumn = (di->iconNumber_ - 1) % icon.columns_;
const float iconX = iconColumn * icon.scaledWidth_;
const float iconY = iconRow * icon.scaledHeight_;
const float ls = icon.texture_.sLeft_ + iconX;
const float rs = ls + icon.scaledWidth_;
const float tt = icon.texture_.tTop_ + iconY;
const float bt = tt + icon.scaledHeight_;
// Fixed modulate color // Fixed modulate color
const float mc0 = 1.0f; const float mc0 = 1.0f;
const float mc1 = 1.0f; const float mc1 = 1.0f;
const float mc2 = 1.0f; const float mc2 = 1.0f;
const float mc3 = 1.0f; const float mc3 = 1.0f;
iconBuffer_.insert( newIconBuffer_.insert(newIconBuffer_.end(),
iconBuffer_.end(), {
{ // Icon
// Icon lat, lon, lx, by, mc0, mc1, mc2, mc3, a, // BL
lat, lon, lx, by, ls, bt, mc0, mc1, mc2, mc3, a, // BL lat, lon, lx, ty, mc0, mc1, mc2, mc3, a, // TL
lat, lon, lx, ty, ls, tt, mc0, mc1, mc2, mc3, a, // TL lat, lon, rx, by, mc0, mc1, mc2, mc3, a, // BR
lat, lon, rx, by, rs, bt, mc0, mc1, mc2, mc3, a, // BR lat, lon, rx, by, mc0, mc1, mc2, mc3, a, // BR
lat, lon, rx, by, rs, bt, mc0, mc1, mc2, mc3, a, // BR lat, lon, rx, ty, mc0, mc1, mc2, mc3, a, // TR
lat, lon, rx, ty, rs, tt, mc0, mc1, mc2, mc3, a, // TR lat, lon, lx, ty, mc0, mc1, mc2, mc3, a // TL
lat, lon, lx, ty, ls, tt, mc0, mc1, mc2, mc3, a // TL });
}); newThresholdBuffer_.insert(newThresholdBuffer_.end(),
thresholdBuffer_.insert(thresholdBuffer_.end(), {thresholdValue, //
{thresholdValue, // thresholdValue,
thresholdValue, thresholdValue,
thresholdValue, thresholdValue,
thresholdValue, thresholdValue,
thresholdValue, thresholdValue});
thresholdValue});
if (!di->hoverText_.empty()) if (!di->hoverText_.empty())
{ {
@ -460,15 +483,105 @@ void PlacefileIcons::Impl::UpdateBuffers()
const glm::vec2 obl = rotate * glm::vec2 {lx, by}; const glm::vec2 obl = rotate * glm::vec2 {lx, by};
const glm::vec2 obr = rotate * glm::vec2 {rx, by}; const glm::vec2 obr = rotate * glm::vec2 {rx, by};
hoverIcons_.emplace_back(IconHoverEntry {di, sc, otl, otr, obl, obr}); newHoverIcons_.emplace_back(
IconHoverEntry {di, sc, otl, otr, obl, obr});
} }
} }
}
dirty_ = true; void PlacefileIcons::Impl::UpdateTextureBuffer()
{
textureBuffer_.clear();
textureBuffer_.reserve(currentIconList_.size() * kTextureBufferLength);
for (auto& di : currentIconList_)
{
auto it = currentIconFiles_.find(di->fileNumber_);
if (it == currentIconFiles_.cend())
{
// No file found
logger_->trace("Could not find file number: {}", di->fileNumber_);
// Should not get here, but insert empty data to match up with data
// already buffered
// clang-format off
textureBuffer_.insert(
textureBuffer_.end(),
{
// Icon
0.0f, 0.0f, // BL
0.0f, 0.0f, // TL
0.0f, 0.0f, // BR
0.0f, 0.0f, // BR
0.0f, 0.0f, // TR
0.0f, 0.0f // TL
});
// clang-format on
continue;
}
auto& icon = it->second;
// Validate icon
if (di->iconNumber_ == 0 || di->iconNumber_ > icon.numIcons_)
{
// No icon found
logger_->trace("Invalid icon number: {}", di->iconNumber_);
// Will get here if a texture changes, and the texture shrunk such that
// the icon is no longer found
// clang-format off
textureBuffer_.insert(
textureBuffer_.end(),
{
// Icon
0.0f, 0.0f, // BL
0.0f, 0.0f, // TL
0.0f, 0.0f, // BR
0.0f, 0.0f, // BR
0.0f, 0.0f, // TR
0.0f, 0.0f // TL
});
// clang-format on
continue;
}
// Texture coordinates
const std::size_t iconRow = (di->iconNumber_ - 1) / icon.columns_;
const std::size_t iconColumn = (di->iconNumber_ - 1) % icon.columns_;
const float iconX = iconColumn * icon.scaledWidth_;
const float iconY = iconRow * icon.scaledHeight_;
const float ls = icon.texture_.sLeft_ + iconX;
const float rs = ls + icon.scaledWidth_;
const float tt = icon.texture_.tTop_ + iconY;
const float bt = tt + icon.scaledHeight_;
// clang-format off
textureBuffer_.insert(
textureBuffer_.end(),
{
// Icon
ls, bt, // BL
ls, tt, // TL
rs, bt, // BR
rs, bt, // BR
rs, tt, // TR
ls, tt // TL
});
// clang-format on
}
} }
void PlacefileIcons::Impl::Update(bool textureAtlasChanged) void PlacefileIcons::Impl::Update(bool textureAtlasChanged)
{ {
gl::OpenGLFunctions& gl = context_->gl();
// If the texture atlas has changed // If the texture atlas has changed
if (dirty_ || textureAtlasChanged) if (dirty_ || textureAtlasChanged)
{ {
@ -478,27 +591,36 @@ void PlacefileIcons::Impl::Update(bool textureAtlasChanged)
iconFile.second.UpdateTextureInfo(); iconFile.second.UpdateTextureInfo();
} }
// Update OpenGL buffer data // Update OpenGL texture buffer data
UpdateBuffers(); UpdateTextureBuffer();
gl::OpenGLFunctions& gl = context_->gl(); // Buffer texture data
gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]);
gl.glBufferData(GL_ARRAY_BUFFER,
sizeof(float) * textureBuffer_.size(),
textureBuffer_.data(),
GL_DYNAMIC_DRAW);
}
// If buffers need updating
if (dirty_)
{
// Buffer vertex data // Buffer vertex data
gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[0]);
gl.glBufferData(GL_ARRAY_BUFFER, gl.glBufferData(GL_ARRAY_BUFFER,
sizeof(float) * iconBuffer_.size(), sizeof(float) * currentIconBuffer_.size(),
iconBuffer_.data(), currentIconBuffer_.data(),
GL_DYNAMIC_DRAW); GL_DYNAMIC_DRAW);
// Buffer threshold data // Buffer threshold data
gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[2]);
gl.glBufferData(GL_ARRAY_BUFFER, gl.glBufferData(GL_ARRAY_BUFFER,
sizeof(GLint) * thresholdBuffer_.size(), sizeof(GLint) * currentThresholdBuffer_.size(),
thresholdBuffer_.data(), currentThresholdBuffer_.data(),
GL_DYNAMIC_DRAW); GL_DYNAMIC_DRAW);
numVertices_ = numVertices_ = static_cast<GLsizei>(currentIconBuffer_.size() /
static_cast<GLsizei>(iconBuffer_.size() / kVerticesPerRectangle); kVerticesPerRectangle);
} }
dirty_ = false; dirty_ = false;
@ -530,8 +652,8 @@ bool PlacefileIcons::RunMousePicking(
// For each pickable icon // For each pickable icon
auto it = std::find_if( auto it = std::find_if(
std::execution::par_unseq, std::execution::par_unseq,
p->hoverIcons_.crbegin(), p->currentHoverIcons_.crbegin(),
p->hoverIcons_.crend(), p->currentHoverIcons_.crend(),
[&mapDistance, &mapMatrix, &mousePos](const auto& icon) [&mapDistance, &mapMatrix, &mousePos](const auto& icon)
{ {
if ( if (
@ -574,7 +696,7 @@ bool PlacefileIcons::RunMousePicking(
return util::maplibre::IsPointInPolygon({tl, bl, br, tr}, mousePos); return util::maplibre::IsPointInPolygon({tl, bl, br, tr}, mousePos);
}); });
if (it != p->hoverIcons_.crend()) if (it != p->currentHoverIcons_.crend())
{ {
itemPicked = true; itemPicked = true;
util::ImGui::Instance().DrawTooltip(it->di_->hoverText_); util::ImGui::Instance().DrawTooltip(it->di_->hoverText_);

View file

@ -62,10 +62,10 @@ PlacefileLayer::PlacefileLayer(const std::shared_ptr<MapContext>& context,
DrawLayer(context), DrawLayer(context),
p(std::make_unique<PlacefileLayer::Impl>(this, context, placefileName)) p(std::make_unique<PlacefileLayer::Impl>(this, context, placefileName))
{ {
AddDrawItem(p->placefileIcons_);
AddDrawItem(p->placefilePolygons_); AddDrawItem(p->placefilePolygons_);
AddDrawItem(p->placefileTriangles_); AddDrawItem(p->placefileTriangles_);
AddDrawItem(p->placefileLines_); AddDrawItem(p->placefileLines_);
AddDrawItem(p->placefileIcons_);
AddDrawItem(p->placefileText_); AddDrawItem(p->placefileText_);
ReloadData(); ReloadData();