# HG changeset patch # User Teemu Piippo # Date 1656501118 -10800 # Node ID d891da20abcac670eef66e8b18659e4eea458d51 # Parent 5d280bceb713c5db629f4d7c6829438f65f95eec Add support for BFC CERTIFY statements diff -r 5d280bceb713 -r d891da20abca src/circularprimitive.h --- a/src/circularprimitive.h Tue Jun 28 22:18:11 2022 +0300 +++ b/src/circularprimitive.h Wed Jun 29 14:11:58 2022 +0300 @@ -17,23 +17,23 @@ case CircularPrimitive::Circle: ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&] (const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){ - fn(edge(xform(p1, 0), xform(p2, 0))); + fn(LineSegment{xform(p1, 0), xform(p2, 0)}, EDGE_COLOR); }); break; case CircularPrimitive::Disc: ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&] (const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){ - fn(triangle(primitiveOrigin, xform(p1, 0), xform(p2, 0))); + fn(Triangle{primitiveOrigin, xform(p1, 0), xform(p2, 0)}, MAIN_COLOR); }); break; case CircularPrimitive::Cylinder: ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&] (const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){ - Colored quad = quadrilateral(xform(p1, 1), xform(p2, 1), xform(p2, 0), xform(p1, 0)); + Quadrilateral quad{xform(p1, 1), xform(p2, 1), xform(p2, 0), xform(p1, 0)}; if (invertedMatrix) { std::swap(quad.p2, quad.p4); } - fn(quad); + fn(quad, MAIN_COLOR); }); break; case CircularPrimitive::CylinderOpen: @@ -77,7 +77,7 @@ {+1, -1}, }; const glm::vec2& corner = corners[i * 4 / circ.fraction.divisions]; - fn(triangle(xform(p2, 0), xform(p1, 0), xform(corner, 0))); + fn(Triangle{xform(p2, 0), xform(p1, 0), xform(corner, 0)}, MAIN_COLOR); ++i; }); } @@ -86,7 +86,7 @@ for (unsigned int i = 1; i < circ.fraction.segments; ++i) { const glm::vec2& p1 = ldraw::rimpoint(circ.fraction.divisions, i); const glm::vec2& p2 = ldraw::rimpoint(circ.fraction.divisions, i + 1); - fn(triangle(xform(p2, 0), xform(p1, 0), xform({1, 0}, 0))); + fn(Triangle{xform(p2, 0), xform(p1, 0), xform({1, 0}, 0)}, MAIN_COLOR); } break; } diff -r 5d280bceb713 -r d891da20abca src/gl/compiler.cpp --- a/src/gl/compiler.cpp Tue Jun 28 22:18:11 2022 +0300 +++ b/src/gl/compiler.cpp Wed Jun 29 14:11:58 2022 +0300 @@ -224,10 +224,10 @@ template void iterateModelPolygons(Model* model, DocumentManager* context, Fn&& fn) { - PolygonCache* cache = findPolygonCacheForModel(model, context); + PolygonCache* const cache = findPolygonCacheForModel(model, context); if (cache != nullptr) { - const PolygonCache::vector_type* polygons = getCachedPolygons(cache, model, context); - for (const WithId& polygon : *polygons) { + recacheIfNeeded(cache, model, context); + for (const WithId& polygon : cache->polygons) { fn(polygon); } } diff -r 5d280bceb713 -r d891da20abca src/layers/edittools.cpp --- a/src/layers/edittools.cpp Tue Jun 28 22:18:11 2022 +0300 +++ b/src/layers/edittools.cpp Wed Jun 29 14:11:58 2022 +0300 @@ -141,7 +141,19 @@ painter->drawPolygon(QPolygonF{convertWorldPointsToScreenPoints(points, renderer)}); } -static std::vector> modelActionPoints(const ModelAction& action) +//! \brief Conversion function from PlainPolygonElement to ModelElement +ModelElement elementFromPolygonAndColor(const PlainPolygonElement& poly, ColorIndex color) +{ + // use std::visit with a templated lambda to resolve the type of poly. + return std::visit([color](const auto& resolvedPoly) -> ModelElement { + // unlike with normal templates we need to pry out the type out manually + using PolygonType = std::decay_t; + // add color and return as a model element. + return Colored{resolvedPoly, color}; + }, poly); +} + +static std::vector> polygonsToBeInserted(const ModelAction& action) { std::vector> result; if (const AppendToModel* append = std::get_if(&action)) { @@ -156,8 +168,10 @@ result.push_back({quad->p1, quad->p2, quad->p3, quad->p4}); } else if (const CircularPrimitive* circ = std::get_if>(&newElement)) { - rasterize(*circ, [&](const ModelElement& element){ - const auto& subpoints = modelActionPoints(AppendToModel{element}); + // rasterize the circle down to polygons, and append them to the result. + rasterize(*circ, [&](const PlainPolygonElement& poly, const ColorIndex color){ + AppendToModel append{elementFromPolygonAndColor(poly, color)}; + const auto& subpoints = polygonsToBeInserted(append); std::copy(subpoints.begin(), subpoints.end(), std::back_inserter(result)); }); } @@ -232,7 +246,7 @@ const Pens& pens = *reinterpret_cast(pensptr); painter->setPen(pens.polygonPen); for (const ModelAction& action : this->modelActions()) { - for (const std::vector& points : modelActionPoints(action)) { + for (const std::vector& points : polygonsToBeInserted(action)) { if (points.size() == 2) { drawWorldPolyline(painter, points, renderer); } diff -r 5d280bceb713 -r d891da20abca src/model.h --- a/src/model.h Tue Jun 28 22:18:11 2022 +0300 +++ b/src/model.h Wed Jun 29 14:11:58 2022 +0300 @@ -108,11 +108,13 @@ Empty, ParseError>; -using PolygonElement = Colored>; + ConditionalEdge>; + +using PolygonElement = Colored; template struct remove_color {}; diff -r 5d280bceb713 -r d891da20abca src/polygoncache.cpp --- 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> getPolygonsAt( +template +static void collectPolygons( + const ModelElement& element, + Winding& winding, + GetPolygonsContext* context, + Fn&& add, + Fn2&& reserve) +{ + std::visit(overloaded{ + [&](const Colored& edge) { + add({edge, edge.color}); + }, + [&](const Colored& triangle) { + add({triangle, triangle.color}); + }, + [&](const Colored& quad) { + add({quad, quad.color}); + }, + [&](const Colored& cedge) { + add({cedge, cedge.color}); + }, + [&add, context, &reserve](const Colored& 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& 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> inlinePolygons( const Model* model, GetPolygonsContext* context) { + Winding winding = NoWinding; std::vector> 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(overloaded{ - [&](const Colored& edge) { - result.push_back({{edge, edge.color}, id}); - }, - [&](const Colored& triangle) { - result.push_back({{triangle, triangle.color}, id}); - }, - [&](const Colored& quad) { - result.push_back({{quad, quad.color}, id}); - }, - [&](const Colored& cedge) { - result.push_back({{cedge, cedge.color}, id}); - }, - [&result, &id, context](const Colored& 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 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& circ) { - rasterize(circ, [&](const ModelElement& element){ - std::visit(overloaded{ - // TODO: :-( - [&](const Colored& edge) { - result.push_back({{edge, edge.color}, id}); - }, - [&](const Colored& triangle) { - result.push_back({{triangle, triangle.color}, id}); - }, - [&](const Colored& quad) { - result.push_back({{quad, quad.color}, id}); - }, - [&](const Colored& 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 = 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; } diff -r 5d280bceb713 -r d891da20abca src/polygoncache.h --- a/src/polygoncache.h Tue Jun 28 22:18:11 2022 +0300 +++ b/src/polygoncache.h Wed Jun 29 14:11:58 2022 +0300 @@ -18,11 +18,11 @@ struct PolygonCache { using vector_type = std::vector>; - vector_type cachedPolygons; + vector_type polygons; bool needRecache = true; }; -const PolygonCache::vector_type* getCachedPolygons( +void recacheIfNeeded( PolygonCache* cache, Model* model, class DocumentManager* documents);