Files
MapLibreParticleLab/src/mbgl/gfx/drawable_builder.cpp
2023-08-31 15:36:19 +02:00

261 lines
9.5 KiB
C++

#include <mbgl/gfx/drawable_builder.hpp>
#include <mbgl/gfx/drawable_builder_impl.hpp>
#include <mbgl/gfx/drawable_impl.hpp>
#include <mbgl/renderer/render_pass.hpp>
#include <mbgl/util/logging.hpp>
namespace mbgl {
namespace gfx {
DrawableBuilder::DrawableBuilder(std::string name_)
: name(std::move(name_)),
vertexAttrName("a_pos"),
colorAttrName("a_color"),
renderPass(RenderPass::Opaque),
impl(std::make_unique<Impl>()) {}
DrawableBuilder::~DrawableBuilder() = default;
const Color& DrawableBuilder::getColor() const {
return impl->currentColor;
}
void DrawableBuilder::setColor(const Color& value) {
impl->currentColor = value;
}
const gfx::CullFaceMode& DrawableBuilder::getCullFaceMode() const {
return impl->cullFaceMode;
}
void DrawableBuilder::setCullFaceMode(const gfx::CullFaceMode& value) {
impl->cullFaceMode = value;
}
const UniqueDrawable& DrawableBuilder::getCurrentDrawable(bool createIfNone) {
if (!currentDrawable && createIfNone) {
currentDrawable = createDrawable();
}
return currentDrawable;
}
void DrawableBuilder::flush() {
if (!impl->vertices.empty()) {
const auto& draw = getCurrentDrawable(/*createIfNone=*/true);
draw->setLineWidth(static_cast<int32_t>(lineWidth));
draw->setNeedsStencil(needsStencil);
draw->setRenderPass(renderPass);
draw->setDrawPriority(drawPriority);
draw->setSubLayerIndex(subLayerIndex);
draw->setDepthType(depthType);
draw->setCullFaceMode(impl->cullFaceMode);
draw->setShader(shader);
draw->setTextures(textures);
draw->setTextureSources(textureSources);
if (auto drawAttrs = getVertexAttributes().clone()) {
vertexAttrs.observeAttributes([&](const std::string& iName, const VertexAttribute& iAttr) {
if (auto& drawAttr = drawAttrs->getOrAdd(iName)) {
if (iAttr.getCount() == 1) {
// Apply the value to all vertexes
for (std::size_t i = 0; i < impl->vertices.elements(); ++i) {
drawAttr->setVariant(i, iAttr.get(0));
}
} else if (iAttr.getCount() == impl->vertices.elements()) {
for (std::size_t i = 0; i < impl->vertices.elements(); ++i) {
drawAttr->setVariant(i, iAttr.get(i));
}
} else {
// throw?
Log::Warning(Event::General, "Invalid attribute count");
}
}
});
draw->setVertexAttributes(std::move(*drawAttrs));
}
init();
}
if (currentDrawable) {
drawables.emplace_back(std::move(currentDrawable));
}
}
util::SimpleIdentity DrawableBuilder::getDrawableId() {
return currentDrawable ? currentDrawable->getId() : util::SimpleIdentity::Empty;
}
DrawPriority DrawableBuilder::getDrawPriority() const {
return drawPriority;
}
void DrawableBuilder::setDrawPriority(DrawPriority value) {
drawPriority = value;
if (currentDrawable) {
currentDrawable->setDrawPriority(value);
}
}
void DrawableBuilder::resetDrawPriority(DrawPriority value) {
setDrawPriority(value);
for (auto& drawble : drawables) {
drawble->setDrawPriority(value);
}
}
void DrawableBuilder::setTexture(const std::shared_ptr<gfx::Texture2D>& texture, int32_t location) {
for (auto& tex : textures) {
if (tex.location == location) {
tex.texture = texture;
return;
}
}
textures.emplace_back(texture, location);
}
void DrawableBuilder::setTextureSource(int32_t location, TexSourceFunc source) {
textureSources.resize(std::max(textureSources.size(), static_cast<size_t>(location + 1)));
textureSources[location] = std::move(source);
}
void DrawableBuilder::addTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2) {
const auto n = static_cast<uint16_t>(impl->vertices.elements());
impl->vertices.emplace_back(Impl::VT({{{x0, y0}}}));
impl->vertices.emplace_back(Impl::VT({{{x1, y1}}}));
impl->vertices.emplace_back(Impl::VT({{{x2, y2}}}));
impl->indexes.insert(impl->indexes.end(), {n, static_cast<uint16_t>(n + 1), static_cast<uint16_t>(n + 2)});
if (colorAttrMode == ColorAttrMode::PerVertex) {
impl->colors.insert(impl->colors.end(), 3, impl->currentColor);
}
if (impl->segments.empty()) {
impl->segments.emplace_back(createSegment(gfx::Triangles(), {0, 0}));
}
auto& segment = impl->segments.back();
segment->getSegment().vertexLength += 3;
segment->getSegment().indexLength += 3;
}
void DrawableBuilder::appendTriangle(int16_t x0, int16_t y0) {
const auto n = (uint16_t)impl->vertices.elements();
impl->vertices.emplace_back(Impl::VT({{{x0, y0}}}));
impl->indexes.insert(impl->indexes.end(), {static_cast<uint16_t>(n - 2), static_cast<uint16_t>(n - 1), n});
if (colorAttrMode == ColorAttrMode::PerVertex) {
impl->colors.emplace_back(impl->currentColor);
}
assert(!impl->segments.empty());
auto& segment = impl->segments.back();
segment->getSegment().vertexLength += 1;
segment->getSegment().indexLength += 3;
}
void DrawableBuilder::addQuad(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {
addTriangle(x0, y0, x1, y0, x0, y1);
appendTriangle(x1, y1);
}
void DrawableBuilder::setVertexAttributes(const VertexAttributeArray& attrs) {
vertexAttrs = attrs;
}
void DrawableBuilder::setVertexAttributes(VertexAttributeArray&& attrs) {
vertexAttrs = attrs;
}
std::size_t DrawableBuilder::addVertices(const std::vector<std::array<int16_t, 2>>& vertices,
std::size_t vertexOffset,
std::size_t vertexLength) {
const auto baseIndex = impl->vertices.elements();
std::for_each(std::next(vertices.begin(), vertexOffset),
std::next(vertices.begin(), vertexOffset + vertexLength),
[&](const std::array<int16_t, 2>& x) { impl->vertices.emplace_back(Impl::VT({{x}})); });
if (colorAttrMode == ColorAttrMode::PerVertex) {
for (size_t i = 0; i < vertexLength; ++i) {
impl->colors.emplace_back(impl->currentColor);
}
}
return baseIndex;
}
void DrawableBuilder::setSegments(gfx::DrawMode mode,
std::vector<uint16_t> indexes,
const std::vector<SegmentBase>& segments) {
impl->indexes = std::move(indexes);
for (const auto& seg : segments) {
#if !defined(NDEBUG)
if (mode.type == DrawModeType::Triangles) {
assert(seg.indexLength % 3 == 0);
} else if (mode.type == DrawModeType::Lines) {
assert(seg.indexLength % 2 == 0);
}
assert(seg.vertexOffset + seg.vertexLength <= impl->vertices.elements());
assert(seg.indexOffset + seg.indexLength <= impl->indexes.size());
for (decltype(seg.indexLength) i = 0; i < seg.indexLength; ++i) {
assert(impl->indexes[seg.indexOffset + i] < impl->vertices.elements());
}
#endif
auto segCopy = SegmentBase{
// no copy constructor
seg.vertexOffset,
seg.indexOffset,
seg.vertexLength,
seg.indexLength,
seg.sortKey,
};
impl->segments.emplace_back(createSegment(mode, std::move(segCopy)));
}
}
void DrawableBuilder::addLines(const std::vector<uint16_t>& indexes,
std::size_t indexOffset,
std::size_t indexLength,
std::size_t baseIndex) {
if (!indexLength) {
return;
}
impl->segments.emplace_back(createSegment(Lines(lineWidth),
SegmentBase{/*.vertexOffset = */ 0,
/*.indexOffset = */ indexes.size(),
/*.vertexLength = */ 0,
/*.indexLength = */ indexLength}));
if (impl->indexes.empty()) {
impl->indexes.reserve(indexLength);
}
for (auto i = std::next(indexes.begin(), indexOffset); i != std::next(indexes.begin(), indexOffset + indexLength);
++i) {
impl->indexes.emplace_back(static_cast<uint16_t>(*i + baseIndex));
}
}
void DrawableBuilder::addTriangles(const std::vector<uint16_t>& indexes,
std::size_t indexOffset,
std::size_t indexLength,
std::size_t baseIndex) {
if (!indexLength) {
return;
}
impl->segments.emplace_back(createSegment(Triangles(),
SegmentBase{/*.vertexOffset = */ 0,
/*.indexOffset = */ impl->indexes.size(),
/*.vertexLength = */ impl->vertices.elements(),
/*.indexLength = */ indexLength}));
if (impl->indexes.empty()) {
impl->indexes.reserve(indexLength);
}
for (auto i = std::next(indexes.begin(), indexOffset); i != std::next(indexes.begin(), indexOffset + indexLength);
++i) {
impl->indexes.emplace_back(static_cast<uint16_t>(*i + baseIndex));
}
}
} // namespace gfx
} // namespace mbgl