--- a/src/polygoncache.cpp Tue Jun 28 22:18:11 2022 +0300 +++ b/src/polygoncache.cpp Wed Jun 29 14:11:58 2022 +0300 @@ -29,101 +29,106 @@ } } -static std::vector<WithId<PolygonElement>> getPolygonsAt( +template<typename Fn, typename Fn2> +static void collectPolygons( + const ModelElement& element, + Winding& winding, + GetPolygonsContext* context, + Fn&& add, + Fn2&& reserve) +{ + std::visit<void>(overloaded{ + [&](const Colored<LineSegment>& edge) { + add({edge, edge.color}); + }, + [&](const Colored<Triangle>& triangle) { + add({triangle, triangle.color}); + }, + [&](const Colored<Quadrilateral>& quad) { + add({quad, quad.color}); + }, + [&](const Colored<ConditionalEdge>& cedge) { + add({cedge, cedge.color}); + }, + [&add, context, &reserve](const Colored<SubfileReference>& ref) { + Model* dependency = context->documents->findDependencyByName(context->modelId, ref.name); + PolygonCache* cache = nullptr; + if (dependency != nullptr) { + cache = findPolygonCacheForModel(dependency, context->documents); + } + if (cache != nullptr) { + const bool needInverting = glm::determinant(ref.transformation) < 0; + recacheIfNeeded(cache, dependency, context->documents); + reserve(cache->polygons.size()); + for (const PolygonElement& cacheElement : cache->polygons) { + PolygonElement polygon = transformed(cacheElement, ref.transformation); + if (needInverting != ref.inverted) { + gl::invert(polygon); + } + if (polygon.color == MAIN_COLOR) { + polygon.color = ref.color; + } + add(polygon); + } + } + }, + [&add](const Colored<CircularPrimitive>& circ) { + rasterize(circ, [&](const PlainPolygonElement& polygon, ColorIndex color){ + if (color == MAIN_COLOR) { + color = circ.color; + } + add(PolygonElement{polygon, color}); + }); + }, + [&winding](const Comment& comment) { + if (comment.text == QStringLiteral("BFC CERTIFY CW")) { + winding = Clockwise; + } + else if (comment.text == QStringLiteral("BFC CERTIFY CCW")) { + winding = Anticlockwise; + } + else if (comment.text == QStringLiteral("BFC NOCERTIFY")) { + winding = NoWinding; + } + }, + [](const ModelElement&) {} + }, element); +} + +static std::vector<WithId<PolygonElement>> inlinePolygons( const Model* model, GetPolygonsContext* context) { + Winding winding = NoWinding; std::vector<WithId<PolygonElement>> result; for (std::size_t i = 0; i < model->size(); i += 1) { const ModelElement& element = (*model)[i]; const ModelId id = model->idAt(i); - std::visit<void>(overloaded{ - [&](const Colored<LineSegment>& edge) { - result.push_back({{edge, edge.color}, id}); - }, - [&](const Colored<Triangle>& triangle) { - result.push_back({{triangle, triangle.color}, id}); - }, - [&](const Colored<Quadrilateral>& quad) { - result.push_back({{quad, quad.color}, id}); - }, - [&](const Colored<ConditionalEdge>& cedge) { - result.push_back({{cedge, cedge.color}, id}); - }, - [&result, &id, context](const Colored<SubfileReference>& ref) { - Model* dependency = context->documents->findDependencyByName(context->modelId, ref.name); - PolygonCache* cache = nullptr; - if (dependency != nullptr) { - cache = findPolygonCacheForModel(dependency, context->documents); + collectPolygons(element, winding, context, + [&result, winding, id](const PolygonElement& poly){ + result.push_back({poly, id}); + if (winding == Winding::Clockwise) { + gl::invert(result.back()); } - if (cache != nullptr) { - const bool needInverting = glm::determinant(ref.transformation) < 0; - const PolygonCache::vector_type* modelPolygons = getCachedPolygons( - cache, - dependency, - context->documents); - reserveMore(result, modelPolygons->size()); - for (WithId<PolygonElement> polygon : *modelPolygons) { - polygon = {transformed(polygon, ref.transformation), polygon.id}; - if (needInverting != ref.inverted) { - gl::invert(polygon); - } - if (polygon.color == MAIN_COLOR) { - polygon.color = ref.color; - } - polygon.id = id; - result.push_back(polygon); - } - } - }, - [&result, id](const Colored<CircularPrimitive>& circ) { - rasterize(circ, [&](const ModelElement& element){ - std::visit<void>(overloaded{ - // TODO: :-( - [&](const Colored<LineSegment>& edge) { - result.push_back({{edge, edge.color}, id}); - }, - [&](const Colored<Triangle>& triangle) { - result.push_back({{triangle, triangle.color}, id}); - }, - [&](const Colored<Quadrilateral>& quad) { - result.push_back({{quad, quad.color}, id}); - }, - [&](const Colored<ConditionalEdge>& cedge) { - result.push_back({{cedge, cedge.color}, id}); - }, - [&](const auto&){}, - }, element); - }); - }, - [](const ModelElement&) {} - }, element); + }, [&result](std::size_t incomingsize){ + reserveMore(result, incomingsize); + }); } return result; } -/** - * @brief Gets a list of GL polygons that are used to represent this model. - * @details Will build polygons if polygons are outdated. - * @param documents Documents to use to resolve subfile references - * @return vector of GL polygons - */ -const PolygonCache::vector_type* getCachedPolygons( - PolygonCache *cache, - Model *model, - DocumentManager *documents) +void recacheIfNeeded(PolygonCache *cache, Model *model, DocumentManager *documents) { if (cache->needRecache) { - cache->cachedPolygons.clear(); + cache->polygons.clear(); const std::optional<ModelId> modelId = documents->findIdForModel(model); if (modelId.has_value()) { GetPolygonsContext context{modelId.value(), documents}; - cache->cachedPolygons = getPolygonsAt(model, &context); + cache->polygons = inlinePolygons(model, &context); } cache->needRecache = false; } - return &cache->cachedPolygons; }