/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include <3DChartObjects.hxx> #include #include #include #include #ifdef _WIN32 #if !defined WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif #include #endif #include #include #define CALC_POS_EVENT_ID 1 #define SHAPE_START_ID 10 #define FPS_TIME 500 #define DATAUPDATE_FPS_TIME 1000 #define HISTORY_NUM 51 #define COLUMNSIZE 25 #define SHOW_VALUE_COUNT 15 #define SHOW_SCROLL_TEXT_DISTANCE 1000 #define FLY_THRESHOLD 20 #define DISPLAY_BARS_NUM 3 using namespace com::sun::star; namespace chart { const size_t STEPS = 200; const size_t STEPS_UPDATE = 100; namespace { const float TEXT_HEIGHT = 10.0f; float DEFAULT_CAMERA_HEIGHT = 500.0f; const sal_uInt32 ID_STEP = 10; const float BAR_SIZE_X = 30.0f; const float BAR_SIZE_Y = 5.0f; const float BAR_DISTANCE_X = 5.0f; const float BAR_DISTANCE_Y = 5.0; float calculateTextWidth(const OUString& rText) { return rText.getLength() * 10; } double findMaxValue(const std::vector >& rDataSeriesContainer) { double nMax = 0.0; for (const std::unique_ptr& rDataSeries : rDataSeriesContainer) { sal_Int32 nPointCount = rDataSeries->getTotalPointCount(); for(sal_Int32 nIndex = 0; nIndex < nPointCount; ++nIndex) { double nVal = rDataSeries->getYValue(nIndex); nMax = std::max(nMax, nVal); } } return nMax; } class SharedResourceAccess { private: osl::Condition& mrCond1; osl::Condition& mrCond2; public: SharedResourceAccess(osl::Condition& rCond1, osl::Condition& rCond2): mrCond1(rCond1), mrCond2(rCond2) { mrCond1.set(); } ~SharedResourceAccess() { mrCond2.set(); } }; } class RenderThread : public salhelper::Thread { public: explicit RenderThread(GL3DBarChart* pChart); protected: void renderFrame(); GL3DBarChart* mpChart; }; RenderThread::RenderThread(GL3DBarChart* pChart): salhelper::Thread("RenderThread"), mpChart(pChart) { } void RenderThread::renderFrame() { if(!mpChart->mbValidContext) return; mpChart->mpWindow->getContext().makeCurrent(); mpChart->renderFrame(); // FIXME: SwapBuffers can take a considerable time, it'd be // nice if we didn't hold the chart mutex while doing that. mpChart->mpWindow->getContext().swapBuffers(); mpChart->mpWindow->getContext().resetCurrent(); } class RenderOneFrameThread : public RenderThread { public: explicit RenderOneFrameThread(GL3DBarChart* pChart): RenderThread(pChart) {} protected: virtual void execute() override; }; void RenderOneFrameThread::execute() { osl::MutexGuard aGuard(mpChart->maMutex); renderFrame(); } class RenderAnimationThread : public RenderThread { public: RenderAnimationThread(GL3DBarChart* pChart, const glm::vec3& rStartPos, const glm::vec3& rEndPos, const sal_Int32 nSteps): RenderThread(pChart), maStartPos(rStartPos), maEndPos(rEndPos), mnSteps(nSteps) { } protected: virtual void execute() override; private: glm::vec3 maStartPos; glm::vec3 maEndPos; sal_Int32 mnSteps; }; void RenderAnimationThread::execute() { osl::MutexGuard aGuard(mpChart->maMutex); glm::vec3 aStep = (maEndPos - maStartPos)/static_cast(mnSteps); for(sal_Int32 i = 0; i < mnSteps; ++i) { mpChart->maCameraPosition += aStep; mpChart->mpCamera->setPosition(mpChart->maCameraPosition); /* mpChart->maCameraDirection += mpChart->maStepDirection; mpChart->mpCamera->setDirection(mpChart->maCameraDirection); */ renderFrame(); } mpChart->mpRenderer->ReleaseScreenTextShapes(); } class RenderBenchMarkThread : public RenderThread { public: explicit RenderBenchMarkThread(GL3DBarChart * pChart) : RenderThread(pChart) , mbAutoFlyExecuting(false) , mbExecuting(false) , mbNeedFlyBack(false) , mnStep(0) , mnStepsTotal(0) { osl_getSystemTime(&maClickFlyBackStartTime); osl_getSystemTime(&maClickFlyBackEndTime); } protected: virtual void execute() override; private: void ProcessMouseEvent(); void MoveCamera(); void MoveCameraToBar(); void MoveToBar(); void MoveToSelectedBar(); void MoveToDefault(); void MoveToCorner(); void ProcessScroll(); void UpdateScreenText(); void ProcessClickFlyBack(); void AutoMoveToBar(); private: bool mbAutoFlyExecuting; bool mbExecuting; bool mbNeedFlyBack; glm::vec3 maStep; glm::vec3 maStepDirection; glm::mat4 maMatrixStep; size_t mnStep; size_t mnStepsTotal; TimeValue maClickFlyBackStartTime; TimeValue maClickFlyBackEndTime; glm::vec3 maTargetPosition; glm::vec3 maTargetDirection; }; void RenderBenchMarkThread::MoveCamera() { if(mnStep < mnStepsTotal) { ++mnStep; mpChart->maCameraPosition += maStep; mpChart->mpCamera->setPosition(mpChart->maCameraPosition); mpChart->maCameraDirection += maStepDirection; mpChart->mpCamera->setDirection(mpChart->maCameraDirection); } else { mnStep = 0; mbExecuting = false; mbAutoFlyExecuting = false; mbNeedFlyBack = false; mpChart->maRenderEvent = EVENT_NONE; } } void RenderBenchMarkThread::MoveCameraToBar() { if(mnStep < mnStepsTotal) { ++mnStep; mpChart->mpRenderer->AddMatrixDiff(maMatrixStep); } else { mpChart->maCameraPosition = maTargetPosition; mpChart->maCameraDirection = maTargetDirection; mpChart->mpCamera->setPosition(maTargetPosition); mpChart->mpCamera->setDirection(maTargetDirection); mpChart->mpRenderer->ResetMatrixDiff(); mnStep = 0; mbExecuting = false; mbAutoFlyExecuting = false; mbNeedFlyBack = true; osl_getSystemTime(&maClickFlyBackStartTime); osl_getSystemTime(&maClickFlyBackEndTime); mpChart->maRenderEvent = EVENT_SHOW_SELECT; } } void RenderBenchMarkThread::MoveToDefault() { if ((mpChart->maCameraPosition == mpChart->maDefaultCameraDirection) && (mpChart->maCameraDirection == mpChart->maDefaultCameraDirection)) { mnStep = 0; mbExecuting = false; mpChart->maRenderEvent = EVENT_NONE; return; } if (!mbExecuting) { mpChart->mpRenderer->EndClick(); mnStep = 0; mnStepsTotal = STEPS; maStep = (mpChart->maDefaultCameraPosition - mpChart->maCameraPosition)/static_cast(mnStepsTotal); maStepDirection = (mpChart->maDefaultCameraDirection - mpChart->maCameraDirection)/static_cast(mnStepsTotal); mbExecuting = true; } MoveCamera(); } void RenderBenchMarkThread::MoveToBar() { if (!mbExecuting) { mpChart->mnSelectBarId = mpChart->barIdAtPosition(mpChart->maClickPos); std::map::const_iterator itr = mpChart->maBarMap.find(mpChart->mnSelectBarId); if(itr == mpChart->maBarMap.end()) { mpChart->mnSelectBarId = mpChart->mnPreSelectBarId; mpChart->maRenderEvent = mpChart->maPreRenderEvent; mpChart->maClickCond.set(); return; } mpChart->mpRenderer->EndClick(); const GL3DBarChart::BarInformation& rBarInfo = itr->second; mnStep = 0; mnStepsTotal = STEPS; maTargetPosition = rBarInfo.maPos; maTargetPosition.z += 240; maTargetPosition.x += BAR_SIZE_X / 2.0f; maTargetDirection = rBarInfo.maPos; maTargetDirection.x += BAR_SIZE_X / 2.0f; maTargetDirection.y += BAR_SIZE_Y / 2.0f; maTargetPosition.y = maTargetDirection.y - 240; maMatrixStep = mpChart->mpRenderer->GetDiffOfTwoCameras(mpChart->maCameraPosition, maTargetPosition, mpChart->maCameraDirection, maTargetDirection)/static_cast(mnStepsTotal); mpChart->maClickCond.set(); mbExecuting = true; mbNeedFlyBack = false; mpChart->mpRenderer->StartClick(mpChart->mnSelectBarId); } MoveCameraToBar(); } void RenderBenchMarkThread::MoveToSelectedBar() { mpChart->mnSelectBarId = mpChart->mnUpdateBarId; std::map::const_iterator itr = mpChart->maBarMap.find(mpChart->mnSelectBarId); if(itr == mpChart->maBarMap.end()) { mpChart->mnSelectBarId = mpChart->mnPreSelectBarId; mpChart->maRenderEvent = mpChart->maPreRenderEvent; mpChart->maClickCond.set(); return; } mpChart->mpRenderer->EndClick(); const GL3DBarChart::BarInformation& rBarInfo = itr->second; mnStep = 0; mnStepsTotal = STEPS_UPDATE; maTargetPosition = rBarInfo.maPos; maTargetPosition.z += 240; maTargetPosition.x += BAR_SIZE_X / 2.0f; maTargetDirection = rBarInfo.maPos; maTargetDirection.x += BAR_SIZE_X / 2.0f; maTargetDirection.y += BAR_SIZE_Y / 2.0f; maTargetPosition.y = maTargetDirection.y - 240; maMatrixStep = mpChart->mpRenderer->GetDiffOfTwoCameras( maTargetPosition, maTargetDirection)/static_cast(mnStepsTotal); mpChart->maClickCond.set(); mbExecuting = true; mbNeedFlyBack = false; mpChart->mpRenderer->StartClick(mpChart->mnSelectBarId); mpChart->maRenderEvent = EVENT_CLICK; } void RenderBenchMarkThread::AutoMoveToBar() { if (!mbAutoFlyExecuting) { mpChart->mpRenderer->EndClick(); std::map::const_iterator itr = mpChart->maBarMap.find(mpChart->mnSelectBarId); if(itr == mpChart->maBarMap.end()) { mpChart->maRenderEvent = EVENT_NONE; return; } const GL3DBarChart::BarInformation& rBarInfo = itr->second; mnStep = 0; mnStepsTotal = STEPS; maTargetPosition = rBarInfo.maPos; maTargetPosition.z += 240; maTargetPosition.x += BAR_SIZE_X / 2.0f; maTargetDirection = rBarInfo.maPos; maTargetDirection.x += BAR_SIZE_X / 2.0f; maTargetDirection.y += BAR_SIZE_Y / 2.0f; maTargetPosition.y = maTargetDirection.y - 240; maMatrixStep = mpChart->mpRenderer->GetDiffOfTwoCameras(mpChart->maCameraPosition, maTargetPosition, mpChart->maCameraDirection, maTargetDirection)/static_cast(mnStepsTotal); mpChart->mpRenderer->StartClick(mpChart->mnSelectBarId); mbAutoFlyExecuting = true; mbNeedFlyBack = false; } MoveCameraToBar(); } void RenderBenchMarkThread::MoveToCorner() { if (!mbExecuting) { mpChart->mpRenderer->EndClick(); mnStep = 0; mnStepsTotal = STEPS; maStep = (mpChart->getCornerPosition(mpChart->mnCornerId) - mpChart->maCameraPosition) / float(mnStepsTotal); maStepDirection = (glm::vec3(mpChart->mnMaxX/2.0f, mpChart->mnMaxY/2.0f, 0) - mpChart->maCameraDirection)/ float(mnStepsTotal); mbExecuting = true; } MoveCamera(); } void RenderBenchMarkThread::ProcessScroll() { //will add other process later mpChart->mpRenderer->EndClick(); mnStep = 0; mnStepsTotal = STEPS; mpChart->maRenderEvent = EVENT_SHOW_SCROLL; } void RenderBenchMarkThread::ProcessClickFlyBack() { if (!mbNeedFlyBack) return; osl_getSystemTime(&maClickFlyBackEndTime); int nDeltaMs = GL3DBarChart::calcTimeInterval(maClickFlyBackStartTime, maClickFlyBackEndTime); if(nDeltaMs >= 10000) { mpChart->maRenderEvent = EVENT_MOVE_TO_DEFAULT; } } void RenderBenchMarkThread::ProcessMouseEvent() { ProcessClickFlyBack(); if (mpChart->maRenderEvent == EVENT_SELECTBAR_UPDEDATE) { MoveToSelectedBar(); } else if (mpChart->maRenderEvent == EVENT_CLICK) { MoveToBar(); } else if (mpChart->maRenderEvent == EVENT_MOVE_TO_DEFAULT) { MoveToDefault(); } else if ((mpChart->maRenderEvent == EVENT_DRAG_LEFT) || (mpChart->maRenderEvent == EVENT_DRAG_RIGHT)) { MoveToCorner(); } else if (mpChart->maRenderEvent == EVENT_SCROLL) { ProcessScroll(); } else if (mpChart->maRenderEvent == EVENT_AUTO_FLY) { AutoMoveToBar(); } } void RenderBenchMarkThread::UpdateScreenText() { if (mpChart->mbScreenTextNewRender) { mpChart->mpWindow->getContext().makeCurrent(); mpChart->mpRenderer->ReleaseScreenTextTexture(); for(std::unique_ptr& aObj : mpChart->maScreenTextShapes) { aObj->render(); } mpChart->mbScreenTextNewRender = false; mpChart->mpWindow->getContext().resetCurrent(); } } void RenderBenchMarkThread::execute() { while (true) { { osl::MutexGuard aGuard(mpChart->maMutex); mpChart->maCond2.reset(); if (mpChart->mbRenderDie) break; UpdateScreenText(); ProcessMouseEvent(); renderFrame(); mpChart->miFrameCount++; } if (mpChart->maCond1.check()) { mpChart->maCond1.reset(); mpChart->maCond2.wait(); } } } GL3DBarChart::GL3DBarChart( const css::uno::Reference& xChartType, OpenGLWindow* pWindow) : mxChartType(xChartType), mpRenderer(new opengl3D::OpenGL3DRenderer()), mpWindow(pWindow), mpCamera(nullptr), mbValidContext(true), mpTextCache(new opengl3D::TextCache), mnMaxX(0), mnMaxY(0), mnDistance(0.0), mnCornerId(0), mbNeedsNewRender(true), mbCameraInit(false), mbRenderDie(false), maRenderEvent(EVENT_NONE), maPreRenderEvent(EVENT_NONE), mnSelectBarId(0), mnPreSelectBarId(0), miScrollRate(0), mbScrollFlg(false), maIdle("chart2 view GL3DBarChart"), mbScreenTextNewRender(false), maFPS(OUString("Render FPS: 0")), maDataUpdateFPS(OUString("Data Update FPS: 0")), miFrameCount(0), miDataUpdateCounter(0), mnColorRate(0), mbBenchMarkMode(false), mnHistoryCounter(0), mnBarsInRow(0), mbAutoFly(false), mnUpdateBarId(0) { maFPSRenderStartTime.Seconds = maFPSRenderStartTime.Nanosec = 0; maFPSRenderEndTime.Seconds = maFPSRenderEndTime.Nanosec = 0; maDataUpdateStartTime.Seconds = maDataUpdateStartTime.Nanosec = 0; maDataUpdateEndTime.Seconds = maDataUpdateEndTime.Nanosec = 0; static const char *aBenchMark = getenv("UNLOCK_FPS_MODE"); if (aBenchMark) { mbBenchMarkMode = atoi(aBenchMark); } if (mbBenchMarkMode) { static const char *scrollFrame = getenv("SCROLL_RATE"); if (scrollFrame) { miScrollRate = atoi(scrollFrame); if (miScrollRate > 0) { mbScrollFlg = true; mpRenderer->SetScroll(); } } char *aAutoFly = getenv("AUTO_FLY"); if (aAutoFly) { mbAutoFly = atoi(aAutoFly); } maIdle.SetPriority(TaskPriority::REPAINT); maIdle.SetInvokeHandler(LINK(this, GL3DBarChart, UpdateTimerHdl)); maIdle.SetDebugName( "charttypes::GL3DBarChart maIdle" ); maIdle.Start(); osl_getSystemTime(&maFPSRenderStartTime); osl_getSystemTime(&maFPSRenderEndTime); osl_getSystemTime(&maDataUpdateStartTime); osl_getSystemTime(&maDataUpdateEndTime); } Size aSize = mpWindow->GetSizePixel(); mpRenderer->SetSize(aSize); mpWindow->setRenderer(this); mpWindow->getContext().makeCurrent(); mpRenderer->init(); mpWindow->getContext().resetCurrent(); } GL3DBarChart::BarInformation::BarInformation(const glm::vec3& rPos, float nVal): maPos(rPos), mnVal(nVal) { } GL3DBarChart::~GL3DBarChart() { if (mbBenchMarkMode) { SharedResourceAccess aResGuard(maCond1, maCond2); osl::MutexGuard aGuard(maMutex); mbRenderDie = true; } joinRenderThread(); if (mbValidContext) { mpWindow->setRenderer(nullptr); mpWindow->getContext().makeCurrent(); mpRenderer.reset(); mpWindow->getContext().resetCurrent(); } } void GL3DBarChart::create3DShapes(const std::vector >& rDataSeriesContainer, ExplicitCategoriesProvider& rCatProvider) { SharedResourceAccess aResGuard(maCond1, maCond2); osl::MutexGuard aGuard(maMutex); if(mnSelectBarId) { int nSelectBarId = mnSelectBarId; int nPreSelectBarId = nSelectBarId; nSelectBarId -= 10; sal_uInt32 nSelectRow = (nSelectBarId - SHAPE_START_ID) / ID_STEP / (mnBarsInRow + 1); sal_uInt32 nPreSelectRow = (nPreSelectBarId - SHAPE_START_ID) / ID_STEP / (mnBarsInRow + 1); if(nSelectRow == nPreSelectRow) { std::map::const_iterator itr = maBarMap.find(nSelectBarId); if((maRenderEvent == EVENT_CLICK || maRenderEvent == EVENT_SHOW_SELECT || maRenderEvent == EVENT_AUTO_FLY)&&(itr != maBarMap.end())) { mnUpdateBarId = nSelectBarId; maRenderEvent = EVENT_SELECTBAR_UPDEDATE; } } } mpRenderer->ReleaseShapes(); // Each series of data flows from left to right, and multiple series are // stacked vertically along y axis. sal_uInt32 nId = SHAPE_START_ID; float nXEnd = 0.0; float nYPos = 0.0; const Color aSeriesColor[] = { COL_RED, COL_GREEN, COL_YELLOW, COL_BROWN, COL_BLUE }; maCategories.clear(); maSeriesNames.clear(); maSeriesNames.reserve(rDataSeriesContainer.size()); maBarMap.clear(); maShapes.clear(); if (mbBenchMarkMode) { mnColorRate = 0; } maShapes.push_back(o3tl::make_unique(mpRenderer.get())); mpCamera = static_cast(maShapes.back().get()); sal_Int32 nSeriesIndex = 0; sal_Int32 nMaxPointCount = 0; double nMaxVal = findMaxValue(rDataSeriesContainer)/100; if (rDataSeriesContainer.empty()) { mnBarsInRow = 0; } else { const VDataSeries& rFirstRow = *rDataSeriesContainer.begin()->get(); mnBarsInRow = rFirstRow.getTotalPointCount(); } for (const std::unique_ptr& rDataSeries : rDataSeriesContainer) { nYPos = nSeriesIndex * (BAR_SIZE_Y + BAR_DISTANCE_Y) + BAR_DISTANCE_Y; sal_Int32 nPointCount = rDataSeries->getTotalPointCount(); nMaxPointCount = std::max(nMaxPointCount, nPointCount); bool bMappedFillProperty = rDataSeries->hasPropertyMapping("FillColor"); // Create series name text object. OUString aSeriesName = DataSeriesHelper::getDataSeriesLabel( rDataSeries->getModel(), mxChartType->getRoleOfSequenceForSeriesLabel()); maSeriesNames.push_back(aSeriesName); if(!aSeriesName.isEmpty()) { maShapes.push_back(o3tl::make_unique(mpRenderer.get(), *mpTextCache, aSeriesName, nId)); nId += ID_STEP; opengl3D::Text* p = static_cast(maShapes.back().get()); glm::vec3 aTopLeft, aTopRight, aBottomRight; aTopRight.x = -BAR_DISTANCE_Y; aTopRight.y = nYPos + BAR_DISTANCE_Y; aTopLeft.x = calculateTextWidth(aSeriesName) * -1.0 - BAR_DISTANCE_Y; aTopLeft.y = nYPos + BAR_DISTANCE_Y; aBottomRight = aTopRight; aBottomRight.y -= TEXT_HEIGHT; p->setPosition(aTopLeft, aTopRight, aBottomRight); } Color nColor = aSeriesColor[nSeriesIndex % SAL_N_ELEMENTS(aSeriesColor)]; for(sal_Int32 nIndex = 0; nIndex < nPointCount; ++nIndex) { if(bMappedFillProperty) { double nPropVal = rDataSeries->getValueByProperty(nIndex, "FillColor"); if(!rtl::math::isNan(nPropVal)) nColor = Color(static_cast(nPropVal)); } float nVal = rDataSeries->getYValue(nIndex); if (rtl::math::isNan(nVal)) continue; float nXPos = nIndex * (BAR_SIZE_X + BAR_DISTANCE_X) + BAR_DISTANCE_X; glm::mat4 aScaleMatrix = glm::scale(glm::vec3(BAR_SIZE_X, BAR_SIZE_Y, float(nVal/nMaxVal))); glm::mat4 aTranslationMatrix = glm::translate(glm::vec3(nXPos, nYPos, 0.0f)); glm::mat4 aBarPosition = aTranslationMatrix * aScaleMatrix; maBarMap.insert(std::pair(nId, BarInformation(glm::vec3(nXPos, nYPos, float(nVal/nMaxVal)), nVal))); recordBarHistory(nId, nVal); if (mbBenchMarkMode) { auto it = maBarColorMap.find(nId); if (it == maBarColorMap.end()) { maBarColorMap[nId] = nColor; } else { if(mbAutoFly) processAutoFly(nId, nColor); } } maShapes.push_back(o3tl::make_unique(mpRenderer.get(), aBarPosition, nColor, nId)); nId += ID_STEP; } float nThisXEnd = nPointCount * (BAR_SIZE_X + BAR_DISTANCE_X); if (nXEnd < nThisXEnd) nXEnd = nThisXEnd; ++nSeriesIndex; } nYPos += BAR_SIZE_Y + BAR_DISTANCE_Y; // X axis maShapes.push_back(o3tl::make_unique(mpRenderer.get(), nId)); nId += ID_STEP; opengl3D::Line* pAxis = static_cast(maShapes.back().get()); glm::vec3 aBegin; aBegin.y = nYPos; glm::vec3 aEnd = aBegin; aEnd.x = mbBenchMarkMode ? (mbScrollFlg ? nXEnd - BAR_SIZE_X : nXEnd) : nXEnd; pAxis->setPosition(aBegin, aEnd); pAxis->setLineColor(COL_BLUE); // Y axis maShapes.push_back(o3tl::make_unique(mpRenderer.get(), nId)); nId += ID_STEP; pAxis = static_cast(maShapes.back().get()); aBegin.x = aBegin.y = 0; aEnd = aBegin; aEnd.y = nYPos; pAxis->setPosition(aBegin, aEnd); pAxis->setLineColor(COL_BLUE); // Chart background. maShapes.push_back(o3tl::make_unique(mpRenderer.get(), nId)); nId += ID_STEP; opengl3D::Rectangle* pRect = static_cast(maShapes.back().get()); glm::vec3 aTopLeft; glm::vec3 aTopRight = aTopLeft; aTopRight.x = mbBenchMarkMode ? (mbScrollFlg ? nXEnd - BAR_SIZE_X : nXEnd + 2 * BAR_DISTANCE_X) : (nXEnd + 2 * BAR_DISTANCE_X); glm::vec3 aBottomRight = aTopRight; aBottomRight.y = nYPos; pRect->setPosition(aTopLeft, aTopRight, aBottomRight); pRect->setFillColor(COL_BLACK); pRect->setLineColor(COL_BLUE); if (mbScrollFlg) mpRenderer->SetSceneEdge(BAR_DISTANCE_X - 0.001f, aTopRight.x - BAR_DISTANCE_X); else mpRenderer->SetSceneEdge(-0.001f, aTopRight.x); // Create category texts along X-axis at the bottom. uno::Sequence aCats = rCatProvider.getSimpleCategories(); for (sal_Int32 i = 0; i < aCats.getLength(); ++i) { if (mbBenchMarkMode && mbScrollFlg && (i + 1 == aCats.getLength())) break; maCategories.push_back(aCats[i]); if(aCats[i].isEmpty()) continue; float nXPos = i * (BAR_SIZE_X + BAR_DISTANCE_X); maShapes.push_back(o3tl::make_unique(mpRenderer.get(), *mpTextCache, aCats[i], nId)); nId += ID_STEP; opengl3D::Text* p = static_cast(maShapes.back().get()); aTopLeft.x = nXPos + TEXT_HEIGHT + 0.5 * BAR_SIZE_X; aTopLeft.y = nYPos + calculateTextWidth(aCats[i]) + 0.5 * BAR_DISTANCE_Y; aTopRight = aTopLeft; aTopRight.y = nYPos + 0.5* BAR_DISTANCE_Y; aBottomRight.x = nXPos; aBottomRight.y = nYPos + 0.5 * BAR_DISTANCE_Y; p->setPosition(aTopLeft, aTopRight, aBottomRight); // create shapes on other side as well maShapes.push_back(o3tl::make_unique(mpRenderer.get(), *mpTextCache, aCats[i], nId)); nId += ID_STEP; p = static_cast(maShapes.back().get()); aTopLeft.x = nXPos + TEXT_HEIGHT + 0.5 * BAR_SIZE_X; aTopLeft.y = - 0.5 * BAR_DISTANCE_Y; aTopRight = aTopLeft; aTopRight.y = -calculateTextWidth(aCats[i]) - 0.5* BAR_DISTANCE_Y; aBottomRight.x = nXPos; aBottomRight.y = -calculateTextWidth(aCats[i]) - 0.5 * BAR_DISTANCE_Y; p->setPosition(aTopLeft, aTopRight, aBottomRight); } mnMaxX = nMaxPointCount * (BAR_SIZE_X + BAR_DISTANCE_X) + 40; mnMaxY = nSeriesIndex * (BAR_SIZE_Y + BAR_DISTANCE_Y) + 40; if (!mbCameraInit) { mnDistance = std::sqrt(mnMaxX * mnMaxX + mnMaxY * mnMaxY + DEFAULT_CAMERA_HEIGHT * DEFAULT_CAMERA_HEIGHT); maDefaultCameraDirection = glm::vec3(mnMaxX * 0.4, mnMaxY * 0.35, 0); maDefaultCameraPosition = glm::vec3(maDefaultCameraDirection.x, maDefaultCameraDirection.y - mnDistance, DEFAULT_CAMERA_HEIGHT * 2); mnCornerId = 0; mbCameraInit = true; float pi = 3.1415926f; float nAngleX = -pi / 6.5f; float nAngleZ = -pi / 8.0f; glm::mat4 aDefaultRotateMatrix = glm::eulerAngleYXZ(0.0f, nAngleX, nAngleZ); maDefaultCameraPosition = glm::vec3(aDefaultRotateMatrix * glm::vec4(maDefaultCameraPosition, 1.0f)); maCameraPosition = maDefaultCameraPosition; maCameraDirection = maDefaultCameraDirection; mpCamera->setPosition(maCameraPosition); mpCamera->setDirection(maCameraDirection); } else { mpCamera->setPosition(maCameraPosition); mpCamera->setDirection(maCameraDirection); } if (mbBenchMarkMode && (!mpRenderThread.is())) { //if scroll the bars, set the speed and distance first if (mbScrollFlg) { mpRenderer->SetScrollSpeed((BAR_SIZE_X + BAR_DISTANCE_X) / static_cast(miScrollRate)); mpRenderer->SetScrollDistance(BAR_SIZE_X + BAR_DISTANCE_X); } spawnRenderThread(new RenderBenchMarkThread(this)); } miDataUpdateCounter++; mnHistoryCounter++; mbNeedsNewRender = true; } void GL3DBarChart::joinRenderThread() { if(mpRenderThread.is()) { // FIXME: badly want to assert that we don't // hold the mutex here ... but can't API-wise. mpRenderThread->join(); } } void GL3DBarChart::spawnRenderThread(RenderThread *pThread) { joinRenderThread(); // not holding maMutex osl::MutexGuard aGuard(maMutex); Size aSize = mpWindow->GetSizePixel(); mpWindow->getContext().setWinSize(aSize); mpRenderThread.set(pThread); mpWindow->getContext().resetCurrent(); mpRenderThread->launch(); } void GL3DBarChart::update() { if (mbBenchMarkMode) return; spawnRenderThread(new RenderOneFrameThread(this)); } void GL3DBarChart::moveToDefault() { if(mbBenchMarkMode) { // add correct handling here!! if ((maRenderEvent != EVENT_NONE) && (maRenderEvent != EVENT_SHOW_SCROLL) && (maRenderEvent != EVENT_AUTO_FLY) && (maRenderEvent != EVENT_SHOW_SELECT)) return; { SharedResourceAccess aResGuard(maCond1, maCond2); osl::MutexGuard aGuard(maMutex); maRenderEvent = EVENT_MOVE_TO_DEFAULT; } return; } spawnRenderThread(new RenderAnimationThread(this, maCameraPosition, maDefaultCameraPosition, STEPS)); /* * TODO: moggi: add to thread glm::vec3 maTargetDirection = maDefaultCameraDirection; maStepDirection = (maTargetDirection - maCameraDirection)/((float)mnStepsTotal); */ } sal_uInt32 GL3DBarChart::barIdAtPosition(const Point& rPos) { sal_uInt32 nId = 5; { osl::MutexGuard aGuard(maMutex); mpWindow->getContext().makeCurrent(); mpRenderer->SetPickingMode(true); renderFrame(); nId = sal_uInt32(mpRenderer->GetPixelColorFromPoint(rPos.X(), rPos.Y())); mpRenderer->SetPickingMode(false); mpWindow->getContext().resetCurrent(); } return nId; } void GL3DBarChart::clickedAt(const Point& rPos, sal_uInt16 nButtons) { if (nButtons == MOUSE_RIGHT) { moveToDefault(); return; } if(nButtons != MOUSE_LEFT) return; if (mbBenchMarkMode) { // add correct handling here !! if ((maRenderEvent != EVENT_NONE) && (maRenderEvent != EVENT_SHOW_SCROLL) && (maRenderEvent != EVENT_AUTO_FLY) && (maRenderEvent != EVENT_SHOW_SELECT)) return; { SharedResourceAccess aResGuard(maCond1, maCond2); osl::MutexGuard aGuard(maMutex); maClickPos = rPos; mnPreSelectBarId = mnSelectBarId; maPreRenderEvent = maRenderEvent; maRenderEvent = EVENT_CLICK; maClickCond.reset(); } maClickCond.wait(); return; } sal_uInt32 nId = barIdAtPosition(rPos); std::map::const_iterator itr = maBarMap.find(nId); if(itr == maBarMap.end()) return; const BarInformation& rBarInfo = itr->second; { osl::MutexGuard aGuard(maMutex); mpWindow->getContext().makeCurrent(); glm::vec3 aTextPos = glm::vec3(rBarInfo.maPos.x + BAR_SIZE_X / 2.0f, rBarInfo.maPos.y + BAR_SIZE_Y / 2.0f, rBarInfo.maPos.z); maShapes.push_back(o3tl::make_unique(mpRenderer.get(), *mpTextCache, "Value: " + OUString::number(rBarInfo.mnVal), glm::vec4(0.0f, 0.0f, 1.0f, 1.0f), CALC_POS_EVENT_ID)); opengl3D::ScreenText* pScreenText = static_cast(maShapes.back().get()); pScreenText->setPosition(glm::vec2(-0.9f, 0.9f), glm::vec2(-0.6f, 0.8f), aTextPos); pScreenText->render(); mpWindow->getContext().resetCurrent(); } glm::vec3 aTargetPosition = rBarInfo.maPos; aTargetPosition.z += 240; aTargetPosition.y += BAR_SIZE_Y / 2.0f; spawnRenderThread(new RenderAnimationThread(this, maCameraPosition, aTargetPosition, STEPS)); /* * TODO: moggi: add to thread glm::vec3 maTargetDirection = rBarInfo.maPos; maTargetDirection.x += BAR_SIZE_X / 2.0f; maTargetDirection.y += BAR_SIZE_Y / 2.0f; maStepDirection = (maTargetDirection - maCameraDirection)/((float)mnStepsTotal); */ } void GL3DBarChart::render() { if (mbBenchMarkMode) return; update(); } void GL3DBarChart::renderFrame() { Size aSize = mpWindow->GetSizePixel(); mpRenderer->SetSize(aSize); if(mbNeedsNewRender) { mpRenderer->ReleaseTextTexture(); for(std::unique_ptr& aObj : maShapes) { aObj->render(); } } else { mpCamera->render(); } mpRenderer->ProcessUnrenderedShape(mbNeedsNewRender); mbNeedsNewRender = false; } void GL3DBarChart::mouseDragMove(const Point& rStartPos, const Point& rEndPos, sal_uInt16 ) { long nDirection = rEndPos.X() - rStartPos.X(); SharedResourceAccess aResGuard(maCond1, maCond2); osl::ClearableGuard aGuard(maMutex); if ((maRenderEvent == EVENT_NONE) || (maRenderEvent == EVENT_SHOW_SCROLL) || (maRenderEvent == EVENT_AUTO_FLY) || (maRenderEvent == EVENT_SHOW_SELECT)) maRenderEvent = nDirection > 0 ? EVENT_DRAG_RIGHT : EVENT_DRAG_LEFT; bool bMove = false; if(nDirection < 0) { mnCornerId = (mnCornerId + 1) % 4; bMove = true; } else if(nDirection > 0) { mnCornerId = mnCornerId - 1; if(mnCornerId < 0) mnCornerId = 3; bMove = true; } if (bMove) { aGuard.clear(); moveToCorner(); } } glm::vec3 GL3DBarChart::getCornerPosition(sal_Int8 nId) { float pi = 3.1415926f; switch(nId) { case 0: { return glm::vec3(mnMaxX / 2 - mnDistance * std::sin(pi / 4), mnMaxY / 2 - mnDistance * std::cos(pi / 4), DEFAULT_CAMERA_HEIGHT * 2); } break; case 1: { return glm::vec3(mnMaxX / 2 + mnDistance * std::sin(pi / 4), mnMaxY / 2 - mnDistance * std::cos(pi / 4), DEFAULT_CAMERA_HEIGHT * 2); } break; case 2: { return glm::vec3(mnMaxX / 2 + mnDistance * std::sin(pi / 4), mnMaxY / 2 + mnDistance * std::cos(pi / 4), DEFAULT_CAMERA_HEIGHT * 2); } break; case 3: { return glm::vec3(mnMaxX / 2 - mnDistance * std::sin(pi / 4), mnMaxY / 2 + mnDistance * std::cos(pi / 4), DEFAULT_CAMERA_HEIGHT * 2); } break; default: assert(false); } return maDefaultCameraPosition; } void GL3DBarChart::moveToCorner() { if(mbBenchMarkMode) { // add correct handling here!! return; } spawnRenderThread(new RenderAnimationThread(this, maCameraPosition, getCornerPosition(mnCornerId), STEPS)); // TODO: moggi: add to thread // maStepDirection = (glm::vec3(mnMaxX/2.0f, mnMaxY/2.0f, 0) - maCameraDirection)/ float(mnStepsTotal); } void GL3DBarChart::scroll(long nDelta) { { SharedResourceAccess aResGuard(maCond1, maCond2); osl::MutexGuard aGuard(maMutex); if ((maRenderEvent != EVENT_NONE) && (maRenderEvent != EVENT_SHOW_SCROLL) && (maRenderEvent != EVENT_AUTO_FLY) && (maRenderEvent != EVENT_SHOW_SELECT)) return; glm::vec3 aDir = glm::normalize(maCameraPosition - maCameraDirection); maCameraPosition -= (static_cast(nDelta)/10) * aDir; mpCamera->setPosition(maCameraPosition); if(mbBenchMarkMode) { maVectorNearest.clear(); getNearestBars(maVectorNearest); maRenderEvent = EVENT_SCROLL; } } update(); } void GL3DBarChart::contextDestroyed() { SharedResourceAccess aResGuard(maCond1, maCond2); osl::MutexGuard aGuard(maMutex); mpWindow->getContext().makeCurrent(); mpRenderer.reset(); mpWindow->getContext().resetCurrent(); mbValidContext = false; } float GL3DBarChart::addScreenTextShape(OUString &nStr, const glm::vec2& rLeftOrRightTop, float nTextHeight, bool bLeftTopFlag, const glm::vec4& rColor, const glm::vec3& rPos, sal_uInt32 nEvent) { maScreenTextShapes.push_back(o3tl::make_unique(mpRenderer.get(), *mpTextCache, nStr, rColor, nEvent)); const opengl3D::TextCacheItem& rTextCache = mpTextCache->getText(nStr); float nRectWidth = static_cast(rTextCache.maSize.Width()) / static_cast(rTextCache.maSize.Height()) * nTextHeight / 2.0f; opengl3D::ScreenText* pScreenText = static_cast(maScreenTextShapes.back().get()); if (bLeftTopFlag) pScreenText->setPosition(rLeftOrRightTop, glm::vec2(rLeftOrRightTop.x + nRectWidth, rLeftOrRightTop.y - nTextHeight), rPos); else pScreenText->setPosition(glm::vec2(rLeftOrRightTop.x - nRectWidth, rLeftOrRightTop.y), glm::vec2(rLeftOrRightTop.x, rLeftOrRightTop.y - nTextHeight), rPos); return nRectWidth; } void GL3DBarChart::updateRenderFPS() { int nDeltaMs = calcTimeInterval(maFPSRenderStartTime, maFPSRenderEndTime); if(nDeltaMs >= FPS_TIME) { osl_getSystemTime(&maFPSRenderEndTime); nDeltaMs = calcTimeInterval(maFPSRenderStartTime, maFPSRenderEndTime); int iFPS = miFrameCount * 1000 / nDeltaMs; maFPS = OUString::number(iFPS); miFrameCount = 0; osl_getSystemTime(&maFPSRenderStartTime); } osl_getSystemTime(&maFPSRenderEndTime); OUString aFPS = "Render FPS: "; addScreenTextShape(aFPS, glm::vec2(-0.77f, 0.99f), 0.07f, false, glm::vec4(0.0f, 1.0f, 1.0f, 0.0f)); addScreenTextShape(maFPS, glm::vec2(-0.77f, 0.99f), 0.07f, true, glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f)); } int GL3DBarChart::calcTimeInterval(TimeValue const &startTime, TimeValue const &endTime) { TimeValue aTime; aTime.Seconds = endTime.Seconds - startTime.Seconds - 1; aTime.Nanosec = 1000000000 + endTime.Nanosec - startTime.Nanosec; aTime.Seconds += aTime.Nanosec / 1000000000; aTime.Nanosec %= 1000000000; return aTime.Seconds * 1000+aTime.Nanosec / 1000000; } void GL3DBarChart::updateScreenText() { SharedResourceAccess aResGuard(maCond1, maCond2); osl::MutexGuard aGuard(maMutex); maScreenTextShapes.clear(); mpRenderer->ReleaseScreenTextShapes(); updateRenderFPS(); updateDataUpdateFPS(); updateClickEvent(); updateScroll(); mbScreenTextNewRender = true; } void GL3DBarChart::updateDataUpdateFPS() { int nDeltaMs = calcTimeInterval(maDataUpdateStartTime, maDataUpdateEndTime); if(nDeltaMs >= DATAUPDATE_FPS_TIME) { int iFPS = miDataUpdateCounter * 1000 / nDeltaMs; if (iFPS) { maDataUpdateFPS = OUString::number(iFPS); } else { float fFPS = static_cast(miDataUpdateCounter) * 1000 / static_cast(nDeltaMs); maDataUpdateFPS = OUString::number(fFPS); } miDataUpdateCounter = 0; osl_getSystemTime(&maDataUpdateStartTime); } osl_getSystemTime(&maDataUpdateEndTime); OUString aDataUpdateFPS = "Data Update Rate: "; addScreenTextShape(aDataUpdateFPS, glm::vec2(-0.77, 0.92f), 0.07f, false, glm::vec4(0.0f, 1.0f, 1.0f, 0.0f)); addScreenTextShape(maDataUpdateFPS, glm::vec2(-0.77f, 0.92f), 0.07f, true, glm::vec4(1.0f, 0.0f, 0.0f, 0.0f)); } void GL3DBarChart::recordBarHistory(sal_uInt32 nBarID, float nVal) { std::deque& aList = maBarHistory[nBarID]; if(aList.size() == HISTORY_NUM) aList.pop_front(); aList.push_back(nVal); } void GL3DBarChart::getNeighborBarID(sal_uInt32 nSelectBarId, sal_uInt32 *pNeighborBarId) { sal_uInt32 nSelectRow = (nSelectBarId - SHAPE_START_ID) / ID_STEP / (mnBarsInRow + 1); for (sal_Int32 i = 0; i < DISPLAY_BARS_NUM; i++) { pNeighborBarId[i] = nSelectBarId + (i - DISPLAY_BARS_NUM / 2) * ID_STEP; if (pNeighborBarId[i] == nSelectBarId) continue; if ((pNeighborBarId[i] - SHAPE_START_ID) / ID_STEP / (mnBarsInRow + 1) != nSelectRow) pNeighborBarId[i] = 0; } } void GL3DBarChart::addMovementScreenText(sal_uInt32 nBarId) { if (nBarId == 0) return; std::map::const_iterator itr = maBarMap.find(nBarId); if (itr == maBarMap.end()) return; const BarInformation& rBarInfo = itr->second; glm::vec3 aTextPos = glm::vec3(rBarInfo.maPos.x + BAR_SIZE_X / 2.0f, rBarInfo.maPos.y + BAR_SIZE_Y / 2.0f, rBarInfo.maPos.z); OUString aBarValue = "Value: " + OUString::number(rBarInfo.mnVal); maScreenTextShapes.push_back(o3tl::make_unique(mpRenderer.get(), *mpTextCache, aBarValue, glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), CALC_POS_EVENT_ID, true)); const opengl3D::TextCacheItem& rTextCache = mpTextCache->getText(aBarValue); float nRectWidth = static_cast(rTextCache.maSize.Width()) / static_cast(rTextCache.maSize.Height()) * 0.024; opengl3D::ScreenText* pScreenText = static_cast(maScreenTextShapes.back().get()); pScreenText->setPosition(glm::vec2(-nRectWidth / 2, 0.03f), glm::vec2(nRectWidth / 2, -0.03f), aTextPos); } void GL3DBarChart::updateClickEvent() { if (maRenderEvent == EVENT_CLICK || maRenderEvent == EVENT_AUTO_FLY || maRenderEvent == EVENT_SHOW_SELECT) { std::deque& aList = maBarHistory[mnSelectBarId]; sal_uInt32 nIdex = 0; sal_uInt32 nBarIdArray[DISPLAY_BARS_NUM] = {0}; OUString aTitle; OUString aBarValue; float nXCoordStart, nYCoordStart, nTextWidth, nMaxXCoord = 0.0f, nMinXCoord = 1.0f, nMaxHight = 0.0f; //write title if (aList.size() > 1) { aTitle = "Time "; nTextWidth = addScreenTextShape(aTitle, glm::vec2(0.875, 0.99f), 0.07f, false, glm::vec4(0.0f, 1.0f, 1.0f, 0.5f)); nMinXCoord = std::min(nMinXCoord, 0.875f - nTextWidth); aTitle = " Value"; nTextWidth = addScreenTextShape(aTitle, glm::vec2(0.875f, 0.99f), 0.07f, true, glm::vec4(0.0f, 1.0f, 1.0f, 0.5f)); nMaxXCoord = std::max(nMaxXCoord, 0.875f + nTextWidth); } if (aList.size() > COLUMNSIZE) { aTitle = "Time "; nTextWidth = addScreenTextShape(aTitle, glm::vec2(0.55f, 0.99f), 0.07f, false, glm::vec4(0.0f, 1.0f, 1.0f, 0.5f)); nMinXCoord = std::min(nMinXCoord, 0.55f - nTextWidth); aTitle = " Value"; nTextWidth = addScreenTextShape(aTitle, glm::vec2(0.55f, 0.99f), 0.07f, true, glm::vec4(0.0f, 1.0f, 1.0f, 0.5f)); nMaxXCoord = std::max(nMaxXCoord, 0.55f + nTextWidth); } getNeighborBarID(mnSelectBarId, nBarIdArray); for (auto const& elem : aList) { if (nIdex + 1 < aList.size()) { aTitle = "[Time:" + OUString::number((mnHistoryCounter - aList.size() + nIdex)) + "]: "; if (nIdex == 0) { aTitle = "Most Recent" + aTitle; } if (aList.size() <= COLUMNSIZE) { nXCoordStart = 0.875f; nYCoordStart = (nIdex + 1) * 0.07f; } else { nXCoordStart = nIdex < COLUMNSIZE ? 0.55f : 0.875f; nYCoordStart = nIdex < COLUMNSIZE ? (nIdex + 1) * 0.07f : (nIdex - 24) * 0.07f; } nMaxHight = std::max(nMaxHight, nYCoordStart + 0.07f); nTextWidth = addScreenTextShape(aTitle, glm::vec2(nXCoordStart, 0.99f - nYCoordStart), 0.07f, false, glm::vec4(0.0f, 1.0f, 1.0f, 0.5f)); nMinXCoord = std::min(nMinXCoord, nXCoordStart - nTextWidth); aBarValue = OUString::number(elem); nTextWidth = addScreenTextShape(aBarValue, glm::vec2(nXCoordStart, 0.99f - nYCoordStart), 0.07f, true, glm::vec4(0.0f, 1.0f, 1.0f, 0.5f)); nMaxXCoord = std::max(nMaxXCoord, nXCoordStart + nTextWidth); } nIdex++; } for (unsigned int i : nBarIdArray) { addMovementScreenText(i); } //add translucent back ground aTitle = " "; maScreenTextShapes.push_back(o3tl::make_unique(mpRenderer.get(), *mpTextCache, aTitle, glm::vec4(0.0f, 0.0f, 0.0f, 0.5f), 0)); opengl3D::ScreenText* pScreenText = static_cast(maScreenTextShapes.back().get()); pScreenText->setPosition(glm::vec2(nMinXCoord, 0.99f), glm::vec2(nMaxXCoord, 0.99f - nMaxHight), glm::vec3(0.0, 0.0, 0.0)); } } float GL3DBarChart::calcScrollDistance(const glm::mat4& rMVP, const glm::vec3& rPos) { glm::vec4 aScreenPos = rMVP * glm::vec4(rPos, 1.0); glm::vec3 aActualPos = glm::vec3(aScreenPos.x / aScreenPos.w, aScreenPos.y / aScreenPos.w, 0.0); return glm::length(aActualPos); } void GL3DBarChart::calcDistance(std::vector & rVectorNearest) { int i =0; glm::mat4 aProjection = mpRenderer->GetProjectionMatrix(); glm::mat4 aView = mpRenderer->GetViewMatrix(); glm::mat4 aScale = mpRenderer->GetGlobalScaleMatrix(); glm::mat4 aMVP = aProjection * aView * aScale; for (auto const& elem : maBarMap) { sal_uInt32 nId = elem.first; if(i < SHOW_VALUE_COUNT) { rVectorNearest.push_back(nId); i++; } maDistanceMap[nId] = calcScrollDistance(aMVP, glm::vec3(elem.second.maPos.x + BAR_SIZE_X / 2.0f, elem.second.maPos.y + BAR_SIZE_Y / 2.0f, elem.second.maPos.z)); } } void GL3DBarChart::initDistanceHeap(std::vector &rVectorNearest) { for(int i= (rVectorNearest.size()-2)/2; i>= 0; i--) { keepHeap(rVectorNearest, i); } } void GL3DBarChart::keepHeap(std::vector &rVectorNearest, int nIndex) { size_t nParentIndex = nIndex; while(nParentIndex < rVectorNearest.size()) { size_t nLeftIndex = nParentIndex * 2 + 1; size_t nRightIndex = nLeftIndex +1; if(nLeftIndex >= rVectorNearest.size()) break; size_t nFarthestIndex = nLeftIndex; float nFarthest = maDistanceMap[rVectorNearest[nLeftIndex]]; if(nRightIndex < rVectorNearest.size()) { float nRight = maDistanceMap[rVectorNearest[nRightIndex]]; if(nRight > nFarthest) { nFarthest = nRight; nFarthestIndex = nRightIndex; } } float nParent = maDistanceMap[rVectorNearest[nParentIndex]]; if(nParent >= nFarthest) break; else { swapVector(nParentIndex , nFarthestIndex, rVectorNearest); nParentIndex = nFarthestIndex; } } } void GL3DBarChart::swapVector(int i, int j, std::vector &rVectorNearest) { sal_uInt32 nTmp = rVectorNearest[i]; rVectorNearest[i] = rVectorNearest[j]; rVectorNearest[j] = nTmp; } void GL3DBarChart::getNearestBars(std::vector &rVectorNearest) { calcDistance(rVectorNearest); initDistanceHeap(rVectorNearest); int i = 0; for (auto const& elem : maDistanceMap) { ++i; if(i <= SHOW_VALUE_COUNT) continue; float nDistance = elem.second; float nHeaphead = maDistanceMap[rVectorNearest[0]]; if(nDistance < nHeaphead) { rVectorNearest[0] = elem.first; keepHeap(rVectorNearest, 0); } } } void GL3DBarChart::updateScroll() { if ((maRenderEvent == EVENT_SCROLL) || (maRenderEvent == EVENT_SHOW_SCROLL)) { float fMinDistance = 0.0f; std::vector aBarInfoList; for(sal_uInt32 i : maVectorNearest) { //get bar height position std::map::const_iterator itr = maBarMap.find(i); const BarInformation& rBarInfo = itr->second; aBarInfoList.push_back(rBarInfo); glm::vec3 aPos = rBarInfo.maPos; fMinDistance = (fMinDistance == 0.0f) ? glm::length(aPos - maCameraPosition) : std::min(glm::length(aPos - maCameraPosition), fMinDistance); } if (fMinDistance <= SHOW_SCROLL_TEXT_DISTANCE) { //update scroll value for(BarInformation & i : aBarInfoList) { OUString aBarValue = "Value: " + OUString::number(i.mnVal); maScreenTextShapes.push_back(o3tl::make_unique(mpRenderer.get(), *mpTextCache, aBarValue, glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), CALC_POS_EVENT_ID, true)); const opengl3D::TextCacheItem& rTextCache = mpTextCache->getText(aBarValue); float nRectWidth = static_cast(rTextCache.maSize.Width()) / static_cast(rTextCache.maSize.Height()) * 0.024; glm::vec3 aTextPos = glm::vec3(i.maPos.x + BAR_SIZE_X / 2.0f, i.maPos.y + BAR_SIZE_Y / 2.0f, i.maPos.z); opengl3D::ScreenText* pScreenText = static_cast(maScreenTextShapes.back().get()); pScreenText->setPosition(glm::vec2(-nRectWidth / 2, 0.03f), glm::vec2(nRectWidth / 2, -0.03f), aTextPos); } } } } void GL3DBarChart::processAutoFly(sal_uInt32 nId, Color nColor) { //record the color Color nPreColor = maBarColorMap[nId]; maBarColorMap[nId] = nColor; //if has manul event, just record the color and process manul event first if (maRenderEvent != EVENT_NONE) { return; } //calc the percentage of color change int nColorRate = (sal_uInt32(nColor) - sal_uInt32(nPreColor)) * 100 / sal_uInt32(nPreColor); nColorRate = abs(nColorRate); if (nColorRate >= FLY_THRESHOLD) { maRenderEvent = EVENT_AUTO_FLY; mnSelectBarId = nColorRate > mnColorRate ? nId : mnSelectBarId; mnPreSelectBarId = mnSelectBarId; mnColorRate = std::max(nColorRate, mnColorRate); } } IMPL_LINK_NOARG(GL3DBarChart, UpdateTimerHdl, Timer *, void) { updateScreenText(); maIdle.Start(); } void GL3DBarChart::setOpenGLWindow(OpenGLWindow* pWindow) { if (mpWindow.get() != pWindow) { mpWindow = pWindow; Size aSize = mpWindow->GetSizePixel(); mpRenderer->SetSize(aSize); mpWindow->setRenderer(this); mpWindow->getContext().makeCurrent(); mpRenderer->init(); mpWindow->getContext().resetCurrent(); mbValidContext = true; } } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */