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

View file

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