Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / chart2 / source / view / charttypes / GL3DBarChart.cxx
blob60309d08ad2a83568250951605453bd09bfbf2e4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <GL3DBarChart.hxx>
12 #include <epoxy/gl.h>
14 #include <cmath>
15 #include <glm/glm.hpp>
16 #include <glm/gtx/transform.hpp>
18 #include <3DChartObjects.hxx>
19 #include <GL3DRenderer.hxx>
20 #include <ExplicitCategoriesProvider.hxx>
21 #include <DataSeriesHelper.hxx>
23 #include <osl/time.h>
24 #ifdef _WIN32
25 #if !defined WIN32_LEAN_AND_MEAN
26 # define WIN32_LEAN_AND_MEAN
27 #endif
28 #include <windows.h>
29 #endif
30 #include <memory>
31 #include <o3tl/make_unique.hxx>
33 #define CALC_POS_EVENT_ID 1
34 #define SHAPE_START_ID 10
35 #define FPS_TIME 500
36 #define DATAUPDATE_FPS_TIME 1000
37 #define HISTORY_NUM 51
38 #define COLUMNSIZE 25
39 #define SHOW_VALUE_COUNT 15
40 #define SHOW_SCROLL_TEXT_DISTANCE 1000
41 #define FLY_THRESHOLD 20
42 #define DISPLAY_BARS_NUM 3
45 using namespace com::sun::star;
47 namespace chart {
49 const size_t STEPS = 200;
50 const size_t STEPS_UPDATE = 100;
51 namespace {
53 const float TEXT_HEIGHT = 10.0f;
54 float DEFAULT_CAMERA_HEIGHT = 500.0f;
55 const sal_uInt32 ID_STEP = 10;
57 const float BAR_SIZE_X = 30.0f;
58 const float BAR_SIZE_Y = 5.0f;
59 const float BAR_DISTANCE_X = 5.0f;
60 const float BAR_DISTANCE_Y = 5.0;
62 float calculateTextWidth(const OUString& rText)
64 return rText.getLength() * 10;
67 double findMaxValue(const std::vector<std::unique_ptr<VDataSeries> >& rDataSeriesContainer)
69 double nMax = 0.0;
70 for (const std::unique_ptr<VDataSeries>& rDataSeries : rDataSeriesContainer)
72 sal_Int32 nPointCount = rDataSeries->getTotalPointCount();
73 for(sal_Int32 nIndex = 0; nIndex < nPointCount; ++nIndex)
75 double nVal = rDataSeries->getYValue(nIndex);
76 nMax = std::max(nMax, nVal);
79 return nMax;
82 class SharedResourceAccess
84 private:
85 osl::Condition& mrCond2;
87 public:
89 SharedResourceAccess(osl::Condition& rCond1, osl::Condition& rCond2):
90 mrCond2(rCond2)
92 rCond1.set();
95 ~SharedResourceAccess()
97 mrCond2.set();
103 class RenderThread : public salhelper::Thread
105 public:
106 explicit RenderThread(GL3DBarChart* pChart);
108 protected:
110 void renderFrame();
111 GL3DBarChart* mpChart;
114 RenderThread::RenderThread(GL3DBarChart* pChart):
115 salhelper::Thread("RenderThread"),
116 mpChart(pChart)
120 void RenderThread::renderFrame()
122 if(!mpChart->mbValidContext)
123 return;
125 mpChart->mpWindow->getContext().makeCurrent();
126 mpChart->renderFrame();
127 // FIXME: SwapBuffers can take a considerable time, it'd be
128 // nice if we didn't hold the chart mutex while doing that.
129 mpChart->mpWindow->getContext().swapBuffers();
130 mpChart->mpWindow->getContext().resetCurrent();
133 class RenderOneFrameThread : public RenderThread
135 public:
136 explicit RenderOneFrameThread(GL3DBarChart* pChart):
137 RenderThread(pChart)
140 protected:
142 virtual void execute() override;
145 void RenderOneFrameThread::execute()
147 osl::MutexGuard aGuard(mpChart->maMutex);
148 renderFrame();
151 class RenderAnimationThread : public RenderThread
153 public:
154 RenderAnimationThread(GL3DBarChart* pChart, const glm::vec3& rStartPos, const glm::vec3& rEndPos,
155 const sal_Int32 nSteps):
156 RenderThread(pChart),
157 maStartPos(rStartPos),
158 maEndPos(rEndPos),
159 mnSteps(nSteps)
163 protected:
165 virtual void execute() override;
167 private:
168 glm::vec3 maStartPos;
169 glm::vec3 maEndPos;
170 sal_Int32 mnSteps;
174 void RenderAnimationThread::execute()
176 osl::MutexGuard aGuard(mpChart->maMutex);
177 glm::vec3 aStep = (maEndPos - maStartPos)/static_cast<float>(mnSteps);
178 for(sal_Int32 i = 0; i < mnSteps; ++i)
180 mpChart->maCameraPosition += aStep;
181 mpChart->mpCamera->setPosition(mpChart->maCameraPosition);
183 mpChart->maCameraDirection += mpChart->maStepDirection;
184 mpChart->mpCamera->setDirection(mpChart->maCameraDirection);
186 renderFrame();
188 mpChart->mpRenderer->ReleaseScreenTextShapes();
191 class RenderBenchMarkThread : public RenderThread
193 public:
194 explicit RenderBenchMarkThread(GL3DBarChart * pChart)
195 : RenderThread(pChart)
196 , mbAutoFlyExecuting(false)
197 , mbExecuting(false)
198 , mbNeedFlyBack(false)
199 , mnStep(0)
200 , mnStepsTotal(0)
202 osl_getSystemTime(&maClickFlyBackStartTime);
203 osl_getSystemTime(&maClickFlyBackEndTime);
205 protected:
206 virtual void execute() override;
207 private:
208 void ProcessMouseEvent();
209 void MoveCamera();
210 void MoveCameraToBar();
211 void MoveToBar();
212 void MoveToSelectedBar();
213 void MoveToDefault();
214 void MoveToCorner();
215 void ProcessScroll();
216 void UpdateScreenText();
217 void ProcessClickFlyBack();
218 void AutoMoveToBar();
219 private:
220 bool mbAutoFlyExecuting;
221 bool mbExecuting;
222 bool mbNeedFlyBack;
223 glm::vec3 maStep;
224 glm::vec3 maStepDirection;
225 glm::mat4 maMatrixStep;
226 size_t mnStep;
227 size_t mnStepsTotal;
228 TimeValue maClickFlyBackStartTime;
229 TimeValue maClickFlyBackEndTime;
230 glm::vec3 maTargetPosition;
231 glm::vec3 maTargetDirection;
234 void RenderBenchMarkThread::MoveCamera()
236 if(mnStep < mnStepsTotal)
238 ++mnStep;
239 mpChart->maCameraPosition += maStep;
240 mpChart->mpCamera->setPosition(mpChart->maCameraPosition);
241 mpChart->maCameraDirection += maStepDirection;
242 mpChart->mpCamera->setDirection(mpChart->maCameraDirection);
244 else
246 mnStep = 0;
247 mbExecuting = false;
248 mbAutoFlyExecuting = false;
249 mbNeedFlyBack = false;
250 mpChart->maRenderEvent = EVENT_NONE;
254 void RenderBenchMarkThread::MoveCameraToBar()
256 if(mnStep < mnStepsTotal)
258 ++mnStep;
259 mpChart->mpRenderer->AddMatrixDiff(maMatrixStep);
261 else
263 mpChart->maCameraPosition = maTargetPosition;
264 mpChart->maCameraDirection = maTargetDirection;
265 mpChart->mpCamera->setPosition(maTargetPosition);
266 mpChart->mpCamera->setDirection(maTargetDirection);
267 mpChart->mpRenderer->ResetMatrixDiff();
268 mnStep = 0;
269 mbExecuting = false;
270 mbAutoFlyExecuting = false;
271 mbNeedFlyBack = true;
272 osl_getSystemTime(&maClickFlyBackStartTime);
273 osl_getSystemTime(&maClickFlyBackEndTime);
274 mpChart->maRenderEvent = EVENT_SHOW_SELECT;
279 void RenderBenchMarkThread::MoveToDefault()
281 if ((mpChart->maCameraPosition == mpChart->maDefaultCameraDirection) &&
282 (mpChart->maCameraDirection == mpChart->maDefaultCameraDirection))
284 mnStep = 0;
285 mbExecuting = false;
286 mpChart->maRenderEvent = EVENT_NONE;
287 return;
289 if (!mbExecuting)
291 mpChart->mpRenderer->EndClick();
292 mnStep = 0;
293 mnStepsTotal = STEPS;
294 maStep = (mpChart->maDefaultCameraPosition - mpChart->maCameraPosition)/static_cast<float>(mnStepsTotal);
295 maStepDirection = (mpChart->maDefaultCameraDirection - mpChart->maCameraDirection)/static_cast<float>(mnStepsTotal);
296 mbExecuting = true;
298 MoveCamera();
301 void RenderBenchMarkThread::MoveToBar()
303 if (!mbExecuting)
305 mpChart->mnSelectBarId = mpChart->barIdAtPosition(mpChart->maClickPos);
307 std::map<sal_uInt32, const GL3DBarChart::BarInformation>::const_iterator itr = mpChart->maBarMap.find(mpChart->mnSelectBarId);
308 if(itr == mpChart->maBarMap.end())
310 mpChart->mnSelectBarId = mpChart->mnPreSelectBarId;
311 mpChart->maRenderEvent = mpChart->maPreRenderEvent;
312 mpChart->maClickCond.set();
313 return;
315 mpChart->mpRenderer->EndClick();
316 const GL3DBarChart::BarInformation& rBarInfo = itr->second;
317 mnStep = 0;
318 mnStepsTotal = STEPS;
319 maTargetPosition = rBarInfo.maPos;
320 maTargetPosition.z += 240;
321 maTargetPosition.x += BAR_SIZE_X / 2.0f;
322 maTargetDirection = rBarInfo.maPos;
323 maTargetDirection.x += BAR_SIZE_X / 2.0f;
324 maTargetDirection.y += BAR_SIZE_Y / 2.0f;
325 maTargetPosition.y = maTargetDirection.y - 240;
326 maMatrixStep = mpChart->mpRenderer->GetDiffOfTwoCameras(mpChart->maCameraPosition, maTargetPosition, mpChart->maCameraDirection, maTargetDirection)/static_cast<float>(mnStepsTotal);
327 mpChart->maClickCond.set();
328 mbExecuting = true;
329 mbNeedFlyBack = false;
330 mpChart->mpRenderer->StartClick(mpChart->mnSelectBarId);
332 MoveCameraToBar();
335 void RenderBenchMarkThread::MoveToSelectedBar()
337 mpChart->mnSelectBarId = mpChart->mnUpdateBarId;
338 std::map<sal_uInt32, const GL3DBarChart::BarInformation>::const_iterator itr = mpChart->maBarMap.find(mpChart->mnSelectBarId);
339 if(itr == mpChart->maBarMap.end())
341 mpChart->mnSelectBarId = mpChart->mnPreSelectBarId;
342 mpChart->maRenderEvent = mpChart->maPreRenderEvent;
343 mpChart->maClickCond.set();
344 return;
346 mpChart->mpRenderer->EndClick();
347 const GL3DBarChart::BarInformation& rBarInfo = itr->second;
348 mnStep = 0;
349 mnStepsTotal = STEPS_UPDATE;
350 maTargetPosition = rBarInfo.maPos;
351 maTargetPosition.z += 240;
352 maTargetPosition.x += BAR_SIZE_X / 2.0f;
353 maTargetDirection = rBarInfo.maPos;
354 maTargetDirection.x += BAR_SIZE_X / 2.0f;
355 maTargetDirection.y += BAR_SIZE_Y / 2.0f;
356 maTargetPosition.y = maTargetDirection.y - 240;
357 maMatrixStep = mpChart->mpRenderer->GetDiffOfTwoCameras( maTargetPosition, maTargetDirection)/static_cast<float>(mnStepsTotal);
358 mpChart->maClickCond.set();
359 mbExecuting = true;
360 mbNeedFlyBack = false;
361 mpChart->mpRenderer->StartClick(mpChart->mnSelectBarId);
362 mpChart->maRenderEvent = EVENT_CLICK;
365 void RenderBenchMarkThread::AutoMoveToBar()
367 if (!mbAutoFlyExecuting)
369 mpChart->mpRenderer->EndClick();
370 std::map<sal_uInt32, const GL3DBarChart::BarInformation>::const_iterator itr = mpChart->maBarMap.find(mpChart->mnSelectBarId);
371 if(itr == mpChart->maBarMap.end())
373 mpChart->maRenderEvent = EVENT_NONE;
374 return;
376 const GL3DBarChart::BarInformation& rBarInfo = itr->second;
377 mnStep = 0;
378 mnStepsTotal = STEPS;
379 maTargetPosition = rBarInfo.maPos;
380 maTargetPosition.z += 240;
381 maTargetPosition.x += BAR_SIZE_X / 2.0f;
382 maTargetDirection = rBarInfo.maPos;
383 maTargetDirection.x += BAR_SIZE_X / 2.0f;
384 maTargetDirection.y += BAR_SIZE_Y / 2.0f;
385 maTargetPosition.y = maTargetDirection.y - 240;
386 maMatrixStep = mpChart->mpRenderer->GetDiffOfTwoCameras(mpChart->maCameraPosition, maTargetPosition, mpChart->maCameraDirection, maTargetDirection)/static_cast<float>(mnStepsTotal);
387 mpChart->mpRenderer->StartClick(mpChart->mnSelectBarId);
388 mbAutoFlyExecuting = true;
389 mbNeedFlyBack = false;
391 MoveCameraToBar();
394 void RenderBenchMarkThread::MoveToCorner()
396 if (!mbExecuting)
398 mpChart->mpRenderer->EndClick();
399 mnStep = 0;
400 mnStepsTotal = STEPS;
401 maStep = (mpChart->getCornerPosition(mpChart->mnCornerId) - mpChart->maCameraPosition) / float(mnStepsTotal);
402 maStepDirection = (glm::vec3(mpChart->mnMaxX/2.0f, mpChart->mnMaxY/2.0f, 0) - mpChart->maCameraDirection)/ float(mnStepsTotal);
403 mbExecuting = true;
405 MoveCamera();
408 void RenderBenchMarkThread::ProcessScroll()
410 //will add other process later
411 mpChart->mpRenderer->EndClick();
412 mnStep = 0;
413 mnStepsTotal = STEPS;
414 mpChart->maRenderEvent = EVENT_SHOW_SCROLL;
417 void RenderBenchMarkThread::ProcessClickFlyBack()
419 if (!mbNeedFlyBack)
420 return;
421 osl_getSystemTime(&maClickFlyBackEndTime);
422 int nDeltaMs = GL3DBarChart::calcTimeInterval(maClickFlyBackStartTime, maClickFlyBackEndTime);
423 if(nDeltaMs >= 10000)
425 mpChart->maRenderEvent = EVENT_MOVE_TO_DEFAULT;
429 void RenderBenchMarkThread::ProcessMouseEvent()
431 ProcessClickFlyBack();
432 if (mpChart->maRenderEvent == EVENT_SELECTBAR_UPDEDATE)
434 MoveToSelectedBar();
436 else if (mpChart->maRenderEvent == EVENT_CLICK)
438 MoveToBar();
440 else if (mpChart->maRenderEvent == EVENT_MOVE_TO_DEFAULT)
442 MoveToDefault();
444 else if ((mpChart->maRenderEvent == EVENT_DRAG_LEFT) || (mpChart->maRenderEvent == EVENT_DRAG_RIGHT))
446 MoveToCorner();
448 else if (mpChart->maRenderEvent == EVENT_SCROLL)
450 ProcessScroll();
452 else if (mpChart->maRenderEvent == EVENT_AUTO_FLY)
454 AutoMoveToBar();
459 void RenderBenchMarkThread::UpdateScreenText()
461 if (mpChart->mbScreenTextNewRender)
463 mpChart->mpWindow->getContext().makeCurrent();
464 mpChart->mpRenderer->ReleaseScreenTextTexture();
465 for(std::unique_ptr<opengl3D::Renderable3DObject>& aObj : mpChart->maScreenTextShapes)
467 aObj->render();
469 mpChart->mbScreenTextNewRender = false;
470 mpChart->mpWindow->getContext().resetCurrent();
474 void RenderBenchMarkThread::execute()
476 while (true)
479 osl::MutexGuard aGuard(mpChart->maMutex);
480 mpChart->maCond2.reset();
481 if (mpChart->mbRenderDie)
482 break;
483 UpdateScreenText();
484 ProcessMouseEvent();
485 renderFrame();
486 mpChart->miFrameCount++;
488 if (mpChart->maCond1.check())
490 mpChart->maCond1.reset();
491 mpChart->maCond2.wait();
496 GL3DBarChart::GL3DBarChart(
497 const css::uno::Reference<css::chart2::XChartType>& xChartType,
498 OpenGLWindow* pWindow) :
499 mxChartType(xChartType),
500 mpRenderer(new opengl3D::OpenGL3DRenderer()),
501 mpWindow(pWindow),
502 mpCamera(nullptr),
503 mbValidContext(true),
504 mpTextCache(new opengl3D::TextCache),
505 mnMaxX(0),
506 mnMaxY(0),
507 mnDistance(0.0),
508 mnCornerId(0),
509 mbNeedsNewRender(true),
510 mbCameraInit(false),
511 mbRenderDie(false),
512 maRenderEvent(EVENT_NONE),
513 maPreRenderEvent(EVENT_NONE),
514 mnSelectBarId(0),
515 mnPreSelectBarId(0),
516 miScrollRate(0),
517 mbScrollFlg(false),
518 maIdle("chart2 view GL3DBarChart"),
519 mbScreenTextNewRender(false),
520 maFPS(OUString("Render FPS: 0")),
521 maDataUpdateFPS(OUString("Data Update FPS: 0")),
522 miFrameCount(0),
523 miDataUpdateCounter(0),
524 mnColorRate(0),
525 mbBenchMarkMode(false),
526 mnHistoryCounter(0),
527 mnBarsInRow(0),
528 mbAutoFly(false),
529 mnUpdateBarId(0)
531 maFPSRenderStartTime.Seconds = maFPSRenderStartTime.Nanosec = 0;
532 maFPSRenderEndTime.Seconds = maFPSRenderEndTime.Nanosec = 0;
533 maDataUpdateStartTime.Seconds = maDataUpdateStartTime.Nanosec = 0;
534 maDataUpdateEndTime.Seconds = maDataUpdateEndTime.Nanosec = 0;
536 static const char *aBenchMark = getenv("UNLOCK_FPS_MODE");
537 if (aBenchMark)
539 mbBenchMarkMode = atoi(aBenchMark);
541 if (mbBenchMarkMode)
543 static const char *scrollFrame = getenv("SCROLL_RATE");
544 if (scrollFrame)
546 miScrollRate = atoi(scrollFrame);
547 if (miScrollRate > 0)
549 mbScrollFlg = true;
550 mpRenderer->SetScroll();
553 char *aAutoFly = getenv("AUTO_FLY");
554 if (aAutoFly)
556 mbAutoFly = atoi(aAutoFly);
558 maIdle.SetPriority(TaskPriority::REPAINT);
559 maIdle.SetInvokeHandler(LINK(this, GL3DBarChart, UpdateTimerHdl));
560 maIdle.SetDebugName( "charttypes::GL3DBarChart maIdle" );
561 maIdle.Start();
562 osl_getSystemTime(&maFPSRenderStartTime);
563 osl_getSystemTime(&maFPSRenderEndTime);
564 osl_getSystemTime(&maDataUpdateStartTime);
565 osl_getSystemTime(&maDataUpdateEndTime);
567 Size aSize = mpWindow->GetSizePixel();
568 mpRenderer->SetSize(aSize);
569 mpWindow->setRenderer(this);
570 mpWindow->getContext().makeCurrent();
571 mpRenderer->init();
572 mpWindow->getContext().resetCurrent();
575 GL3DBarChart::BarInformation::BarInformation(const glm::vec3& rPos, float nVal):
576 maPos(rPos),
577 mnVal(nVal)
581 GL3DBarChart::~GL3DBarChart()
583 if (mbBenchMarkMode)
585 SharedResourceAccess aResGuard(maCond1, maCond2);
586 osl::MutexGuard aGuard(maMutex);
587 mbRenderDie = true;
590 joinRenderThread();
592 if (mbValidContext)
594 mpWindow->setRenderer(nullptr);
595 mpWindow->getContext().makeCurrent();
596 mpRenderer.reset();
597 mpWindow->getContext().resetCurrent();
601 void GL3DBarChart::create3DShapes(const std::vector<std::unique_ptr<VDataSeries> >& rDataSeriesContainer,
602 ExplicitCategoriesProvider& rCatProvider)
604 SharedResourceAccess aResGuard(maCond1, maCond2);
605 osl::MutexGuard aGuard(maMutex);
606 if(mnSelectBarId)
608 int nSelectBarId = mnSelectBarId;
609 int nPreSelectBarId = nSelectBarId;
610 nSelectBarId -= 10;
611 sal_uInt32 nSelectRow = (nSelectBarId - SHAPE_START_ID) / ID_STEP / (mnBarsInRow + 1);
612 sal_uInt32 nPreSelectRow = (nPreSelectBarId - SHAPE_START_ID) / ID_STEP / (mnBarsInRow + 1);
613 if(nSelectRow == nPreSelectRow)
615 std::map<sal_uInt32, const GL3DBarChart::BarInformation>::const_iterator itr = maBarMap.find(nSelectBarId);
616 if((maRenderEvent == EVENT_CLICK || maRenderEvent == EVENT_SHOW_SELECT || maRenderEvent == EVENT_AUTO_FLY)&&(itr != maBarMap.end()))
618 mnUpdateBarId = nSelectBarId;
619 maRenderEvent = EVENT_SELECTBAR_UPDEDATE;
623 mpRenderer->ReleaseShapes();
624 // Each series of data flows from left to right, and multiple series are
625 // stacked vertically along y axis.
627 sal_uInt32 nId = SHAPE_START_ID;
628 float nXEnd = 0.0;
629 float nYPos = 0.0;
631 const Color aSeriesColor[] = {
632 COL_RED, COL_GREEN, COL_YELLOW, COL_BROWN, COL_BLUE
635 maCategories.clear();
636 maSeriesNames.clear();
637 maSeriesNames.reserve(rDataSeriesContainer.size());
638 maBarMap.clear();
639 maShapes.clear();
640 if (mbBenchMarkMode)
642 mnColorRate = 0;
644 maShapes.push_back(o3tl::make_unique<opengl3D::Camera>(mpRenderer.get()));
645 mpCamera = static_cast<opengl3D::Camera*>(maShapes.back().get());
647 sal_Int32 nSeriesIndex = 0;
648 sal_Int32 nMaxPointCount = 0;
649 double nMaxVal = findMaxValue(rDataSeriesContainer)/100;
650 if (rDataSeriesContainer.empty())
652 mnBarsInRow = 0;
654 else
656 const VDataSeries& rFirstRow = *rDataSeriesContainer.begin()->get();
657 mnBarsInRow = rFirstRow.getTotalPointCount();
659 for (const std::unique_ptr<VDataSeries>& rDataSeries : rDataSeriesContainer)
661 nYPos = nSeriesIndex * (BAR_SIZE_Y + BAR_DISTANCE_Y) + BAR_DISTANCE_Y;
663 sal_Int32 nPointCount = rDataSeries->getTotalPointCount();
664 nMaxPointCount = std::max(nMaxPointCount, nPointCount);
666 bool bMappedFillProperty = rDataSeries->hasPropertyMapping("FillColor");
668 // Create series name text object.
669 OUString aSeriesName =
670 DataSeriesHelper::getDataSeriesLabel(
671 rDataSeries->getModel(), mxChartType->getRoleOfSequenceForSeriesLabel());
673 maSeriesNames.push_back(aSeriesName);
675 if(!aSeriesName.isEmpty())
677 maShapes.push_back(o3tl::make_unique<opengl3D::Text>(mpRenderer.get(),
678 *mpTextCache, aSeriesName, nId));
679 nId += ID_STEP;
680 opengl3D::Text* p = static_cast<opengl3D::Text*>(maShapes.back().get());
681 glm::vec3 aTopLeft, aTopRight, aBottomRight;
682 aTopRight.x = -BAR_DISTANCE_Y;
683 aTopRight.y = nYPos + BAR_DISTANCE_Y;
684 aTopLeft.x = calculateTextWidth(aSeriesName) * -1.0 - BAR_DISTANCE_Y;
685 aTopLeft.y = nYPos + BAR_DISTANCE_Y;
686 aBottomRight = aTopRight;
687 aBottomRight.y -= TEXT_HEIGHT;
688 p->setPosition(aTopLeft, aTopRight, aBottomRight);
691 Color nColor = aSeriesColor[nSeriesIndex % SAL_N_ELEMENTS(aSeriesColor)];
692 for(sal_Int32 nIndex = 0; nIndex < nPointCount; ++nIndex)
694 if(bMappedFillProperty)
696 double nPropVal = rDataSeries->getValueByProperty(nIndex, "FillColor");
697 if(!rtl::math::isNan(nPropVal))
698 nColor = Color(static_cast<sal_uInt32>(nPropVal));
701 float nVal = rDataSeries->getYValue(nIndex);
702 if (rtl::math::isNan(nVal))
703 continue;
705 float nXPos = nIndex * (BAR_SIZE_X + BAR_DISTANCE_X) + BAR_DISTANCE_X;
707 glm::mat4 aScaleMatrix = glm::scale(glm::vec3(BAR_SIZE_X, BAR_SIZE_Y, float(nVal/nMaxVal)));
708 glm::mat4 aTranslationMatrix = glm::translate(glm::vec3(nXPos, nYPos, 0.0f));
709 glm::mat4 aBarPosition = aTranslationMatrix * aScaleMatrix;
711 maBarMap.insert(std::pair<sal_uInt32, BarInformation>(nId,
712 BarInformation(glm::vec3(nXPos, nYPos, float(nVal/nMaxVal)),
713 nVal)));
714 recordBarHistory(nId, nVal);
715 if (mbBenchMarkMode)
717 auto it = maBarColorMap.find(nId);
718 if (it == maBarColorMap.end())
720 maBarColorMap[nId] = nColor;
722 else
724 if(mbAutoFly)
725 processAutoFly(nId, nColor);
728 maShapes.push_back(o3tl::make_unique<opengl3D::Bar>(mpRenderer.get(), aBarPosition, nColor, nId));
729 nId += ID_STEP;
732 float nThisXEnd = nPointCount * (BAR_SIZE_X + BAR_DISTANCE_X);
733 if (nXEnd < nThisXEnd)
734 nXEnd = nThisXEnd;
736 ++nSeriesIndex;
739 nYPos += BAR_SIZE_Y + BAR_DISTANCE_Y;
741 // X axis
742 maShapes.push_back(o3tl::make_unique<opengl3D::Line>(mpRenderer.get(), nId));
743 nId += ID_STEP;
744 opengl3D::Line* pAxis = static_cast<opengl3D::Line*>(maShapes.back().get());
745 glm::vec3 aBegin;
746 aBegin.y = nYPos;
747 glm::vec3 aEnd = aBegin;
748 aEnd.x = mbBenchMarkMode ? (mbScrollFlg ? nXEnd - BAR_SIZE_X : nXEnd) : nXEnd;
749 pAxis->setPosition(aBegin, aEnd);
750 pAxis->setLineColor(COL_BLUE);
752 // Y axis
753 maShapes.push_back(o3tl::make_unique<opengl3D::Line>(mpRenderer.get(), nId));
754 nId += ID_STEP;
755 pAxis = static_cast<opengl3D::Line*>(maShapes.back().get());
756 aBegin.x = aBegin.y = 0;
757 aEnd = aBegin;
758 aEnd.y = nYPos;
759 pAxis->setPosition(aBegin, aEnd);
760 pAxis->setLineColor(COL_BLUE);
762 // Chart background.
763 maShapes.push_back(o3tl::make_unique<opengl3D::Rectangle>(mpRenderer.get(), nId));
764 nId += ID_STEP;
765 opengl3D::Rectangle* pRect = static_cast<opengl3D::Rectangle*>(maShapes.back().get());
766 glm::vec3 aTopLeft;
767 glm::vec3 aTopRight = aTopLeft;
768 aTopRight.x = mbBenchMarkMode ? (mbScrollFlg ? nXEnd - BAR_SIZE_X : nXEnd + 2 * BAR_DISTANCE_X) : (nXEnd + 2 * BAR_DISTANCE_X);
769 glm::vec3 aBottomRight = aTopRight;
770 aBottomRight.y = nYPos;
771 pRect->setPosition(aTopLeft, aTopRight, aBottomRight);
772 pRect->setFillColor(COL_BLACK);
773 pRect->setLineColor(COL_BLUE);
774 if (mbScrollFlg)
775 mpRenderer->SetSceneEdge(BAR_DISTANCE_X - 0.001f, aTopRight.x - BAR_DISTANCE_X);
776 else
777 mpRenderer->SetSceneEdge(-0.001f, aTopRight.x);
778 // Create category texts along X-axis at the bottom.
779 uno::Sequence<OUString> aCats = rCatProvider.getSimpleCategories();
780 for (sal_Int32 i = 0; i < aCats.getLength(); ++i)
782 if (mbBenchMarkMode && mbScrollFlg && (i + 1 == aCats.getLength()))
783 break;
784 maCategories.push_back(aCats[i]);
785 if(aCats[i].isEmpty())
786 continue;
788 float nXPos = i * (BAR_SIZE_X + BAR_DISTANCE_X);
790 maShapes.push_back(o3tl::make_unique<opengl3D::Text>(mpRenderer.get(), *mpTextCache,
791 aCats[i], nId));
792 nId += ID_STEP;
793 opengl3D::Text* p = static_cast<opengl3D::Text*>(maShapes.back().get());
794 aTopLeft.x = nXPos + TEXT_HEIGHT + 0.5 * BAR_SIZE_X;
795 aTopLeft.y = nYPos + calculateTextWidth(aCats[i]) + 0.5 * BAR_DISTANCE_Y;
796 aTopRight = aTopLeft;
797 aTopRight.y = nYPos + 0.5* BAR_DISTANCE_Y;
798 aBottomRight.x = nXPos;
799 aBottomRight.y = nYPos + 0.5 * BAR_DISTANCE_Y;
800 p->setPosition(aTopLeft, aTopRight, aBottomRight);
802 // create shapes on other side as well
804 maShapes.push_back(o3tl::make_unique<opengl3D::Text>(mpRenderer.get(), *mpTextCache,
805 aCats[i], nId));
806 nId += ID_STEP;
807 p = static_cast<opengl3D::Text*>(maShapes.back().get());
808 aTopLeft.x = nXPos + TEXT_HEIGHT + 0.5 * BAR_SIZE_X;
809 aTopLeft.y = - 0.5 * BAR_DISTANCE_Y;
810 aTopRight = aTopLeft;
811 aTopRight.y = -calculateTextWidth(aCats[i]) - 0.5* BAR_DISTANCE_Y;
812 aBottomRight.x = nXPos;
813 aBottomRight.y = -calculateTextWidth(aCats[i]) - 0.5 * BAR_DISTANCE_Y;
814 p->setPosition(aTopLeft, aTopRight, aBottomRight);
817 mnMaxX = nMaxPointCount * (BAR_SIZE_X + BAR_DISTANCE_X) + 40;
818 mnMaxY = nSeriesIndex * (BAR_SIZE_Y + BAR_DISTANCE_Y) + 40;
819 if (!mbCameraInit)
821 mnDistance = std::sqrt(mnMaxX * mnMaxX + mnMaxY * mnMaxY + DEFAULT_CAMERA_HEIGHT * DEFAULT_CAMERA_HEIGHT);
822 maDefaultCameraDirection = glm::vec3(mnMaxX * 0.4, mnMaxY * 0.35, 0);
823 maDefaultCameraPosition = glm::vec3(maDefaultCameraDirection.x, maDefaultCameraDirection.y - mnDistance, DEFAULT_CAMERA_HEIGHT * 2);
824 mnCornerId = 0;
825 mbCameraInit = true;
826 float pi = 3.1415926f;
827 float nAngleX = -pi / 6.5f;
828 float nAngleZ = -pi / 8.0f;
829 glm::mat4 aDefaultRotateMatrix = glm::eulerAngleYXZ(0.0f, nAngleX, nAngleZ);
830 maDefaultCameraPosition = glm::vec3(aDefaultRotateMatrix * glm::vec4(maDefaultCameraPosition, 1.0f));
831 maCameraPosition = maDefaultCameraPosition;
832 maCameraDirection = maDefaultCameraDirection;
833 mpCamera->setPosition(maCameraPosition);
834 mpCamera->setDirection(maCameraDirection);
836 else
838 mpCamera->setPosition(maCameraPosition);
839 mpCamera->setDirection(maCameraDirection);
841 if (mbBenchMarkMode && (!mpRenderThread.is()))
843 //if scroll the bars, set the speed and distance first
844 if (mbScrollFlg)
846 mpRenderer->SetScrollSpeed((BAR_SIZE_X + BAR_DISTANCE_X) / static_cast<float>(miScrollRate));
847 mpRenderer->SetScrollDistance(BAR_SIZE_X + BAR_DISTANCE_X);
849 spawnRenderThread(new RenderBenchMarkThread(this));
851 miDataUpdateCounter++;
852 mnHistoryCounter++;
853 mbNeedsNewRender = true;
856 void GL3DBarChart::joinRenderThread()
858 if(mpRenderThread.is())
860 // FIXME: badly want to assert that we don't
861 // hold the mutex here ... but can't API-wise.
862 mpRenderThread->join();
866 void GL3DBarChart::spawnRenderThread(RenderThread *pThread)
868 joinRenderThread(); // not holding maMutex
870 osl::MutexGuard aGuard(maMutex);
872 Size aSize = mpWindow->GetSizePixel();
873 mpWindow->getContext().setWinSize(aSize);
874 mpRenderThread.set(pThread);
875 mpWindow->getContext().resetCurrent();
876 mpRenderThread->launch();
879 void GL3DBarChart::update()
881 if (mbBenchMarkMode)
882 return;
883 spawnRenderThread(new RenderOneFrameThread(this));
886 void GL3DBarChart::moveToDefault()
888 if(mbBenchMarkMode)
890 // add correct handling here!!
891 if ((maRenderEvent != EVENT_NONE) && (maRenderEvent != EVENT_SHOW_SCROLL) &&
892 (maRenderEvent != EVENT_AUTO_FLY) && (maRenderEvent != EVENT_SHOW_SELECT))
893 return;
896 SharedResourceAccess aResGuard(maCond1, maCond2);
897 osl::MutexGuard aGuard(maMutex);
898 maRenderEvent = EVENT_MOVE_TO_DEFAULT;
900 return;
903 spawnRenderThread(new RenderAnimationThread(this, maCameraPosition, maDefaultCameraPosition, STEPS));
906 * TODO: moggi: add to thread
907 glm::vec3 maTargetDirection = maDefaultCameraDirection;
908 maStepDirection = (maTargetDirection - maCameraDirection)/((float)mnStepsTotal);
912 sal_uInt32 GL3DBarChart::barIdAtPosition(const Point& rPos)
914 sal_uInt32 nId = 5;
916 osl::MutexGuard aGuard(maMutex);
917 mpWindow->getContext().makeCurrent();
918 mpRenderer->SetPickingMode(true);
919 renderFrame();
920 nId = sal_uInt32(mpRenderer->GetPixelColorFromPoint(rPos.X(), rPos.Y()));
921 mpRenderer->SetPickingMode(false);
922 mpWindow->getContext().resetCurrent();
924 return nId;
927 void GL3DBarChart::clickedAt(const Point& rPos, sal_uInt16 nButtons)
929 if (nButtons == MOUSE_RIGHT)
931 moveToDefault();
932 return;
935 if(nButtons != MOUSE_LEFT)
936 return;
938 if (mbBenchMarkMode)
940 // add correct handling here !!
941 if ((maRenderEvent != EVENT_NONE) && (maRenderEvent != EVENT_SHOW_SCROLL) &&
942 (maRenderEvent != EVENT_AUTO_FLY) && (maRenderEvent != EVENT_SHOW_SELECT))
943 return;
946 SharedResourceAccess aResGuard(maCond1, maCond2);
947 osl::MutexGuard aGuard(maMutex);
948 maClickPos = rPos;
949 mnPreSelectBarId = mnSelectBarId;
950 maPreRenderEvent = maRenderEvent;
951 maRenderEvent = EVENT_CLICK;
952 maClickCond.reset();
954 maClickCond.wait();
955 return;
958 sal_uInt32 nId = barIdAtPosition(rPos);
960 std::map<sal_uInt32, const BarInformation>::const_iterator itr =
961 maBarMap.find(nId);
963 if(itr == maBarMap.end())
964 return;
966 const BarInformation& rBarInfo = itr->second;
969 osl::MutexGuard aGuard(maMutex);
970 mpWindow->getContext().makeCurrent();
971 glm::vec3 aTextPos = glm::vec3(rBarInfo.maPos.x + BAR_SIZE_X / 2.0f,
972 rBarInfo.maPos.y + BAR_SIZE_Y / 2.0f,
973 rBarInfo.maPos.z);
974 maShapes.push_back(o3tl::make_unique<opengl3D::ScreenText>(mpRenderer.get(), *mpTextCache,
975 "Value: " + OUString::number(rBarInfo.mnVal), glm::vec4(0.0f, 0.0f, 1.0f, 1.0f), CALC_POS_EVENT_ID));
976 opengl3D::ScreenText* pScreenText = static_cast<opengl3D::ScreenText*>(maShapes.back().get());
977 pScreenText->setPosition(glm::vec2(-0.9f, 0.9f), glm::vec2(-0.6f, 0.8f), aTextPos);
978 pScreenText->render();
979 mpWindow->getContext().resetCurrent();
982 glm::vec3 aTargetPosition = rBarInfo.maPos;
983 aTargetPosition.z += 240;
984 aTargetPosition.y += BAR_SIZE_Y / 2.0f;
986 spawnRenderThread(new RenderAnimationThread(this, maCameraPosition,
987 aTargetPosition, STEPS));
990 * TODO: moggi: add to thread
991 glm::vec3 maTargetDirection = rBarInfo.maPos;
992 maTargetDirection.x += BAR_SIZE_X / 2.0f;
993 maTargetDirection.y += BAR_SIZE_Y / 2.0f;
995 maStepDirection = (maTargetDirection - maCameraDirection)/((float)mnStepsTotal);
999 void GL3DBarChart::render()
1001 if (mbBenchMarkMode)
1002 return;
1004 update();
1007 void GL3DBarChart::renderFrame()
1009 Size aSize = mpWindow->GetSizePixel();
1010 mpRenderer->SetSize(aSize);
1011 if(mbNeedsNewRender)
1013 mpRenderer->ReleaseTextTexture();
1014 for(std::unique_ptr<opengl3D::Renderable3DObject>& aObj : maShapes)
1016 aObj->render();
1019 else
1021 mpCamera->render();
1023 mpRenderer->ProcessUnrenderedShape(mbNeedsNewRender);
1024 mbNeedsNewRender = false;
1027 void GL3DBarChart::mouseDragMove(const Point& rStartPos, const Point& rEndPos, sal_uInt16 )
1029 long nDirection = rEndPos.X() - rStartPos.X();
1030 SharedResourceAccess aResGuard(maCond1, maCond2);
1031 osl::ClearableGuard<osl::Mutex> aGuard(maMutex);
1032 if ((maRenderEvent == EVENT_NONE) || (maRenderEvent == EVENT_SHOW_SCROLL) ||
1033 (maRenderEvent == EVENT_AUTO_FLY) || (maRenderEvent == EVENT_SHOW_SELECT))
1034 maRenderEvent = nDirection > 0 ? EVENT_DRAG_RIGHT : EVENT_DRAG_LEFT;
1035 bool bMove = false;
1036 if(nDirection < 0)
1038 mnCornerId = (mnCornerId + 1) % 4;
1039 bMove = true;
1041 else if(nDirection > 0)
1043 mnCornerId = mnCornerId - 1;
1044 if(mnCornerId < 0)
1045 mnCornerId = 3;
1046 bMove = true;
1049 if (bMove)
1051 aGuard.clear();
1052 moveToCorner();
1056 glm::vec3 GL3DBarChart::getCornerPosition(sal_Int8 nId)
1058 float pi = 3.1415926f;
1059 switch(nId)
1061 case 0:
1063 return glm::vec3(mnMaxX / 2 - mnDistance * std::sin(pi / 4), mnMaxY / 2 - mnDistance * std::cos(pi / 4), DEFAULT_CAMERA_HEIGHT * 2);
1065 break;
1066 case 1:
1068 return glm::vec3(mnMaxX / 2 + mnDistance * std::sin(pi / 4), mnMaxY / 2 - mnDistance * std::cos(pi / 4), DEFAULT_CAMERA_HEIGHT * 2);
1070 break;
1071 case 2:
1073 return glm::vec3(mnMaxX / 2 + mnDistance * std::sin(pi / 4), mnMaxY / 2 + mnDistance * std::cos(pi / 4), DEFAULT_CAMERA_HEIGHT * 2);
1075 break;
1076 case 3:
1078 return glm::vec3(mnMaxX / 2 - mnDistance * std::sin(pi / 4), mnMaxY / 2 + mnDistance * std::cos(pi / 4), DEFAULT_CAMERA_HEIGHT * 2);
1080 break;
1081 default:
1082 assert(false);
1084 return maDefaultCameraPosition;
1087 void GL3DBarChart::moveToCorner()
1089 if(mbBenchMarkMode)
1091 // add correct handling here!!
1092 return;
1095 spawnRenderThread(new RenderAnimationThread(this, maCameraPosition,
1096 getCornerPosition(mnCornerId), STEPS));
1098 // TODO: moggi: add to thread
1099 // maStepDirection = (glm::vec3(mnMaxX/2.0f, mnMaxY/2.0f, 0) - maCameraDirection)/ float(mnStepsTotal);
1102 void GL3DBarChart::scroll(long nDelta)
1105 SharedResourceAccess aResGuard(maCond1, maCond2);
1106 osl::MutexGuard aGuard(maMutex);
1107 if ((maRenderEvent != EVENT_NONE) && (maRenderEvent != EVENT_SHOW_SCROLL) &&
1108 (maRenderEvent != EVENT_AUTO_FLY) && (maRenderEvent != EVENT_SHOW_SELECT))
1109 return;
1110 glm::vec3 aDir = glm::normalize(maCameraPosition - maCameraDirection);
1111 maCameraPosition -= (static_cast<float>(nDelta)/10) * aDir;
1112 mpCamera->setPosition(maCameraPosition);
1113 if(mbBenchMarkMode)
1115 maVectorNearest.clear();
1116 getNearestBars(maVectorNearest);
1117 maRenderEvent = EVENT_SCROLL;
1121 update();
1124 void GL3DBarChart::contextDestroyed()
1126 SharedResourceAccess aResGuard(maCond1, maCond2);
1127 osl::MutexGuard aGuard(maMutex);
1128 mpWindow->getContext().makeCurrent();
1129 mpRenderer.reset();
1130 mpWindow->getContext().resetCurrent();
1131 mbValidContext = false;
1134 float GL3DBarChart::addScreenTextShape(OUString &nStr, const glm::vec2& rLeftOrRightTop, float nTextHeight, bool bLeftTopFlag,
1135 const glm::vec4& rColor, const glm::vec3& rPos, sal_uInt32 nEvent)
1137 maScreenTextShapes.push_back(o3tl::make_unique<opengl3D::ScreenText>(mpRenderer.get(), *mpTextCache, nStr, rColor, nEvent));
1138 const opengl3D::TextCacheItem& rTextCache = mpTextCache->getText(nStr);
1139 float nRectWidth = static_cast<float>(rTextCache.maSize.Width()) / static_cast<float>(rTextCache.maSize.Height()) * nTextHeight / 2.0f;
1140 opengl3D::ScreenText* pScreenText = static_cast<opengl3D::ScreenText*>(maScreenTextShapes.back().get());
1141 if (bLeftTopFlag)
1142 pScreenText->setPosition(rLeftOrRightTop, glm::vec2(rLeftOrRightTop.x + nRectWidth, rLeftOrRightTop.y - nTextHeight), rPos);
1143 else
1144 pScreenText->setPosition(glm::vec2(rLeftOrRightTop.x - nRectWidth, rLeftOrRightTop.y), glm::vec2(rLeftOrRightTop.x, rLeftOrRightTop.y - nTextHeight), rPos);
1145 return nRectWidth;
1148 void GL3DBarChart::updateRenderFPS()
1150 int nDeltaMs = calcTimeInterval(maFPSRenderStartTime, maFPSRenderEndTime);
1151 if(nDeltaMs >= FPS_TIME)
1153 osl_getSystemTime(&maFPSRenderEndTime);
1154 nDeltaMs = calcTimeInterval(maFPSRenderStartTime, maFPSRenderEndTime);
1155 int iFPS = miFrameCount * 1000 / nDeltaMs;
1156 maFPS = OUString::number(iFPS);
1157 miFrameCount = 0;
1158 osl_getSystemTime(&maFPSRenderStartTime);
1160 osl_getSystemTime(&maFPSRenderEndTime);
1161 OUString aFPS = "Render FPS: ";
1162 addScreenTextShape(aFPS, glm::vec2(-0.77f, 0.99f), 0.07f, false, glm::vec4(0.0f, 1.0f, 1.0f, 0.0f));
1163 addScreenTextShape(maFPS, glm::vec2(-0.77f, 0.99f), 0.07f, true,
1164 glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f));
1167 int GL3DBarChart::calcTimeInterval(TimeValue const &startTime, TimeValue const &endTime)
1169 TimeValue aTime;
1170 aTime.Seconds = endTime.Seconds - startTime.Seconds - 1;
1171 aTime.Nanosec = 1000000000 + endTime.Nanosec - startTime.Nanosec;
1172 aTime.Seconds += aTime.Nanosec / 1000000000;
1173 aTime.Nanosec %= 1000000000;
1174 return aTime.Seconds * 1000+aTime.Nanosec / 1000000;
1177 void GL3DBarChart::updateScreenText()
1179 SharedResourceAccess aResGuard(maCond1, maCond2);
1180 osl::MutexGuard aGuard(maMutex);
1181 maScreenTextShapes.clear();
1182 mpRenderer->ReleaseScreenTextShapes();
1183 updateRenderFPS();
1184 updateDataUpdateFPS();
1185 updateClickEvent();
1186 updateScroll();
1187 mbScreenTextNewRender = true;
1190 void GL3DBarChart::updateDataUpdateFPS()
1192 int nDeltaMs = calcTimeInterval(maDataUpdateStartTime, maDataUpdateEndTime);
1193 if(nDeltaMs >= DATAUPDATE_FPS_TIME)
1195 int iFPS = miDataUpdateCounter * 1000 / nDeltaMs;
1196 if (iFPS)
1198 maDataUpdateFPS = OUString::number(iFPS);
1200 else
1202 float fFPS = static_cast<float>(miDataUpdateCounter) * 1000 / static_cast<float>(nDeltaMs);
1203 maDataUpdateFPS = OUString::number(fFPS);
1205 miDataUpdateCounter = 0;
1206 osl_getSystemTime(&maDataUpdateStartTime);
1208 osl_getSystemTime(&maDataUpdateEndTime);
1209 OUString aDataUpdateFPS = "Data Update Rate: ";
1210 addScreenTextShape(aDataUpdateFPS, glm::vec2(-0.77, 0.92f), 0.07f, false, glm::vec4(0.0f, 1.0f, 1.0f, 0.0f));
1211 addScreenTextShape(maDataUpdateFPS, glm::vec2(-0.77f, 0.92f), 0.07f, true, glm::vec4(1.0f, 0.0f, 0.0f, 0.0f));
1214 void GL3DBarChart::recordBarHistory(sal_uInt32 nBarID, float nVal)
1216 std::deque<float>& aList = maBarHistory[nBarID];
1217 if(aList.size() == HISTORY_NUM)
1218 aList.pop_front();
1219 aList.push_back(nVal);
1222 void GL3DBarChart::getNeighborBarID(sal_uInt32 nSelectBarId, sal_uInt32 *pNeighborBarId)
1224 sal_uInt32 nSelectRow = (nSelectBarId - SHAPE_START_ID) / ID_STEP / (mnBarsInRow + 1);
1225 for (sal_Int32 i = 0; i < DISPLAY_BARS_NUM; i++)
1227 pNeighborBarId[i] = nSelectBarId + (i - DISPLAY_BARS_NUM / 2) * ID_STEP;
1228 if (pNeighborBarId[i] == nSelectBarId)
1229 continue;
1230 if ((pNeighborBarId[i] - SHAPE_START_ID) / ID_STEP / (mnBarsInRow + 1) != nSelectRow)
1231 pNeighborBarId[i] = 0;
1235 void GL3DBarChart::addMovementScreenText(sal_uInt32 nBarId)
1237 if (nBarId == 0)
1238 return;
1239 std::map<sal_uInt32, const BarInformation>::const_iterator itr = maBarMap.find(nBarId);
1240 if (itr == maBarMap.end())
1241 return;
1242 const BarInformation& rBarInfo = itr->second;
1243 glm::vec3 aTextPos = glm::vec3(rBarInfo.maPos.x + BAR_SIZE_X / 2.0f,
1244 rBarInfo.maPos.y + BAR_SIZE_Y / 2.0f,
1245 rBarInfo.maPos.z);
1246 OUString aBarValue = "Value: " + OUString::number(rBarInfo.mnVal);
1247 maScreenTextShapes.push_back(o3tl::make_unique<opengl3D::ScreenText>(mpRenderer.get(), *mpTextCache, aBarValue, glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), CALC_POS_EVENT_ID, true));
1248 const opengl3D::TextCacheItem& rTextCache = mpTextCache->getText(aBarValue);
1249 float nRectWidth = static_cast<float>(rTextCache.maSize.Width()) / static_cast<float>(rTextCache.maSize.Height()) * 0.024;
1250 opengl3D::ScreenText* pScreenText = static_cast<opengl3D::ScreenText*>(maScreenTextShapes.back().get());
1251 pScreenText->setPosition(glm::vec2(-nRectWidth / 2, 0.03f), glm::vec2(nRectWidth / 2, -0.03f), aTextPos);
1254 void GL3DBarChart::updateClickEvent()
1256 if (maRenderEvent == EVENT_CLICK || maRenderEvent == EVENT_AUTO_FLY || maRenderEvent == EVENT_SHOW_SELECT)
1258 std::deque<float>& aList = maBarHistory[mnSelectBarId];
1259 sal_uInt32 nIdex = 0;
1260 sal_uInt32 nBarIdArray[DISPLAY_BARS_NUM] = {0};
1261 OUString aTitle;
1262 OUString aBarValue;
1263 float nXCoordStart, nYCoordStart, nTextWidth, nMaxXCoord = 0.0f, nMinXCoord = 1.0f, nMaxHight = 0.0f;
1264 //write title
1265 if (aList.size() > 1)
1267 aTitle = "Time ";
1268 nTextWidth = addScreenTextShape(aTitle, glm::vec2(0.875, 0.99f), 0.07f, false, glm::vec4(0.0f, 1.0f, 1.0f, 0.5f));
1269 nMinXCoord = std::min(nMinXCoord, 0.875f - nTextWidth);
1270 aTitle = " Value";
1271 nTextWidth = addScreenTextShape(aTitle, glm::vec2(0.875f, 0.99f), 0.07f, true, glm::vec4(0.0f, 1.0f, 1.0f, 0.5f));
1272 nMaxXCoord = std::max(nMaxXCoord, 0.875f + nTextWidth);
1274 if (aList.size() > COLUMNSIZE)
1276 aTitle = "Time ";
1277 nTextWidth = addScreenTextShape(aTitle, glm::vec2(0.55f, 0.99f), 0.07f, false, glm::vec4(0.0f, 1.0f, 1.0f, 0.5f));
1278 nMinXCoord = std::min(nMinXCoord, 0.55f - nTextWidth);
1279 aTitle = " Value";
1280 nTextWidth = addScreenTextShape(aTitle, glm::vec2(0.55f, 0.99f), 0.07f, true, glm::vec4(0.0f, 1.0f, 1.0f, 0.5f));
1281 nMaxXCoord = std::max(nMaxXCoord, 0.55f + nTextWidth);
1283 getNeighborBarID(mnSelectBarId, nBarIdArray);
1284 for (auto const& elem : aList)
1286 if (nIdex + 1 < aList.size())
1288 aTitle = "[Time:" + OUString::number((mnHistoryCounter - aList.size() + nIdex)) + "]: ";
1289 if (nIdex == 0)
1291 aTitle = "Most Recent" + aTitle;
1293 if (aList.size() <= COLUMNSIZE)
1295 nXCoordStart = 0.875f;
1296 nYCoordStart = (nIdex + 1) * 0.07f;
1298 else
1300 nXCoordStart = nIdex < COLUMNSIZE ? 0.55f : 0.875f;
1301 nYCoordStart = nIdex < COLUMNSIZE ? (nIdex + 1) * 0.07f : (nIdex - 24) * 0.07f;
1303 nMaxHight = std::max(nMaxHight, nYCoordStart + 0.07f);
1304 nTextWidth = addScreenTextShape(aTitle, glm::vec2(nXCoordStart, 0.99f - nYCoordStart), 0.07f, false, glm::vec4(0.0f, 1.0f, 1.0f, 0.5f));
1305 nMinXCoord = std::min(nMinXCoord, nXCoordStart - nTextWidth);
1306 aBarValue = OUString::number(elem);
1307 nTextWidth = addScreenTextShape(aBarValue, glm::vec2(nXCoordStart, 0.99f - nYCoordStart), 0.07f, true, glm::vec4(0.0f, 1.0f, 1.0f, 0.5f));
1308 nMaxXCoord = std::max(nMaxXCoord, nXCoordStart + nTextWidth);
1310 nIdex++;
1312 for (unsigned int i : nBarIdArray)
1314 addMovementScreenText(i);
1316 //add translucent back ground
1317 aTitle = " ";
1318 maScreenTextShapes.push_back(o3tl::make_unique<opengl3D::ScreenText>(mpRenderer.get(), *mpTextCache, aTitle, glm::vec4(0.0f, 0.0f, 0.0f, 0.5f), 0));
1319 opengl3D::ScreenText* pScreenText = static_cast<opengl3D::ScreenText*>(maScreenTextShapes.back().get());
1320 pScreenText->setPosition(glm::vec2(nMinXCoord, 0.99f), glm::vec2(nMaxXCoord, 0.99f - nMaxHight), glm::vec3(0.0, 0.0, 0.0));
1324 float GL3DBarChart::calcScrollDistance(const glm::mat4& rMVP, const glm::vec3& rPos)
1326 glm::vec4 aScreenPos = rMVP * glm::vec4(rPos, 1.0);
1327 glm::vec3 aActualPos = glm::vec3(aScreenPos.x / aScreenPos.w, aScreenPos.y / aScreenPos.w, 0.0);
1328 return glm::length(aActualPos);
1331 void GL3DBarChart::calcDistance(std::vector<sal_uInt32> & rVectorNearest)
1333 int i =0;
1334 glm::mat4 aProjection = mpRenderer->GetProjectionMatrix();
1335 glm::mat4 aView = mpRenderer->GetViewMatrix();
1336 glm::mat4 aScale = mpRenderer->GetGlobalScaleMatrix();
1337 glm::mat4 aMVP = aProjection * aView * aScale;
1338 for (auto const& elem : maBarMap)
1340 sal_uInt32 nId = elem.first;
1341 if(i < SHOW_VALUE_COUNT)
1343 rVectorNearest.push_back(nId);
1344 i++;
1346 maDistanceMap[nId] = calcScrollDistance(aMVP, glm::vec3(elem.second.maPos.x + BAR_SIZE_X / 2.0f,
1347 elem.second.maPos.y + BAR_SIZE_Y / 2.0f,
1348 elem.second.maPos.z));
1352 void GL3DBarChart::initDistanceHeap(std::vector<sal_uInt32> &rVectorNearest)
1354 for(int i= (rVectorNearest.size()-2)/2; i>= 0; i--)
1356 keepHeap(rVectorNearest, i);
1360 void GL3DBarChart::keepHeap(std::vector<sal_uInt32> &rVectorNearest, int nIndex)
1362 size_t nParentIndex = nIndex;
1363 while(nParentIndex < rVectorNearest.size())
1365 size_t nLeftIndex = nParentIndex * 2 + 1;
1366 size_t nRightIndex = nLeftIndex +1;
1367 if(nLeftIndex >= rVectorNearest.size())
1368 break;
1369 size_t nFarthestIndex = nLeftIndex;
1370 float nFarthest = maDistanceMap[rVectorNearest[nLeftIndex]];
1371 if(nRightIndex < rVectorNearest.size())
1373 float nRight = maDistanceMap[rVectorNearest[nRightIndex]];
1374 if(nRight > nFarthest)
1376 nFarthest = nRight;
1377 nFarthestIndex = nRightIndex;
1380 float nParent = maDistanceMap[rVectorNearest[nParentIndex]];
1381 if(nParent >= nFarthest)
1382 break;
1383 else
1385 swapVector(nParentIndex , nFarthestIndex, rVectorNearest);
1386 nParentIndex = nFarthestIndex;
1392 void GL3DBarChart::swapVector(int i, int j, std::vector<sal_uInt32> &rVectorNearest)
1394 sal_uInt32 nTmp = rVectorNearest[i];
1395 rVectorNearest[i] = rVectorNearest[j];
1396 rVectorNearest[j] = nTmp;
1399 void GL3DBarChart::getNearestBars(std::vector<sal_uInt32> &rVectorNearest)
1401 calcDistance(rVectorNearest);
1402 initDistanceHeap(rVectorNearest);
1403 int i = 0;
1404 for (auto const& elem : maDistanceMap)
1406 ++i;
1407 if(i <= SHOW_VALUE_COUNT)
1408 continue;
1409 float nDistance = elem.second;
1410 float nHeaphead = maDistanceMap[rVectorNearest[0]];
1411 if(nDistance < nHeaphead)
1413 rVectorNearest[0] = elem.first;
1414 keepHeap(rVectorNearest, 0);
1419 void GL3DBarChart::updateScroll()
1421 if ((maRenderEvent == EVENT_SCROLL) || (maRenderEvent == EVENT_SHOW_SCROLL))
1423 float fMinDistance = 0.0f;
1424 std::vector<BarInformation> aBarInfoList;
1425 for(sal_uInt32 i : maVectorNearest)
1427 //get bar height position
1428 std::map<sal_uInt32, const BarInformation>::const_iterator itr = maBarMap.find(i);
1429 const BarInformation& rBarInfo = itr->second;
1430 aBarInfoList.push_back(rBarInfo);
1431 glm::vec3 aPos = rBarInfo.maPos;
1432 fMinDistance = (fMinDistance == 0.0f) ? glm::length(aPos - maCameraPosition) :
1433 std::min(glm::length(aPos - maCameraPosition), fMinDistance);
1436 if (fMinDistance <= SHOW_SCROLL_TEXT_DISTANCE)
1438 //update scroll value
1439 for(BarInformation & i : aBarInfoList)
1441 OUString aBarValue = "Value: " + OUString::number(i.mnVal);
1442 maScreenTextShapes.push_back(o3tl::make_unique<opengl3D::ScreenText>(mpRenderer.get(), *mpTextCache, aBarValue, glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), CALC_POS_EVENT_ID, true));
1443 const opengl3D::TextCacheItem& rTextCache = mpTextCache->getText(aBarValue);
1444 float nRectWidth = static_cast<float>(rTextCache.maSize.Width()) / static_cast<float>(rTextCache.maSize.Height()) * 0.024;
1445 glm::vec3 aTextPos = glm::vec3(i.maPos.x + BAR_SIZE_X / 2.0f,
1446 i.maPos.y + BAR_SIZE_Y / 2.0f,
1447 i.maPos.z);
1448 opengl3D::ScreenText* pScreenText = static_cast<opengl3D::ScreenText*>(maScreenTextShapes.back().get());
1449 pScreenText->setPosition(glm::vec2(-nRectWidth / 2, 0.03f), glm::vec2(nRectWidth / 2, -0.03f), aTextPos);
1455 void GL3DBarChart::processAutoFly(sal_uInt32 nId, Color nColor)
1457 //record the color
1458 Color nPreColor = maBarColorMap[nId];
1459 maBarColorMap[nId] = nColor;
1460 //if has manul event, just record the color and process manul event first
1461 if (maRenderEvent != EVENT_NONE)
1463 return;
1465 //calc the percentage of color change
1466 int nColorRate = (sal_uInt32(nColor) - sal_uInt32(nPreColor)) * 100 / sal_uInt32(nPreColor);
1467 nColorRate = abs(nColorRate);
1468 if (nColorRate >= FLY_THRESHOLD)
1470 maRenderEvent = EVENT_AUTO_FLY;
1471 mnSelectBarId = nColorRate > mnColorRate ? nId : mnSelectBarId;
1472 mnPreSelectBarId = mnSelectBarId;
1473 mnColorRate = std::max(nColorRate, mnColorRate);
1477 IMPL_LINK_NOARG(GL3DBarChart, UpdateTimerHdl, Timer *, void)
1479 updateScreenText();
1480 maIdle.Start();
1483 void GL3DBarChart::setOpenGLWindow(OpenGLWindow* pWindow)
1485 if (mpWindow.get() != pWindow)
1487 mpWindow = pWindow;
1488 Size aSize = mpWindow->GetSizePixel();
1489 mpRenderer->SetSize(aSize);
1490 mpWindow->setRenderer(this);
1491 mpWindow->getContext().makeCurrent();
1492 mpRenderer->init();
1493 mpWindow->getContext().resetCurrent();
1494 mbValidContext = true;
1500 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */