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 } |