70 |
70 |
71 print("OpenGL ERROR: at %1:%2: %3", Basename(QString(file)), line, errmsg); |
71 print("OpenGL ERROR: at %1:%2: %3", Basename(QString(file)), line, errmsg); |
72 } |
72 } |
73 |
73 |
74 |
74 |
75 GLCompiler::GLCompiler(GLRenderer* renderer) : |
75 GLCompiler::GLCompiler(LDDocument* document, GLRenderer* renderer) : |
76 HierarchyElement(renderer), |
76 document {document}, |
77 m_renderer(renderer) |
77 renderer {renderer} {} |
78 { |
|
79 needMerge(); |
|
80 memset(m_vboSizes, 0, sizeof m_vboSizes); |
|
81 } |
|
82 |
78 |
83 |
79 |
84 void GLCompiler::initialize() |
80 void GLCompiler::initialize() |
85 { |
81 { |
86 initializeOpenGLFunctions(); |
82 initializeOpenGLFunctions(); |
87 glGenBuffers(NumVbos, &m_vbo[0]); |
83 glGenBuffers(NumVbos, &vboIndices[0]); |
88 CHECK_GL_ERROR(); |
84 CHECK_GL_ERROR(); |
89 } |
85 } |
90 |
86 |
91 |
87 |
92 GLCompiler::~GLCompiler() |
88 GLCompiler::~GLCompiler() |
93 { |
89 { |
94 glDeleteBuffers(NumVbos, &m_vbo[0]); |
90 glDeleteBuffers(NumVbos, &vboIndices[0]); |
95 CHECK_GL_ERROR(); |
91 CHECK_GL_ERROR(); |
96 } |
92 } |
97 |
93 |
98 |
94 /* |
|
95 * Returns a color that represents this object index. There are 256³ possible |
|
96 * colors, so that many indices can be bijectively addressed with colorss. |
|
97 */ |
99 QColor GLCompiler::indexColorForID(int id) const |
98 QColor GLCompiler::indexColorForID(int id) const |
100 { |
99 { |
101 // Calculate a color based from this index. This method caters for |
100 int red = (id / 0x10000) % 0x100; |
102 // 16777216 objects. I don't think that will be exceeded anytime soon. :) |
101 int green = (id / 0x100) % 0x100; |
103 int r = (id / 0x10000) % 0x100, |
102 int blue = id % 0x100; |
104 g = (id / 0x100) % 0x100, |
103 |
105 b = id % 0x100; |
104 return {red, green, blue}; |
106 |
105 } |
107 return QColor(r, g, b); |
106 |
|
107 |
|
108 QColor blend(QColor baseColor, QColor blendColor, double intensity) |
|
109 { |
|
110 double red = baseColor.redF(); |
|
111 red += blendColor.redF() * intensity; |
|
112 red /= (intensity + 1.0); |
|
113 double green = baseColor.greenF(); |
|
114 green += blendColor.greenF() * intensity; |
|
115 green /= (intensity + 1.0); |
|
116 double blue = baseColor.blueF(); |
|
117 blue += blendColor.blueF() * intensity; |
|
118 blue /= (intensity + 1.0); |
|
119 return {int(round(red)), int(round(green)), int(round(blue))}; |
108 } |
120 } |
109 |
121 |
110 |
122 |
111 QColor GLCompiler::getColorForPolygon(LDPolygon& poly, LDObject* topobj, ComplementVboType complement) const |
123 QColor GLCompiler::getColorForPolygon(LDPolygon& poly, LDObject* topobj, ComplementVboType complement) const |
112 { |
124 { |
113 QColor qcol; |
125 QColor color; |
114 static const QColor bfcFrontColor(64, 192, 80); |
|
115 static const QColor bfcBackColor(208, 64, 64); |
|
116 |
126 |
117 switch(complement) |
127 switch(complement) |
118 { |
128 { |
119 case SurfacesVboComplement: |
129 case SurfacesVboComplement: |
120 case NumVboComplements: |
130 case NumVboComplements: |
121 return QColor(); |
131 return {}; |
122 |
132 |
123 case BfcFrontColorsVboComplement: |
133 case BfcFrontColorsVboComplement: |
124 qcol = bfcFrontColor; |
134 color = bfcFrontColor; |
125 break; |
135 break; |
126 |
136 |
127 case BfcBackColorsVboComplement: |
137 case BfcBackColorsVboComplement: |
128 qcol = bfcBackColor; |
138 color = bfcBackColor; |
129 break; |
139 break; |
130 |
140 |
131 case PickColorsVboComplement: |
141 case PickColorsVboComplement: |
132 return indexColorForID(topobj->id()); |
142 return indexColorForID(topobj->id()); |
133 |
143 |
134 case RandomColorsVboComplement: |
144 case RandomColorsVboComplement: |
135 qcol = topobj->randomColor(); |
145 color = topobj->randomColor(); |
136 break; |
146 break; |
137 |
147 |
138 case NormalColorsVboComplement: |
148 case NormalColorsVboComplement: |
139 if (poly.color == MainColor) |
149 if (poly.color == MainColor) |
140 { |
150 { |
141 if (topobj->color() == MainColor) |
151 if (topobj->color() == MainColor) |
142 qcol = guiUtilities()->mainColorRepresentation(); |
152 color = mainColorRepresentation(); |
143 else |
153 else |
144 qcol = topobj->color().faceColor(); |
154 color = topobj->color().faceColor(); |
145 } |
155 } |
146 else if (poly.color == EdgeColor) |
156 else if (poly.color == EdgeColor) |
147 { |
157 { |
148 qcol = luma(QColor(config->backgroundColor())) > 40 ? Qt::black : Qt::white; |
158 if (luma(config->backgroundColor()) > 40) |
|
159 color = Qt::black; |
|
160 else |
|
161 color = Qt::white; |
149 } |
162 } |
150 else |
163 else |
151 { |
164 { |
152 LDColor col = poly.color; |
165 LDColor colorInfo = poly.color; |
153 |
166 |
154 if (col.isValid()) |
167 if (colorInfo.isValid()) |
155 qcol = col.faceColor(); |
168 color = colorInfo.faceColor(); |
156 } |
169 } |
157 break; |
170 break; |
158 } |
171 } |
159 |
172 |
160 if (not qcol.isValid()) |
173 if (not color.isValid()) |
161 { |
174 { |
162 // The color was unknown. Use main color to make the polygon at least |
175 // The color was unknown. Use main color to make the polygon at least |
163 // not appear pitch-black. |
176 // not appear pitch-black. |
164 if (poly.num != 2 and poly.num != 5) |
177 if (poly.num != 2 and poly.num != 5) |
165 qcol = guiUtilities()->mainColorRepresentation(); |
178 color = mainColorRepresentation(); |
166 else |
179 else |
167 qcol = Qt::black; |
180 color = Qt::black; |
168 |
181 |
169 // Warn about the unknown color, but only once. |
182 // Warn about the unknown color, but only once. |
170 static QList<int> warnedColors; |
183 static QSet<int> warnedColors; |
171 if (not warnedColors.contains(poly.color)) |
184 if (not warnedColors.contains(poly.color)) |
172 { |
185 { |
173 print("Unknown color %1!\n", poly.color); |
186 print("Unknown color %1!\n", poly.color); |
174 warnedColors << poly.color; |
187 warnedColors.insert(poly.color); |
175 } |
188 } |
176 |
189 |
177 return qcol; |
190 return color; |
178 } |
191 } |
179 |
192 |
180 double blendAlpha = 0.0; |
193 double blendAlpha = 0.0; |
181 |
194 |
182 if (topobj->isSelected()) |
195 if (topobj->isSelected()) |
183 blendAlpha = 1.0; |
196 blendAlpha = 1.0; |
184 else if (topobj == m_renderer->objectAtCursor()) |
197 else if (topobj == renderer->objectAtCursor()) |
185 blendAlpha = 0.5; |
198 blendAlpha = 0.5; |
186 |
199 |
187 if (blendAlpha != 0.0) |
200 color = blend(color, config->selectColorBlend(), blendAlpha); |
188 { |
201 return color; |
189 QColor selcolor(config->selectColorBlend()); |
|
190 double denom = blendAlpha + 1.0; |
|
191 qcol.setRed((qcol.red() +(selcolor.red() * blendAlpha)) / denom); |
|
192 qcol.setGreen((qcol.green() +(selcolor.green() * blendAlpha)) / denom); |
|
193 qcol.setBlue((qcol.blue() +(selcolor.blue() * blendAlpha)) / denom); |
|
194 } |
|
195 |
|
196 return qcol; |
|
197 } |
202 } |
198 |
203 |
199 |
204 |
200 void GLCompiler::needMerge() |
205 void GLCompiler::needMerge() |
201 { |
206 { |
202 for (int i = 0; i < countof(m_vboChanged); ++i) |
207 for (bool& changed_flag : this->vboChanged) |
203 m_vboChanged[i] = true; |
208 changed_flag = true; |
204 } |
209 } |
205 |
210 |
206 |
211 |
207 void GLCompiler::stageForCompilation(LDObject* obj) |
212 void GLCompiler::stageForCompilation(LDObject* obj) |
208 { |
213 { |
209 /* |
214 stagedObjects << obj; |
210 g_objectOrigins[obj] = format("%1:%2(%3)", |
|
211 obj->document()->getDisplayName(), obj->lineNumber(), obj->typeName()); |
|
212 */ |
|
213 |
|
214 m_staged << obj; |
|
215 } |
215 } |
216 |
216 |
217 |
217 |
218 void GLCompiler::unstage(LDObject* obj) |
218 void GLCompiler::unstage(LDObject* obj) |
219 { |
219 { |
220 m_staged.remove(obj); |
220 stagedObjects.remove(obj); |
221 } |
221 } |
222 |
222 |
223 |
223 |
224 void GLCompiler::compileDocument(LDDocument* doc) |
224 void GLCompiler::compileDocument(LDDocument* document) |
225 { |
225 { |
226 if (doc) |
226 if (document) |
227 { |
227 { |
228 for (LDObject* obj : doc->objects()) |
228 for (LDObject* obj : document->objects()) |
229 compileObject(obj); |
229 compileObject(obj); |
230 } |
230 } |
231 } |
231 } |
232 |
232 |
233 |
233 |
234 void GLCompiler::compileStaged() |
234 void GLCompiler::compileStaged() |
235 { |
235 { |
236 for (QSetIterator<LDObject*> it(m_staged); it.hasNext();) |
236 for (QSetIterator<LDObject*> it(stagedObjects); it.hasNext();) |
237 compileObject(it.next()); |
237 compileObject(it.next()); |
238 |
238 |
239 m_staged.clear(); |
239 stagedObjects.clear(); |
240 } |
240 } |
241 |
241 |
242 |
242 |
243 void GLCompiler::prepareVBO(int vbonum) |
243 void GLCompiler::prepareVBO(int vbonum) |
244 { |
244 { |
245 // Compile anything that still awaits it |
245 // Compile anything that still awaits it |
246 compileStaged(); |
246 compileStaged(); |
247 |
247 |
248 if (not m_vboChanged[vbonum]) |
248 if (not vboChanged[vbonum]) |
249 return; |
249 { |
250 |
250 print("Merging %1", vbonum); |
251 QVector<GLfloat> vbodata; |
251 QVector<GLfloat> vbodata; |
252 |
252 |
253 for (auto it = m_objectInfo.begin(); it != m_objectInfo.end();) |
253 for (auto it = objectInfo.begin(); it != objectInfo.end();) |
254 { |
254 { |
255 if (it.key() == nullptr) |
255 if (it.key() == nullptr) |
256 { |
256 { |
257 it = m_objectInfo.erase(it); |
257 it = objectInfo.erase(it); |
258 continue; |
258 } |
259 } |
259 else |
260 |
260 { |
261 if (it.key()->document() == currentDocument() and not it.key()->isHidden()) |
261 if (not it.key()->isHidden()) |
262 vbodata += it->data[vbonum]; |
262 vbodata += it->data[vbonum]; |
263 |
263 |
264 ++it; |
264 ++it; |
265 } |
265 } |
266 |
266 } |
267 glBindBuffer(GL_ARRAY_BUFFER, m_vbo[vbonum]); |
267 |
268 glBufferData(GL_ARRAY_BUFFER, vbodata.size() * sizeof(GLfloat), vbodata.constData(), GL_STATIC_DRAW); |
268 glBindBuffer(GL_ARRAY_BUFFER, vboIndices[vbonum]); |
269 glBindBuffer(GL_ARRAY_BUFFER, 0); |
269 glBufferData( |
270 CHECK_GL_ERROR(); |
270 GL_ARRAY_BUFFER, |
271 m_vboChanged[vbonum] = false; |
271 vbodata.size() * sizeof(GLfloat), |
272 m_vboSizes[vbonum] = vbodata.size(); |
272 vbodata.constData(), |
|
273 GL_STATIC_DRAW); |
|
274 glBindBuffer(GL_ARRAY_BUFFER, 0); |
|
275 CHECK_GL_ERROR(); |
|
276 vboChanged[vbonum] = false; |
|
277 vboSizes[vbonum] = vbodata.size(); |
|
278 } |
273 } |
279 } |
274 |
280 |
275 |
281 |
276 void GLCompiler::dropObjectInfo(LDObject* obj) |
282 void GLCompiler::dropObjectInfo(LDObject* obj) |
277 { |
283 { |
278 if (m_objectInfo.contains(obj)) |
284 if (objectInfo.contains(obj)) |
279 { |
285 { |
280 m_objectInfo.remove(obj); |
286 objectInfo.remove(obj); |
281 needMerge(); |
287 needMerge(); |
282 } |
288 } |
283 } |
289 } |
284 |
290 |
285 |
291 |