diff --git a/examples/cpu/CMakeLists.txt b/examples/cpu/CMakeLists.txt index 9f48b949..3b27d689 100644 --- a/examples/cpu/CMakeLists.txt +++ b/examples/cpu/CMakeLists.txt @@ -6,6 +6,7 @@ add_example(bubblechart bubblechart.cpp cpu CXX11) add_example(field field.cpp cpu) add_example(fractal fractal.cpp cpu) add_example(histogram histogram.cpp cpu) +add_example(pie pie.cpp cpu) add_example(plot3 plot3.cpp cpu) add_example(plotting plotting.cpp cpu) add_example(stream stream.cpp cpu) diff --git a/examples/cpu/pie.cpp b/examples/cpu/pie.cpp new file mode 100644 index 00000000..91bf45cf --- /dev/null +++ b/examples/cpu/pie.cpp @@ -0,0 +1,81 @@ +/******************************************************* + * Copyright (c) 2015-2019, ArrayFire + * All rights reserved. + * + * This file is distributed under 3-clause BSD license. + * The complete license agreement can be obtained at: + * http://arrayfire.com/licenses/BSD-3-Clause + ********************************************************/ + +#include +#define USE_FORGE_CPU_COPY_HELPERS +#include +#include +#include +#include +#include + +const unsigned DIMX = 1000; +const unsigned DIMY = 800; +const unsigned NSECTORS = 10; + +std::vector generateSectors(unsigned count = NSECTORS) { + std::vector result; + float prefixSum = 0; + for (; count > 0; --count) { + result.push_back(prefixSum); + result.push_back(std::rand() & 0xffff); + prefixSum += result.back(); + } + return result; +} + +std::vector generateColors(unsigned count = NSECTORS) { + std::vector result; + for (; count > 0; --count) { + for (int channel = 0; channel < 3; ++channel) + result.push_back(std::rand() / (float)RAND_MAX); + } + return result; +} + +int main(int argc, char* argv[]) { + /* + * First Forge call should be a window creation call + * so that necessary OpenGL context is created for any + * other forge::* object to be created successfully + */ + forge::Window wnd(DIMX, DIMY, "Pie Demo"); + wnd.makeCurrent(); + + forge::Chart chart(FG_CHART_2D); + + /* + * Create pie object specifying number of bins + */ + forge::Pie pie = chart.pie(NSECTORS, forge::f32); + + GfxHandle* handles[2]; + createGLBuffer(&handles[0], pie.vertices(), FORGE_VERTEX_BUFFER); + createGLBuffer(&handles[1], pie.colors(), FORGE_VERTEX_BUFFER); + + std::vector pieArray = generateSectors(); + std::vector colArray = generateColors(); + + /* set the axes limits to minimum and maximum values of data */ + float valueRange = + pieArray[pieArray.size() - 2] + pieArray[pieArray.size() - 1]; + chart.setAxesLimits(0, valueRange, 0, valueRange); + + copyToGLBuffer(handles[0], (ComputeResourceHandle)pieArray.data(), + pie.verticesSize()); + copyToGLBuffer(handles[1], (ComputeResourceHandle)colArray.data(), + pie.colorsSize()); + + do { wnd.draw(chart); } while (!wnd.close()); + + releaseGLBuffer(handles[0]); + releaseGLBuffer(handles[1]); + + return 0; +} diff --git a/include/fg/chart.h b/include/fg/chart.h index e2a578e5..c869e7ab 100644 --- a/include/fg/chart.h +++ b/include/fg/chart.h @@ -10,12 +10,12 @@ #pragma once #include +#include #include +#include #include #include #include -#include - #ifdef __cplusplus extern "C" { @@ -148,6 +148,16 @@ FGAPI fg_err fg_append_image_to_chart(fg_chart pChart, fg_image pImage); */ FGAPI fg_err fg_append_histogram_to_chart(fg_chart pChart, fg_histogram pHistogram); +/** + Add an existing pie object to chart + + \param[in] pChart is the chart to which pie has to be added + \param[in] pPie is the pie to be added to the chart + + \return \ref fg_err error code + */ +FGAPI fg_err fg_append_pie_to_chart(fg_chart pChart, fg_pie pPie); + /** Add an existing plot object to chart @@ -211,6 +221,21 @@ FGAPI fg_err fg_add_image_to_chart(fg_image* pImage, fg_chart pHandle, FGAPI fg_err fg_add_histogram_to_chart(fg_histogram* pHistogram, fg_chart pHandle, const unsigned pNBins, const fg_dtype pType); +/** + Create and add a Pie object to the current chart + + \param[out] pPie is the handle of the pie object created + \param[in] pHandle is chart handle + \param[in] pNSectors is number of sectors the data is sorted out + \param[in] pType takes one of the values of \ref fg_dtype that indicates + the integral data type of pie data + + \return \ref fg_err error code + */ +FGAPI fg_err fg_add_pie_to_chart(fg_pie *pPie, fg_chart pHandle, + const unsigned pNSectors, + const fg_dtype pType); + /** Create and add an Plot object to the current chart @@ -283,6 +308,16 @@ Remove a Histogram object from the current chart FGAPI fg_err fg_remove_histogram_from_chart(fg_chart pHandle, fg_histogram pHistogram); +/** +Remove a Pie object from the current chart + +\param[in] pHandle is chart handle +\param[in] pPie is the handle of the pie object to remove + +\return \ref fg_err error code +*/ +FGAPI fg_err fg_remove_pie_from_chart(fg_chart pHandle, fg_pie pPie); + /** Remove a Plot object from the current chart @@ -459,6 +494,13 @@ class Chart { */ FGAPI void add(const Histogram& pHistogram); + /** + Add an existing Pie object to the current chart + + \param[in] pPie is the Pie to render on the chart + */ + FGAPI void add(const Pie &pPie); + /** Add an existing Plot object to the current chart @@ -494,6 +536,13 @@ class Chart { */ FGAPI void remove(const Histogram &pHistogram); + /** + Remove an existing Pie object to the current chart + + \param[in] pPie is the Pie to remove from the chart + */ + FGAPI void remove(const Pie &pPie); + /** Remove an existing Plot object to the current chart @@ -537,6 +586,15 @@ class Chart { */ FGAPI Histogram histogram(const unsigned pNBins, const dtype pDataType); + /** + Create and add a Pie object to the current chart + + \param[in] pNSectors is number of sectors the data is sorted out + \param[in] pDataType takes one of the values of \ref dtype that + indicates the integral data type of pie data + */ + FGAPI Pie pie(const unsigned pNSectors, const dtype pDataType); + /** Create and add an Plot object to the current chart diff --git a/include/fg/defines.h b/include/fg/defines.h index fc471fb1..8cc0bce3 100644 --- a/include/fg/defines.h +++ b/include/fg/defines.h @@ -49,6 +49,9 @@ typedef void* fg_image; /// \brief Histogram handle typedef void* fg_histogram; +/// \brief Pie handle +typedef void *fg_pie; + /// \brief Plot handle typedef void* fg_plot; diff --git a/include/fg/histogram.h b/include/fg/histogram.h index 0287540c..306349ee 100644 --- a/include/fg/histogram.h +++ b/include/fg/histogram.h @@ -58,8 +58,8 @@ FGAPI fg_err fg_release_histogram(fg_histogram pHistogram); This is global alpha value for the histogram rendering that takes effect if individual bar alphas are not set by calling the following member functions - - Histogram::alphas() - - Histogram::alphasSize() + - fg_get_histogram_alpha_buffer + - fg_get_histogram_alpha_buffer_size \param[in] pHistogram is the histogram handle \param[in] pRed is Red component in range [0, 1] diff --git a/include/fg/pie.h b/include/fg/pie.h new file mode 100644 index 00000000..98cef7cb --- /dev/null +++ b/include/fg/pie.h @@ -0,0 +1,272 @@ +/******************************************************* + * Copyright (c) 2015-2019, ArrayFire + * All rights reserved. + * + * This file is distributed under 3-clause BSD license. + * The complete license agreement can be obtained at: + * http://arrayfire.com/licenses/BSD-3-Clause + ********************************************************/ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \addtogroup pie_functions + * @{ + */ + +/** + Creates a Pie object + + \param[out] pPie will point to the pie object created after this function + call \param[in] pNSectors is number of sectors the data is sorted out + \param[in] pDataType takes one of the values of \ref fg_dtype that indicates + the integral data type of sector data + + \return \ref fg_err error code + */ +FGAPI fg_err fg_create_pie(fg_pie *pPie, const unsigned pNSectors, + const fg_dtype pDataType); + +/** + Increase reference count of the resource + + \param[out] pOut is the new handle to existing resource + \param[in] pIn is the existing resource handle + + \return \ref fg_err error code + */ +FGAPI fg_err fg_retain_pie(fg_pie *pOut, fg_pie pIn); + +/** + Destroy Pie object + + \param[in] pPie is the pie handle + + \return \ref fg_err error code + */ +FGAPI fg_err fg_release_pie(fg_pie pPie); + +/** + Set the color of all sectors in the pie chart + + This is global alpha value for the pie rendering that takes + effect if individual sector alphas are not set in the buffer + obtained by the following functions + - fg_get_pie_alpha_buffer + - fg_get_pie_alpha_buffer_size + + \param[in] pPie is the pie handle + \param[in] pRed is Red component in range [0, 1] + \param[in] pGreen is Green component in range [0, 1] + \param[in] pBlue is Blue component in range [0, 1] + \param[in] pAlpha is Alpha component in range [0, 1] + + \return \ref fg_err error code + */ +FGAPI fg_err fg_set_pie_color(fg_pie pPie, const float pRed, const float pGreen, + const float pBlue, const float pAlpha); + +/** + Set legend for pie plot + + \param[in] pPie is the pie handle + \param[in] pLegend + + \return \ref fg_err error code + */ +FGAPI fg_err fg_set_pie_legend(fg_pie pPie, const char *pLegend); + +/** + Get the resource identifier for vertices buffer + + \param[out] pOut will have the buffer identifier after this function is + called \param[in] pPie is the pie handle + + \return \ref fg_err error code + */ +FGAPI fg_err fg_get_pie_vertex_buffer(unsigned *pOut, const fg_pie pPie); + +/** + Get the resource identifier for colors buffer + + \param[out] pOut will have the buffer identifier after this function is + called \param[in] pPie is the pie handle + + \return \ref fg_err error code + */ +FGAPI fg_err fg_get_pie_color_buffer(unsigned *pOut, const fg_pie pPie); + +/** + Get the resource identifier for alpha values buffer + + \param[out] pOut will have the buffer identifier after this function is + called \param[in] pPie is the pie handle + + \return \ref fg_err error code + */ +FGAPI fg_err fg_get_pie_alpha_buffer(unsigned *pOut, const fg_pie pPie); + +/** + Get the vertices buffer size in bytes + + \param[out] pOut will have the buffer size in bytes after this function is + called \param[in] pPie is the pie handle + + \return \ref fg_err error code + */ +FGAPI fg_err fg_get_pie_vertex_buffer_size(unsigned *pOut, const fg_pie pPie); + +/** + Get the colors buffer size in bytes + + \param[out] pOut will have the buffer size in bytes after this function is + called \param[in] pPie is the pie handle + + \return \ref fg_err error code + */ +FGAPI fg_err fg_get_pie_color_buffer_size(unsigned *pOut, const fg_pie pPie); + +/** + Get the alpha values buffer size in bytes + + \param[out] pOut will have the buffer size in bytes after this function is + called \param[in] pPie is the pie handle + + \return \ref fg_err error code + */ +FGAPI fg_err fg_get_pie_alpha_buffer_size(unsigned *pOut, const fg_pie pPie); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus + +namespace forge { + +/// \brief Pie is a statistical graph to display numerical proportion. +class Pie { +private: + fg_pie mValue; + +public: + /** + Creates a Pie object + + \param[in] pNSectors is number of bins the data is sorted out + \param[in] pDataType takes one of the values of \ref fg_dtype that + indicates the integral data type of pie data + */ + FGAPI Pie(const unsigned pNSectors, const dtype pDataType); + + /** + Copy constructor for Pie + + \param[in] pOther is the Pie of which we make a copy of. + */ + FGAPI Pie(const Pie &pOther); + + /** + Construct Pie ojbect from fg_pie resource handle + + \param[in] pHandle is the input fg_pie resource handle + + \note This kind of construction assumes ownership of the resource handle + is released during the Pie object's destruction. + */ + FGAPI explicit Pie(const fg_pie pHandle); + + /** + Pie Destructor + */ + FGAPI ~Pie(); + + /** + Set the color of all sectors in the pie chart + + \param[in] pColor takes values of type forge::Color to define sector color + */ + FGAPI void setColor(const Color pColor); + + /** + Set the color of all sectors in the pie chart + + This is global alpha value for the pie rendering that takes + effect if individual sector alphas are not set by calling the following + member functions + - Pie::alphas() + - Pie::alphasSize() + + \param[in] pRed is Red component in range [0, 1] + \param[in] pGreen is Green component in range [0, 1] + \param[in] pBlue is Blue component in range [0, 1] + \param[in] pAlpha is Alpha component in range [0, 1] + */ + FGAPI void setColor(const float pRed, const float pGreen, const float pBlue, + const float pAlpha); + + /** + Set legend for pie plot + + \param[in] pLegend + */ + FGAPI void setLegend(const char *pLegend); + + /** + Get the buffer identifier for vertices + + \return vertex buffer resource id. + */ + FGAPI unsigned vertices() const; + + /** + Get the buffer identifier for color values per vertex + + \return colors buffer resource id. + */ + FGAPI unsigned colors() const; + + /** + Get the buffer identifier for alpha values per vertex + + \return alpha values buffer resource id. + */ + FGAPI unsigned alphas() const; + + /** + Get the vertex buffer size in bytes + + \return vertex buffer size in bytes + */ + FGAPI unsigned verticesSize() const; + + /** + Get the colors buffer size in bytes + + \return colors buffer size in bytes + */ + FGAPI unsigned colorsSize() const; + + /** + Get the alpha values buffer size in bytes + + \return alpha buffer size in bytes + */ + FGAPI unsigned alphasSize() const; + + /** + Get the handle to internal implementation of Pie + */ + FGAPI fg_pie get() const; +}; + +} // namespace forge + +#endif diff --git a/src/api/c/CMakeLists.txt b/src/api/c/CMakeLists.txt index 9f4574d5..e1ff9fdb 100644 --- a/src/api/c/CMakeLists.txt +++ b/src/api/c/CMakeLists.txt @@ -7,6 +7,7 @@ target_sources(forge_c_api_interface $ $ $ + $ $ $ $ diff --git a/src/api/c/chart.cpp b/src/api/c/chart.cpp index ae095ba2..76171d33 100644 --- a/src/api/c/chart.cpp +++ b/src/api/c/chart.cpp @@ -7,21 +7,22 @@ * http://arrayfire.com/licenses/BSD-3-Clause ********************************************************/ +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include using namespace forge; using namespace forge::common; @@ -161,6 +162,19 @@ fg_err fg_append_histogram_to_chart(fg_chart pChart, fg_histogram pHistogram) { return FG_ERR_NONE; } +fg_err fg_append_pie_to_chart(fg_chart pChart, fg_pie pPie) { + try { + ARG_ASSERT(0, (pChart != 0)); + ARG_ASSERT(1, (pPie != 0)); + + getChart(pChart)->addRenderable(getPie(pPie)->impl()); + getChart(pChart)->setAxesVisibility(false); + } + CATCHALL + + return FG_ERR_NONE; +} + fg_err fg_append_plot_to_chart(fg_chart pChart, fg_plot pPlot) { try { ARG_ASSERT(0, (pChart != 0)); @@ -238,6 +252,27 @@ fg_err fg_add_histogram_to_chart(fg_histogram* pHistogram, fg_chart pChart, return FG_ERR_NONE; } +fg_err fg_add_pie_to_chart(fg_pie* pPie, fg_chart pChart, + const unsigned pNSectors, const fg_dtype pType) { + try { + ARG_ASSERT(1, (pChart != 0)); + ARG_ASSERT(2, (pNSectors > 0)); + + common::Chart* chrt = getChart(pChart); + + // Pie is only allowed in FG_CHART_2D + ARG_ASSERT(5, chrt->chartType() == FG_CHART_2D); + + common::Pie* pie = new common::Pie(pNSectors, (forge::dtype)pType); + chrt->addRenderable(pie->impl()); + chrt->setAxesVisibility(false); + *pPie = getHandle(pie); + } + CATCHALL + + return FG_ERR_NONE; +} + fg_err fg_add_plot_to_chart(fg_plot* pPlot, fg_chart pChart, const unsigned pNPoints, const fg_dtype pType, const fg_plot_type pPlotType, @@ -340,6 +375,21 @@ fg_err fg_remove_histogram_from_chart(fg_chart pChart, return FG_ERR_NONE; } +fg_err fg_remove_pie_from_chart(fg_chart pChart, fg_pie pPie) { + try { + ARG_ASSERT(0, (pPie != 0)); + ARG_ASSERT(1, (pChart != 0)); + + common::Chart* chrt = getChart(pChart); + + common::Pie* pie = getPie(pPie); + chrt->removeRenderable(pie->impl()); + } + CATCHALL + + return FG_ERR_NONE; +} + fg_err fg_remove_plot_from_chart(fg_chart pChart, fg_plot pPlot) { try { ARG_ASSERT(0, (pPlot != 0)); diff --git a/src/api/c/pie.cpp b/src/api/c/pie.cpp new file mode 100644 index 00000000..8c817a99 --- /dev/null +++ b/src/api/c/pie.cpp @@ -0,0 +1,142 @@ +/******************************************************* + * Copyright (c) 2015-2019, ArrayFire + * All rights reserved. + * + * This file is distributed under 3-clause BSD license. + * The complete license agreement can be obtained at: + * http://arrayfire.com/licenses/BSD-3-Clause + ********************************************************/ + +#include + +#include +#include + +using namespace forge; + +using forge::common::getPie; + +fg_err fg_create_pie(fg_pie* pPie, const unsigned pNSectors, + const fg_dtype pType) { + try { + ARG_ASSERT(1, (pNSectors > 0)); + + *pPie = getHandle(new common::Pie(pNSectors, (forge::dtype)pType)); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_retain_pie(fg_pie* pOut, fg_pie pIn) { + try { + ARG_ASSERT(1, (pIn != 0)); + + common::Pie* temp = new common::Pie(getPie(pIn)); + *pOut = getHandle(temp); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_release_pie(fg_pie pPie) { + try { + ARG_ASSERT(0, (pPie != 0)); + + delete getPie(pPie); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_pie_color(fg_pie pPie, const float pRed, const float pGreen, + const float pBlue, const float pAlpha) { + try { + ARG_ASSERT(0, (pPie != 0)); + + getPie(pPie)->setColor(pRed, pGreen, pBlue, pAlpha); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_pie_legend(fg_pie pPie, const char* pLegend) { + try { + ARG_ASSERT(0, (pPie != 0)); + ARG_ASSERT(1, (pLegend != 0)); + + getPie(pPie)->setLegend(pLegend); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_pie_vertex_buffer(unsigned* pOut, const fg_pie pPie) { + try { + ARG_ASSERT(1, (pPie != 0)); + + *pOut = getPie(pPie)->vbo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_pie_color_buffer(unsigned* pOut, const fg_pie pPie) { + try { + ARG_ASSERT(1, (pPie != 0)); + + *pOut = getPie(pPie)->cbo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_pie_alpha_buffer(unsigned* pOut, const fg_pie pPie) { + try { + ARG_ASSERT(1, (pPie != 0)); + + *pOut = getPie(pPie)->abo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_pie_vertex_buffer_size(unsigned* pOut, const fg_pie pPie) { + try { + ARG_ASSERT(1, (pPie != 0)); + + *pOut = (unsigned)getPie(pPie)->vboSize(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_pie_color_buffer_size(unsigned* pOut, const fg_pie pPie) { + try { + ARG_ASSERT(1, (pPie != 0)); + + *pOut = (unsigned)getPie(pPie)->cboSize(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_pie_alpha_buffer_size(unsigned* pOut, const fg_pie pPie) { + try { + ARG_ASSERT(1, (pPie != 0)); + + *pOut = (unsigned)getPie(pPie)->aboSize(); + } + CATCHALL + + return FG_ERR_NONE; +} diff --git a/src/api/cpp/CMakeLists.txt b/src/api/cpp/CMakeLists.txt index c0a6ba9a..d02c4a05 100644 --- a/src/api/cpp/CMakeLists.txt +++ b/src/api/cpp/CMakeLists.txt @@ -8,6 +8,7 @@ target_sources(forge_cpp_api_interface $ $ $ + $ $ $ $ diff --git a/src/api/cpp/chart.cpp b/src/api/cpp/chart.cpp index 615b2145..8a4e3c6f 100644 --- a/src/api/cpp/chart.cpp +++ b/src/api/cpp/chart.cpp @@ -68,6 +68,10 @@ void Chart::add(const Histogram& pHistogram) { FG_THROW(fg_append_histogram_to_chart(get(), pHistogram.get())); } +void Chart::add(const Pie& pPie) { + FG_THROW(fg_append_pie_to_chart(get(), pPie.get())); +} + void Chart::add(const Plot& pPlot) { FG_THROW(fg_append_plot_to_chart(get(), pPlot.get())); } @@ -88,6 +92,10 @@ void Chart::remove(const Histogram& pHistogram) { FG_THROW(fg_remove_histogram_from_chart(get(), pHistogram.get())); } +void Chart::remove(const Pie& pPie) { + FG_THROW(fg_remove_pie_from_chart(get(), pPie.get())); +} + void Chart::remove(const Plot& pPlot) { FG_THROW(fg_remove_plot_from_chart(get(), pPlot.get())); } @@ -116,6 +124,12 @@ Histogram Chart::histogram(const unsigned pNBins, const dtype pDataType) { return Histogram(temp); } +Pie Chart::pie(const unsigned pNSectors, const dtype pDataType) { + fg_pie temp = 0; + FG_THROW(fg_add_pie_to_chart(&temp, get(), pNSectors, (fg_dtype)pDataType)); + return Pie(temp); +} + Plot Chart::plot(const unsigned pNumPoints, const dtype pDataType, const PlotType pPlotType, const MarkerType pMarkerType) { fg_plot temp = 0; diff --git a/src/api/cpp/pie.cpp b/src/api/cpp/pie.cpp new file mode 100644 index 00000000..e0eb8397 --- /dev/null +++ b/src/api/cpp/pie.cpp @@ -0,0 +1,90 @@ +/******************************************************* + * Copyright (c) 2015-2019, ArrayFire + * All rights reserved. + * + * This file is distributed under 3-clause BSD license. + * The complete license agreement can be obtained at: + * http://arrayfire.com/licenses/BSD-3-Clause + ********************************************************/ + +#include + +#include + +#include + +namespace forge { +Pie::Pie(const unsigned pNSectors, const dtype pDataType) { + fg_pie temp = 0; + FG_THROW(fg_create_pie(&temp, pNSectors, (fg_dtype)pDataType)); + std::swap(mValue, temp); +} + +Pie::Pie(const Pie& pOther) { + fg_pie temp = 0; + + FG_THROW(fg_retain_pie(&temp, pOther.get())); + + std::swap(mValue, temp); +} + +Pie::Pie(const fg_pie pHandle) : mValue(pHandle) {} + +Pie::~Pie() { fg_release_pie(get()); } + +void Pie::setColor(const Color pColor) { + float r = (((int)pColor >> 24) & 0xFF) / 255.f; + float g = (((int)pColor >> 16) & 0xFF) / 255.f; + float b = (((int)pColor >> 8) & 0xFF) / 255.f; + float a = (((int)pColor) & 0xFF) / 255.f; + + FG_THROW(fg_set_pie_color(get(), r, g, b, a)); +} + +void Pie::setColor(const float pRed, const float pGreen, const float pBlue, + const float pAlpha) { + FG_THROW(fg_set_pie_color(get(), pRed, pGreen, pBlue, pAlpha)); +} + +void Pie::setLegend(const char* pLegend) { + FG_THROW(fg_set_pie_legend(get(), pLegend)); +} + +unsigned Pie::vertices() const { + unsigned temp = 0; + FG_THROW(fg_get_pie_vertex_buffer(&temp, get())); + return temp; +} + +unsigned Pie::colors() const { + unsigned temp = 0; + FG_THROW(fg_get_pie_color_buffer(&temp, get())); + return temp; +} + +unsigned Pie::alphas() const { + unsigned temp = 0; + FG_THROW(fg_get_pie_alpha_buffer(&temp, get())); + return temp; +} + +unsigned Pie::verticesSize() const { + unsigned temp = 0; + FG_THROW(fg_get_pie_vertex_buffer_size(&temp, get())); + return temp; +} + +unsigned Pie::colorsSize() const { + unsigned temp = 0; + FG_THROW(fg_get_pie_color_buffer_size(&temp, get())); + return temp; +} + +unsigned Pie::alphasSize() const { + unsigned temp = 0; + FG_THROW(fg_get_pie_alpha_buffer_size(&temp, get())); + return temp; +} + +fg_pie Pie::get() const { return mValue; } +} // namespace forge diff --git a/src/backend/common/chart_renderables.hpp b/src/backend/common/chart_renderables.hpp index c97b8c5b..e060ee7f 100644 --- a/src/backend/common/chart_renderables.hpp +++ b/src/backend/common/chart_renderables.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,17 @@ class Histogram : public ChartRenderableBase { reinterpret_cast(pOther)->impl()) {} }; +class Pie : public ChartRenderableBase { + public: + Pie(unsigned pNSectors, forge::dtype pDataType) + : ChartRenderableBase( + std::make_shared(pNSectors, pDataType)) {} + + Pie(const fg_pie pOther) + : ChartRenderableBase( + reinterpret_cast(pOther)->impl()) {} +}; + class Plot : public ChartRenderableBase { public: Plot(const unsigned pNumPoints, const forge::dtype pDataType, diff --git a/src/backend/common/handle.cpp b/src/backend/common/handle.cpp index eac1fbfa..49a07377 100644 --- a/src/backend/common/handle.cpp +++ b/src/backend/common/handle.cpp @@ -29,6 +29,8 @@ fg_histogram getHandle(Histogram* pValue) { fg_plot getHandle(Plot* pValue) { return reinterpret_cast(pValue); } +fg_pie getHandle(Pie* pValue) { return reinterpret_cast(pValue); } + fg_surface getHandle(Surface* pValue) { return reinterpret_cast(pValue); } @@ -57,6 +59,10 @@ Histogram* getHistogram(const fg_histogram& pValue) { return reinterpret_cast(pValue); } +Pie* getPie(const fg_pie& pValue) { + return reinterpret_cast(pValue); +} + Plot* getPlot(const fg_plot& pValue) { return reinterpret_cast(pValue); } diff --git a/src/backend/common/handle.hpp b/src/backend/common/handle.hpp index e88d2d5b..9d6ec576 100644 --- a/src/backend/common/handle.hpp +++ b/src/backend/common/handle.hpp @@ -29,6 +29,8 @@ fg_chart getHandle(Chart* pValue); fg_histogram getHandle(Histogram* pValue); +fg_pie getHandle(Pie* pValue); + fg_plot getHandle(Plot* pValue); fg_surface getHandle(Surface* pValue); @@ -45,6 +47,8 @@ Chart* getChart(const fg_chart& pValue); Histogram* getHistogram(const fg_histogram& pValue); +Pie* getPie(const fg_pie& pValue); + Plot* getPlot(const fg_plot& pValue); Surface* getSurface(const fg_surface& pValue); diff --git a/src/backend/glsl_shaders/pie_gs.glsl b/src/backend/glsl_shaders/pie_gs.glsl new file mode 100644 index 00000000..d6f80887 --- /dev/null +++ b/src/backend/glsl_shaders/pie_gs.glsl @@ -0,0 +1,42 @@ +#version 330 +layout(points) in; +layout(triangle_strip, max_vertices = 64) out; + +const float Pi = 3.1415926535; +const float radius = 0.75; +const int PointsOnCircle = 42; +const vec4 origin = vec4(0.0, 0.0, 0.0, 1.0); + +uniform mat4 viewMat; + +in VS_OUT { + vec4 color; + vec2 normRange; +} gs_in[]; + +out vec4 pervcol; + +void main() +{ + pervcol = gs_in[0].color; + + vec2 pos = gs_in[0].normRange; + float currAngle = 2 * Pi * pos.x; + int Points = max(int(PointsOnCircle * pos.y), 1); + float stepAngle = 2 * Pi * pos.y / Points; + + float midAngle = 2 * Pi * (pos.x + pos.y / 2); + vec4 center = vec4(origin.xy + 0.01 * vec2(cos(midAngle), sin(midAngle)), origin.zw); + + for (int i = 0; i <= Points; ++i) { + if ((i & 1) == 0) { + gl_Position = viewMat * center; + EmitVertex(); + } + + gl_Position = viewMat * vec4(center.xy + radius * vec2(cos(currAngle), sin(currAngle)), center.zw); + EmitVertex(); + currAngle += stepAngle; + } + EndPrimitive(); +} diff --git a/src/backend/glsl_shaders/pie_vs.glsl b/src/backend/glsl_shaders/pie_vs.glsl new file mode 100644 index 00000000..f7c29923 --- /dev/null +++ b/src/backend/glsl_shaders/pie_vs.glsl @@ -0,0 +1,18 @@ +#version 330 + +uniform float maxValue; + +in vec2 range; +in vec3 color; +in float alpha; + +out VS_OUT { + vec4 color; + vec2 normRange; +} vs_out; + +void main(void) +{ + vs_out.color = vec4(color, alpha); + vs_out.normRange = range / maxValue; +} diff --git a/src/backend/opengl/CMakeLists.txt b/src/backend/opengl/CMakeLists.txt index 828e8756..e7b3247d 100755 --- a/src/backend/opengl/CMakeLists.txt +++ b/src/backend/opengl/CMakeLists.txt @@ -20,6 +20,8 @@ target_sources(${BkndTargetName} ${CMAKE_CURRENT_SOURCE_DIR}/histogram_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/image_impl.hpp ${CMAKE_CURRENT_SOURCE_DIR}/image_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/pie_impl.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/pie_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/plot_impl.hpp ${CMAKE_CURRENT_SOURCE_DIR}/plot_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/shader_program.hpp diff --git a/src/backend/opengl/pie_impl.cpp b/src/backend/opengl/pie_impl.cpp new file mode 100644 index 00000000..88ad1fa1 --- /dev/null +++ b/src/backend/opengl/pie_impl.cpp @@ -0,0 +1,151 @@ +/******************************************************* + * Copyright (c) 2015-2019, ArrayFire + * All rights reserved. + * + * This file is distributed under 3-clause BSD license. + * The complete license agreement can be obtained at: + * http://arrayfire.com/licenses/BSD-3-Clause + ********************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +using namespace std; + +namespace forge { +namespace opengl { + +void pie_impl::bindResources(const int pWindowId) { + if (mVAOMap.find(pWindowId) == mVAOMap.end()) { + GLuint vao = 0; + /* create a vertex array object + * with appropriate bindings */ + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + // attach vertices + glEnableVertexAttribArray(mSectorRangeIndex); + glBindBuffer(GL_ARRAY_BUFFER, mVBO); + glVertexAttribPointer(mSectorRangeIndex, 2, dtype2gl(mDataType), + GL_FALSE, 0, 0); + // attach colors + glEnableVertexAttribArray(mSectorColorIndex); + glBindBuffer(GL_ARRAY_BUFFER, mCBO); + glVertexAttribPointer(mSectorColorIndex, 3, GL_FLOAT, GL_FALSE, 0, 0); + // attach alphas + glEnableVertexAttribArray(mSectorAlphaIndex); + glBindBuffer(GL_ARRAY_BUFFER, mABO); + glVertexAttribPointer(mSectorAlphaIndex, 1, GL_FLOAT, GL_FALSE, 0, 0); + glBindVertexArray(0); + /* store the vertex array object corresponding to + * the window instance in the map */ + mVAOMap[pWindowId] = vao; + } + + glBindVertexArray(mVAOMap[pWindowId]); +} + +void pie_impl::unbindResources() const { glBindVertexArray(0); } + +pie_impl::pie_impl(const uint32_t pNSectors, const forge::dtype pDataType) + : mNSectors(pNSectors) + , mDataType(pDataType) + , mSectorProgram(glsl::pie_vs.c_str(), glsl::histogram_fs.c_str(), + glsl::pie_gs.c_str()) + , mSectorRangeIndex(-1) + , mSectorColorIndex(-1) + , mSectorAlphaIndex(-1) + , mMaxValueIndex(-1) + , mSectorPVMatIndex(-1) + , mSectorPVCOnIndex(-1) + , mSectorPVAOnIndex(-1) { + CheckGL("Begin pie_impl::pie_impl"); + + setColor(0, 1, 0, 1); + + mVBOSize = 2 * mNSectors; + mCBOSize = 3 * mNSectors; + mABOSize = mNSectors; + + mSectorRangeIndex = mSectorProgram.getAttributeLocation("range"); + mSectorColorIndex = mSectorProgram.getAttributeLocation("color"); + mSectorAlphaIndex = mSectorProgram.getAttributeLocation("alpha"); + + mMaxValueIndex = mSectorProgram.getUniformLocation("maxValue"); + mSectorPVMatIndex = mSectorProgram.getUniformLocation("viewMat"); + + mSectorPVCOnIndex = mSectorProgram.getUniformLocation("isPVCOn"); + mSectorPVAOnIndex = mSectorProgram.getUniformLocation("isPVAOn"); + +#define PLOT_CREATE_BUFFERS(type) \ + mVBO = \ + createBuffer(GL_ARRAY_BUFFER, mVBOSize, NULL, GL_DYNAMIC_DRAW); \ + mCBO = \ + createBuffer(GL_ARRAY_BUFFER, mCBOSize, NULL, GL_DYNAMIC_DRAW); \ + mABO = \ + createBuffer(GL_ARRAY_BUFFER, mABOSize, NULL, GL_DYNAMIC_DRAW); \ + mVBOSize *= sizeof(type); \ + mCBOSize *= sizeof(float); \ + mABOSize *= sizeof(float); + + switch (dtype2gl(mDataType)) { + case GL_FLOAT: PLOT_CREATE_BUFFERS(float); break; + case GL_INT: PLOT_CREATE_BUFFERS(int); break; + case GL_UNSIGNED_INT: PLOT_CREATE_BUFFERS(uint32_t); break; + case GL_SHORT: PLOT_CREATE_BUFFERS(short); break; + case GL_UNSIGNED_SHORT: PLOT_CREATE_BUFFERS(uint16_t); break; + case GL_UNSIGNED_BYTE: PLOT_CREATE_BUFFERS(float); break; + default: TYPE_ERROR(1, mDataType); + } +#undef PLOT_CREATE_BUFFERS + CheckGL("End pie_impl::pie_impl"); +} + +pie_impl::~pie_impl() { + for (auto it = mVAOMap.begin(); it != mVAOMap.end(); ++it) { + GLuint vao = it->second; + glDeleteVertexArrays(1, &vao); + } +} + +void pie_impl::render(const int pWindowId, const int pX, const int pY, + const int pVPW, const int pVPH, const glm::mat4& pView, + const glm::mat4& pOrient) { + CheckGL("Begin pie_impl::render"); + if (mIsPVAOn) { + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + mSectorProgram.bind(); + + glUniformMatrix4fv(mSectorPVMatIndex, 1, GL_FALSE, glm::value_ptr(pView)); + glUniform1f(mMaxValueIndex, mRange[3]); + glUniform1i(mSectorPVCOnIndex, mIsPVCOn); + glUniform1i(mSectorPVAOnIndex, mIsPVAOn); + + pie_impl::bindResources(pWindowId); + glDrawArrays(GL_POINTS, 0, mNSectors); + pie_impl::unbindResources(); + + mSectorProgram.unbind(); + + if (mIsPVAOn) { + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + } + CheckGL("End pie_impl::render"); +} + +} // namespace opengl +} // namespace forge diff --git a/src/backend/opengl/pie_impl.hpp b/src/backend/opengl/pie_impl.hpp new file mode 100644 index 00000000..66896c39 --- /dev/null +++ b/src/backend/opengl/pie_impl.hpp @@ -0,0 +1,60 @@ +/******************************************************* + * Copyright (c) 2015-2019, ArrayFire + * All rights reserved. + * + * This file is distributed under 3-clause BSD license. + * The complete license agreement can be obtained at: + * http://arrayfire.com/licenses/BSD-3-Clause + ********************************************************/ + +#pragma once + +#include +#include +#include + +#include + +#include +#include + +namespace forge { +namespace opengl { + +class pie_impl : public AbstractRenderable { + protected: + /* plot points characteristics */ + forge::dtype mDataType; + uint32_t mNSectors; + /* OpenGL Objects */ + ShaderProgram mSectorProgram; + /* shader variable index locations */ + /* vertex shader */ + uint32_t mSectorRangeIndex; + uint32_t mSectorColorIndex; + uint32_t mSectorAlphaIndex; + uint32_t mMaxValueIndex; + /* geometry shader */ + uint32_t mSectorPVMatIndex; + /* fragment shader */ + uint32_t mSectorPVCOnIndex; + uint32_t mSectorPVAOnIndex; + + std::map mVAOMap; + + /* bind and unbind helper functions + * for rendering resources */ + void bindResources(const int pWindowId); + void unbindResources() const; + + public: + pie_impl(const uint32_t pNSectors, const forge::dtype pDataType); + ~pie_impl(); + + virtual void render(const int pWindowId, const int pX, const int pY, + const int pVPW, const int pVPH, const glm::mat4 &pView, + const glm::mat4 &pOrient); +}; + +} // namespace opengl +} // namespace forge