14 #include "graphpainter.h"
15 #include "graphwidget.h"
20 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
31 #define DEFAULT_FONT_SIZE 12
33 #define checkGLError() \
35 GLenum err = glGetError(); \
36 if(err != GL_NO_ERROR) { \
39 case GL_INVALID_ENUM: \
40 dbgPrint("GL_INVALID_ENUM"); \
42 case GL_INVALID_VALUE: \
43 dbgPrint("GL_INVALID_VALUE"); \
45 case GL_INVALID_OPERATION: \
46 dbgPrint("GL_INVALID_OPERATION"); \
48 case GL_STACK_OVERFLOW: \
49 dbgPrint("GL_STACK_OVERFLOW"); \
51 case GL_STACK_UNDERFLOW: \
52 dbgPrint("GL_STACK_UNDERFLOW"); \
54 case GL_OUT_OF_MEMORY: \
55 dbgPrint("GL_OUT_OF_MEMORY"); \
61 XQGraphPainter::XQGraphPainter(
const shared_ptr<XGraph> &graph,
XQGraph* item) :
64 m_selectionStateNow(Selecting),
65 m_selectionModeNow(SelNone),
69 m_listplanemarkers(0),
71 m_bIsRedrawNeeded(true),
72 m_bIsAxisRedrawNeeded(false),
75 item->m_painter.reset(
this);
77 m_lsnRedraw = tr[ *graph].onUpdate().connectWeakly(
78 shared_from_this(), &XQGraphPainter::onRedraw,
79 XListener::FLAG_MAIN_THREAD_CALL | XListener::FLAG_AVOID_DUP | XListener::FLAG_DELAY_ADAPTIVE);
81 m_pixel_ratio = m_pItem->devicePixelRatio();
83 XQGraphPainter::~XQGraphPainter() {
84 m_pItem->makeCurrent();
86 if(m_listplanemarkers) glDeleteLists(m_listplanemarkers, 1);
87 if(m_listaxismarkers) glDeleteLists(m_listaxismarkers, 1);
88 if(m_listgrids) glDeleteLists(m_listgrids, 1);
89 if(m_listaxes) glDeleteLists(m_listaxes, 1);
90 if(m_listpoints) glDeleteLists(m_listpoints, 1);
96 int ret = gluUnProject(x * m_pixel_ratio, (
double)m_viewport[3] - y * m_pixel_ratio, z,
97 m_model, m_proj, m_viewport, &nx, &ny, &nz);
101 return (ret != GL_TRUE);
104 XQGraphPainter::screenToWindow(
const XGraph::ScrPoint &scr,
double *x,
double *y,
double *z) {
106 int ret = gluProject(scr.x, scr.y, scr.z, m_model, m_proj, m_viewport, &nx, &ny, &nz);
107 *x = nx / m_pixel_ratio;
108 *y = (m_viewport[3] - ny) / m_pixel_ratio;
110 return (ret != GL_TRUE);
114 XQGraphPainter::repaintBuffer(
int x1,
int y1,
int x2,
int y2) {
115 if((x1 != x2) || (y1 != y2)) {
121 m_bIsRedrawNeeded =
true;
125 XQGraphPainter::beginLine(
double size) {
131 XQGraphPainter::endLine() {
137 XQGraphPainter::beginPoint(
double size) {
143 XQGraphPainter::endPoint() {
148 XQGraphPainter::beginQuad(
bool ) {
153 XQGraphPainter::endQuad() {
159 XQGraphPainter::defaultFont() {
161 m_curFontSize = std::min(14L, std::max(9L,
162 lrint(DEFAULT_FONT_SIZE * m_pItem->height() / m_pItem->logicalDpiY() / 3.5)));
171 if(screenToWindow(s1, &x, &y, &z))
return -1;
176 if(screenToWindow(s2, &x1, &y1, &z1))
return -1;
182 if(screenToWindow(s3, &x2, &y2, &z2))
return -1;
186 if(screenToWindow(s4, &x3, &y3, &z3))
return -1;
189 double w = fabs(x3 - x2), h = fabs(y3 - y2);
190 if( fabs(x - x1) > fabs( y - y1) ) {
192 align |= Qt::AlignVCenter;
193 h = min(h, 2 * min(y, m_pItem->height() - y));
195 align |= Qt::AlignRight;
199 align |= Qt::AlignLeft;
200 w = m_pItem->width() - x;
205 align |= Qt::AlignHCenter;
206 w = min(w, 2 * min(x, m_pItem->width() - x));
208 align |= Qt::AlignTop;
209 h = m_pItem->height() - y;
212 align |= Qt::AlignBottom;
217 m_curFontSize += sizehint;
218 int fontsize_org = m_curFontSize;
222 QFont font(m_pItem->font());
224 font.setPointSize(m_curFontSize);
225 QFontMetrics fm(font);
226 QRect bb = fm.boundingRect(str);
227 if(m_curFontSize < fontsize_org - 4)
return -1;
228 if((bb.width() < w ) && (bb.height() < h))
break;
238 screenToWindow(p, &x, &y, &z);
240 QFont font(m_pItem->font());
241 font.setPointSize(m_curFontSize);
242 QFontMetrics fm(font);
243 QRect bb = fm.boundingRect(str);
244 if( (m_curAlign & Qt::AlignBottom) ) y -= bb.bottom();
245 if( (m_curAlign & Qt::AlignVCenter) ) y += -bb.bottom() + bb.height() / 2;
246 if( (m_curAlign & Qt::AlignTop) ) y -= bb.top();
247 if( (m_curAlign & Qt::AlignHCenter) ) x -= bb.left() + bb.width() / 2;
248 if( (m_curAlign & Qt::AlignRight) ) x -= bb.right();
255 txt.fontsize = m_curFontSize;
256 txt.rgba = m_curTextColor;
257 m_textOverpaint.push_back(txt);
261 #define VIEW_NEAR -1.5
266 XQGraphPainter::setInitView() {
268 glOrtho(0.0,1.0,0.0,1.0,VIEW_NEAR,VIEW_FAR);
272 m_pItem->makeCurrent();
275 glMatrixMode(GL_PROJECTION);
278 glGetDoublev(GL_PROJECTION_MATRIX, m_proj_rot);
283 glTranslated(0.5, 0.5, 0.5);
284 glRotatef(angle, x, y, z);
285 glTranslated(-0.5, -0.5, -0.5);
286 glMultMatrixd(m_proj_rot);
287 glGetDoublev(GL_PROJECTION_MATRIX, m_proj_rot);
289 glMultMatrixd(m_proj_rot);
294 if(ov != m_bTilted) m_bIsRedrawNeeded =
true;
296 m_bIsAxisRedrawNeeded =
true;
300 #define MAX_SELECTION 100
303 XQGraphPainter::selectGL(
int x,
int y,
int dx,
int dy, GLint list,
305 m_pItem->makeCurrent();
309 GLuint selections[MAX_SELECTION];
310 glGetDoublev(GL_PROJECTION_MATRIX, m_proj);
311 glGetDoublev(GL_MODELVIEW_MATRIX, m_model);
312 glGetIntegerv(GL_VIEWPORT, m_viewport);
313 glSelectBuffer(MAX_SELECTION, selections);
314 glRenderMode(GL_SELECT);
316 glPushName((
unsigned int)-1);
317 glMatrixMode(GL_PROJECTION);
321 gluPickMatrix((
double)(x - dx) * m_pixel_ratio, (
double)m_viewport[3] - (y + dy) * m_pixel_ratio,
322 2 * dx * m_pixel_ratio, 2 * dy * m_pixel_ratio, m_viewport);
323 glMultMatrixd(m_proj);
325 glEnable(GL_DEPTH_TEST);
329 glMatrixMode(GL_PROJECTION);
331 int hits = glRenderMode(GL_RENDER);
334 GLuint *ptr = selections;
335 for (
int i = 0; i < hits; i++) {
336 double zmin1 = (double)ptr[1] / (
double)0xffffffffu;
337 double zmax1 = (double)ptr[2] / (
double)0xffffffffu;
340 for (
int j = 0; j < n; j++) {
343 zmin = min(zmin1, zmin);
344 zmax = max(zmax1, zmax);
348 if((zmin < 1.0) && (zmax > 0.0) ) {
360 return selectGL(x, y, dx, dy, m_listplanemarkers, scr, dsdx, dsdy);
363 XQGraphPainter::selectAxis(
int x,
int y,
int dx,
int dy,
365 return selectGL(x, y, dx, dy, m_listaxismarkers, scr, dsdx, dsdy);
368 XQGraphPainter::selectPoint(
int x,
int y,
int dx,
int dy,
370 return selectGL(x, y, dx, dy, m_listpoints, scr, dsdx, dsdy);
374 initializeOpenGLFunctions();
376 glEnable(GL_MULTISAMPLE);
379 if(m_listplanemarkers) glDeleteLists(m_listplanemarkers, 1);
380 if(m_listaxismarkers) glDeleteLists(m_listaxismarkers, 1);
381 if(m_listgrids) glDeleteLists(m_listgrids, 1);
382 if(m_listaxes) glDeleteLists(m_listaxes, 1);
383 if(m_listpoints) glDeleteLists(m_listpoints, 1);
384 m_listplanemarkers = glGenLists(1);
385 m_listaxismarkers = glGenLists(1);
386 m_listgrids = glGenLists(1);
387 m_listaxes = glGenLists(1);
388 m_listpoints = glGenLists(1);
389 glMatrixMode(GL_PROJECTION);
395 XQGraphPainter::resizeGL (
int width ,
int height ) {
397 glMatrixMode(GL_PROJECTION);
398 m_bIsRedrawNeeded =
true;
405 GLint depth_func_org;
407 glGetIntegerv(GL_DEPTH_FUNC, &depth_func_org);
408 glMatrixMode(GL_MODELVIEW);
410 m_textOverpaint.clear();
412 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
413 glDepthFunc(GL_LEQUAL);
415 glMatrixMode(GL_PROJECTION);
417 glViewport( 0, 0, (GLint)(m_pItem->width() * m_pixel_ratio),
418 (GLint)(m_pItem->height() * m_pixel_ratio));
419 glGetDoublev(GL_PROJECTION_MATRIX, m_proj);
420 glGetDoublev(GL_MODELVIEW_MATRIX, m_model);
421 glGetIntegerv(GL_VIEWPORT, m_viewport);
429 XTime time_started = XTime::now();
430 if(m_bIsRedrawNeeded || m_bIsAxisRedrawNeeded) {
431 m_modifiedTime = time_started;
433 m_updatedTime = time_started;
435 m_updatedTime =
XTime();
440 if(m_bIsRedrawNeeded) {
443 QColor bgc = (QRgb)shot[ *m_graph->backGround()];
444 glClearColor(bgc.redF(), bgc.greenF(), bgc.blueF(), bgc.alphaF());
446 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
448 glMatrixMode(GL_MODELVIEW);
449 glEnable(GL_DEPTH_TEST);
453 glNewList(m_listgrids, GL_COMPILE_AND_EXECUTE);
454 drawOffScreenGrids(shot);
459 glNewList(m_listpoints, GL_COMPILE_AND_EXECUTE);
460 drawOffScreenPoints(shot);
466 glNewList(m_listaxes, GL_COMPILE_AND_EXECUTE);
467 drawOffScreenAxes(shot);
472 glNewList(m_listaxismarkers, GL_COMPILE);
478 glNewList(m_listplanemarkers, GL_COMPILE);
484 m_bIsRedrawNeeded =
false;
485 m_bIsAxisRedrawNeeded =
false;
488 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
490 glMatrixMode(GL_MODELVIEW);
491 glEnable(GL_DEPTH_TEST);
493 glCallList(m_listgrids);
494 glCallList(m_listpoints);
498 glNewList(m_listaxes, GL_COMPILE_AND_EXECUTE);
499 drawOffScreenAxes(shot);
501 m_bIsAxisRedrawNeeded =
false;
504 glCallList(m_listaxes);
510 glMatrixMode(GL_PROJECTION);
513 glGetDoublev(GL_PROJECTION_MATRIX, m_proj);
514 glMatrixMode(GL_MODELVIEW);
516 double persist = shot[ *m_graph->persistence()];
519 double tau = persist / (-log(OFFSET)) * 0.4;
520 double scale = exp(-(time_started - m_updatedTime)/tau);
521 double offset = -OFFSET*(1.0-scale);
522 bool update = (time_started - m_modifiedTime) < persist;
524 glGetIntegerv(GL_ACCUM_ALPHA_BITS, &accum);
529 glAccum(GL_MULT, scale);
531 glAccum(GL_ACCUM, 1.0 - scale);
533 glAccum(GL_RETURN, 1.0);
537 glAccum(GL_LOAD, 1.0);
542 m_lastFrame.resize(m_pItem->width() * m_pItem->height() * 4);
544 glPixelTransferf(GL_ALPHA_SCALE, scale);
546 glPixelTransferf(GL_ALPHA_BIAS, offset);
550 glDrawPixels((GLint)m_pItem->width(), (GLint)m_pItem->height(),
553 glPixelTransferf(GL_ALPHA_SCALE, 1.0);
555 glPixelTransferf(GL_ALPHA_BIAS, 0.0);
558 glReadPixels(0, 0, (GLint)m_pItem->width(), (GLint)m_pItem->height(),
562 m_updatedTime = time_started;
564 QTimer::singleShot(50, m_pItem, SLOT(update()));
569 m_updatedTime =
XTime();
574 glDisable(GL_DEPTH_TEST);
575 glMatrixMode(GL_PROJECTION);
581 glShadeModel(GL_FLAT);
582 glDisable(GL_CULL_FACE);
583 glDisable(GL_DEPTH_TEST);
584 glDisable(GL_LIGHTING);
585 glDepthFunc(depth_func_org);
586 glMatrixMode(GL_MODELVIEW);
589 QPainter qpainter(m_pItem);
590 qpainter.setRenderHint(QPainter::Antialiasing);
592 drawTextOverpaint(qpainter);
594 drawOnScreenHelp(shot, &qpainter);
595 drawTextOverpaint(qpainter);
602 XQGraphPainter::drawTextOverpaint(QPainter &qpainter) {
603 QFont font(qpainter.font());
604 for(
auto it = m_textOverpaint.begin(); it != m_textOverpaint.end(); ++it) {
605 qpainter.setPen(QColor(it->rgba));
606 font.setPointSize(it->fontsize);
607 qpainter.setFont(font);
608 qpainter.drawText(it->x, it->y, it->text);
610 m_textOverpaint.clear();