##// END OF EJS Templates
Add support for reversed axis when useOpenGL is true...
Andy Shaw -
r2863:15eed6371853
parent child
Show More
@@ -1,650 +1,657
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2016 The Qt Company Ltd.
4 4 ** Contact: https://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:GPL$
9 9 ** Commercial License Usage
10 10 ** Licensees holding valid commercial Qt licenses may use this file in
11 11 ** accordance with the commercial license agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and The Qt Company. For licensing terms
14 14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 15 ** information use the contact form at https://www.qt.io/contact-us.
16 16 **
17 17 ** GNU General Public License Usage
18 18 ** Alternatively, this file may be used under the terms of the GNU
19 19 ** General Public License version 3 or (at your option) any later version
20 20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 22 ** included in the packaging of this file. Please review the following
23 23 ** information to ensure the GNU General Public License requirements will
24 24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 25 **
26 26 ** $QT_END_LICENSE$
27 27 **
28 28 ****************************************************************************/
29 29
30 30 #include <private/chartdataset_p.h>
31 31 #include <private/chartpresenter_p.h>
32 32 #include <QtCharts/QChart>
33 33 #include <private/qchart_p.h>
34 34 #include <QtCharts/QValueAxis>
35 35 #include <QtCharts/QBarCategoryAxis>
36 36 #include <private/qvalueaxis_p.h>
37 37 #include <QtCharts/QCategoryAxis>
38 38 #include <private/qabstractseries_p.h>
39 39 #include <QtCharts/QAbstractBarSeries>
40 40 #include <QtCharts/QStackedBarSeries>
41 41 #include <QtCharts/QPercentBarSeries>
42 42 #include <QtCharts/QPieSeries>
43 43 #include <private/chartitem_p.h>
44 44 #include <private/xydomain_p.h>
45 45 #include <private/xypolardomain_p.h>
46 46 #include <private/xlogydomain_p.h>
47 47 #include <private/logxydomain_p.h>
48 48 #include <private/logxlogydomain_p.h>
49 49 #include <private/xlogypolardomain_p.h>
50 50 #include <private/logxypolardomain_p.h>
51 51 #include <private/logxlogypolardomain_p.h>
52 52 #include <private/glxyseriesdata_p.h>
53 53
54 54 #ifndef QT_QREAL_IS_FLOAT
55 55 #include <QtCharts/QDateTimeAxis>
56 56 #endif
57 57
58 58 QT_CHARTS_BEGIN_NAMESPACE
59 59
60 60 ChartDataSet::ChartDataSet(QChart *chart)
61 61 : QObject(chart),
62 62 m_chart(chart),
63 63 m_glXYSeriesDataManager(new GLXYSeriesDataManager(this))
64 64 {
65 65
66 66 }
67 67
68 68 ChartDataSet::~ChartDataSet()
69 69 {
70 70 deleteAllSeries();
71 71 deleteAllAxes();
72 72 }
73 73
74 74 /*
75 75 * This method adds series to chartdataset, series ownership is taken from caller.
76 76 */
77 77 void ChartDataSet::addSeries(QAbstractSeries *series)
78 78 {
79 79 if (m_seriesList.contains(series)) {
80 80 qWarning() << QObject::tr("Can not add series. Series already on the chart.");
81 81 return;
82 82 }
83 83
84 84 // Ignore unsupported series added to polar chart
85 85 if (m_chart && m_chart->chartType() == QChart::ChartTypePolar) {
86 86 if (!(series->type() == QAbstractSeries::SeriesTypeArea
87 87 || series->type() == QAbstractSeries::SeriesTypeLine
88 88 || series->type() == QAbstractSeries::SeriesTypeScatter
89 89 || series->type() == QAbstractSeries::SeriesTypeSpline)) {
90 90 qWarning() << QObject::tr("Can not add series. Series type is not supported by a polar chart.");
91 91 return;
92 92 }
93 93 // Disable OpenGL for series in polar charts
94 94 series->setUseOpenGL(false);
95 95 series->d_ptr->setDomain(new XYPolarDomain());
96 96 // Set the correct domain for upper and lower series too
97 97 if (series->type() == QAbstractSeries::SeriesTypeArea) {
98 98 foreach (QObject *child, series->children()) {
99 99 if (qobject_cast<QAbstractSeries *>(child)) {
100 100 QAbstractSeries *childSeries = qobject_cast<QAbstractSeries *>(child);
101 101 childSeries->d_ptr->setDomain(new XYPolarDomain());
102 102 }
103 103 }
104 104 }
105 105 } else {
106 106 series->d_ptr->setDomain(new XYDomain());
107 107 }
108 108
109 109 series->d_ptr->initializeDomain();
110 110 m_seriesList.append(series);
111 111
112 112 series->setParent(this); // take ownership
113 113 series->d_ptr->m_chart = m_chart;
114 114
115 115 emit seriesAdded(series);
116 116 }
117 117
118 118 /*
119 119 * This method adds axis to chartdataset, axis ownership is taken from caller.
120 120 */
121 121 void ChartDataSet::addAxis(QAbstractAxis *axis, Qt::Alignment aligment)
122 122 {
123 123 if (m_axisList.contains(axis)) {
124 124 qWarning() << QObject::tr("Can not add axis. Axis already on the chart.");
125 125 return;
126 126 }
127 127
128 128 axis->d_ptr->setAlignment(aligment);
129 129
130 130 if (!axis->alignment()) {
131 131 qWarning() << QObject::tr("No alignment specified !");
132 132 return;
133 133 };
134 134
135 135 AbstractDomain *newDomain;
136 136 if (m_chart && m_chart->chartType() == QChart::ChartTypePolar)
137 137 newDomain = new XYPolarDomain();
138 138 else
139 139 newDomain = new XYDomain();
140 140
141 141 QSharedPointer<AbstractDomain> domain(newDomain);
142 142 axis->d_ptr->initializeDomain(domain.data());
143 143
144 144 axis->setParent(this);
145 145 axis->d_ptr->m_chart = m_chart;
146 146 m_axisList.append(axis);
147 147
148 148 emit axisAdded(axis);
149 149 }
150 150
151 151 /*
152 152 * This method removes series form chartdataset, series ownership is passed back to caller.
153 153 */
154 154 void ChartDataSet::removeSeries(QAbstractSeries *series)
155 155 {
156 156
157 157 if (! m_seriesList.contains(series)) {
158 158 qWarning() << QObject::tr("Can not remove series. Series not found on the chart.");
159 159 return;
160 160 }
161 161
162 162 QList<QAbstractAxis*> axes = series->d_ptr->m_axes;
163 163
164 164 foreach(QAbstractAxis* axis, axes) {
165 165 detachAxis(series,axis);
166 166 }
167 167
168 168 emit seriesRemoved(series);
169 169 m_seriesList.removeAll(series);
170 170
171 171 // Reset domain to default
172 172 series->d_ptr->setDomain(new XYDomain());
173 173 series->setParent(0);
174 174 series->d_ptr->m_chart = 0;
175 175
176 176 QXYSeries *xySeries = qobject_cast<QXYSeries *>(series);
177 177 if (xySeries)
178 178 m_glXYSeriesDataManager->removeSeries(xySeries);
179 179 }
180 180
181 181 /*
182 182 * This method removes axis form chartdataset, series ownership is passed back to caller.
183 183 */
184 184 void ChartDataSet::removeAxis(QAbstractAxis *axis)
185 185 {
186 186 if (! m_axisList.contains(axis)) {
187 187 qWarning() << QObject::tr("Can not remove axis. Axis not found on the chart.");
188 188 return;
189 189 }
190 190
191 191 QList<QAbstractSeries*> series = axis->d_ptr->m_series;
192 192
193 193 foreach(QAbstractSeries* s, series) {
194 194 detachAxis(s,axis);
195 195 }
196 196
197 197 emit axisRemoved(axis);
198 198 m_axisList.removeAll(axis);
199 199
200 200 axis->setParent(0);
201 201 axis->d_ptr->m_chart = 0;
202 202 }
203 203
204 204 /*
205 205 * This method attaches axis to series, return true if success.
206 206 */
207 207 bool ChartDataSet::attachAxis(QAbstractSeries *series,QAbstractAxis *axis)
208 208 {
209 209 Q_ASSERT(axis);
210 210
211 211 if (!series)
212 212 return false;
213 213
214 214 QList<QAbstractSeries *> attachedSeriesList = axis->d_ptr->m_series;
215 215 QList<QAbstractAxis *> attachedAxisList = series->d_ptr->m_axes;
216 216
217 217 if (!m_seriesList.contains(series)) {
218 218 qWarning() << QObject::tr("Can not find series on the chart.");
219 219 return false;
220 220 }
221 221
222 222 if (axis && !m_axisList.contains(axis)) {
223 223 qWarning() << QObject::tr("Can not find axis on the chart.");
224 224 return false;
225 225 }
226 226
227 227 if (attachedAxisList.contains(axis)) {
228 228 qWarning() << QObject::tr("Axis already attached to series.");
229 229 return false;
230 230 }
231 231
232 232 if (attachedSeriesList.contains(series)) {
233 233 qWarning() << QObject::tr("Axis already attached to series.");
234 234 return false;
235 235 }
236 236
237 237 AbstractDomain *domain = series->d_ptr->domain();
238 238 AbstractDomain::DomainType type = selectDomain(attachedAxisList<<axis);
239 239
240 240 if (type == AbstractDomain::UndefinedDomain) return false;
241 241
242 242 if (domain->type() != type) {
243 243 AbstractDomain *old = domain;
244 244 domain = createDomain(type);
245 245 domain->setRange(old->minX(), old->maxX(), old->minY(), old->maxY());
246 246 // Initialize domain size to old domain size, as it won't get updated
247 247 // unless geometry changes.
248 248 domain->setSize(old->size());
249 249 }
250 250
251 251 if (!domain)
252 252 return false;
253 253
254 254 if (!domain->attachAxis(axis))
255 255 return false;
256 256
257 257 QList<AbstractDomain *> blockedDomains;
258 258 domain->blockRangeSignals(true);
259 259 blockedDomains << domain;
260 260
261 261 if (domain != series->d_ptr->domain()) {
262 262 foreach (QAbstractAxis *axis, series->d_ptr->m_axes) {
263 263 series->d_ptr->domain()->detachAxis(axis);
264 264 domain->attachAxis(axis);
265 265 foreach (QAbstractSeries *otherSeries, axis->d_ptr->m_series) {
266 266 if (otherSeries != series && otherSeries->d_ptr->domain()) {
267 267 if (!otherSeries->d_ptr->domain()->rangeSignalsBlocked()) {
268 268 otherSeries->d_ptr->domain()->blockRangeSignals(true);
269 269 blockedDomains << otherSeries->d_ptr->domain();
270 270 }
271 271 }
272 272 }
273 273 }
274 274 series->d_ptr->setDomain(domain);
275 275 series->d_ptr->initializeDomain();
276 276 }
277 277
278 278 series->d_ptr->m_axes<<axis;
279 279 axis->d_ptr->m_series<<series;
280 280
281 281 series->d_ptr->initializeAxes();
282 282 axis->d_ptr->initializeDomain(domain);
283
283 connect(axis, &QAbstractAxis::reverseChanged, this, &ChartDataSet::reverseChanged);
284 284 foreach (AbstractDomain *blockedDomain, blockedDomains)
285 285 blockedDomain->blockRangeSignals(false);
286 286
287 287 return true;
288 288 }
289 289
290 290 /*
291 291 * This method detaches axis to series, return true if success.
292 292 */
293 293 bool ChartDataSet::detachAxis(QAbstractSeries* series,QAbstractAxis *axis)
294 294 {
295 295 Q_ASSERT(series);
296 296 Q_ASSERT(axis);
297 297
298 298 QList<QAbstractSeries* > attachedSeriesList = axis->d_ptr->m_series;
299 299 QList<QAbstractAxis* > attachedAxisList = series->d_ptr->m_axes;
300 300 AbstractDomain* domain = series->d_ptr->domain();
301 301
302 302 if (!m_seriesList.contains(series)) {
303 303 qWarning() << QObject::tr("Can not find series on the chart.");
304 304 return false;
305 305 }
306 306
307 307 if (axis && !m_axisList.contains(axis)) {
308 308 qWarning() << QObject::tr("Can not find axis on the chart.");
309 309 return false;
310 310 }
311 311
312 312 if (!attachedAxisList.contains(axis)) {
313 313 qWarning() << QObject::tr("Axis not attached to series.");
314 314 return false;
315 315 }
316 316
317 317 Q_ASSERT(axis->d_ptr->m_series.contains(series));
318 318
319 319 domain->detachAxis(axis);
320 320 series->d_ptr->m_axes.removeAll(axis);
321 321 axis->d_ptr->m_series.removeAll(series);
322
322 disconnect(axis, &QAbstractAxis::reverseChanged, this, &ChartDataSet::reverseChanged);
323 323 return true;
324 324 }
325 325
326 326 void ChartDataSet::createDefaultAxes()
327 327 {
328 328 if (m_seriesList.isEmpty())
329 329 return;
330 330
331 331 QAbstractAxis::AxisTypes typeX(0);
332 332 QAbstractAxis::AxisTypes typeY(0);
333 333
334 334 // Remove possibly existing axes
335 335 deleteAllAxes();
336 336
337 337 Q_ASSERT(m_axisList.isEmpty());
338 338
339 339 // Select the required axis x and axis y types based on the types of the current series
340 340 foreach(QAbstractSeries* s, m_seriesList) {
341 341 typeX |= s->d_ptr->defaultAxisType(Qt::Horizontal);
342 342 typeY |= s->d_ptr->defaultAxisType(Qt::Vertical);
343 343 }
344 344
345 345 createAxes(typeX, Qt::Horizontal);
346 346 createAxes(typeY, Qt::Vertical);
347 347 }
348 348
349 349 void ChartDataSet::createAxes(QAbstractAxis::AxisTypes type, Qt::Orientation orientation)
350 350 {
351 351 QAbstractAxis *axis = 0;
352 352 //decide what axis should be created
353 353
354 354 switch (type) {
355 355 case QAbstractAxis::AxisTypeValue:
356 356 axis = new QValueAxis(this);
357 357 break;
358 358 case QAbstractAxis::AxisTypeBarCategory:
359 359 axis = new QBarCategoryAxis(this);
360 360 break;
361 361 case QAbstractAxis::AxisTypeCategory:
362 362 axis = new QCategoryAxis(this);
363 363 break;
364 364 #ifndef QT_QREAL_IS_FLOAT
365 365 case QAbstractAxis::AxisTypeDateTime:
366 366 axis = new QDateTimeAxis(this);
367 367 break;
368 368 #endif
369 369 default:
370 370 axis = 0;
371 371 break;
372 372 }
373 373
374 374 if (axis) {
375 375 //create one axis for all
376 376
377 377 addAxis(axis,orientation==Qt::Horizontal?Qt::AlignBottom:Qt::AlignLeft);
378 378 qreal min = 0;
379 379 qreal max = 0;
380 380 findMinMaxForSeries(m_seriesList,orientation,min,max);
381 381 foreach(QAbstractSeries *s, m_seriesList) {
382 382 attachAxis(s,axis);
383 383 }
384 384 axis->setRange(min,max);
385 385 } else {
386 386 // Create separate axis for each series
387 387 foreach(QAbstractSeries *s, m_seriesList) {
388 388 QAbstractAxis *axis = s->d_ptr->createDefaultAxis(orientation);
389 389 if(axis) {
390 390 addAxis(axis,orientation==Qt::Horizontal?Qt::AlignBottom:Qt::AlignLeft);
391 391 attachAxis(s,axis);
392 392 }
393 393 }
394 394 }
395 395 }
396 396
397 397 void ChartDataSet::findMinMaxForSeries(QList<QAbstractSeries *> series,Qt::Orientations orientation, qreal &min, qreal &max)
398 398 {
399 399 Q_ASSERT(!series.isEmpty());
400 400
401 401 AbstractDomain *domain = series.first()->d_ptr->domain();
402 402 min = (orientation == Qt::Vertical) ? domain->minY() : domain->minX();
403 403 max = (orientation == Qt::Vertical) ? domain->maxY() : domain->maxX();
404 404
405 405 for (int i = 1; i< series.size(); i++) {
406 406 AbstractDomain *domain = series[i]->d_ptr->domain();
407 407 min = qMin((orientation == Qt::Vertical) ? domain->minY() : domain->minX(), min);
408 408 max = qMax((orientation == Qt::Vertical) ? domain->maxY() : domain->maxX(), max);
409 409 }
410 410 if (min == max) {
411 411 min -= 0.5;
412 412 max += 0.5;
413 413 }
414 414 }
415 415
416 416 void ChartDataSet::deleteAllSeries()
417 417 {
418 418 foreach (QAbstractSeries *s , m_seriesList){
419 419 removeSeries(s);
420 420 s->deleteLater();
421 421 }
422 422 Q_ASSERT(m_seriesList.count() == 0);
423 423 }
424 424
425 425 void ChartDataSet::deleteAllAxes()
426 426 {
427 427 foreach (QAbstractAxis *a , m_axisList){
428 428 removeAxis(a);
429 429 a->deleteLater();
430 430 }
431 431 Q_ASSERT(m_axisList.count() == 0);
432 432 }
433 433
434 434 void ChartDataSet::zoomInDomain(const QRectF &rect)
435 435 {
436 436 QList<AbstractDomain*> domains;
437 437 foreach(QAbstractSeries *s, m_seriesList) {
438 438 AbstractDomain* domain = s->d_ptr->domain();
439 439 s->d_ptr->m_domain->blockRangeSignals(true);
440 440 domains<<domain;
441 441 }
442 442
443 443 foreach(AbstractDomain *domain, domains)
444 444 domain->zoomIn(rect);
445 445
446 446 foreach(AbstractDomain *domain, domains)
447 447 domain->blockRangeSignals(false);
448 448 }
449 449
450 450 void ChartDataSet::zoomOutDomain(const QRectF &rect)
451 451 {
452 452 QList<AbstractDomain*> domains;
453 453 foreach(QAbstractSeries *s, m_seriesList) {
454 454 AbstractDomain* domain = s->d_ptr->domain();
455 455 s->d_ptr->m_domain->blockRangeSignals(true);
456 456 domains<<domain;
457 457 }
458 458
459 459 foreach(AbstractDomain *domain, domains)
460 460 domain->zoomOut(rect);
461 461
462 462 foreach(AbstractDomain *domain, domains)
463 463 domain->blockRangeSignals(false);
464 464 }
465 465
466 466 void ChartDataSet::zoomResetDomain()
467 467 {
468 468 QList<AbstractDomain*> domains;
469 469 foreach (QAbstractSeries *s, m_seriesList) {
470 470 AbstractDomain *domain = s->d_ptr->domain();
471 471 s->d_ptr->m_domain->blockRangeSignals(true);
472 472 domains << domain;
473 473 }
474 474
475 475 foreach (AbstractDomain *domain, domains)
476 476 domain->zoomReset();
477 477
478 478 foreach (AbstractDomain *domain, domains)
479 479 domain->blockRangeSignals(false);
480 480 }
481 481
482 482 bool ChartDataSet::isZoomedDomain()
483 483 {
484 484 foreach (QAbstractSeries *s, m_seriesList) {
485 485 if (s->d_ptr->domain()->isZoomed())
486 486 return true;
487 487 }
488 488 return false;
489 489 }
490 490
491 491 void ChartDataSet::scrollDomain(qreal dx, qreal dy)
492 492 {
493 493 QList<AbstractDomain*> domains;
494 494 foreach(QAbstractSeries *s, m_seriesList) {
495 495 AbstractDomain* domain = s->d_ptr->domain();
496 496 s->d_ptr->m_domain->blockRangeSignals(true);
497 497 domains<<domain;
498 498 }
499 499
500 500 foreach(AbstractDomain *domain, domains)
501 501 domain->move(dx, dy);
502 502
503 503 foreach(AbstractDomain *domain, domains)
504 504 domain->blockRangeSignals(false);
505 505 }
506 506
507 507 QPointF ChartDataSet::mapToValue(const QPointF &position, QAbstractSeries *series)
508 508 {
509 509 QPointF point;
510 510 if (series == 0 && !m_seriesList.isEmpty())
511 511 series = m_seriesList.first();
512 512
513 513 if (series && series->type() == QAbstractSeries::SeriesTypePie)
514 514 return point;
515 515
516 516 if (series && m_seriesList.contains(series))
517 517 point = series->d_ptr->m_domain->calculateDomainPoint(position - m_chart->plotArea().topLeft());
518 518 return point;
519 519 }
520 520
521 521 QPointF ChartDataSet::mapToPosition(const QPointF &value, QAbstractSeries *series)
522 522 {
523 523 QPointF point = m_chart->plotArea().topLeft();
524 524 if (series == 0 && !m_seriesList.isEmpty())
525 525 series = m_seriesList.first();
526 526
527 527 if (series && series->type() == QAbstractSeries::SeriesTypePie)
528 528 return QPoint(0, 0);
529 529
530 530 bool ok;
531 531 if (series && m_seriesList.contains(series))
532 532 point += series->d_ptr->m_domain->calculateGeometryPoint(value, ok);
533 533 return point;
534 534 }
535 535
536 536 QList<QAbstractAxis *> ChartDataSet::axes() const
537 537 {
538 538 return m_axisList;
539 539 }
540 540
541 541 QList<QAbstractSeries *> ChartDataSet::series() const
542 542 {
543 543 return m_seriesList;
544 544 }
545 545
546 546 AbstractDomain::DomainType ChartDataSet::selectDomain(QList<QAbstractAxis *> axes)
547 547 {
548 548 enum Type {
549 549 Undefined = 0,
550 550 LogType = 0x1,
551 551 ValueType = 0x2
552 552 };
553 553
554 554 int horizontal(Undefined);
555 555 int vertical(Undefined);
556 556
557 557 // Assume cartesian chart type, unless chart is set
558 558 QChart::ChartType chartType(QChart::ChartTypeCartesian);
559 559 if (m_chart)
560 560 chartType = m_chart->chartType();
561 561
562 562 foreach (QAbstractAxis *axis, axes)
563 563 {
564 564 switch (axis->type()) {
565 565 case QAbstractAxis::AxisTypeLogValue:
566 566 if (axis->orientation() == Qt::Horizontal)
567 567 horizontal |= LogType;
568 568 if (axis->orientation() == Qt::Vertical)
569 569 vertical |= LogType;
570 570 break;
571 571 case QAbstractAxis::AxisTypeValue:
572 572 case QAbstractAxis::AxisTypeBarCategory:
573 573 case QAbstractAxis::AxisTypeCategory:
574 574 case QAbstractAxis::AxisTypeDateTime:
575 575 if (axis->orientation() == Qt::Horizontal)
576 576 horizontal |= ValueType;
577 577 if (axis->orientation() == Qt::Vertical)
578 578 vertical |= ValueType;
579 579 break;
580 580 default:
581 581 qWarning() << "Undefined type";
582 582 break;
583 583 }
584 584 }
585 585
586 586 if (vertical == Undefined)
587 587 vertical = ValueType;
588 588 if (horizontal == Undefined)
589 589 horizontal = ValueType;
590 590
591 591 if (vertical == ValueType && horizontal == ValueType) {
592 592 if (chartType == QChart::ChartTypeCartesian)
593 593 return AbstractDomain::XYDomain;
594 594 else if (chartType == QChart::ChartTypePolar)
595 595 return AbstractDomain::XYPolarDomain;
596 596 }
597 597
598 598 if (vertical == LogType && horizontal == ValueType) {
599 599 if (chartType == QChart::ChartTypeCartesian)
600 600 return AbstractDomain::XLogYDomain;
601 601 if (chartType == QChart::ChartTypePolar)
602 602 return AbstractDomain::XLogYPolarDomain;
603 603 }
604 604
605 605 if (vertical == ValueType && horizontal == LogType) {
606 606 if (chartType == QChart::ChartTypeCartesian)
607 607 return AbstractDomain::LogXYDomain;
608 608 else if (chartType == QChart::ChartTypePolar)
609 609 return AbstractDomain::LogXYPolarDomain;
610 610 }
611 611
612 612 if (vertical == LogType && horizontal == LogType) {
613 613 if (chartType == QChart::ChartTypeCartesian)
614 614 return AbstractDomain::LogXLogYDomain;
615 615 else if (chartType == QChart::ChartTypePolar)
616 616 return AbstractDomain::LogXLogYPolarDomain;
617 617 }
618 618
619 619 return AbstractDomain::UndefinedDomain;
620 620 }
621 621
622 622 //refactor create factory
623 623 AbstractDomain* ChartDataSet::createDomain(AbstractDomain::DomainType type)
624 624 {
625 625 switch (type)
626 626 {
627 627 case AbstractDomain::LogXLogYDomain:
628 628 return new LogXLogYDomain();
629 629 case AbstractDomain::XYDomain:
630 630 return new XYDomain();
631 631 case AbstractDomain::XLogYDomain:
632 632 return new XLogYDomain();
633 633 case AbstractDomain::LogXYDomain:
634 634 return new LogXYDomain();
635 635 case AbstractDomain::XYPolarDomain:
636 636 return new XYPolarDomain();
637 637 case AbstractDomain::XLogYPolarDomain:
638 638 return new XLogYPolarDomain();
639 639 case AbstractDomain::LogXYPolarDomain:
640 640 return new LogXYPolarDomain();
641 641 case AbstractDomain::LogXLogYPolarDomain:
642 642 return new LogXLogYPolarDomain();
643 643 default:
644 644 return 0;
645 645 }
646 646 }
647 647
648 void ChartDataSet::reverseChanged()
649 {
650 QAbstractAxis *axis = qobject_cast<QAbstractAxis *>(sender());
651 if (axis)
652 m_glXYSeriesDataManager->handleAxisReverseChanged(axis->d_ptr->m_series);
653 }
654
648 655 #include "moc_chartdataset_p.cpp"
649 656
650 657 QT_CHARTS_END_NAMESPACE
@@ -1,107 +1,108
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2016 The Qt Company Ltd.
4 4 ** Contact: https://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:GPL$
9 9 ** Commercial License Usage
10 10 ** Licensees holding valid commercial Qt licenses may use this file in
11 11 ** accordance with the commercial license agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and The Qt Company. For licensing terms
14 14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 15 ** information use the contact form at https://www.qt.io/contact-us.
16 16 **
17 17 ** GNU General Public License Usage
18 18 ** Alternatively, this file may be used under the terms of the GNU
19 19 ** General Public License version 3 or (at your option) any later version
20 20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 22 ** included in the packaging of this file. Please review the following
23 23 ** information to ensure the GNU General Public License requirements will
24 24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 25 **
26 26 ** $QT_END_LICENSE$
27 27 **
28 28 ****************************************************************************/
29 29
30 30 // W A R N I N G
31 31 // -------------
32 32 //
33 33 // This file is not part of the Qt Chart API. It exists purely as an
34 34 // implementation detail. This header file may change from version to
35 35 // version without notice, or even be removed.
36 36 //
37 37 // We mean it.
38 38
39 39 #ifndef CHARTDATASET_P_H
40 40 #define CHARTDATASET_P_H
41 41
42 42 #include <QtCharts/QAbstractSeries>
43 43 #include <private/abstractdomain_p.h>
44 44 #include <private/qabstractaxis_p.h>
45 45 #include <QtCore/QVector>
46 46
47 47 QT_CHARTS_BEGIN_NAMESPACE
48 48
49 49 class QAbstractAxis;
50 50 class ChartPresenter;
51 51 class GLXYSeriesDataManager;
52 52
53 53 class Q_AUTOTEST_EXPORT ChartDataSet : public QObject
54 54 {
55 55 Q_OBJECT
56 56 public:
57 57 ChartDataSet(QChart *chart);
58 58 virtual ~ChartDataSet();
59 59
60 60 void addSeries(QAbstractSeries *series);
61 61 void removeSeries(QAbstractSeries *series);
62 62 QList<QAbstractSeries *> series() const;
63 63
64 64 void addAxis(QAbstractAxis *axis,Qt::Alignment aligment);
65 65 void removeAxis(QAbstractAxis *axis);
66 66 QList<QAbstractAxis*> axes() const;
67 67
68 68 bool attachAxis(QAbstractSeries* series,QAbstractAxis *axis);
69 69 bool detachAxis(QAbstractSeries* series,QAbstractAxis *axis);
70 70
71 71 void createDefaultAxes();
72 72
73 73 void zoomInDomain(const QRectF &rect);
74 74 void zoomOutDomain(const QRectF &rect);
75 75 void zoomResetDomain();
76 76 bool isZoomedDomain();
77 77 void scrollDomain(qreal dx, qreal dy);
78 78
79 79 QPointF mapToValue(const QPointF &position, QAbstractSeries *series = 0);
80 80 QPointF mapToPosition(const QPointF &value, QAbstractSeries *series = 0);
81 81
82 82 GLXYSeriesDataManager *glXYSeriesDataManager() { return m_glXYSeriesDataManager; }
83 83
84 84 Q_SIGNALS:
85 85 void axisAdded(QAbstractAxis* axis);
86 86 void axisRemoved(QAbstractAxis* axis);
87 87 void seriesAdded(QAbstractSeries* series);
88 88 void seriesRemoved(QAbstractSeries* series);
89
89 public Q_SLOTS:
90 void reverseChanged();
90 91 private:
91 92 void createAxes(QAbstractAxis::AxisTypes type, Qt::Orientation orientation);
92 93 QAbstractAxis *createAxis(QAbstractAxis::AxisType type, Qt::Orientation orientation);
93 94 AbstractDomain::DomainType selectDomain(QList<QAbstractAxis* > axes);
94 95 AbstractDomain* createDomain(AbstractDomain::DomainType type);
95 96 void deleteAllAxes();
96 97 void deleteAllSeries();
97 98 void findMinMaxForSeries(QList<QAbstractSeries *> series,Qt::Orientations orientation, qreal &min, qreal &max);
98 99 private:
99 100 QList<QAbstractSeries *> m_seriesList;
100 101 QList<QAbstractAxis *> m_axisList;
101 102 QChart* m_chart;
102 103 GLXYSeriesDataManager *m_glXYSeriesDataManager;
103 104 };
104 105
105 106 QT_CHARTS_END_NAMESPACE
106 107
107 108 #endif /* CHARTENGINE_P_H */
@@ -1,233 +1,236
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2016 The Qt Company Ltd.
4 4 ** Contact: https://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:GPL$
9 9 ** Commercial License Usage
10 10 ** Licensees holding valid commercial Qt licenses may use this file in
11 11 ** accordance with the commercial license agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and The Qt Company. For licensing terms
14 14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 15 ** information use the contact form at https://www.qt.io/contact-us.
16 16 **
17 17 ** GNU General Public License Usage
18 18 ** Alternatively, this file may be used under the terms of the GNU
19 19 ** General Public License version 3 or (at your option) any later version
20 20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 22 ** included in the packaging of this file. Please review the following
23 23 ** information to ensure the GNU General Public License requirements will
24 24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 25 **
26 26 ** $QT_END_LICENSE$
27 27 **
28 28 ****************************************************************************/
29 29
30 30 #ifndef QT_NO_OPENGL
31 31
32 32 #include "private/glwidget_p.h"
33 33 #include "private/glxyseriesdata_p.h"
34 34 #include <QtGui/QOpenGLShaderProgram>
35 35 #include <QtGui/QOpenGLContext>
36 36 #include <QtGui/QOpenGLBuffer>
37 37
38 38 //#define QDEBUG_TRACE_GL_FPS
39 39 #ifdef QDEBUG_TRACE_GL_FPS
40 40 # include <QElapsedTimer>
41 41 #endif
42 42
43 43 QT_CHARTS_BEGIN_NAMESPACE
44 44
45 45 GLWidget::GLWidget(GLXYSeriesDataManager *xyDataManager, QWidget *parent)
46 46 : QOpenGLWidget(parent),
47 47 m_program(0),
48 48 m_shaderAttribLoc(-1),
49 49 m_colorUniformLoc(-1),
50 50 m_minUniformLoc(-1),
51 51 m_deltaUniformLoc(-1),
52 52 m_pointSizeUniformLoc(-1),
53 53 m_xyDataManager(xyDataManager)
54 54 {
55 55 setAttribute(Qt::WA_TranslucentBackground);
56 56 setAttribute(Qt::WA_AlwaysStackOnTop);
57 57 setAttribute(Qt::WA_TransparentForMouseEvents);
58 58
59 59 QSurfaceFormat surfaceFormat;
60 60 surfaceFormat.setDepthBufferSize(0);
61 61 surfaceFormat.setStencilBufferSize(0);
62 62 surfaceFormat.setRedBufferSize(8);
63 63 surfaceFormat.setGreenBufferSize(8);
64 64 surfaceFormat.setBlueBufferSize(8);
65 65 surfaceFormat.setAlphaBufferSize(8);
66 66 surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
67 67 surfaceFormat.setRenderableType(QSurfaceFormat::DefaultRenderableType);
68 68 setFormat(surfaceFormat);
69 69
70 70 connect(xyDataManager, &GLXYSeriesDataManager::seriesRemoved,
71 71 this, &GLWidget::cleanXYSeriesResources);
72 72 }
73 73
74 74 GLWidget::~GLWidget()
75 75 {
76 76 cleanup();
77 77 }
78 78
79 79 void GLWidget::cleanup()
80 80 {
81 81 makeCurrent();
82 82
83 83 delete m_program;
84 84 m_program = 0;
85 85
86 86 foreach (QOpenGLBuffer *buffer, m_seriesBufferMap.values())
87 87 delete buffer;
88 88 m_seriesBufferMap.clear();
89 89
90 90 doneCurrent();
91 91 }
92 92
93 93 void GLWidget::cleanXYSeriesResources(const QXYSeries *series)
94 94 {
95 95 makeCurrent();
96 96 if (series) {
97 97 delete m_seriesBufferMap.take(series);
98 98 } else {
99 99 // Null series means all series were removed
100 100 foreach (QOpenGLBuffer *buffer, m_seriesBufferMap.values())
101 101 delete buffer;
102 102 m_seriesBufferMap.clear();
103 103 }
104 104 doneCurrent();
105 105 }
106 106
107 107 static const char *vertexSource =
108 108 "attribute highp vec2 points;\n"
109 109 "uniform highp vec2 min;\n"
110 110 "uniform highp vec2 delta;\n"
111 111 "uniform highp float pointSize;\n"
112 "uniform highp mat4 matrix;\n"
112 113 "void main() {\n"
113 114 " vec2 normalPoint = vec2(-1, -1) + ((points - min) / delta);\n"
114 " gl_Position = vec4(normalPoint, 0, 1);\n"
115 " gl_Position = matrix * vec4(normalPoint, 0, 1);\n"
115 116 " gl_PointSize = pointSize;\n"
116 117 "}";
117 118 static const char *fragmentSource =
118 119 "uniform highp vec3 color;\n"
119 120 "void main() {\n"
120 121 " gl_FragColor = vec4(color,1);\n"
121 122 "}\n";
122 123
123 124 void GLWidget::initializeGL()
124 125 {
125 126 connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &GLWidget::cleanup);
126 127
127 128 initializeOpenGLFunctions();
128 129 glClearColor(0, 0, 0, 0);
129 130
130 131 m_program = new QOpenGLShaderProgram;
131 132 m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource);
132 133 m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentSource);
133 134 m_program->bindAttributeLocation("points", 0);
134 135 m_program->link();
135 136
136 137 m_program->bind();
137 138 m_colorUniformLoc = m_program->uniformLocation("color");
138 139 m_minUniformLoc = m_program->uniformLocation("min");
139 140 m_deltaUniformLoc = m_program->uniformLocation("delta");
140 141 m_pointSizeUniformLoc = m_program->uniformLocation("pointSize");
142 m_matrixUniformLoc = m_program->uniformLocation("matrix");
141 143
142 144
143 145 // Create a vertex array object. In OpenGL ES 2.0 and OpenGL 2.x
144 146 // implementations this is optional and support may not be present
145 147 // at all. Nonetheless the below code works in all cases and makes
146 148 // sure there is a VAO when one is needed.
147 149 m_vao.create();
148 150 QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
149 151
150 152 glEnableVertexAttribArray(0);
151 153
152 154 glDisable(GL_DEPTH_TEST);
153 155 glDisable(GL_STENCIL_TEST);
154 156
155 157 #if !defined(QT_OPENGL_ES_2)
156 158 if (!QOpenGLContext::currentContext()->isOpenGLES()) {
157 159 // Make it possible to change point primitive size and use textures with them in
158 160 // the shaders. These are implicitly enabled in ES2.
159 161 glEnable(GL_PROGRAM_POINT_SIZE);
160 162 }
161 163 #endif
162 164
163 165 m_program->release();
164 166 }
165 167
166 168 void GLWidget::paintGL()
167 169 {
168 170 glClear(GL_COLOR_BUFFER_BIT);
169 171
170 172 QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
171 173 m_program->bind();
172 174
173 175 GLXYDataMapIterator i(m_xyDataManager->dataMap());
174 176 while (i.hasNext()) {
175 177 i.next();
176 178 QOpenGLBuffer *vbo = m_seriesBufferMap.value(i.key());
177 179 GLXYSeriesData *data = i.value();
178 180
179 181 m_program->setUniformValue(m_colorUniformLoc, data->color);
180 182 m_program->setUniformValue(m_minUniformLoc, data->min);
181 183 m_program->setUniformValue(m_deltaUniformLoc, data->delta);
184 m_program->setUniformValue(m_matrixUniformLoc, data->matrix);
182 185
183 186 if (!vbo) {
184 187 vbo = new QOpenGLBuffer;
185 188 m_seriesBufferMap.insert(i.key(), vbo);
186 189 vbo->create();
187 190 }
188 191 vbo->bind();
189 192 if (data->dirty) {
190 193 vbo->allocate(data->array.constData(), data->array.count() * sizeof(GLfloat));
191 194 data->dirty = false;
192 195 }
193 196
194 197 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
195 198 if (data->type == QAbstractSeries::SeriesTypeLine) {
196 199 glLineWidth(data->width);
197 200 glDrawArrays(GL_LINE_STRIP, 0, data->array.size() / 2);
198 201 } else { // Scatter
199 202 m_program->setUniformValue(m_pointSizeUniformLoc, data->width);
200 203 glDrawArrays(GL_POINTS, 0, data->array.size() / 2);
201 204 }
202 205 vbo->release();
203 206 }
204 207
205 208 #ifdef QDEBUG_TRACE_GL_FPS
206 209 static QElapsedTimer stopWatch;
207 210 static int frameCount = -1;
208 211 if (frameCount == -1) {
209 212 stopWatch.start();
210 213 frameCount = 0;
211 214 }
212 215 frameCount++;
213 216 int elapsed = stopWatch.elapsed();
214 217 if (elapsed >= 1000) {
215 218 elapsed = stopWatch.restart();
216 219 qreal fps = qreal(0.1 * int(10000.0 * (qreal(frameCount) / qreal(elapsed))));
217 220 qDebug() << "FPS:" << fps;
218 221 frameCount = 0;
219 222 }
220 223 #endif
221 224
222 225 m_program->release();
223 226 }
224 227
225 228 void GLWidget::resizeGL(int w, int h)
226 229 {
227 230 Q_UNUSED(w)
228 231 Q_UNUSED(h)
229 232 }
230 233
231 234 QT_CHARTS_END_NAMESPACE
232 235
233 236 #endif
@@ -1,90 +1,91
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2016 The Qt Company Ltd.
4 4 ** Contact: https://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:GPL$
9 9 ** Commercial License Usage
10 10 ** Licensees holding valid commercial Qt licenses may use this file in
11 11 ** accordance with the commercial license agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and The Qt Company. For licensing terms
14 14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 15 ** information use the contact form at https://www.qt.io/contact-us.
16 16 **
17 17 ** GNU General Public License Usage
18 18 ** Alternatively, this file may be used under the terms of the GNU
19 19 ** General Public License version 3 or (at your option) any later version
20 20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 22 ** included in the packaging of this file. Please review the following
23 23 ** information to ensure the GNU General Public License requirements will
24 24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 25 **
26 26 ** $QT_END_LICENSE$
27 27 **
28 28 ****************************************************************************/
29 29
30 30 // W A R N I N G
31 31 // -------------
32 32 //
33 33 // This file is not part of the Qt Chart API. It exists purely as an
34 34 // implementation detail. This header file may change from version to
35 35 // version without notice, or even be removed.
36 36 //
37 37 // We mean it.
38 38
39 39 #ifndef GLWIDGET_H
40 40 #define GLWIDGET_H
41 41
42 42 #ifndef QT_NO_OPENGL
43 43
44 44 #include <QtWidgets/QOpenGLWidget>
45 45 #include <QtGui/QOpenGLFunctions>
46 46 #include <QtGui/QOpenGLVertexArrayObject>
47 47 #include <QtGui/QOpenGLBuffer>
48 48 #include <QtCore/QHash>
49 49 #include <QtCharts/QAbstractSeries>
50 50 #include <QtCharts/QXYSeries>
51 51
52 52 QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
53 53
54 54 QT_CHARTS_BEGIN_NAMESPACE
55 55
56 56 class GLXYSeriesDataManager;
57 57
58 58 class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions
59 59 {
60 60 Q_OBJECT
61 61
62 62 public:
63 63 GLWidget(GLXYSeriesDataManager *xyDataManager, QWidget *parent = 0);
64 64 ~GLWidget();
65 65
66 66 public Q_SLOTS:
67 67 void cleanup();
68 68 void cleanXYSeriesResources(const QXYSeries *series);
69 69
70 70 protected:
71 71 void initializeGL() Q_DECL_OVERRIDE;
72 72 void paintGL() Q_DECL_OVERRIDE;
73 73 void resizeGL(int width, int height) Q_DECL_OVERRIDE;
74 74
75 75 private:
76 76 QOpenGLShaderProgram *m_program;
77 77 int m_shaderAttribLoc;
78 78 int m_colorUniformLoc;
79 79 int m_minUniformLoc;
80 80 int m_deltaUniformLoc;
81 81 int m_pointSizeUniformLoc;
82 int m_matrixUniformLoc;
82 83 QOpenGLVertexArrayObject m_vao;
83 84
84 85 QHash<const QAbstractSeries *, QOpenGLBuffer *> m_seriesBufferMap;
85 86 GLXYSeriesDataManager *m_xyDataManager;
86 87 };
87 88
88 89 QT_CHARTS_END_NAMESPACE
89 90 #endif
90 91 #endif
@@ -1,189 +1,233
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2016 The Qt Company Ltd.
4 4 ** Contact: https://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:GPL$
9 9 ** Commercial License Usage
10 10 ** Licensees holding valid commercial Qt licenses may use this file in
11 11 ** accordance with the commercial license agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and The Qt Company. For licensing terms
14 14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 15 ** information use the contact form at https://www.qt.io/contact-us.
16 16 **
17 17 ** GNU General Public License Usage
18 18 ** Alternatively, this file may be used under the terms of the GNU
19 19 ** General Public License version 3 or (at your option) any later version
20 20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 22 ** included in the packaging of this file. Please review the following
23 23 ** information to ensure the GNU General Public License requirements will
24 24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 25 **
26 26 ** $QT_END_LICENSE$
27 27 **
28 28 ****************************************************************************/
29 29
30 30 #include "private/glxyseriesdata_p.h"
31 31 #include "private/abstractdomain_p.h"
32 32 #include <QtCharts/QScatterSeries>
33 33
34 34 QT_CHARTS_BEGIN_NAMESPACE
35 35
36 36 GLXYSeriesDataManager::GLXYSeriesDataManager(QObject *parent)
37 37 : QObject(parent),
38 38 m_mapDirty(false)
39 39 {
40 40 }
41 41
42 42 GLXYSeriesDataManager::~GLXYSeriesDataManager()
43 43 {
44 44 cleanup();
45 45 }
46 46
47 47 void GLXYSeriesDataManager::setPoints(QXYSeries *series, const AbstractDomain *domain)
48 48 {
49 49 GLXYSeriesData *data = m_seriesDataMap.value(series);
50 50 if (!data) {
51 51 data = new GLXYSeriesData;
52 52 data->type = series->type();
53 53 QColor sc;
54 54 if (data->type == QAbstractSeries::SeriesTypeScatter) {
55 55 QScatterSeries *scatter = static_cast<QScatterSeries *>(series);
56 56 data->width = float(scatter->markerSize());
57 57 sc = scatter->color(); // Scatter overwrites color property
58 58 connect(scatter, &QScatterSeries::colorChanged, this,
59 59 &GLXYSeriesDataManager::handleScatterColorChange);
60 60 connect(scatter, &QScatterSeries::markerSizeChanged, this,
61 61 &GLXYSeriesDataManager::handleScatterMarkerSizeChange);
62 62 } else {
63 63 data->width = float(series->pen().widthF());
64 64 sc = series->color();
65 65 connect(series, &QXYSeries::penChanged, this,
66 66 &GLXYSeriesDataManager::handleSeriesPenChange);
67 67 }
68 68 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
69 69 connect(series, &QXYSeries::useOpenGLChanged, this,
70 70 &GLXYSeriesDataManager::handleSeriesOpenGLChange);
71 71 m_seriesDataMap.insert(series, data);
72 72 m_mapDirty = true;
73 73 }
74 74 QVector<float> &array = data->array;
75 75
76 76 bool logAxis = false;
77 bool reverseX = false;
78 bool reverseY = false;
77 79 foreach (QAbstractAxis* axis, series->attachedAxes()) {
78 80 if (axis->type() == QAbstractAxis::AxisTypeLogValue) {
79 81 logAxis = true;
80 break;
82 }
83 if (axis->isReverse()) {
84 if (axis->orientation() == Qt::Horizontal)
85 reverseX = true;
86 else
87 reverseY = true;
88 if (reverseX && reverseY)
89 break;
81 90 }
82 91 }
83
84 92 int count = series->count();
85 93 int index = 0;
86 94 array.resize(count * 2);
95 QMatrix4x4 matrix;
96 if (reverseX)
97 matrix.scale(-1.0, 1.0);
98 if (reverseY)
99 matrix.scale(1.0, -1.0);
100 data->matrix = matrix;
87 101 if (logAxis) {
88 102 // Use domain to resolve geometry points. Not as fast as shaders, but simpler that way
89 103 QVector<QPointF> geometryPoints = domain->calculateGeometryPoints(series->pointsVector());
90 104 const float height = domain->size().height();
91 105 if (geometryPoints.size()) {
92 106 for (int i = 0; i < count; i++) {
93 107 const QPointF &point = geometryPoints.at(i);
94 108 array[index++] = float(point.x());
95 109 array[index++] = float(height - point.y());
96 110 }
97 111 } else {
98 112 // If there are invalid log values, geometry points generation fails
99 113 for (int i = 0; i < count; i++) {
100 114 array[index++] = 0.0f;
101 115 array[index++] = 0.0f;
102 116 }
103 117 }
104 118 data->min = QVector2D(0, 0);
105 119 data->delta = QVector2D(domain->size().width() / 2.0f, domain->size().height() / 2.0f);
106 120 } else {
107 121 // Regular value axes, so we can do the math easily on shaders.
108 122 QVector<QPointF> seriesPoints = series->pointsVector();
109 123 for (int i = 0; i < count; i++) {
110 124 const QPointF &point = seriesPoints.at(i);
111 125 array[index++] = float(point.x());
112 126 array[index++] = float(point.y());
113 127 }
114 128 data->min = QVector2D(domain->minX(), domain->minY());
115 129 data->delta = QVector2D((domain->maxX() - domain->minX()) / 2.0f,
116 130 (domain->maxY() - domain->minY()) / 2.0f);
117 131 }
118 132 data->dirty = true;
119 133 }
120 134
121 135 void GLXYSeriesDataManager::removeSeries(const QXYSeries *series)
122 136 {
123 137 GLXYSeriesData *data = m_seriesDataMap.take(series);
124 138 if (data) {
125 139 disconnect(series, 0, this, 0);
126 140 delete data;
127 141 emit seriesRemoved(series);
128 142 m_mapDirty = true;
129 143 }
130 144 }
131 145
132 146 void GLXYSeriesDataManager::cleanup()
133 147 {
134 148 foreach (GLXYSeriesData *data, m_seriesDataMap.values())
135 149 delete data;
136 150 m_seriesDataMap.clear();
137 151 m_mapDirty = true;
138 152 // Signal all series removal by using zero as parameter
139 153 emit seriesRemoved(0);
140 154 }
141 155
142 156 void GLXYSeriesDataManager::handleSeriesPenChange()
143 157 {
144 158 QXYSeries *series = qobject_cast<QXYSeries *>(sender());
145 159 if (series) {
146 160 GLXYSeriesData *data = m_seriesDataMap.value(series);
147 161 if (data) {
148 162 QColor sc = series->color();
149 163 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
150 164 data->width = float(series->pen().widthF());
151 165 data->dirty = true;
152 166 }
153 167 }
154 168 }
155 169
156 170 void GLXYSeriesDataManager::handleSeriesOpenGLChange()
157 171 {
158 172 QXYSeries *series = qobject_cast<QXYSeries *>(sender());
159 173 if (!series->useOpenGL())
160 174 removeSeries(series);
161 175 }
162 176
163 177 void GLXYSeriesDataManager::handleScatterColorChange()
164 178 {
165 179 QScatterSeries *series = qobject_cast<QScatterSeries *>(sender());
166 180 if (series) {
167 181 GLXYSeriesData *data = m_seriesDataMap.value(series);
168 182 if (data) {
169 183 QColor sc = series->color();
170 184 data->color = QVector3D(float(sc.redF()), float(sc.greenF()), float(sc.blueF()));
171 185 data->dirty = true;
172 186 }
173 187 }
174 188 }
175 189
176 190 void GLXYSeriesDataManager::handleScatterMarkerSizeChange()
177 191 {
178 192 QScatterSeries *series = qobject_cast<QScatterSeries *>(sender());
179 193 if (series) {
180 194 GLXYSeriesData *data = m_seriesDataMap.value(series);
181 195 if (data) {
182 196 data->width =float(series->markerSize());
183 197 data->dirty = true;
184 198 }
185 199 }
186 200 }
187 201
202 void GLXYSeriesDataManager::handleAxisReverseChanged(const QList<QAbstractSeries *> &seriesList)
203 {
204 bool reverseX = false;
205 bool reverseY = false;
206 foreach (QAbstractSeries *series, seriesList) {
207 if (QXYSeries *xyseries = qobject_cast<QXYSeries *>(series)) {
208 GLXYSeriesData *data = m_seriesDataMap.value(xyseries);
209 if (data) {
210 foreach (QAbstractAxis* axis, xyseries->attachedAxes()) {
211 if (axis->isReverse()) {
212 if (axis->orientation() == Qt::Horizontal)
213 reverseX = true;
214 else
215 reverseY = true;
216 }
217 if (reverseX && reverseY)
218 break;
219 }
220 QMatrix4x4 matrix;
221 if (reverseX)
222 matrix.scale(-1.0, 1.0);
223 if (reverseY)
224 matrix.scale(1.0, -1.0);
225 data->matrix = matrix;
226 data->dirty = true;
227 }
228 }
229 }
230 }
231
188 232 QT_CHARTS_END_NAMESPACE
189 233
@@ -1,104 +1,119
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2016 The Qt Company Ltd.
4 4 ** Contact: https://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:GPL$
9 9 ** Commercial License Usage
10 10 ** Licensees holding valid commercial Qt licenses may use this file in
11 11 ** accordance with the commercial license agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and The Qt Company. For licensing terms
14 14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 15 ** information use the contact form at https://www.qt.io/contact-us.
16 16 **
17 17 ** GNU General Public License Usage
18 18 ** Alternatively, this file may be used under the terms of the GNU
19 19 ** General Public License version 3 or (at your option) any later version
20 20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 22 ** included in the packaging of this file. Please review the following
23 23 ** information to ensure the GNU General Public License requirements will
24 24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 25 **
26 26 ** $QT_END_LICENSE$
27 27 **
28 28 ****************************************************************************/
29 29
30 30 // W A R N I N G
31 31 // -------------
32 32 //
33 33 // This file is not part of the Qt Chart API. It exists purely as an
34 34 // implementation detail. This header file may change from version to
35 35 // version without notice, or even be removed.
36 36 //
37 37 // We mean it.
38 38
39 39 #ifndef GLXYSERIESDATA_H
40 40 #define GLXYSERIESDATA_H
41 41
42 42 #include <QtCore/QMap>
43 43 #include <QtCharts/QAbstractSeries>
44 44 #include <QtCharts/QXYSeries>
45 45 #include <QtGui/QVector3D>
46 46 #include <QtGui/QVector2D>
47 #include <QtGui/QMatrix4x4>
47 48
48 49 QT_CHARTS_BEGIN_NAMESPACE
49 50
50 51 class AbstractDomain;
51 52
52 53 struct GLXYSeriesData {
53 54 QVector<float> array;
54 55 bool dirty;
55 56 QVector3D color;
56 57 float width;
57 58 QAbstractSeries::SeriesType type;
58 59 QVector2D min;
59 60 QVector2D delta;
61 QMatrix4x4 matrix;
62 public:
63 GLXYSeriesData &operator=(const GLXYSeriesData &data) {
64 array = data.array;
65 dirty = data.dirty;
66 color = data.color;
67 width = data.width;
68 type = data.type;
69 min = data.min;
70 delta = data.delta;
71 matrix = data.matrix;
72 return *this;
73 }
60 74 };
61 75
62 76 typedef QMap<const QXYSeries *, GLXYSeriesData *> GLXYDataMap;
63 77 typedef QMapIterator<const QXYSeries *, GLXYSeriesData *> GLXYDataMapIterator;
64 78
65 79 class GLXYSeriesDataManager : public QObject
66 80 {
67 81 Q_OBJECT
68 82
69 83 public:
70 84 GLXYSeriesDataManager(QObject *parent = 0);
71 85 ~GLXYSeriesDataManager();
72 86
73 87 void setPoints(QXYSeries *series, const AbstractDomain *domain);
74 88
75 89 void removeSeries(const QXYSeries *series);
76 90
77 91 GLXYDataMap &dataMap() { return m_seriesDataMap; }
78 92
79 93 // These functions are needed by qml side, so they must be inline
80 94 bool mapDirty() const { return m_mapDirty; }
81 95 void clearAllDirty() {
82 96 m_mapDirty = false;
83 97 foreach (GLXYSeriesData *data, m_seriesDataMap.values())
84 98 data->dirty = false;
85 99 }
100 void handleAxisReverseChanged(const QList<QAbstractSeries *> &seriesList);
86 101
87 102 public Q_SLOTS:
88 103 void cleanup();
89 104 void handleSeriesPenChange();
90 105 void handleSeriesOpenGLChange();
91 106 void handleScatterColorChange();
92 107 void handleScatterMarkerSizeChange();
93 108
94 109 Q_SIGNALS:
95 110 void seriesRemoved(const QXYSeries *series);
96 111
97 112 private:
98 113 GLXYDataMap m_seriesDataMap;
99 114 bool m_mapDirty;
100 115 };
101 116
102 117 QT_CHARTS_END_NAMESPACE
103 118
104 119 #endif
@@ -1,332 +1,322
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2016 The Qt Company Ltd.
4 4 ** Contact: https://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:GPL$
9 9 ** Commercial License Usage
10 10 ** Licensees holding valid commercial Qt licenses may use this file in
11 11 ** accordance with the commercial license agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and The Qt Company. For licensing terms
14 14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 15 ** information use the contact form at https://www.qt.io/contact-us.
16 16 **
17 17 ** GNU General Public License Usage
18 18 ** Alternatively, this file may be used under the terms of the GNU
19 19 ** General Public License version 3 or (at your option) any later version
20 20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 22 ** included in the packaging of this file. Please review the following
23 23 ** information to ensure the GNU General Public License requirements will
24 24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 25 **
26 26 ** $QT_END_LICENSE$
27 27 **
28 28 ****************************************************************************/
29 29
30 30 #include "declarativerendernode.h"
31 31
32 32 #include <QtGui/QOpenGLContext>
33 33 #include <QtGui/QOpenGLFunctions>
34 34 #include <QtGui/QOpenGLFramebufferObjectFormat>
35 35 #include <QtGui/QOpenGLFramebufferObject>
36 36 #include <QOpenGLShaderProgram>
37 37 #include <QtGui/QOpenGLBuffer>
38 38
39 39 //#define QDEBUG_TRACE_GL_FPS
40 40 #ifdef QDEBUG_TRACE_GL_FPS
41 41 # include <QElapsedTimer>
42 42 #endif
43 43
44 44 QT_CHARTS_BEGIN_NAMESPACE
45 45
46 46 // This node draws the xy series data on a transparent background using OpenGL.
47 47 // It is used as a child node of the chart node.
48 48 DeclarativeRenderNode::DeclarativeRenderNode(QQuickWindow *window) :
49 49 QObject(),
50 50 QSGSimpleTextureNode(),
51 51 m_texture(0),
52 52 m_window(window),
53 53 m_textureOptions(QQuickWindow::TextureHasAlphaChannel),
54 54 m_textureSize(1, 1),
55 55 m_recreateFbo(false),
56 56 m_fbo(0),
57 57 m_program(0),
58 58 m_shaderAttribLoc(-1),
59 59 m_colorUniformLoc(-1),
60 60 m_minUniformLoc(-1),
61 61 m_deltaUniformLoc(-1),
62 62 m_pointSizeUniformLoc(-1),
63 63 m_renderNeeded(true)
64 64 {
65 65 initializeOpenGLFunctions();
66 66
67 67 // Our texture node must have a texture, so use a default one pixel texture
68 68 GLuint defaultTexture = 0;
69 69 glGenTextures(1, &defaultTexture);
70 70 glBindTexture(GL_TEXTURE_2D, defaultTexture);
71 71 uchar buf[4] = { 0, 0, 0, 0 };
72 72 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &buf);
73 73
74 74 QQuickWindow::CreateTextureOptions defaultTextureOptions = QQuickWindow::CreateTextureOptions(
75 75 QQuickWindow::TextureHasAlphaChannel | QQuickWindow::TextureOwnsGLTexture);
76 76 m_texture = m_window->createTextureFromId(defaultTexture, QSize(1, 1), defaultTextureOptions);
77 77
78 78 setTexture(m_texture);
79 79 setFiltering(QSGTexture::Linear);
80 80 setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
81 81 }
82 82
83 83 DeclarativeRenderNode::~DeclarativeRenderNode()
84 84 {
85 85 delete m_texture;
86 86 delete m_fbo;
87 87
88 88 delete m_program;
89 89 m_program = 0;
90 90
91 91 cleanXYSeriesResources(0);
92 92 }
93 93
94 94 static const char *vertexSource =
95 95 "attribute highp vec2 points;\n"
96 96 "uniform highp vec2 min;\n"
97 97 "uniform highp vec2 delta;\n"
98 98 "uniform highp float pointSize;\n"
99 "uniform highp mat4 matrix;\n"
99 100 "void main() {\n"
100 101 " vec2 normalPoint = vec2(-1, -1) + ((points - min) / delta);\n"
101 " gl_Position = vec4(normalPoint, 0, 1);\n"
102 " gl_Position = matrix * vec4(normalPoint, 0, 1);\n"
102 103 " gl_PointSize = pointSize;\n"
103 104 "}";
104 105 static const char *fragmentSource =
105 106 "uniform highp vec3 color;\n"
106 107 "void main() {\n"
107 108 " gl_FragColor = vec4(color,1);\n"
108 109 "}\n";
109 110
110 111 // Must be called on render thread and in context
111 112 void DeclarativeRenderNode::initGL()
112 113 {
113 114 recreateFBO();
114 115
115 116 m_program = new QOpenGLShaderProgram;
116 117 m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource);
117 118 m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentSource);
118 119 m_program->bindAttributeLocation("points", 0);
119 120 m_program->link();
120 121
121 122 m_program->bind();
122 123 m_colorUniformLoc = m_program->uniformLocation("color");
123 124 m_minUniformLoc = m_program->uniformLocation("min");
124 125 m_deltaUniformLoc = m_program->uniformLocation("delta");
125 126 m_pointSizeUniformLoc = m_program->uniformLocation("pointSize");
127 m_matrixUniformLoc = m_program->uniformLocation("matrix");
126 128
127 129 // Create a vertex array object. In OpenGL ES 2.0 and OpenGL 2.x
128 130 // implementations this is optional and support may not be present
129 131 // at all. Nonetheless the below code works in all cases and makes
130 132 // sure there is a VAO when one is needed.
131 133 m_vao.create();
132 134 QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
133 135
134 136 #if !defined(QT_OPENGL_ES_2)
135 137 if (!QOpenGLContext::currentContext()->isOpenGLES()) {
136 138 // Make it possible to change point primitive size and use textures with them in
137 139 // the shaders. These are implicitly enabled in ES2.
138 140 // Qt Quick doesn't change these flags, so it should be safe to just enable them
139 141 // at initialization.
140 142 glEnable(GL_PROGRAM_POINT_SIZE);
141 143 }
142 144 #endif
143 145
144 146 m_program->release();
145 147 }
146 148
147 149 void DeclarativeRenderNode::recreateFBO()
148 150 {
149 151 QOpenGLFramebufferObjectFormat fboFormat;
150 152 fboFormat.setAttachment(QOpenGLFramebufferObject::NoAttachment);
151 153 delete m_fbo;
152 154 m_fbo = new QOpenGLFramebufferObject(m_textureSize.width(),
153 155 m_textureSize.height(),
154 156 fboFormat);
155 157
156 158 delete m_texture;
157 159 m_texture = m_window->createTextureFromId(m_fbo->texture(), m_textureSize, m_textureOptions);
158 160 setTexture(m_texture);
159 161
160 162 m_recreateFbo = false;
161 163 }
162 164
163 165 // Must be called on render thread and in context
164 166 void DeclarativeRenderNode::setTextureSize(const QSize &size)
165 167 {
166 168 m_textureSize = size;
167 169 m_recreateFbo = true;
168 170 m_renderNeeded = true;
169 171 }
170 172
171 173 // Must be called on render thread while gui thread is blocked, and in context
172 174 void DeclarativeRenderNode::setSeriesData(bool mapDirty, const GLXYDataMap &dataMap)
173 175 {
174 176 if (mapDirty) {
175 177 // Series have changed, recreate map, but utilize old data where feasible
176 178 GLXYDataMap oldMap = m_xyDataMap;
177 179 m_xyDataMap.clear();
178 180
179 181 GLXYDataMapIterator i(dataMap);
180 182 while (i.hasNext()) {
181 183 i.next();
182 184 GLXYSeriesData *data = oldMap.take(i.key());
183 185 const GLXYSeriesData *newData = i.value();
184 186 if (!data || newData->dirty) {
185 187 data = new GLXYSeriesData;
186 data->array = newData->array;
187 data->color = newData->color;
188 data->dirty = newData->dirty;
189 data->width = newData->width;
190 data->type = newData->type;
191 data->min = newData->min;
192 data->delta = newData->delta;
188 *data = *newData;
193 189 }
194 190 m_xyDataMap.insert(i.key(), data);
195 191 }
196 192 // Delete remaining old data
197 193 i = oldMap;
198 194 while (i.hasNext()) {
199 195 i.next();
200 196 delete i.value();
201 197 cleanXYSeriesResources(i.key());
202 198 }
203 199 } else {
204 200 // Series have not changed, so just copy dirty data over
205 201 GLXYDataMapIterator i(dataMap);
206 202 while (i.hasNext()) {
207 203 i.next();
208 204 const GLXYSeriesData *newData = i.value();
209 205 if (i.value()->dirty) {
210 206 GLXYSeriesData *data = m_xyDataMap.value(i.key());
211 if (data) {
212 data->array = newData->array;
213 data->color = newData->color;
214 data->dirty = newData->dirty;
215 data->width = newData->width;
216 data->type = newData->type;
217 data->min = newData->min;
218 data->delta = newData->delta;
219 }
207 if (data)
208 *data = *newData;
220 209 }
221 210 }
222 211 }
223 212 markDirty(DirtyMaterial);
224 213 m_renderNeeded = true;
225 214 }
226 215
227 216 void DeclarativeRenderNode::renderGL()
228 217 {
229 218 glClearColor(0, 0, 0, 0);
230 219
231 220 QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
232 221 m_program->bind();
233 222 m_fbo->bind();
234 223
235 224 glClear(GL_COLOR_BUFFER_BIT);
236 225 glEnableVertexAttribArray(0);
237 226
238 227 glViewport(0, 0, m_textureSize.width(), m_textureSize.height());
239 228
240 229 GLXYDataMapIterator i(m_xyDataMap);
241 230 while (i.hasNext()) {
242 231 i.next();
243 232 QOpenGLBuffer *vbo = m_seriesBufferMap.value(i.key());
244 233 GLXYSeriesData *data = i.value();
245 234
246 235 m_program->setUniformValue(m_colorUniformLoc, data->color);
247 236 m_program->setUniformValue(m_minUniformLoc, data->min);
248 237 m_program->setUniformValue(m_deltaUniformLoc, data->delta);
238 m_program->setUniformValue(m_matrixUniformLoc, data->matrix);
249 239
250 240 if (!vbo) {
251 241 vbo = new QOpenGLBuffer;
252 242 m_seriesBufferMap.insert(i.key(), vbo);
253 243 vbo->create();
254 244 }
255 245 vbo->bind();
256 246 if (data->dirty) {
257 247 vbo->allocate(data->array.constData(), data->array.count() * sizeof(GLfloat));
258 248 data->dirty = false;
259 249 }
260 250
261 251 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
262 252 if (data->type == QAbstractSeries::SeriesTypeLine) {
263 253 glLineWidth(data->width);
264 254 glDrawArrays(GL_LINE_STRIP, 0, data->array.size() / 2);
265 255 } else { // Scatter
266 256 m_program->setUniformValue(m_pointSizeUniformLoc, data->width);
267 257 glDrawArrays(GL_POINTS, 0, data->array.size() / 2);
268 258 }
269 259 vbo->release();
270 260 }
271 261
272 262 #ifdef QDEBUG_TRACE_GL_FPS
273 263 static QElapsedTimer stopWatch;
274 264 static int frameCount = -1;
275 265 if (frameCount == -1) {
276 266 stopWatch.start();
277 267 frameCount = 0;
278 268 }
279 269 frameCount++;
280 270 int elapsed = stopWatch.elapsed();
281 271 if (elapsed >= 1000) {
282 272 elapsed = stopWatch.restart();
283 273 qreal fps = qreal(0.1 * int(10000.0 * (qreal(frameCount) / qreal(elapsed))));
284 274 qDebug() << "FPS:" << fps;
285 275 frameCount = 0;
286 276 }
287 277 #endif
288 278
289 279 markDirty(DirtyMaterial);
290 280 m_window->resetOpenGLState();
291 281 }
292 282
293 283 // Must be called on render thread as response to beforeRendering signal
294 284 void DeclarativeRenderNode::render()
295 285 {
296 286 if (m_renderNeeded) {
297 287 if (m_xyDataMap.size()) {
298 288 if (!m_program)
299 289 initGL();
300 290 if (m_recreateFbo)
301 291 recreateFBO();
302 292 renderGL();
303 293 } else {
304 294 if (rect() != QRectF()) {
305 295 glClearColor(0, 0, 0, 0);
306 296 m_fbo->bind();
307 297 glClear(GL_COLOR_BUFFER_BIT);
308 298
309 299 // If last series was removed, zero out the node rect
310 300 setRect(QRectF());
311 301 }
312 302 }
313 303 m_renderNeeded = false;
314 304 }
315 305 }
316 306
317 307 void DeclarativeRenderNode::cleanXYSeriesResources(const QXYSeries *series)
318 308 {
319 309 if (series) {
320 310 delete m_seriesBufferMap.take(series);
321 311 delete m_xyDataMap.take(series);
322 312 } else {
323 313 foreach (QOpenGLBuffer *buffer, m_seriesBufferMap.values())
324 314 delete buffer;
325 315 m_seriesBufferMap.clear();
326 316 foreach (GLXYSeriesData *data, m_xyDataMap.values())
327 317 delete data;
328 318 m_xyDataMap.clear();
329 319 }
330 320 }
331 321
332 322 QT_CHARTS_END_NAMESPACE
@@ -1,84 +1,85
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2016 The Qt Company Ltd.
4 4 ** Contact: https://www.qt.io/licensing/
5 5 **
6 6 ** This file is part of the Qt Charts module of the Qt Toolkit.
7 7 **
8 8 ** $QT_BEGIN_LICENSE:GPL$
9 9 ** Commercial License Usage
10 10 ** Licensees holding valid commercial Qt licenses may use this file in
11 11 ** accordance with the commercial license agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and The Qt Company. For licensing terms
14 14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 15 ** information use the contact form at https://www.qt.io/contact-us.
16 16 **
17 17 ** GNU General Public License Usage
18 18 ** Alternatively, this file may be used under the terms of the GNU
19 19 ** General Public License version 3 or (at your option) any later version
20 20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 22 ** included in the packaging of this file. Please review the following
23 23 ** information to ensure the GNU General Public License requirements will
24 24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 25 **
26 26 ** $QT_END_LICENSE$
27 27 **
28 28 ****************************************************************************/
29 29
30 30 #ifndef DECLARATIVERENDERNODE_P_H
31 31 #define DECLARATIVERENDERNODE_P_H
32 32
33 33 #include <QtCharts/QChartGlobal>
34 34 #include <private/glxyseriesdata_p.h>
35 35 #include <QtQuick/QSGSimpleTextureNode>
36 36 #include <QtQuick/QQuickWindow>
37 37 #include <QtGui/QOpenGLVertexArrayObject>
38 38 #include <QtGui/QOpenGLFunctions>
39 39 #include <QtGui/QOpenGLFramebufferObject>
40 40 #include <QtGui/QOpenGLBuffer>
41 41
42 42 QT_CHARTS_BEGIN_NAMESPACE
43 43
44 44 class DeclarativeRenderNode : public QObject, public QSGSimpleTextureNode, QOpenGLFunctions
45 45 {
46 46 Q_OBJECT
47 47 public:
48 48 DeclarativeRenderNode(QQuickWindow *window);
49 49 ~DeclarativeRenderNode();
50 50
51 51 void initGL();
52 52 QSize textureSize() const { return m_textureSize; }
53 53 void setTextureSize(const QSize &size);
54 54 void setSeriesData(bool mapDirty, const GLXYDataMap &dataMap);
55 55
56 56 public Q_SLOTS:
57 57 void render();
58 58
59 59 private:
60 60 void renderGL();
61 61 void recreateFBO();
62 62 void cleanXYSeriesResources(const QXYSeries *series);
63 63
64 64 QSGTexture *m_texture;
65 65 QQuickWindow *m_window;
66 66 QQuickWindow::CreateTextureOptions m_textureOptions;
67 67 QSize m_textureSize;
68 68 bool m_recreateFbo;
69 69 GLXYDataMap m_xyDataMap;
70 70 QOpenGLFramebufferObject *m_fbo;
71 71 QOpenGLShaderProgram *m_program;
72 72 int m_shaderAttribLoc;
73 73 int m_colorUniformLoc;
74 74 int m_minUniformLoc;
75 75 int m_deltaUniformLoc;
76 76 int m_pointSizeUniformLoc;
77 int m_matrixUniformLoc;
77 78 QOpenGLVertexArrayObject m_vao;
78 79 QHash<const QAbstractSeries *, QOpenGLBuffer *> m_seriesBufferMap;
79 80 bool m_renderNeeded;
80 81 };
81 82
82 83 QT_CHARTS_END_NAMESPACE
83 84
84 85 #endif // DECLARATIVERENDERNODE_P_H
General Comments 0
You need to be logged in to leave comments. Login now