| 27 else { |
27 else { |
| 28 return nullptr; |
28 return nullptr; |
| 29 } |
29 } |
| 30 } |
30 } |
| 31 |
31 |
| 32 static std::vector<WithId<PolygonElement>> getPolygonsAt( |
32 template<typename Fn, typename Fn2> |
| |
33 static void collectPolygons( |
| |
34 const ModelElement& element, |
| |
35 Winding& winding, |
| |
36 GetPolygonsContext* context, |
| |
37 Fn&& add, |
| |
38 Fn2&& reserve) |
| |
39 { |
| |
40 std::visit<void>(overloaded{ |
| |
41 [&](const Colored<LineSegment>& edge) { |
| |
42 add({edge, edge.color}); |
| |
43 }, |
| |
44 [&](const Colored<Triangle>& triangle) { |
| |
45 add({triangle, triangle.color}); |
| |
46 }, |
| |
47 [&](const Colored<Quadrilateral>& quad) { |
| |
48 add({quad, quad.color}); |
| |
49 }, |
| |
50 [&](const Colored<ConditionalEdge>& cedge) { |
| |
51 add({cedge, cedge.color}); |
| |
52 }, |
| |
53 [&add, context, &reserve](const Colored<SubfileReference>& ref) { |
| |
54 Model* dependency = context->documents->findDependencyByName(context->modelId, ref.name); |
| |
55 PolygonCache* cache = nullptr; |
| |
56 if (dependency != nullptr) { |
| |
57 cache = findPolygonCacheForModel(dependency, context->documents); |
| |
58 } |
| |
59 if (cache != nullptr) { |
| |
60 const bool needInverting = glm::determinant(ref.transformation) < 0; |
| |
61 recacheIfNeeded(cache, dependency, context->documents); |
| |
62 reserve(cache->polygons.size()); |
| |
63 for (const PolygonElement& cacheElement : cache->polygons) { |
| |
64 PolygonElement polygon = transformed(cacheElement, ref.transformation); |
| |
65 if (needInverting != ref.inverted) { |
| |
66 gl::invert(polygon); |
| |
67 } |
| |
68 if (polygon.color == MAIN_COLOR) { |
| |
69 polygon.color = ref.color; |
| |
70 } |
| |
71 add(polygon); |
| |
72 } |
| |
73 } |
| |
74 }, |
| |
75 [&add](const Colored<CircularPrimitive>& circ) { |
| |
76 rasterize(circ, [&](const PlainPolygonElement& polygon, ColorIndex color){ |
| |
77 if (color == MAIN_COLOR) { |
| |
78 color = circ.color; |
| |
79 } |
| |
80 add(PolygonElement{polygon, color}); |
| |
81 }); |
| |
82 }, |
| |
83 [&winding](const Comment& comment) { |
| |
84 if (comment.text == QStringLiteral("BFC CERTIFY CW")) { |
| |
85 winding = Clockwise; |
| |
86 } |
| |
87 else if (comment.text == QStringLiteral("BFC CERTIFY CCW")) { |
| |
88 winding = Anticlockwise; |
| |
89 } |
| |
90 else if (comment.text == QStringLiteral("BFC NOCERTIFY")) { |
| |
91 winding = NoWinding; |
| |
92 } |
| |
93 }, |
| |
94 [](const ModelElement&) {} |
| |
95 }, element); |
| |
96 } |
| |
97 |
| |
98 static std::vector<WithId<PolygonElement>> inlinePolygons( |
| 33 const Model* model, |
99 const Model* model, |
| 34 GetPolygonsContext* context) |
100 GetPolygonsContext* context) |
| 35 { |
101 { |
| |
102 Winding winding = NoWinding; |
| 36 std::vector<WithId<PolygonElement>> result; |
103 std::vector<WithId<PolygonElement>> result; |
| 37 for (std::size_t i = 0; i < model->size(); i += 1) |
104 for (std::size_t i = 0; i < model->size(); i += 1) |
| 38 { |
105 { |
| 39 const ModelElement& element = (*model)[i]; |
106 const ModelElement& element = (*model)[i]; |
| 40 const ModelId id = model->idAt(i); |
107 const ModelId id = model->idAt(i); |
| 41 std::visit<void>(overloaded{ |
108 collectPolygons(element, winding, context, |
| 42 [&](const Colored<LineSegment>& edge) { |
109 [&result, winding, id](const PolygonElement& poly){ |
| 43 result.push_back({{edge, edge.color}, id}); |
110 result.push_back({poly, id}); |
| 44 }, |
111 if (winding == Winding::Clockwise) { |
| 45 [&](const Colored<Triangle>& triangle) { |
112 gl::invert(result.back()); |
| 46 result.push_back({{triangle, triangle.color}, id}); |
|
| 47 }, |
|
| 48 [&](const Colored<Quadrilateral>& quad) { |
|
| 49 result.push_back({{quad, quad.color}, id}); |
|
| 50 }, |
|
| 51 [&](const Colored<ConditionalEdge>& cedge) { |
|
| 52 result.push_back({{cedge, cedge.color}, id}); |
|
| 53 }, |
|
| 54 [&result, &id, context](const Colored<SubfileReference>& ref) { |
|
| 55 Model* dependency = context->documents->findDependencyByName(context->modelId, ref.name); |
|
| 56 PolygonCache* cache = nullptr; |
|
| 57 if (dependency != nullptr) { |
|
| 58 cache = findPolygonCacheForModel(dependency, context->documents); |
|
| 59 } |
113 } |
| 60 if (cache != nullptr) { |
114 }, [&result](std::size_t incomingsize){ |
| 61 const bool needInverting = glm::determinant(ref.transformation) < 0; |
115 reserveMore(result, incomingsize); |
| 62 const PolygonCache::vector_type* modelPolygons = getCachedPolygons( |
116 }); |
| 63 cache, |
|
| 64 dependency, |
|
| 65 context->documents); |
|
| 66 reserveMore(result, modelPolygons->size()); |
|
| 67 for (WithId<PolygonElement> polygon : *modelPolygons) { |
|
| 68 polygon = {transformed(polygon, ref.transformation), polygon.id}; |
|
| 69 if (needInverting != ref.inverted) { |
|
| 70 gl::invert(polygon); |
|
| 71 } |
|
| 72 if (polygon.color == MAIN_COLOR) { |
|
| 73 polygon.color = ref.color; |
|
| 74 } |
|
| 75 polygon.id = id; |
|
| 76 result.push_back(polygon); |
|
| 77 } |
|
| 78 } |
|
| 79 }, |
|
| 80 [&result, id](const Colored<CircularPrimitive>& circ) { |
|
| 81 rasterize(circ, [&](const ModelElement& element){ |
|
| 82 std::visit<void>(overloaded{ |
|
| 83 // TODO: :-( |
|
| 84 [&](const Colored<LineSegment>& edge) { |
|
| 85 result.push_back({{edge, edge.color}, id}); |
|
| 86 }, |
|
| 87 [&](const Colored<Triangle>& triangle) { |
|
| 88 result.push_back({{triangle, triangle.color}, id}); |
|
| 89 }, |
|
| 90 [&](const Colored<Quadrilateral>& quad) { |
|
| 91 result.push_back({{quad, quad.color}, id}); |
|
| 92 }, |
|
| 93 [&](const Colored<ConditionalEdge>& cedge) { |
|
| 94 result.push_back({{cedge, cedge.color}, id}); |
|
| 95 }, |
|
| 96 [&](const auto&){}, |
|
| 97 }, element); |
|
| 98 }); |
|
| 99 }, |
|
| 100 [](const ModelElement&) {} |
|
| 101 }, element); |
|
| 102 } |
117 } |
| 103 return result; |
118 return result; |
| 104 } |
119 } |
| 105 |
120 |
| 106 /** |
121 void recacheIfNeeded(PolygonCache *cache, Model *model, DocumentManager *documents) |
| 107 * @brief Gets a list of GL polygons that are used to represent this model. |
|
| 108 * @details Will build polygons if polygons are outdated. |
|
| 109 * @param documents Documents to use to resolve subfile references |
|
| 110 * @return vector of GL polygons |
|
| 111 */ |
|
| 112 const PolygonCache::vector_type* getCachedPolygons( |
|
| 113 PolygonCache *cache, |
|
| 114 Model *model, |
|
| 115 DocumentManager *documents) |
|
| 116 { |
122 { |
| 117 if (cache->needRecache) |
123 if (cache->needRecache) |
| 118 { |
124 { |
| 119 cache->cachedPolygons.clear(); |
125 cache->polygons.clear(); |
| 120 const std::optional<ModelId> modelId = documents->findIdForModel(model); |
126 const std::optional<ModelId> modelId = documents->findIdForModel(model); |
| 121 if (modelId.has_value()) |
127 if (modelId.has_value()) |
| 122 { |
128 { |
| 123 GetPolygonsContext context{modelId.value(), documents}; |
129 GetPolygonsContext context{modelId.value(), documents}; |
| 124 cache->cachedPolygons = getPolygonsAt(model, &context); |
130 cache->polygons = inlinePolygons(model, &context); |
| 125 } |
131 } |
| 126 cache->needRecache = false; |
132 cache->needRecache = false; |
| 127 } |
133 } |
| 128 return &cache->cachedPolygons; |
|
| 129 } |
134 } |