29 #include "misc.h" |
29 #include "misc.h" |
30 #include "history.h" |
30 #include "history.h" |
31 |
31 |
32 static double g_objOffset[3]; |
32 static double g_objOffset[3]; |
33 |
33 |
34 static short g_pulseTick = 0; |
|
35 static const short g_numPulseTicks = 8; |
|
36 static const short g_pulseInterval = 65; |
|
37 |
|
38 static const struct staticCameraMeta { |
34 static const struct staticCameraMeta { |
39 const char glrotate[3]; |
35 const char glrotate[3]; |
40 const Axis axisX, axisY; |
36 const Axis axisX, axisY; |
41 const bool negX, negY; |
37 const bool negX, negY; |
42 } g_staticCameras[6] = { |
38 } g_staticCameras[6] = { |
51 cfg (str, gl_bgcolor, "#CCCCD9"); |
47 cfg (str, gl_bgcolor, "#CCCCD9"); |
52 cfg (str, gl_maincolor, "#707078"); |
48 cfg (str, gl_maincolor, "#707078"); |
53 cfg (float, gl_maincolor_alpha, 1.0); |
49 cfg (float, gl_maincolor_alpha, 1.0); |
54 cfg (int, gl_linethickness, 2); |
50 cfg (int, gl_linethickness, 2); |
55 cfg (bool, gl_colorbfc, true); |
51 cfg (bool, gl_colorbfc, true); |
56 cfg (bool, gl_selflash, false); |
|
57 cfg (int, gl_camera, GLRenderer::Free); |
52 cfg (int, gl_camera, GLRenderer::Free); |
58 cfg (bool, gl_blackedges, true); |
53 cfg (bool, gl_blackedges, true); |
59 cfg (bool, gl_axes, false); |
54 cfg (bool, gl_axes, false); |
60 |
55 |
61 // CameraIcon::img is a heap-allocated QPixmap because otherwise it gets |
56 // CameraIcon::img is a heap-allocated QPixmap because otherwise it gets |
96 m_picking = m_rangepick = false; |
91 m_picking = m_rangepick = false; |
97 m_camera = (GLRenderer::Camera) gl_camera.value; |
92 m_camera = (GLRenderer::Camera) gl_camera.value; |
98 m_drawToolTip = false; |
93 m_drawToolTip = false; |
99 m_planeDraw = false; |
94 m_planeDraw = false; |
100 |
95 |
101 m_pulseTimer = new QTimer (this); |
|
102 connect (m_pulseTimer, SIGNAL (timeout ()), this, SLOT (slot_timerUpdate ())); |
|
103 |
|
104 m_toolTipTimer = new QTimer (this); |
96 m_toolTipTimer = new QTimer (this); |
105 m_toolTipTimer->setSingleShot (true); |
97 m_toolTipTimer->setSingleShot (true); |
106 connect (m_toolTipTimer, SIGNAL (timeout ()), this, SLOT (slot_toolTipTimer ())); |
98 connect (m_toolTipTimer, SIGNAL (timeout ()), this, SLOT (slot_toolTipTimer ())); |
107 |
99 |
108 m_thickBorderPen = QPen (QColor (0, 0, 0, 208), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); |
100 m_thickBorderPen = QPen (QColor (0, 0, 0, 208), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); |
129 } |
121 } |
130 |
122 |
131 // ============================================================================= |
123 // ============================================================================= |
132 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
124 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
133 // ============================================================================= |
125 // ============================================================================= |
134 void GLRenderer::calcCameraIconRects () { |
126 void GLRenderer::calcCameraIcons () { |
135 ushort i = 0; |
127 ushort i = 0; |
136 |
128 |
137 for (CameraIcon& info : g_CameraIcons) { |
129 for (CameraIcon& info : g_CameraIcons) { |
138 const long x1 = (m_width - (info.cam != Free ? 48 : 16)) + ((i % 3) * 16) - 1, |
130 const long x1 = (m_width - (info.cam != Free ? 48 : 16)) + ((i % 3) * 16) - 1, |
139 y1 = ((i / 3) * 16) + 1; |
131 y1 = ((i / 3) * 16) + 1; |
165 glLineWidth (gl_linethickness); |
157 glLineWidth (gl_linethickness); |
166 |
158 |
167 setAutoFillBackground (false); |
159 setAutoFillBackground (false); |
168 setMouseTracking (true); |
160 setMouseTracking (true); |
169 setFocusPolicy (Qt::WheelFocus); |
161 setFocusPolicy (Qt::WheelFocus); |
170 compileObjects (); |
162 compileAllObjects (); |
171 } |
163 } |
172 |
164 |
173 // ============================================================================= |
165 // ============================================================================= |
174 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
166 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
175 // ============================================================================= |
167 // ============================================================================= |
197 } |
189 } |
198 |
190 |
199 // ============================================================================= |
191 // ============================================================================= |
200 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
192 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
201 // ============================================================================= |
193 // ============================================================================= |
202 static vector<short> g_daWarnedColors; |
194 static vector<short> g_warnedColors; |
203 void GLRenderer::setObjectColor (LDObject* obj, const ListType list) { |
195 void GLRenderer::setObjectColor (LDObject* obj, const ListType list) { |
204 QColor qcol; |
196 QColor qcol; |
205 |
197 |
206 if (!obj->isColored ()) |
198 if (!obj->isColored ()) |
207 return; |
199 return; |
208 |
200 |
209 if (list == GL::PickList) { |
201 if (list == GL::PickList) { |
210 // Make the color by the object's index color if we're picking, so we can |
202 // Make the color by the object's index color if we're picking, so we can |
211 // make the index from the color we get from the picking results. |
203 // make the index from the color we get from the picking results. Be sure |
212 long i = obj->getIndex (g_curfile); |
204 // to use the top level parent's index since inlinees don't have an index. |
213 |
205 long i = obj->topLevelParent ()->getIndex (g_curfile); |
214 // If we couldn't find the index, this object must not be from this file, |
|
215 // therefore it must be an object inlined from a subfile reference or |
|
216 // decomposed from a radial. Find the top level parent object and use |
|
217 // its index. |
|
218 if (i == -1) |
|
219 i = obj->topLevelParent ()->getIndex (g_curfile); |
|
220 |
206 |
221 // We should have the index now. |
207 // We should have the index now. |
222 assert (i != -1); |
208 assert (i != -1); |
223 |
209 |
224 // Calculate a color based from this index. This method caters for |
210 // Calculate a color based from this index. This method caters for |
230 |
216 |
231 qglColor (QColor (r, g, b, 255)); |
217 qglColor (QColor (r, g, b, 255)); |
232 return; |
218 return; |
233 } |
219 } |
234 |
220 |
235 #if 0 |
221 if ((list == BFCFrontList || list == BFCBackList) && |
236 if (gl_colorbfc && |
|
237 obj->getType () != LDObject::Line && |
222 obj->getType () != LDObject::Line && |
238 obj->getType () != LDObject::CondLine) |
223 obj->getType () != LDObject::CondLine) |
239 { |
224 { |
240 if (bBackSide) |
225 if (list == GL::BFCFrontList) |
241 glColor4f (0.9f, 0.0f, 0.0f, 1.0f); |
226 qcol = QColor (80, 192, 0); |
242 else |
227 else |
243 glColor4f (0.0f, 0.8f, 0.0f, 1.0f); |
228 qcol = QColor (224, 0, 0); |
244 return; |
229 } else { |
245 } |
230 if (obj->color == maincolor) |
246 #endif |
|
247 |
|
248 if (obj->color == maincolor) |
|
249 qcol = getMainColor (); |
|
250 else { |
|
251 color* col = getColor (obj->color); |
|
252 qcol = col->faceColor; |
|
253 } |
|
254 |
|
255 if (obj->color == edgecolor) { |
|
256 qcol = Qt::black; |
|
257 color* col; |
|
258 |
|
259 if (!gl_blackedges && obj->parent != null && (col = getColor (obj->parent->color)) != null) |
|
260 qcol = col->edgeColor; |
|
261 } |
|
262 |
|
263 if (qcol.isValid () == false) { |
|
264 // The color was unknown. Use main color to make the object at least |
|
265 // not appear pitch-black. |
|
266 if (obj->color != edgecolor) |
|
267 qcol = getMainColor (); |
231 qcol = getMainColor (); |
268 |
232 else { |
269 // Warn about the unknown colors, but only once. |
233 color* col = getColor (obj->color); |
270 for (short i : g_daWarnedColors) |
234 qcol = col->faceColor; |
271 if (obj->color == i) |
235 } |
272 return; |
236 |
273 |
237 if (obj->color == edgecolor) { |
274 printf ("%s: Unknown color %d!\n", __func__, obj->color); |
238 qcol = Qt::black; |
275 g_daWarnedColors.push_back (obj->color); |
239 color* col; |
276 return; |
240 |
|
241 if (!gl_blackedges && obj->parent != null && (col = getColor (obj->parent->color)) != null) |
|
242 qcol = col->edgeColor; |
|
243 } |
|
244 |
|
245 if (qcol.isValid () == false) { |
|
246 // The color was unknown. Use main color to make the object at least |
|
247 // not appear pitch-black. |
|
248 if (obj->color != edgecolor) |
|
249 qcol = getMainColor (); |
|
250 |
|
251 // Warn about the unknown colors, but only once. |
|
252 for (short i : g_warnedColors) |
|
253 if (obj->color == i) |
|
254 return; |
|
255 |
|
256 printf ("%s: Unknown color %d!\n", __func__, obj->color); |
|
257 g_warnedColors.push_back (obj->color); |
|
258 return; |
|
259 } |
277 } |
260 } |
278 |
261 |
279 long r = qcol.red (), |
262 long r = qcol.red (), |
280 g = qcol.green (), |
263 g = qcol.green (), |
281 b = qcol.blue (), |
264 b = qcol.blue (), |
282 a = qcol.alpha (); |
265 a = qcol.alpha (); |
283 |
266 |
284 // Brighten it up for the select list. |
267 if (obj->topLevelParent ()->selected ()) { |
285 if (list == GL::SelectList) { |
268 // Brighten it up for the select list. |
286 const uchar add = 51; |
269 const uchar add = 51; |
|
270 |
287 r = min (r + add, 255l); |
271 r = min (r + add, 255l); |
288 g = min (g + add, 255l); |
272 g = min (g + add, 255l); |
289 b = min (b + add, 255l); |
273 b = min (b + add, 255l); |
290 } |
274 } |
291 |
275 |
317 // ============================================================================= |
301 // ============================================================================= |
318 void GLRenderer::resizeGL (int w, int h) { |
302 void GLRenderer::resizeGL (int w, int h) { |
319 m_width = w; |
303 m_width = w; |
320 m_height = h; |
304 m_height = h; |
321 |
305 |
322 calcCameraIconRects (); |
306 calcCameraIcons (); |
323 |
307 |
324 glViewport (0, 0, w, h); |
308 glViewport (0, 0, w, h); |
325 glMatrixMode (GL_PROJECTION); |
309 glMatrixMode (GL_PROJECTION); |
326 glLoadIdentity (); |
310 glLoadIdentity (); |
327 gluPerspective (45.0f, (double)w / (double)h, 1.0f, 10000.0f); |
311 gluPerspective (45.0f, (double)w / (double)h, 1.0f, 10000.0f); |
361 glRotatef (m_rotX, 1.0f, 0.0f, 0.0f); |
345 glRotatef (m_rotX, 1.0f, 0.0f, 0.0f); |
362 glRotatef (m_rotY, 0.0f, 1.0f, 0.0f); |
346 glRotatef (m_rotY, 0.0f, 1.0f, 0.0f); |
363 glRotatef (m_rotZ, 0.0f, 0.0f, 1.0f); |
347 glRotatef (m_rotZ, 0.0f, 0.0f, 1.0f); |
364 } |
348 } |
365 |
349 |
366 for (LDObject* obj : g_curfile->m_objs) { |
350 if (gl_colorbfc && !m_picking) { |
367 if (obj->hidden ()) |
351 glEnable (GL_CULL_FACE); |
368 continue; // Don't draw hidden objects |
352 |
369 |
353 for (LDObject* obj : g_curfile->m_objs) { |
370 glCallList (obj->glLists[(m_picking) ? PickList : (obj->selected ()) ? SelectList : NormalList]); |
354 if (obj->hidden ()) |
|
355 continue; |
|
356 |
|
357 glCullFace (GL_BACK); |
|
358 glCallList (obj->glLists[BFCFrontList]); |
|
359 |
|
360 glCullFace (GL_FRONT); |
|
361 glCallList (obj->glLists[BFCBackList]); |
|
362 } |
|
363 |
|
364 glDisable (GL_CULL_FACE); |
|
365 } else { |
|
366 for (LDObject* obj : g_curfile->m_objs) { |
|
367 if (obj->hidden ()) |
|
368 continue; |
|
369 |
|
370 glCallList (obj->glLists[(m_picking) ? PickList : NormalList]); |
|
371 } |
371 } |
372 } |
372 |
373 |
373 if (gl_axes && !m_picking) |
374 if (gl_axes && !m_picking) |
374 glCallList (m_axeslist); |
375 glCallList (m_axeslist); |
375 |
376 |
596 } |
597 } |
597 |
598 |
598 // ============================================================================= |
599 // ============================================================================= |
599 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
600 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
600 // ============================================================================= |
601 // ============================================================================= |
601 void GLRenderer::compileObjects () { |
602 void GLRenderer::compileAllObjects () { |
602 if (g_BBox.empty () == false) { |
603 if (g_BBox.empty () == false) { |
603 g_objOffset[X] = -(g_BBox.v0 ()[X] + g_BBox.v1 ()[X]) / 2; |
604 g_objOffset[X] = -(g_BBox.v0 ()[X] + g_BBox.v1 ()[X]) / 2; |
604 g_objOffset[Y] = -(g_BBox.v0 ()[Y] + g_BBox.v1 ()[Y]) / 2; |
605 g_objOffset[Y] = -(g_BBox.v0 ()[Y] + g_BBox.v1 ()[Y]) / 2; |
605 g_objOffset[Z] = -(g_BBox.v0 ()[Z] + g_BBox.v1 ()[Z]) / 2; |
606 g_objOffset[Z] = -(g_BBox.v0 ()[Z] + g_BBox.v1 ()[Z]) / 2; |
606 } else { |
607 } else { |
630 } |
631 } |
631 |
632 |
632 // ============================================================================= |
633 // ============================================================================= |
633 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
634 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
634 // ============================================================================= |
635 // ============================================================================= |
|
636 static bool g_glInvert = false; |
|
637 |
635 void GLRenderer::compileSubObject (LDObject* obj, const GLenum gltype) { |
638 void GLRenderer::compileSubObject (LDObject* obj, const GLenum gltype) { |
636 glBegin (gltype); |
639 glBegin (gltype); |
637 |
640 |
638 const short numverts = (obj->getType () != LDObject::CondLine) ? obj->vertices () : 2; |
641 const short numverts = (obj->getType () != LDObject::CondLine) ? obj->vertices () : 2; |
639 |
642 |
640 for (short i = 0; i < numverts; ++i) |
643 if (g_glInvert == false) |
641 compileVertex (obj->coords[i]); |
644 for (short i = 0; i < numverts; ++i) |
|
645 compileVertex (obj->coords[i]); |
|
646 else |
|
647 for (short i = numverts - 1; i >= 0; --i) |
|
648 compileVertex (obj->coords[i]); |
642 |
649 |
643 glEnd (); |
650 glEnd (); |
644 } |
651 } |
645 |
652 |
646 // ============================================================================= |
653 // ============================================================================= |
676 case LDObject::Subfile: |
683 case LDObject::Subfile: |
677 { |
684 { |
678 LDSubfile* ref = static_cast<LDSubfile*> (obj); |
685 LDSubfile* ref = static_cast<LDSubfile*> (obj); |
679 vector<LDObject*> objs = ref->inlineContents (true, true); |
686 vector<LDObject*> objs = ref->inlineContents (true, true); |
680 |
687 |
|
688 bool oldinvert = g_glInvert; |
|
689 |
|
690 if (ref->transform.determinant () < 0) |
|
691 g_glInvert = !g_glInvert; |
|
692 |
|
693 LDObject* prev = ref->prev (); |
|
694 if (prev->getType () == LDObject::BFC && static_cast<LDBFC*> (prev)->type == LDBFC::InvertNext) |
|
695 g_glInvert = !g_glInvert; |
|
696 |
681 for (LDObject* obj : objs) { |
697 for (LDObject* obj : objs) { |
682 compileList (obj, list); |
698 compileList (obj, list); |
683 delete obj; |
699 delete obj; |
684 } |
700 } |
|
701 |
|
702 g_glInvert = oldinvert; |
685 } |
703 } |
686 break; |
704 break; |
687 |
705 |
688 case LDObject::Radial: |
706 case LDObject::Radial: |
689 { |
707 { |
690 LDRadial* pRadial = static_cast<LDRadial*> (obj); |
708 LDRadial* rad = static_cast<LDRadial*> (obj); |
691 std::vector<LDObject*> objs = pRadial->decompose (true); |
709 std::vector<LDObject*> objs = rad->decompose (true); |
|
710 |
|
711 bool oldinvert = g_glInvert; |
|
712 if (rad->transform.determinant () < 0) |
|
713 g_glInvert = !g_glInvert; |
|
714 |
|
715 LDObject* prev = rad->prev (); |
|
716 if (prev->getType () == LDObject::BFC && static_cast<LDBFC*> (prev)->type == LDBFC::InvertNext) |
|
717 g_glInvert = !g_glInvert; |
692 |
718 |
693 for (LDObject* obj : objs) { |
719 for (LDObject* obj : objs) { |
694 compileList (obj, list); |
720 compileList (obj, list); |
695 delete obj; |
721 delete obj; |
696 } |
722 } |
|
723 |
|
724 g_glInvert = oldinvert; |
697 } |
725 } |
698 break; |
726 break; |
699 |
727 |
700 #if 0 |
728 #if 0 |
701 TODO: find a proper way to draw vertices without having them be affected by zoom. |
729 TODO: find a proper way to draw vertices without having them be affected by zoom. |
896 } |
924 } |
897 |
925 |
898 // ============================================================================= |
926 // ============================================================================= |
899 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
927 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
900 // ============================================================================= |
928 // ============================================================================= |
901 void GLRenderer::updateSelFlash () { |
|
902 if (gl_selflash && g_win->sel ().size() > 0) { |
|
903 m_pulseTimer->start (g_pulseInterval); |
|
904 g_pulseTick = 0; |
|
905 } else |
|
906 m_pulseTimer->stop (); |
|
907 } |
|
908 |
|
909 // ============================================================================= |
|
910 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
911 // ============================================================================= |
|
912 void GLRenderer::pick (uint mouseX, uint mouseY) { |
929 void GLRenderer::pick (uint mouseX, uint mouseY) { |
913 // Check if we selected a camera icon |
930 // Check if we selected a camera icon |
914 if (!m_rangepick) { |
931 if (!m_rangepick) { |
915 QPoint pos (mouseX, mouseY); |
932 QPoint pos (mouseX, mouseY); |
916 |
933 |
928 // Clear the selection if we do not wish to add to it. |
945 // Clear the selection if we do not wish to add to it. |
929 if (!m_addpick) { |
946 if (!m_addpick) { |
930 std::vector<LDObject*> oldsel = g_win->sel (); |
947 std::vector<LDObject*> oldsel = g_win->sel (); |
931 g_win->sel ().clear (); |
948 g_win->sel ().clear (); |
932 |
949 |
933 for (LDObject* obj : oldsel) |
950 for (LDObject* obj : oldsel) { |
|
951 obj->setSelected (false); |
934 compileObject (obj); |
952 compileObject (obj); |
|
953 } |
935 } |
954 } |
936 |
955 |
937 m_picking = true; |
956 m_picking = true; |
938 |
957 |
939 // Paint the picking scene |
958 // Paint the picking scene |
940 glDisable (GL_DITHER); |
959 glDisable (GL_DITHER); |
941 glClearColor (1.0f, 1.0f, 1.0f, 1.0f); |
960 glClearColor (1.0f, 1.0f, 1.0f, 1.0f); |
|
961 |
942 drawGLScene (); |
962 drawGLScene (); |
943 |
963 |
944 glGetIntegerv (GL_VIEWPORT, viewport); |
964 glGetIntegerv (GL_VIEWPORT, viewport); |
945 |
965 |
946 short x0 = mouseX, |
966 short x0 = mouseX, |
1032 |
1053 |
1033 // Recompile the objects now to update their color |
1054 // Recompile the objects now to update their color |
1034 for (LDObject* obj : sel) |
1055 for (LDObject* obj : sel) |
1035 compileObject (obj); |
1056 compileObject (obj); |
1036 |
1057 |
|
1058 if (removedObj) |
|
1059 compileObject (removedObj); |
|
1060 |
1037 m_picking = false; |
1061 m_picking = false; |
1038 m_rangepick = false; |
1062 m_rangepick = false; |
1039 glEnable (GL_DITHER); |
1063 glEnable (GL_DITHER); |
1040 |
1064 |
1041 setBackground (); |
1065 setBackground (); |
1042 updateSelFlash (); |
|
1043 |
|
1044 update (); |
1066 update (); |
1045 } |
1067 } |
1046 |
1068 |
1047 // ============================================================================= |
1069 // ============================================================================= |
1048 void GLRenderer::beginPlaneDraw () { |
1070 void GLRenderer::beginPlaneDraw () { |