diff --git a/CMakeLists.txt b/CMakeLists.txt index 353bdf45..b1a8d529 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,8 @@ INCLUDE(${CMAKE_MODULE_PATH}/Version.cmake) FIND_PACKAGE(OpenGL REQUIRED) FIND_PACKAGE(GLEWmx REQUIRED) -IF(GLEWmx_FOUND AND OPENGL_FOUND) +FIND_PACKAGE(FreeImage REQUIRED) +IF(GLEWmx_FOUND AND OPENGL_FOUND AND FREEIMAGE_FOUND) ADD_DEFINITIONS(-DGLEW_MX) ELSE() IF(NOT GLEWmx_FOUND) @@ -62,12 +63,16 @@ ELSE() IF(NOT OPENGL_FOUND) MESSAGE(FATAL_ERROR "OpenGL not found") ENDIF() + IF(NOT FREEIMAGE_FOUND) + MESSAGE(FATAL_ERROR "FreeImage not found") + ENDIF() ENDIF() INCLUDE_DIRECTORIES( "${PROJECT_SOURCE_DIR}/include" ${OPENGL_INCLUDE_DIR} ${GLEW_INCLUDE_DIR} + ${FREEIMAGE_INCLUDE_PATH} ) SET(X11_LIBS "") @@ -77,7 +82,9 @@ IF(APPLE) SET(X11_LIBS ${X11_LIBRARIES}) ENDIF(APPLE) -ADD_SUBDIRECTORY(src) +ADD_EXECUTABLE(glsl2cpp "${CMAKE_MODULE_PATH}/glsl2cpp.cpp") + +ADD_SUBDIRECTORY(src/backend/opengl) IF(BUILD_EXAMPLES) ADD_SUBDIRECTORY(examples) diff --git a/CMakeModules/FindFreeImage.cmake b/CMakeModules/FindFreeImage.cmake new file mode 100644 index 00000000..627ffb39 --- /dev/null +++ b/CMakeModules/FindFreeImage.cmake @@ -0,0 +1,69 @@ +# +# Try to find the FreeImage library and include path. +# Once done this will define +# +# FREEIMAGE_FOUND +# FREEIMAGE_INCLUDE_PATH +# FREEIMAGE_LIBRARY +# FREEIMAGE_STATIC_LIBRARY +# FREEIMAGE_DYNAMIC_LIBRARY +# + +OPTION(USE_FREEIMAGE_STATIC "Use Static FreeImage Lib" OFF) + +FIND_PATH( FREEIMAGE_INCLUDE_PATH + NAMES FreeImage.h + HINTS ${PROJECT_SOURCE_DIR}/extern/FreeImage + PATHS + /usr/include + /usr/local/include + /sw/include + /opt/local/include + DOC "The directory where FreeImage.h resides") + +FIND_LIBRARY( FREEIMAGE_DYNAMIC_LIBRARY + NAMES FreeImage freeimage + HINTS ${PROJECT_SOURCE_DIR}/FreeImage + PATHS + /usr/lib64 + /usr/lib + /usr/local/lib64 + /usr/local/lib + /sw/lib + /opt/local/lib + DOC "The FreeImage library") + +SET(PX ${CMAKE_STATIC_LIBRARY_PREFIX}) +SET(SX ${CMAKE_STATIC_LIBRARY_SUFFIX}) +FIND_LIBRARY( FREEIMAGE_STATIC_LIBRARY + NAMES ${PX}FreeImageLIB${SX} ${PX}FreeImage${SX} ${PX}freeimage${SX} + HINTS ${PROJECT_SOURCE_DIR}/FreeImage + PATHS + /usr/lib64 + /usr/lib + /usr/local/lib64 + /usr/local/lib + /sw/lib + /opt/local/lib + DOC "The FreeImage library") +UNSET(PX) +UNSET(SX) + +IF(USE_FREEIMAGE_STATIC) + MESSAGE(STATUS "Using Static FreeImage Lib") + ADD_DEFINITIONS(-DFREEIMAGE_LIB) + SET(FREEIMAGE_LIBRARY ${FREEIMAGE_STATIC_LIBRARY}) +ELSE(USE_FREEIMAGE_STATIC) + MESSAGE(STATUS "Using Dynamic FreeImage Lib") + REMOVE_DEFINITIONS(-DFREEIMAGE_LIB) + SET(FREEIMAGE_LIBRARY ${FREEIMAGE_DYNAMIC_LIBRARY}) +ENDIF(USE_FREEIMAGE_STATIC) + +MARK_AS_ADVANCED( + FREEIMAGE_DYNAMIC_LIBRARY + FREEIMAGE_STATIC_LIBRARY + ) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(FREEIMAGE DEFAULT_MSG FREEIMAGE_INCLUDE_PATH FREEIMAGE_LIBRARY) diff --git a/CMakeModules/GLSLtoH.cmake b/CMakeModules/GLSLtoH.cmake new file mode 100644 index 00000000..48bf1069 --- /dev/null +++ b/CMakeModules/GLSLtoH.cmake @@ -0,0 +1,61 @@ +# Function to turn an GLSL shader source file into a C string within a source file. +# xxd uses its input's filename to name the string and its length, so we +# need to move them to a name that depends only on the path output, not its +# input. Otherwise, builds in different relative locations would put the +# source into different variable names, and everything would fall over. +# The actual name will be filename (.s replaced with underscores), and length +# name_len. +# +# Usage example: +# +# set(KERNELS a.cl b/c.cl) +# resource_to_cxx_source( +# SOURCES ${KERNELS} +# VARNAME OUTPUTS +# ) +# add_executable(foo ${OUTPUTS}) +# +# The namespace they are placed in is taken from filename.namespace. +# +# For example, if the input file is kernel.cl, the two variables will be +# unsigned char ns::kernel_cl[]; +# unsigned int ns::kernel_cl_len; +# +# where ns is the contents of kernel.cl.namespace. + +INCLUDE(CMakeParseArguments) + +SET(GLSL2CPP_PROGRAM "glsl2cpp") + +FUNCTION(GLSL_TO_H) + CMAKE_PARSE_ARGUMENTS(RTCS "" "VARNAME;EXTENSION;OUTPUT_DIR;TARGETS;NAMESPACE;EOF" "SOURCES" ${ARGN}) + + SET(_output_files "") + FOREACH(_input_file ${RTCS_SOURCES}) + GET_FILENAME_COMPONENT(_path "${_input_file}" PATH) + GET_FILENAME_COMPONENT(_name "${_input_file}" NAME) + GET_FILENAME_COMPONENT(var_name "${_input_file}" NAME_WE) + + SET(_namespace "${RTCS_NAMESPACE}") + STRING(REPLACE "." "_" var_name ${var_name}) + + SET(_output_path "${CMAKE_CURRENT_BINARY_DIR}/${RTCS_OUTPUT_DIR}") + SET(_output_file "${_output_path}/${var_name}.${RTCS_EXTENSION}") + + ADD_CUSTOM_COMMAND( + OUTPUT ${_output_file} + DEPENDS ${_input_file} ${GLSL2CPP_PROGRAM} + COMMAND ${CMAKE_COMMAND} -E make_directory "${_output_path}" + COMMAND ${CMAKE_COMMAND} -E echo "\\#include \\<${_path}/${var_name}.hpp\\>" >>"${_output_file}" + COMMAND ${GLSL2CPP_PROGRAM} --file ${_name} --namespace ${_namespace} --output ${_output_file} --name ${var_name} --eof ${RTCS_EOF} + WORKING_DIRECTORY "${_path}" + COMMENT "Converting ${_input_file} to GLSL source string" + ) + + LIST(APPEND _output_files ${_output_file}) + ENDFOREACH() + ADD_CUSTOM_TARGET(${RTCS_NAMESPACE}_bin_target DEPENDS ${_output_files}) + + SET("${RTCS_VARNAME}" ${_output_files} PARENT_SCOPE) + SET("${RTCS_TARGETS}" ${RTCS_NAMESPACE}_bin_target PARENT_SCOPE) +ENDFUNCTION(GLSL_TO_H) diff --git a/CMakeModules/glsl2cpp.cpp b/CMakeModules/glsl2cpp.cpp new file mode 100644 index 00000000..e50e2540 --- /dev/null +++ b/CMakeModules/glsl2cpp.cpp @@ -0,0 +1,184 @@ +// Umar Arshad +// Copyright 2015-2019 +// +// Modified by Pradeep Garigipati on Dec 30, 2015 for Forge +// Purpose of modification: To use the program to convert +// GLSL shader files into compile time constant string literals + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +typedef map opt_t; + +static +void print_usage() { + cout << R"delimiter(GLSL2CPP +Converts OpenGL shader files to C++ headers. It is similar to bin2c and xxd but adds +support for namespaces. + +| --name | name of the variable (default: var) | +| --file | input file | +| --output | output file (If no output is specified then it prints to stdout) | +| --type | Type of variable (default: char) | +| --namespace | A space seperated list of namespaces | +| --formatted | Tabs for formatting | +| --version | Prints my name | +| --help | Prints usage info | + +Example +------- +Command: +./glsl2cpp --file blah.txt --namespace shaders --formatted --name image_vs + +Will produce the following: +#pragma once +#include +namespace shaders { + static const char image_vs[] = R"shader( +#version 330 + +layout(location = 0) in vec3 pos; +layout(location = 1) in vec2 tex; + +uniform mat4 matrix; + +out vec2 texcoord; + +void main() { + texcoord = tex; + gl_Position = matrix * vec4(pos,1.0); +} + )shader"; +} +)delimiter"; + exit(0); +} + +static bool formatted; + +static +void add_tabs(const int level) +{ + if(formatted) { + for(int i =0; i < level; i++) { + cout << "\t"; + } + } +} + +static +opt_t parse_options(const vector& args) +{ + opt_t options; + + options["--name"] = ""; + options["--type"] = ""; + options["--file"] = ""; + options["--output"] = ""; + options["--namespace"] = ""; + options["--eof"] = ""; + + //Parse Arguments + string curr_opt; + bool verbose = false; + for(auto arg : args) { + if(arg == "--verbose") { + verbose = true; + } else if(arg == "--formatted") { + formatted = true; + } else if(arg == "--version") { + cout << args[0] << " Original Author: Umar Arshad;\n Modified later by: Pradeep Garigipati." << endl; + } else if(arg == "--help") { + print_usage(); + } else if(options.find(arg) != options.end()) { + curr_opt = arg; + } else if(curr_opt.empty()) { + //cerr << "Invalid Argument: " << arg << endl; + } else { + if(options[curr_opt] != "") { + options[curr_opt] += " " + arg; + } + else { + options[curr_opt] += arg; + } + } + } + + if(verbose) { + for(auto opts : options) { + cout << get<0>(opts) << " " << get<1>(opts) << endl; + } + } + return options; +} + +int main(int argc, const char * const * const argv) +{ + + vector args(argv, argv+argc); + + opt_t&& options = parse_options(args); + + //Save default cout buffer. Need this to prevent crash. + auto bak = cout.rdbuf(); + unique_ptr outfile; + + // Set defaults + if(options["--name"] == "") { options["--name"] = "var"; } + if(options["--output"] != "") { + //redirect stream if output file is specified + outfile.reset(new ofstream(options["--output"])); + cout.rdbuf(outfile->rdbuf()); + } + + cout << "#pragma once\n"; + cout << "#include \n"; // defines std::string + + int ns_cnt = 0; + int level = 0; + if(options["--namespace"] != "") { + std::stringstream namespaces(options["--namespace"]); + string name; + namespaces >> name; + do { + add_tabs(level++); + cout << "namespace " << name << "\n{\n"; + ns_cnt++; + namespaces >> name; + } while(!namespaces.fail()); + } + + if(options["--type"] == "") { + options["--type"] = "std::string"; + } + add_tabs(level); + cout << "static const " << options["--type"] << " " << options["--name"] << " = R\"shader(\n"; + level++; + + ifstream input(options["--file"]); + + for(std::string line; std::getline(input, line);) { + add_tabs(level); + cout << line << endl; + } + + if (options["--eof"].c_str()[0] == '1') { + // Add end of file character + cout << "0x0"; + } + + add_tabs(--level); + cout << ")shader\";\n"; + + while(ns_cnt--) { + add_tabs(--level); + cout << "}\n"; + } + cout.rdbuf(bak); +} diff --git a/README.md b/README.md index 0b1de898..2ced05ae 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,10 @@ A prototype of the OpenGL interop library that can be used with ArrayFire. The g * On `Linux` and `OS X`, [fontconfig](http://www.freedesktop.org/wiki/Software/fontconfig/) is required. Above dependencies are available through package managers on most of the Unix/Linux based distributions. We have provided an option in `CMake` for `Forge` to build it's own internal `freetype` version if you choose to not install it on your machine. + +### Sample Images +| | | +|-----|-----| +| Image | 2D Plot | +| 3d Plot | Rotated 3d Plot | +| histogram | Surface | diff --git a/docs/images/bubble.png b/docs/images/bubble.png new file mode 100644 index 00000000..33d5d4ec Binary files /dev/null and b/docs/images/bubble.png differ diff --git a/docs/images/hist.png b/docs/images/hist.png new file mode 100644 index 00000000..040bc5f0 Binary files /dev/null and b/docs/images/hist.png differ diff --git a/docs/images/image.png b/docs/images/image.png new file mode 100644 index 00000000..cc74f7d9 Binary files /dev/null and b/docs/images/image.png differ diff --git a/docs/images/plot.png b/docs/images/plot.png new file mode 100644 index 00000000..f239e7eb Binary files /dev/null and b/docs/images/plot.png differ diff --git a/docs/images/plot31.png b/docs/images/plot31.png new file mode 100644 index 00000000..df7ee266 Binary files /dev/null and b/docs/images/plot31.png differ diff --git a/docs/images/plot32.png b/docs/images/plot32.png new file mode 100644 index 00000000..27c5c3a2 Binary files /dev/null and b/docs/images/plot32.png differ diff --git a/docs/images/surface.png b/docs/images/surface.png new file mode 100644 index 00000000..5d1cd774 Binary files /dev/null and b/docs/images/surface.png differ diff --git a/docs/pages/README.md b/docs/pages/README.md index dea7801f..c02c27a1 100644 --- a/docs/pages/README.md +++ b/docs/pages/README.md @@ -22,10 +22,12 @@ install it on your machine. We plan to provide support for alternatives to GLFW as windowing toolkit, however GLFW is the default option. Should you chose to use an alternative, you -have to chose it explicity. +have to chose it explicity while building forge. -Alternatives to GLFW which are currently under consideration are given below: +Currently supported alternatives: * [SDL2](https://www.libsdl.org/download-2.0.php) + +Alternatives to GLFW which are currently under consideration are given below: * [Qt5](https://wiki.qt.io/Qt_5) #### Email diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 1dc90748..6f28b6f2 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -3,6 +3,9 @@ PROJECT(Forge-Examples) SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeModules") +OPTION(BUILD_EXAMPLES_CUDA "Turn off/on building cuda examples" ON) +OPTION(BUILD_EXAMPLES_OPENCL "Turn off/on building opencl examples" ON) + MACRO(BUILD_EXAMPLE EX_NAME EX_SRC COMPUTE_NAME FG_LIBS COMPUTE_LIBS) IF(${COMPUTE_NAME} STREQUAL "cuda") CUDA_ADD_EXECUTABLE(example_${EX_NAME}_${COMPUTE_NAME} ${EX_SRC}) @@ -23,7 +26,7 @@ IF(TARGET forge) ELSE(TARGET forge) SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) FIND_PACKAGE(GLEWmx REQUIRED) - + FIND_PACKAGE(FreeImage REQUIRED) FIND_PACKAGE(OpenGL REQUIRED) FIND_PACKAGE(Forge REQUIRED) SET(X11_LIBS "") @@ -35,6 +38,7 @@ ELSE(TARGET forge) ${FORGE_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR} ${GLEW_INCLUDE_DIR} + ${FREEIMAGE_INCLUDE_PATH} ) ADD_DEFINITIONS(-DGLEW_MX) IF(UNIX) @@ -71,58 +75,64 @@ FOREACH(FILE ${CPU_EXAMPLE_SRC_FILES}) IF(TARGET forge) BUILD_EXAMPLE(${EXAMPLE} ${FILE} ${DIR_NAME} forge - "${GLEWmx_LIBRARY};${OPENGL_gl_LIBRARY}") + "${FREEIMAGE_LIBRARY};${GLEWmx_LIBRARY};${OPENGL_gl_LIBRARY}") ELSE(TARGET forge) BUILD_EXAMPLE(${EXAMPLE} ${FILE} ${DIR_NAME} ${FORGE_LIBRARIES} - "${GLEWmx_LIBRARY};${OPENGL_gl_LIBRARY};${X11_LIBS};") + "${FREEIMAGE_LIBRARY};${GLEWmx_LIBRARY};${OPENGL_gl_LIBRARY};${X11_LIBS};") ENDIF() ENDFOREACH() -FIND_PACKAGE(CUDA QUIET) -IF(CUDA_FOUND) - INCLUDE_DIRECTORIES(${CUDA_INCLUDE_DIRS}) +IF (BUILD_EXAMPLES_CUDA) + FIND_PACKAGE(CUDA QUIET) + IF(CUDA_FOUND) + INCLUDE_DIRECTORIES(${CUDA_INCLUDE_DIRS}) - FILE(GLOB CUDA_EXAMPLE_SRC_FILES "cuda/*.cu") - FOREACH(FILE ${CUDA_EXAMPLE_SRC_FILES}) - GET_FILENAME_COMPONENT(EXAMPLE ${FILE} NAME_WE) - GET_FILENAME_COMPONENT(FULL_DIR_NAME ${FILE} PATH) - GET_FILENAME_COMPONENT(DIR_NAME ${FULL_DIR_NAME} NAME) + FILE(GLOB CUDA_EXAMPLE_SRC_FILES "cuda/*.cu") + FOREACH(FILE ${CUDA_EXAMPLE_SRC_FILES}) + GET_FILENAME_COMPONENT(EXAMPLE ${FILE} NAME_WE) + GET_FILENAME_COMPONENT(FULL_DIR_NAME ${FILE} PATH) + GET_FILENAME_COMPONENT(DIR_NAME ${FULL_DIR_NAME} NAME) - IF(TARGET forge) - BUILD_EXAMPLE(${EXAMPLE} ${FILE} ${DIR_NAME} forge - "${CUDA_CUDA_LIBRARY};${CUDA_LIBRARIES}") - ELSE(TARGET forge) - BUILD_EXAMPLE(${EXAMPLE} ${FILE} ${DIR_NAME} ${FORGE_LIBRARIES} - "${GLEWmx_LIBRARY};${OPENGL_gl_LIBRARY};${X11_LIBS};${CUDA_CUDA_LIBRARY};${CUDA_LIBRARIES}") - ENDIF() - ENDFOREACH() -ELSE() - MESSAGE(STATUS "CUDA Toolkit not found, not building CUDA examples.") -ENDIF() - -FIND_PACKAGE(OpenCL QUIET) -IF(OpenCL_FOUND) - IF(UNIX) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations -Wno-unused-function") + IF(TARGET forge) + BUILD_EXAMPLE(${EXAMPLE} ${FILE} ${DIR_NAME} forge + "${FREEIMAGE_LIBRARY};${CUDA_CUDA_LIBRARY};${CUDA_LIBRARIES}") + ELSE(TARGET forge) + BUILD_EXAMPLE(${EXAMPLE} ${FILE} ${DIR_NAME} ${FORGE_LIBRARIES} + "${FREEIMAGE_LIBRARY};${GLEWmx_LIBRARY};${OPENGL_gl_LIBRARY};${X11_LIBS};${CUDA_CUDA_LIBRARY};${CUDA_LIBRARIES}") + ENDIF() + ENDFOREACH() + ELSE() + MESSAGE(STATUS "CUDA Toolkit not found, not building CUDA examples.") ENDIF() - FILE(GLOB OpenCL_EXAMPLE_SRC_FILES "opencl/*.cpp") - INCLUDE_DIRECTORIES( - "${CMAKE_CURRENT_SOURCE_DIR}/opencl" - ${OpenCL_INCLUDE_DIRS} - ) - FOREACH(FILE ${OpenCL_EXAMPLE_SRC_FILES}) - GET_FILENAME_COMPONENT(EXAMPLE ${FILE} NAME_WE) - GET_FILENAME_COMPONENT(FULL_DIR_NAME ${FILE} PATH) - GET_FILENAME_COMPONENT(DIR_NAME ${FULL_DIR_NAME} NAME) +ENDIF() - IF(TARGET forge) - BUILD_EXAMPLE(${EXAMPLE} ${FILE} ${DIR_NAME} forge - "${GLEWmx_LIBRARY};${OPENGL_gl_LIBRARY};${OpenCL_LIBRARIES}") - ELSE(TARGET forge) - BUILD_EXAMPLE(${EXAMPLE} ${FILE} ${DIR_NAME} ${FORGE_LIBRARIES} - "${GLEWmx_LIBRARY};${OPENGL_gl_LIBRARY};${X11_LIBS};${OpenCL_LIBRARIES}") +IF (BUILD_EXAMPLES_OPENCL) + FIND_PACKAGE(OpenCL QUIET) + IF(OpenCL_FOUND) + IF(UNIX) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations -Wno-unused-function") ENDIF() - ENDFOREACH() -ELSE() - MESSAGE(STATUS "OpenCL Libraries not found, not building OpenCL examples.") + FILE(GLOB OpenCL_EXAMPLE_SRC_FILES "opencl/*.cpp") + INCLUDE_DIRECTORIES( + "${CMAKE_CURRENT_SOURCE_DIR}/opencl" + ${OpenCL_INCLUDE_DIRS} + ) + FOREACH(FILE ${OpenCL_EXAMPLE_SRC_FILES}) + GET_FILENAME_COMPONENT(EXAMPLE ${FILE} NAME_WE) + GET_FILENAME_COMPONENT(FULL_DIR_NAME ${FILE} PATH) + GET_FILENAME_COMPONENT(DIR_NAME ${FULL_DIR_NAME} NAME) + + IF(TARGET forge) + BUILD_EXAMPLE(${EXAMPLE} ${FILE} ${DIR_NAME} forge + "${FREEIMAGE_LIBRARY};${GLEWmx_LIBRARY};${OPENGL_gl_LIBRARY};${OpenCL_LIBRARIES}") + ELSE(TARGET forge) + BUILD_EXAMPLE(${EXAMPLE} ${FILE} ${DIR_NAME} ${FORGE_LIBRARIES} + "${FREEIMAGE_LIBRARY};${GLEWmx_LIBRARY};${OPENGL_gl_LIBRARY};${X11_LIBS};${OpenCL_LIBRARIES}") + ENDIF() + ENDFOREACH() + ELSE() + MESSAGE(STATUS "OpenCL Libraries not found, not building OpenCL examples.") + ENDIF() ENDIF() + +MARK_AS_ADVANCED(BUILD_EXAMPLES_CUDA BUILD_EXAMPLES_OPENCL) diff --git a/examples/cpu/bubblechart.cpp b/examples/cpu/bubblechart.cpp new file mode 100644 index 00000000..56d27011 --- /dev/null +++ b/examples/cpu/bubblechart.cpp @@ -0,0 +1,116 @@ +/******************************************************* + * 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 +#include + +const unsigned DIMX = 1000; +const unsigned DIMY = 800; + +const float FRANGE_START = 0.f; +const float FRANGE_END = 2.f * 3.1415926f; + +using namespace std; +void map_range_to_vec_vbo(float range_start, float range_end, float dx, + std::vector &vec, + float (*map) (float)) +{ + if(range_start > range_end && dx > 0) return; + for(float i=range_start; i < range_end; i+=dx){ + vec.push_back(i); + vec.push_back((*map)(i)); + } +} + +int main(void) +{ + std::vector cosData; + std::vector tanData; + + map_range_to_vec_vbo(FRANGE_START, FRANGE_END, 0.1f, cosData, &cosf); + map_range_to_vec_vbo(FRANGE_START, FRANGE_END, 0.1f, tanData, &tanf); + + std::random_device r; + + std::default_random_engine e1(r()); + std::mt19937_64 gen(r()); + + std::uniform_int_distribution uDist(20, 80); + std::uniform_real_distribution cDist(0.2, 0.6); + std::uniform_real_distribution fDist(0.4, 0.6); + + auto clr = std::bind(cDist, gen); + auto rnd = std::bind(uDist, e1); + auto alp = std::bind(fDist, gen); + + std::vector colors(3*tanData.size()); + std::vector alphas(tanData.size()); + std::vector radii(tanData.size()); + + std::generate(colors.begin(), colors.end(), clr); + std::generate(radii.begin(), radii.end(), rnd); + std::generate(alphas.begin(), alphas.end(), alp); + + /* + * First Forge call should be a window creation call + * so that necessary OpenGL context is created for any + * other fg::* object to be created successfully + */ + fg::Window wnd(DIMX, DIMY, "Bubble chart with Transparency Demo"); + wnd.makeCurrent(); + + fg::Chart chart(FG_CHART_2D); + chart.setAxesLimits(FRANGE_START, FRANGE_END, -1.1f, 1.1f); + + /* Create several plot objects which creates the necessary + * vertex buffer objects to hold the different plot types + */ + fg::Plot plt1 = chart.plot(cosData.size()/2, fg::f32, + FG_PLOT_LINE, FG_MARKER_TRIANGLE); //or specify a specific plot type + fg::Plot plt2 = chart.plot(tanData.size()/2, fg::f32, + FG_PLOT_LINE, FG_MARKER_CIRCLE); //last parameter specifies marker shape + + /* Set plot colors */ + plt1.setColor(FG_RED); + plt2.setColor(FG_GREEN); //use a forge predefined color + /* Set plot legends */ + plt1.setLegend("Cosine"); + plt2.setLegend("Tangent"); + /* set plot global marker size */ + plt1.setMarkerSize(20); + /* copy your data into the opengl buffer object exposed by + * fg::Plot class and then proceed to rendering. + * To help the users with copying the data from compute + * memory to display memory, Forge provides copy headers + * along with the library to help with this task + */ + fg::copy(plt1.vertices(), plt1.verticesSize(), (const void*)cosData.data()); + fg::copy(plt2.vertices(), plt2.verticesSize(), (const void*)tanData.data()); + + /* update color value for tan graph */ + fg::copy(plt2.colors(), plt2.colorsSize(), (const void*)colors.data()); + /* update alpha values for tan graph */ + fg::copy(plt2.alphas(), plt2.alphasSize(), (const void*)alphas.data()); + /* update marker sizes for tan graph markers */ + fg::copy(plt2.markers(), plt2.markersSize(), (const void*)radii.data()); + + do { + wnd.draw(chart); + } while(!wnd.close()); + + return 0; +} diff --git a/examples/cpu/fractal.cpp b/examples/cpu/fractal.cpp index 935ad617..6e076531 100644 --- a/examples/cpu/fractal.cpp +++ b/examples/cpu/fractal.cpp @@ -37,21 +37,25 @@ int main(void) */ fg::Window wnd(DIMX, DIMY, "Fractal Demo"); wnd.makeCurrent(); + /* create an font object and load necessary font * and later pass it on to window object so that - * it can be used for rendering text */ + * it can be used for rendering text + * + * NOTE: THIS IS OPTIONAL STEP, BY DEFAULT WINDOW WILL + * HAVE FONT ALREADY SETUP*/ fg::Font fnt; #ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); + fnt.loadSystemFont("Calibri"); #else - fnt.loadSystemFont("Vera", 32); + fnt.loadSystemFont("Vera"); #endif wnd.setFont(&fnt); /* Create an image object which creates the necessary * textures and pixel buffer objects to hold the image * */ - fg::Image img(DIMX, DIMY, fg::FG_RGBA, fg::u8); + fg::Image img(DIMX, DIMY, FG_RGBA, fg::u8); /* copy your data into the pixel buffer object exposed by * fg::Image class and then proceed to rendering. * To help the users with copying the data from compute @@ -59,7 +63,7 @@ int main(void) * along with the library to help with this task */ kernel(bmp); - fg::copy(img, bmp.ptr); + fg::copy(img, (const void*)bmp.ptr); do { wnd.draw(img); diff --git a/examples/cpu/histogram.cpp b/examples/cpu/histogram.cpp index aef9f7e1..b6b2b52d 100644 --- a/examples/cpu/histogram.cpp +++ b/examples/cpu/histogram.cpp @@ -12,17 +12,17 @@ #include #include #include +#include #include #include -const unsigned DIMX = 1000; -const unsigned DIMY = 800; -const unsigned WIN_ROWS = 1; -const unsigned WIN_COLS = 2; - -const unsigned NBINS = 5; - -static float t=0.1; +const unsigned IMGW = 256; +const unsigned IMGH = 256; +const unsigned DIMX = 1000; +const unsigned DIMY = 800; +const unsigned WIN_ROWS = 1; +const unsigned WIN_COLS = 2; +const unsigned NBINS = 256; using namespace std; @@ -31,18 +31,28 @@ struct Bitmap { unsigned width; unsigned height; }; + +class PerlinNoise +{ + private: + float base[IMGW][IMGH]; + float perlin[IMGW][IMGH]; + public: + PerlinNoise(); + float noise(float u, float v); +}; + Bitmap createBitmap(unsigned w, unsigned h); -void destroyBitmap(Bitmap& bmp); -void kernel(Bitmap& bmp); -void hist_freq(Bitmap& bmp, int *hist_array, const unsigned nbins); -float perlinNoise(float x, float y, float z, int tileSize); -float octavesPerlin(float x, float y, float z, int octaves, float persistence, int tileSize); +void destroyBitmap(Bitmap& bmp); -int main(void) { +void kernel(Bitmap& bmp); - Bitmap bmp = createBitmap(DIMX, DIMY); +void populateBins(Bitmap& bmp, int *hist_array, const unsigned nbins, float *hist_cols); +int main(void) +{ + Bitmap bmp = createBitmap(IMGW, IMGH); /* * First Forge call should be a window creation call * so that necessary OpenGL context is created for any @@ -50,73 +60,119 @@ int main(void) { */ fg::Window wnd(DIMX, DIMY, "Histogram Demo"); wnd.makeCurrent(); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); /* * Split the window into grid regions */ wnd.grid(WIN_ROWS, WIN_COLS); - fg::Image img(DIMX, DIMY, fg::FG_RGBA, fg::u8); - /* - * Create histogram object while specifying desired number of bins - */ - fg::Histogram hist(NBINS, fg::u8); + fg::Image img(IMGW, IMGH, FG_RGBA, fg::u8); - /* - * Set histogram colors - */ - hist.setBarColor(fg::FG_YELLOW); + fg::Chart chart(FG_CHART_2D); + /* set x axis limits to maximum and minimum values of data + * and y axis limits to range [0, number of pixels ideally] + * but practically total number of pixels as y range will skew + * the histogram graph vertically. Therefore setting it to + * 25% of total number of pixels */ + chart.setAxesLimits(0, 1, 0, IMGW*IMGH/(float)(NBINS/4.0)); /* - * generate image, and prepare data to pass into - * Histogram's underlying vertex buffer object + * Create histogram object specifying number of bins */ - kernel(bmp); - fg::copy(img, bmp.ptr); - - /* set x axis limits to maximum and minimum values of data - * and y axis limits to range [0, nBins]*/ - hist.setAxesLimits(1, 0, 1000, 0); - - /* copy your data into the vertex buffer object exposed by - * fg::Histogram class and then proceed to rendering. - * To help the users with copying the data from compute - * memory to display memory, Forge provides copy headers - * along with the library to help with this task + fg::Histogram hist = chart.histogram(NBINS, fg::s32); + /* + * Set histogram colors */ - int histogram_array[NBINS] = {0}; - hist_freq(bmp, &histogram_array[0], NBINS); - fg::copy(hist, histogram_array); + hist.setColor(FG_YELLOW); do { + /* + * generate image, and prepare data to pass into + * Histogram's underlying vertex buffer object + */ kernel(bmp); - fg::copy(img, bmp.ptr); + fg::copy(img, (const void*)bmp.ptr); - int histogram_array[NBINS] = {0}; - hist_freq(bmp, &histogram_array[0], NBINS); - // limit histogram update frequency - if(fmod(t,0.4f) < 0.02f) - fg::copy(hist, histogram_array); + /* copy your data into the vertex buffer object exposed by + * fg::Histogram class and then proceed to rendering. + * To help the users with copying the data from compute + * memory to display memory, Forge provides copy headers + * along with the library to help with this task + */ + std::vector histArray(NBINS, 0); + std::vector colArray(3*NBINS, 0.0f); + populateBins(bmp, histArray.data(), NBINS, colArray.data()); + + fg::copy(hist.vertices(), hist.verticesSize(), (const void*)histArray.data()); + fg::copy(hist.colors(), hist.colorsSize(), (const void*)colArray.data()); wnd.draw(0, 0, img, "Dynamic Perlin Noise" ); - wnd.draw(1, 0, hist, "Histogram of Noisy Image"); - // draw window and poll for events last + wnd.draw(1, 0, chart, "Histogram of Noisy Image"); + wnd.swapBuffers(); } while(!wnd.close()); return 0; } +float interp(float x0, float x1, float alpha) +{ + return x0 * (1 - alpha) + alpha * x1; +} + +PerlinNoise::PerlinNoise() +{ + std::srand(std::time(0)); + + for(uint i=0; i < IMGW; i++) + { + for(uint j=0; j < IMGH; j++) + { + base[i][j] = std::rand()/(float)(RAND_MAX); + perlin[i][j] = 0; + } + } + + float persistence = 0.5f; + float amp = 1.0f; + float tamp = 0.0f; + + for (int octave=6; octave>=0; --octave) + { + int period = 1 << octave; + float freq = 1.0f / period; + + for(uint i=0; i < IMGW; i++) + { + int si0 = (i/period) * period; + int si1 = (si0 + period) % IMGW; + float hblend = (i - si0) * freq; + + for(uint j=0; j < IMGH; j++) + { + int sj0 = (j/period) * period; + int sj1 = (sj0 + period) % IMGH; + float vblend = (j - sj0) * freq; + + float top = interp(base[si0][sj0], base[si1][sj0], hblend); + float bot = interp(base[si0][sj1], base[si1][sj1], hblend); + + perlin[i][j] += (amp * interp(top, bot, vblend)); + } + } + tamp += amp; + amp *= persistence; + } + + for(uint i=0; i < IMGW; i++) + for(uint j=0; j < IMGH; j++) + perlin[i][j] /= tamp; +} + +float PerlinNoise::noise(float u, float v) +{ + return perlin[(unsigned)(IMGW*u)][(unsigned)(IMGH*v)]; +} Bitmap createBitmap(unsigned w, unsigned h) { @@ -132,102 +188,40 @@ void destroyBitmap(Bitmap& bmp) delete[] bmp.ptr; } -void kernel(Bitmap& bmp) { - static unsigned tileSize=100; +void kernel(Bitmap& bmp) +{ + PerlinNoise perlin; + for (unsigned y=0; y &vec ) { + +void gen_curve(float t, float dx, std::vector &vec ) +{ vec.clear(); for(float z=ZMIN; z < ZMAX; z+=dx){ vec.push_back(cos(z*t+t)/z); @@ -33,7 +35,8 @@ void gen_curve(float t, float dx, std::vector &vec ) { } } -int main(void){ +int main(void) +{ /* * First Forge call should be a window creation call * so that necessary OpenGL context is created for any @@ -41,31 +44,12 @@ int main(void){ */ fg::Window wnd(DIMX, DIMY, "Plot3d Demo"); wnd.makeCurrent(); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); - - /* Create several plot objects which creates the necessary - * vertex buffer objects to hold the different plot types - */ - fg::Plot3 plot3(ZSIZE, fg::f32); - /* - * Set draw limits for plots - */ - plot3.setAxesLimits(1.1f, -1.1f, 1.1f, -1.1f, 10.f, 0.f); + fg::Chart chart(FG_CHART_3D); + chart.setAxesLimits(-1.1f, 1.1f, -1.1f, 1.1f, 0.f, 10.f); + chart.setAxesTitles("x-axis", "y-axis", "z-axis"); - /* - * Set axis titles - */ - plot3.setAxesTitles("x-axis", "y-axis", "z-axis"); + fg::Plot plot3 = chart.plot(ZSIZE, fg::f32); //generate a surface std::vector function; @@ -77,14 +61,13 @@ int main(void){ * memory to display memory, Forge provides copy headers * along with the library to help with this task */ - copy(plot3, &function[0]); + fg::copy(plot3.vertices(), plot3.verticesSize(), (const void*)function.data()); do { t+=0.01; gen_curve(t, DX, function); - copy(plot3, &function[0]); - // draw window and poll for events last - wnd.draw(plot3); + fg::copy(plot3.vertices(), plot3.verticesSize(), (const void*)function.data()); + wnd.draw(chart); } while(!wnd.close()); return 0; diff --git a/examples/cpu/plotting.cpp b/examples/cpu/plotting.cpp index cbc7daee..e331f048 100644 --- a/examples/cpu/plotting.cpp +++ b/examples/cpu/plotting.cpp @@ -16,14 +16,15 @@ const unsigned DIMX = 1000; const unsigned DIMY = 800; -const unsigned WIN_ROWS = 2; -const unsigned WIN_COLS = 2; const float FRANGE_START = 0.f; const float FRANGE_END = 2.f * 3.1415926f; using namespace std; -void map_range_to_vec_vbo(float range_start, float range_end, float dx, std::vector &vec, float (*map) (float)){ +void map_range_to_vec_vbo(float range_start, float range_end, float dx, + std::vector &vec, + float (*map) (float)) +{ if(range_start > range_end && dx > 0) return; for(float i=range_start; i < range_end; i+=dx){ vec.push_back(i); @@ -31,9 +32,16 @@ void map_range_to_vec_vbo(float range_start, float range_end, float dx, std::vec } } -int main(void){ - std::vector function; - map_range_to_vec_vbo(FRANGE_START, FRANGE_END, 0.1f, function, &sinf); +int main(void) +{ + std::vector sinData; + std::vector cosData; + std::vector tanData; + std::vector logData; + map_range_to_vec_vbo(FRANGE_START, FRANGE_END, 0.1f, sinData, &sinf); + map_range_to_vec_vbo(FRANGE_START, FRANGE_END, 0.1f, cosData, &cosf); + map_range_to_vec_vbo(FRANGE_START, FRANGE_END, 0.1f, tanData, &tanf); + map_range_to_vec_vbo(FRANGE_START, FRANGE_END, 0.1f, logData, &log10f); /* * First Forge call should be a window creation call @@ -42,45 +50,33 @@ int main(void){ */ fg::Window wnd(DIMX, DIMY, "Plotting Demo"); wnd.makeCurrent(); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); - /* - * Split the window into grid regions - */ - wnd.grid(WIN_ROWS, WIN_COLS); + fg::Chart chart(FG_CHART_2D); + chart.setAxesLimits(FRANGE_START, FRANGE_END, -1.1f, 1.1f); /* Create several plot objects which creates the necessary * vertex buffer objects to hold the different plot types */ - fg::Plot plt0(function.size()/2, fg::f32); //create a default plot - fg::Plot plt1(function.size()/2, fg::f32, fg::FG_LINE, fg::FG_NONE); //or specify a specific plot type - fg::Plot plt2(function.size()/2, fg::f32, fg::FG_LINE, fg::FG_TRIANGLE); //last parameter specifies marker shape - fg::Plot plt3(function.size()/2, fg::f32, fg::FG_SCATTER, fg::FG_POINT); + fg::Plot plt0 = chart.plot(sinData.size()/2, fg::f32); //create a default plot + fg::Plot plt1 = chart.plot(cosData.size()/2, fg::f32, FG_PLOT_LINE, FG_MARKER_NONE); //or specify a specific plot type + fg::Plot plt2 = chart.plot(tanData.size()/2, fg::f32, FG_PLOT_LINE, FG_MARKER_TRIANGLE); //last parameter specifies marker shape + fg::Plot plt3 = chart.plot(logData.size()/2, fg::f32, FG_PLOT_SCATTER, FG_MARKER_CROSS); /* * Set plot colors */ - plt0.setColor(fg::FG_YELLOW); - plt1.setColor(fg::FG_BLUE); - plt2.setColor(fg::FG_WHITE); //use a forge predefined color - plt3.setColor((fg::Color) 0xABFF01FF); //or any hex-valued color - + plt0.setColor(FG_RED); + plt1.setColor(FG_BLUE); + plt2.setColor(FG_YELLOW); //use a forge predefined color + plt3.setColor((fg::Color) 0x257973FF); //or any hex-valued color /* - * Set draw limits for plots + * Set plot legends */ - plt0.setAxesLimits(FRANGE_END, FRANGE_START, 1.1f, -1.1f); - plt1.setAxesLimits(FRANGE_END, FRANGE_START, 1.1f, -1.1f); - plt2.setAxesLimits(FRANGE_END, FRANGE_START, 1.1f, -1.1f); - plt3.setAxesLimits(FRANGE_END, FRANGE_START, 1.1f, -1.1f); + plt0.setLegend("Sine"); + plt1.setLegend("Cosine"); + plt2.setLegend("Tangent"); + plt3.setLegend("Log base 10"); + /* copy your data into the pixel buffer object exposed by * fg::Plot class and then proceed to rendering. @@ -88,18 +84,13 @@ int main(void){ * memory to display memory, Forge provides copy headers * along with the library to help with this task */ - copy(plt0, &function[0]); - copy(plt1, &function[0]); - copy(plt2, &function[0]); - copy(plt3, &function[0]); + fg::copy(plt0.vertices(), plt0.verticesSize(), (const void*)sinData.data()); + fg::copy(plt1.vertices(), plt1.verticesSize(), (const void*)cosData.data()); + fg::copy(plt2.vertices(), plt2.verticesSize(), (const void*)tanData.data()); + fg::copy(plt3.vertices(), plt3.verticesSize(), (const void*)logData.data()); do { - wnd.draw(0, 0, plt0, NULL ); - wnd.draw(0, 1, plt1, "sinf_line_blue" ); - wnd.draw(1, 1, plt2, "sinf_line_triangle" ); - wnd.draw(1, 0, plt3, "sinf_scatter_point" ); - // draw window and poll for events last - wnd.swapBuffers(); + wnd.draw(chart); } while(!wnd.close()); return 0; diff --git a/examples/cpu/surface.cpp b/examples/cpu/surface.cpp index 11b13bce..66f53b41 100644 --- a/examples/cpu/surface.cpp +++ b/examples/cpu/surface.cpp @@ -14,90 +14,62 @@ #include #include -const unsigned DIMX = 800; -const unsigned DIMY = 800; +using namespace std; -static const float XMIN = -1.0f; -static const float XMAX = 2.f; -static const float YMIN = -1.0f; -static const float YMAX = 1.f; +static const float XMIN = -8.0f; +static const float XMAX = 8.f; +static const float YMIN = -8.0f; +static const float YMAX = 8.f; -const float DX = 0.01; -const size_t XSIZE = (XMAX-XMIN)/DX+1; -const size_t YSIZE = (YMAX-YMIN)/DX+1; +const float DX = 0.5; +const size_t XSIZE = (XMAX-XMIN)/DX; +const size_t YSIZE = (YMAX-YMIN)/DX; -bool set=false; -using namespace std; -void gen_surface(float t, float dx, std::vector &vec ){ +void genSurface(float dx, std::vector &vec ) +{ vec.clear(); for(float x=XMIN; x < XMAX; x+=dx){ for(float y=YMIN; y < YMAX; y+=dx){ vec.push_back(x); vec.push_back(y); - vec.push_back(10*x*-abs(y) * cos(x*x*(y+t))+sin(y*(x+t))-1.5); + float z = sqrt(x*x+y*y) + 2.2204e-16; + vec.push_back(sin(z)/z); } } } -int main(void){ +int main(void) +{ /* * First Forge call should be a window creation call * so that necessary OpenGL context is created for any * other fg::* object to be created successfully */ - fg::Window wnd(DIMX, DIMY, "3d Surface Demo"); + fg::Window wnd(1024, 768, "3d Surface Demo"); wnd.makeCurrent(); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); - - /* Create several plot objects which creates the necessary - * vertex buffer objects to hold the different plot types - */ - fg::Surface surf(XSIZE, YSIZE, fg::f32, fg::FG_SURFACE); - - /* - * Set plot colors - */ - surf.setColor(fg::FG_YELLOW); - /* - * Set draw limits for plots - */ - surf.setAxesLimits(1.1f, -1.1f, 1.1f, -1.1f, 10.f, -5.f); + fg::Chart chart(FG_CHART_3D); + chart.setAxesLimits(-10.f, 10.f, -10.f, 10.f, -0.5f, 1.f); + chart.setAxesTitles("x-axis", "y-axis", "z-axis"); - /* - * Set axis titles - */ - surf.setAxesTitles("x-axis", "y-axis", "z-axis"); + fg::Surface surf = chart.surface(XSIZE, YSIZE, fg::f32); + surf.setColor(FG_YELLOW); //generate a surface std::vector function; - static float t=0; - gen_surface(t, DX, function); + + genSurface(DX, function); /* copy your data into the pixel buffer object exposed by * fg::Plot class and then proceed to rendering. * To help the users with copying the data from compute * memory to display memory, Forge provides copy headers * along with the library to help with this task */ - copy(surf, &function[0]); + fg::copy(surf.vertices(), surf.verticesSize(), (const void*)function.data()); do { - t+=0.07; - gen_surface(t, DX, function); - copy(surf, &function[0]); - // draw window and poll for events last - wnd.draw(surf); + wnd.draw(chart); } while(!wnd.close()); return 0; } - diff --git a/examples/cuda/fractal.cu b/examples/cuda/fractal.cu index 0b18d926..16f28df2 100644 --- a/examples/cuda/fractal.cu +++ b/examples/cuda/fractal.cu @@ -21,28 +21,18 @@ int main(void) */ fg::Window wnd(DIMX, DIMY, "Fractal Demo"); wnd.makeCurrent(); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); /* Create an image object which creates the necessary * textures and pixel buffer objects to hold the image * */ - fg::Image img(DIMX, DIMY, fg::FG_RGBA, fg::u8); + fg::Image img(DIMX, DIMY, FG_RGBA, fg::u8); /* copy your data into the pixel buffer object exposed by * fg::Image class and then proceed to rendering. * To help the users with copying the data from compute * memory to display memory, Forge provides copy headers * along with the library to help with this task */ - CUDA_ERROR_CHECK(cudaMalloc((void**)&dev_out, SIZE)); + FORGE_CUDA_CHECK(cudaMalloc((void**)&dev_out, SIZE)); kernel(dev_out); fg::copy(img, dev_out); @@ -50,7 +40,7 @@ int main(void) wnd.draw(img); } while(!wnd.close()); - CUDA_ERROR_CHECK(cudaFree(dev_out)); + FORGE_CUDA_CHECK(cudaFree(dev_out)); return 0; } @@ -85,9 +75,9 @@ void julia(unsigned char* out) // now calculate the value at that position int juliaValue = julia(x, y); - out[offset*4 + 0] = 255 * juliaValue; + out[offset*4 + 2] = 255 * juliaValue; + out[offset*4 + 0] = 0; out[offset*4 + 1] = 0; - out[offset*4 + 2] = 0; out[offset*4 + 3] = 255; } } diff --git a/examples/cuda/histogram.cu b/examples/cuda/histogram.cu index 652a5c33..740d84ac 100644 --- a/examples/cuda/histogram.cu +++ b/examples/cuda/histogram.cu @@ -9,47 +9,60 @@ #include #include +#include +#include #include #include #include +const unsigned IMGW = 256; +const unsigned IMGH = 256; const unsigned DIMX = 1000; const unsigned DIMY = 800; -const unsigned IMG_SIZE = DIMX * DIMY * 4; const unsigned WIN_ROWS = 1; const unsigned WIN_COLS = 2; +const unsigned NBINS = 256; -static float persistance; -const unsigned NBINS = 5; - - -const static int hperm[] = {26, 58, 229, 82, 132, 72, 144, 251, 196, 192, 127, 16, - 68, 118, 104, 213, 91, 105, 203, 61, 59, 93, 136, 249, 27, 137, 141, 223, 119, - 193, 155, 43, 71, 244, 170, 115, 201, 150, 165, 78, 208, 53, 90, 232, 209, 83, - 45, 174, 140, 178, 220, 184, 70, 6, 202, 17, 128, 212, 117, 200, 254, 57, 248, - 62, 164, 172, 19, 177, 241, 103, 48, 38, 210, 129, 23, 211, 8, 112, 107, 126, - 252, 198, 32, 123, 111, 176, 206, 15, 219, 221, 147, 245, 67, 92, 108, 143, - 54, 102, 169, 22, 74, 124, 181, 186, 138, 18, 7, 34, 81, 46, 120, 236, 89,228, - 197, 205, 13, 63, 134, 242, 157, 135, 237, 35, 234, 49, 85, 76, 148, 188, 98, - 87, 173, 84, 226, 11, 125, 122, 2, 94, 191, 179, 175, 187, 133, 231, 154, 44, - 28, 110, 247, 121, 146, 240, 97, 88, 130,195, 30, 25, 56, 171, 80, 69, 139, 9, - 238, 160, 227, 204, 31, 40, 66, 77, 21, 159, 162, 207, 167, 214, 10, 3, 149, - 194, 239, 166, 145, 235, 20, 50, 113, 189, 99, 37, 86, 42, 168, 114, 96, 246, - 183, 250, 233, 156, 52, 65, 131, 47, 255, 5, 33, 217, 73, 4, 60, 64, 109, 0, - 215, 100, 180, 12, 24, 190, 222, 106, 41, 216, 230, 161, 55, 152, 79, 75, 142, - 36, 101, 1, 253, 225, 51, 224, 182, 116, 218, 95, 39, 158, 14, 243, 151, 163, - 29, 153, 199, 185 +curandState_t* state; + +struct Bitmap { + unsigned char *ptr; + unsigned width; + unsigned height; +}; + +class PerlinNoise +{ + public: + float* base; + float* perlin; + + PerlinNoise(); + ~PerlinNoise(); + void generateNoise(); }; -__constant__ int perm[256]; -void kernel(unsigned char* dev_out); -void kernel_hist(unsigned char * src, int* hist_out); +Bitmap createBitmap(unsigned w, unsigned h); + +void destroyBitmap(Bitmap& bmp); + +void kernel(Bitmap& bmp, PerlinNoise& pn); + +void populateBins(Bitmap& bmp, int *hist_array, const unsigned nbins, float *hist_cols); + +__global__ +void setupRandomKernel(curandState *states, unsigned long long seed) +{ + unsigned tid = blockDim.x * blockIdx.x + threadIdx.x; + curand_init(seed, tid, 0, &states[tid]); +} int main(void) { - int *hist_out; - unsigned char *dev_out; - cudaMemcpyToSymbol(perm, hperm, 256 * sizeof(int)); + Bitmap bmp = createBitmap(IMGW, IMGH); + + FORGE_CUDA_CHECK(cudaMalloc((void **)&state, NBINS*sizeof(curandState_t))); + setupRandomKernel <<< 1, NBINS >>> (state, 314567); /* * First Forge call should be a window creation call @@ -58,165 +71,242 @@ int main(void) */ fg::Window wnd(DIMX, DIMY, "Histogram Demo"); wnd.makeCurrent(); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); /* * Split the window into grid regions */ wnd.grid(WIN_ROWS, WIN_COLS); - fg::Image img(DIMX, DIMY, fg::FG_RGBA, fg::u8); + fg::Image img(IMGW, IMGH, FG_RGBA, fg::u8); + + fg::Chart chart(FG_CHART_2D); + /* set x axis limits to maximum and minimum values of data + * and y axis limits to range [0, number of pixels ideally] + * but practically total number of pixels as y range will skew + * the histogram graph vertically. Therefore setting it to + * 25% of total number of pixels */ + chart.setAxesLimits(0, 1, 0, IMGW*IMGH/(float)(NBINS/4.0)); + /* - * Create histogram object while specifying desired number of bins + * Create histogram object specifying number of bins */ - fg::Histogram hist(NBINS, fg::u8); - + fg::Histogram hist = chart.histogram(NBINS, fg::s32); /* * Set histogram colors */ - hist.setBarColor(fg::FG_YELLOW); + hist.setColor(FG_YELLOW); - /* set x axis limits to maximum and minimum values of data - * and y axis limits to range [0, nBins]*/ - hist.setAxesLimits(1, 0, 1000, 0); - CUDA_ERROR_CHECK(cudaMalloc((void**)&dev_out, IMG_SIZE )); - CUDA_ERROR_CHECK(cudaMalloc((void**)&hist_out, NBINS * sizeof(int))); - kernel(dev_out); - kernel_hist(dev_out, hist_out); - fg::copy(img, dev_out); - fg::copy(hist, hist_out); + PerlinNoise noiseGenerator; + int *histOut; + float *histColors; + + FORGE_CUDA_CHECK(cudaMalloc((void**)&histOut, NBINS * sizeof(int))); + FORGE_CUDA_CHECK(cudaMalloc((void**)&histColors, 3*NBINS * sizeof(float))); + unsigned frame = 0; do { - kernel(dev_out); - kernel_hist(dev_out, hist_out); - fg::copy(img, dev_out); - // limit histogram update frequency - if(fmod(persistance, 0.5f) < 0.01) - fg::copy(hist, hist_out); + if (frame%8==0) { + kernel(bmp, noiseGenerator); + fg::copy(img, bmp.ptr); + + populateBins(bmp, histOut, NBINS, histColors); + + fg::copy(hist.vertices(), histOut); + fg::copy(hist.colors(), histColors); + frame = 0; + } + wnd.draw(0, 0, img, "Dynamic Perlin Noise" ); - wnd.draw(1, 0, hist, "Histogram of Noisy Image"); + wnd.draw(1, 0, chart, "Histogram of Noisy Image"); + wnd.swapBuffers(); + frame++; } while(!wnd.close()); - CUDA_ERROR_CHECK(cudaFree(dev_out)); + FORGE_CUDA_CHECK(cudaFree(histOut)); + FORGE_CUDA_CHECK(cudaFree(histColors)); return 0; } -__device__ -inline float interp(float t){ - return ((6 * t - 15) * t + 10) * t * t * t; +Bitmap createBitmap(unsigned w, unsigned h) +{ + Bitmap retVal; + retVal.width = w; + retVal.height= h; + FORGE_CUDA_CHECK(cudaMalloc((void**)&retVal.ptr, sizeof(unsigned char)*4*w*h)); + return retVal; } -__device__ -inline float lerp (float x0, float x1, float t) { - return x0 + (x1 - x0) * t; +void destroyBitmap(Bitmap& bmp) +{ + FORGE_CUDA_CHECK(cudaFree(bmp.ptr)); } -__device__ -inline float dot (float2 v0, float2 v1) { - return v0.x*v1.x + v0.y*v1.y; +PerlinNoise::PerlinNoise() +{ + const size_t IMG_SIZE = IMGW*IMGH*sizeof(float); + + FORGE_CUDA_CHECK(cudaMalloc((void**)&base, IMG_SIZE)); + FORGE_CUDA_CHECK(cudaMalloc((void**)&perlin, IMG_SIZE)); } -__device__ -inline float2 sub (float2 v0, float2 v1) { - return make_float2(v0.x-v1.x, v0.y-v1.y); +PerlinNoise::~PerlinNoise() +{ + FORGE_CUDA_CHECK(cudaFree(base)); + FORGE_CUDA_CHECK(cudaFree(perlin)); +} + +inline +int divup(int a, int b) +{ + return (a+b-1)/b; } __device__ -float perlinNoise(float x, float y, int tileSize) { - const float2 default_gradients[] = { make_float2(1,1), make_float2(-1,1),make_float2 (1,-1), make_float2(-1,-1) }; - int x_grid = x/tileSize; - int y_grid = y/tileSize; - unsigned rand_id0 = perm[(x_grid+2*y_grid) % 256 ] % 4; - unsigned rand_id1 = perm[(x_grid+1+2*y_grid) % 256 ] % 4; - unsigned rand_id2 = perm[(x_grid+2*(y_grid+1)) % 256 ] % 4; - unsigned rand_id3 = perm[(x_grid+1+2*(y_grid+1)) % 256 ] % 4; - - x=fmod(x,__int2float_rd(tileSize))/tileSize; - y=fmod(y,__int2float_rd(tileSize))/tileSize; - float u = interp(x); - float v = interp(y); - - float influence_vecs[4]; - influence_vecs[0] = dot(sub(make_float2(x,y), make_float2(0,0)), default_gradients[rand_id0]); - influence_vecs[1] = dot(sub(make_float2(x,y), make_float2(1,0)), default_gradients[rand_id1]); - influence_vecs[2] = dot(sub(make_float2(x,y), make_float2(0,1)), default_gradients[rand_id2]); - influence_vecs[3] = dot(sub(make_float2(x,y), make_float2(1,1)), default_gradients[rand_id3]); - - return lerp(lerp(influence_vecs[0], influence_vecs[1], u), lerp(influence_vecs[2], influence_vecs[3], u), v); - -} - __device__ -float octavesPerlin(float x, float y, int octaves, float persistence, int tileSize) { - float total = 0, max_value = 0; - float amplitude = 1, frequency = 1; - for(int i=0; i>> (base, perlin, state); - static int tileSize = 32; tileSize++; - persistance += 0.01; - image_gen<<< blocks, threads >>>(dev_out, persistance, tileSize); + for (int octave=6; octave>=0; --octave) { + int period = 1 << octave; + + perlinComputeKernel<<< blocks, threads >>>(perlin, base, amp, period); + + tamp += amp; + amp *= persistence; + } + + perlinNormalize<<< blocks, threads >>>(perlin, tamp); } __global__ -void hist_freq(const unsigned char* src, int* hist_array, const unsigned nbins) { +void fillImageKernel(unsigned char* ptr, unsigned width, unsigned height, float* perlin) +{ int x = blockIdx.x * blockDim.x + threadIdx.x; int y = blockIdx.y * blockDim.y + threadIdx.y; - if (x>>(bmp.ptr, bmp.width, bmp.height, pn.perlin); +} + +__global__ +void histogramKernel(const unsigned char* perlinNoise, int* histOut, const unsigned nbins) +{ + int x = blockIdx.x * blockDim.x + threadIdx.x; + int y = blockIdx.y * blockDim.y + threadIdx.y; + + if (x>>(bmp.ptr, histOut, nbins); - cudaMemset(hist_out, 0, NBINS * sizeof(int)); - hist_freq<<< blocks, threads >>>(src, hist_out, NBINS); + histColorsKernel<<< 1, nbins >>>(histColors, state); } diff --git a/examples/cuda/plot3.cu b/examples/cuda/plot3.cu index 2b40682f..75f19a2f 100644 --- a/examples/cuda/plot3.cu +++ b/examples/cuda/plot3.cu @@ -36,34 +36,15 @@ int main(void) */ fg::Window wnd(DIMX, DIMY, "Plot 3d Demo"); wnd.makeCurrent(); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); - - /* Create several plot objects which creates the necessary - * vertex buffer objects to hold the different plot types - */ - fg::Plot3 plot3(ZSIZE, fg::f32); - /* - * Set draw limits for plots - */ - plot3.setAxesLimits(1.1f, -1.1f, 1.1f, -1.1f, 10.f, 0.f); + fg::Chart chart(FG_CHART_3D); + chart.setAxesLimits(-1.1f, 1.1f, -1.1f, 1.1f, 0.f, 10.f); + chart.setAxesTitles("x-axis", "y-axis", "z-axis"); - /* - * Set axis titles - */ - plot3.setAxesTitles("x-axis", "y-axis", "z-axis"); + fg::Plot plot3 = chart.plot(ZSIZE, fg::f32); static float t=0; - CUDA_ERROR_CHECK(cudaMalloc((void**)&dev_out, ZSIZE * 3 * sizeof(float) )); + FORGE_CUDA_CHECK(cudaMalloc((void**)&dev_out, ZSIZE * 3 * sizeof(float) )); kernel(t, DX, dev_out); /* copy your data into the vertex buffer object exposed by * fg::Plot class and then proceed to rendering. @@ -71,18 +52,17 @@ int main(void) * memory to display memory, Forge provides copy headers * along with the library to help with this task */ - fg::copy(plot3, dev_out); + fg::copy(plot3.vertices(), dev_out); do { t+=0.01; kernel(t, DX, dev_out); - fg::copy(plot3, dev_out); - // draw window and poll for events last - wnd.draw(plot3); + fg::copy(plot3.vertices(), dev_out); + wnd.draw(chart); } while(!wnd.close()); - CUDA_ERROR_CHECK(cudaFree(dev_out)); + FORGE_CUDA_CHECK(cudaFree(dev_out)); return 0; } diff --git a/examples/cuda/plotting.cu b/examples/cuda/plotting.cu index 40ba9050..da09654b 100644 --- a/examples/cuda/plotting.cu +++ b/examples/cuda/plotting.cu @@ -7,19 +7,20 @@ const unsigned DIMX = 1000; const unsigned DIMY = 800; -const unsigned WIN_ROWS = 2; -const unsigned WIN_COLS = 2; static const float dx = 0.1; static const float FRANGE_START = 0.f; static const float FRANGE_END = 2 * 3.141592f; static const size_t DATA_SIZE = ( FRANGE_END - FRANGE_START ) / dx; -void kernel(float* dev_out); +void kernel(float* dev_out, int functionCode); int main(void) { - float *dev_out; + float *sin_out; + float *cos_out; + float *tan_out; + float *log_out; /* * First Forge call should be a window creation call @@ -29,81 +30,85 @@ int main(void) fg::Window wnd(DIMX, DIMY, "Plotting Demo"); wnd.makeCurrent(); wnd.grid(1,2); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); - /* - * Split the window into grid regions - */ - wnd.grid(WIN_ROWS, WIN_COLS); + fg::Chart chart(FG_CHART_2D); + chart.setAxesLimits(FRANGE_START, FRANGE_END, -1.1f, 1.1f); /* Create several plot objects which creates the necessary * vertex buffer objects to hold the different plot types */ - fg::Plot plt0( DATA_SIZE, fg::f32); //create a default plot - fg::Plot plt1( DATA_SIZE, fg::f32, fg::FG_LINE, fg::FG_NONE); //or specify a specific plot type - fg::Plot plt2( DATA_SIZE, fg::f32, fg::FG_LINE, fg::FG_TRIANGLE); //last parameter specifies marker shape - fg::Plot plt3( DATA_SIZE, fg::f32, fg::FG_SCATTER, fg::FG_POINT); + fg::Plot plt0 = chart.plot( DATA_SIZE, fg::f32); //create a default plot + fg::Plot plt1 = chart.plot( DATA_SIZE, fg::f32, FG_PLOT_LINE, FG_MARKER_NONE); //or specify a specific plot type + fg::Plot plt2 = chart.plot( DATA_SIZE, fg::f32, FG_PLOT_LINE, FG_MARKER_TRIANGLE); //last parameter specifies marker shape + fg::Plot plt3 = chart.plot( DATA_SIZE, fg::f32, FG_PLOT_SCATTER, FG_MARKER_CROSS); /* * Set plot colors */ - plt0.setColor(fg::FG_YELLOW); - plt1.setColor(fg::FG_BLUE); - plt2.setColor(fg::FG_WHITE); //use a forge predefined color - plt3.setColor((fg::Color) 0xABFF01FF); //or any hex-valued color - + plt0.setColor(FG_RED); + plt1.setColor(FG_BLUE); + plt2.setColor(FG_YELLOW); //use a forge predefined color + plt3.setColor((fg::Color) 0x257973FF); //or any hex-valued color /* - * Set draw limits for plots + * Set plot legends */ - plt0.setAxesLimits(FRANGE_END, FRANGE_START, 1.1f, -1.1f); - plt1.setAxesLimits(FRANGE_END, FRANGE_START, 1.1f, -1.1f); - plt2.setAxesLimits(FRANGE_END, FRANGE_START, 1.1f, -1.1f); - plt3.setAxesLimits(FRANGE_END, FRANGE_START, 1.1f, -1.1f); - - CUDA_ERROR_CHECK(cudaMalloc((void**)&dev_out, sizeof(float) * DATA_SIZE * 2)); - kernel(dev_out); + plt0.setLegend("Sine"); + plt1.setLegend("Cosine"); + plt2.setLegend("Tangent"); + plt3.setLegend("Log base 10"); + + FORGE_CUDA_CHECK(cudaMalloc((void**)&sin_out, sizeof(float) * DATA_SIZE * 2)); + FORGE_CUDA_CHECK(cudaMalloc((void**)&cos_out, sizeof(float) * DATA_SIZE * 2)); + FORGE_CUDA_CHECK(cudaMalloc((void**)&tan_out, sizeof(float) * DATA_SIZE * 2)); + FORGE_CUDA_CHECK(cudaMalloc((void**)&log_out, sizeof(float) * DATA_SIZE * 2)); + + kernel(sin_out, 0); + kernel(cos_out, 1); + kernel(tan_out, 2); + kernel(log_out, 3); /* copy your data into the vertex buffer object exposed by * fg::Plot class and then proceed to rendering. * To help the users with copying the data from compute * memory to display memory, Forge provides copy headers * along with the library to help with this task */ - fg::copy(plt0, dev_out); - fg::copy(plt1, dev_out); - fg::copy(plt2, dev_out); - fg::copy(plt3, dev_out); + fg::copy(plt0.vertices(), sin_out); + fg::copy(plt1.vertices(), cos_out); + fg::copy(plt2.vertices(), tan_out); + fg::copy(plt3.vertices(), log_out); do { - wnd.draw(0, 0, plt0, NULL ); - wnd.draw(0, 1, plt1, "sinf_line_blue" ); - wnd.draw(1, 1, plt2, "sinf_line_triangle" ); - wnd.draw(1, 0, plt3, "sinf_scatter_point" ); - // draw window and poll for events last - wnd.swapBuffers(); + wnd.draw(chart); } while(!wnd.close()); - CUDA_ERROR_CHECK(cudaFree(dev_out)); + FORGE_CUDA_CHECK(cudaFree(sin_out)); + FORGE_CUDA_CHECK(cudaFree(cos_out)); + FORGE_CUDA_CHECK(cudaFree(tan_out)); + FORGE_CUDA_CHECK(cudaFree(log_out)); return 0; } - __global__ -void simple_sinf(float* out, const size_t DATA_SIZE, const float dx) +void simple_sinf(float* out, const size_t DATA_SIZE, int fnCode) { int x = blockIdx.x * blockDim.x + threadIdx.x; if (x> >(dev_out, DATA_SIZE, dx); + simple_sinf << < blocks, threads >> >(dev_out, DATA_SIZE, functionCode); } diff --git a/examples/cuda/surface.cu b/examples/cuda/surface.cu index 4ea89d03..53824a24 100644 --- a/examples/cuda/surface.cu +++ b/examples/cuda/surface.cu @@ -5,19 +5,16 @@ #include #include -const unsigned DIMX = 1000; -const unsigned DIMY = 800; +const float XMIN = -8.0f; +const float XMAX = 8.f; +const float YMIN = -8.0f; +const float YMAX = 8.f; -const float XMIN = -1.0f; -const float XMAX = 2.f; -const float YMIN = -1.0f; -const float YMAX = 1.f; +const float DX = 0.5; +const size_t XSIZE = (XMAX-XMIN)/DX; +const size_t YSIZE = (YMAX-YMIN)/DX; -const float DX = 0.01; -const size_t XSIZE = (XMAX-XMIN)/DX+1; -const size_t YSIZE = (YMAX-YMIN)/DX+1; - -void kernel(float t, float dx, float* dev_out); +void kernel(float dx, float* dev_out); int main(void) { @@ -28,65 +25,37 @@ int main(void) * so that necessary OpenGL context is created for any * other fg::* object to be created successfully */ - fg::Window wnd(DIMX, DIMY, "3d Surface Demo"); + fg::Window wnd(1024, 768, "3d Surface Demo"); wnd.makeCurrent(); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); - - /* Create several plot objects which creates the necessary - * vertex buffer objects to hold the different plot types - */ - fg::Surface surf(XSIZE, YSIZE, fg::f32, fg::FG_SURFACE); - - /* - * Set plot colors - */ - surf.setColor(fg::FG_YELLOW); - /* - * Set draw limits for plots - */ - surf.setAxesLimits(1.1f, -1.1f, 1.1f, -1.1f, 10.f, -5.f); + fg::Chart chart(FG_CHART_3D); + chart.setAxesLimits(-10.f, 10.f, -10.f, 10.f, -0.5f, 1.f); + chart.setAxesTitles("x-axis", "y-axis", "z-axis"); - /* - * Set axis titles - */ - surf.setAxesTitles("x-axis", "y-axis", "z-axis"); + fg::Surface surf = chart.surface(XSIZE, YSIZE, fg::f32); + surf.setColor(FG_YELLOW); - static float t=0; - CUDA_ERROR_CHECK(cudaMalloc((void**)&dev_out, XSIZE * YSIZE * 3 * sizeof(float) )); - kernel(t, DX, dev_out); + FORGE_CUDA_CHECK(cudaMalloc((void**)&dev_out, XSIZE * YSIZE * 3 * sizeof(float) )); + kernel(DX, dev_out); /* copy your data into the vertex buffer object exposed by * fg::Plot class and then proceed to rendering. * To help the users with copying the data from compute * memory to display memory, Forge provides copy headers * along with the library to help with this task */ - fg::copy(surf, dev_out); + fg::copy(surf.vertices(), dev_out); do { - t+=0.07; - kernel(t, DX, dev_out); - fg::copy(surf, dev_out); - // draw window and poll for events last - wnd.draw(surf); + wnd.draw(chart); } while(!wnd.close()); - CUDA_ERROR_CHECK(cudaFree(dev_out)); + FORGE_CUDA_CHECK(cudaFree(dev_out)); return 0; } __global__ -void sincos_surf(float t, float dx, float* out, +void sincos_surf(float dx, float* out, const float XMIN, const float YMIN, const size_t XSIZE, const size_t YSIZE) { @@ -99,20 +68,22 @@ void sincos_surf(float t, float dx, float* out, int offset = j + i * YSIZE; out[ 3 * offset ] = x; out[ 3 * offset + 1 ] = y; - out[ 3 * offset + 2 ] = 10*x*-abs(y) * cos(x*x*(y+t))+sin(y*(x+t))-1.5; + float z = sqrt(x*x+y*y) + 2.2204e-16; + out[ 3 * offset + 2 ] = sinf(z)/z; } } -inline int divup(int a, int b) +inline +int divup(int a, int b) { return (a+b-1)/b; } -void kernel(float t, float dx, float* dev_out) +void kernel(float dx, float* dev_out) { static const dim3 threads(8, 8); dim3 blocks(divup(XSIZE, threads.x), divup(YSIZE, threads.y)); - sincos_surf<<< blocks, threads >>>(t, dx, dev_out, XMIN, YMIN, XSIZE, YSIZE); + sincos_surf<<< blocks, threads >>>(dx, dev_out, XMIN, YMIN, XSIZE, YSIZE); } diff --git a/examples/opencl/fractal.cpp b/examples/opencl/fractal.cpp index 65d6da98..093663ad 100644 --- a/examples/opencl/fractal.cpp +++ b/examples/opencl/fractal.cpp @@ -113,21 +113,11 @@ int main(void) */ fg::Window wnd(DIMX, DIMY, "Fractal Demo"); wnd.makeCurrent(); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); /* Create an image object which creates the necessary * textures and pixel buffer objects to hold the image * */ - fg::Image img(DIMX, DIMY, fg::FG_RGBA, fg::u8); + fg::Image img(DIMX, DIMY, FG_RGBA, fg::u8); Platform plat = getPlatform(); diff --git a/examples/opencl/histogram.cpp b/examples/opencl/histogram.cpp index 9fc85ff5..7675ae58 100644 --- a/examples/opencl/histogram.cpp +++ b/examples/opencl/histogram.cpp @@ -11,8 +11,8 @@ #define __CL_ENABLE_EXCEPTIONS #include #include -#include #include +#include #include #include #include @@ -23,160 +23,237 @@ using namespace cl; using namespace std; +const unsigned IMGW = 256; +const unsigned IMGH = 256; const unsigned DIMX = 1000; const unsigned DIMY = 800; -const unsigned IMG_SIZE = DIMX * DIMY * 4; - +const unsigned IMG_SIZE = IMGW * IMGH * 4; const unsigned WIN_ROWS = 1; const unsigned WIN_COLS = 2; +const unsigned NBINS = 256; +const float PERSISTENCE = 0.5f; + +static const std::string perlinKernels = +R"EOK( +float rand(int x) +{ + x = (x << 13) ^ x; + return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0); +} + +float interp(float x0, float x1, float t) +{ + return x0 + (x1 - x0) * t; +} + +kernel +void init(global float* base, global float* perlin, int IMGW, int IMGH, int randSeed) +{ + int x = get_global_id(0); + int y = get_global_id(1); + + if (x(), fractal_ocl_kernel, true); - kern_img = cl::Kernel(prog, "image_gen"); - kern_hist = cl::Kernel(prog, "hist_freq"); - kern_zero = cl::Kernel(prog, "zero_buffer"); - }); + static bool compileFlag = true; + static cl::Program prog; + static cl::Kernel initKernel, computeKernel, normKernel, fillKernel; + static cl::Kernel memSetKernel, genHistogram, genHistColors; + + std::srand(std::time(0)); + + if (compileFlag) { + try { + prog = cl::Program(queue.getInfo(), perlinKernels, false); + + std::vector devs; + devs.push_back(device); + prog.build(devs); + + initKernel = cl::Kernel(prog, "init"); + computeKernel = cl::Kernel(prog, "compute"); + normKernel = cl::Kernel(prog, "normalizeNoise"); + fillKernel = cl::Kernel(prog, "fillImage"); + memSetKernel = cl::Kernel(prog, "memSet"); + genHistogram = cl::Kernel(prog, "histogram"); + genHistColors = cl::Kernel(prog, "setColors"); + } catch (cl::Error err) { + std::cout << "Compile Errors: " << std::endl; + std::cout << err.what() << err.err() << std::endl; + std::cout << prog.getBuildInfo(device) << std::endl; + exit(255); + } + std::cout<< "Kernels compiled successfully" << std::endl; + compileFlag = false; + } static const NDRange local(16, 16); - NDRange global(local[0] * divup(DIMX, local[0]), - local[1] * divup(DIMY, local[1])); - - static int tileSize = 32; tileSize++; - persistance += 0.01; - kern_img.setArg(0, devOut); - kern_img.setArg(1, DIMX); - kern_img.setArg(2, DIMY); - kern_img.setArg(3, persistance); - kern_img.setArg(4, tileSize); - queue.enqueueNDRangeKernel(kern_img, cl::NullRange, global, local); + NDRange global(local[0] * divup(IMGW, local[0]), + local[1] * divup(IMGH, local[1])); + + float persistence = 0.5f; + float amp = 1.0f; + float tamp = 0.0f; + + initKernel.setArg(0, base); + initKernel.setArg(1, perlin); + initKernel.setArg(2, IMGW); + initKernel.setArg(3, IMGH); + initKernel.setArg(4, std::rand()); + queue.enqueueNDRangeKernel(initKernel, cl::NullRange, global, local); + + for (int octave=6; octave>=0; --octave) { + int period = 1 << octave; + computeKernel.setArg(0, perlin); + computeKernel.setArg(1, base); + computeKernel.setArg(2, IMGW); + computeKernel.setArg(3, IMGH); + computeKernel.setArg(4, amp); + computeKernel.setArg(5, period); + queue.enqueueNDRangeKernel(computeKernel, cl::NullRange, global, local); + tamp += amp; + amp *= persistence; + } + + normKernel.setArg(0, perlin); + normKernel.setArg(1, IMGW); + normKernel.setArg(2, IMGH); + normKernel.setArg(3, tamp); + queue.enqueueNDRangeKernel(normKernel, cl::NullRange, global, local); + + fillKernel.setArg(0, image); + fillKernel.setArg(1, IMGW); + fillKernel.setArg(2, IMGH); + fillKernel.setArg(3, perlin); + fillKernel.setArg(4, IMGW); + fillKernel.setArg(5, IMGH); + queue.enqueueNDRangeKernel(fillKernel, cl::NullRange, global, local); static const NDRange global_hist(NBINS); - kern_zero.setArg(0, histOut); - kern_zero.setArg(1, NBINS); - queue.enqueueNDRangeKernel(kern_zero, cl::NullRange, global_hist); - - kern_hist.setArg(0, devOut); - kern_hist.setArg(1, histOut); - kern_hist.setArg(2, DIMX); - kern_hist.setArg(3, DIMY); - kern_hist.setArg(4, NBINS); - queue.enqueueNDRangeKernel(kern_hist, cl::NullRange, global, local); + + memSetKernel.setArg(0, histOut); + memSetKernel.setArg(1, NBINS); + queue.enqueueNDRangeKernel(memSetKernel, cl::NullRange, global_hist); + + genHistogram.setArg(0, image); + genHistogram.setArg(1, histOut); + genHistogram.setArg(2, IMGW); + genHistogram.setArg(3, IMGH); + genHistogram.setArg(4, NBINS); + queue.enqueueNDRangeKernel(genHistogram, cl::NullRange, global, local); + + genHistColors.setArg(0, colors); + genHistColors.setArg(1, std::rand()); + genHistColors.setArg(2, std::rand()); + genHistColors.setArg(3, std::rand()); + queue.enqueueNDRangeKernel(genHistColors, cl::NullRange, global_hist); } int main(void) @@ -189,39 +266,30 @@ int main(void) */ fg::Window wnd(DIMX, DIMY, "Histogram Demo"); wnd.makeCurrent(); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); /* * Split the window into grid regions */ wnd.grid(WIN_ROWS, WIN_COLS); - /* Create an image object which creates the necessary - * textures and pixel buffer objects to hold the image - * */ - fg::Image img(DIMX, DIMY, fg::FG_RGBA, fg::u8); + fg::Image img(IMGW, IMGH, FG_RGBA, fg::u8); + + fg::Chart chart(FG_CHART_2D); + /* set x axis limits to maximum and minimum values of data + * and y axis limits to range [0, number of pixels ideally] + * but practically total number of pixels as y range will skew + * the histogram graph vertically. Therefore setting it to + * 25% of total number of pixels */ + chart.setAxesLimits(0, 1, 0, IMGW*IMGH/(float)(NBINS/4.0)); + /* - * Create histogram object while specifying desired number of bins + * Create histogram object specifying number of bins */ - fg::Histogram hist(NBINS, fg::u8); - + fg::Histogram hist = chart.histogram(NBINS, fg::s32); /* * Set histogram colors */ - hist.setBarColor(fg::FG_YELLOW); - - /* set x axis limits to maximum and minimum values of data - * and y axis limits to range [0, nBins]*/ - hist.setAxesLimits(1, 0, 1000, 0); + hist.setColor(FG_YELLOW); Platform plat = getPlatform(); // Select the default platform and create a context using this platform and the GPU @@ -267,31 +335,28 @@ int main(void) } } - cl::Buffer devOut(context, CL_MEM_READ_WRITE, IMG_SIZE); + cl::Buffer image(context, CL_MEM_READ_WRITE, IMG_SIZE); + cl::Buffer baseNoise(context, CL_MEM_READ_WRITE, IMG_SIZE); + cl::Buffer perlinNoise(context, CL_MEM_READ_WRITE, IMG_SIZE); cl::Buffer histOut(context, CL_MEM_READ_WRITE, NBINS * sizeof(int)); + cl::Buffer colors(context, CL_MEM_READ_WRITE, 3 * NBINS * sizeof(float)); - /* - * generate image, and prepare data to pass into - * Histogram's underlying vertex buffer object - */ - kernel(devOut, histOut, queue); - /* To help the users with copying the data from compute - * memory to display memory, Forge provides copy headers - * along with the library to help with this task - */ - fg::copy(img, devOut, queue); - fg::copy(hist, histOut, queue); - + unsigned frame = 0; do { - kernel(devOut, histOut, queue); - fg::copy(img, devOut, queue); - // limit histogram update frequency - if(fmod(persistance, 0.4f) < 0.02f) - fg::copy(hist, histOut, queue); - // draw window and poll for events last + if (frame%8==0) { + kernel(image, baseNoise, perlinNoise, histOut, colors, queue, device); + + fg::copy(img, image, queue); + fg::copy(hist.vertices(), hist.verticesSize(), histOut, queue); + fg::copy(hist.colors(), hist.colorsSize(), colors, queue); + frame = 0; + } + wnd.draw(0, 0, img, "Dynamic Perlin Noise" ); - wnd.draw(1, 0, hist, "Histogram of Noisy Image"); + wnd.draw(1, 0, chart, "Histogram of Noisy Image"); + wnd.swapBuffers(); + frame++; } while(!wnd.close()); }catch (fg::Error err) { std::cout << err.what() << "(" << err.err() << ")" << std::endl; diff --git a/examples/opencl/plot3.cpp b/examples/opencl/plot3.cpp index d1404ccc..99b5f6ca 100644 --- a/examples/opencl/plot3.cpp +++ b/examples/opencl/plot3.cpp @@ -82,37 +82,12 @@ int main(void) */ fg::Window wnd(DIMX, DIMY, "Plot3d Demo"); wnd.makeCurrent(); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); - - /* Create several plot objects which creates the necessary - * vertex buffer objects to hold the different plot types - */ - fg::Plot3 plot3(ZSIZE, fg::f32); - - /* - * Set draw limits for plots - */ - plot3.setAxesLimits(1.1f, -1.1f, 1.1f, -1.1f, 10.f, 0.f); - /* - * Set draw limits for plots - */ - plot3.setAxesLimits(1.1f, -1.1f, 1.1f, -1.1f, 10.f, 0.f); - - /* - * Set axis titles - */ - plot3.setAxesTitles("x-axis", "y-axis", "z-axis"); + fg::Chart chart(FG_CHART_3D); + chart.setAxesLimits(-1.1f, 1.1f, -1.1f, 1.1f, 0.f, 10.f); + chart.setAxesTitles("x-axis", "y-axis", "z-axis"); + fg::Plot plot3 = chart.plot(ZSIZE, fg::f32); Platform plat = getPlatform(); // Select the default platform and create a context using this platform and the GPU @@ -167,14 +142,13 @@ int main(void) * memory to display memory, Forge provides copy headers * along with the library to help with this task */ - fg::copy(plot3, devOut, queue); + fg::copy(plot3.vertices(), plot3.verticesSize(), devOut, queue); do { t+=0.01; kernel(devOut, queue, t); - fg::copy(plot3, devOut, queue); - // draw window and poll for events last - wnd.draw(plot3); + fg::copy(plot3.vertices(), plot3.verticesSize(), devOut, queue); + wnd.draw(chart); } while(!wnd.close()); }catch (fg::Error err) { std::cout << err.what() << "(" << err.err() << ")" << std::endl; diff --git a/examples/opencl/plotting.cpp b/examples/opencl/plotting.cpp index ba7f8af0..cdae4369 100644 --- a/examples/opencl/plotting.cpp +++ b/examples/opencl/plotting.cpp @@ -24,25 +24,37 @@ using namespace std; const unsigned DIMX = 1000; const unsigned DIMY = 800; -const unsigned WIN_ROWS = 2; -const unsigned WIN_COLS = 2; const float dx = 0.1; const float FRANGE_START = 0.f; const float FRANGE_END = 2 * 3.141592f; const unsigned DATA_SIZE = ( FRANGE_END - FRANGE_START ) / dx; -static const std::string sinf_ocl_kernel = -"kernel void sinf(global float* out, const float dx, const unsigned DATA_SIZE)\n" -"{\n" -" unsigned x = get_global_id(0);\n" -" if(x < DATA_SIZE){\n" -" out[2 * x] = x * dx ;\n" -" out[2 * x + 1] = sin(x*dx);\n" -" }\n" -"}\n"; - -void kernel(cl::Buffer& devOut, cl::CommandQueue& queue) +static const std::string sinf_ocl_kernel = R"( +kernel void sinf(global float* out, const float dx, const unsigned DATA_SIZE, int fnCode) +{ + unsigned x = get_global_id(0); + if(x < DATA_SIZE) { + out[2 * x] = x * dx ; + switch(fnCode) { + case 0: + out[ 2 * x + 1 ] = sin(x*dx); + break; + case 1: + out[ 2 * x + 1 ] = cos(x*dx); + break; + case 2: + out[ 2 * x + 1 ] = tan(x*dx); + break; + case 3: + out[ 2 * x + 1 ] = log10(x*dx); + break; + } + } +} +)"; + +void kernel(cl::Buffer& devOut, cl::CommandQueue& queue, int fnCode) { static std::once_flag compileFlag; static cl::Program prog; @@ -59,6 +71,7 @@ void kernel(cl::Buffer& devOut, cl::CommandQueue& queue) kern.setArg(0, devOut); kern.setArg(1, dx); kern.setArg(2, DATA_SIZE); + kern.setArg(3, fnCode); queue.enqueueNDRangeKernel(kern, cl::NullRange, global); } @@ -70,47 +83,34 @@ int main(void) * so that necessary OpenGL context is created for any * other fg::* object to be created successfully */ - fg::Window wnd(DIMX, DIMY, "Fractal Demo"); + fg::Window wnd(DIMX, DIMY, "Plotting Demo"); wnd.makeCurrent(); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); - /* - * Split the window into grid regions - */ - wnd.grid(WIN_ROWS, WIN_COLS); + fg::Chart chart(FG_CHART_2D); + chart.setAxesLimits(FRANGE_START, FRANGE_END, -1.1f, 1.1f); /* Create several plot objects which creates the necessary * vertex buffer objects to hold the different plot types */ - fg::Plot plt0(DATA_SIZE, fg::f32); //create a default plot - fg::Plot plt1(DATA_SIZE, fg::f32, fg::FG_LINE, fg::FG_NONE); //or specify a specific plot type - fg::Plot plt2(DATA_SIZE, fg::f32, fg::FG_LINE, fg::FG_TRIANGLE); //last parameter specifies marker shape - fg::Plot plt3(DATA_SIZE, fg::f32, fg::FG_SCATTER, fg::FG_POINT); + fg::Plot plt0 = chart.plot(DATA_SIZE, fg::f32); //create a default plot + fg::Plot plt1 = chart.plot(DATA_SIZE, fg::f32, FG_PLOT_LINE, FG_MARKER_NONE); //or specify a specific plot type + fg::Plot plt2 = chart.plot(DATA_SIZE, fg::f32, FG_PLOT_LINE, FG_MARKER_TRIANGLE); //last parameter specifies marker shape + fg::Plot plt3 = chart.plot(DATA_SIZE, fg::f32, FG_PLOT_SCATTER, FG_MARKER_CROSS); /* * Set plot colors */ - plt0.setColor(fg::FG_YELLOW); - plt1.setColor(fg::FG_BLUE); - plt2.setColor(fg::FG_WHITE); //use a forge predefined color - plt3.setColor((fg::Color) 0xABFF01FF); //or any hex-valued color - + plt0.setColor(FG_RED); + plt1.setColor(FG_BLUE); + plt2.setColor(FG_YELLOW); //use a forge predefined color + plt3.setColor((fg::Color) 0x257973FF); //or any hex-valued color /* - * Set draw limits for plots + * Set plot legends */ - plt0.setAxesLimits(FRANGE_END, FRANGE_START, 1.1f, -1.1f); - plt1.setAxesLimits(FRANGE_END, FRANGE_START, 1.1f, -1.1f); - plt2.setAxesLimits(FRANGE_END, FRANGE_START, 1.1f, -1.1f); - plt3.setAxesLimits(FRANGE_END, FRANGE_START, 1.1f, -1.1f); + plt0.setLegend("Sine"); + plt1.setLegend("Cosine"); + plt2.setLegend("Tangent"); + plt3.setLegend("Log base 10"); Platform plat = getPlatform(); // Select the default platform and create a context using this platform and the GPU @@ -156,8 +156,14 @@ int main(void) } } - cl::Buffer devOut(context, CL_MEM_READ_WRITE, sizeof(float) * DATA_SIZE * 2); - kernel(devOut, queue); + cl::Buffer sinOut(context, CL_MEM_READ_WRITE, sizeof(float) * DATA_SIZE * 2); + cl::Buffer cosOut(context, CL_MEM_READ_WRITE, sizeof(float) * DATA_SIZE * 2); + cl::Buffer tanOut(context, CL_MEM_READ_WRITE, sizeof(float) * DATA_SIZE * 2); + cl::Buffer logOut(context, CL_MEM_READ_WRITE, sizeof(float) * DATA_SIZE * 2); + kernel(sinOut, queue, 0); + kernel(cosOut, queue, 1); + kernel(tanOut, queue, 2); + kernel(logOut, queue, 3); /* copy your data into the vertex buffer object exposed by * fg::Plot class and then proceed to rendering. @@ -165,18 +171,13 @@ int main(void) * memory to display memory, Forge provides copy headers * along with the library to help with this task */ - fg::copy(plt0, devOut, queue); - fg::copy(plt1, devOut, queue); - fg::copy(plt2, devOut, queue); - fg::copy(plt3, devOut, queue); + fg::copy(plt0.vertices(), plt0.verticesSize(), sinOut, queue); + fg::copy(plt1.vertices(), plt1.verticesSize(), cosOut, queue); + fg::copy(plt2.vertices(), plt2.verticesSize(), tanOut, queue); + fg::copy(plt3.vertices(), plt3.verticesSize(), logOut, queue); do { - wnd.draw(0, 0, plt0, NULL ); - wnd.draw(0, 1, plt1, "sinf_line_blue" ); - wnd.draw(1, 1, plt2, "sinf_line_triangle" ); - wnd.draw(1, 0, plt3, "sinf_scatter_point" ); - // draw window and poll for events last - wnd.swapBuffers(); + wnd.draw(chart); } while(!wnd.close()); }catch (fg::Error err) { std::cout << err.what() << "(" << err.err() << ")" << std::endl; diff --git a/examples/opencl/surface.cpp b/examples/opencl/surface.cpp index 9552ee20..71ce5134 100644 --- a/examples/opencl/surface.cpp +++ b/examples/opencl/surface.cpp @@ -20,62 +20,82 @@ #include #include "cl_helpers.h" -const unsigned DIMX = 1000; -const unsigned DIMY = 800; - -static const float XMIN = -1.0f; -static const float XMAX = 2.f; -static const float YMIN = -1.0f; -static const float YMAX = 1.f; - -const float DX = 0.01; -const unsigned XSIZE = (XMAX-XMIN)/DX+1; -const unsigned YSIZE = (YMAX-YMIN)/DX+1; +static const float XMIN = -8.0f; +static const float XMAX = 8.f; +static const float YMIN = -8.0f; +static const float YMAX = 8.f; +const float DX = 0.5; +const unsigned XSIZE = (XMAX-XMIN)/DX; +const unsigned YSIZE = (YMAX-YMIN)/DX; using namespace std; -static const std::string sincos_surf_kernel = -"kernel void sincos_surf(global float* out, const float dx, const float t, const float xmin, const float ymin, const unsigned w, const unsigned h)\n" -"{\n" -" int offset = get_global_id(0);\n" -" unsigned i = offset%h;\n" -" unsigned j = offset/h;\n" -"\n" -" float x = xmin + i*dx;\n" -" float y = ymin + j*dx;\n" -" out[offset*3 + 0] = x;\n" -" out[offset*3 + 1] = y;\n" -" out[offset*3 + 2] = 10*x*-fabs(y) * cos(x*x*(y+t))+sin(y*(x+t))-1.5;\n" -"}\n"; - -inline int divup(int a, int b) +static const std::string sin_surf_kernel = +R"EOK( +kernel +void surf(global float* out, const float dx, + const float xmin, const float ymin, + const unsigned w, const unsigned h) { - return (a+b-1)/b; + int i = get_global_id(0); + int j = get_global_id(1); + + float x = xmin + i*dx; + float y = ymin + j*dx; + + if (i(), sincos_surf_kernel, true); - kern = cl::Kernel(prog, "sincos_surf"); - }); +void kernel(cl::Buffer& devOut, cl::CommandQueue& queue, cl::Device& device) +{ + static bool compileFlag = true; + static cl::Program prog; + static cl::Kernel kern; + + if (compileFlag) { + try { + prog = cl::Program(queue.getInfo(), sin_surf_kernel, false); + + std::vector devs; + devs.push_back(device); + prog.build(devs); + + kern = cl::Kernel(prog, "surf"); + } catch (cl::Error err) { + std::cout << "Compile Errors: " << std::endl; + std::cout << err.what() << err.err() << std::endl; + std::cout << prog.getBuildInfo(device) << std::endl; + exit(255); + } + std::cout<< "Kernels compiled successfully" << std::endl; + compileFlag = false; + } - NDRange global(XSIZE*YSIZE); + NDRange local(8, 8); + NDRange global(local[0]*divup(XSIZE, local[0]), + local[1]*divup(YSIZE, local[1])); kern.setArg(0, devOut); kern.setArg(1, DX); - kern.setArg(2, t); - kern.setArg(3, XMIN); - kern.setArg(4, YMIN); - kern.setArg(5, XSIZE); - kern.setArg(6, YSIZE); - queue.enqueueNDRangeKernel(kern, cl::NullRange, global); + kern.setArg(2, XMIN); + kern.setArg(3, YMIN); + kern.setArg(4, XSIZE); + kern.setArg(5, YSIZE); + queue.enqueueNDRangeKernel(kern, cl::NullRange, global, local); } int main(void) @@ -86,39 +106,15 @@ int main(void) * so that necessary OpenGL context is created for any * other fg::* object to be created successfully */ - fg::Window wnd(DIMX, DIMY, "3d Surface Demo"); + fg::Window wnd(1024, 768, "3d Surface Demo"); wnd.makeCurrent(); - /* create an font object and load necessary font - * and later pass it on to window object so that - * it can be used for rendering text */ - fg::Font fnt; -#ifdef OS_WIN - fnt.loadSystemFont("Calibri", 32); -#else - fnt.loadSystemFont("Vera", 32); -#endif - wnd.setFont(&fnt); - /* Create several plot objects which creates the necessary - * vertex buffer objects to hold the different plot types - */ - fg::Surface surf(XSIZE, YSIZE, fg::f32, fg::FG_SURFACE); - - /* - * Set plot colors - */ - surf.setColor(fg::FG_YELLOW); - - /* - * Set draw limits for plots - */ - surf.setAxesLimits(1.1f, -1.1f, 1.1f, -1.1f, 10.f, -5.f); - - /* - * Set axis titles - */ - surf.setAxesTitles("x-axis", "y-axis", "z-axis"); + fg::Chart chart(FG_CHART_3D); + chart.setAxesLimits(-10.f, 10.f, -10.f, 10.f, -0.5f, 1.f); + chart.setAxesTitles("x-axis", "y-axis", "z-axis"); + fg::Surface surf = chart.surface(XSIZE, YSIZE, fg::f32); + surf.setColor(FG_YELLOW); Platform plat = getPlatform(); // Select the default platform and create a context using this platform and the GPU @@ -165,22 +161,18 @@ int main(void) } cl::Buffer devOut(context, CL_MEM_READ_WRITE, sizeof(float) * XSIZE * YSIZE * 3); - static float t=0; - kernel(devOut, queue, t); + + kernel(devOut, queue, device); /* copy your data into the pixel buffer object exposed by * fg::Surface class and then proceed to rendering. * To help the users with copying the data from compute * memory to display memory, Forge provides copy headers * along with the library to help with this task */ - fg::copy(surf, devOut, queue); + fg::copy(surf.vertices(), surf.verticesSize(), devOut, queue); do { - t+=0.07; - kernel(devOut, queue, t); - fg::copy(surf, devOut, queue); - // draw window and poll for events last - wnd.draw(surf); + wnd.draw(chart); } while(!wnd.close()); }catch (fg::Error err) { std::cout << err.what() << "(" << err.err() << ")" << std::endl; diff --git a/include/CPUCopy.hpp b/include/CPUCopy.hpp index 4334bc50..7a474cf9 100644 --- a/include/CPUCopy.hpp +++ b/include/CPUCopy.hpp @@ -10,11 +10,23 @@ #ifndef __CPU_DATA_COPY_H__ #define __CPU_DATA_COPY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus + namespace fg { -template -void copy(fg::Image& out, const T * dataPtr) +static +void copy(fg::Image& out, const void * dataPtr) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, out.pbo()); glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, out.size(), dataPtr); @@ -22,22 +34,19 @@ void copy(fg::Image& out, const T * dataPtr) } /* - * Below functions takes any renderable forge object that has following member functions - * defined - * - * `unsigned Renderable::vbo() const;` - * `unsigned Renderable::size() const;` - * - * Currently fg::Plot, fg::Histogram objects in Forge library fit the bill + * Below functions expects OpenGL resource Id and size in bytes to copy the data from + * cpu memory location to graphics memory */ -template -void copy(Renderable& out, const T * dataPtr) +static +void copy(const int resourceId, const size_t resourceSize, const void * dataPtr) { - glBindBuffer(GL_ARRAY_BUFFER, out.vbo()); - glBufferSubData(GL_ARRAY_BUFFER, 0, out.size(), dataPtr); + glBindBuffer(GL_ARRAY_BUFFER, resourceId); + glBufferSubData(GL_ARRAY_BUFFER, 0, resourceSize, dataPtr); glBindBuffer(GL_ARRAY_BUFFER, 0); } } +#endif + #endif //__CPU_DATA_COPY_H__ diff --git a/include/CUDACopy.hpp b/include/CUDACopy.hpp index 31b8753a..0d640930 100644 --- a/include/CUDACopy.hpp +++ b/include/CUDACopy.hpp @@ -11,6 +11,19 @@ #define __CUDA_DATA_COPY_H__ #include + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus + #include static void handleCUDAError(cudaError_t err, const char *file, int line) @@ -21,7 +34,7 @@ static void handleCUDAError(cudaError_t err, const char *file, int line) } } -#define CUDA_ERROR_CHECK(err) (handleCUDAError(err, __FILE__, __LINE__ )) +#define FORGE_CUDA_CHECK(err) (handleCUDAError(err, __FILE__, __LINE__ )) namespace fg { @@ -30,43 +43,40 @@ template void copy(fg::Image& out, const T * devicePtr) { cudaGraphicsResource *cudaPBOResource; - CUDA_ERROR_CHECK(cudaGraphicsGLRegisterBuffer(&cudaPBOResource, out.pbo(), cudaGraphicsMapFlagsWriteDiscard)); + FORGE_CUDA_CHECK(cudaGraphicsGLRegisterBuffer(&cudaPBOResource, out.pbo(), cudaGraphicsMapFlagsWriteDiscard)); size_t num_bytes; T* pboDevicePtr = NULL; - CUDA_ERROR_CHECK(cudaGraphicsMapResources(1, &cudaPBOResource, 0)); - CUDA_ERROR_CHECK(cudaGraphicsResourceGetMappedPointer((void **)&pboDevicePtr, &num_bytes, cudaPBOResource)); - CUDA_ERROR_CHECK(cudaMemcpy(pboDevicePtr, devicePtr, num_bytes, cudaMemcpyDeviceToDevice)); - CUDA_ERROR_CHECK(cudaGraphicsUnmapResources(1, &cudaPBOResource, 0)); - CUDA_ERROR_CHECK(cudaGraphicsUnregisterResource(cudaPBOResource)); + FORGE_CUDA_CHECK(cudaGraphicsMapResources(1, &cudaPBOResource, 0)); + FORGE_CUDA_CHECK(cudaGraphicsResourceGetMappedPointer((void **)&pboDevicePtr, &num_bytes, cudaPBOResource)); + FORGE_CUDA_CHECK(cudaMemcpy(pboDevicePtr, devicePtr, num_bytes, cudaMemcpyDeviceToDevice)); + FORGE_CUDA_CHECK(cudaGraphicsUnmapResources(1, &cudaPBOResource, 0)); + FORGE_CUDA_CHECK(cudaGraphicsUnregisterResource(cudaPBOResource)); } /* - * Below functions takes any renderable forge object that has following member functions - * defined - * - * `unsigned Renderable::vbo() const;` - * `unsigned Renderable::size() const;` - * - * Currently fg::Plot, fg::Histogram objects in Forge library fit the bill + * Below functions expects OpenGL resource Id and size in bytes to copy the data from + * CUDA device memory location to graphics memory */ -template -void copy(Renderable& out, const T * devicePtr) +template +void copy(const int resourceId, const T * devicePtr) { cudaGraphicsResource *cudaVBOResource; - CUDA_ERROR_CHECK(cudaGraphicsGLRegisterBuffer(&cudaVBOResource, out.vbo(), cudaGraphicsMapFlagsWriteDiscard)); - + FORGE_CUDA_CHECK(cudaGraphicsGLRegisterBuffer(&cudaVBOResource, resourceId, + cudaGraphicsMapFlagsWriteDiscard)); size_t num_bytes; T* vboDevicePtr = NULL; - CUDA_ERROR_CHECK(cudaGraphicsMapResources(1, &cudaVBOResource, 0)); - CUDA_ERROR_CHECK(cudaGraphicsResourceGetMappedPointer((void **)&vboDevicePtr, &num_bytes, cudaVBOResource)); - CUDA_ERROR_CHECK(cudaMemcpy(vboDevicePtr, devicePtr, num_bytes, cudaMemcpyDeviceToDevice)); - CUDA_ERROR_CHECK(cudaGraphicsUnmapResources(1, &cudaVBOResource, 0)); - CUDA_ERROR_CHECK(cudaGraphicsUnregisterResource(cudaVBOResource)); + FORGE_CUDA_CHECK(cudaGraphicsMapResources(1, &cudaVBOResource, 0)); + FORGE_CUDA_CHECK(cudaGraphicsResourceGetMappedPointer((void **)&vboDevicePtr, &num_bytes, cudaVBOResource)); + FORGE_CUDA_CHECK(cudaMemcpy(vboDevicePtr, devicePtr, num_bytes, cudaMemcpyDeviceToDevice)); + FORGE_CUDA_CHECK(cudaGraphicsUnmapResources(1, &cudaVBOResource, 0)); + FORGE_CUDA_CHECK(cudaGraphicsUnregisterResource(cudaVBOResource)); } } +#endif + #endif //__CUDA_DATA_COPY_H__ diff --git a/include/OpenCLCopy.hpp b/include/OpenCLCopy.hpp index 7f0db3a7..0b2211fb 100644 --- a/include/OpenCLCopy.hpp +++ b/include/OpenCLCopy.hpp @@ -10,10 +10,23 @@ #ifndef __OPENCL_DATA_COPY_H__ #define __OPENCL_DATA_COPY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus + namespace fg { -static void copy(fg::Image& out, const cl::Buffer& in, const cl::CommandQueue& queue) +static +void copy(fg::Image& out, const cl::Buffer& in, const cl::CommandQueue& queue) { cl::BufferGL pboMapBuffer(queue.getInfo(), CL_MEM_WRITE_ONLY, out.pbo(), NULL); @@ -28,29 +41,27 @@ static void copy(fg::Image& out, const cl::Buffer& in, const cl::CommandQueue& q } /* - * Below functions takes any renderable forge object that has following member functions - * defined - * - * `unsigned Renderable::vbo() const;` - * `unsigned Renderable::size() const;` - * - * Currently fg::Plot, fg::Histogram objects in Forge library fit the bill + * Below functions expects OpenGL resource Id and size in bytes to copy the data from + * OpenCL Buffer to graphics memory */ -template -void copy(Renderable& out, const cl::Buffer& in, const cl::CommandQueue& queue) +static +void copy(const int resourceId, const size_t resourceSize, + const cl::Buffer& in, const cl::CommandQueue& queue) { - cl::BufferGL vboMapBuffer(queue.getInfo(), CL_MEM_WRITE_ONLY, out.vbo(), NULL); + cl::BufferGL vboMapBuffer(queue.getInfo(), CL_MEM_WRITE_ONLY, resourceId, NULL); std::vector shared_objects; shared_objects.push_back(vboMapBuffer); glFinish(); queue.enqueueAcquireGLObjects(&shared_objects); - queue.enqueueCopyBuffer(in, vboMapBuffer, 0, 0, out.size(), NULL, NULL); + queue.enqueueCopyBuffer(in, vboMapBuffer, 0, 0, resourceSize, NULL, NULL); queue.finish(); queue.enqueueReleaseGLObjects(&shared_objects); } } +#endif + #endif //__OPENCL_DATA_COPY_H__ diff --git a/include/fg/chart.h b/include/fg/chart.h new file mode 100644 index 00000000..88b1f2b9 --- /dev/null +++ b/include/fg/chart.h @@ -0,0 +1,241 @@ +/******************************************************* + * 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 + + +#ifdef __cplusplus +extern "C" { +#endif + +FGAPI fg_err fg_create_chart(fg_chart *pHandle, + const fg_chart_type pChartType); + +FGAPI fg_err fg_destroy_chart(fg_chart pHandle); + +FGAPI fg_err fg_set_chart_axes_titles(fg_chart pHandle, + const char* pX, + const char* pY, + const char* pZ); + +FGAPI fg_err fg_set_chart_axes_limits(fg_chart pHandle, + const float pXmin, const float pXmax, + const float pYmin, const float pYmax, + const float pZmin, const float pZmax); + +FGAPI fg_err fg_set_chart_legend_position(fg_chart pHandle, const float pX, const float pY); + +FGAPI fg_err fg_add_image_to_chart(fg_image* pImage, fg_chart pHandle, + const uint pWidth, const uint pHeight, + const fg_channel_format pFormat, + const fg_dtype pType); + +FGAPI fg_err fg_add_histogram_to_chart(fg_histogram* pHistogram, fg_chart pHandle, + const uint pNBins, const fg_dtype pType); + +FGAPI fg_err fg_add_plot_to_chart(fg_plot* pPlot, fg_chart pHandle, + const uint pNPoints, const fg_dtype pType, + const fg_plot_type pPlotType, const fg_marker_type pMarkerType); + +FGAPI fg_err fg_add_surface_to_chart(fg_surface* pSurface, fg_chart pHandle, + const uint pXPoints, const uint pYPoints, const fg_dtype pType, + const fg_plot_type pPlotType, const fg_marker_type pMarkerType); + +FGAPI fg_err fg_render_chart(const fg_window pWindow, + const fg_chart pChart, + const int pX, const int pY, const int pWidth, const int pHeight, + const float* pTransform); + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus + +namespace fg +{ + +/** + \class Chart + + \brief Chart is base canvas where other plottable objects are rendered. + + Charts come in two types: + - \ref FG_2D - Two dimensional charts + - \ref FG_3D - Three dimensional charts + */ +class Chart { + private: + fg_chart mValue; + + public: + /** + Creates a Chart object with given dimensional property + + \param[in] cType is chart dimension property + */ + FGAPI Chart(const ChartType cType); + + /** + Chart copy constructor + */ + FGAPI Chart(const Chart& pOther); + + /** + Chart destructor + */ + FGAPI ~Chart(); + + /** + Set axes titles for the chart + + \param[in] pX is x-axis title label + \param[in] pY is y-axis title label + \param[in] pZ is z-axis title label + */ + FGAPI void setAxesTitles(const char* pX, + const char* pY, + const char* pZ=NULL); + + /** + Set axes data ranges + + \param[in] pXmin is x-axis minimum data value + \param[in] pXmax is x-axis maximum data value + \param[in] pYmin is y-axis minimum data value + \param[in] pYmax is y-axis maximum data value + \param[in] pZmin is z-axis minimum data value + \param[in] pZmax is z-axis maximum data value + */ + FGAPI void setAxesLimits(const float pXmin, const float pXmax, + const float pYmin, const float pYmax, + const float pZmin=-1, const float pZmax=1); + + /** + Set legend position for Chart + + \param[in] pX is horizontal position in normalized coordinates + \param[in] pY is vertical position in normalized coordinates + + \note By normalized coordinates, the range of these coordinates is expected to be [0-1]. + (0,0) is the bottom hand left corner. + */ + FGAPI void setLegendPosition(const float pX, const float pY); + + /** + Add an existing Image object to the current chart + + \param[in] pImage is the Image to render on the chart + */ + FGAPI void add(const Image& pImage); + + /** + Add an existing Histogram object to the current chart + + \param[in] pHistogram is the Histogram to render on the chart + */ + FGAPI void add(const Histogram& pHistogram); + + /** + Add an existing Plot object to the current chart + + \param[in] pPlot is the Plot to render on the chart + */ + FGAPI void add(const Plot& pPlot); + + /** + Add an existing Surface object to the current chart + + \param[in] pSurface is the Surface to render on the chart + */ + FGAPI void add(const Surface& pSurface); + + /** + Create and add an Image object to the current chart + + \param[in] pWidth Width of the image + \param[in] pHeight Height of the image + \param[in] pFormat Color channel format of image, uses one of the values + of \ref ChannelFormat + \param[in] pDataType takes one of the values of \ref dtype that indicates + the integral data type of histogram data + */ + FGAPI Image image(const uint pWidth, const uint pHeight, + const ChannelFormat pFormat=FG_RGBA, const dtype pDataType=f32); + + /** + Create and add an Histogram object to the current chart + + \param[in] pNBins is number of bins the data is sorted out + \param[in] pDataType takes one of the values of \ref dtype that indicates + the integral data type of histogram data + */ + FGAPI Histogram histogram(const uint pNBins, const dtype pDataType); + + /** + Create and add an Plot object to the current chart + + \param[in] pNumPoints is number of data points to display + \param[in] pDataType takes one of the values of \ref dtype that indicates + the integral data type of plot data + \param[in] pPlotType dictates the type of plot/graph, + it can take one of the values of \ref PlotType + \param[in] pMarkerType indicates which symbol is rendered as marker. It can take one of + the values of \ref MarkerType. + */ + FGAPI Plot plot(const uint pNumPoints, const dtype pDataType, + const PlotType pPlotType=FG_PLOT_LINE, const MarkerType pMarkerType=FG_MARKER_NONE); + + /** + Create and add an Plot object to the current chart + + \param[in] pNumXPoints is number of data points along X dimension + \param[in] pNumYPoints is number of data points along Y dimension + \param[in] pDataType takes one of the values of \ref dtype that indicates + the integral data type of plot data + \param[in] pPlotType is the render type which can be one of \ref PlotType (valid choices + are FG_SURFACE and FG_SCATTER) + \param[in] pMarkerType is the type of \ref MarkerType to draw for \ref FG_SCATTER plot type + */ + FGAPI Surface surface(const uint pNumXPoints, const uint pNumYPoints, const dtype pDataType, + const PlotType pPlotType=FG_PLOT_SURFACE, const MarkerType pMarkerType=FG_MARKER_NONE); + + /** + Render the chart to given window + + \param[in] pWindow is target window to where chart will be rendered + \param[in] pX is x coordinate of origin of viewport in window coordinates + \param[in] pY is y coordinate of origin of viewport in window coordinates + \param[in] pVPW is the width of the viewport + \param[in] pVPH is the height of the viewport + \param[in] pTransform is an array of floats. This array is expected to contain + at least 16 elements + + Note: pTransform array is assumed to be of expected length. + */ + FGAPI void render(const Window& pWindow, + const int pX, const int pY, const int pVPW, const int pVPH, + const float* pTransform) const; + + /** + Get the handle to internal implementation of Chart + */ + FGAPI fg_chart get() const; +}; + +} + +#endif diff --git a/include/fg/defines.h b/include/fg/defines.h index aff86208..fd8fd79b 100644 --- a/include/fg/defines.h +++ b/include/fg/defines.h @@ -47,11 +47,20 @@ */ FGAPI GLEWContext* glewGetContext(); -namespace fg -{ - -enum ErrorCode { - FG_SUCCESS = 0, ///< Fuction returned successfully. +typedef void* fg_window; +typedef void* fg_font; +typedef void* fg_chart; +typedef void* fg_image; +typedef void* fg_histogram; +typedef void* fg_plot; +typedef void* fg_surface; + +typedef unsigned int uint; +typedef unsigned short ushort; +typedef unsigned char uchar; + +typedef enum { + FG_ERR_NONE = 0, ///< Fuction returned successfully. /* * Arguement related error codes that are * generated when invalid arguments are @@ -88,6 +97,17 @@ enum ErrorCode { * */ FG_ERR_NOT_SUPPORTED = 5001, ///< Feature not supported FG_ERR_NOT_CONFIGURED = 5002, ///< Library configuration mismatch + /* + * Font config related error codes + * '6**' + * */ + FG_ERR_FONTCONFIG_ERROR = 6001, ///< Fontconfig related error + /* + * FreeImage errors + */ + FG_ERR_FREEIMAGE_UNKNOWN_FORMAT = 7001, ///< Unknown format, not supported by freeimage + FG_ERR_FREEIMAGE_BAD_ALLOC = 7002, ///< freeimage memory allocation failed + FG_ERR_FREEIMAGE_SAVE_FAILED = 7003, ///< freeimage file save failed /* * other error codes * match the following pattern @@ -96,33 +116,38 @@ enum ErrorCode { FG_ERR_INTERNAL = 9001, ///< Internal error FG_ERR_RUNTIME = 9002, ///< Runtime error FG_ERR_UNKNOWN = 9003 ///< Unkown error -}; +} fg_err; -enum ChannelFormat { +typedef enum { FG_GRAYSCALE = 100, ///< Single channel FG_RG = 200, ///< Three(Red, Green & Blue) channels FG_RGB = 300, ///< Three(Red, Green & Blue) channels FG_BGR = 301, ///< Three(Red, Green & Blue) channels FG_RGBA = 400, ///< Four(Red, Green, Blue & Alpha) channels FG_BGRA = 401 ///< Four(Red, Green, Blue & Alpha) channels -}; +} fg_channel_format; + +typedef enum { + FG_CHART_2D = 2, ///< Two dimensional charts + FG_CHART_3D = 3 ///< Three dimensional charts +} fg_chart_type; /** Color maps \image html gfx_palette.png */ -enum ColorMap { - FG_DEFAULT_MAP = 0, ///< Default [0-255] grayscale colormap - FG_SPECTRUM_MAP = 1, ///< Spectrum color - FG_COLORS_MAP = 2, ///< Pure Colors - FG_RED_MAP = 3, ///< Red color map - FG_MOOD_MAP = 4, ///< Mood color map - FG_HEAT_MAP = 5, ///< Heat color map - FG_BLUE_MAP = 6 ///< Blue color map -}; - -enum Color { +typedef enum { + FG_COLOR_MAP_DEFAULT = 0, ///< Default [0-255] grayscale colormap + FG_COLOR_MAP_SPECTRUM = 1, ///< Spectrum color + FG_COLOR_MAP_COLORS = 2, ///< Pure Colors + FG_COLOR_MAP_RED = 3, ///< Red color map + FG_COLOR_MAP_MOOD = 4, ///< Mood color map + FG_COLOR_MAP_HEAT = 5, ///< Heat color map + FG_COLOR_MAP_BLUE = 6 ///< Blue color map +} fg_color_map; + +typedef enum { FG_RED = 0xFF0000FF, FG_GREEN = 0x00FF00FF, FG_BLUE = 0x0000FFFF, @@ -131,33 +156,55 @@ enum Color { FG_MAGENTA = 0xFF00FFFF, FG_WHITE = 0xFFFFFFFF, FG_BLACK = 0x000000FF -}; - -enum dtype { - s8 = 0, ///< Signed byte (8-bits) - u8 = 1, ///< Unsigned byte (8-bits) - s32 = 2, ///< Signed integer (32-bits) - u32 = 3, ///< Unsigned integer (32-bits) - f32 = 4, ///< Float (32-bits) - s16 = 5, ///< Signed integer (16-bits) - u16 = 6 ///< Unsigned integer (16-bits) -}; - -enum PlotType { - FG_LINE = 0, - FG_SCATTER = 1, - FG_SURFACE = 2 -}; - -enum MarkerType { - FG_NONE = 0, - FG_POINT = 1, - FG_CIRCLE = 2, - FG_SQUARE = 3, - FG_TRIANGLE = 4, - FG_CROSS = 5, - FG_PLUS = 6, - FG_STAR = 7 -}; - +} fg_color; + +typedef enum { + FG_INT8 = 0, ///< Signed byte (8-bits) + FG_UINT8 = 1, ///< Unsigned byte (8-bits) + FG_INT32 = 2, ///< Signed integer (32-bits) + FG_UINT32 = 3, ///< Unsigned integer (32-bits) + FG_FLOAT32 = 4, ///< Float (32-bits) + FG_INT16 = 5, ///< Signed integer (16-bits) + FG_UINT16 = 6 ///< Unsigned integer (16-bits) +} fg_dtype; + +typedef enum { + FG_PLOT_LINE = 0, ///< Line plot + FG_PLOT_SCATTER = 1, ///< Scatter plot + FG_PLOT_SURFACE = 2 ///< Surface plot +} fg_plot_type; + +typedef enum { + FG_MARKER_NONE = 0, ///< No marker + FG_MARKER_POINT = 1, ///< Point marker + FG_MARKER_CIRCLE = 2, ///< Circle marker + FG_MARKER_SQUARE = 3, ///< Square marker + FG_MARKER_TRIANGLE = 4, ///< Triangle marker + FG_MARKER_CROSS = 5, ///< Cross-hair marker + FG_MARKER_PLUS = 6, ///< Plus symbol marker + FG_MARKER_STAR = 7 ///< Star symbol marker +} fg_marker_type; + + +#ifdef __cplusplus +namespace fg +{ + typedef fg_err ErrorCode; + typedef fg_channel_format ChannelFormat; + typedef fg_chart_type ChartType; + typedef fg_color_map ColorMap; + typedef fg_color Color; + typedef fg_plot_type PlotType; + typedef fg_marker_type MarkerType; + + typedef enum { + s8 = FG_INT8, + u8 = FG_UINT8, + s32 = FG_INT32, + u32 = FG_UINT32, + f32 = FG_FLOAT32, + s16 = FG_INT16, + u16 = FG_UINT16, + } dtype; } +#endif diff --git a/include/fg/exception.h b/include/fg/exception.h index b6215741..07381f0f 100644 --- a/include/fg/exception.h +++ b/include/fg/exception.h @@ -10,6 +10,8 @@ #pragma once #include + +#ifdef __cplusplus #include #include @@ -106,3 +108,5 @@ class FGAPI DimensionError : public Error }; } + +#endif // __cplusplus diff --git a/include/fg/font.h b/include/fg/font.h index c34b3942..c9156b9b 100644 --- a/include/fg/font.h +++ b/include/fg/font.h @@ -10,10 +10,24 @@ #pragma once #include -namespace internal -{ -class _Font; +#ifdef __cplusplus +extern "C" { +#endif + +FGAPI fg_err fg_create_font(fg_font* pFont); + +FGAPI fg_err fg_destroy_font(fg_font pFont); + +FGAPI fg_err fg_load_font_file(fg_font pFont, const char* const pFileFullPath); + +FGAPI fg_err fg_load_system_font(fg_font pFont, const char* const pFontName); + +#ifdef __cplusplus } +#endif + + +#ifdef __cplusplus namespace fg { @@ -25,7 +39,7 @@ namespace fg */ class Font { private: - internal::_Font* value; + fg_font mValue; public: /** @@ -49,22 +63,22 @@ class Font { Load a given font file \param[in] pFile True Type Font file path - \param[in] pFontSize the size of the font glyphs that will be created */ - FGAPI void loadFont(const char* const pFile, int pFontSize); + FGAPI void loadFontFile(const char* const pFile); /** Load a system font based on the name \param[in] pName True Type Font name - \param[in] pFontSize the size of the font glyphs that will be created */ - FGAPI void loadSystemFont(const char* const pName, int pFontSize); + FGAPI void loadSystemFont(const char* const pName); /** Get handle for internal implementation of Font object */ - FGAPI internal::_Font* get() const; + FGAPI fg_font get() const; }; } + +#endif diff --git a/include/fg/histogram.h b/include/fg/histogram.h index 9e5ffd75..55b328aa 100644 --- a/include/fg/histogram.h +++ b/include/fg/histogram.h @@ -11,10 +11,40 @@ #include -namespace internal -{ -class _Histogram; + +#ifdef __cplusplus +extern "C" { +#endif + +FGAPI fg_err fg_create_histogram(fg_histogram *pHistogram, + const uint nbins, const fg_dtype type); + +FGAPI fg_err fg_destroy_histogram(fg_histogram pHistogram); + +FGAPI fg_err fg_set_histogram_color(fg_histogram pHistogram, + const float pRed, const float pGreen, + const float pBlue, const float pAlpha); + +FGAPI fg_err fg_set_histogram_legend(fg_histogram pHistogram, const char* pLegend); + +FGAPI fg_err fg_get_histogram_vbo(uint* out, const fg_histogram pHistogram); + +FGAPI fg_err fg_get_histogram_cbo(uint* out, const fg_histogram pHistogram); + +FGAPI fg_err fg_get_histogram_abo(uint* out, const fg_histogram pHistogram); + +FGAPI fg_err fg_get_histogram_vbo_size(uint* out, const fg_histogram pHistogram); + +FGAPI fg_err fg_get_histogram_cbo_size(uint* out, const fg_histogram pHistogram); + +FGAPI fg_err fg_get_histogram_abo_size(uint* out, const fg_histogram pHistogram); + +#ifdef __cplusplus } +#endif + + +#ifdef __cplusplus namespace fg { @@ -22,11 +52,11 @@ namespace fg /** \class Histogram - \brief Bar graph to display data frequencey. + \brief Histogram is a bar graph to display data frequencey. */ class Histogram { private: - internal::_Histogram* value; + fg_histogram mValue; public: /** @@ -36,14 +66,14 @@ class Histogram { \param[in] pDataType takes one of the values of \ref dtype that indicates the integral data type of histogram data */ - FGAPI Histogram(unsigned pNBins, dtype pDataType); + FGAPI Histogram(const uint pNBins, const dtype pDataType); /** Copy constructor for Histogram - \param[in] other is the Histogram of which we make a copy of. + \param[in] pOther is the Histogram of which we make a copy of. */ - FGAPI Histogram(const Histogram& other); + FGAPI Histogram(const Histogram& pOther); /** Histogram Destructor @@ -53,84 +83,82 @@ class Histogram { /** Set the color of bar in the bar graph(histogram) - \param[in] col takes values of type fg::Color to define bar color + \param[in] pColor takes values of type fg::Color to define bar color **/ - FGAPI void setBarColor(fg::Color col); - + FGAPI void setColor(const Color pColor); /** Set the color of bar in the bar graph(histogram) + 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() + \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 setBarColor(float pRed, float pGreen, float pBlue); - - /** - Set the chart axes limits - - \param[in] pXmax is X-Axis maximum value - \param[in] pXmin is X-Axis minimum value - \param[in] pYmax is Y-Axis maximum value - \param[in] pYmin is Y-Axis minimum value - */ - FGAPI void setAxesLimits(float pXmax, float pXmin, float pYmax, float pYmin); + FGAPI void setColor(const float pRed, const float pGreen, + const float pBlue, const float pAlpha); /** - Set axes titles in histogram(bar chart) + Set legend for histogram plot - \param[in] pXTitle is X-Axis title - \param[in] pYTitle is Y-Axis title + \param[in] pLegend */ - FGAPI void setAxesTitles(const char* pXTitle, const char* pYTitle); + FGAPI void setLegend(const char* pLegend); /** - Get X-Axis maximum value + Get the OpenGL buffer object identifier for vertices - \return Maximum value along X-Axis + \return OpenGL VBO resource id. */ - FGAPI float xmax() const; + FGAPI uint vertices() const; /** - Get X-Axis minimum value + Get the OpenGL buffer object identifier for color values per vertex - \return Minimum value along X-Axis + \return OpenGL VBO resource id. */ - FGAPI float xmin() const; + FGAPI uint colors() const; /** - Get Y-Axis maximum value + Get the OpenGL buffer object identifier for alpha values per vertex - \return Maximum value along Y-Axis + \return OpenGL VBO resource id. */ - FGAPI float ymax() const; + FGAPI uint alphas() const; /** - Get Y-Axis minimum value + Get the OpenGL Vertex Buffer Object resource size - \return Minimum value along Y-Axis + \return vertex buffer object size in bytes */ - FGAPI float ymin() const; + FGAPI uint verticesSize() const; /** - Get the OpenGL Vertex Buffer Object identifier + Get the OpenGL Vertex Buffer Object resource size - \return OpenGL VBO resource id. + \return colors buffer object size in bytes */ - FGAPI unsigned vbo() const; + FGAPI uint colorsSize() const; /** Get the OpenGL Vertex Buffer Object resource size - \return OpenGL VBO resource size. + \return alpha buffer object size in bytes */ - FGAPI unsigned size() const; + FGAPI uint alphasSize() const; /** Get the handle to internal implementation of Histogram */ - FGAPI internal::_Histogram* get() const; + FGAPI fg_histogram get() const; }; } + +#endif diff --git a/include/fg/image.h b/include/fg/image.h index 3e51a057..a5a58f3a 100644 --- a/include/fg/image.h +++ b/include/fg/image.h @@ -11,20 +11,58 @@ #include -namespace internal -{ -class _Image; + +#ifdef __cplusplus +extern "C" { +#endif + +FGAPI fg_err fg_create_image(fg_image* pImage, + const uint pWidth, const uint pHeight, + const fg_channel_format pFormat, const fg_dtype pType); + +FGAPI fg_err fg_destroy_image(fg_image pImage); + +FGAPI fg_err fg_set_image_alpha(fg_image pImage, const float pAlpha); + +FGAPI fg_err fg_set_image_aspect_ratio(fg_image pImage, const bool pKeepRatio); + +FGAPI fg_err fg_get_image_width(uint *pOut, const fg_image pImage); + +FGAPI fg_err fg_get_image_height(uint *pOut, const fg_image pImage); + +FGAPI fg_err fg_get_image_pixelformat(fg_channel_format* pOut, const fg_image pImage); + +FGAPI fg_err fg_get_image_type(fg_dtype* pOut, const fg_image pImage); + +FGAPI fg_err fg_get_image_pbo(uint* pOut, const fg_image pImage); + +FGAPI fg_err fg_get_image_pbo_size(uint* pOut, const fg_image pImage); + +FGAPI fg_err fg_render_image(const fg_window pWindow, + const fg_image pImage, + const int pX, const int pY, const int pWidth, const int pHeight, + const float* pTransform); + +#ifdef __cplusplus } +#endif + + +#ifdef __cplusplus namespace fg { +class Window; + /** \class Image + + \brief Image is plain rendering of an image over the window or sub-region of it. */ class Image { private: - internal::_Image* value; + fg_image mValue; public: /** @@ -37,31 +75,46 @@ class Image { \param[in] pDataType takes one of the values of \ref dtype that indicates the integral data type of histogram data */ - FGAPI Image(unsigned pWidth, unsigned pHeight, ChannelFormat pFormat, dtype pDataType); + FGAPI Image(const uint pWidth, const uint pHeight, + const ChannelFormat pFormat=FG_RGBA, const dtype pDataType=f32); /** Copy constructor of Image - \param[in] other is the Image of which we make a copy of. + \param[in] pOther is the Image of which we make a copy of. */ - FGAPI Image(const Image& other); + FGAPI Image(const Image& pOther); /** Image Destructor */ FGAPI ~Image(); + /** + Set a global alpha value for rendering the image + + \param[in] pAlpha + */ + FGAPI void setAlpha(const float pAlpha); + + /** + Set option to inform whether to maintain aspect ratio of original image + + \param[in] pKeep + */ + FGAPI void keepAspectRatio(const bool pKeep); + /** Get Image width \return image width */ - FGAPI unsigned width() const; + FGAPI uint width() const; /** Get Image height \return image width */ - FGAPI unsigned height() const; + FGAPI uint height() const; /** Get Image's channel format @@ -80,19 +133,38 @@ class Image { \return OpenGL PBO resource id. */ - FGAPI unsigned pbo() const; + FGAPI uint pbo() const; /** Get the OpenGL Pixel Buffer Object resource size \return OpenGL PBO resource size. */ - FGAPI unsigned size() const; + FGAPI uint size() const; + + /** + Render the image to given window + + \param[in] pWindow is target window to where image will be rendered + \param[in] pX is x coordinate of origin of viewport in window coordinates + \param[in] pY is y coordinate of origin of viewport in window coordinates + \param[in] pVPW is the width of the viewport + \param[in] pVPH is the height of the viewport + \param[in] pTransform is an array of floats. This array is expected to contain + at least 16 elements + + Note: pTransform array is assumed to be of expected length. + */ + FGAPI void render(const Window& pWindow, + const int pX, const int pY, const int pVPW, const int pVPH, + const float* pTransform) const; /** Get the handle to internal implementation of Image */ - FGAPI internal::_Image* get() const; + FGAPI fg_image get() const; }; } + +#endif diff --git a/include/fg/plot.h b/include/fg/plot.h index 18b121bb..56173900 100644 --- a/include/fg/plot.h +++ b/include/fg/plot.h @@ -11,10 +11,49 @@ #include -namespace internal -{ -class _Plot; + +#ifdef __cplusplus +extern "C" { +#endif + +FGAPI fg_err fg_create_plot(fg_plot *pPlot, + const uint pNPoints, const fg_dtype pType, + const fg_chart_type pChartType, + const fg_plot_type pPlotType, + const fg_marker_type pMarkerType); + +FGAPI fg_err fg_destroy_plot(fg_plot pPlot); + +FGAPI fg_err fg_set_plot_color(fg_plot pPlot, + const float pRed, const float pGreen, + const float pBlue, const float pAlpha); + +FGAPI fg_err fg_set_plot_legend(fg_plot pPlot, const char* pLegend); + +FGAPI fg_err fg_set_plot_marker_size(fg_plot pPlot, const float pMarkerSize); + +FGAPI fg_err fg_get_plot_vbo(uint* pOut, const fg_plot pPlot); + +FGAPI fg_err fg_get_plot_cbo(uint* pOut, const fg_plot pPlot); + +FGAPI fg_err fg_get_plot_abo(uint* pOut, const fg_plot pPlot); + +FGAPI fg_err fg_get_plot_mbo(uint* pOut, const fg_plot pPlot); + +FGAPI fg_err fg_get_plot_vbo_size(uint* pOut, const fg_plot pPlot); + +FGAPI fg_err fg_get_plot_cbo_size(uint* pOut, const fg_plot pPlot); + +FGAPI fg_err fg_get_plot_abo_size(uint* pOut, const fg_plot pPlot); + +FGAPI fg_err fg_get_plot_mbo_size(uint* pOut, const fg_plot pPlot); + +#ifdef __cplusplus } +#endif + + +#ifdef __cplusplus namespace fg { @@ -22,11 +61,11 @@ namespace fg /** \class Plot - \brief Line graph to display plots. + \brief Plot is a line graph to display two dimensional data. */ class Plot { private: - internal::_Plot* value; + fg_plot mValue; public: /** @@ -35,15 +74,21 @@ class Plot { \param[in] pNumPoints is number of data points to display \param[in] pDataType takes one of the values of \ref dtype that indicates the integral data type of plot data + \param[in] pChartType dictates the dimensionality of the chart + \param[in] pPlotType dictates the type of plot/graph, + it can take one of the values of \ref PlotType + \param[in] pMarkerType indicates which symbol is rendered as marker. It can take one of + the values of \ref MarkerType. */ - FGAPI Plot(unsigned pNumPoints, dtype pDataType, fg::PlotType=fg::FG_LINE, fg::MarkerType=fg::FG_NONE); + FGAPI Plot(const uint pNumPoints, const dtype pDataType, const ChartType pChartType, + const PlotType pPlotType=FG_PLOT_LINE, const MarkerType pMarkerType=FG_MARKER_NONE); /** Copy constructor for Plot - \param[in] other is the Plot of which we make a copy of. + \param[in] pOther is the Plot of which we make a copy of. */ - FGAPI Plot(const Plot& other); + FGAPI Plot(const Plot& pOther); /** Plot Destructor @@ -53,9 +98,9 @@ class Plot { /** Set the color of line graph(plot) - \param[in] col takes values of fg::Color to define plot color + \param[in] pColor takes values of fg::Color to define plot color */ - FGAPI void setColor(fg::Color col); + FGAPI void setColor(const fg::Color pColor); /** Set the color of line graph(plot) @@ -63,73 +108,90 @@ class Plot { \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 Blue component in range [0, 1] */ - FGAPI void setColor(float pRed, float pGreen, float pBlue); + FGAPI void setColor(const float pRed, const float pGreen, + const float pBlue, const float pAlpha); /** - Set the chart axes limits + Set plot legend - \param[in] pXmax is X-Axis maximum value - \param[in] pXmin is X-Axis minimum value - \param[in] pYmax is Y-Axis maximum value - \param[in] pYmin is Y-Axis minimum value + \param[in] pLegend */ - FGAPI void setAxesLimits(float pXmax, float pXmin, float pYmax, float pYmin); + FGAPI void setLegend(const char* pLegend); /** - Set axes titles in histogram(bar chart) + Set global marker size - \param[in] pXTitle is X-Axis title - \param[in] pYTitle is Y-Axis title + This size will be used for rendering markers if no per vertex marker sizes are provided. + This value defaults to 10 + + \param[in] pMarkerSize is the target marker size for scatter plots or line plots with markers */ - FGAPI void setAxesTitles(const char* pXTitle, const char* pYTitle); + FGAPI void setMarkerSize(const float pMarkerSize); /** - Get X-Axis maximum value + Get the OpenGL buffer object identifier for vertices - \return Maximum value along X-Axis + \return OpenGL VBO resource id. */ - FGAPI float xmax() const; + FGAPI uint vertices() const; /** - Get X-Axis minimum value + Get the OpenGL buffer object identifier for color values per vertex - \return Minimum value along X-Axis + \return OpenGL VBO resource id. */ - FGAPI float xmin() const; + FGAPI uint colors() const; /** - Get Y-Axis maximum value + Get the OpenGL buffer object identifier for alpha values per vertex - \return Maximum value along Y-Axis + \return OpenGL VBO resource id. */ - FGAPI float ymax() const; + FGAPI uint alphas() const; /** - Get Y-Axis minimum value + Get the OpenGL buffer object identifier for markers sizes, per vertex - \return Minimum value along Y-Axis + \return OpenGL VBO resource id. */ - FGAPI float ymin() const; + FGAPI uint markers() const; /** - Get the OpenGL Vertex Buffer Object identifier + Get the OpenGL Vertex Buffer Object resource size - \return OpenGL VBO resource id. + \return vertex buffer object size in bytes */ - FGAPI unsigned vbo() const; + FGAPI uint verticesSize() const; /** - Get the OpenGL Vertex Buffer Object resource size + Get the OpenGL colors Buffer Object resource size - \return OpenGL VBO resource size. + \return colors buffer object size in bytes */ - FGAPI unsigned size() const; + FGAPI uint colorsSize() const; /** - Get the handle to internal implementation of Histogram + Get the OpenGL alpha Buffer Object resource size + + \return alpha buffer object size in bytes */ - FGAPI internal::_Plot* get() const; + FGAPI uint alphasSize() const; + + /** + Get the OpenGL markers Buffer Object resource size + + \return alpha buffer object size in bytes + */ + FGAPI uint markersSize() const; + + /** + Get the handle to internal implementation of plot + */ + FGAPI fg_plot get() const; }; } + +#endif diff --git a/include/fg/plot3.h b/include/fg/plot3.h deleted file mode 100644 index cda08bcf..00000000 --- a/include/fg/plot3.h +++ /dev/null @@ -1,155 +0,0 @@ -/******************************************************* - * 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 - -namespace internal -{ -class _Plot3; -} - -namespace fg -{ - -/** - \class Plot3 - - \brief 3d graph to display 3d line plots. - */ -class Plot3 { - private: - internal::_Plot3* value; - - public: - /** - Creates a Plot3 object - - \param[in] pNumPoints is number of data points - \param[in] pDataType takes one of the values of \ref dtype that indicates - the integral data type of plot data - \param[in] pPlotType is the render type which can be one of \ref PlotType (valid choices - are FG_LINE and FG_SCATTER) - \param[in] pMarkerType is the type of \ref MarkerType to draw for \ref FG_SCATTER plot type - */ - FGAPI Plot3(unsigned pNumPoints, dtype pDataType, PlotType pPlotType=fg::FG_LINE, MarkerType pMarkerType=fg::FG_NONE); - - /** - Copy constructor for Plot3 - - \param[in] other is the Plot3 of which we make a copy of. - */ - FGAPI Plot3(const Plot3& other); - - /** - Plot3 Destructor - */ - FGAPI ~Plot3(); - - /** - Set the color of the 3d line plot - - \param[in] col takes values of fg::Color to define plot color - */ - FGAPI void setColor(fg::Color col); - - /** - Set the color of the 3d line plot - - \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] - */ - FGAPI void setColor(float pRed, float pGreen, float pBlue); - - /** - Set the chart axes limits - - \param[in] pXmax is X-Axis maximum value - \param[in] pXmin is X-Axis minimum value - \param[in] pYmax is Y-Axis maximum value - \param[in] pYmin is Y-Axis minimum value - \param[in] pZmax is Z-Axis maximum value - \param[in] pZmin is Z-Axis minimum value - */ - FGAPI void setAxesLimits(float pXmax, float pXmin, float pYmax, float pYmin, float pZmax, float pZmin); - - /** - Set axes titles - - \param[in] pXTitle is X-Axis title - \param[in] pYTitle is Y-Axis title - \param[in] pZTitle is Z-Axis title - */ - FGAPI void setAxesTitles(const char* pXTitle, const char* pYTitle, const char* pZTitle); - - /** - Get X-Axis maximum value - - \return Maximum value along X-Axis - */ - FGAPI float xmax() const; - - /** - Get X-Axis minimum value - - \return Minimum value along X-Axis - */ - FGAPI float xmin() const; - - /** - Get Y-Axis maximum value - - \return Maximum value along Y-Axis - */ - FGAPI float ymax() const; - - /** - Get Y-Axis minimum value - - \return Minimum value along Y-Axis - */ - FGAPI float ymin() const; - - /** - Get Z-Axis maximum value - - \return Maximum value along Z-Axis - */ - FGAPI float zmax() const; - - /** - Get Z-Axis minimum value - - \return Minimum value along Z-Axis - */ - FGAPI float zmin() const; - - /** - Get the OpenGL Vertex Buffer Object identifier - - \return OpenGL VBO resource id. - */ - FGAPI unsigned vbo() const; - - /** - Get the OpenGL Vertex Buffer Object resource size - - \return OpenGL VBO resource size. - */ - FGAPI unsigned size() const; - - /** - Get the handle to internal implementation of _Surface - */ - FGAPI internal::_Plot3* get() const; -}; - -} diff --git a/include/fg/surface.h b/include/fg/surface.h index 0348f8d2..5e9d8185 100644 --- a/include/fg/surface.h +++ b/include/fg/surface.h @@ -11,10 +11,41 @@ #include -namespace internal -{ -class _Surface; +#ifdef __cplusplus +extern "C" { +#endif + +FGAPI fg_err fg_create_surface(fg_surface *pSurface, + const uint pXPoints, const uint pYPoints, + const fg_dtype pType, + const fg_plot_type pPlotType, + const fg_marker_type pMarkerType); + +FGAPI fg_err fg_destroy_surface(fg_surface pSurface); + +FGAPI fg_err fg_set_surface_color(fg_surface pSurface, + const float pRed, const float pGreen, + const float pBlue, const float pAlpha); + +FGAPI fg_err fg_set_surface_legend(fg_surface pSurface, const char* pLegend); + +FGAPI fg_err fg_get_surface_vbo(uint* pOut, const fg_surface pSurface); + +FGAPI fg_err fg_get_surface_cbo(uint* pOut, const fg_surface pSurface); + +FGAPI fg_err fg_get_surface_abo(uint* pOut, const fg_surface pSurface); + +FGAPI fg_err fg_get_surface_vbo_size(uint* pOut, const fg_surface pSurface); + +FGAPI fg_err fg_get_surface_cbo_size(uint* pOut, const fg_surface pSurface); + +FGAPI fg_err fg_get_surface_abo_size(uint* pOut, const fg_surface pSurface); + +#ifdef __cplusplus } +#endif + +#ifdef __cplusplus namespace fg { @@ -22,11 +53,11 @@ namespace fg /** \class Surface - \brief 3d graph to display plots. + \brief Surface is a graph to display three dimensional data. */ class Surface { private: - internal::_Surface* value; + fg_surface mValue; public: /** @@ -40,14 +71,15 @@ class Surface { are FG_SURFACE and FG_SCATTER) \param[in] pMarkerType is the type of \ref MarkerType to draw for \ref FG_SCATTER plot type */ - FGAPI Surface(unsigned pNumXPoints, unsigned pNumYPoints, dtype pDataType, PlotType pPlotType=fg::FG_SURFACE, MarkerType pMarkerType=fg::FG_NONE); + FGAPI Surface(const uint pNumXPoints, const uint pNumYPoints, const dtype pDataType, + const PlotType pPlotType=FG_PLOT_SURFACE, const MarkerType pMarkerType=FG_MARKER_NONE); /** Copy constructor for Plot - \param[in] other is the Plot of which we make a copy of. + \param[in] pOther is the Plot of which we make a copy of. */ - FGAPI Surface(const Surface& other); + FGAPI Surface(const Surface& pOther); /** Plot Destructor @@ -57,9 +89,9 @@ class Surface { /** Set the color of line graph(plot) - \param[in] col takes values of fg::Color to define plot color + \param[in] pColor takes values of fg::Color to define plot color */ - FGAPI void setColor(fg::Color col); + FGAPI void setColor(const fg::Color pColor); /** Set the color of line graph(plot) @@ -67,90 +99,66 @@ class Surface { \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 Blue component in range [0, 1] */ - FGAPI void setColor(float pRed, float pGreen, float pBlue); - - /** - Set the chart axes limits - - \param[in] pXmax is X-Axis maximum value - \param[in] pXmin is X-Axis minimum value - \param[in] pYmax is Y-Axis maximum value - \param[in] pYmin is Y-Axis minimum value - \param[in] pZmax is Z-Axis maximum value - \param[in] pZmin is Z-Axis minimum value - */ - FGAPI void setAxesLimits(float pXmax, float pXmin, float pYmax, float pYmin, float pZmax, float pZmin); + FGAPI void setColor(const float pRed, const float pGreen, + const float pBlue, const float pAlpha); /** - Set axes titles + Set plot legend - \param[in] pXTitle is X-Axis title - \param[in] pYTitle is Y-Axis title - \param[in] pZTitle is Z-Axis title + \param[in] pLegend */ - FGAPI void setAxesTitles(const char* pXTitle, const char* pYTitle, const char* pZTitle); + FGAPI void setLegend(const char* pLegend); /** - Get X-Axis maximum value + Get the OpenGL buffer object identifier for vertices - \return Maximum value along X-Axis - */ - FGAPI float xmax() const; - - /** - Get X-Axis minimum value - - \return Minimum value along X-Axis - */ - FGAPI float xmin() const; - - /** - Get Y-Axis maximum value - - \return Maximum value along Y-Axis + \return OpenGL VBO resource id. */ - FGAPI float ymax() const; + FGAPI uint vertices() const; /** - Get Y-Axis minimum value + Get the OpenGL buffer object identifier for color values per vertex - \return Minimum value along Y-Axis + \return OpenGL VBO resource id. */ - FGAPI float ymin() const; + FGAPI uint colors() const; /** - Get Z-Axis maximum value + Get the OpenGL buffer object identifier for alpha values per vertex - \return Maximum value along Z-Axis + \return OpenGL VBO resource id. */ - FGAPI float zmax() const; + FGAPI uint alphas() const; /** - Get Z-Axis minimum value + Get the OpenGL Vertex Buffer Object resource size - \return Minimum value along Z-Axis + \return vertex buffer object size in bytes */ - FGAPI float zmin() const; + FGAPI uint verticesSize() const; /** - Get the OpenGL Vertex Buffer Object identifier + Get the OpenGL Vertex Buffer Object resource size - \return OpenGL VBO resource id. + \return colors buffer object size in bytes */ - FGAPI unsigned vbo() const; + FGAPI uint colorsSize() const; /** Get the OpenGL Vertex Buffer Object resource size - \return OpenGL VBO resource size. + \return alpha buffer object size in bytes */ - FGAPI unsigned size() const; + FGAPI uint alphasSize() const; /** - Get the handle to internal implementation of _Surface + Get the handle to internal implementation of surface */ - FGAPI internal::_Surface* get() const; + FGAPI fg_surface get() const; }; } + +#endif diff --git a/include/fg/window.h b/include/fg/window.h index 358b6497..f3462e2a 100644 --- a/include/fg/window.h +++ b/include/fg/window.h @@ -12,15 +12,71 @@ #include #include #include -#include -#include +#include #include #include -namespace internal -{ -class _Window; + +#ifdef __cplusplus +extern "C" { +#endif + +FGAPI fg_err fg_create_window(fg_window *pWindow, + const int pWidth, const int pHeight, + const char* pTitle, + const fg_window pShareWindow, + const bool pInvisible); + +FGAPI fg_err fg_destroy_window(fg_window pWindow); + +FGAPI fg_err fg_set_window_font(fg_window pWindow, fg_font pFont); + +FGAPI fg_err fg_set_window_title(fg_window pWindow, const char* pTitle); + +FGAPI fg_err fg_set_window_position(fg_window pWindow, const int pX, const int pY); + +FGAPI fg_err fg_set_window_size(fg_window pWindow, const uint pWidth, const uint pHeight); + +FGAPI fg_err fg_set_window_colormap(fg_window pWindow, const fg_color_map pColorMap); + +FGAPI fg_err fg_get_window_context_handle(long long *pContext, const fg_window pWindow); + +FGAPI fg_err fg_get_window_display_handle(long long *pDisplay, const fg_window pWindow); + +FGAPI fg_err fg_get_window_width(int *pWidth, const fg_window pWindow); + +FGAPI fg_err fg_get_window_height(int *pHeight, const fg_window pWindow); + +FGAPI fg_err fg_make_window_current(const fg_window pWindow); + +FGAPI fg_err fg_hide_window(const fg_window pWindow); + +FGAPI fg_err fg_show_window(const fg_window pWindow); + +FGAPI fg_err fg_close_window(bool* pIsClosed, const fg_window pWindow); + +FGAPI fg_err fg_draw_image(const fg_window pWindow, const fg_image pImage, const bool pKeepAspectRatio); + +FGAPI fg_err fg_draw_chart(const fg_window pWindow, const fg_chart pChart); + +FGAPI fg_err fg_setup_window_layout(int pRows, int pCols, fg_window pWindow); + +FGAPI fg_err fg_draw_image_to_cell(const fg_window pWindow, int pColId, int pRowId, + const fg_image pImage, const char* pTitle, const bool pKeepAspectRatio); + +FGAPI fg_err fg_draw_chart_to_cell(const fg_window pWindow, int pColId, int pRowId, + const fg_chart pChart, const char* pTitle); + +FGAPI fg_err fg_swap_window_buffers(const fg_window pWindow); + +FGAPI fg_err fg_save_window_framebuffer(const char* pFullPath, const fg_window pWindow); + +#ifdef __cplusplus } +#endif + + +#ifdef __cplusplus namespace fg { @@ -32,7 +88,7 @@ namespace fg */ class Window { private: - internal::_Window* value; + fg_window mValue; Window() {} @@ -126,7 +182,7 @@ class Window { /** \return internal handle for window implementation */ - FGAPI internal::_Window* get() const; + FGAPI fg_window get() const; /** Make the current window's OpenGL context active context @@ -166,47 +222,15 @@ class Window { FGAPI void draw(const Image& pImage, const bool pKeepAspectRatio=true); /** - Render a Plot to Window + Render a chart to Window - \param[in] pPlot is an object of class Plot + \param[in] pChart is an chart object \note this draw call does a OpenGL swap buffer, so we do not need to call Window::draw() after this function is called upon for rendering a plot */ - FGAPI void draw(const Plot& pPlot); - - /** - Render a Plot3 to Window - - \param[in] pPlot3 is an object of class Plot3 - - \note this draw call does a OpenGL swap buffer, so we do not need - to call Window::draw() after this function is called upon for rendering - a plot - */ - FGAPI void draw(const Plot3& pPlot3); - - /** - Render a Surface to Window - - \param[in] pSurface is an object of class Surface - - \note this draw call does a OpenGL swap buffer, so we do not need - to call Window::draw() after this function is called upon for rendering - a plot - */ - FGAPI void draw(const Surface& pSurface); - /** - Render Histogram to Window - - \param[in] pHist is an object of class Histogram - - \note this draw call does a OpenGL swap buffer, so we do not need - to call Window::draw() after this function is called upon for rendering - a histogram - */ - FGAPI void draw(const Histogram& pHist); + FGAPI void draw(const Chart& pChart); /** Setup grid layout for multivew mode @@ -241,34 +265,14 @@ class Window { FGAPI void draw(int pColId, int pRowId, const Image& pImage, const char* pTitle=0, const bool pKeepAspectRatio=true); /** - Render Plot to given sub-region of the window in multiview mode - - Window::grid should have been already called before any of the draw calls - that accept coloum index and row index is used to render an object. - - \param[in] pColId is coloumn index - \param[in] pRowId is row index - \param[in] pPlot is an object of class Plot - \param[in] pTitle is the title that will be displayed for the cell represented - by \p pColId and \p pRowId - - \note This draw call doesn't do OpenGL swap buffer since it doesn't have the - knowledge of which sub-regions already got rendered. We should call - Window::draw() once all draw calls corresponding to all sub-regions are called - when in multiview mode. - */ - FGAPI void draw(int pColId, int pRowId, const Plot& pPlot, const char* pTitle = 0); - - - /** - Render Plot3 to given sub-region of the window in multiview mode + Render the chart to given sub-region of the window in multiview mode Window::grid should have been already called before any of the draw calls that accept coloum index and row index is used to render an object. \param[in] pColId is coloumn index \param[in] pRowId is row index - \param[in] pPlot3 is an object of class Plot3 + \param[in] pChart is a Chart with one or more plottable renderables \param[in] pTitle is the title that will be displayed for the cell represented by \p pColId and \p pRowId @@ -277,53 +281,29 @@ class Window { Window::draw() once all draw calls corresponding to all sub-regions are called when in multiview mode. */ - FGAPI void draw(int pColId, int pRowId, const Plot3& pPlot3, const char* pTitle = 0); + FGAPI void draw(int pColId, int pRowId, const Chart& pChart, const char* pTitle = 0); /** - Render Surface to given sub-region of the window in multiview mode - - Window::grid should have been already called before any of the draw calls - that accept coloum index and row index is used to render an object. - - \param[in] pColId is coloumn index - \param[in] pRowId is row index - \param[in] pSurface is an object of class Surface - \param[in] pTitle is the title that will be displayed for the cell represented - by \p pColId and \p pRowId + Swaps background OpenGL buffer with front buffer - \note This draw call doesn't do OpenGL swap buffer since it doesn't have the - knowledge of which sub-regions already got rendered. We should call - Window::draw() once all draw calls corresponding to all sub-regions are called - when in multiview mode. + This draw call should only be used when the window is displaying + something in multiview mode */ - FGAPI void draw(int pColId, int pRowId, const Surface& pSurface, const char* pTitle = 0); + FGAPI void swapBuffers(); /** - Render Histogram to given sub-region of the window in multiview mode + Save window frame buffer to give location in provided image format - Window::grid should have been already called before any of the draw calls - that accept coloum index and row index is used to render an object. + The image format to be saved in is inferred from the file extension + provided in the path string. - \param[in] pColId is coloumn index - \param[in] pRowId is row index - \param[in] pHist is an object of class Histogram - \param[in] pTitle is the title that will be displayed for the cell represented - by \p pColId and \p pRowId - - \note This draw call doesn't do OpenGL swap buffer since it doesn't have the - knowledge of which sub-regions already got rendered. We should call - Window::draw() once all draw calls corresponding to all sub-regions are called - when in multiview mode. - */ - FGAPI void draw(int pColId, int pRowId, const Histogram& pHist, const char* pTitle = 0); - - /** - Swaps background OpenGL buffer with front buffer - - This draw call should only be used when the window is displaying - something in multiview mode + \param[in] pFullPath should be the absolute path of the target location + where the framebuffer should be stored. The target image format + is inferred from the file extension. */ - FGAPI void swapBuffers(); + FGAPI void saveFrameBuffer(const char* pFullPath); }; } + +#endif diff --git a/include/forge.h b/include/forge.h index c17c8ec1..dd8e0edc 100644 --- a/include/forge.h +++ b/include/forge.h @@ -16,6 +16,5 @@ #include "fg/image.h" #include "fg/version.h" #include "fg/plot.h" -#include "fg/plot3.h" #include "fg/surface.h" #include "fg/histogram.h" diff --git a/src/api/c/chart.cpp b/src/api/c/chart.cpp new file mode 100644 index 00000000..6fd53826 --- /dev/null +++ b/src/api/c/chart.cpp @@ -0,0 +1,178 @@ +/******************************************************* + * 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 +#include +#include +#include +#include +#include + +fg_err fg_create_chart(fg_chart *pHandle, + const fg_chart_type pChartType) +{ + try { + *pHandle = getHandle(new common::Chart(pChartType)); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_destroy_chart(fg_chart pHandle) +{ + try { + delete getChart(pHandle); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_chart_axes_titles(fg_chart pHandle, + const char* pX, + const char* pY, + const char* pZ) +{ + try { + getChart(pHandle)->setAxesTitles(pX, pY, pZ); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_chart_axes_limits(fg_chart pHandle, + const float pXmin, const float pXmax, + const float pYmin, const float pYmax, + const float pZmin, const float pZmax) +{ + try { + getChart(pHandle)->setAxesLimits(pXmin, pXmax, pYmin, pYmax, pZmin, pZmax); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_chart_legend_position(fg_chart pHandle, const float pX, const float pY) +{ + try { + getChart(pHandle)->setLegendPosition(pX, pY); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_add_image_to_chart(fg_image* pImage, fg_chart pHandle, + const uint pWidth, const uint pHeight, + const fg_channel_format pFormat, + const fg_dtype pType) +{ + try { + common::Image* img = new common::Image(pWidth, pHeight, pFormat, (fg::dtype)pType); + getChart(pHandle)->addRenderable(img->impl()); + *pImage = getHandle(img); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_add_histogram_to_chart(fg_histogram* pHistogram, fg_chart pHandle, + const uint pNBins, const fg_dtype pType) +{ + try { + common::Chart* chrt = getChart(pHandle); + + if (chrt->chartType()== FG_CHART_2D) { + common::Histogram* hist = new common::Histogram(pNBins, (fg::dtype)pType); + chrt->addRenderable(hist->impl()); + *pHistogram = getHandle(hist); + } else { + throw fg::ArgumentError("Chart::render", __LINE__, 5, + "Can add histogram to a 2d chart only"); + } + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_add_plot_to_chart(fg_plot* pPlot, fg_chart pHandle, + const uint pNPoints, const fg_dtype pType, + const fg_plot_type pPlotType, const fg_marker_type pMarkerType) +{ + try { + common::Chart* chrt = getChart(pHandle); + fg::ChartType ctype = chrt->chartType(); + + if (ctype == FG_CHART_2D) { + common::Plot* plt = new common::Plot(pNPoints, (fg::dtype)pType, pPlotType, + pMarkerType, FG_CHART_2D); + chrt->addRenderable(plt->impl()); + *pPlot = getHandle(plt); + } else { + common::Plot* plt = new common::Plot(pNPoints, (fg::dtype)pType, pPlotType, + pMarkerType, FG_CHART_3D); + chrt->addRenderable(plt->impl()); + *pPlot = getHandle(plt); + } + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_add_surface_to_chart(fg_surface* pSurface, fg_chart pHandle, + const uint pXPoints, const uint pYPoints, const fg_dtype pType, + const fg_plot_type pPlotType, const fg_marker_type pMarkerType) +{ + try { + common::Chart* chrt = getChart(pHandle); + fg::ChartType ctype = chrt->chartType(); + + if (ctype == FG_CHART_3D) { + common::Surface* surf = new common::Surface(pXPoints, pYPoints, (fg::dtype)pType, + pPlotType, pMarkerType); + chrt->addRenderable(surf->impl()); + *pSurface = getHandle(surf); + } else { + throw fg::ArgumentError("Chart::render", __LINE__, 5, + "Can add surface plot to a 3d chart only"); + } + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_render_chart(const fg_window pWindow, const fg_chart pChart, + const int pX, const int pY, const int pWidth, const int pHeight, + const float* pTransform) +{ + try { + getChart(pChart)->render(getWindow(pWindow)->getID(), + pX, pY, pWidth, pHeight, + glm::make_mat4(pTransform)); + } + CATCHALL + + return FG_ERR_NONE; +} diff --git a/src/api/c/font.cpp b/src/api/c/font.cpp new file mode 100644 index 00000000..da6775e0 --- /dev/null +++ b/src/api/c/font.cpp @@ -0,0 +1,53 @@ +/******************************************************* + * 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 + +fg_err fg_create_font(fg_font* pFont) +{ + try { + *pFont = getHandle(new common::Font()); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_destroy_font(fg_font pFont) +{ + try { + delete getFont(pFont); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_load_font_file(fg_font pFont, const char* const pFileFullPath) +{ + try { + getFont(pFont)->loadFont(pFileFullPath); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_load_system_font(fg_font pFont, const char* const pFontName) +{ + try { + getFont(pFont)->loadSystemFont(pFontName); + } + CATCHALL + + return FG_ERR_NONE; +} diff --git a/src/api/c/histogram.cpp b/src/api/c/histogram.cpp new file mode 100644 index 00000000..1da870bd --- /dev/null +++ b/src/api/c/histogram.cpp @@ -0,0 +1,116 @@ +/******************************************************* + * 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 + +fg_err fg_create_histogram(fg_histogram *pHistogram, + const uint pNBins, const fg_dtype pType) +{ + try { + *pHistogram = getHandle(new common::Histogram(pNBins, (fg::dtype)pType)); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_destroy_histogram(fg_histogram pHistogram) +{ + try { + delete getHistogram(pHistogram); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_histogram_color(fg_histogram pHistogram, + const float pRed, const float pGreen, + const float pBlue, const float pAlpha) +{ + try { + getHistogram(pHistogram)->setColor(pRed, pGreen, pBlue, pAlpha); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_histogram_legend(fg_histogram pHistogram, const char* pLegend) +{ + try { + getHistogram(pHistogram)->setLegend(pLegend); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_histogram_vbo(uint* pOut, const fg_histogram pHistogram) +{ + try { + *pOut = getHistogram(pHistogram)->vbo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_histogram_cbo(uint* pOut, const fg_histogram pHistogram) +{ + try { + *pOut = getHistogram(pHistogram)->cbo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_histogram_abo(uint* pOut, const fg_histogram pHistogram) +{ + try { + *pOut = getHistogram(pHistogram)->abo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_histogram_vbo_size(uint* pOut, const fg_histogram pHistogram) +{ + try { + *pOut = (uint)getHistogram(pHistogram)->vboSize(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_histogram_cbo_size(uint* pOut, const fg_histogram pHistogram) +{ + try { + *pOut = (uint)getHistogram(pHistogram)->cboSize(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_histogram_abo_size(uint* pOut, const fg_histogram pHistogram) +{ + try { + *pOut = (uint)getHistogram(pHistogram)->aboSize(); + } + CATCHALL + + return FG_ERR_NONE; +} diff --git a/src/api/c/image.cpp b/src/api/c/image.cpp new file mode 100644 index 00000000..dd276c17 --- /dev/null +++ b/src/api/c/image.cpp @@ -0,0 +1,136 @@ +/******************************************************* + * 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 + +fg_err fg_create_image(fg_image* pImage, + const uint pWidth, const uint pHeight, + const fg_channel_format pFormat, const fg_dtype pType) +{ + try { + *pImage = getHandle(new common::Image(pWidth, pHeight, pFormat, (fg::dtype)pType)); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_destroy_image(fg_image pImage) +{ + try { + delete getImage(pImage); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_image_alpha(fg_image pImage, const float pAlpha) +{ + try { + getImage(pImage)->setAlpha(pAlpha); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_image_aspect_ratio(fg_image pImage, const bool pKeepRatio) +{ + try { + getImage(pImage)->keepAspectRatio(pKeepRatio); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_image_width(uint *pOut, const fg_image pImage) +{ + try { + *pOut = getImage(pImage)->width(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_image_height(uint *pOut, const fg_image pImage) +{ + try { + *pOut = getImage(pImage)->height(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_image_pixelformat(fg_channel_format* pOut, const fg_image pImage) +{ + try { + *pOut = getImage(pImage)->pixelFormat(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_image_type(fg_dtype* pOut, const fg_image pImage) +{ + try { + *pOut = (fg_dtype)(getImage(pImage)->channelType()); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_image_pbo(uint* pOut, const fg_image pImage) +{ + try { + *pOut = getImage(pImage)->pbo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_image_pbo_size(uint* pOut, const fg_image pImage) +{ + try { + *pOut = getImage(pImage)->size(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_render_image(const fg_window pWindow, + const fg_image pImage, + const int pX, const int pY, const int pWidth, const int pHeight, + const float* pTransform) +{ + try { + getImage(pImage)->render(getWindow(pWindow)->getID(), + pX, pY, pWidth, pHeight, + glm::make_mat4(pTransform)); + } + CATCHALL + + return FG_ERR_NONE; +} diff --git a/src/api/c/plot.cpp b/src/api/c/plot.cpp new file mode 100644 index 00000000..dfc63b79 --- /dev/null +++ b/src/api/c/plot.cpp @@ -0,0 +1,150 @@ +/******************************************************* + * 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 + +fg_err fg_create_plot(fg_plot *pPlot, + const uint pNPoints, const fg_dtype pType, + const fg_chart_type pChartType, + const fg_plot_type pPlotType, + const fg_marker_type pMarkerType) +{ + try { + *pPlot = getHandle(new common::Plot(pNPoints, (fg::dtype)pType, pPlotType, + pMarkerType, pChartType)); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_destroy_plot(fg_plot pPlot) +{ + try { + delete getPlot(pPlot); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_plot_color(fg_plot pPlot, + const float pRed, const float pGreen, + const float pBlue, const float pAlpha) +{ + try { + getPlot(pPlot)->setColor(pRed, pGreen, pBlue, pAlpha); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_plot_legend(fg_plot pPlot, const char* pLegend) +{ + try { + getPlot(pPlot)->setLegend(pLegend); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_plot_marker_size(fg_plot pPlot, const float pMarkerSize) +{ + try { + getPlot(pPlot)->setMarkerSize(pMarkerSize); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_plot_vbo(uint* pOut, const fg_plot pPlot) +{ + try { + *pOut = getPlot(pPlot)->vbo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_plot_cbo(uint* pOut, const fg_plot pPlot) +{ + try { + *pOut = getPlot(pPlot)->cbo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_plot_abo(uint* pOut, const fg_plot pPlot) +{ + try { + *pOut = getPlot(pPlot)->abo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_plot_mbo(uint* pOut, const fg_plot pPlot) +{ + try { + *pOut = getPlot(pPlot)->mbo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_plot_vbo_size(uint* pOut, const fg_plot pPlot) +{ + try { + *pOut = (uint)getPlot(pPlot)->vboSize(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_plot_cbo_size(uint* pOut, const fg_plot pPlot) +{ + try { + *pOut = (uint)getPlot(pPlot)->cboSize(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_plot_abo_size(uint* pOut, const fg_plot pPlot) +{ + try { + *pOut = (uint)getPlot(pPlot)->aboSize(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_plot_mbo_size(uint* pOut, const fg_plot pPlot) +{ + try { + *pOut = (uint)getPlot(pPlot)->mboSize(); + } + CATCHALL + + return FG_ERR_NONE; +} diff --git a/src/api/c/surface.cpp b/src/api/c/surface.cpp new file mode 100644 index 00000000..4816729a --- /dev/null +++ b/src/api/c/surface.cpp @@ -0,0 +1,120 @@ +/******************************************************* + * 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 + +fg_err fg_create_surface(fg_surface *pSurface, + const uint pXPoints, const uint pYPoints, + const fg_dtype pType, + const fg_plot_type pPlotType, + const fg_marker_type pMarkerType) +{ + try { + *pSurface = getHandle(new common::Surface(pXPoints, pYPoints, (fg::dtype)pType, + pPlotType, pMarkerType)); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_destroy_surface(fg_surface pSurface) +{ + try { + delete getSurface(pSurface); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_surface_color(fg_surface pSurface, + const float pRed, const float pGreen, + const float pBlue, const float pAlpha) +{ + try { + getSurface(pSurface)->setColor(pRed, pGreen, pBlue, pAlpha); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_surface_legend(fg_surface pSurface, const char* pLegend) +{ + try { + getSurface(pSurface)->setLegend(pLegend); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_surface_vbo(uint* pOut, const fg_surface pSurface) +{ + try { + *pOut = getSurface(pSurface)->vbo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_surface_cbo(uint* pOut, const fg_surface pSurface) +{ + try { + *pOut = getSurface(pSurface)->cbo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_surface_abo(uint* pOut, const fg_surface pSurface) +{ + try { + *pOut = getSurface(pSurface)->abo(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_surface_vbo_size(uint* pOut, const fg_surface pSurface) +{ + try { + *pOut = (uint)getSurface(pSurface)->vboSize(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_surface_cbo_size(uint* pOut, const fg_surface pSurface) +{ + try { + *pOut = (uint)getSurface(pSurface)->cboSize(); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_get_surface_abo_size(uint* pOut, const fg_surface pSurface) +{ + try { + *pOut = (uint)getSurface(pSurface)->aboSize(); + } + CATCHALL + + return FG_ERR_NONE; +} diff --git a/src/api/c/window.cpp b/src/api/c/window.cpp new file mode 100644 index 00000000..81274f7d --- /dev/null +++ b/src/api/c/window.cpp @@ -0,0 +1,227 @@ +/******************************************************* + * 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 + +fg_err fg_create_window(fg_window *pWindow, + const int pWidth, const int pHeight, + const char* pTitle, + const fg_window pShareWindow, + const bool pInvisible) +{ + try { + common::Window* shrdWnd = getWindow(pShareWindow); + common::Window* temp = nullptr; + if (shrdWnd == nullptr) { + temp = new common::Window(pWidth, pHeight, pTitle, nullptr, pInvisible); + } else { + temp = new common::Window(pWidth, pHeight, pTitle, shrdWnd, pInvisible); + } + *pWindow = getHandle(temp); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_destroy_window(fg_window pWindow) +{ + try { + delete getWindow(pWindow); + } + CATCHALL + + return FG_ERR_NONE; +} + +fg_err fg_set_window_font(fg_window pWindow, fg_font pFont) +{ + try { + getWindow(pWindow)->setFont(getFont(pFont)); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_set_window_title(fg_window pWindow, const char* pTitle) +{ + try { + getWindow(pWindow)->setTitle(pTitle); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_set_window_position(fg_window pWindow, const int pX, const int pY) +{ + try { + getWindow(pWindow)->setPos(pX, pY); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_set_window_size(fg_window pWindow, const uint pWidth, const uint pHeight) +{ + try { + getWindow(pWindow)->setSize(pWidth, pHeight); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_set_window_colormap(fg_window pWindow, const fg_color_map pColorMap) +{ + try { + getWindow(pWindow)->setColorMap(pColorMap); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_get_window_context_handle(long long *pContext, const fg_window pWindow) +{ + try { + *pContext = getWindow(pWindow)->context(); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_get_window_display_handle(long long *pDisplay, const fg_window pWindow) +{ + try { + *pDisplay = getWindow(pWindow)->display(); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_get_window_width(int *pWidth, const fg_window pWindow) +{ + try { + *pWidth = getWindow(pWindow)->width(); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_get_window_height(int *pHeight, const fg_window pWindow) +{ + try { + *pHeight = getWindow(pWindow)->height(); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_make_window_current(const fg_window pWindow) +{ + try { + getWindow(pWindow)->makeCurrent(); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_hide_window(const fg_window pWindow) +{ + try { + getWindow(pWindow)->hide(); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_show_window(const fg_window pWindow) +{ + try { + getWindow(pWindow)->show(); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_close_window(bool* pIsClosed, const fg_window pWindow) +{ + try { + *pIsClosed = getWindow(pWindow)->close(); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_draw_image(const fg_window pWindow, const fg_image pImage, const bool pKeepAspectRatio) +{ + try { + getWindow(pWindow)->draw(getImage(pImage), pKeepAspectRatio); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_draw_chart(const fg_window pWindow, const fg_chart pChart) +{ + try { + getWindow(pWindow)->draw(getChart(pChart)); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_setup_window_layout(int pRows, int pCols, fg_window pWindow) +{ + try { + getWindow(pWindow)->grid(pRows, pCols); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_draw_image_to_cell(const fg_window pWindow, int pColId, int pRowId, + const fg_image pImage, const char* pTitle, const bool pKeepAspectRatio) +{ + try { + getWindow(pWindow)->draw(pColId, pRowId, getImage(pImage), pTitle, pKeepAspectRatio); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_draw_chart_to_cell(const fg_window pWindow, int pColId, int pRowId, + const fg_chart pChart, const char* pTitle) +{ + try { + getWindow(pWindow)->draw(pColId, pRowId, getChart(pChart), pTitle); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_swap_window_buffers(const fg_window pWindow) +{ + try { + getWindow(pWindow)->swapBuffers(); + } + CATCHALL + return FG_ERR_NONE; +} + +fg_err fg_save_window_framebuffer(const char* pFullPath, const fg_window pWindow) +{ + try { + getWindow(pWindow)->saveFrameBuffer(pFullPath); + } + CATCHALL + return FG_ERR_NONE; +} diff --git a/src/api/cpp/chart.cpp b/src/api/cpp/chart.cpp new file mode 100644 index 00000000..ad96f784 --- /dev/null +++ b/src/api/cpp/chart.cpp @@ -0,0 +1,152 @@ +/******************************************************* + * 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 +#include +#include +#include +#include + +namespace fg +{ + +Chart::Chart(const ChartType cType) +{ + mValue = getHandle(new common::Chart(cType)); +} + +Chart::Chart(const Chart& pOther) +{ + mValue = getHandle(new common::Chart(pOther.get())); +} + +Chart::~Chart() +{ + delete getChart(mValue); +} + +void Chart::setAxesTitles(const char* pX, + const char* pY, + const char* pZ) +{ + getChart(mValue)->setAxesTitles(pX, pY, pZ); +} + +void Chart::setAxesLimits(const float pXmin, const float pXmax, + const float pYmin, const float pYmax, + const float pZmin, const float pZmax) +{ + getChart(mValue)->setAxesLimits(pXmin, pXmax, pYmin, pYmax, pZmin, pZmax); +} + +void Chart::setLegendPosition(const float pX, const float pY) +{ + getChart(mValue)->setLegendPosition(pX, pY); +} + +void Chart::add(const Image& pImage) +{ + getChart(mValue)->addRenderable(getImage(pImage.get())->impl()); +} + +void Chart::add(const Histogram& pHistogram) +{ + getChart(mValue)->addRenderable(getHistogram(pHistogram.get())->impl()); +} + +void Chart::add(const Plot& pPlot) +{ + getChart(mValue)->addRenderable(getPlot(pPlot.get())->impl()); +} + +void Chart::add(const Surface& pSurface) +{ + getChart(mValue)->addRenderable(getSurface(pSurface.get())->impl()); +} + +Image Chart::image(const uint pWidth, const uint pHeight, + const ChannelFormat pFormat, const dtype pDataType) +{ + Image retVal(pWidth, pHeight, pFormat, pDataType); + getChart(mValue)->addRenderable(getImage(retVal.get())->impl()); + return retVal; +} + +Histogram Chart::histogram(const uint pNBins, const dtype pDataType) +{ + common::Chart* chrt = getChart(mValue); + ChartType ctype = chrt->chartType(); + + if (ctype == FG_CHART_2D) { + Histogram retVal(pNBins, pDataType); + chrt->addRenderable(getHistogram(retVal.get())->impl()); + return retVal; + } else { + throw ArgumentError("Chart::render", __LINE__, 5, + "Can add histogram to a 2d chart only"); + } +} + +Plot Chart::plot(const uint pNumPoints, const dtype pDataType, + const PlotType pPlotType, const MarkerType pMarkerType) +{ + common::Chart* chrt = getChart(mValue); + ChartType ctype = chrt->chartType(); + + if (ctype == FG_CHART_2D) { + Plot retVal(pNumPoints, pDataType, FG_CHART_2D, pPlotType, pMarkerType); + chrt->addRenderable(getPlot(retVal.get())->impl()); + return retVal; + } else { + Plot retVal(pNumPoints, pDataType, FG_CHART_3D, pPlotType, pMarkerType); + chrt->addRenderable(getPlot(retVal.get())->impl()); + return retVal; + } +} + +Surface Chart::surface(const uint pNumXPoints, const uint pNumYPoints, const dtype pDataType, + const PlotType pPlotType, const MarkerType pMarkerType) +{ + common::Chart* chrt = getChart(mValue); + ChartType ctype = chrt->chartType(); + + if (ctype == FG_CHART_3D) { + Surface retVal(pNumXPoints, pNumYPoints, pDataType, pPlotType, pMarkerType); + getChart(mValue)->addRenderable(getSurface(retVal.get())->impl()); + return retVal; + } else { + throw ArgumentError("Chart::render", __LINE__, 5, + "Can add surface plot to a 3d chart only"); + } +} + +void Chart::render(const Window& pWindow, + const int pX, const int pY, const int pVPW, const int pVPH, + const float* pTransform) const +{ + getChart(mValue)->render(getWindow(pWindow.get())->getID(), + pX, pY, pVPW, pVPH, + glm::make_mat4(pTransform)); +} + +fg_chart Chart::get() const +{ + return getChart(mValue); +} + +} diff --git a/src/exception.cpp b/src/api/cpp/exception.cpp similarity index 99% rename from src/exception.cpp rename to src/api/cpp/exception.cpp index a319a029..79c5b462 100644 --- a/src/exception.cpp +++ b/src/api/cpp/exception.cpp @@ -20,7 +20,7 @@ using std::cerr; std::string getName(fg::dtype pType) { - // FIXME + // TODO return std::string("test"); } diff --git a/src/api/cpp/font.cpp b/src/api/cpp/font.cpp new file mode 100644 index 00000000..78a0846e --- /dev/null +++ b/src/api/cpp/font.cpp @@ -0,0 +1,48 @@ +/******************************************************* + * 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 fg +{ + +Font::Font() +{ + mValue = getHandle(new common::Font()); +} + +Font::Font(const Font& other) +{ + mValue = getHandle(new common::Font(other.get())); +} + +Font::~Font() +{ + delete getFont(mValue); +} + +void Font::loadFontFile(const char* const pFile) +{ + getFont(mValue)->loadFont(pFile); +} + +void Font::loadSystemFont(const char* const pName) +{ + getFont(mValue)->loadSystemFont(pName); +} + +fg_font Font::get() const +{ + return getFont(mValue); +} + +} diff --git a/src/api/cpp/histogram.cpp b/src/api/cpp/histogram.cpp new file mode 100644 index 00000000..9a1f7370 --- /dev/null +++ b/src/api/cpp/histogram.cpp @@ -0,0 +1,88 @@ +/******************************************************* + * 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 fg +{ + +Histogram::Histogram(const uint pNBins, const dtype pDataType) +{ + mValue = getHandle(new common::Histogram(pNBins, pDataType)); +} + +Histogram::Histogram(const Histogram& pOther) +{ + mValue = getHandle(new common::Histogram(pOther.get())); +} + +Histogram::~Histogram() +{ + delete getHistogram(mValue); +} + +void Histogram::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; + getHistogram(mValue)->setColor(r, g, b, a); +} + +void Histogram::setColor(const float pRed, const float pGreen, + const float pBlue, const float pAlpha) +{ + getHistogram(mValue)->setColor(pRed, pGreen, pBlue, pAlpha); +} + +void Histogram::setLegend(const char* pLegend) +{ + getHistogram(mValue)->setLegend(pLegend); +} + +uint Histogram::vertices() const +{ + return getHistogram(mValue)->vbo(); +} + +uint Histogram::colors() const +{ + return getHistogram(mValue)->cbo(); +} + +uint Histogram::alphas() const +{ + return getHistogram(mValue)->abo(); +} + +uint Histogram::verticesSize() const +{ + return (uint)getHistogram(mValue)->vboSize(); +} + +uint Histogram::colorsSize() const +{ + return (uint)getHistogram(mValue)->cboSize(); +} + +uint Histogram::alphasSize() const +{ + return (uint)getHistogram(mValue)->aboSize(); +} + +fg_histogram Histogram::get() const +{ + return mValue; +} + +} diff --git a/src/api/cpp/image.cpp b/src/api/cpp/image.cpp new file mode 100644 index 00000000..7eb293fa --- /dev/null +++ b/src/api/cpp/image.cpp @@ -0,0 +1,94 @@ +/******************************************************* + * 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 + +namespace fg +{ + +Image::Image(const uint pWidth, const uint pHeight, + const ChannelFormat pFormat, const dtype pDataType) +{ + mValue = getHandle(new common::Image(pWidth, pHeight, pFormat, pDataType)); +} + +Image::Image(const Image& pOther) +{ + mValue = getHandle(new common::Image(pOther.get())); +} + +Image::~Image() +{ + delete getImage(mValue); +} + +void Image::setAlpha(const float pAlpha) +{ + getImage(mValue)->setAlpha(pAlpha); +} + +void Image::keepAspectRatio(const bool pKeep) +{ + getImage(mValue)->keepAspectRatio(pKeep); +} + +uint Image::width() const +{ + return getImage(mValue)->width(); +} + +uint Image::height() const +{ + return getImage(mValue)->height(); +} + +ChannelFormat Image::pixelFormat() const +{ + return getImage(mValue)->pixelFormat(); +} + +fg::dtype Image::channelType() const +{ + return getImage(mValue)->channelType(); +} + +GLuint Image::pbo() const +{ + return getImage(mValue)->pbo(); +} + +uint Image::size() const +{ + return (uint)getImage(mValue)->size(); +} + +void Image::render(const Window& pWindow, + const int pX, const int pY, const int pVPW, const int pVPH, + const float* pTransform) const +{ + getImage(mValue)->render(getWindow(pWindow.get())->getID(), + pX, pY, pVPW, pVPH, + glm::make_mat4(pTransform)); +} + + +fg_image Image::get() const +{ + return mValue; +} + +} diff --git a/src/api/cpp/plot.cpp b/src/api/cpp/plot.cpp new file mode 100644 index 00000000..47d90347 --- /dev/null +++ b/src/api/cpp/plot.cpp @@ -0,0 +1,104 @@ +/******************************************************* + * 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 fg +{ + +Plot::Plot(const uint pNumPoints, const dtype pDataType, const ChartType pChartType, + const PlotType pPlotType, const MarkerType pMarkerType) +{ + mValue = getHandle(new common::Plot(pNumPoints, pDataType, pPlotType, pMarkerType, pChartType)); +} + +Plot::Plot(const Plot& pOther) +{ + mValue = getHandle(new common::Plot(pOther.get())); +} + +Plot::~Plot() +{ + delete getPlot(mValue); +} + +void Plot::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; + getPlot(mValue)->setColor(r, g, b, a); +} + +void Plot::setColor(const float pRed, const float pGreen, + const float pBlue, const float pAlpha) +{ + getPlot(mValue)->setColor(pRed, pGreen, pBlue, pAlpha); +} + +void Plot::setLegend(const char* pLegend) +{ + getPlot(mValue)->setLegend(pLegend); +} + +void Plot::setMarkerSize(const float pMarkerSize) +{ + getPlot(mValue)->setMarkerSize(pMarkerSize); +} + +uint Plot::vertices() const +{ + return getPlot(mValue)->vbo(); +} + +uint Plot::colors() const +{ + return getPlot(mValue)->cbo(); +} + +uint Plot::alphas() const +{ + return getPlot(mValue)->abo(); +} + +uint Plot::markers() const +{ + return getPlot(mValue)->mbo(); +} + +uint Plot::verticesSize() const +{ + return (uint)getPlot(mValue)->vboSize(); +} + +uint Plot::colorsSize() const +{ + return (uint)getPlot(mValue)->cboSize(); +} + +uint Plot::alphasSize() const +{ + return (uint)getPlot(mValue)->aboSize(); +} + +uint Plot::markersSize() const +{ + return (uint)getPlot(mValue)->mboSize(); +} + +fg_plot Plot::get() const +{ + return mValue; +} + +} diff --git a/src/api/cpp/surface.cpp b/src/api/cpp/surface.cpp new file mode 100644 index 00000000..c18fc42c --- /dev/null +++ b/src/api/cpp/surface.cpp @@ -0,0 +1,88 @@ +/******************************************************* + * 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 fg +{ + +Surface::Surface(unsigned pNumXPoints, unsigned pNumYPoints, dtype pDataType, PlotType pPlotType, MarkerType pMarkerType) +{ + mValue = getHandle(new common::Surface(pNumXPoints, pNumYPoints, pDataType, pPlotType, pMarkerType)); +} + +Surface::Surface(const Surface& other) +{ + mValue = getHandle(new common::Surface(other.get())); +} + +Surface::~Surface() +{ + delete getSurface(mValue); +} + +void Surface::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; + getSurface(mValue)->setColor(r, g, b, a); +} + +void Surface::setColor(const float pRed, const float pGreen, + const float pBlue, const float pAlpha) +{ + getSurface(mValue)->setColor(pRed, pGreen, pBlue, pAlpha); +} + +void Surface::setLegend(const char* pLegend) +{ + getSurface(mValue)->setLegend(pLegend); +} + +uint Surface::vertices() const +{ + return getSurface(mValue)->vbo(); +} + +uint Surface::colors() const +{ + return getSurface(mValue)->cbo(); +} + +uint Surface::alphas() const +{ + return getSurface(mValue)->abo(); +} + +uint Surface::verticesSize() const +{ + return (uint)getSurface(mValue)->vboSize(); +} + +uint Surface::colorsSize() const +{ + return (uint)getSurface(mValue)->cboSize(); +} + +uint Surface::alphasSize() const +{ + return (uint)getSurface(mValue)->aboSize(); +} + +fg_surface Surface::get() const +{ + return mValue; +} + +} diff --git a/src/api/cpp/window.cpp b/src/api/cpp/window.cpp new file mode 100644 index 00000000..c2ba4476 --- /dev/null +++ b/src/api/cpp/window.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 + +namespace fg +{ + +Window::Window(int pWidth, int pHeight, const char* pTitle, const Window* pWindow, const bool invisible) +{ + if (pWindow == nullptr) { + mValue = getHandle(new common::Window(pWidth, pHeight, pTitle, nullptr, invisible)); + } else { + mValue = getHandle(new common::Window(pWidth, pHeight, pTitle, getWindow(pWindow->get()), invisible)); + } +} + +Window::~Window() +{ + delete getWindow(mValue); +} + +Window::Window(const Window& other) +{ + mValue = getHandle(new common::Window(other.get())); +} + +void Window::setFont(Font* pFont) +{ + getWindow(mValue)->setFont(getFont(pFont->get())); +} + +void Window::setTitle(const char* pTitle) +{ + getWindow(mValue)->setTitle(pTitle); +} + +void Window::setPos(int pX, int pY) +{ + getWindow(mValue)->setPos(pX, pY); +} + +void Window::setSize(unsigned pW, unsigned pH) +{ + getWindow(mValue)->setSize(pW, pH); +} + +void Window::setColorMap(ColorMap cmap) +{ + getWindow(mValue)->setColorMap(cmap); +} + +long long Window::context() const +{ + return getWindow(mValue)->context(); +} + +long long Window::display() const +{ + return getWindow(mValue)->display(); +} + +int Window::width() const +{ + return getWindow(mValue)->width(); +} + +int Window::height() const +{ + return getWindow(mValue)->height(); +} + +fg_window Window::get() const +{ + return getWindow(mValue); +} + +void Window::hide() +{ + getWindow(mValue)->hide(); +} + +void Window::show() +{ + getWindow(mValue)->show(); +} + +bool Window::close() +{ + return getWindow(mValue)->close(); +} + +void Window::makeCurrent() +{ + getWindow(mValue)->makeCurrent(); +} + +void Window::draw(const Image& pImage, const bool pKeepAspectRatio) +{ + getWindow(mValue)->draw(getImage(pImage.get()), pKeepAspectRatio); +} + +void Window::draw(const Chart& pChart) +{ + getWindow(mValue)->draw(getChart(pChart.get())); +} + +void Window::grid(int pRows, int pCols) +{ + getWindow(mValue)->grid(pRows, pCols); +} + +void Window::draw(int pColId, int pRowId, const Image& pImage, const char* pTitle, const bool pKeepAspectRatio) +{ + getWindow(mValue)->draw(pColId, pRowId, getImage(pImage.get()), pTitle, pKeepAspectRatio); +} + +void Window::draw(int pColId, int pRowId, const Chart& pChart, const char* pTitle) +{ + getWindow(mValue)->draw(pColId, pRowId, getChart(pChart.get()), pTitle); +} + +void Window::swapBuffers() +{ + getWindow(mValue)->swapBuffers(); +} + +void Window::saveFrameBuffer(const char* pFullPath) +{ + getWindow(mValue)->saveFrameBuffer(pFullPath); +} + +} diff --git a/src/backend/Chart.hpp b/src/backend/Chart.hpp new file mode 100644 index 00000000..b249bc0c --- /dev/null +++ b/src/backend/Chart.hpp @@ -0,0 +1,82 @@ +/******************************************************* +* 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 + +namespace common +{ + +class Chart { + private: + fg::ChartType mChartType; + std::shared_ptr mChart; + + public: + Chart(const fg::ChartType cType) + : mChartType(cType) { + if (cType == FG_CHART_2D) { + mChart = std::make_shared(); + } else if (cType == FG_CHART_3D) { + mChart = std::make_shared(); + } else { + throw fg::ArgumentError("Chart::Chart", + __LINE__, 0, + "Invalid chart type"); + } + } + + Chart(const fg_chart pOther) { + mChart = reinterpret_cast(pOther)->impl(); + } + + inline fg::ChartType chartType() const { + return mChartType; + } + + inline const std::shared_ptr& impl() const { + return mChart; + } + + inline void setAxesTitles(const char* pX, + const char* pY, + const char* pZ) { + mChart->setAxesTitles(pX, pY, pZ); + } + + inline void setAxesLimits(const float pXmin, const float pXmax, + const float pYmin, const float pYmax, + const float pZmin, const float pZmax) { + mChart->setAxesLimits(pXmin, pXmax, pYmin, pYmax, pZmin, pZmax); + } + + inline void setLegendPosition(const uint pX, const uint pY) { + mChart->setLegendPosition(pX, pY); + } + + inline void addRenderable(const std::shared_ptr pRenderable) { + mChart->addRenderable(pRenderable); + } + + inline void render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4 &pTransform) const { + mChart->render(pWindowId, pX, pY, pVPW, pVPH, pTransform); + } +}; + +} diff --git a/src/backend/Font.hpp b/src/backend/Font.hpp new file mode 100644 index 00000000..760a4cdf --- /dev/null +++ b/src/backend/Font.hpp @@ -0,0 +1,48 @@ +/******************************************************* +* 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 + +namespace common +{ + +class Font { + private: + std::shared_ptr mFont; + + public: + Font() : mFont(std::make_shared()) {} + + Font(const fg_font pOther) { + mFont = reinterpret_cast(pOther)->impl(); + } + + const std::shared_ptr& impl() const { + return mFont; + } + + inline void setOthro2D(int pWidth, int pHeight) { + mFont->setOthro2D(pWidth, pHeight); + } + + inline void loadFont(const char* const pFile) { + mFont->loadFont(pFile); + } + + inline void loadSystemFont(const char* const pName) { + mFont->loadSystemFont(pName); + } +}; + +} diff --git a/src/backend/Image.hpp b/src/backend/Image.hpp new file mode 100644 index 00000000..a6daec2c --- /dev/null +++ b/src/backend/Image.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 + +namespace common +{ + +class Image { + private: + std::shared_ptr mImage; + + public: + Image(const uint pWidth, const uint pHeight, + const fg::ChannelFormat pFormat, const fg::dtype pDataType) + : mImage(std::make_shared(pWidth, pHeight, pFormat, pDataType)) {} + + Image(const fg_image pOther) { + mImage = reinterpret_cast(pOther)->impl(); + } + + inline const std::shared_ptr& impl() const { return mImage; } + + inline void setAlpha(const float pAlpha) { mImage->setAlpha(pAlpha); } + + inline void keepAspectRatio(const bool pKeep) { mImage->keepAspectRatio(pKeep); } + + inline uint width() const { return mImage->width(); } + + inline uint height() const { return mImage->height(); } + + inline fg::ChannelFormat pixelFormat() const { return mImage->pixelFormat(); } + + inline fg::dtype channelType() const { return mImage->channelType(); } + + inline GLuint pbo() const { return mImage->pbo(); } + + inline size_t size() const { return mImage->size(); } + + inline void render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4& pTransform) const { + mImage->render(pWindowId, pX, pY, pVPW, pVPH, pTransform); + } +}; + +} diff --git a/src/backend/Window.hpp b/src/backend/Window.hpp new file mode 100644 index 00000000..31b15550 --- /dev/null +++ b/src/backend/Window.hpp @@ -0,0 +1,141 @@ +/******************************************************* +* 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 common +{ + +class Window { + private: + std::shared_ptr mWindow; + + Window() {} + + public: + + Window(int pWidth, int pHeight, const char* pTitle, + const Window* pWindow, const bool invisible = false) { + if (pWindow) { + mWindow = std::make_shared(pWidth, pHeight, pTitle, + pWindow->impl(), invisible); + } else { + std::shared_ptr other; + mWindow = std::make_shared(pWidth, pHeight, pTitle, + other, invisible); + } + } + + Window(const fg_window pOther) { + mWindow = reinterpret_cast(pOther)->impl(); + } + + inline const std::shared_ptr& impl () const { + return mWindow; + } + + inline void setFont (Font* pFont) { + mWindow->setFont (pFont->impl()); + } + + inline void setTitle(const char* pTitle) { + mWindow->setTitle(pTitle); + } + + inline void setPos(int pX, int pY) { + mWindow->setPos(pX, pY); + } + + inline void setSize(unsigned pWidth, int pHeight) { + mWindow->setSize(pWidth, pHeight); + } + + inline void setColorMap(fg::ColorMap cmap) { + mWindow->setColorMap(cmap); + } + + inline int getID() const { + return mWindow->getID(); + } + + inline long long context() const { + return mWindow->context() ; + } + + inline long long display() const { + return mWindow->display(); + } + + inline int width() const { + return mWindow->width(); + } + + inline int height() const { + return mWindow->height(); + } + + inline void makeCurrent() { + MakeContextCurrent(mWindow.get()); + } + + inline void hide() { + mWindow->hide(); + } + + inline void show() { + mWindow->show(); + } + + inline bool close() { + return mWindow->close(); + } + + inline void draw(Image* pImage, const bool pKeepAspectRatio) { + pImage->keepAspectRatio(pKeepAspectRatio); + mWindow->draw(pImage->impl()) ; + } + + inline void draw(const Chart* pChart) { + mWindow->draw(pChart->impl()) ; + } + + inline void swapBuffers() { + mWindow->swapBuffers(); + } + + inline void grid(int pRows, int pCols) { + mWindow->grid(pRows, pCols); + } + + template + void draw(int pColId, int pRowId, T* pRenderable, const char* pTitle) { + mWindow->draw(pColId, pRowId, pRenderable->impl(), pTitle); + } + + void draw(int pColId, int pRowId, Image* pRenderable, + const char* pTitle, const bool pKeepAspectRatio) { + pRenderable->keepAspectRatio(pKeepAspectRatio); + mWindow->draw(pColId, pRowId, pRenderable->impl(), pTitle); + } + + inline void saveFrameBuffer(const char* pFullPath) { + mWindow->saveFrameBuffer(pFullPath); + } +}; + +} diff --git a/src/backend/chart_common.hpp b/src/backend/chart_common.hpp new file mode 100644 index 00000000..a3f8b9b2 --- /dev/null +++ b/src/backend/chart_common.hpp @@ -0,0 +1,79 @@ +/******************************************************* +* 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 + +namespace common +{ + +// Objects of type `RenderableType` in the following class definition +// should implement all the member functons of ChartRenderableBase +// class, otherwise you cannot use this class. +template +class ChartRenderableBase { + protected: + std::shared_ptr< RenderableType > mShrdPtr; + + public: + ChartRenderableBase() { + } + + ChartRenderableBase(const std::shared_ptr< RenderableType > &pValue) + : mShrdPtr(pValue) { + } + + inline const std::shared_ptr< RenderableType >& impl() const { + return mShrdPtr; + } + + inline void setColor(const float pRed, const float pGreen, + const float pBlue, const float pAlpha) { + mShrdPtr->setColor(pRed, pGreen, pBlue, pAlpha); + } + + inline void setLegend(const char* pLegend) { + mShrdPtr->setLegend(pLegend); + } + + inline GLuint vbo() const { + return mShrdPtr->vbo(); + } + + inline GLuint cbo() const { + return mShrdPtr->cbo(); + } + + inline GLuint abo() const { + return mShrdPtr->abo(); + } + + inline size_t vboSize() const { + return mShrdPtr->vboSize(); + } + + inline size_t cboSize() const { + return mShrdPtr->cboSize(); + } + + inline size_t aboSize() const { + return mShrdPtr->aboSize(); + } + + inline void render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4& pTransform) const { + mShrdPtr->render(pWindowId, pX, pY, pVPW, pVPH, pTransform); + } +}; + +} diff --git a/src/backend/chart_renderables.hpp b/src/backend/chart_renderables.hpp new file mode 100644 index 00000000..aedeaa7e --- /dev/null +++ b/src/backend/chart_renderables.hpp @@ -0,0 +1,91 @@ +/******************************************************* +* 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 common +{ + +class Histogram : public ChartRenderableBase { + public: + Histogram(uint pNBins, fg::dtype pDataType) + : ChartRenderableBase( + std::make_shared(pNBins, pDataType)) { + } + + Histogram(const fg_histogram pOther) + : ChartRenderableBase( + reinterpret_cast(pOther)->impl()) { + } +}; + +class Plot : public ChartRenderableBase { + public: + Plot(const uint pNumPoints, const fg::dtype pDataType, + const fg::PlotType pPlotType, const fg::MarkerType pMarkerType, + const fg::ChartType pChartType) { + if (pChartType == FG_CHART_2D) { + mShrdPtr = std::make_shared< detail::plot2d_impl >(pNumPoints, pDataType, + pPlotType, pMarkerType); + } else { + mShrdPtr = std::make_shared< detail::plot_impl >(pNumPoints, pDataType, + pPlotType, pMarkerType); + } + } + + Plot(const fg_plot pOther) + : ChartRenderableBase( + reinterpret_cast(pOther)->impl()) { + } + + inline void setMarkerSize(const float pMarkerSize) { + mShrdPtr->setMarkerSize(pMarkerSize); + } + + inline GLuint mbo() const { + return mShrdPtr->markers(); + } + + inline size_t mboSize() const { + return mShrdPtr->markersSizes(); + } +}; + +class Surface : public ChartRenderableBase { + public: + Surface(const uint pNumXPoints, const uint pNumYPoints, + const fg::dtype pDataType, const fg::PlotType pPlotType=FG_PLOT_SURFACE, + const fg::MarkerType pMarkerType=FG_MARKER_NONE) { + switch(pPlotType){ + case(FG_PLOT_SURFACE): + mShrdPtr = std::make_shared(pNumXPoints, pNumYPoints, pDataType, pMarkerType); + break; + case(FG_PLOT_SCATTER): + mShrdPtr = std::make_shared(pNumXPoints, pNumYPoints, pDataType, pMarkerType); + break; + default: + mShrdPtr = std::make_shared(pNumXPoints, pNumYPoints, pDataType, pMarkerType); + }; + } + + Surface(const fg_surface pOther) + : ChartRenderableBase( + reinterpret_cast(pOther)->impl()) { + } +}; + +} diff --git a/src/cmap.hpp b/src/backend/cmap.hpp similarity index 100% rename from src/cmap.hpp rename to src/backend/cmap.hpp diff --git a/src/backend/err_common.cpp b/src/backend/err_common.cpp new file mode 100644 index 00000000..56624088 --- /dev/null +++ b/src/backend/err_common.cpp @@ -0,0 +1,77 @@ +/******************************************************* + * Copyright (c) 2016, 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 + +using namespace fg; + +using std::string; +using std::stringstream; + +std::string& getGlobalErrorString() +{ + static std::string global_error_string = std::string(""); + return global_error_string; +} + +void print_error(const string &msg) +{ + std::string perr = getEnvVar("FG_PRINT_ERRORS"); + if(!perr.empty()) { + if(perr != "0") + fprintf(stderr, "%s\n", msg.c_str()); + } + + getGlobalErrorString() = msg; +} + +fg_err processException() +{ + stringstream ss; + fg_err err= FG_ERR_INTERNAL; + + try { + throw; + } catch (const TypeError &ex) { + ss << ex << std::endl + << "In function " << ex.functionName() << "\n" + << "Invalid type for argument " << ex.argIndex() << "\n" + << "Expects the type : "<< ex.typeName() << "\n"; + + print_error(ss.str()); + err = FG_ERR_INVALID_TYPE; + } catch (const ArgumentError &ex) { + ss << ex << std::endl + << "In function " << ex.functionName() << "\n" + << "Invalid argument at index " << ex.argIndex() << "\n" + << "Expected: " << ex.expectedCondition() << "\n"; + + print_error(ss.str()); + err = FG_ERR_INVALID_ARG; + } catch (const DimensionError &ex) { + ss << ex << std::endl + << "In function " << ex.functionName() << "\n" + << "Invalid argument at index " << ex.argIndex() << "\n" + << "Expected: " << ex.expectedCondition() << "\n"; + + print_error(ss.str()); + err = FG_ERR_SIZE; + } catch (...) { + print_error(ss.str()); + err = FG_ERR_UNKNOWN; + } + + return err; +} diff --git a/src/backend/err_common.hpp b/src/backend/err_common.hpp new file mode 100644 index 00000000..2b496f2c --- /dev/null +++ b/src/backend/err_common.hpp @@ -0,0 +1,26 @@ +/******************************************************* + * Copyright (c) 2016, 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 + +void print_error(const std::string &msg); + +fg_err processException(); + +#define CATCHALL \ + catch(...) { \ + return processException(); \ + } diff --git a/src/backend/handle.cpp b/src/backend/handle.cpp new file mode 100644 index 00000000..9ef70d87 --- /dev/null +++ b/src/backend/handle.cpp @@ -0,0 +1,80 @@ +/******************************************************* +* 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 + +fg_window getHandle(common::Window* pValue) +{ + return reinterpret_cast(pValue); +} + +fg_font getHandle(common::Font* pValue) +{ + return reinterpret_cast(pValue); +} + +fg_image getHandle(common::Image* pValue) +{ + return reinterpret_cast(pValue); +} + +fg_chart getHandle(common::Chart* pValue) +{ + return reinterpret_cast(pValue); +} + +fg_histogram getHandle(common::Histogram* pValue) +{ + return reinterpret_cast(pValue); +} + +fg_plot getHandle(common::Plot* pValue) +{ + return reinterpret_cast(pValue); +} + +fg_surface getHandle(common::Surface* pValue) +{ + return reinterpret_cast(pValue); +} + +common::Window* getWindow(const fg_window& pValue) +{ + return reinterpret_cast(pValue); +} + +common::Font* getFont(const fg_font& pValue) +{ + return reinterpret_cast(pValue); +} + +common::Image* getImage(const fg_image& pValue) +{ + return reinterpret_cast(pValue); +} + +common::Chart* getChart(const fg_chart& pValue) +{ + return reinterpret_cast(pValue); +} + +common::Histogram* getHistogram(const fg_histogram& pValue) +{ + return reinterpret_cast(pValue); +} + +common::Plot* getPlot(const fg_plot& pValue) +{ + return reinterpret_cast(pValue); +} + +common::Surface* getSurface(const fg_surface& pValue) +{ + return reinterpret_cast(pValue); +} diff --git a/src/backend/handle.hpp b/src/backend/handle.hpp new file mode 100644 index 00000000..a2eb0f86 --- /dev/null +++ b/src/backend/handle.hpp @@ -0,0 +1,46 @@ +/******************************************************* +* 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 + +fg_window getHandle(common::Window* pValue); + +fg_font getHandle(common::Font* pValue); + +fg_image getHandle(common::Image* pValue); + +fg_chart getHandle(common::Chart* pValue); + +fg_histogram getHandle(common::Histogram* pValue); + +fg_plot getHandle(common::Plot* pValue); + +fg_surface getHandle(common::Surface* pValue); + +common::Window* getWindow(const fg_window& pValue); + +common::Font* getFont(const fg_font& pValue); + +common::Image* getImage(const fg_image& pValue); + +common::Chart* getChart(const fg_chart& pValue); + +common::Histogram* getHistogram(const fg_histogram& pValue); + +common::Plot* getPlot(const fg_plot& pValue); + +common::Surface* getSurface(const fg_surface& pValue); diff --git a/src/CMakeLists.txt b/src/backend/opengl/CMakeLists.txt similarity index 56% rename from src/CMakeLists.txt rename to src/backend/opengl/CMakeLists.txt index e8546b58..bcb55766 100755 --- a/src/CMakeLists.txt +++ b/src/backend/opengl/CMakeLists.txt @@ -5,6 +5,8 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) FIND_PACKAGE(GLM QUIET) FIND_PACKAGE(glm QUIET) +INCLUDE("${CMAKE_MODULE_PATH}/GLSLtoH.cmake") + IF((NOT glm_FOUND AND NOT GLM_FOUND) OR (${USE_LOCAL_GLM})) SET(USE_LOCAL_GLM ON) MESSAGE(STATUS "Downloading GLM headers.") @@ -61,12 +63,19 @@ ELSE(UNIX) #Windows SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") ENDIF(UNIX) +# DON'T REMOVE CURRENT BINARY DIRECTORY FROM +# INCLUDE_DIRECTORIES, IT IS USED TO FIND +# AUTO-GENERATED GLSL HEADERS INCLUDE_DIRECTORIES( ${CMAKE_INCLUDE_PATH} ${FREETYPE_INCLUDE_DIRS} ${GLM_INCLUDE_DIRS} ${WTK_INCLUDE_DIRS} - "${PROJECT_SOURCE_DIR}/src" + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + "${PROJECT_SOURCE_DIR}/src/api/c" + "${PROJECT_SOURCE_DIR}/src/api/cpp" + "${PROJECT_SOURCE_DIR}/src/backend" ) IF(UNIX) @@ -78,42 +87,94 @@ FILE(GLOB api_headers "${PROJECT_SOURCE_DIR}/include/fg/*.h" ) -FILE(GLOB headers +FILE(GLOB c_api_headers + "${PROJECT_SOURCE_DIR}/src/api/c/*.hpp" + ) +FILE(GLOB c_api_sources + "${PROJECT_SOURCE_DIR}/src/api/c/*.cpp" + ) +FILE(GLOB cpp_api_headers + "${PROJECT_SOURCE_DIR}/src/api/cpp/*.hpp" + ) +FILE(GLOB cpp_api_sources + "${PROJECT_SOURCE_DIR}/src/api/cpp/*.cpp" + ) + +FILE(GLOB bknd_headers + "${PROJECT_SOURCE_DIR}/src/backend/*.hpp" + ) + +FILE(GLOB bknd_sources + "${PROJECT_SOURCE_DIR}/src/backend/*.cpp" + ) + +FILE(GLOB gl_headers "*.hpp" "*.h" ) -FILE(GLOB sources +FILE(GLOB gl_sources "*.c" "*.cpp" ) -SOURCE_GROUP(API FILES ${api_headers}) -SOURCE_GROUP(Headers FILES ${headers}) -SOURCE_GROUP(Sources FILES ${sources}) +SET(glsl_shader_headers + "shader_headers") +FILE(GLOB glsl_shaders + "shaders/*.glsl") + +SOURCE_GROUP(inc FILES ${api_headers}) + +SOURCE_GROUP("src\\api\\c\\headers" FILES ${c_api_headers}) +SOURCE_GROUP("src\\api\\c\\sources" FILES ${c_api_sources}) + +SOURCE_GROUP("src\\api\\cpp\\headers" FILES ${cpp_api_headers}) +SOURCE_GROUP("src\\api\\cpp\\sources" FILES ${cpp_api_sources}) + +SOURCE_GROUP("src\\backend" FILES ${bknd_headers}) +SOURCE_GROUP("src\\backend" FILES ${bknd_sources}) + +SOURCE_GROUP("src\\backend\\opengl\\headers" FILES ${gl_headers}) +SOURCE_GROUP("src\\backend\\opengl\\sources" FILES ${gl_sources}) IF(${USE_WINDOW_TOOLKIT} STREQUAL "glfw3") FILE(GLOB wtk_headers "glfw/*.hpp") FILE(GLOB wtk_sources "glfw/*.cpp") - SOURCE_GROUP(Headers\\glfw FILES ${wtk_headers}) - SOURCE_GROUP(Sources\\glfw FILES ${wtk_sources}) - + SOURCE_GROUP("src\\backend\\opengl\\glfw\\headers" FILES ${wtk_headers}) + SOURCE_GROUP("src\\backend\\opengl\\glfw\\sources" FILES ${wtk_sources}) ELSEIF(${USE_WINDOW_TOOLKIT} STREQUAL "sdl2") FILE(GLOB wtk_headers "sdl/*.hpp") FILE(GLOB wtk_sources "sdl/*.cpp") - SOURCE_GROUP(Headers\\sdl FILES ${wtk_headers}) - SOURCE_GROUP(Sources\\sdl FILES ${wtk_sources}) - + SOURCE_GROUP("src\\backend\\opengl\\sdl\\headers" FILES ${wtk_headers}) + SOURCE_GROUP("src\\backend\\opengl\\sdl\\sources" FILES ${wtk_sources}) ENDIF() +SOURCE_GROUP("src\\backend\\opengl\\glsl" FILES ${glsl_shaders}) + +GLSL_TO_H( + SOURCES ${glsl_shaders} + VARNAME shader_files + EXTENSION "hpp" + OUTPUT_DIR ${glsl_shader_headers} + TARGETS glsl_shader_targets + NAMESPACE "glsl" + EOD "0" + ) + ADD_LIBRARY(forge SHARED ${api_headers} - ${headers} - ${sources} + ${c_api_headers} + ${c_api_sources} + ${cpp_api_headers} + ${cpp_api_sources} + ${bknd_headers} + ${bknd_sources} + ${gl_headers} + ${gl_sources} ${wtk_headers} ${wtk_sources} ) @@ -124,9 +185,12 @@ TARGET_LINK_LIBRARIES(forge PRIVATE ${WTK_LIBRARIES} PRIVATE ${OPENGL_gl_LIBRARY} PRIVATE ${GLEWmx_LIBRARY} + PRIVATE ${FREEIMAGE_LIBRARY} PRIVATE ${X11_LIBS} ) +ADD_DEPENDENCIES(forge ${glsl_shader_targets}) + INSTALL(TARGETS forge EXPORT FORGE DESTINATION "${FG_INSTALL_LIB_DIR}" diff --git a/src/backend/opengl/backend.hpp b/src/backend/opengl/backend.hpp new file mode 100644 index 00000000..07d9c745 --- /dev/null +++ b/src/backend/opengl/backend.hpp @@ -0,0 +1,14 @@ +/******************************************************* + * 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 + +namespace detail = opengl; diff --git a/src/chart.cpp b/src/backend/opengl/chart.cpp similarity index 58% rename from src/chart.cpp rename to src/backend/opengl/chart.cpp index 9bb05dfb..db2a3cd0 100644 --- a/src/chart.cpp +++ b/src/backend/opengl/chart.cpp @@ -7,66 +7,52 @@ * 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 #include +#include +#include +#include + using namespace std; typedef std::vector::const_iterator StringIter; -static const int CHART2D_FONT_SIZE = 15; - -const char *gChartVertexShaderSrc = -"#version 330\n" -"in vec3 point;\n" -"uniform mat4 transform;\n" -"void main(void) {\n" -" gl_Position = transform * vec4(point.xyz, 1);\n" -"}"; - -const char *gChartFragmentShaderSrc = -"#version 330\n" -"uniform vec4 color;\n" -"out vec4 outputColor;\n" -"void main(void) {\n" -" outputColor = color;\n" -"}"; - -const char *gChartSpriteFragmentShaderSrc = -"#version 330\n" -"uniform bool isYAxis;\n" -"uniform vec4 tick_color;\n" -"out vec4 outputColor;\n" -"void main(void) {\n" -" bool y_axis = isYAxis && abs(gl_PointCoord.y)>0.2;\n" -" bool x_axis = !isYAxis && abs(gl_PointCoord.x)>0.2;\n" -" if(y_axis || x_axis)\n" -" discard;\n" -" else\n" -" outputColor = tick_color;\n" -"}"; - -const std::shared_ptr& getChartFont() +static const int CHART2D_FONT_SIZE = 16; + +const std::shared_ptr& getChartFont() { - static internal::_Font mChartFont; + static common::Font gChartFont; static std::once_flag flag; std::call_once(flag, []() { #if defined(OS_WIN) - mChartFont.loadSystemFont("Calibri", 32); + gChartFont.loadSystemFont("Calibri"); #else - mChartFont.loadSystemFont("Vera", 32); + gChartFont.loadSystemFont("Vera"); #endif }); - return mChartFont.impl(); + return gChartFont.impl(); } template @@ -84,48 +70,54 @@ void pushPoint(vector &points, T x, T y, T z) points.push_back(z); } -namespace internal +namespace opengl { /********************* BEGIN-AbstractChart *********************/ -void AbstractChart::renderTickLabels(int pWindowId, unsigned w, unsigned h, - std::vector &texts, - glm::mat4 &transformation, int coor_offset, - bool useZoffset) +void AbstractChart::renderTickLabels( + const int pWindowId, const uint pW, const uint pH, + const std::vector &pTexts, + const glm::mat4 &pTransformation, const int pCoordsOffset, + const bool pUseZoffset) const { auto &fonter = getChartFont(); - fonter->setOthro2D(int(w), int(h)); + fonter->setOthro2D(int(pW), int(pH)); float pos[2]; - for (StringIter it = texts.begin(); it!=texts.end(); ++it) { - int idx = int(it - texts.begin()); - glm::vec4 p = glm::vec4(mTickTextX[idx+coor_offset], - mTickTextY[idx+coor_offset], - (useZoffset ? mTickTextZ[idx+coor_offset] : 0), 1); - glm::vec4 res = transformation * p; + for (StringIter it = pTexts.begin(); it!=pTexts.end(); ++it) { + int idx = int(it - pTexts.begin()); + glm::vec4 p = glm::vec4(mTickTextX[idx+pCoordsOffset], + mTickTextY[idx+pCoordsOffset], + (pUseZoffset ? mTickTextZ[idx+pCoordsOffset] : 0), 1); + glm::vec4 res = pTransformation * p; /* convert text position from [-1,1] range to * [0, 1) range and then offset horizontally * to compensate for margins and ticksize */ - pos[0] = w*(res.x/res.w+1.0f)/2.0f; - pos[1] = h*(res.y/res.w+1.0f)/2.0f; + pos[0] = pW * (res.x/res.w+1.0f)/2.0f; + pos[1] = pH * (res.y/res.w+1.0f)/2.0f; /* offset based on text size to align * text center with tick mark position */ - if(coor_offset < mTickCount) { - pos[0] -= ((CHART2D_FONT_SIZE*it->length()/2.0f)); - }else if(coor_offset >= mTickCount && coor_offset < 2*mTickCount) { - pos[1] -= ((CHART2D_FONT_SIZE)); + if(pCoordsOffset < mTickCount) { + // offset for y axis labels + pos[0] -= (CHART2D_FONT_SIZE*it->length()/2.0f+mTickSize); + }else if(pCoordsOffset >= mTickCount && pCoordsOffset < 2*mTickCount) { + // offset for x axis labels + pos[0] -= (CHART2D_FONT_SIZE*it->length()/4.0f); + pos[1] -= (CHART2D_FONT_SIZE*1.32); }else { - pos[0] -= ((CHART2D_FONT_SIZE*it->length()/2.0f)); - pos[1] -= ((CHART2D_FONT_SIZE)); + // offsets for 3d chart axes ticks + pos[0] -= (CHART2D_FONT_SIZE*it->length()/2.0f); + pos[1] -= (CHART2D_FONT_SIZE); } - fonter->render(pWindowId, pos, WHITE, it->c_str(), CHART2D_FONT_SIZE); + fonter->render(pWindowId, pos, BLACK, it->c_str(), CHART2D_FONT_SIZE); } } -AbstractChart::AbstractChart(int pLeftMargin, int pRightMargin, int pTopMargin, int pBottomMargin) +AbstractChart::AbstractChart(const int pLeftMargin, const int pRightMargin, + const int pTopMargin, const int pBottomMargin) : mTickCount(9), mTickSize(10), mLeftMargin(pLeftMargin), mRightMargin(pRightMargin), mTopMargin(pTopMargin), mBottomMargin(pBottomMargin), @@ -134,7 +126,8 @@ AbstractChart::AbstractChart(int pLeftMargin, int pRightMargin, int pTopMargin, mDecorVBO(-1), mBorderProgram(-1), mSpriteProgram(-1), mBorderAttribPointIndex(-1), mBorderUniformColorIndex(-1), mBorderUniformMatIndex(-1), mSpriteUniformMatIndex(-1), - mSpriteUniformTickcolorIndex(-1), mSpriteUniformTickaxisIndex(-1) + mSpriteUniformTickcolorIndex(-1), mSpriteUniformTickaxisIndex(-1), + mLegendX(0.4f), mLegendY(0.9f) { CheckGL("Begin AbstractChart::AbstractChart"); /* load font Vera font for chart text @@ -144,8 +137,8 @@ AbstractChart::AbstractChart(int pLeftMargin, int pRightMargin, int pTopMargin, * are loaded into the shared Font object */ getChartFont(); - mBorderProgram = initShaders(gChartVertexShaderSrc, gChartFragmentShaderSrc); - mSpriteProgram = initShaders(gChartVertexShaderSrc, gChartSpriteFragmentShaderSrc); + mBorderProgram = initShaders(glsl::chart_vs.c_str(), glsl::chart_fs.c_str()); + mSpriteProgram = initShaders(glsl::chart_vs.c_str(), glsl::tick_fs.c_str()); mBorderAttribPointIndex = glGetAttribLocation (mBorderProgram, "point"); mBorderUniformColorIndex = glGetUniformLocation(mBorderProgram, "color"); @@ -171,9 +164,9 @@ AbstractChart::~AbstractChart() CheckGL("End AbstractChart::~AbstractChart"); } -void AbstractChart::setAxesLimits(float pXmax, float pXmin, - float pYmax, float pYmin, - float pZmax, float pZmin) +void AbstractChart::setAxesLimits(const float pXmin, const float pXmax, + const float pYmin, const float pYmax, + const float pZmin, const float pZmax) { mXMax = pXmax; mXMin = pXmin; mYMax = pYmax; mYMin = pYmin; @@ -188,11 +181,20 @@ void AbstractChart::setAxesLimits(float pXmax, float pXmin, generateTickLabels(); } -void AbstractChart::setAxesTitles(const char* pXTitle, const char* pYTitle, const char* pZTitle) +void AbstractChart::setAxesTitles(const char* pXTitle, + const char* pYTitle, + const char* pZTitle) { mXTitle = std::string(pXTitle); mYTitle = std::string(pYTitle); - mZTitle = std::string(pZTitle); + if (pZTitle) + mZTitle = std::string(pZTitle); +} + +void AbstractChart::setLegendPosition(const float pX, const float pY) +{ + mLegendX = pX; + mLegendY = pY; } float AbstractChart::xmax() const { return mXMax; } @@ -202,15 +204,20 @@ float AbstractChart::ymin() const { return mYMin; } float AbstractChart::zmax() const { return mZMax; } float AbstractChart::zmin() const { return mZMin; } +void AbstractChart::addRenderable(const std::shared_ptr pRenderable) +{ + mRenderables.emplace_back(pRenderable); +} + /********************* END-AbstractChart *********************/ -/********************* BEGIN-Chart2D *********************/ +/********************* BEGIN-chart2d_impl *********************/ -void Chart2D::bindResources(int pWindowId) +void chart2d_impl::bindResources(const int pWindowId) { - CheckGL("Begin Chart2D::bindResources"); + CheckGL("Begin chart2d_impl::bindResources"); if (mVAOMap.find(pWindowId) == mVAOMap.end()) { GLuint vao = 0; /* create a vertex array object @@ -226,23 +233,23 @@ void Chart2D::bindResources(int pWindowId) mVAOMap[pWindowId] = vao; } glBindVertexArray(mVAOMap[pWindowId]); - CheckGL("End Chart2D::bindResources"); + CheckGL("End chart2d_impl::bindResources"); } -void Chart2D::unbindResources() const +void chart2d_impl::unbindResources() const { glBindVertexArray(0); } -void Chart2D::pushTicktextCoords(float x, float y, float z) +void chart2d_impl::pushTicktextCoords(const float pX, const float pY, const float pZ) { - mTickTextX.push_back(x); - mTickTextY.push_back(y); + mTickTextX.push_back(pX); + mTickTextY.push_back(pY); } -void Chart2D::generateChartData() +void chart2d_impl::generateChartData() { - CheckGL("Begin Chart2D::generateChartData"); + CheckGL("Begin chart2d_impl::generateChartData"); static const float border[8] = { -1, -1, 1, -1, 1, 1, -1, 1 }; static const int nValues = sizeof(border)/sizeof(float); @@ -250,11 +257,12 @@ void Chart2D::generateChartData() std::copy(border, border+nValues, std::back_inserter(decorData)); float step = 2.0f/(mTickCount); + int ticksLeft = mTickCount/2; + /* push tick points for y axis: * push (0) first followed by * [-1, 0) ticks and then * (0, 1] ticks */ - int ticksLeft = mTickCount/2; pushPoint(decorData, -1.0f, 0.0f); pushTicktextCoords(-1.0f, 0.0f); mYText.push_back(toString(0)); @@ -299,6 +307,23 @@ void Chart2D::generateChartData() mXText.push_back(toString(pos)); } + /* push grid lines */ + pushPoint(decorData, -1.0f, 0.0f); + pushPoint(decorData, 1.0f, 0.0f); + pushPoint(decorData, 0.0f,-1.0f); + pushPoint(decorData, 0.0f, 1.0f); + for (int i=1; i<=ticksLeft; ++i) { + float delta = i*step; + pushPoint(decorData, -1.0f,-delta); + pushPoint(decorData, 1.0f,-delta); + pushPoint(decorData, -1.0f, delta); + pushPoint(decorData, 1.0f, delta); + pushPoint(decorData,-delta, -1.0f); + pushPoint(decorData,-delta, 1.0f); + pushPoint(decorData, delta, -1.0f); + pushPoint(decorData, delta, 1.0f); + } + /* check if decoration VBO has been already used(case where * tick marks are being changed from default(21) */ if (mDecorVBO != 0) @@ -307,10 +332,10 @@ void Chart2D::generateChartData() /* create vbo that has the border and axis data */ mDecorVBO = createBuffer(GL_ARRAY_BUFFER, decorData.size(), &(decorData.front()), GL_STATIC_DRAW); - CheckGL("End Chart2D::generateChartData"); + CheckGL("End chart2d_impl::generateChartData"); } -void Chart2D::generateTickLabels() +void chart2d_impl::generateTickLabels() { /* remove all the tick text markers that were generated * by default during the base class(chart) creation and @@ -327,10 +352,18 @@ void Chart2D::generateTickLabels() int ticksLeft = mTickCount/2; /* push tick points for y axis */ mYText.push_back(toString(ymid)); + size_t maxYLabelWidth = 0; for (int i = 1; i <= ticksLeft; i++) { - mYText.push_back(toString(ymid + i*-ystep)); - mYText.push_back(toString(ymid + i*ystep)); + std::string temp = toString(ymid + i*-ystep); + mYText.push_back(temp); + maxYLabelWidth = std::max(maxYLabelWidth, temp.length()); + temp = toString(ymid + i*ystep); + mYText.push_back(temp); + maxYLabelWidth = std::max(maxYLabelWidth, temp.length()); } + + mLeftMargin = std::max((int)maxYLabelWidth, mLeftMargin)+2*CHART2D_FONT_SIZE; + /* push tick points for x axis */ mXText.push_back(toString(xmid)); for (int i = 1; i <= ticksLeft; i++) { @@ -339,9 +372,16 @@ void Chart2D::generateTickLabels() } } -void Chart2D::renderChart(int pWindowId, int pX, int pY, int pVPW, int pVPH) +chart2d_impl::chart2d_impl() + : AbstractChart(64, 8, 8, 44) { + generateChartData(); +} + +void chart2d_impl::render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4& pTransform) { - CheckGL("Begin Chart2D::renderChart"); + CheckGL("Begin chart2d_impl::renderChart"); float w = float(pVPW - (mLeftMargin + mRightMargin + mTickSize)); float h = float(pVPH - (mTopMargin + mBottomMargin + mTickSize)); @@ -350,31 +390,44 @@ void Chart2D::renderChart(int pWindowId, int pX, int pY, int pVPW, int pVPH) float scale_x = w / pVPW; float scale_y = h / pVPH; - Chart2D::bindResources(pWindowId); - - /* bind the plotting shader program */ - glUseProgram(mBorderProgram); - /* set uniform attributes of shader * for drawing the plot borders */ glm::mat4 trans = glm::translate(glm::scale(glm::mat4(1), glm::vec3(scale_x, scale_y, 1)), glm::vec3(offset_x, offset_y, 0)); + + trans = pTransform*trans; + + /* Draw grid */ + chart2d_impl::bindResources(pWindowId); + glUseProgram(mBorderProgram); glUniformMatrix4fv(mBorderUniformMatIndex, 1, GL_FALSE, glm::value_ptr(trans)); - glUniform4fv(mBorderUniformColorIndex, 1, WHITE); + glUniform4fv(mBorderUniformColorIndex, 1, GRAY); + glDrawArrays(GL_LINES, 4+2*mTickCount, 4*mTickCount); + glUseProgram(0); + chart2d_impl::unbindResources(); + /* render all renderables */ + for (auto renderable : mRenderables) { + renderable->setRanges(mXMin, mXMax, mYMin, mYMax, mZMin, mZMax); + renderable->render(pWindowId, pX, pY, pVPW, pVPH, trans); + } + + chart2d_impl::bindResources(pWindowId); + + glUseProgram(mBorderProgram); + glUniformMatrix4fv(mBorderUniformMatIndex, 1, GL_FALSE, glm::value_ptr(trans)); + glUniform4fv(mBorderUniformColorIndex, 1, BLACK); /* Draw borders */ glDrawArrays(GL_LINE_LOOP, 0, 4); - - /* reset shader program binding */ glUseProgram(0); /* bind the sprite shader program to * draw ticks on x and y axes */ glPointSize((GLfloat)mTickSize); - glUseProgram(mSpriteProgram); - glUniform4fv(mSpriteUniformTickcolorIndex, 1, WHITE); + + glUniform4fv(mSpriteUniformTickcolorIndex, 1, BLACK); glUniformMatrix4fv(mSpriteUniformMatIndex, 1, GL_FALSE, glm::value_ptr(trans)); /* Draw tick marks on y axis */ glUniform1i(mSpriteUniformTickaxisIndex, 1); @@ -385,42 +438,59 @@ void Chart2D::renderChart(int pWindowId, int pX, int pY, int pVPW, int pVPH) glUseProgram(0); glPointSize(1); - Chart2D::unbindResources(); + chart2d_impl::unbindResources(); renderTickLabels(pWindowId, int(w), int(h), mYText, trans, 0, false); renderTickLabels(pWindowId, int(w), int(h), mXText, trans, mTickCount, false); auto &fonter = getChartFont(); fonter->setOthro2D(int(w), int(h)); + float pos[2]; /* render chart axes titles */ if (!mYTitle.empty()) { glm::vec4 res = trans * glm::vec4(-1.0f, 0.0f, 0.0f, 1.0f); - pos[0] = w*(res.x+1.0f)/2.0f; + pos[0] = CHART2D_FONT_SIZE; /* additional pixel gap from edge of rendering */ pos[1] = h*(res.y+1.0f)/2.0f; - pos[0] += (mTickSize * (w/pVPW)); - fonter->render(pWindowId, pos, WHITE, mYTitle.c_str(), CHART2D_FONT_SIZE, true); + fonter->render(pWindowId, pos, BLACK, mYTitle.c_str(), CHART2D_FONT_SIZE, true); } if (!mXTitle.empty()) { glm::vec4 res = trans * glm::vec4(0.0f, -1.0f, 0.0f, 1.0f); pos[0] = w*(res.x+1.0f)/2.0f; pos[1] = h*(res.y+1.0f)/2.0f; - pos[1] += (mTickSize * (h/pVPH)); - fonter->render(pWindowId, pos, WHITE, mXTitle.c_str(), CHART2D_FONT_SIZE); + pos[1] -= (4*mTickSize * (h/pVPH)); + fonter->render(pWindowId, pos, BLACK, mXTitle.c_str(), CHART2D_FONT_SIZE); } - CheckGL("End Chart2D::renderChart"); + /* render all legends of the respective renderables */ + pos[0] = mLegendX; + pos[1] = mLegendY; + + float lcol[4]; + + for (auto renderable : mRenderables) { + renderable->getColor(lcol[0], lcol[1], lcol[2], lcol[3]); + + float cpos[2]; + glm::vec4 res = trans * glm::vec4(pos[0], pos[1], 0.0f, 1.0f); + cpos[0] = res.x * w; + cpos[1] = res.y * h; + fonter->render(pWindowId, cpos, lcol, renderable->legend().c_str(), CHART2D_FONT_SIZE); + pos[1] -= (CHART2D_FONT_SIZE/(float)pVPH); + } + + CheckGL("End chart2d_impl::renderChart"); } -/********************* END-Chart2D *********************/ +/********************* END-chart2d_impl *********************/ -/********************* BEGIN-Chart3D *********************/ +/********************* BEGIN-chart3d_impl *********************/ -void Chart3D::bindResources(int pWindowId) +void chart3d_impl::bindResources(const int pWindowId) { - CheckGL("Begin Chart3D::bindResources"); + CheckGL("Begin chart3d_impl::bindResources"); if (mVAOMap.find(pWindowId) == mVAOMap.end()) { GLuint vao = 0; /* create a vertex array object @@ -436,24 +506,24 @@ void Chart3D::bindResources(int pWindowId) mVAOMap[pWindowId] = vao; } glBindVertexArray(mVAOMap[pWindowId]); - CheckGL("End Chart3D::bindResources"); + CheckGL("End chart3d_impl::bindResources"); } -void Chart3D::unbindResources() const +void chart3d_impl::unbindResources() const { glBindVertexArray(0); } -void Chart3D::pushTicktextCoords(float x, float y, float z) +void chart3d_impl::pushTicktextCoords(const float pX, const float pY, const float pZ) { - mTickTextX.push_back(x); - mTickTextY.push_back(y); - mTickTextZ.push_back(z); + mTickTextX.push_back(pX); + mTickTextY.push_back(pY); + mTickTextZ.push_back(pZ); } -void Chart3D::generateChartData() +void chart3d_impl::generateChartData() { - CheckGL("Begin Chart3D::generateChartData"); + CheckGL("Begin chart3d_impl::generateChartData"); static const float border[] = { -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1 }; static const int nValues = sizeof(border)/sizeof(float); @@ -532,6 +602,53 @@ void Chart3D::generateChartData() mXText.push_back(toString(pos)); } + /* push grid lines */ + /* xy plane center lines */ + pushPoint(decorData, -1.0f, 0.0f, -1.0f); + pushPoint(decorData, 1.0f, 0.0f, -1.0f); + pushPoint(decorData, 0.0f,-1.0f, -1.0f); + pushPoint(decorData, 0.0f, 1.0f, -1.0f); + /* xz plane center lines */ + pushPoint(decorData, -1.0f, -1.0f, 0.0f); + pushPoint(decorData, -1.0f, 1.0f, 0.0f); + pushPoint(decorData, -1.0f, 0.0f,-1.0f); + pushPoint(decorData, -1.0f, 0.0f, 1.0f); + /* yz plane center lines */ + pushPoint(decorData, -1.0f, 1.0f, 0.0f); + pushPoint(decorData, 1.0f, 1.0f, 0.0f); + pushPoint(decorData, 0.0f, 1.0f,-1.0f); + pushPoint(decorData, 0.0f, 1.0f, 1.0f); + for (int i=1; i<=ticksLeft; ++i) { + float delta = i*step; + /* xy plane center lines */ + pushPoint(decorData, -1.0f,-delta, -1.0f); + pushPoint(decorData, 1.0f,-delta, -1.0f); + pushPoint(decorData, -1.0f, delta, -1.0f); + pushPoint(decorData, 1.0f, delta, -1.0f); + pushPoint(decorData,-delta, -1.0f, -1.0f); + pushPoint(decorData,-delta, 1.0f, -1.0f); + pushPoint(decorData, delta, -1.0f, -1.0f); + pushPoint(decorData, delta, 1.0f, -1.0f); + /* xz plane center lines */ + pushPoint(decorData, -1.0f, -1.0f,-delta); + pushPoint(decorData, -1.0f, 1.0f,-delta); + pushPoint(decorData, -1.0f, -1.0f, delta); + pushPoint(decorData, -1.0f, 1.0f, delta); + pushPoint(decorData, -1.0f,-delta, -1.0f); + pushPoint(decorData, -1.0f,-delta, 1.0f); + pushPoint(decorData, -1.0f, delta, -1.0f); + pushPoint(decorData, -1.0f, delta, 1.0f); + /* yz plane center lines */ + pushPoint(decorData, -1.0f, 1.0f,-delta); + pushPoint(decorData, 1.0f, 1.0f,-delta); + pushPoint(decorData, -1.0f, 1.0f, delta); + pushPoint(decorData, 1.0f, 1.0f, delta); + pushPoint(decorData,-delta, 1.0f, -1.0f); + pushPoint(decorData,-delta, 1.0f, 1.0f); + pushPoint(decorData, delta, 1.0f, -1.0f); + pushPoint(decorData, delta, 1.0f, 1.0f); + } + /* check if decoration VBO has been already used(case where * tick marks are being changed from default(21) */ if (mDecorVBO != 0) @@ -540,10 +657,10 @@ void Chart3D::generateChartData() /* create vbo that has the border and axis data */ mDecorVBO = createBuffer(GL_ARRAY_BUFFER, decorData.size(), &(decorData.front()), GL_STATIC_DRAW); - CheckGL("End Chart3D::generateChartData"); + CheckGL("End chart3d_impl::generateChartData"); } -void Chart3D::generateTickLabels() +void chart3d_impl::generateTickLabels() { /* remove all the tick text markers that were generated * by default during the base class(chart) creation and @@ -579,42 +696,61 @@ void Chart3D::generateTickLabels() } } -void Chart3D::renderChart(int pWindowId, int pX, int pY, int pVPW, int pVPH) -{ - CheckGL("Being Chart3D::renderChart"); - float w = float(pVPW - (mLeftMargin + mRightMargin + mTickSize)); - float h = float(pVPH - (mTopMargin + mBottomMargin + mTickSize)); - - Chart3D::bindResources(pWindowId); - - /* bind the plotting shader program */ - glUseProgram(mBorderProgram); +chart3d_impl::chart3d_impl() + :AbstractChart(32, 32, 32, 32) { + generateChartData(); +} +void chart3d_impl::render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4& pTransform) +{ /* set uniform attributes of shader * for drawing the plot borders */ - glm::mat4 model = glm::rotate(glm::mat4(1.0f), -glm::radians(90.f), glm::vec3(0,1,0)) * glm::rotate(glm::mat4(1.0f), -glm::radians(90.f), glm::vec3(1,0,0)) * glm::scale(glm::mat4(1.f), glm::vec3(1.0f, 1.0f, 1.0f)); - glm::mat4 view = glm::lookAt(glm::vec3(-1,0.5f,1.0f), glm::vec3(1,-1,-1),glm::vec3(0,1,0)); - glm::mat4 projection = glm::ortho(-2.f, 2.f, -2.f, 2.f, -1.1f, 10.f); - glm::mat4 mvp = projection * view * model; + static const glm::mat4 VIEW = glm::lookAt(glm::vec3(-1.f,0.5f, 1.f), + glm::vec3( 1.f,-1.f,-1.f), + glm::vec3( 0.f, 1.f, 0.f)); + static const glm::mat4 PROJECTION = glm::ortho(-2.f, 2.f, -2.f, 2.f, -1.f, 100.f); + static const glm::mat4 MODEL = glm::rotate(glm::mat4(1.0f), -glm::radians(90.f), glm::vec3(0,1,0)) * + glm::rotate(glm::mat4(1.0f), -glm::radians(90.f), glm::vec3(1,0,0)) * + glm::scale(glm::mat4(1.f), glm::vec3(1.0f, 1.0f, 1.0f)); + static const glm::mat4 PV = PROJECTION * VIEW; + static const glm::mat4 PVM = PV * MODEL; + + CheckGL("Being chart3d_impl::renderChart"); + + /* draw grid */ + chart3d_impl::bindResources(pWindowId); + glUseProgram(mBorderProgram); + glUniformMatrix4fv(mBorderUniformMatIndex, 1, GL_FALSE, glm::value_ptr(PVM)); + glUniform4fv(mBorderUniformColorIndex, 1, GRAY); + glDrawArrays(GL_LINES, 6+3*mTickCount, 12*mTickCount); + glUseProgram(0); + chart3d_impl::unbindResources(); - glm::mat4 trans = mvp; - glUniformMatrix4fv(mBorderUniformMatIndex, 1, GL_FALSE, glm::value_ptr(trans)); - glUniform4fv(mBorderUniformColorIndex, 1, WHITE); + /* render all the renderables */ + for (auto renderable : mRenderables) { + renderable->setRanges(mXMin, mXMax, mYMin, mYMax, mZMin, mZMax); + renderable->render(pWindowId, pX, pY, pVPW, pVPH, PV*pTransform); + } /* Draw borders */ - glDrawArrays(GL_LINES, 0, 6); + chart3d_impl::bindResources(pWindowId); - /* reset shader program binding */ + glUseProgram(mBorderProgram); + glUniformMatrix4fv(mBorderUniformMatIndex, 1, GL_FALSE, glm::value_ptr(PVM)); + glUniform4fv(mBorderUniformColorIndex, 1, BLACK); + glDrawArrays(GL_LINES, 0, 6); glUseProgram(0); /* bind the sprite shader program to * draw ticks on x and y axes */ glEnable(GL_PROGRAM_POINT_SIZE); glPointSize((GLfloat)mTickSize); - glUseProgram(mSpriteProgram); - glUniform4fv(mSpriteUniformTickcolorIndex, 1, WHITE); - glUniformMatrix4fv(mSpriteUniformMatIndex, 1, GL_FALSE, glm::value_ptr(trans)); + + glUniform4fv(mSpriteUniformTickcolorIndex, 1, BLACK); + glUniformMatrix4fv(mSpriteUniformMatIndex, 1, GL_FALSE, glm::value_ptr(PVM)); /* Draw tick marks on z axis */ glUniform1i(mSpriteUniformTickaxisIndex, 1); glDrawArrays(GL_POINTS, 6, mTickCount); @@ -628,42 +764,46 @@ void Chart3D::renderChart(int pWindowId, int pX, int pY, int pVPW, int pVPH) glUseProgram(0); glPointSize(1); glDisable(GL_PROGRAM_POINT_SIZE); - Chart3D::unbindResources(); - renderTickLabels(pWindowId, w, h, mZText, trans, 0); - renderTickLabels(pWindowId, w, h, mYText, trans, mTickCount); - renderTickLabels(pWindowId, w, h, mXText, trans, 2*mTickCount); + chart3d_impl::unbindResources(); + + float w = float(pVPW - (mLeftMargin + mRightMargin + mTickSize)); + float h = float(pVPH - (mTopMargin + mBottomMargin + mTickSize)); + + renderTickLabels(pWindowId, w, h, mZText, PVM, 0); + renderTickLabels(pWindowId, w, h, mYText, PVM, mTickCount); + renderTickLabels(pWindowId, w, h, mXText, PVM, 2*mTickCount); auto &fonter = getChartFont(); fonter->setOthro2D(int(w), int(h)); float pos[2]; /* render chart axes titles */ if (!mZTitle.empty()) { - glm::vec4 res = trans * glm::vec4(-1.0f, -1.0f, 0.0f, 1.0f); + glm::vec4 res = PVM * glm::vec4(-1.0f, -1.0f, 0.0f, 1.0f); pos[0] = w*(res.x/res.w+1.0f)/2.0f; pos[1] = h*(res.y/res.w+1.0f)/2.0f; pos[0] -= 6*(mTickSize * (w/pVPW)); pos[1] += mZTitle.length()/2 * CHART2D_FONT_SIZE; - fonter->render(pWindowId, pos, WHITE, mZTitle.c_str(), CHART2D_FONT_SIZE, true); + fonter->render(pWindowId, pos, BLACK, mZTitle.c_str(), CHART2D_FONT_SIZE, true); } if (!mYTitle.empty()) { - glm::vec4 res = trans * glm::vec4(1.0f, 0.0f, -1.0f, 1.0f); + glm::vec4 res = PVM * glm::vec4(1.0f, 0.0f, -1.0f, 1.0f); pos[0] = w*(res.x/res.w+1.0f)/2.0f; pos[1] = h*(res.y/res.w+1.0f)/2.0f; pos[0] += 0.5 * ((mTickSize * (w/pVPW)) + mYTitle.length()/2 * CHART2D_FONT_SIZE); pos[1] -= 4*(mTickSize * (h/pVPH)); - fonter->render(pWindowId, pos, WHITE, mYTitle.c_str(), CHART2D_FONT_SIZE); + fonter->render(pWindowId, pos, BLACK, mYTitle.c_str(), CHART2D_FONT_SIZE); } if (!mXTitle.empty()) { - glm::vec4 res = trans * glm::vec4(0.0f, -1.0f, -1.0f, 1.0f); + glm::vec4 res = PVM * glm::vec4(0.0f, -1.0f, -1.0f, 1.0f); pos[0] = w*(res.x/res.w+1.0f)/2.0f; pos[1] = h*(res.y/res.w+1.0f)/2.0f; pos[0] -= (mTickSize * (w/pVPW)) + mXTitle.length()/2 * CHART2D_FONT_SIZE; pos[1] -= 4*(mTickSize * (h/pVPH)); - fonter->render(pWindowId, pos, WHITE, mXTitle.c_str(), CHART2D_FONT_SIZE); + fonter->render(pWindowId, pos, BLACK, mXTitle.c_str(), CHART2D_FONT_SIZE); } - CheckGL("End Chart3D::renderChart"); + CheckGL("End chart3d_impl::renderChart"); } } diff --git a/src/backend/opengl/chart.hpp b/src/backend/opengl/chart.hpp new file mode 100644 index 00000000..fa205fd2 --- /dev/null +++ b/src/backend/opengl/chart.hpp @@ -0,0 +1,150 @@ +/******************************************************* +* 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 opengl +{ + +class AbstractChart : public AbstractRenderable { + protected: + /* internal class attributes for + * drawing ticks on axes for plots*/ + std::vector mTickTextX; + std::vector mTickTextY; + std::vector mTickTextZ; + std::vector mXText; + std::vector mYText; + std::vector mZText; + int mTickCount; /* should be an odd number always */ + int mTickSize; + int mLeftMargin; + int mRightMargin; + int mTopMargin; + int mBottomMargin; + /* chart axes ranges and titles */ + float mXMax; + float mXMin; + float mYMax; + float mYMin; + float mZMax; + float mZMin; + std::string mXTitle; + std::string mYTitle; + std::string mZTitle; + /* OpenGL Objects */ + GLuint mDecorVBO; + GLuint mBorderProgram; + GLuint mSpriteProgram; + /* shader uniform variable locations */ + GLuint mBorderAttribPointIndex; + GLuint mBorderUniformColorIndex; + GLuint mBorderUniformMatIndex; + GLuint mSpriteUniformMatIndex; + GLuint mSpriteUniformTickcolorIndex; + GLuint mSpriteUniformTickaxisIndex; + /* Chart legend position*/ + float mLegendX; + float mLegendY; + /* VAO map to store a vertex array object + * for each valid window context */ + std::map mVAOMap; + /* list of renderables to be displayed on the chart*/ + std::vector< std::shared_ptr > mRenderables; + + /* rendering helper functions */ + void renderTickLabels(const int pWindowId, const uint pW, const uint pH, + const std::vector &pTexts, + const glm::mat4 &pTransformation, const int pCoordsOffset, + const bool pUseZoffset=true) const; + + /* virtual functions that has to be implemented by + * dervied class: chart2d_impl, chart3d_impl */ + virtual void bindResources(const int pWindowId) = 0; + virtual void unbindResources() const = 0; + virtual void pushTicktextCoords(const float pX, const float pY, const float pZ=0.0) = 0; + virtual void generateChartData() = 0; + virtual void generateTickLabels() = 0; + + public: + AbstractChart(const int pLeftMargin, const int pRightMargin, + const int pTopMargin, const int pBottomMargin); + virtual ~AbstractChart(); + + void setAxesTitles(const char* pXTitle, + const char* pYTitle, + const char* pZTitle); + + void setAxesLimits(const float pXmin, const float pXmax, + const float pYmin, const float pYmax, + const float pZmin, const float pZmax); + + void setLegendPosition(const float pX, const float pY); + + float xmax() const; + float xmin() const; + float ymax() const; + float ymin() const; + float zmax() const; + float zmin() const; + + void addRenderable(const std::shared_ptr pRenderable); +}; + +class chart2d_impl : public AbstractChart { + private: + /* rendering helper functions that are derived + * from AbstractRenderable base class + * */ + void bindResources(const int pWindowId); + void unbindResources() const; + void pushTicktextCoords(const float x, const float y, const float z=0.0); + void generateChartData(); + void generateTickLabels(); + + public: + chart2d_impl(); + + virtual ~chart2d_impl() {} + + void render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4& pTransform); +}; + +class chart3d_impl : public AbstractChart { + private: + /* rendering helper functions that are derived + * from AbstractRenderable base class + * */ + void bindResources(const int pWindowId); + void unbindResources() const; + void pushTicktextCoords(const float x, const float y, const float z=0.0); + void generateChartData(); + void generateTickLabels(); + + public: + chart3d_impl(); + + virtual ~chart3d_impl() {} + + void render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4& pTransform); +}; + +} diff --git a/src/colormap.cpp b/src/backend/opengl/colormap.cpp similarity index 99% rename from src/colormap.cpp rename to src/backend/opengl/colormap.cpp index e918ed8c..bf83bd37 100644 --- a/src/colormap.cpp +++ b/src/backend/opengl/colormap.cpp @@ -14,7 +14,7 @@ #define CREATE_UNIFORM_BUFFER(color_array, size) \ createBuffer(GL_UNIFORM_BUFFER, 4*size, color_array, GL_STATIC_DRAW) -namespace internal +namespace opengl { colormap_impl::colormap_impl() diff --git a/src/colormap.hpp b/src/backend/opengl/colormap.hpp similarity index 99% rename from src/colormap.hpp rename to src/backend/opengl/colormap.hpp index 96497ced..7e781391 100644 --- a/src/colormap.hpp +++ b/src/backend/opengl/colormap.hpp @@ -12,7 +12,7 @@ #include #include -namespace internal +namespace opengl { class colormap_impl { diff --git a/src/backend/opengl/common.cpp b/src/backend/opengl/common.cpp new file mode 100644 index 00000000..84a494f7 --- /dev/null +++ b/src/backend/opengl/common.cpp @@ -0,0 +1,332 @@ +/******************************************************* + * 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 + +using namespace fg; +using namespace std; + +#define PI 3.14159 + +typedef struct { + GLuint vertex; + GLuint fragment; + GLuint geometry; +} Shaders; + +GLenum dtype2gl(const fg::dtype pValue) +{ + switch(pValue) { + case s8: return GL_BYTE; + case u8: return GL_UNSIGNED_BYTE; + case s32: return GL_INT; + case u32: return GL_UNSIGNED_INT; + case s16: return GL_SHORT; + case u16: return GL_UNSIGNED_SHORT; + default: return GL_FLOAT; + } +} + +GLenum ctype2gl(const ChannelFormat pMode) +{ + switch(pMode) { + case FG_GRAYSCALE: return GL_RED; + case FG_RG : return GL_RG; + case FG_RGB : return GL_RGB; + case FG_BGR : return GL_BGR; + case FG_BGRA: return GL_BGRA; + default : return GL_RGBA; + } +} + +GLenum ictype2gl(const ChannelFormat pMode) +{ + if (pMode==FG_GRAYSCALE) + return GL_RED; + else if (pMode==FG_RG) + return GL_RG; + else if (pMode==FG_RGB || pMode==FG_BGR) + return GL_RGB; + + return GL_RGBA; +} + +void printShaderInfoLog(GLint pShader) +{ + int infoLogLen = 0; + int charsWritten = 0; + GLchar *infoLog; + + glGetShaderiv(pShader, GL_INFO_LOG_LENGTH, &infoLogLen); + + if (infoLogLen > 1) { + infoLog = new GLchar[infoLogLen]; + glGetShaderInfoLog(pShader, infoLogLen, &charsWritten, infoLog); + std::cerr << "InfoLog:" << std::endl << infoLog << std::endl; + delete [] infoLog; + throw fg::Error("printShaderInfoLog", __LINE__, + "OpenGL Shader compilation failed", FG_ERR_GL_ERROR); + } +} + +void printLinkInfoLog(GLint pProgram) +{ + int infoLogLen = 0; + int charsWritten = 0; + GLchar *infoLog; + + glGetProgramiv(pProgram, GL_INFO_LOG_LENGTH, &infoLogLen); + + if (infoLogLen > 1) { + infoLog = new GLchar[infoLogLen]; + // error check for fail to allocate memory omitted + glGetProgramInfoLog(pProgram, infoLogLen, &charsWritten, infoLog); + std::cerr << "InfoLog:" << std::endl << infoLog << std::endl; + delete [] infoLog; + throw fg::Error("printLinkInfoLog", __LINE__, + "OpenGL Shader linking failed", FG_ERR_GL_ERROR); + } +} + +void attachAndLinkProgram(GLuint pProgram, Shaders pShaders) +{ + glAttachShader(pProgram, pShaders.vertex); + glAttachShader(pProgram, pShaders.fragment); + if (pShaders.geometry>0) { + glAttachShader(pProgram, pShaders.geometry); + } + + glLinkProgram(pProgram); + GLint linked; + glGetProgramiv(pProgram,GL_LINK_STATUS, &linked); + if (!linked) { + std::cerr << "Program did not link." << std::endl; + throw fg::Error("attachAndLinkProgram", __LINE__, + "OpenGL program linking failed", FG_ERR_GL_ERROR); + } + printLinkInfoLog(pProgram); +} + +Shaders loadShaders(const char* pVertexShaderSrc, + const char* pFragmentShaderSrc, + const char* pGeometryShaderSrc) +{ + GLuint f, v; + + v = glCreateShader(GL_VERTEX_SHADER); + f = glCreateShader(GL_FRAGMENT_SHADER); + + // load shaders & get length of each + glShaderSource(v, 1, &pVertexShaderSrc, NULL); + glShaderSource(f, 1, &pFragmentShaderSrc, NULL); + + GLint compiled; + + glCompileShader(v); + glGetShaderiv(v, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + std::cerr << "Vertex shader not compiled." << std::endl; + printShaderInfoLog(v); + } + + glCompileShader(f); + glGetShaderiv(f, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + std::cerr << "Fragment shader not compiled." << std::endl; + printShaderInfoLog(f); + } + + GLuint g = 0; + /* compile geometry shader if source provided */ + if (pGeometryShaderSrc) { + g = glCreateShader(GL_GEOMETRY_SHADER); + glShaderSource(g, 1, &pGeometryShaderSrc, NULL); + glCompileShader(g); + glGetShaderiv(g, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + std::cerr << "Geometry shader not compiled." << std::endl; + printShaderInfoLog(g); + } + } + + Shaders out; out.vertex = v; out.fragment = f; out.geometry = g; + + return out; +} + +GLuint initShaders(const char* pVertShaderSrc, const char* pFragShaderSrc, const char* pGeomShaderSrc) +{ + Shaders shrds = loadShaders(pVertShaderSrc, pFragShaderSrc, pGeomShaderSrc); + GLuint shaderProgram = glCreateProgram(); + attachAndLinkProgram(shaderProgram, shrds); + return shaderProgram; +} + +float clampTo01(const float pValue) +{ + return (pValue < 0.0f ? 0.0f : (pValue>1.0f ? 1.0f : pValue)); +} + +#ifdef OS_WIN +#include +#include + +void getFontFilePaths(std::vector& pFiles, + const std::string& pDir, + const std::string& pExt) +{ + WIN32_FIND_DATA ffd; + LARGE_INTEGER filesize; + TCHAR szDir[MAX_PATH]; + size_t length_of_arg; + DWORD dwError=0; + HANDLE hFind = INVALID_HANDLE_VALUE; + + // Check that the input path plus 3 is not longer than MAX_PATH. + // Three characters are for the "\*" plus NULL appended below. + StringCchLength(pDir.c_str(), MAX_PATH, &length_of_arg); + + if (length_of_arg > (MAX_PATH - 3)) { + throw fg::Error("getImageFilePaths", __LINE__, + "WIN API call: Directory path is too long", + FG_ERR_FILE_NOT_FOUND); + } + + //printf("\nTarget directory is %s\n\n", pDir.c_str()); + // Prepare string for use with FindFile functions. First, copy the + // string to a buffer, then append '\*' to the directory name. + StringCchCopy(szDir, MAX_PATH, pDir.c_str()); + std::string wildcard = "\\*" + pExt; + StringCchCat(szDir, MAX_PATH, wildcard.c_str()); + + // Find the first file in the directory. + hFind = FindFirstFile(szDir, &ffd); + if (INVALID_HANDLE_VALUE == hFind) { + throw fg::Error("getImageFilePaths", __LINE__, + "WIN API call: file fetch in DIR failed", + FG_ERR_FILE_NOT_FOUND); + } + + // List all the files in the directory with some info about them. + do { + if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + // It is a directory, skip the entry + //_tprintf(TEXT(" %s \n"), ffd.cFileName); + } else { + filesize.LowPart = ffd.nFileSizeLow; + filesize.HighPart = ffd.nFileSizeHigh; + //_tprintf(TEXT(" %s %ld bytes\n"), ffd.cFileName, filesize.QuadPart); + pFiles.push_back(std::string(ffd.cFileName)); + } + } while (FindNextFile(hFind, &ffd) != 0); + + dwError = GetLastError(); + if (dwError != ERROR_NO_MORE_FILES) { + throw fg::Error("getImageFilePaths", __LINE__, + "WIN API call: files fetch returned no files", + FG_ERR_FILE_NOT_FOUND); + } + + FindClose(hFind); +} +#endif + +std::string toString(const float pVal, const int pPrecision) +{ + std::ostringstream out; + out << std::fixed << std::setprecision(pPrecision) << pVal; + return out.str(); +} + +GLuint screenQuadVBO(const int pWindowId) +{ + //FIXME: VBOs can be shared, but for simplicity + // right now just created one VBO each window, + // ignoring shared contexts + static std::map svboMap; + + if (svboMap.find(pWindowId)==svboMap.end()) { + static const float vertices[8] = { + -1.0f,-1.0f, + 1.0f,-1.0f, + 1.0f, 1.0f, + -1.0f, 1.0f + }; + svboMap[pWindowId] = createBuffer(GL_ARRAY_BUFFER, 8, vertices, GL_STATIC_DRAW); + } + + return svboMap[pWindowId]; +} + +GLuint screenQuadVAO(const int pWindowId) +{ + static std::map svaoMap; + + if (svaoMap.find(pWindowId)==svaoMap.end()) { + static const float texcords[8] = {0.0,1.0,1.0,1.0,1.0,0.0,0.0,0.0}; + static const uint indices[6] = {0,1,2,0,2,3}; + + GLuint tbo = createBuffer(GL_ARRAY_BUFFER, 8, texcords, GL_STATIC_DRAW); + GLuint ibo = createBuffer(GL_ELEMENT_ARRAY_BUFFER, 6, indices, GL_STATIC_DRAW); + + GLuint vao = 0; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + // attach vbo + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, screenQuadVBO(pWindowId)); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); + // attach tbo + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, tbo); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL); + // attach ibo + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + glBindVertexArray(0); + /* store the vertex array object corresponding to + * the window instance in the map */ + svaoMap[pWindowId] = vao; + } + + return svaoMap[pWindowId]; +} + +std::ostream& operator<<(std::ostream& pOut, const glm::mat4& pMat) +{ + const float* ptr = (const float*)glm::value_ptr(pMat); + pOut << "\n" << std::fixed; + pOut << ptr[0] << "\t" << ptr[1] << "\t" << ptr[2] << "\t" << ptr[3] << "\n"; + pOut << ptr[4] << "\t" << ptr[5] << "\t" << ptr[6] << "\t" << ptr[7] << "\n"; + pOut << ptr[8] << "\t" << ptr[9] << "\t" << ptr[10] << "\t" << ptr[11] << "\n"; + pOut << ptr[12] << "\t" << ptr[13] << "\t" << ptr[14] << "\t" << ptr[15] << "\n"; + pOut << "\n"; + return pOut; +} + +glm::vec3 trackballPoint(const float pX, const float pY, + const float pWidth, const float pHeight) +{ + float d, a; + float x, y, z; + x = (2*pX - pWidth)/pWidth; + y = (pHeight - 2*pY)/pHeight; + d = sqrt(x*x+y*y); + z = cos((PI/2.0) * ((d < 1.0) ? d : 1.0)); + a = 1.0f / sqrt(x*x + y*y + z*z); + return glm::vec3(x*a,y*a,z*a); +} diff --git a/src/backend/opengl/common.hpp b/src/backend/opengl/common.hpp new file mode 100644 index 00000000..0a0108e7 --- /dev/null +++ b/src/backend/opengl/common.hpp @@ -0,0 +1,242 @@ +/******************************************************* + * 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 + +#define GLM_FORCE_RADIANS +#include +#include + +#include + +static const float BLACK[] = {0.0f , 0.0f , 0.0f , 1.0f}; +static const float GRAY[] = {0.85f , 0.85f , 0.85f , 1.0f}; +static const float WHITE[] = {1.0f , 1.0f , 1.0f , 1.0f}; +static const float AF_BLUE[] = {0.0588f , 0.1137f , 0.2745f , 1.0f}; + +/* clamp the float to [0-1] range + * + * @pValue is the value to be clamped + */ +float clampTo01(const float pValue); + +/* Convert forge type enum to OpenGL enum for GL_* type + * + * @pValue is the forge type enum + * + * @return GL_* typedef for data type + */ +GLenum dtype2gl(const fg::dtype pValue); + +/* Convert forge channel format enum to OpenGL enum to indicate color component layout + * + * @pValue is the forge type enum + * + * @return OpenGL enum indicating color component layout + */ +GLenum ctype2gl(const fg::ChannelFormat pMode); + +/* Convert forge channel format enum to OpenGL enum to indicate color component layout + * + * This function is used to group color component layout formats based + * on number of components. + * + * @pValue is the forge type enum + * + * @return OpenGL enum indicating color component layout + */ +GLenum ictype2gl(const fg::ChannelFormat pMode); + +/* Compile OpenGL GLSL vertex and fragment shader sources + * + * @pVertShaderSrc is the vertex shader source code string + * @pFragShaderSrc is the vertex shader source code string + * @pGeomShaderSrc is the vertex shader source code string + * + * @return GLSL program unique identifier for given shader duo + */ +GLuint initShaders(const char* pVertShaderSrc, const char* pFragShaderSrc, const char* pGeomShaderSrc=NULL); + +/* Create OpenGL buffer object + * + * @pTarget should be either GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER + * @pSize is the size of the data in bytes + * @pPtr is the pointer to host data. This can be NULL + * @pUsage should be either GL_STATIC_DRAW or GL_DYNAMIC_DRAW + * + * @return OpenGL buffer object identifier + */ +template +GLuint createBuffer(GLenum pTarget, size_t pSize, const T* pPtr, GLenum pUsage) +{ + GLuint retVal = 0; + glGenBuffers(1, &retVal); + glBindBuffer(pTarget, retVal); + glBufferData(pTarget, pSize*sizeof(T), pPtr, pUsage); + glBindBuffer(pTarget, 0); + return retVal; +} + +#ifdef OS_WIN +/* Get the paths to font files in Windows system directory + * + * @pFiles is the output vector to which font file paths are appended to. + * @pDir is the directory from which font files are looked up + * @pExt is the target font file extension we are looking for. + */ +void getFontFilePaths(std::vector& pFiles, + const std::string& pDir, + const std::string& pExt); +#endif + +/* Convert float value to string with given precision + * + * @pVal is the float value whose string representation is requested. + * @pPrecision is the precision of the float used while converting to string. + * + * @return is the string representation of input float value. + */ +std::string toString(const float pVal, const int pPrecision = 2); + +/* Get a vertex buffer object for quad that spans the screen + */ +GLuint screenQuadVBO(const int pWindowId); + +/* Get a vertex array object that uses screenQuadVBO + * + * This vertex array object when bound and rendered, basically + * draws a rectangle over the entire screen with standard + * texture coordinates. Use of this vao would be as follows + * + * `glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);` + */ +GLuint screenQuadVAO(const int pWindowId); + +/* Print glm::mat4 to std::cout stream */ +std::ostream& operator<<(std::ostream&, const glm::mat4&); + +/* get the point of the surface of track ball */ +glm::vec3 trackballPoint(const float pX, const float pY, + const float pWidth, const float pHeight); + +namespace opengl +{ + +typedef unsigned int uint; +typedef unsigned short ushort; +typedef unsigned char uchar; + +/* Basic renderable class + * + * Any object that is renderable to a window should inherit from this + * class. + */ +class AbstractRenderable { + protected: + /* OpenGL buffer objects */ + GLuint mVBO; + GLuint mCBO; + GLuint mABO; + size_t mVBOSize; + size_t mCBOSize; + size_t mABOSize; + GLfloat mColor[4]; + GLfloat mRange[6]; + std::string mLegend; + bool mIsPVCOn; + bool mIsPVAOn; + + public: + /* Getter functions for OpenGL buffer objects + * identifiers and their size in bytes + * + * vbo is for vertices + * cbo is for colors of those vertices + * abo is for alpha values for those vertices + */ + GLuint vbo() const { return mVBO; } + GLuint cbo() { mIsPVCOn = true; return mCBO; } + GLuint abo() { mIsPVAOn = true; return mABO; } + size_t vboSize() const { return mVBOSize; } + size_t cboSize() const { return mCBOSize; } + size_t aboSize() const { return mABOSize; } + + /* Set color for rendering + */ + void setColor(const float pRed, const float pGreen, + const float pBlue, const float pAlpha) { + mColor[0] = clampTo01(pRed); + mColor[1] = clampTo01(pGreen); + mColor[2] = clampTo01(pBlue); + mColor[3] = clampTo01(pAlpha); + } + + /* Get renderable solid color + */ + void getColor(float& pRed, float& pGreen, float& pBlue, float& pAlpha) { + pRed = mColor[0]; + pGreen = mColor[1]; + pBlue = mColor[2]; + pAlpha = mColor[3]; + } + + /* Set legend for rendering + */ + void setLegend(const char* pLegend) { + mLegend = std::string(pLegend); + } + + /* Get legend string + */ + const std::string& legend() const { + return mLegend; + } + + /* Set 3d world coordinate ranges + * + * This method is mostly used for charts and related renderables + */ + void setRanges(const float pMinX, const float pMaxX, + const float pMinY, const float pMaxY, + const float pMinZ, const float pMaxZ) { + mRange[0] = pMinX; mRange[1] = pMaxX; + mRange[2] = pMinY; mRange[3] = pMaxY; + mRange[4] = pMinZ; mRange[5] = pMaxZ; + } + + /* virtual function to set colormap, a derviced class might + * use it or ignore it if it doesnt have a need for color maps. + */ + virtual void setColorMapUBOParams(const GLuint pUBO, const GLuint pSize) { + } + + /* render is a pure virtual function. + * + * @pWindowId is the window identifier + * @pX is the X coordinate at which the currently bound viewport begins. + * @pX is the Y coordinate at which the currently bound viewport begins. + * @pViewPortWidth is the width of the currently bound viewport. + * @pViewPortHeight is the height of the currently bound viewport. + * + * Any concrete class that inherits AbstractRenderable class needs to + * implement this method to render their OpenGL objects to + * the currently bound viewport of the Window bearing identifier pWindowId. + * + * @return nothing. + */ + virtual void render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4 &pTransform) = 0; +}; + +} diff --git a/src/err_common.cpp b/src/backend/opengl/err_opengl.cpp similarity index 90% rename from src/err_common.cpp rename to src/backend/opengl/err_opengl.cpp index 732a5004..2fdfc245 100644 --- a/src/err_common.cpp +++ b/src/backend/opengl/err_opengl.cpp @@ -7,9 +7,11 @@ * http://arrayfire.com/licenses/BSD-3-Clause ********************************************************/ -#include -#include #include + +#include +#include + #include #include @@ -21,7 +23,7 @@ void commonErrorCheck(const char *pMsg, const char* pFile, int pLine) std::stringstream ss; ss << "GL Error at: "<< pFile << ":"< + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include FT_FREETYPE_H +#include FT_STROKER_H + +#undef __FTERRORS_H__ +#define FT_ERRORDEF( e, v, s ) { e, s }, +#define FT_ERROR_START_LIST { +#define FT_ERROR_END_LIST { 0, 0 } }; +static const struct { + int code; + const char* message; +} FT_Errors[] = +#include FT_ERRORS_H + +#ifndef OS_WIN +#include +#endif + +#ifdef OS_WIN +#include +#include +#endif + +#define START_CHAR 32 +#define END_CHAR 126 + +/* freetype library types */ + +namespace opengl +{ + +#ifdef NDEBUG +/* Relase Mode */ +#define FT_THROW_ERROR(msg, error) \ + throw fg::Error("Freetype library", __LINE__, msg, error); + +#else +/* Debug Mode */ +#define FT_THROW_ERROR(msg, err) \ + do { \ + std::ostringstream ss; \ + ss << "FT_Error (0x"<< std::hex << FT_Errors[bError].code <<") : " \ + << FT_Errors[bError].message << std::endl; \ + throw fg::Error(ss.str().c_str(), __LINE__, msg, err); \ + } while(0); + +#endif + +void font_impl::loadAtlasWithGlyphs(const size_t pFontSize) +{ + FT_Library library; + FT_Face face; + /* Initialize freetype font library */ + FT_Error bError = FT_Init_FreeType(&library); + if (bError) + FT_THROW_ERROR("Freetype Initialization failed", FG_ERR_FREETYPE_ERROR); + /* get font face for requested font */ + bError = FT_New_Face(library, mTTFfile.c_str(), 0, &face); + if (bError) { + FT_Done_FreeType(library); + FT_THROW_ERROR("Freetype face initilization", FG_ERR_FREETYPE_ERROR); + } + /* Select charmap */ + bError = FT_Select_Charmap(face, FT_ENCODING_UNICODE); + if (bError) { + FT_Done_Face(face); + FT_Done_FreeType(library); + FT_THROW_ERROR("Freetype charmap set failed", FG_ERR_FREETYPE_ERROR); + } + /* set the pixel size of font */ + bError = FT_Set_Pixel_Sizes(face, 0, pFontSize); + if (bError) { + FT_Done_Face(face); + FT_Done_FreeType(library); + FT_THROW_ERROR("Freetype char size set failed", FG_ERR_FREETYPE_ERROR); + } + + size_t missed = 0; + + /* retrieve the list of current font size */ + auto& currList = mGlyphLists[pFontSize-MIN_FONT_SIZE]; + + for (size_t i=0; i<(END_CHAR-START_CHAR+1); ++i) + { + FT_ULong ccode = (FT_ULong)(START_CHAR + i); + + FT_UInt glyphIndex = FT_Get_Char_Index(face, ccode); + + FT_Int32 flags = 0; + + /* solid outline */ + flags |= FT_LOAD_NO_BITMAP; + flags |= FT_LOAD_FORCE_AUTOHINT; + + /* load glyph */ + FT_Error bError = FT_Load_Glyph(face, glyphIndex, flags); + if (bError) { + FT_Done_Face(face); + FT_Done_FreeType(library); + FT_THROW_ERROR("FT_Load_Glyph failed", FG_ERR_FREETYPE_ERROR); + } + + FT_Glyph currGlyph;; + + bError = FT_Get_Glyph(face->glyph, &currGlyph); + if (bError) { + FT_Done_Face(face); + FT_Done_FreeType(library); + FT_THROW_ERROR("FT_Get_Glyph", FG_ERR_FREETYPE_ERROR); + } + + ////FIXME Renable when outline strokes are working + ///* use stroker to get outline */ + //FT_Stroker stroker; + //bError = FT_Stroker_New(library, &stroker); + //if (bError) { + // FT_Stroker_Done(stroker); + // FT_Done_Face(face); + // FT_Done_FreeType(library); + // FT_THROW_ERROR("FT_Stroker_New", fg::FG_ERR_FREETYPE_ERROR); + //} + + //FT_Stroker_Set(stroker, 16, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); + + ///* stroke the outline to current glyph */ + //bError = FT_Glyph_Stroke(&currGlyph, stroker, 1); + //if (bError) { + // FT_Stroker_Done(stroker); + // FT_Done_Face(face); + // FT_Done_FreeType(library); + // FT_THROW_ERROR("FT_Glyph_Stroke", fg::FG_ERR_FREETYPE_ERROR); + //} + //FT_Stroker_Done(stroker); + + /* fixed channel depth of 1 */ + bError = FT_Glyph_To_Bitmap(&currGlyph, FT_RENDER_MODE_NORMAL, 0, 1); + if (bError) { + //FIXME Renable when outline strokes are working + //FT_Stroker_Done(stroker); + FT_Done_Face(face); + FT_Done_FreeType(library); + FT_THROW_ERROR("FT_Glyph_To_Bitmap", FG_ERR_FREETYPE_ERROR); + } + + FT_BitmapGlyph bmpGlyph = (FT_BitmapGlyph) currGlyph; + FT_Bitmap bmp = bmpGlyph->bitmap; + + int w = bmp.width + 1; + int h = bmp.rows + 1; + + glm::vec4 region = mAtlas->getRegion(w, h); + + if (region.x<0 || region.y<0) { + missed++; + std::cerr<<"Texture atlas is full"<setRegion(x, y, w, h, bmp.buffer, bmp.pitch); + + Glyph* glyph = new Glyph(); + + glyph->mWidth = w; + glyph->mHeight = h; + + glyph->mBearingX = face->glyph->metrics.horiBearingX>>6; + glyph->mBearingY = face->glyph->metrics.horiBearingY>>6; + + glyph->mAdvanceX = face->glyph->advance.x>>6; + glyph->mAdvanceY = (face->glyph->metrics.height - face->glyph->metrics.horiBearingY)>>6; + + glyph->mS0 = x/(float)mAtlas->width(); + glyph->mT1 = y/(float)mAtlas->height(); + glyph->mS1 = (x + glyph->mWidth)/(float)mAtlas->width(); + glyph->mT0 = (y + glyph->mHeight)/(float)mAtlas->height(); + + currList.push_back(glyph); + + FT_Done_Glyph(currGlyph); + } + + /* cleanup freetype variables */ + FT_Done_Face(face); + FT_Done_FreeType(library); +} + +void font_impl::bindResources(int pWindowId) +{ + if (mVAOMap.find(pWindowId) == mVAOMap.end()) { + size_t sz = 2*sizeof(float); + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, mVBO); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2*sz, 0); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2*sz, reinterpret_cast(sz)); + /* store the vertex array object corresponding to + * the window instance in the map */ + mVAOMap[pWindowId] = vao; + } + glBindVertexArray(mVAOMap[pWindowId]); +} + +void font_impl::unbindResources() const +{ + glBindVertexArray(0); +} + +void font_impl::destroyGLResources() +{ + if (mVBO) + glDeleteBuffers(1, &mVBO); + /* remove all glyph structures from heap */ + for (auto it: mGlyphLists) { + /* for each font size glyph list */ + for (auto& m : it) { + delete m; /* delete Glyph structure */ + } + it.clear(); + } + /* clear list */ + mGlyphLists.clear(); +} + +font_impl::font_impl() + : mTTFfile(""), mIsFontLoaded(false), mAtlas(new FontAtlas(1024, 1024, 1)), + mVBO(0), mProgram(0), mOrthoW(1), mOrthoH(1) +{ + mProgram = initShaders(glsl::font_vs.c_str(), glsl::font_fs.c_str()); + mPMatIndex = glGetUniformLocation(mProgram, "projectionMatrix"); + mMMatIndex = glGetUniformLocation(mProgram, "modelViewMatrix"); + mTexIndex = glGetUniformLocation(mProgram, "tex"); + mClrIndex = glGetUniformLocation(mProgram, "textColor"); + + mGlyphLists.resize(MAX_FONT_SIZE-MIN_FONT_SIZE+1, GlyphList()); +} + +font_impl::~font_impl() +{ + destroyGLResources(); + if (mProgram) glDeleteProgram(mProgram); +} + +void font_impl::setOthro2D(int pWidth, int pHeight) +{ + mOrthoW = pWidth; + mOrthoH = pHeight; + mProjMat = glm::ortho(0.0f, float(mOrthoW), 0.0f, float(mOrthoH)); +} + +void font_impl::loadFont(const char* const pFile) +{ + CheckGL("Begin font_impl::loadFont"); + + /* Check if font is already loaded. If yes, check if current font load + * request is same as earlier. If so, return from the function, otherwise, + * cleanup currently used resources and mark accordingly for subsequent + * font loading.*/ + if (mIsFontLoaded) { + if (pFile==mTTFfile) + return; + else { + destroyGLResources(); + mIsFontLoaded = false; + } + } + + mTTFfile = pFile; + /* Load different font sizes into font atlas */ + for (size_t s=MIN_FONT_SIZE; s<=MAX_FONT_SIZE; ++s) { + loadAtlasWithGlyphs(s); + } + + mAtlas->upload(); + + /* push each glyphs vertex and texture data into VBO */ + std::vector vdata; + + uint index = 0; + + for (size_t f=0; f data(16, 0.0f); + data[0] = 0.0f; data[1] = float(-g->mAdvanceY+g->mHeight); + data[2] = g->mS0; data[3] = g->mT1; + + data[4] = 0.0f; data[5] = float(-g->mAdvanceY); + data[6] = g->mS0; data[7] = g->mT0; + + data[8] = float(g->mWidth); data[9] = float(-g->mAdvanceY+g->mHeight); + data[10] = g->mS1; data[11] = g->mT1; + + data[12] = float(g->mWidth); data[13] = float(-g->mAdvanceY); + data[14] = g->mS1; data[15] = g->mT0; + + vdata.insert(vdata.end(), data.begin(), data.end()); + + g->mOffset = index; + index += 4; + } + } + + mVBO = createBuffer(GL_ARRAY_BUFFER, vdata.size(), vdata.data(), GL_STATIC_DRAW); + + mIsFontLoaded = true; + + CheckGL("End Font::loadFont"); +} + +void font_impl::loadSystemFont(const char* const pName) +{ + std::string ttf_file_path; + +#ifndef OS_WIN + // use fontconfig to get the file + FcConfig* config = FcInitLoadConfigAndFonts(); + if (!config) { + throw fg::Error("Fontconfig init failed", + __LINE__, __PRETTY_FUNCTION__, + FG_ERR_FONTCONFIG_ERROR); + } + // configure the search pattern, + FcPattern* pat = FcNameParse((const FcChar8*)(pName)); + if (!pat) { + throw fg::Error("Fontconfig name parse failed", + __LINE__, __PRETTY_FUNCTION__, + FG_ERR_FONTCONFIG_ERROR); + } + + FcConfigSubstitute(config, pat, FcMatchPattern); + FcDefaultSubstitute(pat); + + // find the font + FcResult res; + FcPattern* font = FcFontMatch(config, pat, &res); + + FcConfigSubstitute(config, pat, FcMatchPattern); + if (font) { + FcChar8* file = NULL; + if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) { + // save the file to another std::string + ttf_file_path = (char*)file; + } + FcPatternDestroy(font); + } + // destroy fontconfig pattern object + FcPatternDestroy(pat); +#else + char buf[512]; + GetWindowsDirectory(buf, 512); + + std::regex fontRegex(std::string(pName), std::regex_constants::egrep | std::regex_constants::icase); + std::vector fontFiles; + std::vector matchedFontFiles; + + getFontFilePaths(fontFiles, std::string(buf)+"\\Fonts\\", std::string("ttf")); + for (const auto &fontName : fontFiles) { + if (std::regex_search(fontName, fontRegex)) { + matchedFontFiles.push_back(fontName); + } + } + /* out of all the possible matches, we choose the + first possible match for given input font name parameter + */ + if (matchedFontFiles.size()==0) + FT_THROW_ERROR("loadSystemFont failed to find the given font name", fg::FG_ERR_FREETYPE_ERROR); + + ttf_file_path = buf; + ttf_file_path += "\\Fonts\\"; + ttf_file_path += matchedFontFiles[0]; +#endif + + loadFont(ttf_file_path.c_str()); +} + +void font_impl::render(int pWindowId, + const float pPos[], const float pColor[], const char* pText, + size_t pFontSize, bool pIsVertical) +{ + static const glm::mat4 I(1); + + CheckGL("Begin font_impl::render "); + if(!mIsFontLoaded) { + return; + } + + glDepthMask(GL_FALSE); + glDepthFunc(GL_ALWAYS); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glUseProgram(mProgram); + + glUniformMatrix4fv(mPMatIndex, 1, GL_FALSE, (GLfloat*)&mProjMat); + glUniform4fv(mClrIndex, 1, pColor); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, mAtlas->atlasTextureId()); + glUniform1i(mTexIndex, 0); + + bindResources(pWindowId); + + float loc_x = pPos[0]; + float loc_y = pPos[1]; + + if (pFontSizeMAX_FONT_SIZE) { + pFontSize = MAX_FONT_SIZE; + } + + glm::mat4 R = (pIsVertical ? glm::rotate(I, glm::radians(90.f), glm::vec3(0,0,1)) : I); + + auto& glyphList = mGlyphLists[pFontSize - MIN_FONT_SIZE]; + + for (size_t i=0; i=START_CHAR && ccode<=END_CHAR) { + + int idx = ccode - START_CHAR; + + Glyph* g = glyphList[idx]; + + if (!pIsVertical) + loc_x += g->mBearingX; + + glm::mat4 TR = glm::translate(I, glm::vec3(loc_x, loc_y, 0.0f)) * R; + + glUniformMatrix4fv(mMMatIndex, 1, GL_FALSE, (GLfloat*)&TR); + + glDrawArrays(GL_TRIANGLE_STRIP, g->mOffset, 4); + + if (pIsVertical) { + loc_y += (g->mAdvanceX); + } else { + loc_x += (g->mAdvanceX-g->mBearingX); + } + } + } + + unbindResources(); + + glUseProgram(0); + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LESS); + + CheckGL("End font_impl::render "); +} + +} diff --git a/src/backend/opengl/font.hpp b/src/backend/opengl/font.hpp new file mode 100644 index 00000000..89723b5d --- /dev/null +++ b/src/backend/opengl/font.hpp @@ -0,0 +1,76 @@ +/******************************************************* +* 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 + +static const size_t MIN_FONT_SIZE = 8; +static const size_t MAX_FONT_SIZE = 36; + +namespace opengl +{ + +typedef std::vector GlyphList; + +class font_impl { + private: + /* VAO map to store a vertex array object + * for each valid window context */ + std::map mVAOMap; + + /* attributes */ + std::string mTTFfile; + bool mIsFontLoaded; + FontAtlas* mAtlas; + GLuint mVBO; + GLuint mProgram; + int mOrthoW; + int mOrthoH; + + std::vector mGlyphLists; + + /* OpenGL Data */ + glm::mat4 mProjMat; + GLuint mPMatIndex; + GLuint mMMatIndex; + GLuint mTexIndex; + GLuint mClrIndex; + + /* load all glyphs and create character atlas */ + void loadAtlasWithGlyphs(const size_t pFontSize); + + /* helper functions to bind and unbind + * rendering resources */ + void bindResources(int pWindowId); + void unbindResources() const; + + /* helper to destroy GL objects created for + * given font face and size if required */ + void destroyGLResources(); + + public: + font_impl(); + ~font_impl(); + + void setOthro2D(int pWidth, int pHeight); + void loadFont(const char* const pFile); + void loadSystemFont(const char* const pName); + + void render(int pWindowId, + const float pPos[2], const float pColor[4], const char* pText, + size_t pFontSize, bool pIsVertical = false); +}; + +} diff --git a/src/backend/opengl/font_atlas.cpp b/src/backend/opengl/font_atlas.cpp new file mode 100644 index 00000000..401d2287 --- /dev/null +++ b/src/backend/opengl/font_atlas.cpp @@ -0,0 +1,284 @@ +/******************************************************* +* 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 +********************************************************/ + +/* ========================================================================= + * The following copyright block is related to freetype-gl project + * from where the algorithm for Skyline-Bottom Left used in glyph bin packing + * is used. Hence, the following copyright block is attached in this + * source file where it is only pertained to. + =========================================================================== + */ + +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: https://github.com/rougier/freetype-gl + * ------------------------------------------------------------------------- + * Copyright 2011,2012 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * + ========================================================================= + */ + + +#include +#include +#include + +#include +#include + +namespace opengl +{ + +int FontAtlas::fit(const size_t pIndex, const size_t pWidth, const size_t pHeight) +{ + auto node = nodes[pIndex]; + int x = node.x; + int y = node.y; + int widthLeft = pWidth; + int i = pIndex; + + if ((x + pWidth) > (mWidth-1)) { + return -1; + } + + y = node.y; + + while (widthLeft > 0) { + auto node = nodes[i]; + if (node.y > y) { + y = node.y; + } + if ((y + pHeight) > (mHeight-1)) { + return -1; + } + widthLeft -= node.z; + ++i; + } + return y; +} + +void FontAtlas::merge() +{ + for (size_t i=0; i< nodes.size()-1; ++i) { + glm::vec3& node = nodes[i]; + auto next = nodes[i+1]; + + if (node.y == next.y) { + node.z += next.z; + nodes.erase(nodes.begin()+(i+1)); + --i; + } + } +} + +FontAtlas::FontAtlas(const size_t pWidth, const size_t pHeight, const size_t pDepth) + : mWidth(pWidth), mHeight(pHeight), mDepth(pDepth), mUsed(0), mId(0) +{ + CheckGL("Begin FontAtlas::FontAtlas"); + if (!((pDepth == 1) || (pDepth == 3) || (pDepth == 4))) { + throw fg::Error("Font Atlas", __LINE__, "Invalid depth argument", FG_ERR_INTERNAL); + } + + glGenTextures(1, &mId); + glBindTexture(GL_TEXTURE_2D, mId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + + // one pixel border around the whole atlas to + // avoid any artefact when sampling texture + nodes.push_back(glm::vec3(1,1,mWidth-2)); + + mData.reserve(mWidth*mHeight*mDepth); + CheckGL("End FontAtlas::FontAtlas"); +} + +FontAtlas::~FontAtlas() +{ + nodes.clear(); + mData.clear(); + if (mId) { + glDeleteTextures(1, &mId); + } +} + +size_t FontAtlas::width() const +{ + return mWidth; +} + +size_t FontAtlas::height() const +{ + return mHeight; +} + +size_t FontAtlas::depth() const +{ + return mDepth; +} + +glm::vec4 FontAtlas::getRegion(const size_t pWidth, const size_t pHeight) +{ + glm::vec4 region(0, 0, pWidth, pHeight); + + size_t best_height = INT_MAX; + int best_index = -1; + size_t best_width = INT_MAX; + int y; + + for(size_t i=0; i= 0) { + auto node = nodes[i]; + if ( ((y + pHeight) < best_height) || + (((y + pHeight) == best_height) && (node.z < best_width)) ) + { + best_height = y + pHeight; + best_index = i; + best_width = node.z; + region.x = node.x; + region.y = y; + } + } + } + + if (best_index == -1) { + region.x = -1; + region.y = -1; + region.z = 0; + region.w = 0; + return region; + } + + glm::vec3 node(region.x, region.y+pHeight, pWidth); + + nodes.insert(nodes.begin()+best_index, node); + + for(size_t i = best_index+1; i < nodes.size(); ++i) + { + glm::vec3& node = nodes[i]; + auto prev = nodes[i-1]; + + if (node.x < (prev.x + prev.z) ) + { + int shrink = prev.x + prev.z - node.x; + node.x += shrink; + node.z -= shrink; + if (node.z <= 0) { + nodes.erase(nodes.begin()+i); + --i; + } else { + break; + } + } else { + break; + } + } + + merge(); + mUsed += pWidth * pHeight; + + return region; +} + +bool FontAtlas::setRegion(const size_t pX, const size_t pY, + const size_t pWidth, const size_t pHeight, + const uchar* pData, const size_t pStride) +{ + if (pX>0 && pY>0 && pX < (mWidth-1) && (pX+pWidth) <= (mWidth-1) && + pY <(mHeight-1) && (pY+pHeight) <= (mHeight-1)) + { + size_t depth = mDepth; + size_t charsize = sizeof(uchar); + + for (size_t i=0; i + +#include + +#include + +namespace opengl +{ + +class FontAtlas { + private: + size_t mWidth; + size_t mHeight; + size_t mDepth; + size_t mUsed; + GLuint mId; + + std::vector mData; + std::vector nodes; + + /* helper functions */ + int fit(const size_t pIndex, const size_t pWidth, const size_t pHeight); + void merge(); + + public: + FontAtlas(const size_t pWidth, const size_t pHeight, const size_t pDepth); + ~FontAtlas(); + + size_t width() const; + size_t height() const; + size_t depth() const; + + glm::vec4 getRegion(const size_t pWidth, const size_t pHeight); + bool setRegion(const size_t pX, const size_t pY, + const size_t pWidth, const size_t pHeight, + const uchar* pData, const size_t pStride); + + void upload(); + void clear(); + + GLuint atlasTextureId() const; +}; + +struct Glyph { + size_t mWidth; + size_t mHeight; + + size_t mBearingX; + size_t mBearingY; + + float mAdvanceX; + float mAdvanceY; + + /* normalized texture coordinate (x) of top-left corner */ + float mS0, mT0; + + /* First normalized texture coordinate (x) of bottom-right corner */ + float mS1, mT1; + + /* render quad vbo offset */ + size_t mOffset; +}; + +} diff --git a/src/backend/opengl/glfw/window.cpp b/src/backend/opengl/glfw/window.cpp new file mode 100644 index 00000000..f101ab68 --- /dev/null +++ b/src/backend/opengl/glfw/window.cpp @@ -0,0 +1,303 @@ +/******************************************************* +* 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 + +using glm::rotate; +using glm::translate; +using glm::scale; + +#define GLFW_THROW_ERROR(msg, err) \ + throw fg::Error("Window constructor", __LINE__, msg, err); + +namespace wtk +{ + +Widget::Widget() + : mWindow(NULL), mClose(false), mLastXPos(0), mLastYPos(0), mButton(-1), + mWidth(512), mHeight(512), mRows(1), mCols(1) +{ + mCellWidth = mWidth; + mCellHeight = mHeight; + mFramePBO = 0; +} + +Widget::Widget(int pWidth, int pHeight, const char* pTitle, const Widget* pWindow, const bool invisible) + : mWindow(NULL), mClose(false), mLastXPos(0), mLastYPos(0), mButton(-1), mRows(1), mCols(1) +{ + mFramePBO = 0; + + if (!glfwInit()) { + std::cerr << "ERROR: GLFW wasn't able to initalize\n"; + GLFW_THROW_ERROR("glfw initilization failed", FG_ERR_GL_ERROR) + } + + auto wndErrCallback = [](int errCode, const char* pDescription) + { + fputs(pDescription, stderr); + }; + glfwSetErrorCallback(wndErrCallback); + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + if (invisible) + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); + else + glfwWindowHint(GLFW_VISIBLE, GL_TRUE); + + glfwWindowHint(GLFW_SAMPLES, 4); + mWindow = glfwCreateWindow(pWidth, pHeight, pTitle, nullptr, + (pWindow!=nullptr ? pWindow->getNativeHandle(): nullptr)); + + if (!mWindow) { + std::cerr<<"Error: Could not Create GLFW Window!\n"; + GLFW_THROW_ERROR("glfw window creation failed", FG_ERR_GL_ERROR) + } + + glfwSetWindowUserPointer(mWindow, this); + + auto rsCallback = [](GLFWwindow* w, int pWidth, int pHeight) + { + static_cast(glfwGetWindowUserPointer(w))->resizeHandler(pWidth, pHeight); + }; + + auto kbCallback = [](GLFWwindow* w, int pKey, int pScancode, int pAction, int pMods) + { + static_cast(glfwGetWindowUserPointer(w))->keyboardHandler(pKey, pScancode, pAction, pMods); + }; + + auto closeCallback = [](GLFWwindow* w) + { + static_cast(glfwGetWindowUserPointer(w))->hide(); + }; + + auto cursorCallback = [](GLFWwindow* w, double xpos, double ypos) + { + static_cast(glfwGetWindowUserPointer(w))->cursorHandler(xpos, ypos); + }; + + auto mouseButtonCallback = [](GLFWwindow* w, int button, int action, int mods) + { + static_cast(glfwGetWindowUserPointer(w))->mouseButtonHandler(button, action, mods); + }; + + glfwSetFramebufferSizeCallback(mWindow, rsCallback); + glfwSetWindowCloseCallback(mWindow, closeCallback); + glfwSetKeyCallback(mWindow, kbCallback); + glfwSetCursorPosCallback(mWindow, cursorCallback); + glfwSetMouseButtonCallback(mWindow, mouseButtonCallback); + + glfwGetFramebufferSize(mWindow, &mWidth, &mHeight); + mCellWidth = mWidth; + mCellHeight = mHeight; +} + +Widget::~Widget() +{ + glDeleteBuffers(1, &mFramePBO); + + if (mWindow) + glfwDestroyWindow(mWindow); +} + +GLFWwindow* Widget::getNativeHandle() const +{ + return mWindow; +} + +void Widget::makeContextCurrent() const +{ + glfwMakeContextCurrent(mWindow); +} + +long long Widget::getGLContextHandle() +{ +#ifdef OS_WIN + return reinterpret_cast(glfwGetWGLContext(mWindow)); +#elif OS_LNX + return reinterpret_cast(glfwGetGLXContext(mWindow)); +#else + return 0; +#endif +} + +long long Widget::getDisplayHandle() +{ +#ifdef OS_WIN + return reinterpret_cast(GetDC(glfwGetWin32Window(mWindow))); +#elif OS_LNX + return reinterpret_cast(glfwGetX11Display()); +#else + return 0; +#endif +} + +void Widget::setTitle(const char* pTitle) +{ + glfwSetWindowTitle(mWindow, pTitle); +} + +void Widget::setPos(int pX, int pY) +{ + glfwSetWindowPos(mWindow, pX, pY); +} + +void Widget::setSize(unsigned pW, unsigned pH) +{ + glfwSetWindowSize(mWindow, pW, pH); +} + +void Widget::swapBuffers() +{ + glfwSwapBuffers(mWindow); + + glReadBuffer(GL_FRONT); + glBindBuffer(GL_PIXEL_PACK_BUFFER, mFramePBO); + glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); +} + +void Widget::hide() +{ + mClose = true; + glfwHideWindow(mWindow); +} + +void Widget::show() +{ + mClose = false; + glfwShowWindow(mWindow); +} + +bool Widget::close() +{ + return mClose; +} + +void Widget::resetCloseFlag() +{ + if(mClose==true) { + show(); + } +} + +void Widget::resizeHandler(int pWidth, int pHeight) +{ + mWidth = pWidth; + mHeight = pHeight; + mCellWidth = mWidth / mCols; + mCellHeight = mHeight / mRows; + resizePixelBuffers(); +} + +void Widget::keyboardHandler(int pKey, int pScancode, int pAction, int pMods) +{ + if (pKey == GLFW_KEY_ESCAPE && pAction == GLFW_PRESS) { + hide(); + } +} + +void Widget::cursorHandler(const float pXPos, const float pYPos) +{ + static const float SPEED = 0.005f; + + float deltaX = mLastXPos - pXPos; + float deltaY = mLastYPos - pYPos; + + int r, c; + getViewIds(&r, &c); + glm::mat4& mvp = mMVPs[r+c*mRows]; + + if (mButton == GLFW_MOUSE_BUTTON_LEFT) { + // Translate + mvp = translate(mvp, glm::vec3(-deltaX, deltaY, 0.0f) * SPEED); + + } else if (mButton == GLFW_MOUSE_BUTTON_LEFT + 10 * GLFW_MOD_ALT || + mButton == GLFW_MOUSE_BUTTON_LEFT + 10 * GLFW_MOD_CONTROL) { + // Zoom + if(deltaY != 0) { + if(deltaY < 0) { + deltaY = 1.0 / (-deltaY); + } + mvp = scale(mvp, glm::vec3(pow(deltaY, SPEED))); + } + } else if (mButton == GLFW_MOUSE_BUTTON_RIGHT) { + int width, height; + glfwGetWindowSize(mWindow, &width, &height); + + glm::vec3 curPos = trackballPoint(pXPos, pYPos, width, height); + glm::vec3 delta = mLastPos - curPos; + float angle = glm::radians(90.0f * sqrt(delta.x*delta.x + delta.y*delta.y + delta.z*delta.z)); + glm::vec3 axis( + mLastPos.y*curPos.z-mLastPos.z*curPos.y, + mLastPos.z*curPos.x-mLastPos.x*curPos.z, + mLastPos.x*curPos.y-mLastPos.y*curPos.x + ); + float dMag = sqrt(dot(delta, delta)); + float aMag = sqrt(dot(axis, axis)); + if (dMag>0 && aMag>0) { + mvp = rotate(mvp, angle, axis); + } + mLastPos = curPos; + } + + mLastXPos = pXPos; + mLastYPos = pYPos; +} + +void Widget::mouseButtonHandler(int pButton, int pAction, int pMods) +{ + mButton = -1; + if (pAction == GLFW_PRESS) { + switch(pButton) { + case GLFW_MOUSE_BUTTON_LEFT : mButton = GLFW_MOUSE_BUTTON_LEFT ; break; + case GLFW_MOUSE_BUTTON_RIGHT : mButton = GLFW_MOUSE_BUTTON_RIGHT ; break; + case GLFW_MOUSE_BUTTON_MIDDLE: mButton = GLFW_MOUSE_BUTTON_MIDDLE; break; + } + } + if (pMods == GLFW_MOD_ALT || pMods == GLFW_MOD_CONTROL) { + mButton += 10 * pMods; + } + // reset UI transforms upon mouse middle click + if (pButton == GLFW_MOUSE_BUTTON_MIDDLE && pMods == GLFW_MOD_CONTROL && pAction == GLFW_PRESS) { + int r, c; + getViewIds(&r, &c); + glm::mat4& mvp = mMVPs[r+c*mRows]; + mvp = glm::mat4(1.0f); + } +} + +void Widget::pollEvents() +{ + glfwPollEvents(); +} + +void Widget::resizePixelBuffers() +{ + if (mFramePBO!=0) + glDeleteBuffers(1, &mFramePBO); + + uint w = mWidth; + uint h = mHeight; + + glGenBuffers(1, &mFramePBO); + glBindBuffer(GL_PIXEL_PACK_BUFFER, mFramePBO); + glBufferData(GL_PIXEL_PACK_BUFFER, w*h*4*sizeof(uchar), 0, GL_DYNAMIC_READ); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); +} + +} diff --git a/src/glfw/window.hpp b/src/backend/opengl/glfw/window.hpp similarity index 63% rename from src/glfw/window.hpp rename to src/backend/opengl/glfw/window.hpp index e7f0dd98..9c5421db 100644 --- a/src/glfw/window.hpp +++ b/src/backend/opengl/glfw/window.hpp @@ -24,6 +24,8 @@ #include #endif +#include + /* the short form wtk stands for * Windowing Tool Kit */ namespace wtk @@ -33,10 +35,31 @@ class Widget { private: GLFWwindow* mWindow; bool mClose; + float mLastXPos; + float mLastYPos; + int mButton; + glm::vec3 mLastPos; Widget(); + inline void getViewIds(int* pRow, int* pCol) { + *pRow = mLastXPos/mCellWidth; + *pCol = mLastYPos/mCellHeight; + } + public: + /* public variables */ + int mWidth; // Framebuffer width + int mHeight; // Framebuffer height + int mRows; + int mCols; + int mCellWidth; + int mCellHeight; + std::vector mMVPs; + + GLuint mFramePBO; + + /* Constructors and methods */ Widget(int pWidth, int pHeight, const char* pTitle, const Widget* pWindow, const bool invisible); ~Widget(); @@ -49,8 +72,6 @@ class Widget { long long getDisplayHandle(); - void getFrameBufferSize(int* pW, int* pH); - void setTitle(const char* pTitle); void setPos(int pX, int pY); @@ -67,9 +88,17 @@ class Widget { void resetCloseFlag(); + void resizeHandler(int pWidth, int pHeight); + void keyboardHandler(int pKey, int pScancode, int pAction, int pMods); + void cursorHandler(float pXPos, float pYPos); + + void mouseButtonHandler(int pButton, int pAction, int pMods); + void pollEvents(); + + void resizePixelBuffers(); }; } diff --git a/src/backend/opengl/histogram.cpp b/src/backend/opengl/histogram.cpp new file mode 100644 index 00000000..98146f5e --- /dev/null +++ b/src/backend/opengl/histogram.cpp @@ -0,0 +1,173 @@ +/******************************************************* + * 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 +#include + +#include + +using namespace std; + +namespace opengl +{ + +void hist_impl::bindResources(const int pWindowId) +{ + if (mVAOMap.find(pWindowId) == mVAOMap.end()) { + CheckGL("Begin hist_impl::bindResources"); + GLuint vao = 0; + /* create a vertex array object + * with appropriate bindings */ + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + // attach histogram bar vertices + glEnableVertexAttribArray(mPointIndex); + glBindBuffer(GL_ARRAY_BUFFER, screenQuadVBO(pWindowId)); + glVertexAttribPointer(mPointIndex, 2, GL_FLOAT, GL_FALSE, 0, 0); + // attach histogram frequencies + glEnableVertexAttribArray(mFreqIndex); + glBindBuffer(GL_ARRAY_BUFFER, mVBO); + glVertexAttribPointer(mFreqIndex, 1, mGLType, GL_FALSE, 0, 0); + glVertexAttribDivisor(mFreqIndex, 1); + // attach histogram bar colors + glEnableVertexAttribArray(mColorIndex); + glBindBuffer(GL_ARRAY_BUFFER, mCBO); + glVertexAttribPointer(mColorIndex, 3, GL_FLOAT, GL_FALSE, 0, 0); + glVertexAttribDivisor(mColorIndex, 1); + // attach histogram bar alphas + glEnableVertexAttribArray(mAlphaIndex); + glBindBuffer(GL_ARRAY_BUFFER, mABO); + glVertexAttribPointer(mAlphaIndex, 1, GL_FLOAT, GL_FALSE, 0, 0); + glVertexAttribDivisor(mAlphaIndex, 1); + glBindVertexArray(0); + /* store the vertex array object corresponding to + * the window instance in the map */ + mVAOMap[pWindowId] = vao; + CheckGL("End hist_impl::bindResources"); + } + + glBindVertexArray(mVAOMap[pWindowId]); +} + +void hist_impl::unbindResources() const +{ + glBindVertexArray(0); +} + +hist_impl::hist_impl(const uint pNBins, const fg::dtype pDataType) + : mDataType(pDataType), mGLType(dtype2gl(mDataType)), mNBins(pNBins), + mProgram(0), mYMaxIndex(-1), mNBinsIndex(-1), mMatIndex(-1), mPointIndex(-1), + mFreqIndex(-1), mColorIndex(-1), mAlphaIndex(-1), mPVCIndex(-1), mPVAIndex(-1), + mBColorIndex(-1) +{ + CheckGL("Begin hist_impl::hist_impl"); + mIsPVCOn = false; + mIsPVAOn = false; + + setColor(0.8f, 0.6f, 0.0f, 1.0f); + mLegend = std::string(""); + + mProgram = initShaders(glsl::histogram_vs.c_str(), glsl::histogram_fs.c_str()); + + mYMaxIndex = glGetUniformLocation(mProgram, "ymax" ); + mNBinsIndex = glGetUniformLocation(mProgram, "nbins" ); + mMatIndex = glGetUniformLocation(mProgram, "transform"); + mPVCIndex = glGetUniformLocation(mProgram, "isPVCOn" ); + mPVAIndex = glGetUniformLocation(mProgram, "isPVAOn" ); + mBColorIndex = glGetUniformLocation(mProgram, "barColor" ); + mPointIndex = glGetAttribLocation (mProgram, "point" ); + mFreqIndex = glGetAttribLocation (mProgram, "freq" ); + mColorIndex = glGetAttribLocation (mProgram, "color" ); + mAlphaIndex = glGetAttribLocation (mProgram, "alpha" ); + + mVBOSize = mNBins; + mCBOSize = 3*mVBOSize; + mABOSize = mNBins; + +#define HIST_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(mGLType) { + case GL_FLOAT : HIST_CREATE_BUFFERS(float) ; break; + case GL_INT : HIST_CREATE_BUFFERS(int) ; break; + case GL_UNSIGNED_INT : HIST_CREATE_BUFFERS(uint) ; break; + case GL_SHORT : HIST_CREATE_BUFFERS(short) ; break; + case GL_UNSIGNED_SHORT : HIST_CREATE_BUFFERS(ushort); break; + case GL_UNSIGNED_BYTE : HIST_CREATE_BUFFERS(float) ; break; + default: fg::TypeError("hist_impl::hist_impl", __LINE__, 1, mDataType); + } +#undef HIST_CREATE_BUFFERS + + CheckGL("End hist_impl::hist_impl"); +} + +hist_impl::~hist_impl() +{ + CheckGL("Begin hist_impl::~hist_impl"); + for (auto it = mVAOMap.begin(); it!=mVAOMap.end(); ++it) { + GLuint vao = it->second; + glDeleteVertexArrays(1, &vao); + } + glDeleteBuffers(1, &mVBO); + glDeleteBuffers(1, &mCBO); + glDeleteBuffers(1, &mABO); + glDeleteProgram(mProgram); + CheckGL("End hist_impl::~hist_impl"); +} + +void hist_impl::render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4& pTransform) +{ + CheckGL("Begin hist_impl::render"); + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_SCISSOR_TEST); + + glScissor(pX, pY, pVPW, pVPH); + glUseProgram(mProgram); + + glUniform1f(mYMaxIndex, mRange[3]); + glUniform1f(mNBinsIndex, (GLfloat)mNBins); + glUniformMatrix4fv(mMatIndex, 1, GL_FALSE, glm::value_ptr(pTransform)); + glUniform1i(mPVCIndex, mIsPVCOn); + glUniform1i(mPVAIndex, mIsPVAOn); + glUniform4fv(mBColorIndex, 1, mColor); + + /* render a rectangle for each bin. Same + * rectangle is scaled and translated accordingly + * for each bin. OpenGL instanced rendering is used to do it.*/ + hist_impl::bindResources(pWindowId); + glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, mNBins); + hist_impl::unbindResources(); + + glUseProgram(0); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + CheckGL("End hist_impl::render"); +} + +} diff --git a/src/backend/opengl/histogram.hpp b/src/backend/opengl/histogram.hpp new file mode 100644 index 00000000..14e7a6b1 --- /dev/null +++ b/src/backend/opengl/histogram.hpp @@ -0,0 +1,59 @@ +/******************************************************* +* 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 + +namespace opengl +{ + +class hist_impl : public AbstractRenderable { + private: + /* plot points characteristics */ + fg::dtype mDataType; + GLenum mGLType; + GLuint mNBins; + /* OpenGL Objects */ + GLuint mProgram; + /* internal shader attributes for mProgram + * shader program to render histogram bars for each + * bin*/ + GLuint mYMaxIndex; + GLuint mNBinsIndex; + GLuint mMatIndex; + GLuint mPointIndex; + GLuint mFreqIndex; + GLuint mColorIndex; + GLuint mAlphaIndex; + GLuint mPVCIndex; + GLuint mPVAIndex; + GLuint mBColorIndex; + + std::map mVAOMap; + + /* bind and unbind helper functions + * for rendering resources */ + void bindResources(const int pWindowId); + void unbindResources() const; + void computeTransformMat(glm::mat4& pOut, const glm::mat4 pInput); + + public: + hist_impl(const uint pNBins, const fg::dtype pDataType); + ~hist_impl(); + + void render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4& pTransform); +}; + +} diff --git a/src/backend/opengl/image.cpp b/src/backend/opengl/image.cpp new file mode 100644 index 00000000..72a8f26b --- /dev/null +++ b/src/backend/opengl/image.cpp @@ -0,0 +1,201 @@ +/******************************************************* + * 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 +#include +#include + +#include +#include + +namespace opengl +{ + +void image_impl::bindResources(int pWindowId) const +{ + glBindVertexArray(screenQuadVAO(pWindowId)); +} + +void image_impl::unbindResources() const +{ + glBindVertexArray(0); +} + +image_impl::image_impl(const uint pWidth, const uint pHeight, + const fg::ChannelFormat pFormat, const fg::dtype pDataType) + : mWidth(pWidth), mHeight(pHeight), mFormat(pFormat), + mGLformat(ctype2gl(mFormat)), mGLiformat(ictype2gl(mFormat)), + mDataType(pDataType), mGLType(dtype2gl(mDataType)), mAlpha(1.0f), + mKeepARatio(true), mFormatSize(1), mMatIndex(-1), mTexIndex(-1), + mNumCIndex(-1), mAlphaIndex(-1), mCMapLenIndex(-1), mCMapIndex(-1) +{ + CheckGL("Begin image_impl::image_impl"); + + mProgram = initShaders(glsl::image_vs.c_str(), glsl::image_fs.c_str()); + mMatIndex = glGetUniformLocation(mProgram, "matrix"); + mCMapIndex = glGetUniformBlockIndex(mProgram, "ColorMap"); + mCMapLenIndex = glGetUniformLocation(mProgram, "cmaplen"); + mTexIndex = glGetUniformLocation(mProgram, "tex"); + mNumCIndex = glGetUniformLocation(mProgram, "numcomps"); + mAlphaIndex = glGetUniformLocation(mProgram, "alpha"); + + // Initialize OpenGL Items + glGenTextures(1, &(mTex)); + glBindTexture(GL_TEXTURE_2D, mTex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glTexImage2D(GL_TEXTURE_2D, 0, mGLiformat, mWidth, mHeight, 0, mGLformat, mGLType, NULL); + + CheckGL("Before PBO Initialization"); + glGenBuffers(1, &mPBO); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO); + size_t typeSize = 0; + switch(mGLType) { + case GL_INT: typeSize = sizeof(int ); break; + case GL_UNSIGNED_INT: typeSize = sizeof(uint ); break; + case GL_SHORT: typeSize = sizeof(short ); break; + case GL_UNSIGNED_SHORT: typeSize = sizeof(ushort); break; + case GL_BYTE: typeSize = sizeof(char ); break; + case GL_UNSIGNED_BYTE: typeSize = sizeof(uchar ); break; + default: typeSize = sizeof(float); break; + } + switch(mFormat) { + case FG_GRAYSCALE: mFormatSize = 1; break; + case FG_RG: mFormatSize = 2; break; + case FG_RGB: mFormatSize = 3; break; + case FG_BGR: mFormatSize = 3; break; + case FG_RGBA: mFormatSize = 4; break; + case FG_BGRA: mFormatSize = 4; break; + default: mFormatSize = 1; break; + } + mPBOsize = mWidth * mHeight * mFormatSize * typeSize; + glBufferData(GL_PIXEL_UNPACK_BUFFER, mPBOsize, NULL, GL_STREAM_COPY); + + glBindTexture(GL_TEXTURE_2D, 0); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + CheckGL("End image_impl::image_impl"); +} + +image_impl::~image_impl() +{ + CheckGL("Begin image_impl::~image_impl"); + glDeleteBuffers(1, &mPBO); + glDeleteTextures(1, &mTex); + glDeleteProgram(mProgram); + CheckGL("End image_impl::~image_impl"); +} + +void image_impl::setColorMapUBOParams(const GLuint pUBO, const GLuint pSize) +{ + mColorMapUBO = pUBO; + mUBOSize = pSize; +} + +void image_impl::setAlpha(const float pAlpha) +{ + mAlpha = pAlpha; +} + +void image_impl::keepAspectRatio(const bool pKeep) +{ + mKeepARatio = pKeep; +} + +uint image_impl::width() const { return mWidth; } + +uint image_impl::height() const { return mHeight; } + +fg::ChannelFormat image_impl::pixelFormat() const { return mFormat; } + +fg::dtype image_impl::channelType() const { return mDataType; } + +uint image_impl::pbo() const { return mPBO; } + +uint image_impl::size() const { return (uint)mPBOsize; } + +void image_impl::render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4& pTransform) +{ + CheckGL("Begin image_impl::render"); + + float xscale = 1.f; + float yscale = 1.f; + if (mKeepARatio) { + if (mWidth > mHeight) { + float trgtH = pVPW * float(mHeight)/float(mWidth); + float trgtW = trgtH * float(mWidth)/float(mHeight); + xscale = trgtW/pVPW; + yscale = trgtH/pVPH; + } else { + float trgtW = pVPH * float(mWidth)/float(mHeight); + float trgtH = trgtW * float(mHeight)/float(mWidth); + xscale = trgtW/pVPW; + yscale = trgtH/pVPH; + } + } + + glm::mat4 strans = glm::scale(pTransform, glm::vec3(xscale, yscale, 1)); + + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glUseProgram(mProgram); + + glUniform1i(mNumCIndex, mFormatSize); + glUniform1f(mAlphaIndex, mAlpha); + + // load texture from PBO + glActiveTexture(GL_TEXTURE0); + glUniform1i(mTexIndex, 0); + glBindTexture(GL_TEXTURE_2D, mTex); + // bind PBO to load data into texture + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mWidth, mHeight, mGLformat, mGLType, 0); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + + glUniformMatrix4fv(mMatIndex, 1, GL_FALSE, glm::value_ptr(strans)); + + glUniform1f(mCMapLenIndex, (GLfloat)mUBOSize); + glBindBufferBase(GL_UNIFORM_BUFFER, 0, mColorMapUBO); + glUniformBlockBinding(mProgram, mCMapIndex, 0); + + // Draw to screen + bindResources(pWindowId); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + unbindResources(); + + glBindTexture(GL_TEXTURE_2D, 0); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + // ubind the shader program + glUseProgram(0); + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + + CheckGL("End image_impl::render"); +} + +} diff --git a/src/backend/opengl/image.hpp b/src/backend/opengl/image.hpp new file mode 100644 index 00000000..7c3996a8 --- /dev/null +++ b/src/backend/opengl/image.hpp @@ -0,0 +1,72 @@ +/******************************************************* +* 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 + +namespace opengl +{ + +class image_impl : public AbstractRenderable { + private: + uint mWidth; + uint mHeight; + fg::ChannelFormat mFormat; + GLenum mGLformat; + GLenum mGLiformat; + fg::dtype mDataType; + GLenum mGLType; + float mAlpha; + bool mKeepARatio; + size_t mFormatSize; + /* internal resources for interop */ + size_t mPBOsize; + GLuint mPBO; + GLuint mTex; + GLuint mProgram; + GLuint mMatIndex; + GLuint mTexIndex; + GLuint mNumCIndex; + GLuint mAlphaIndex; + GLuint mCMapLenIndex; + GLuint mCMapIndex; + /* color map details */ + GLuint mColorMapUBO; + GLuint mUBOSize; + + /* helper functions to bind and unbind + * resources for render quad primitive */ + void bindResources(int pWindowId) const; + void unbindResources() const; + + public: + image_impl(const uint pWidth, const uint pHeight, + const fg::ChannelFormat pFormat, const fg::dtype pDataType); + ~image_impl(); + + void setColorMapUBOParams(const GLuint pUBO, const GLuint pSize); + void setAlpha(const float pAlpha); + void keepAspectRatio(const bool pKeep=true); + + uint width() const; + uint height() const; + fg::ChannelFormat pixelFormat() const; + fg::dtype channelType() const; + uint pbo() const; + uint size() const; + + void render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4& pTransform); +}; + +} diff --git a/src/backend/opengl/plot.cpp b/src/backend/opengl/plot.cpp new file mode 100644 index 00000000..c1c78193 --- /dev/null +++ b/src/backend/opengl/plot.cpp @@ -0,0 +1,306 @@ +/******************************************************* + * 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 + +using namespace std; + +// identity matrix +static const glm::mat4 I(1.0f); + +namespace opengl +{ + +void plot_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(mPlotPointIndex); + glBindBuffer(GL_ARRAY_BUFFER, mVBO); + glVertexAttribPointer(mPlotPointIndex, mDimension, mGLType, GL_FALSE, 0, 0); + // attach colors + glEnableVertexAttribArray(mPlotColorIndex); + glBindBuffer(GL_ARRAY_BUFFER, mCBO); + glVertexAttribPointer(mPlotColorIndex, 3, GL_FLOAT, GL_FALSE, 0, 0); + // attach alphas + glEnableVertexAttribArray(mPlotAlphaIndex); + glBindBuffer(GL_ARRAY_BUFFER, mABO); + glVertexAttribPointer(mPlotAlphaIndex, 1, GL_FLOAT, GL_FALSE, 0, 0); + // attach radii + glEnableVertexAttribArray(mMarkerRadiiIndex); + glBindBuffer(GL_ARRAY_BUFFER, mRBO); + glVertexAttribPointer(mMarkerRadiiIndex, 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 plot_impl::unbindResources() const +{ + glBindVertexArray(0); +} + +void plot_impl::computeTransformMat(glm::mat4& pOut, const glm::mat4 pInput, + const int pX, const int pY, + const int pVPW, const int pVPH) +{ + float range_x = mRange[1] - mRange[0]; + float range_y = mRange[3] - mRange[2]; + float range_z = mRange[5] - mRange[4]; + // set scale to zero if input is constant array + // otherwise compute scale factor by standard equation + float graph_scale_x = std::abs(range_x) < 1.0e-3 ? 0.0f : 2/(range_x); + float graph_scale_y = std::abs(range_y) < 1.0e-3 ? 0.0f : 2/(range_y); + float graph_scale_z = std::abs(range_z) < 1.0e-3 ? 0.0f : 2/(range_z); + + float coor_offset_x = (-mRange[0] * graph_scale_x); + float coor_offset_y = (-mRange[2] * graph_scale_y); + float coor_offset_z = (-mRange[4] * graph_scale_z); + + glm::mat4 rMat = glm::rotate(I, -glm::radians(90.f), glm::vec3(1,0,0)); + glm::mat4 tMat = glm::translate(I, + glm::vec3(-1 + coor_offset_x , -1 + coor_offset_y, -1 + coor_offset_z)); + glm::mat4 sMat = glm::scale(I, + glm::vec3(1.0f * graph_scale_x, -1.0f * graph_scale_y, 1.0f * graph_scale_z)); + + glm::mat4 model= rMat * tMat * sMat; + + pOut = pInput * model; + glScissor(pX, pY, pVPW, pVPH); +} + +void plot_impl::bindDimSpecificUniforms() +{ + glUniform2fv(mPlotRangeIndex, 3, mRange); +} + +plot_impl::plot_impl(const uint pNumPoints, const fg::dtype pDataType, + const fg::PlotType pPlotType, const fg::MarkerType pMarkerType, const int pD) + : mDimension(pD), mMarkerSize(12), mNumPoints(pNumPoints), mDataType(pDataType), + mGLType(dtype2gl(mDataType)), mMarkerType(pMarkerType), mPlotType(pPlotType), mIsPVROn(false), + mPlotProgram(-1), mMarkerProgram(-1), mRBO(-1), mPlotMatIndex(-1), mPlotPVCOnIndex(-1), + mPlotPVAOnIndex(-1), mPlotUColorIndex(-1), mPlotRangeIndex(-1), mPlotPointIndex(-1), + mPlotColorIndex(-1), mPlotAlphaIndex(-1), mMarkerPVCOnIndex(-1), mMarkerPVAOnIndex(-1), + mMarkerTypeIndex(-1), mMarkerColIndex(-1), mMarkerMatIndex(-1), mMarkerPointIndex(-1), + mMarkerColorIndex(-1), mMarkerAlphaIndex(-1), mMarkerRadiiIndex(-1) +{ + CheckGL("Begin plot_impl::plot_impl"); + mIsPVCOn = false; + mIsPVAOn = false; + + setColor(0, 1, 0, 1); + mLegend = std::string(""); + + if (mDimension==2) { + mPlotProgram = initShaders(glsl::marker2d_vs.c_str(), glsl::histogram_fs.c_str()); + mMarkerProgram = initShaders(glsl::marker2d_vs.c_str(), glsl::marker_fs.c_str()); + mPlotUColorIndex = glGetUniformLocation(mPlotProgram, "barColor"); + mVBOSize = 2*mNumPoints; + } else { + mPlotProgram = initShaders(glsl::plot3_vs.c_str(), glsl::plot3_fs.c_str()); + mMarkerProgram = initShaders(glsl::plot3_vs.c_str(), glsl::marker_fs.c_str()); + mPlotRangeIndex = glGetUniformLocation(mPlotProgram, "minmaxs"); + mVBOSize = 3*mNumPoints; + } + + mCBOSize = 3*mNumPoints; + mABOSize = mNumPoints; + mRBOSize = mNumPoints; + + mPlotMatIndex = glGetUniformLocation(mPlotProgram, "transform"); + mPlotPVCOnIndex = glGetUniformLocation(mPlotProgram, "isPVCOn"); + mPlotPVAOnIndex = glGetUniformLocation(mPlotProgram, "isPVAOn"); + mPlotPointIndex = glGetAttribLocation (mPlotProgram, "point"); + mPlotColorIndex = glGetAttribLocation (mPlotProgram, "color"); + mPlotAlphaIndex = glGetAttribLocation (mPlotProgram, "alpha"); + + mMarkerMatIndex = glGetUniformLocation(mMarkerProgram, "transform"); + mMarkerPVCOnIndex = glGetUniformLocation(mMarkerProgram, "isPVCOn"); + mMarkerPVAOnIndex = glGetUniformLocation(mMarkerProgram, "isPVAOn"); + mMarkerPVROnIndex = glGetUniformLocation(mMarkerProgram, "isPVROn"); + mMarkerTypeIndex = glGetUniformLocation(mMarkerProgram, "marker_type"); + mMarkerColIndex = glGetUniformLocation(mMarkerProgram, "marker_color"); + mMarkerPSizeIndex = glGetUniformLocation(mMarkerProgram, "psize"); + mMarkerPointIndex = glGetAttribLocation (mMarkerProgram, "point"); + mMarkerColorIndex = glGetAttribLocation (mMarkerProgram, "color"); + mMarkerAlphaIndex = glGetAttribLocation (mMarkerProgram, "alpha"); + mMarkerRadiiIndex = glGetAttribLocation (mMarkerProgram, "pointsize"); + +#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); \ + mRBO = createBuffer(GL_ARRAY_BUFFER, mRBOSize, NULL, GL_DYNAMIC_DRAW); \ + mVBOSize *= sizeof(type); \ + mCBOSize *= sizeof(float); \ + mABOSize *= sizeof(float); \ + mRBOSize *= sizeof(float); + + switch(mGLType) { + case GL_FLOAT : PLOT_CREATE_BUFFERS(float) ; break; + case GL_INT : PLOT_CREATE_BUFFERS(int) ; break; + case GL_UNSIGNED_INT : PLOT_CREATE_BUFFERS(uint) ; break; + case GL_SHORT : PLOT_CREATE_BUFFERS(short) ; break; + case GL_UNSIGNED_SHORT : PLOT_CREATE_BUFFERS(ushort); break; + case GL_UNSIGNED_BYTE : PLOT_CREATE_BUFFERS(float) ; break; + default: fg::TypeError("plot_impl::plot_impl", __LINE__, 1, mDataType); + } +#undef PLOT_CREATE_BUFFERS + CheckGL("End plot_impl::plot_impl"); +} + +plot_impl::~plot_impl() +{ + CheckGL("Begin plot_impl::~plot_impl"); + for (auto it = mVAOMap.begin(); it!=mVAOMap.end(); ++it) { + GLuint vao = it->second; + glDeleteVertexArrays(1, &vao); + } + glDeleteBuffers(1, &mVBO); + glDeleteBuffers(1, &mCBO); + glDeleteBuffers(1, &mABO); + glDeleteProgram(mPlotProgram); + glDeleteProgram(mMarkerProgram); + CheckGL("End plot_impl::~plot_impl"); +} + +void plot_impl::setMarkerSize(const float pMarkerSize) +{ + mMarkerSize = pMarkerSize; +} + +GLuint plot_impl::markers() +{ + mIsPVROn = true; + return mRBO; +} + +size_t plot_impl::markersSizes() const +{ + return mRBOSize; +} + +void plot_impl::render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4& pTransform) +{ + CheckGL("Begin plot_impl::render"); + glEnable(GL_SCISSOR_TEST); + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glm::mat4 mvp(1.0); + this->computeTransformMat(mvp, pTransform, pX, pY, pVPW, pVPH); + + if (mPlotType == FG_PLOT_LINE) { + glUseProgram(mPlotProgram); + + this->bindDimSpecificUniforms(); + glUniformMatrix4fv(mPlotMatIndex, 1, GL_FALSE, glm::value_ptr(mvp)); + glUniform1i(mPlotPVCOnIndex, mIsPVCOn); + glUniform1i(mPlotPVAOnIndex, mIsPVAOn); + + plot_impl::bindResources(pWindowId); + glDrawArrays(GL_LINE_STRIP, 0, mNumPoints); + plot_impl::unbindResources(); + + glUseProgram(0); + } + + if (mMarkerType != FG_MARKER_NONE) { + glEnable(GL_PROGRAM_POINT_SIZE); + glUseProgram(mMarkerProgram); + + glUniformMatrix4fv(mMarkerMatIndex, 1, GL_FALSE, glm::value_ptr(mvp)); + glUniform1i(mMarkerPVCOnIndex, mIsPVCOn); + glUniform1i(mMarkerPVAOnIndex, mIsPVAOn); + glUniform1i(mMarkerPVROnIndex, mIsPVROn); + glUniform1i(mMarkerTypeIndex, mMarkerType); + glUniform4fv(mMarkerColIndex, 1, mColor); + glUniform1f(mMarkerPSizeIndex, mMarkerSize); + + plot_impl::bindResources(pWindowId); + glDrawArrays(GL_POINTS, 0, mNumPoints); + plot_impl::unbindResources(); + + glUseProgram(0); + glDisable(GL_PROGRAM_POINT_SIZE); + } + + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + glDisable(GL_SCISSOR_TEST); + CheckGL("End plot_impl::render"); +} + +void plot2d_impl::computeTransformMat(glm::mat4& pOut, const glm::mat4 pInput, + const int pX, const int pY, + const int pVPW, const int pVPH) +{ + float range_x = mRange[1] - mRange[0]; + float range_y = mRange[3] - mRange[2]; + // set scale to zero if input is constant array + // otherwise compute scale factor by standard equation + float graph_scale_x = std::abs(range_x) < 1.0e-3 ? 0.0f : 2/(range_x); + float graph_scale_y = std::abs(range_y) < 1.0e-3 ? 0.0f : 2/(range_y); + + float coor_offset_x = (-mRange[0] * graph_scale_x); + float coor_offset_y = (-mRange[2] * graph_scale_y); + + //FIXME: Using hard constants for now, find a way to get chart values + const float lMargin = 68; + const float rMargin = 8; + const float tMargin = 8; + const float bMargin = 44; + const float tickSize = 10; + + float viewWidth = pVPW - (lMargin + rMargin + tickSize/2); + float viewHeight = pVPH - (bMargin + tMargin + tickSize/2); + float view_scale_x = viewWidth/pVPW; + float view_scale_y = viewHeight/pVPH; + + coor_offset_x *= view_scale_x; + coor_offset_y *= view_scale_y; + + float view_offset_x = (2.0f * (lMargin + tickSize/2 )/ pVPW ) ; + float view_offset_y = (2.0f * (bMargin + tickSize )/ pVPH ) ; + + glm::mat4 tMat = glm::translate(I, + glm::vec3(-1 + view_offset_x + coor_offset_x , -1 + view_offset_y + coor_offset_y, 0)); + pOut = glm::scale(tMat, + glm::vec3(graph_scale_x * view_scale_x , graph_scale_y * view_scale_y ,1)); + + pOut = pInput * pOut; + + glScissor(pX + lMargin + tickSize/2, pY+bMargin + tickSize/2, + pVPW - lMargin - rMargin - tickSize/2, + pVPH - bMargin - tMargin - tickSize/2); +} + +void plot2d_impl::bindDimSpecificUniforms() +{ + glUniform4fv(mPlotUColorIndex, 1, mColor); +} + +} diff --git a/src/backend/opengl/plot.hpp b/src/backend/opengl/plot.hpp new file mode 100644 index 00000000..074bfff6 --- /dev/null +++ b/src/backend/opengl/plot.hpp @@ -0,0 +1,109 @@ +/******************************************************* +* 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 +#include + +#include +#include +#include + +#include +#include + +namespace opengl +{ + +class plot_impl : public AbstractRenderable { + protected: + GLuint mDimension; + GLfloat mMarkerSize; + /* plot points characteristics */ + GLuint mNumPoints; + fg::dtype mDataType; + GLenum mGLType; + fg::MarkerType mMarkerType; + fg::PlotType mPlotType; + bool mIsPVROn; + /* OpenGL Objects */ + GLuint mPlotProgram; + GLuint mMarkerProgram; + GLuint mRBO; + size_t mRBOSize; + /* shader variable index locations */ + GLuint mPlotMatIndex; + GLuint mPlotPVCOnIndex; + GLuint mPlotPVAOnIndex; + GLuint mPlotUColorIndex; + GLuint mPlotRangeIndex; + GLuint mPlotPointIndex; + GLuint mPlotColorIndex; + GLuint mPlotAlphaIndex; + + GLuint mMarkerPVCOnIndex; + GLuint mMarkerPVAOnIndex; + GLuint mMarkerPVROnIndex; + GLuint mMarkerTypeIndex; + GLuint mMarkerColIndex; + GLuint mMarkerMatIndex; + GLuint mMarkerPSizeIndex; + GLuint mMarkerPointIndex; + GLuint mMarkerColorIndex; + GLuint mMarkerAlphaIndex; + GLuint mMarkerRadiiIndex; + + std::map mVAOMap; + + /* bind and unbind helper functions + * for rendering resources */ + void bindResources(const int pWindowId); + void unbindResources() const; + + virtual void computeTransformMat(glm::mat4& pOut, const glm::mat4 pInput, + const int pX, const int pY, + const int pVPW, const int pVPH); + virtual void bindDimSpecificUniforms(); // has to be called only after shaders are bound + + public: + plot_impl(const uint pNumPoints, const fg::dtype pDataType, + const fg::PlotType pPlotType, const fg::MarkerType pMarkerType, + const int pDimension=3); + ~plot_impl(); + + void setMarkerSize(const float pMarkerSize); + + GLuint markers(); + size_t markersSizes() const; + + virtual void render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4& pTransform); +}; + +class plot2d_impl : public plot_impl { + protected: + void computeTransformMat(glm::mat4& pOut, const glm::mat4 pInput, + const int pX, const int pY, + const int pVPW, const int pVPH) override; + void bindDimSpecificUniforms() override; // has to be called only after shaders are bound + + public: + plot2d_impl(const uint pNumPoints, const fg::dtype pDataType, + const fg::PlotType pPlotType, const fg::MarkerType pMarkerType) + : plot_impl(pNumPoints, pDataType, pPlotType, pMarkerType, 2) {} +}; + +} diff --git a/src/backend/opengl/sdl/window.cpp b/src/backend/opengl/sdl/window.cpp new file mode 100644 index 00000000..75068ba6 --- /dev/null +++ b/src/backend/opengl/sdl/window.cpp @@ -0,0 +1,285 @@ +/******************************************************* +* 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 + +#ifndef OS_WIN +#include +#else +#include +#endif +#include + +using glm::rotate; +using glm::translate; +using glm::scale; + +#define SDL_THROW_ERROR(msg, err) \ + throw fg::Error("Window constructor", __LINE__, msg, err); + +namespace wtk +{ + +Widget::Widget() + : mWindow(nullptr), mClose(false), mLastXPos(0), mLastYPos(0), mButton(-1), + mWidth(512), mHeight(512), mRows(1), mCols(1) +{ + mCellWidth = mWidth; + mCellHeight = mHeight; + mFramePBO = 0; +} + +Widget::Widget(int pWidth, int pHeight, const char* pTitle, const Widget* pWindow, const bool invisible) + : mWindow(nullptr), mClose(false), mLastXPos(0), mLastYPos(0), mButton(-1), mRows(1), mCols(1) +{ + mFramePBO = 0; + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + std::cerr << "ERROR: SDL wasn't able to initalize\n"; + SDL_THROW_ERROR("SDL initilization failed", FG_ERR_GL_ERROR) + } + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + + if (pWindow != nullptr) { + pWindow->makeContextCurrent(); + SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); + } else { + //SDL_GL_MakeCurrent(NULL, NULL); + SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 0); + } + + mWindow = SDL_CreateWindow( + pTitle, + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + pWidth, pHeight, + (invisible ? SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN + : SDL_WINDOW_OPENGL) | SDL_WINDOW_RESIZABLE + ); + if (mWindow==NULL) { + std::cerr<<"Error: Could not Create SDL Window!"<< SDL_GetError() << std::endl; + SDL_THROW_ERROR("sdl window creation failed", FG_ERR_GL_ERROR) + } + + mContext = SDL_GL_CreateContext(mWindow); + if (mContext==NULL) { + std::cerr<<"Error: Could not OpenGL context!" << SDL_GetError() << std::endl; + SDL_THROW_ERROR("opengl context creation failed", FG_ERR_GL_ERROR) + } + + SDL_GL_SetSwapInterval(1); + mWindowId = SDL_GetWindowID(mWindow); + SDL_GetWindowSize(mWindow, &mWidth, &mHeight); + mCellWidth = mWidth; + mCellHeight = mHeight; +} + +Widget::~Widget() +{ + glDeleteBuffers(1, &mFramePBO); + + SDL_DestroyWindow(mWindow); + SDL_GL_DeleteContext(mContext); +} + +SDL_Window* Widget::getNativeHandle() const +{ + return mWindow; +} + +void Widget::makeContextCurrent() const +{ + SDL_GL_MakeCurrent(mWindow, mContext); +} + +long long Widget::getGLContextHandle() +{ +#ifdef OS_WIN + return reinterpret_cast(wglGetCurrentContext()); +#endif +#ifdef OS_LNX + return reinterpret_cast(glXGetCurrentContext()); +#endif +} + +long long Widget::getDisplayHandle() +{ +#ifdef OS_WIN + return reinterpret_cast(wglGetCurrentDC()); +#endif +#ifdef OS_LNX + return reinterpret_cast(glXGetCurrentDisplay()); +#endif +} + +void Widget::setTitle(const char* pTitle) +{ + SDL_SetWindowTitle(mWindow, pTitle); +} + +void Widget::setPos(int pX, int pY) +{ + SDL_SetWindowPosition(mWindow, pX, pY); +} + +void Widget::setSize(unsigned pW, unsigned pH) +{ + SDL_SetWindowSize(mWindow, pW, pH); +} + +void Widget::swapBuffers() +{ + SDL_GL_SwapWindow(mWindow); + + glReadBuffer(GL_FRONT); + glBindBuffer(GL_PIXEL_PACK_BUFFER, mFramePBO); + glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); +} + +void Widget::hide() +{ + mClose = true; + SDL_HideWindow(mWindow); +} + +void Widget::show() +{ + mClose = false; + SDL_ShowWindow(mWindow); +} + +bool Widget::close() +{ + return mClose; +} + +void Widget::resetCloseFlag() +{ + if(mClose==true) { + show(); + } +} + +void Widget::pollEvents() +{ + static const float SPEED = 0.005f; + SDL_Event evnt; + SDL_PollEvent(&evnt); + + /* handle window events that are triggered + when the window with window id 'mWindowId' is in focus + */ + if (evnt.key.windowID == mWindowId) { + if (evnt.type == SDL_WINDOWEVENT) { + switch(evnt.window.event) { + case SDL_WINDOWEVENT_CLOSE: + mClose = true; + break; + case SDL_WINDOWEVENT_RESIZED: + mWidth = evnt.window.data1; + mHeight = evnt.window.data2; + mCellWidth = mWidth / mCols; + mCellHeight = mHeight / mRows; + resizePixelBuffers(); + break; + } + } + + if (evnt.type == SDL_KEYDOWN) { + switch(evnt.key.keysym.sym) { + case SDLK_ESCAPE: mClose = true ; break; + case SDLK_LALT : mMod = SDLK_LALT; break; + case SDLK_RALT : mMod = SDLK_RALT; break; + } + } else if (evnt.type == SDL_KEYUP) { + switch(evnt.key.keysym.sym) { + case SDLK_LALT: mMod = -1; break; + case SDLK_RALT: mMod = -1; break; + } + } + + if(evnt.type == SDL_MOUSEBUTTONUP) { + if(evnt.button.button == SDL_BUTTON_MIDDLE && mMod == SDLK_LALT) { + int r, c; + getViewIds(&r, &c); + glm::mat4& mvp = mMVPs[r+c*mRows]; + mvp = glm::mat4(1.0f); + } + } + + if(evnt.type == SDL_MOUSEMOTION) { + double deltaX = -evnt.motion.xrel; + double deltaY = -evnt.motion.yrel; + + int r, c; + getViewIds(&r, &c); + glm::mat4& mvp = mMVPs[r+c*mRows]; + + if(evnt.motion.state == SDL_BUTTON_LMASK && + (mMod == SDLK_LALT || mMod == SDLK_RALT)) { + // Zoom + if(deltaY != 0) { + if(deltaY < 0) { + deltaY = 1.0 / (-deltaY); + } + mvp = scale(mvp, glm::vec3(pow(deltaY, SPEED))); + } + } else if (evnt.motion.state == SDL_BUTTON_LMASK) { + // Translate + mvp = translate(mvp, glm::vec3(-deltaX, deltaY, 0.0f) * SPEED); + } else if (evnt.motion.state == SDL_BUTTON_RMASK) { + // Rotations + int width, height; + SDL_GetWindowSize(mWindow, &width, &height); + glm::vec3 curPos = trackballPoint(evnt.motion.x, evnt.motion.y, width, height); + glm::vec3 delta = mLastPos - curPos; + float angle = glm::radians(90.0f * sqrt(delta.x*delta.x + delta.y*delta.y + delta.z*delta.z)); + glm::vec3 axis( + mLastPos.y*curPos.z-mLastPos.z*curPos.y, + mLastPos.z*curPos.x-mLastPos.x*curPos.z, + mLastPos.x*curPos.y-mLastPos.y*curPos.x + ); + float dMag = sqrt(dot(delta, delta)); + float aMag = sqrt(dot(axis, axis)); + if (dMag>0 && aMag>0) { + mvp = rotate(mvp, angle, axis); + } + mLastPos = curPos; + } + + mLastXPos = evnt.motion.x; + mLastYPos = evnt.motion.y; + } + } +} + +void Widget::resizePixelBuffers() +{ + if (mFramePBO!=0) + glDeleteBuffers(1, &mFramePBO); + + uint w = mWidth; + uint h = mHeight; + + glGenBuffers(1, &mFramePBO); + glBindBuffer(GL_PIXEL_PACK_BUFFER, mFramePBO); + glBufferData(GL_PIXEL_PACK_BUFFER, w*h*4*sizeof(uchar), 0, GL_DYNAMIC_READ); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); +} + +} diff --git a/src/sdl/window.hpp b/src/backend/opengl/sdl/window.hpp similarity index 58% rename from src/sdl/window.hpp rename to src/backend/opengl/sdl/window.hpp index 0042359a..020bfddf 100644 --- a/src/sdl/window.hpp +++ b/src/backend/opengl/sdl/window.hpp @@ -11,6 +11,8 @@ #include +#include + /* the short form wtk stands for * Windowing Tool Kit */ namespace wtk @@ -18,14 +20,36 @@ namespace wtk class Widget { private: - SDL_Window* mWindow; - SDL_GLContext mContext; - bool mClose; - uint32_t mWindowId; + SDL_Window* mWindow; + SDL_GLContext mContext; + bool mClose; + uint32_t mWindowId; + float mLastXPos; + float mLastYPos; + int mButton; + SDL_Keycode mMod; + glm::vec3 mLastPos; Widget(); + inline void getViewIds(int* pRow, int* pCol) { + *pRow = mLastXPos/mCellWidth; + *pCol = mLastYPos/mCellHeight; + } + public: + /* public variables */ + int mWidth; // Framebuffer width + int mHeight; // Framebuffer height + int mRows; + int mCols; + int mCellWidth; + int mCellHeight; + std::vector mMVPs; + + GLuint mFramePBO; + + /* Constructors and methods */ Widget(int pWidth, int pHeight, const char* pTitle, const Widget* pWindow, const bool invisible); ~Widget(); @@ -38,8 +62,6 @@ class Widget { long long getDisplayHandle(); - void getFrameBufferSize(int* pW, int* pH); - bool getClose() const; void setTitle(const char* pTitle); @@ -62,6 +84,7 @@ class Widget { void pollEvents(); + void resizePixelBuffers(); }; } diff --git a/src/backend/opengl/shaders/chart_fs.glsl b/src/backend/opengl/shaders/chart_fs.glsl new file mode 100644 index 00000000..84721949 --- /dev/null +++ b/src/backend/opengl/shaders/chart_fs.glsl @@ -0,0 +1,10 @@ +#version 330 + +uniform vec4 color; + +out vec4 outputColor; + +void main(void) +{ + outputColor = color; +} diff --git a/src/backend/opengl/shaders/chart_vs.glsl b/src/backend/opengl/shaders/chart_vs.glsl new file mode 100644 index 00000000..94130222 --- /dev/null +++ b/src/backend/opengl/shaders/chart_vs.glsl @@ -0,0 +1,10 @@ +#version 330 + +uniform mat4 transform; + +in vec3 point; + +void main(void) +{ + gl_Position = transform * vec4(point.xyz, 1); +} diff --git a/src/backend/opengl/shaders/font_fs.glsl b/src/backend/opengl/shaders/font_fs.glsl new file mode 100644 index 00000000..87d8e8f9 --- /dev/null +++ b/src/backend/opengl/shaders/font_fs.glsl @@ -0,0 +1,13 @@ +#version 330 + +uniform sampler2D tex; +uniform vec4 textColor; + +in vec2 texCoord; +out vec4 outputColor; + +void main() +{ + vec4 texC = texture(tex, texCoord); + outputColor = vec4(textColor.rgb, textColor.a*texC.r); +} diff --git a/src/backend/opengl/shaders/font_vs.glsl b/src/backend/opengl/shaders/font_vs.glsl new file mode 100644 index 00000000..ac3f2a0c --- /dev/null +++ b/src/backend/opengl/shaders/font_vs.glsl @@ -0,0 +1,15 @@ +#version 330 + +uniform mat4 projectionMatrix; +uniform mat4 modelViewMatrix; + +layout (location = 0) in vec2 inPosition; +layout (location = 1) in vec2 inCoord; + +out vec2 texCoord; + +void main() +{ + gl_Position = projectionMatrix*modelViewMatrix*vec4(inPosition, 0.0, 1.0); + texCoord = inCoord; +} diff --git a/src/backend/opengl/shaders/histogram_fs.glsl b/src/backend/opengl/shaders/histogram_fs.glsl new file mode 100644 index 00000000..095d50a3 --- /dev/null +++ b/src/backend/opengl/shaders/histogram_fs.glsl @@ -0,0 +1,14 @@ +#version 330 + +uniform bool isPVCOn; +uniform bool isPVAOn; +uniform vec4 barColor; + +in vec4 pervcol; +out vec4 outColor; + +void main(void) +{ + float a = isPVAOn ? pervcol.w : 1.0; + outColor = vec4(isPVCOn ? pervcol.xyz : barColor.xyz, isPVAOn ? pervcol.w : 1.0); +} diff --git a/src/backend/opengl/shaders/histogram_vs.glsl b/src/backend/opengl/shaders/histogram_vs.glsl new file mode 100644 index 00000000..d29d2688 --- /dev/null +++ b/src/backend/opengl/shaders/histogram_vs.glsl @@ -0,0 +1,29 @@ +#version 330 + +uniform float ymax; +uniform float nbins; +uniform mat4 transform; + +in vec2 point; +in float freq; +in vec3 color; +in float alpha; + +out vec4 pervcol; + +void main(void) +{ + float binId = gl_InstanceID; + float deltax = 2.0/nbins; + float deltay = 2.0/ymax; + float xcurr = -1.0 + binId * deltax; + if (point.x==1) { + xcurr += deltax; + } + float ycurr = -1.0; + if (point.y==1) { + ycurr += deltay * freq; + } + pervcol = vec4(color, alpha); + gl_Position = transform * vec4(xcurr, ycurr, 0, 1); +} diff --git a/src/backend/opengl/shaders/image_fs.glsl b/src/backend/opengl/shaders/image_fs.glsl new file mode 100644 index 00000000..2397c8c1 --- /dev/null +++ b/src/backend/opengl/shaders/image_fs.glsl @@ -0,0 +1,39 @@ +#version 330 + +const int size = 259; + +layout(std140) uniform ColorMap +{ + vec4 ch[size]; +}; + +uniform float cmaplen; +uniform sampler2D tex; +uniform int numcomps; +uniform float alpha; + +in vec2 texcoord; +out vec4 fragColor; + +void main() +{ + vec4 tcolor = texture(tex, texcoord); + vec4 clrs = vec4(1, 0, 0, 1); + if(numcomps == 1) + clrs = vec4(tcolor.r, tcolor.r, tcolor.r, alpha); + else if (numcomps==2) + clrs = vec4(tcolor.r, tcolor.g, 1, alpha); + else if (numcomps==3) + clrs = vec4(tcolor.r, tcolor.g, tcolor.b, alpha); + else + clrs = tcolor; + float aval = clrs.a; + + vec4 fidx = (cmaplen-1) * clrs; + ivec4 idx = ivec4(fidx.x, fidx.y, fidx.z, fidx.w); + float r_ch = ch[idx.x].r; + float g_ch = ch[idx.y].g; + float b_ch = ch[idx.z].b; + + fragColor = vec4(r_ch, g_ch , b_ch, aval); +} diff --git a/src/backend/opengl/shaders/image_vs.glsl b/src/backend/opengl/shaders/image_vs.glsl new file mode 100644 index 00000000..0d7dfe56 --- /dev/null +++ b/src/backend/opengl/shaders/image_vs.glsl @@ -0,0 +1,14 @@ +#version 330 + +layout(location = 0) in vec2 pos; +layout(location = 1) in vec2 tex; + +uniform mat4 matrix; + +out vec2 texcoord; + +void main() +{ + texcoord = tex; + gl_Position = matrix * vec4(pos, 0.0, 1.0); +} diff --git a/src/backend/opengl/shaders/marker2d_vs.glsl b/src/backend/opengl/shaders/marker2d_vs.glsl new file mode 100644 index 00000000..ed7b6028 --- /dev/null +++ b/src/backend/opengl/shaders/marker2d_vs.glsl @@ -0,0 +1,19 @@ +#version 330 + +uniform mat4 transform; +uniform bool isPVROn; +uniform float psize; + +in vec2 point; +in vec3 color; +in float alpha; +in float pointsize; + +out vec4 pervcol; + +void main(void) +{ + pervcol = vec4(color, alpha); + gl_Position = transform * vec4(point.xy, 0, 1); + gl_PointSize = isPVROn ? pointsize : psize; +} diff --git a/src/backend/opengl/shaders/marker_fs.glsl b/src/backend/opengl/shaders/marker_fs.glsl new file mode 100644 index 00000000..0e7cc068 --- /dev/null +++ b/src/backend/opengl/shaders/marker_fs.glsl @@ -0,0 +1,54 @@ +#version 330 + +uniform bool isPVCOn; +uniform bool isPVAOn; +uniform int marker_type; +uniform vec4 marker_color; + +in vec4 pervcol; +out vec4 outColor; + +void main(void) +{ + vec2 coords = gl_PointCoord; + float dist = sqrt((coords.x - 0.5)*(coords.x-0.5) + (coords.y-0.5)*(coords.y-0.5)); + bool in_bounds; + + switch(marker_type) { + case 1: + in_bounds = dist<0.1; + break; + case 2: + in_bounds = dist<0.5; + break; + case 3: + in_bounds = ((coords.x > 0.15) || (coords.x < 0.85)) || + ((coords.y > 0.15) || (coords.y < 0.85)); + break; + case 4: + in_bounds = (2*(coords.x - 0.25) - (coords.y + 0.5) < 0) && + (2*(coords.x - 0.25) + (coords.y + 0.5) > 1); + break; + case 5: + in_bounds = abs((coords.x - 0.5) + (coords.y - 0.5) ) < 0.13 || + abs((coords.x - 0.5) - (coords.y - 0.5) ) < 0.13 ; + break; + case 6: + in_bounds = abs((coords.x - 0.5)) < 0.07 || + abs((coords.y - 0.5)) < 0.07; + break; + case 7: + in_bounds = abs((coords.x - 0.5) + (coords.y - 0.5) ) < 0.07 || + abs((coords.x - 0.5) - (coords.y - 0.5) ) < 0.07 || + abs((coords.x - 0.5)) < 0.07 || + abs((coords.y - 0.5)) < 0.07; + break; + default: + in_bounds = true; + } + + if(!in_bounds) + discard; + else + outColor = vec4(isPVCOn ? pervcol.xyz : marker_color.xyz, isPVAOn ? pervcol.w : 1.0); +} diff --git a/src/backend/opengl/shaders/plot3_fs.glsl b/src/backend/opengl/shaders/plot3_fs.glsl new file mode 100644 index 00000000..a7d827d7 --- /dev/null +++ b/src/backend/opengl/shaders/plot3_fs.glsl @@ -0,0 +1,32 @@ +#version 330 + +uniform vec2 minmaxs[3]; +uniform bool isPVCOn; +uniform bool isPVAOn; + +in vec4 pervcol; +in vec4 hpoint; + +out vec4 outColor; + +vec3 hsv2rgb(vec3 c) +{ + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +void main(void) +{ + bool nin_bounds = (hpoint.x > minmaxs[0].y || hpoint.x < minmaxs[0].x || + hpoint.y > minmaxs[1].y || hpoint.y < minmaxs[1].x || hpoint.z < minmaxs[2].x); + + float height = (minmaxs[2].y- hpoint.z)/(minmaxs[2].y-minmaxs[2].x); + + float a = isPVAOn ? pervcol.w : 1.0; + + if(nin_bounds) + discard; + else + outColor = isPVCOn ? vec4(pervcol.xyz, a) : vec4(hsv2rgb(vec3(height, 1, 1)),a); +} diff --git a/src/backend/opengl/shaders/plot3_vs.glsl b/src/backend/opengl/shaders/plot3_vs.glsl new file mode 100644 index 00000000..057860ba --- /dev/null +++ b/src/backend/opengl/shaders/plot3_vs.glsl @@ -0,0 +1,21 @@ +#version 330 + +uniform mat4 transform; +uniform bool isPVROn; +uniform float psize; + +in vec3 point; +in vec3 color; +in float alpha; +in float pointsize; + +out vec4 hpoint; +out vec4 pervcol; + +void main(void) +{ + hpoint = vec4(point.xyz,1); + pervcol = vec4(color, alpha); + gl_Position = transform * hpoint; + gl_PointSize = isPVROn ? pointsize : psize; +} diff --git a/src/backend/opengl/shaders/tick_fs.glsl b/src/backend/opengl/shaders/tick_fs.glsl new file mode 100644 index 00000000..6f13e59e --- /dev/null +++ b/src/backend/opengl/shaders/tick_fs.glsl @@ -0,0 +1,16 @@ +#version 330 + +uniform bool isYAxis; +uniform vec4 tick_color; + +out vec4 outputColor; + +void main(void) +{ + bool y_axis = isYAxis && abs(gl_PointCoord.y-0.5)>0.12; + bool x_axis = !isYAxis && abs(gl_PointCoord.x-0.5)>0.12; + if(y_axis || x_axis) + discard; + else + outputColor = tick_color; +} diff --git a/src/backend/opengl/surface.cpp b/src/backend/opengl/surface.cpp new file mode 100644 index 00000000..7597a25c --- /dev/null +++ b/src/backend/opengl/surface.cpp @@ -0,0 +1,278 @@ +/******************************************************* + * 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 + +#include + +using namespace std; + +void generateGridIndices(unsigned short rows, unsigned short cols, unsigned short *indices) +{ + unsigned short idx = 0; + for(unsigned short r = 0; r < rows-1; ++r){ + for(unsigned short c = 0; c < cols*2; ++c){ + unsigned short i = c + (r * (cols*2)); + + if(c == cols * 2 - 1) { + *indices++ = idx; + }else{ + *indices++ = idx; + if(i%2 == 0){ + idx += cols; + } else { + idx -= (r%2 == 0) ? (cols-1) : (cols+1); + } + } + } + } +} + +namespace opengl +{ + +void surface_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 plot vertices + glEnableVertexAttribArray(mSurfPointIndex); + glBindBuffer(GL_ARRAY_BUFFER, mVBO); + glVertexAttribPointer(mSurfPointIndex, 3, mDataType, GL_FALSE, 0, 0); + glEnableVertexAttribArray(mSurfColorIndex); + glBindBuffer(GL_ARRAY_BUFFER, mCBO); + glVertexAttribPointer(mSurfColorIndex, 3, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(mSurfAlphaIndex); + glBindBuffer(GL_ARRAY_BUFFER, mABO); + glVertexAttribPointer(mSurfAlphaIndex, 1, GL_FLOAT, GL_FALSE, 0, 0); + //attach indices + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIBO); + glBindVertexArray(0); + /* store the vertex array object corresponding to + * the window instance in the map */ + mVAOMap[pWindowId] = vao; + } + + glBindVertexArray(mVAOMap[pWindowId]); +} + +void surface_impl::unbindResources() const +{ + glBindVertexArray(0); +} + +void surface_impl::computeTransformMat(glm::mat4& pOut, const glm::mat4 pInput) +{ + // identity matrix + static const glm::mat4 I(1.0f); + + float range_x = mRange[1] - mRange[0]; + float range_y = mRange[3] - mRange[2]; + float range_z = mRange[5] - mRange[4]; + // set scale to zero if input is constant array + // otherwise compute scale factor by standard equation + float graph_scale_x = std::abs(range_x) < 1.0e-3 ? 0.0f : 2/(range_x); + float graph_scale_y = std::abs(range_y) < 1.0e-3 ? 0.0f : 2/(range_y); + float graph_scale_z = std::abs(range_z) < 1.0e-3 ? 0.0f : 2/(range_z); + + float coor_offset_x = (-mRange[0] * graph_scale_x); + float coor_offset_y = (-mRange[2] * graph_scale_y); + float coor_offset_z = (-mRange[4] * graph_scale_z); + + glm::mat4 rMat = glm::rotate(I, -glm::radians(90.f), glm::vec3(1,0,0)); + glm::mat4 tMat = glm::translate(I, + glm::vec3(-1 + coor_offset_x , -1 + coor_offset_y, -1 + coor_offset_z)); + glm::mat4 sMat = glm::scale(I, + glm::vec3(1.0f * graph_scale_x, -1.0f * graph_scale_y, 1.0f * graph_scale_z)); + + glm::mat4 model = rMat * tMat * sMat; + + pOut = pInput * model; +} + +void surface_impl::renderGraph(const int pWindowId, const glm::mat4& transform) +{ + CheckGL("Begin surface_impl::renderGraph"); + + glUseProgram(mSurfProgram); + + glUniformMatrix4fv(mSurfMatIndex, 1, GL_FALSE, glm::value_ptr(transform)); + glUniform2fv(mSurfRangeIndex, 3, mRange); + glUniform1i(mSurfPVCIndex, mIsPVCOn); + glUniform1i(mSurfPVAIndex, mIsPVAOn); + + bindResources(pWindowId); + glDrawElements(GL_TRIANGLE_STRIP, mIBOSize, GL_UNSIGNED_SHORT, (void*)0 ); + unbindResources(); + glUseProgram(0); + + if(mMarkerType != FG_MARKER_NONE) { + glEnable(GL_PROGRAM_POINT_SIZE); + glUseProgram(mMarkerProgram); + + glUniformMatrix4fv(mMarkerMatIndex, 1, GL_FALSE, glm::value_ptr(transform)); + glUniform1i(mMarkerPVCIndex, mIsPVCOn); + glUniform1i(mMarkerPVAIndex, mIsPVAOn); + glUniform1i(mMarkerTypeIndex, mMarkerType); + glUniform4fv(mMarkerColIndex, 1, mColor); + + bindResources(pWindowId); + glDrawElements(GL_POINTS, mIBOSize, GL_UNSIGNED_SHORT, (void*)0); + unbindResources(); + + glUseProgram(0); + glDisable(GL_PROGRAM_POINT_SIZE); + } + CheckGL("End surface_impl::renderGraph"); +} + + +surface_impl::surface_impl(unsigned pNumXPoints, unsigned pNumYPoints, + fg::dtype pDataType, fg::MarkerType pMarkerType) + : mNumXPoints(pNumXPoints),mNumYPoints(pNumYPoints), mDataType(dtype2gl(pDataType)), + mMarkerType(pMarkerType), mIBO(0), mIBOSize(0), mMarkerProgram(-1), mSurfProgram(-1), + mMarkerMatIndex(-1), mMarkerPointIndex(-1), mMarkerColorIndex(-1), mMarkerAlphaIndex(-1), + mMarkerPVCIndex(-1), mMarkerPVAIndex(-1), mMarkerTypeIndex(-1), mMarkerColIndex(-1), + mSurfMatIndex(-1), mSurfRangeIndex(-1), mSurfPointIndex(-1), mSurfColorIndex(-1), + mSurfAlphaIndex(-1), mSurfPVCIndex(-1), mSurfPVAIndex(-1) +{ + CheckGL("Begin surface_impl::surface_impl"); + mIsPVCOn = false; + mIsPVAOn = false; + setColor(0.9, 0.5, 0.6, 1.0); + mLegend = std::string(""); + + mMarkerProgram = initShaders(glsl::plot3_vs.c_str(), glsl::marker_fs.c_str()); + mMarkerMatIndex = glGetUniformLocation(mMarkerProgram, "transform"); + mMarkerPVCIndex = glGetUniformLocation(mMarkerProgram, "isPVCOn"); + mMarkerPVAIndex = glGetUniformLocation(mMarkerProgram, "isPVAOn"); + mMarkerTypeIndex = glGetUniformLocation(mMarkerProgram, "marker_type"); + mMarkerColIndex = glGetUniformLocation(mMarkerProgram, "marker_color"); + mMarkerPointIndex= glGetAttribLocation (mMarkerProgram, "point"); + mMarkerColorIndex= glGetAttribLocation (mMarkerProgram, "color"); + mMarkerAlphaIndex= glGetAttribLocation (mMarkerProgram, "alpha"); + + mSurfProgram = initShaders(glsl::plot3_vs.c_str(), glsl::plot3_fs.c_str()); + mSurfMatIndex = glGetUniformLocation(mSurfProgram, "transform"); + mSurfRangeIndex = glGetUniformLocation(mSurfProgram, "minmaxs"); + mSurfPVCIndex = glGetUniformLocation(mSurfProgram, "isPVCOn"); + mSurfPVAIndex = glGetUniformLocation(mSurfProgram, "isPVAOn"); + mSurfPointIndex = glGetAttribLocation (mSurfProgram, "point"); + mSurfColorIndex = glGetAttribLocation (mSurfProgram, "color"); + mSurfAlphaIndex = glGetAttribLocation (mSurfProgram, "alpha"); + + unsigned totalPoints = mNumXPoints * mNumYPoints; + + mVBOSize = 3*totalPoints; + mCBOSize = 3*totalPoints; + mABOSize = totalPoints; +#define SURF_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(mDataType) { + case GL_FLOAT : SURF_CREATE_BUFFERS(float) ; break; + case GL_INT : SURF_CREATE_BUFFERS(int) ; break; + case GL_UNSIGNED_INT : SURF_CREATE_BUFFERS(uint) ; break; + case GL_SHORT : SURF_CREATE_BUFFERS(short) ; break; + case GL_UNSIGNED_SHORT : SURF_CREATE_BUFFERS(ushort); break; + case GL_UNSIGNED_BYTE : SURF_CREATE_BUFFERS(float) ; break; + default: fg::TypeError("surface_impl::surface_impl", __LINE__, 1, pDataType); + } + +#undef SURF_CREATE_BUFFERS + + mIBOSize = (2 * mNumYPoints) * (mNumXPoints - 1); + std::vector indices(mIBOSize); + generateGridIndices(mNumXPoints, mNumYPoints, indices.data()); + mIBO = createBuffer(GL_ELEMENT_ARRAY_BUFFER, mIBOSize, indices.data(), GL_STATIC_DRAW); + + CheckGL("End surface_impl::surface_impl"); +} + +surface_impl::~surface_impl() +{ + CheckGL("Begin Plot::~Plot"); + for (auto it = mVAOMap.begin(); it!=mVAOMap.end(); ++it) { + GLuint vao = it->second; + glDeleteVertexArrays(1, &vao); + } + glDeleteBuffers(1, &mVBO); + glDeleteBuffers(1, &mCBO); + glDeleteBuffers(1, &mABO); + glDeleteBuffers(1, &mIBO); + glDeleteProgram(mMarkerProgram); + glDeleteProgram(mSurfProgram); + CheckGL("End Plot::~Plot"); +} + +void surface_impl::render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4 &pModel) +{ + CheckGL("Begin surface_impl::render"); + // FIXME: even when per vertex alpha is enabled + // primitives of transparent object should be sorted + // from the furthest to closest primitive + if (mIsPVAOn) { + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + glm::mat4 mvp(1.0); + computeTransformMat(mvp, pModel); + renderGraph(pWindowId, mvp); + + if (mIsPVAOn) { + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + } + CheckGL("End surface_impl::render"); +} + +void scatter3_impl::renderGraph(const int pWindowId, const glm::mat4& transform) +{ + if(mMarkerType != FG_MARKER_NONE) { + glEnable(GL_PROGRAM_POINT_SIZE); + glUseProgram(mMarkerProgram); + + glUniformMatrix4fv(mMarkerMatIndex, 1, GL_FALSE, glm::value_ptr(transform)); + glUniform1i(mMarkerPVCIndex, mIsPVCOn); + glUniform1i(mMarkerPVAIndex, mIsPVAOn); + glUniform1i(mMarkerTypeIndex, mMarkerType); + glUniform4fv(mMarkerColIndex, 1, mColor); + + bindResources(pWindowId); + glDrawElements(GL_POINTS, mIBOSize, GL_UNSIGNED_SHORT, (void*)0); + unbindResources(); + + glUseProgram(0); + glDisable(GL_PROGRAM_POINT_SIZE); + } +} + +} diff --git a/src/backend/opengl/surface.hpp b/src/backend/opengl/surface.hpp new file mode 100644 index 00000000..fde99bb0 --- /dev/null +++ b/src/backend/opengl/surface.hpp @@ -0,0 +1,91 @@ +/******************************************************* +* 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 + +namespace opengl +{ + +class surface_impl : public AbstractRenderable { + protected: + /* plot points characteristics */ + GLuint mNumXPoints; + GLuint mNumYPoints; + GLenum mDataType; + bool mIsPVCOn; + bool mIsPVAOn; + fg::MarkerType mMarkerType; + /* OpenGL Objects */ + GLuint mIBO; + size_t mIBOSize; + GLuint mMarkerProgram; + GLuint mSurfProgram; + /* shared variable index locations */ + GLuint mMarkerMatIndex; + GLuint mMarkerPointIndex; + GLuint mMarkerColorIndex; + GLuint mMarkerAlphaIndex; + GLuint mMarkerPVCIndex; + GLuint mMarkerPVAIndex; + GLuint mMarkerTypeIndex; + GLuint mMarkerColIndex; + + GLuint mSurfMatIndex; + GLuint mSurfRangeIndex; + GLuint mSurfPointIndex; + GLuint mSurfColorIndex; + GLuint mSurfAlphaIndex; + GLuint mSurfPVCIndex; + GLuint mSurfPVAIndex; + + std::map mVAOMap; + + /* bind and unbind helper functions + * for rendering resources */ + void bindResources(const int pWindowId); + void unbindResources() const; + void computeTransformMat(glm::mat4& pOut, const glm::mat4 pInput); + virtual void renderGraph(const int pWindowId, const glm::mat4& transform); + + public: + surface_impl(const uint pNumXpoints, const uint pNumYpoints, + const fg::dtype pDataType, const fg::MarkerType pMarkerType); + ~surface_impl(); + + void render(const int pWindowId, + const int pX, const int pY, const int pVPW, const int pVPH, + const glm::mat4 &pTransform); + + inline void usePerVertexColors(const bool pFlag=true) { + mIsPVCOn = pFlag; + } + + inline void usePerVertexAlphas(const bool pFlag=true) { + mIsPVAOn = pFlag; + } +}; + +class scatter3_impl : public surface_impl { + private: + void renderGraph(const int pWindowId, const glm::mat4& transform); + + public: + scatter3_impl(const uint pNumXPoints, const uint pNumYPoints, + const fg::dtype pDataType, const fg::MarkerType pMarkerType=FG_MARKER_NONE) + : surface_impl(pNumXPoints, pNumYPoints, pDataType, pMarkerType) {} +}; + +} diff --git a/src/window.cpp b/src/backend/opengl/window.cpp similarity index 51% rename from src/window.cpp rename to src/backend/opengl/window.cpp index 46000958..68857555 100644 --- a/src/window.cpp +++ b/src/backend/opengl/window.cpp @@ -11,11 +11,15 @@ // https://gist.github.com/SnopyDogy/a9a22497a893ec86aa3e #include -#include +#include #include + +#include #include #include +#include + using namespace fg; static GLEWContext* current = nullptr; @@ -35,7 +39,50 @@ int getNextUniqueId() return wndUnqIdTracker++; } -namespace internal +class FI_Manager +{ + public: + static bool initialized; + FI_Manager() + { +#ifdef FREEIMAGE_LIB + FreeImage_Initialise(); +#endif + initialized = true; + } + + ~FI_Manager() + { +#ifdef FREEIMAGE_LIB + FreeImage_DeInitialise(); +#endif + } +}; + +bool FI_Manager::initialized = false; + +static void FI_Init() +{ + static FI_Manager manager = FI_Manager(); +} + +class FI_BitmapResource +{ +public: + explicit FI_BitmapResource(FIBITMAP * p) : + pBitmap(p) + { + } + + ~FI_BitmapResource() + { + FreeImage_Unload(pBitmap); + } +private: + FIBITMAP * pBitmap; +}; + +namespace opengl { void MakeContextCurrent(const window_impl* pWindow) @@ -50,8 +97,7 @@ void MakeContextCurrent(const window_impl* pWindow) window_impl::window_impl(int pWidth, int pHeight, const char* pTitle, std::weak_ptr pWindow, const bool invisible) - : mID(getNextUniqueId()), mWidth(pWidth), mHeight(pHeight), - mRows(0), mCols(0) + : mID(getNextUniqueId()) { if (auto observe = pWindow.lock()) { mWindow = new wtk::Widget(pWidth, pHeight, pTitle, observe->get(), invisible); @@ -69,7 +115,7 @@ window_impl::window_impl(int pWidth, int pHeight, const char* pTitle, if (mGLEWContext == NULL) { std::cerr<<"Error: Could not create GLEW Context!\n"; throw fg::Error("window_impl constructor", __LINE__, - "GLEW context creation failed", fg::FG_ERR_GL_ERROR); + "GLEW context creation failed", FG_ERR_GL_ERROR); } } @@ -82,7 +128,7 @@ window_impl::window_impl(int pWidth, int pHeight, const char* pTitle, if (err != GLEW_OK) { char buffer[128]; sprintf(buffer, "GLEW init failed: Error: %s\n", glewGetErrorString(err)); - throw fg::Error("window_impl constructor", __LINE__, buffer, fg::FG_ERR_GL_ERROR); + throw fg::Error("window_impl constructor", __LINE__, buffer, FG_ERR_GL_ERROR); } err = glGetError(); if (err!=GL_NO_ERROR && err!=GL_INVALID_ENUM) { @@ -92,7 +138,7 @@ window_impl::window_impl(int pWidth, int pHeight, const char* pTitle, */ ForceCheckGL("GLEW initilization failed"); throw fg::Error("window_impl constructor", __LINE__, - "GLEW initilization failed", fg::FG_ERR_GL_ERROR); + "GLEW initilization failed", FG_ERR_GL_ERROR); } mCxt = mWindow->getGLContextHandle(); @@ -106,10 +152,27 @@ window_impl::window_impl(int pWidth, int pHeight, const char* pTitle, mCMap = std::make_shared(); } + + mWindow->resizePixelBuffers(); + /* set the colormap to default */ mColorMapUBO = mCMap->defaultMap(); mUBOSize = mCMap->defaultLen(); glEnable(GL_MULTISAMPLE); + + std::vector& mats = mWindow->mMVPs; + mats.resize(mWindow->mRows*mWindow->mCols); + std::fill(mats.begin(), mats.end(), glm::mat4(1)); + + /* setup default window font */ + mFont = std::make_shared(); +#ifdef OS_WIN + mFont->loadSystemFont("Calibri"); +#else + mFont->loadSystemFont("Vera"); +#endif + glEnable(GL_DEPTH_TEST); + CheckGL("End Window::Window"); } @@ -141,37 +204,42 @@ void window_impl::setSize(unsigned pW, unsigned pH) void window_impl::setColorMap(fg::ColorMap cmap) { switch(cmap) { - case FG_DEFAULT_MAP: + case FG_COLOR_MAP_DEFAULT: mColorMapUBO = mCMap->defaultMap(); mUBOSize = mCMap->defaultLen(); break; - case FG_SPECTRUM_MAP: + case FG_COLOR_MAP_SPECTRUM: mColorMapUBO = mCMap->spectrum(); mUBOSize = mCMap->spectrumLen(); break; - case FG_COLORS_MAP: + case FG_COLOR_MAP_COLORS: mColorMapUBO = mCMap->colors(); mUBOSize = mCMap->colorsLen(); break; - case FG_RED_MAP: + case FG_COLOR_MAP_RED: mColorMapUBO = mCMap->red(); mUBOSize = mCMap->redLen(); break; - case FG_MOOD_MAP: + case FG_COLOR_MAP_MOOD: mColorMapUBO = mCMap->mood(); mUBOSize = mCMap->moodLen(); break; - case FG_HEAT_MAP: + case FG_COLOR_MAP_HEAT: mColorMapUBO = mCMap->heat(); mUBOSize = mCMap->heatLen(); break; - case FG_BLUE_MAP: + case FG_COLOR_MAP_BLUE: mColorMapUBO = mCMap->blue(); mUBOSize = mCMap->blueLen(); break; } } +int window_impl::getID() const +{ + return mID; +} + long long window_impl::context() const { return mCxt; @@ -184,12 +252,12 @@ long long window_impl::display() const int window_impl::width() const { - return mWidth; + return mWindow->mWidth; } int window_impl::height() const { - return mHeight; + return mWindow->mHeight; } GLEWContext* window_impl::glewContext() const @@ -224,40 +292,41 @@ bool window_impl::close() void window_impl::draw(const std::shared_ptr& pRenderable) { - CheckGL("Begin draw"); + CheckGL("Begin window_impl::draw"); MakeContextCurrent(this); mWindow->resetCloseFlag(); + glViewport(0, 0, mWindow->mWidth, mWindow->mHeight); - int wind_width, wind_height; - mWindow->getFrameBufferSize(&wind_width, &wind_height); - glViewport(0, 0, wind_width, wind_height); - + const glm::mat4& mvp = mWindow->mMVPs[0]; // clear color and depth buffers + glClearColor(WHITE[0], WHITE[1], WHITE[2], WHITE[3]); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glClearColor(GRAY[0], GRAY[1], GRAY[2], GRAY[3]); + // set colormap call is equivalent to noop for non-image renderables pRenderable->setColorMapUBOParams(mColorMapUBO, mUBOSize); - pRenderable->render(mID, 0, 0, wind_width, wind_height); + pRenderable->render(mID, 0, 0, mWindow->mWidth, mWindow->mHeight, mvp); mWindow->swapBuffers(); mWindow->pollEvents(); - CheckGL("End draw"); + CheckGL("End window_impl::draw"); } void window_impl::grid(int pRows, int pCols) { - mRows= pRows; - mCols= pCols; - - int wind_width, wind_height; - mWindow->getFrameBufferSize(&wind_width, &wind_height); - glViewport(0, 0, wind_width, wind_height); + glViewport(0, 0, mWindow->mWidth, mWindow->mHeight); + glClearColor(WHITE[0], WHITE[1], WHITE[2], WHITE[3]); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - mCellWidth = wind_width / mCols; - mCellHeight = wind_height / mRows; -} + mWindow->mRows = pRows; + mWindow->mCols = pCols; + mWindow->mCellWidth = mWindow->mWidth / mWindow->mCols; + mWindow->mCellHeight = mWindow->mHeight / mWindow->mRows; + // resize mvp array for views to appropriate size + std::vector& mats = mWindow->mMVPs; + mats.resize(mWindow->mRows*mWindow->mCols); + std::fill(mats.begin(), mats.end(), glm::mat4(1)); +} void window_impl::draw(int pColId, int pRowId, const std::shared_ptr& pRenderable, @@ -267,44 +336,41 @@ void window_impl::draw(int pColId, int pRowId, MakeContextCurrent(this); mWindow->resetCloseFlag(); - int wind_width, wind_height; - mWindow->getFrameBufferSize(&wind_width, &wind_height); - mCellWidth = wind_width / mCols; - mCellHeight = wind_height / mRows; - float pos[2] = {0.0, 0.0}; int c = pColId; int r = pRowId; - int x_off = c * mCellWidth; - int y_off = (mRows - 1 - r) * mCellHeight; + int x_off = c * mWindow->mCellWidth; + int y_off = (mWindow->mRows - 1 - r) * mWindow->mCellHeight; + const glm::mat4& mvp = mWindow->mMVPs[r+c*mWindow->mRows]; /* following margins are tested out for various * aspect ratios and are working fine. DO NOT CHANGE. * */ - int top_margin = int(0.06f*mCellHeight); - int bot_margin = int(0.02f*mCellHeight); - int lef_margin = int(0.02f*mCellWidth); - int rig_margin = int(0.02f*mCellWidth); + int top_margin = int(0.06f*mWindow->mCellHeight); + int bot_margin = int(0.02f*mWindow->mCellHeight); + int lef_margin = int(0.02f*mWindow->mCellWidth); + int rig_margin = int(0.02f*mWindow->mCellWidth); // set viewport to render sub image - glViewport(x_off + lef_margin, y_off + bot_margin, mCellWidth - 2 * rig_margin, mCellHeight - 2 * top_margin); - glScissor(x_off + lef_margin, y_off + bot_margin, mCellWidth - 2 * rig_margin, mCellHeight - 2 * top_margin); + glViewport(x_off + lef_margin, y_off + bot_margin, + mWindow->mCellWidth - 2 * rig_margin, mWindow->mCellHeight - 2 * top_margin); + glScissor(x_off + lef_margin, y_off + bot_margin, + mWindow->mCellWidth - 2 * rig_margin, mWindow->mCellHeight - 2 * top_margin); glEnable(GL_SCISSOR_TEST); - glClearColor(GRAY[0], GRAY[1], GRAY[2], GRAY[3]); + // set colormap call is equivalent to noop for non-image renderables pRenderable->setColorMapUBOParams(mColorMapUBO, mUBOSize); - pRenderable->render(mID, x_off, y_off, mCellWidth, mCellHeight); + pRenderable->render(mID, x_off, y_off, mWindow->mCellWidth, mWindow->mCellHeight, mvp); glDisable(GL_SCISSOR_TEST); - glViewport(x_off, y_off, mCellWidth, mCellHeight); + glViewport(x_off, y_off, mWindow->mCellWidth, mWindow->mCellHeight); if (pTitle!=NULL) { - mFont->setOthro2D(mCellWidth, mCellHeight); - pos[0] = mCellWidth / 3.0f; - pos[1] = mCellHeight*0.92f; - mFont->render(mID, pos, RED, pTitle, 16); + mFont->setOthro2D(mWindow->mCellWidth, mWindow->mCellHeight); + pos[0] = mWindow->mCellWidth / 3.0f; + pos[1] = mWindow->mCellHeight*0.92f; + mFont->render(mID, pos, AF_BLUE, pTitle, 16); } - CheckGL("End draw(column, row)"); } @@ -315,159 +381,87 @@ void window_impl::swapBuffers() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -} - -namespace fg +void window_impl::saveFrameBuffer(const char* pFullPath) { - -Window::Window(int pWidth, int pHeight, const char* pTitle, const Window* pWindow, const bool invisible) -{ - if (pWindow == nullptr) { - value = new internal::_Window(pWidth, pHeight, pTitle, nullptr, invisible); - } else { - value = new internal::_Window(pWidth, pHeight, pTitle, pWindow->get(), invisible); + if (!pFullPath) { + throw fg::ArgumentError("window_impl::saveFrameBuffer", __LINE__, 1, + "Empty path string"); } -} - -Window::~Window() -{ - delete value; -} - -Window::Window(const Window& other) -{ - value = new internal::_Window(*other.get()); -} - -void Window::setFont(Font* pFont) -{ - value->setFont(pFont->get()); -} - -void Window::setTitle(const char* pTitle) -{ - value->setTitle(pTitle); -} - -void Window::setPos(int pX, int pY) -{ - value->setPos(pX, pY); -} - -void Window::setSize(unsigned pW, unsigned pH) -{ - value->setSize(pW, pH); -} - -void Window::setColorMap(ColorMap cmap) -{ - value->setColorMap(cmap); -} -long long Window::context() const -{ - return value->context(); -} - -long long Window::display() const -{ - return value->display(); -} + FI_Init(); -int Window::width() const -{ - return value->width(); -} + auto FIErrorHandler = [](FREE_IMAGE_FORMAT pOutputFIFormat, const char* pMessage) { + printf("FreeImage Error Handler: %s\n", pMessage); + }; -int Window::height() const -{ - return value->height(); -} - -internal::_Window* Window::get() const -{ - return value; -} - -void Window::hide() -{ - value->hide(); -} + FreeImage_SetOutputMessage(FIErrorHandler); -void Window::show() -{ - value->show(); -} - -bool Window::close() -{ - return value->close(); -} - -void Window::makeCurrent() -{ - value->makeCurrent(); -} - -void Window::draw(const Image& pImage, const bool pKeepAspectRatio) -{ - value->draw(pImage.get(), pKeepAspectRatio); -} - -void Window::draw(const Plot& pPlot) -{ - value->draw(pPlot.get()); -} - -void Window::draw(const Plot3& pPlot3) -{ - value->draw(pPlot3.get()); -} + FREE_IMAGE_FORMAT format = FreeImage_GetFileType(pFullPath); + if (format == FIF_UNKNOWN) { + format = FreeImage_GetFIFFromFilename(pFullPath); + } + if (format == FIF_UNKNOWN) { + throw fg::Error("window_impl::saveFrameBuffer", __LINE__, + "Freeimage: unrecognized image format", FG_ERR_FREEIMAGE_UNKNOWN_FORMAT); + } -void Window::draw(const Surface& pSurface) -{ - value->draw(pSurface.get()); -} + if (!(format==FIF_BMP || format==FIF_PNG)) { + throw fg::ArgumentError("window_impl::saveFrameBuffer", __LINE__, 1, + "Supports only bmp and png as of now"); + } -void Window::draw(const Histogram& pHist) -{ - value->draw(pHist.get()); -} + uint w = mWindow->mWidth; + uint h = mWindow->mHeight; + uint c = 4; + uint d = c * 8; -void Window::grid(int pRows, int pCols) -{ - value->grid(pRows, pCols); -} + FIBITMAP* bmp = FreeImage_Allocate(w, h, d); + if (!bmp) { + throw fg::Error("window_impl::saveFrameBuffer", __LINE__, + "Freeimage: allocation failed", FG_ERR_FREEIMAGE_BAD_ALLOC); + } -void Window::draw(int pColId, int pRowId, const Image& pImage, const char* pTitle, const bool pKeepAspectRatio) -{ - value->draw(pColId, pRowId, pImage.get(), pTitle, pKeepAspectRatio); -} + FI_BitmapResource bmpUnloader(bmp); -void Window::draw(int pColId, int pRowId, const Plot& pPlot, const char* pTitle) -{ - value->draw(pColId, pRowId, pPlot.get(), pTitle); -} + uint pitch = FreeImage_GetPitch(bmp); + uchar* dst = FreeImage_GetBits(bmp); -void Window::draw(int pColId, int pRowId, const Plot3& pPlot3, const char* pTitle) -{ - value->draw(pColId, pRowId, pPlot3.get(), pTitle); -} + /* as glReadPixels was called using PBO earlier, hopefully + * it was async call(which it should be unless vendor driver + * is doing something fishy) and the transfer is over by now + * */ + glBindBuffer(GL_PIXEL_PACK_BUFFER, mWindow->mFramePBO); + + uchar* src = (uchar*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); + + if (src) { + // copy data from mapped memory location + uint w = mWindow->mWidth; + uint h = mWindow->mHeight; + uint i = 0; + + for (uint y = 0; y < h; ++y) { + for (uint x = 0; x < w; ++x) { + *(dst + x * c + FI_RGBA_RED ) = (uchar) src[4*i+0]; // r + *(dst + x * c + FI_RGBA_GREEN) = (uchar) src[4*i+1]; // g + *(dst + x * c + FI_RGBA_BLUE ) = (uchar) src[4*i+2]; // b + *(dst + x * c + FI_RGBA_ALPHA) = (uchar) src[4*i+3]; // a + ++i; + } + dst += pitch; + } -void Window::draw(int pColId, int pRowId, const Surface& pSurface, const char* pTitle) -{ - value->draw(pColId, pRowId, pSurface.get(), pTitle); -} + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + } + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); -void Window::draw(int pColId, int pRowId, const Histogram& pHist, const char* pTitle) -{ - value->draw(pColId, pRowId, pHist.get(), pTitle); -} + int flags = 0; + if (format == FIF_JPEG) + flags = flags | JPEG_QUALITYSUPERB; -void Window::swapBuffers() -{ - value->swapBuffers(); + if (!(FreeImage_Save(format,bmp, pFullPath, flags) == TRUE)) { + } } } diff --git a/src/backend/opengl/window.hpp b/src/backend/opengl/window.hpp new file mode 100644 index 00000000..a77843f2 --- /dev/null +++ b/src/backend/opengl/window.hpp @@ -0,0 +1,84 @@ +/******************************************************* +* 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 + +#if defined(USE_GLFW) +#include +#elif defined(USE_SDL) +#include +#endif + +#include +#include +#include +#include + +#include + +namespace opengl +{ + +class window_impl { + private: + long long mCxt; + long long mDsp; + int mID; + wtk::Widget* mWindow; + GLEWContext* mGLEWContext; + + std::shared_ptr mFont; + std::shared_ptr mCMap; + + GLuint mColorMapUBO; + GLuint mUBOSize; + + public: + window_impl(int pWidth, int pHeight, const char* pTitle, + std::weak_ptr pWindow, const bool invisible=false); + + ~window_impl(); + + void setFont(const std::shared_ptr& pFont); + void setTitle(const char* pTitle); + void setPos(int pX, int pY); + void setSize(unsigned pWidth, unsigned pHeight); + void setColorMap(fg::ColorMap cmap); + + int getID() const; + long long context() const; + long long display() const; + int width() const; + int height() const; + GLEWContext* glewContext() const; + const wtk::Widget* get() const; + const std::shared_ptr& colorMapPtr() const; + + void hide(); + void show(); + bool close(); + + void draw(const std::shared_ptr& pRenderable); + + void grid(int pRows, int pCols); + + void draw(int pColId, int pRowId, + const std::shared_ptr& pRenderable, + const char* pTitle); + + void swapBuffers(); + + void saveFrameBuffer(const char* pFullPath); +}; + +void MakeContextCurrent(const window_impl* pWindow); + +} diff --git a/src/backend/util.cpp b/src/backend/util.cpp new file mode 100644 index 00000000..7c4cd2e6 --- /dev/null +++ b/src/backend/util.cpp @@ -0,0 +1,37 @@ +/******************************************************* + * Copyright (c) 2016, 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 + ********************************************************/ + +/// This file contains platform independent utility functions +#include +#include + +#if defined(OS_WIN) +#include +#endif + +using std::string; + +string getEnvVar(const std::string &key) +{ +#if defined(OS_WIN) + DWORD bufSize = 32767; // limit according to GetEnvironment Variable documentation + string retVal; + retVal.resize(bufSize); + bufSize = GetEnvironmentVariable(key.c_str(), &retVal[0], bufSize); + if (!bufSize) { + return string(""); + } else { + retVal.resize(bufSize); + return retVal; + } +#else + char * str = getenv(key.c_str()); + return str==NULL ? string("") : string(str); +#endif +} diff --git a/src/backend/util.hpp b/src/backend/util.hpp new file mode 100644 index 00000000..e1cd85a6 --- /dev/null +++ b/src/backend/util.hpp @@ -0,0 +1,16 @@ +/******************************************************* + * Copyright (c) 2016, 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 + ********************************************************/ + +/// This file contains platform independent utility functions + +#include + +#pragma once + +std::string getEnvVar(const std::string &key); diff --git a/src/chart.hpp b/src/chart.hpp deleted file mode 100644 index f29e45f5..00000000 --- a/src/chart.hpp +++ /dev/null @@ -1,159 +0,0 @@ -/******************************************************* -* 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 - -namespace internal -{ - -class AbstractChart : public AbstractRenderable { - protected: - /* internal class attributes for - * drawing ticks on axes for plots*/ - std::vector mTickTextX; - std::vector mTickTextY; - std::vector mTickTextZ; - std::vector mXText; - std::vector mYText; - std::vector mZText; - int mTickCount; /* should be an odd number always */ - int mTickSize; - int mLeftMargin; - int mRightMargin; - int mTopMargin; - int mBottomMargin; - /* chart axes ranges and titles */ - float mXMax; - float mXMin; - float mYMax; - float mYMin; - float mZMax; - float mZMin; - std::string mXTitle; - std::string mYTitle; - std::string mZTitle; - /* OpenGL Objects */ - GLuint mDecorVBO; - GLuint mBorderProgram; - GLuint mSpriteProgram; - /* shader uniform variable locations */ - GLint mBorderAttribPointIndex; - GLint mBorderUniformColorIndex; - GLint mBorderUniformMatIndex; - GLint mSpriteUniformMatIndex; - GLint mSpriteUniformTickcolorIndex; - GLint mSpriteUniformTickaxisIndex; - /* VAO map to store a vertex array object - * for each valid window context */ - std::map mVAOMap; - - /* rendering helper functions */ - void renderTickLabels(int pWindowId, unsigned w, unsigned h, - std::vector &texts, - glm::mat4 &transformation, int coor_offset, - bool useZoffset=true); - - /* virtual functions that has to be implemented by - * dervied class: Chart2D, Chart3D */ - virtual void bindResources(int pWindowId) = 0; - virtual void unbindResources() const = 0; - virtual void pushTicktextCoords(float x, float y, float z=0.0) = 0; - virtual void generateChartData() = 0; - virtual void generateTickLabels() = 0; - - public: - AbstractChart(int pLeftMargin, int pRightMargin, int pTopMargin, int pBottomMargin); - virtual ~AbstractChart(); - - void setAxesLimits(float pXmax, float pXmin, float pYmax, float pYmin, - float pZmax=1, float pZmin=-1); - void setAxesTitles(const char* pXTitle, const char* pYTitle, const char* pZTitle="Z-Axis"); - - float xmax() const; - float xmin() const; - float ymax() const; - float ymin() const; - float zmax() const; - float zmin() const; - - virtual GLuint vbo() const = 0; - virtual size_t size() const = 0; - virtual void renderChart(int pWindowId, int pX, int pY, - int pViewPortWidth, int pViewPortHeight) = 0; - /* Below is pure virtual function of AbstractRenderable */ - virtual void render(int pWindowId, int pX, int pY, - int pViewPortWidth, int pViewPortHeight) = 0; -}; - -class Chart2D : public AbstractChart { - private: - /* rendering helper functions that are derived - * from AbstractRenderable base class - * */ - void bindResources(int pWindowId); - void unbindResources() const; - void pushTicktextCoords(float x, float y, float z=0.0); - void generateChartData(); - void generateTickLabels(); - - public: - Chart2D() - :AbstractChart(68, 8, 8, 32) { - generateChartData(); - } - virtual ~Chart2D() {} - - void renderChart(int pWindowId, int pX, int pY, - int pViewPortWidth, int pViewPortHeight); - - /* Below pure virtual functions have to - * be implemented by Concrete classes - * which have Chart2D as base class - * */ - virtual GLuint vbo() const = 0; - virtual size_t size() const = 0; - virtual void render(int pWindowId, int pX, int pY, - int pViewPortWidth, int pViewPortHeight) = 0; -}; - -class Chart3D : public AbstractChart { - private: - /* rendering helper functions that are derived - * from AbstractRenderable base class - * */ - void bindResources(int pWindowId); - void unbindResources() const; - void pushTicktextCoords(float x, float y, float z=0.0); - void generateChartData(); - void generateTickLabels(); - - public: - Chart3D() - :AbstractChart(32, 32, 32, 32) { - generateChartData(); - } - virtual ~Chart3D() {} - - void renderChart(int pWindowId, int pX, int pY, - int pViewPortWidth, int pViewPortHeight); - - virtual GLuint vbo() const = 0; - virtual size_t size() const = 0; - virtual void render(int pWindowId, int pX, int pY, - int pViewPortWidth, int pViewPortHeight) = 0; -}; - -} diff --git a/src/common.cpp b/src/common.cpp deleted file mode 100644 index e54bf8cf..00000000 --- a/src/common.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/******************************************************* - * 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 - -using namespace fg; -using namespace std; - -typedef struct { - GLuint vertex; - GLuint fragment; -} shaders_t; - -GLenum gl_dtype(fg::dtype val) -{ - switch(val) { - case s8: return GL_BYTE; - case u8: return GL_UNSIGNED_BYTE; - case s32: return GL_INT; - case u32: return GL_UNSIGNED_INT; - case s16: return GL_SHORT; - case u16: return GL_UNSIGNED_SHORT; - default: return GL_FLOAT; - } -} - -GLenum gl_ctype(ChannelFormat mode) -{ - switch(mode) { - case FG_GRAYSCALE: return GL_RED; - case FG_RG : return GL_RG; - case FG_RGB : return GL_RGB; - case FG_BGR : return GL_BGR; - case FG_BGRA: return GL_BGRA; - default : return GL_RGBA; - } -} - -GLenum gl_ictype(ChannelFormat mode) -{ - if (mode==FG_GRAYSCALE) - return GL_RED; - else if (mode==FG_RG) - return GL_RG; - else if (mode==FG_RGB || mode==FG_BGR) - return GL_RGB; - else - return GL_RGBA; -} - -char* loadFile(const char * fname, GLint &fSize) -{ - std::ifstream file(fname,std::ios::in|std::ios::binary|std::ios::ate); - if (file.is_open()) - { - unsigned int size = (unsigned int)file.tellg(); - fSize = size; - char *memblock = new char [size]; - file.seekg (0, std::ios::beg); - file.read (memblock, size); - file.close(); - std::cerr << "file " << fname << " loaded" << std::endl; - return memblock; - } - - char buffer[64]; - sprintf(buffer, "Unable to open file %s", fname); - - throw fg::Error("loadFile", __LINE__, buffer, FG_ERR_GL_ERROR); -} - -void printShaderInfoLog(GLint shader) -{ - int infoLogLen = 0; - int charsWritten = 0; - GLchar *infoLog; - - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen); - - if (infoLogLen > 1) - { - infoLog = new GLchar[infoLogLen]; - glGetShaderInfoLog(shader,infoLogLen, &charsWritten, infoLog); - std::cerr << "InfoLog:" << std::endl << infoLog << std::endl; - delete [] infoLog; - throw fg::Error("printShaderInfoLog", __LINE__, "OpenGL Shader compilation failed", FG_ERR_GL_ERROR); - } -} - -void printLinkInfoLog(GLint prog) -{ - int infoLogLen = 0; - int charsWritten = 0; - GLchar *infoLog; - - glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &infoLogLen); - - if (infoLogLen > 1) - { - infoLog = new GLchar[infoLogLen]; - // error check for fail to allocate memory omitted - glGetProgramInfoLog(prog,infoLogLen, &charsWritten, infoLog); - std::cerr << "InfoLog:" << std::endl << infoLog << std::endl; - delete [] infoLog; - throw fg::Error("printLinkInfoLog", __LINE__, "OpenGL Shader linking failed", FG_ERR_GL_ERROR); - } -} - -void attachAndLinkProgram(GLuint program, shaders_t shaders) -{ - glAttachShader(program, shaders.vertex); - glAttachShader(program, shaders.fragment); - - glLinkProgram(program); - GLint linked; - glGetProgramiv(program,GL_LINK_STATUS, &linked); - if (!linked) - { - std::cerr << "Program did not link." << std::endl; - throw fg::Error("attachAndLinkProgram", __LINE__, "OpenGL program linking failed", FG_ERR_GL_ERROR); - } - printLinkInfoLog(program); -} - -shaders_t loadShaders(const char * vert_code, const char * frag_code) -{ - GLuint f, v; - - v = glCreateShader(GL_VERTEX_SHADER); - f = glCreateShader(GL_FRAGMENT_SHADER); - - // load shaders & get length of each - glShaderSource(v, 1, &vert_code, NULL); - glShaderSource(f, 1, &frag_code, NULL); - - GLint compiled; - - glCompileShader(v); - glGetShaderiv(v, GL_COMPILE_STATUS, &compiled); - if (!compiled) - { - std::cerr << "Vertex shader not compiled." << std::endl; - printShaderInfoLog(v); - } - - glCompileShader(f); - glGetShaderiv(f, GL_COMPILE_STATUS, &compiled); - if (!compiled) - { - std::cerr << "Fragment shader not compiled." << std::endl; - printShaderInfoLog(f); - } - - shaders_t out; out.vertex = v; out.fragment = f; - - return out; -} - -GLuint initShaders(const char* vshader_code, const char* fshader_code) -{ - shaders_t shaders = loadShaders(vshader_code, fshader_code); - GLuint shader_program = glCreateProgram(); - attachAndLinkProgram(shader_program, shaders); - return shader_program; -} - -int next_p2(int value) -{ - return int(std::pow(2, (std::ceil(std::log2(value))))); -} - -float clampTo01(float a) -{ - return (a < 0.0f ? 0.0f : (a>1.0f ? 1.0f : a)); -} - -#ifdef OS_WIN -#include -#include - -void getFontFilePaths(std::vector& pFiles, std::string pDir, std::string pExt) -{ - WIN32_FIND_DATA ffd; - LARGE_INTEGER filesize; - TCHAR szDir[MAX_PATH]; - size_t length_of_arg; - DWORD dwError=0; - HANDLE hFind = INVALID_HANDLE_VALUE; - - // Check that the input path plus 3 is not longer than MAX_PATH. - // Three characters are for the "\*" plus NULL appended below. - StringCchLength(pDir.c_str(), MAX_PATH, &length_of_arg); - - if (length_of_arg > (MAX_PATH - 3)) { - throw fg::Error("getImageFilePaths", __LINE__, - "WIN API call: Directory path is too long", - FG_ERR_FILE_NOT_FOUND); - } - - //printf("\nTarget directory is %s\n\n", pDir.c_str()); - // Prepare string for use with FindFile functions. First, copy the - // string to a buffer, then append '\*' to the directory name. - StringCchCopy(szDir, MAX_PATH, pDir.c_str()); - std::string wildcard = "\\*" + pExt; - StringCchCat(szDir, MAX_PATH, wildcard.c_str()); - - // Find the first file in the directory. - hFind = FindFirstFile(szDir, &ffd); - if (INVALID_HANDLE_VALUE == hFind) { - throw fg::Error("getImageFilePaths", __LINE__, - "WIN API call: file fetch in DIR failed", - FG_ERR_FILE_NOT_FOUND); - } - - // List all the files in the directory with some info about them. - do { - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - // It is a directory, skip the entry - //_tprintf(TEXT(" %s \n"), ffd.cFileName); - } else { - filesize.LowPart = ffd.nFileSizeLow; - filesize.HighPart = ffd.nFileSizeHigh; - //_tprintf(TEXT(" %s %ld bytes\n"), ffd.cFileName, filesize.QuadPart); - pFiles.push_back(std::string(ffd.cFileName)); - } - } while (FindNextFile(hFind, &ffd) != 0); - - dwError = GetLastError(); - if (dwError != ERROR_NO_MORE_FILES) { - throw fg::Error("getImageFilePaths", __LINE__, - "WIN API call: files fetch returned no files", - FG_ERR_FILE_NOT_FOUND); - } - - FindClose(hFind); -} -#endif - -std::string toString(float pVal, const int n) -{ - std::ostringstream out; - out << std::fixed << std::setprecision(n) << pVal; - return out.str(); -} diff --git a/src/common.hpp b/src/common.hpp deleted file mode 100644 index b108c4a5..00000000 --- a/src/common.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************* - * 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 - -#define GLM_FORCE_RADIANS -#include -#include -#include -#include - -static const float GRAY[] = {0.0f , 0.0f , 0.0f , 1.0f}; -static const float WHITE[] = {1.0f , 1.0f , 1.0f , 1.0f}; -static const float BLUE[] = {0.0588f, 0.1137f, 0.2745f, 1.0f}; -static const float RED[] = {1.0f , 0.0f , 0.0f , 1.0f}; - -namespace internal -{ - -/* Basic renderable class - * - * Any object that is renderable to a window should inherit from this - * class. - */ -class AbstractRenderable { - public: - /* render is a pure virtual function. - * @pX X coordinate at which the currently bound viewport begins. - * @pX Y coordinate at which the currently bound viewport begins. - * @pViewPortWidth Width of the currently bound viewport. - * @pViewPortHeight Height of the currently bound viewport. - * - * Any concrete class that inherits AbstractRenderable class needs to - * implement this method to render their OpenGL objects to - * the currently bound viewport. - * - * @return nothing. - */ - virtual void render(int pWindowId, - int pX, int pY, int pViewPortWidth, int pViewPortHeight) = 0; - - /* virtual function to set colormap, a derviced class might - * use it or ignore it if it doesnt have a need for color maps */ - virtual void setColorMapUBOParams(GLuint ubo, GLuint size) { - } -}; - -} - -GLenum gl_dtype(fg::dtype val); - -GLenum gl_ctype(fg::ChannelFormat mode); - -GLenum gl_ictype(fg::ChannelFormat mode); - -char* loadFile(const char *fname, GLint &fSize); - -GLuint initShaders(const char* vshader_code, const char* fshader_code); - -template -GLuint createBuffer(GLenum target, size_t size, const T* data, GLenum usage) -{ - GLuint ret_val = 0; - glGenBuffers(1, &ret_val); - glBindBuffer(target, ret_val); - glBufferData(target, size*sizeof(T), data, usage); - glBindBuffer(target, 0); - return ret_val; -} - -int next_p2(int value); - -float clampTo01(float a); - -#ifdef OS_WIN -void getFontFilePaths(std::vector& pFiles, std::string pDir, std::string pExt); -#endif - -std::string toString(float pVal, const int n = 2); diff --git a/src/font.cpp b/src/font.cpp deleted file mode 100644 index 0592b746..00000000 --- a/src/font.cpp +++ /dev/null @@ -1,422 +0,0 @@ -/******************************************************* - * 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 -#include FT_FREETYPE_H - -#ifndef OS_WIN -#include -#endif - -#ifdef OS_WIN -#include -#include -#endif - -/* freetype library types */ -static FT_Library gFTLib; -static FT_Face gFTFace; - -static const char* gFontVertShader = -"#version 330\n" -"uniform mat4 projectionMatrix;\n" -"uniform mat4 modelViewMatrix;\n" -"layout (location = 0) in vec2 inPosition;\n" -"layout (location = 1) in vec2 inCoord;\n" -"out vec2 texCoord;\n" -"void main()\n" -"{\n" -" gl_Position = projectionMatrix*modelViewMatrix*vec4(inPosition, 0.0, 1.0);\n" -" texCoord = inCoord;\n" -"}\n"; - -static const char* gFontFragShader = -"#version 330\n" -"in vec2 texCoord;\n" -"out vec4 outputColor;\n" -"uniform sampler2D tex;\n" -"uniform vec4 textColor;\n" -"void main()\n" -"{\n" -" vec4 texC = texture(tex, texCoord);\n" -" vec4 alpha = vec4(1.0, 1.0, 1.0, texC.r);\n" -" outputColor = alpha*textColor;\n" -"}\n"; - -static const int START_CHAR = 32; -static const int END_CHAR = 127; - -namespace internal -{ - -#define FT_THROW_ERROR(msg, err) \ - throw fg::Error("Freetype library", __LINE__, msg, err); - -void font_impl::extractGlyph(int pCharacter) -{ - FT_Load_Glyph(gFTFace, FT_Get_Char_Index(gFTFace, pCharacter), FT_LOAD_DEFAULT); - FT_Render_Glyph(gFTFace->glyph, FT_RENDER_MODE_NORMAL); - FT_Bitmap& bitmap = gFTFace->glyph->bitmap; - - int pIndex = pCharacter - START_CHAR; - - int bmp_w = bitmap.width; - int bmp_h = bitmap.rows; - int w = next_p2(bmp_w); - int h = next_p2(bmp_h); - - std::vector glyphData(w*h, 0); - for (int j=0; jglyph->advance.x>>6; - mBearingX[pIndex] = gFTFace->glyph->metrics.horiBearingX>>6; - mCharWidth[pIndex] = gFTFace->glyph->metrics.width>>6; - - mAdvY[pIndex] = (gFTFace->glyph->metrics.height - gFTFace->glyph->metrics.horiBearingY)>>6; - mBearingY[pIndex] = gFTFace->glyph->metrics.horiBearingY>>6; - mCharHeight[pIndex] = gFTFace->glyph->metrics.height>>6; - - mNewLine = std::max(mNewLine, int(gFTFace->glyph->metrics.height>>6)); - - // Rendering data, texture coordinates are always the same, - // so now we waste a little memory - float quad[8]; - float quad_texcoords[8] = { 0, 1, 0, 0, 1, 1, 1, 0}; - - quad[0] = 0.0f; quad[1] = float(-mAdvY[pIndex]+h); - quad[2] = 0.0f; quad[3] = float(-mAdvY[pIndex]); - quad[4] = float(w); quad[5] = float(-mAdvY[pIndex]+h); - quad[6] = float(w); quad[7] = float(-mAdvY[pIndex]); - - // texture coordinates are duplicated for each character - // TODO work on removing this duplicates to reduce memory usage - for (int i=0; i<4; ++i) { - float* vert_ptr = quad+2*i; - float* tex_ptr = quad_texcoords+2*i; - mVertexData.insert(mVertexData.end(), vert_ptr, vert_ptr+2); - mVertexData.insert(mVertexData.end(), tex_ptr, tex_ptr+2); - } -} - -void font_impl::bindResources(int pWindowId) -{ - if (mVAOMap.find(pWindowId) == mVAOMap.end()) { - GLsizei size = sizeof(glm::vec2); - GLuint vao = 0; - /* create a vertex array object - * with appropriate bindings */ - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, mVBO); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, size*2, 0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, size*2, reinterpret_cast(size)); - glBindVertexArray(0); - /* store the vertex array object corresponding to - * the window instance in the map */ - mVAOMap[pWindowId] = vao; - } - glBindVertexArray(mVAOMap[pWindowId]); -} - -void font_impl::unbindResources() const -{ - glBindVertexArray(0); -} - -void font_impl::destroyGLResources() -{ - if (mIsFontLoaded) { - if (mProgram) glDeleteProgram(mProgram); - if (mVBO) glDeleteBuffers(1, &mVBO); - glDeleteTextures(NUM_CHARS, mCharTextures); - } - if (mProgram) glDeleteProgram(mProgram); - if (mSampler) glDeleteSamplers(1, &mSampler); -} - -font_impl::font_impl() - : mIsFontLoaded(false), mTTFfile(""), - mVBO(0), mProgram(0), mSampler(0) -{ - mProgram = initShaders(gFontVertShader, gFontFragShader); - memset(mCharTextures, 0, NUM_CHARS); - glGenSamplers(1, &mSampler); - glSamplerParameteri(mSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glSamplerParameteri(mSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glSamplerParameteri(mSampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glSamplerParameteri(mSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -} - -font_impl::~font_impl() -{ - destroyGLResources(); -} - -void font_impl::setOthro2D(int pWidth, int pHeight) -{ - mWidth = pWidth; - mHeight= pHeight; -} - -void font_impl::loadFont(const char* const pFile, int pFontSize) -{ - if (mIsFontLoaded) { - if (pFile==mTTFfile) - return; - else { - destroyGLResources(); - mIsFontLoaded = false; - } - } - mLoadedPixelSize = pFontSize; - - CheckGL("Begin Font::loadFont"); - // Initialize freetype font library - FT_Error bError = FT_Init_FreeType(&gFTLib); - - bError = FT_New_Face(gFTLib, pFile, 0, &gFTFace); - if(bError) { - FT_Done_FreeType(gFTLib); - FT_THROW_ERROR("font face creation failed", fg::FG_ERR_FREETYPE_ERROR); - } - - bError = FT_Set_Pixel_Sizes(gFTFace, 0, pFontSize); - if (bError) { - FT_Done_Face(gFTFace); - FT_Done_FreeType(gFTLib); - FT_THROW_ERROR("set font size failed", fg::FG_ERR_FREETYPE_ERROR); - } - - // read font glyphs for only characters - // from ' ' to '~' - for (int i=START_CHAR; i(GL_ARRAY_BUFFER, mVertexData.size(), &(mVertexData.front()), GL_STATIC_DRAW); - - mIsFontLoaded = true; - mTTFfile = pFile; - CheckGL("End Font::loadFont"); -} - -void font_impl::loadSystemFont(const char* const pName, int pFontSize) -{ - //TODO do error checking once it is working - std::string ttf_file_path; - -#ifndef OS_WIN - // use fontconfig to get the file - FcConfig* config = FcInitLoadConfigAndFonts(); - if (!config) { - FT_THROW_ERROR("fontconfig initilization failed", fg::FG_ERR_FREETYPE_ERROR); - } - // configure the search pattern, - FcPattern* pat = FcNameParse((const FcChar8*)(pName)); - if (!pat) { - FT_THROW_ERROR("fontconfig pattern creation failed", fg::FG_ERR_FREETYPE_ERROR); - } - - FcConfigSubstitute(config, pat, FcMatchPattern); - FcDefaultSubstitute(pat); - - // find the font - FcResult res; - FcPattern* font = FcFontMatch(config, pat, &res); - - FcConfigSubstitute(config, pat, FcMatchPattern); - if (font) { - FcChar8* file = NULL; - if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) { - // save the file to another std::string - ttf_file_path = (char*)file; - } - FcPatternDestroy(font); - } - // destroy fontconfig pattern object - FcPatternDestroy(pat); -#else - char buf[512]; - GetWindowsDirectory(buf, 512); - - std::regex fontRegex(std::string(pName), std::regex_constants::egrep | std::regex_constants::icase); - std::vector fontFiles; - std::vector matchedFontFiles; - - getFontFilePaths(fontFiles, std::string(buf)+"\\Fonts\\", std::string("ttf")); - for (const auto &fontName : fontFiles) { - if (std::regex_search(fontName, fontRegex)) { - matchedFontFiles.push_back(fontName); - } - } - /* out of all the possible matches, we choose the - first possible match for given input font name parameter - */ - if (matchedFontFiles.size()==0) - FT_THROW_ERROR("loadSystemFont failed to find the given font name", fg::FG_ERR_FREETYPE_ERROR); - - ttf_file_path = buf; - ttf_file_path += "\\Fonts\\"; - ttf_file_path += matchedFontFiles[0]; -#endif - - loadFont(ttf_file_path.c_str(), pFontSize); -} - -void font_impl::render(int pWindowId, - const float pPos[], const float pColor[], const char* pText, - int pFontSize, bool pIsVertical) -{ - if(!mIsFontLoaded) { - std::cerr<<"No font was loaded!, hence skipping text rendering."<= ' ') { - // regular characters are rendered as textured quad - int idx = int(currChar) - START_CHAR; - loc_x += mBearingX[idx] * pFontSize / mLoadedPixelSize; - - glBindTexture(GL_TEXTURE_2D, mCharTextures[idx]); - - /* rotate by 90 degress if we need - * to render the characters vertically */ - glm::mat4 modelView = glm::translate(glm::mat4(1.0f), - glm::vec3(float(loc_x), float(loc_y), 0.0f)); - - modelView = glm::scale(modelView, glm::vec3(scale_factor)); - glUniformMatrix4fv(mvmat_loc, 1, GL_FALSE, (GLfloat*)&modelView); - - // Draw letter - glDrawArrays(GL_TRIANGLE_STRIP, idx*4, 4); - - loc_x += (mAdvX[idx] - mBearingX[idx]) * pFontSize / mLoadedPixelSize; - } - /* if the text needs to be rendered vertically, - * move the pen cursor to next line after each - * character render mandatorily */ - if (pIsVertical) { - loc_x = int(pPos[0]); - loc_y -= mNewLine * pFontSize / mLoadedPixelSize; - } - } - - unbindResources(); - - glUseProgram(0); - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - CheckGL("After Font::render "); -} - -} - -namespace fg -{ - -Font::Font() -{ - value = new internal::_Font(); -} - -Font::Font(const Font& other) -{ - value = new internal::_Font(*other.get()); -} - -Font::~Font() -{ - delete value; -} - -void Font::loadFont(const char* const pFile, int pFontSize) -{ - value->loadFont(pFile, pFontSize); -} - -void Font::loadSystemFont(const char* const pName, int pFontSize) -{ - value->loadSystemFont(pName, pFontSize); -} - -internal::_Font* Font::get() const -{ - return value; -} - -} diff --git a/src/font.hpp b/src/font.hpp deleted file mode 100644 index d0505ea7..00000000 --- a/src/font.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************* -* 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 - -static const int NUM_CHARS = 95; - -namespace internal -{ - -class font_impl { - private: - /* VAO map to store a vertex array object - * for each valid window context */ - std::map mVAOMap; - - /* attributes */ - bool mIsFontLoaded; - std::string mTTFfile; - std::vector mVertexData; - int mWidth; - int mHeight; - GLuint mVBO; - GLuint mProgram; - GLuint mSampler; - - GLuint mCharTextures[NUM_CHARS]; - int mAdvX[NUM_CHARS], mAdvY[NUM_CHARS]; - int mBearingX[NUM_CHARS], mBearingY[NUM_CHARS]; - int mCharWidth[NUM_CHARS], mCharHeight[NUM_CHARS]; - int mLoadedPixelSize, mNewLine; - - /* helper function to extract glyph of - * ASCII character pointed by pIndex*/ - void extractGlyph(int pIndex); - - /* helper functions to bind and unbind - * rendering resources */ - void bindResources(int pWindowId); - void unbindResources() const; - - /* helper to destroy GL objects created for - * given font face and size if required */ - void destroyGLResources(); - - public: - font_impl(); - ~font_impl(); - - void setOthro2D(int pWidth, int pHeight); - void loadFont(const char* const pFile, int pFontSize); - void loadSystemFont(const char* const pName, int pFontSize); - - void render(int pWindowId, - const float pPos[2], const float pColor[4], const char* pText, - int pFontSize = -1, bool pIsVertical = false); -}; - -class _Font { - private: - std::shared_ptr fnt; - - public: - _Font() : fnt(std::make_shared()) {} - - const std::shared_ptr& impl() const { - return fnt; - } - - inline void setOthro2D(int pWidth, int pHeight) { - fnt->setOthro2D(pWidth, pHeight); - } - - inline void loadFont(const char* const pFile, int pFontSize) { - fnt->loadFont(pFile, pFontSize); - } - - inline void loadSystemFont(const char* const pName, int pFontSize) { - fnt->loadSystemFont(pName, pFontSize); - } -}; - -} diff --git a/src/glfw/window.cpp b/src/glfw/window.cpp deleted file mode 100644 index fdf95fc3..00000000 --- a/src/glfw/window.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/******************************************************* -* 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 - -#define GLFW_THROW_ERROR(msg, err) \ - throw fg::Error("Window constructor", __LINE__, msg, err); - -namespace wtk -{ - -Widget::Widget() - : mWindow(NULL), mClose(false) -{ -} - -Widget::Widget(int pWidth, int pHeight, const char* pTitle, const Widget* pWindow, const bool invisible) -{ - mClose = false; - - if (!glfwInit()) { - std::cerr << "ERROR: GLFW wasn't able to initalize\n"; - GLFW_THROW_ERROR("glfw initilization failed", fg::FG_ERR_GL_ERROR) - } - - auto wndErrCallback = [](int errCode, const char* pDescription) - { - fputs(pDescription, stderr); - }; - glfwSetErrorCallback(wndErrCallback); - - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - - if (invisible) - glfwWindowHint(GLFW_VISIBLE, GL_FALSE); - else - glfwWindowHint(GLFW_VISIBLE, GL_TRUE); - - glfwWindowHint(GLFW_SAMPLES, 4); - mWindow = glfwCreateWindow(pWidth, pHeight, pTitle, nullptr, - (pWindow!=nullptr ? pWindow->getNativeHandle(): nullptr)); - - if (!mWindow) { - std::cerr<<"Error: Could not Create GLFW Window!\n"; - GLFW_THROW_ERROR("glfw window creation failed", fg::FG_ERR_GL_ERROR) - } - - glfwSetWindowUserPointer(mWindow, this); - - auto kbCallback = [](GLFWwindow* w, int pKey, int pScancode, int pAction, int pMods) - { - static_cast(glfwGetWindowUserPointer(w))->keyboardHandler(pKey, pScancode, pAction, pMods); - }; - glfwSetKeyCallback(mWindow, kbCallback); - - auto closeCallback = [](GLFWwindow* w) - { - static_cast(glfwGetWindowUserPointer(w))->hide(); - }; - glfwSetWindowCloseCallback(mWindow, closeCallback); -} - -Widget::~Widget() -{ - if (mWindow) - glfwDestroyWindow(mWindow); -} - -GLFWwindow* Widget::getNativeHandle() const -{ - return mWindow; -} - -void Widget::makeContextCurrent() const -{ - glfwMakeContextCurrent(mWindow); -} - -long long Widget::getGLContextHandle() -{ -#ifdef OS_WIN - return reinterpret_cast(glfwGetWGLContext(mWindow)); -#elif OS_LNX - return reinterpret_cast(glfwGetGLXContext(mWindow)); -#else - return 0; -#endif -} - -long long Widget::getDisplayHandle() -{ -#ifdef OS_WIN - return reinterpret_cast(GetDC(glfwGetWin32Window(mWindow))); -#elif OS_LNX - return reinterpret_cast(glfwGetX11Display()); -#else - return 0; -#endif -} - -void Widget::getFrameBufferSize(int* pW, int* pH) -{ - glfwGetFramebufferSize(mWindow, pW, pH); -} - -void Widget::setTitle(const char* pTitle) -{ - glfwSetWindowTitle(mWindow, pTitle); -} - -void Widget::setPos(int pX, int pY) -{ - glfwSetWindowPos(mWindow, pX, pY); -} - -void Widget::setSize(unsigned pW, unsigned pH) -{ - glfwSetWindowSize(mWindow, pW, pH); -} - -void Widget::swapBuffers() -{ - glfwSwapBuffers(mWindow); -} - -void Widget::hide() -{ - mClose = true; - glfwHideWindow(mWindow); -} - -void Widget::show() -{ - mClose = false; - glfwShowWindow(mWindow); -} - -bool Widget::close() -{ - return mClose; -} - -void Widget::resetCloseFlag() -{ - if(mClose==true) { - show(); - } -} - -void Widget::keyboardHandler(int pKey, int pScancode, int pAction, int pMods) -{ - if (pKey == GLFW_KEY_ESCAPE && pAction == GLFW_PRESS) { - hide(); - } -} - -void Widget::pollEvents() -{ - glfwPollEvents(); -} - -} diff --git a/src/histogram.cpp b/src/histogram.cpp deleted file mode 100644 index e1966c61..00000000 --- a/src/histogram.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/******************************************************* - * 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 - -using namespace std; - -const char *gHistBarVertexShaderSrc = -"#version 330\n" -"in vec2 point;\n" -"in float freq;\n" -"uniform float ymax;\n" -"uniform float nbins;\n" -"uniform mat4 transform;\n" -"void main(void) {\n" -" float binId = gl_InstanceID;\n" -" float deltax = 2.0f/nbins;\n" -" float deltay = 2.0f/ymax;\n" -" float xcurr = -1.0f + binId * deltax;\n" -" if (point.x==1) {\n" -" xcurr += deltax;\n" -" }\n" -" float ycurr = -1.0f;\n" -" if (point.y==1) {\n" -" ycurr += deltay * freq;\n" -" }\n" -" gl_Position = transform * vec4(xcurr, ycurr, 0, 1);\n" -"}"; - -const char *gHistBarFragmentShaderSrc = -"#version 330\n" -"uniform vec4 barColor;\n" -"out vec4 outColor;\n" -"void main(void) {\n" -" outColor = barColor;\n" -"}"; - -namespace internal -{ - -void hist_impl::bindResources(int pWindowId) -{ - if (mVAOMap.find(pWindowId) == mVAOMap.end()) { - GLuint vao = 0; - /* create a vertex array object - * with appropriate bindings */ - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - glEnableVertexAttribArray(mPointIndex); - glEnableVertexAttribArray(mFreqIndex); - // attach histogram bar vertices - glBindBuffer(GL_ARRAY_BUFFER, mDecorVBO); - glVertexAttribPointer(mPointIndex, 2, GL_FLOAT, GL_FALSE, 0, 0); - // attach histogram frequencies - glBindBuffer(GL_ARRAY_BUFFER, mHistogramVBO); - glVertexAttribPointer(mFreqIndex, 1, mGLType, GL_FALSE, 0, 0); - glVertexAttribDivisor(mFreqIndex, 1); - glBindVertexArray(0); - /* store the vertex array object corresponding to - * the window instance in the map */ - mVAOMap[pWindowId] = vao; - } - - glBindVertexArray(mVAOMap[pWindowId]); -} - -void hist_impl::unbindResources() const -{ - glBindVertexArray(0); - //glVertexAttribDivisor(mFreqIndex, 0); -} - -hist_impl::hist_impl(unsigned pNBins, fg::dtype pDataType) - : Chart2D(), mDataType(pDataType), mGLType(gl_dtype(mDataType)), - mNBins(pNBins), mHistogramVBO(0), mHistogramVBOSize(0), mHistBarProgram(0), - mHistBarMatIndex(0), mHistBarColorIndex(0), mHistBarYMaxIndex(0), - mPointIndex(0), mFreqIndex(0) -{ - CheckGL("Begin hist_impl::hist_impl"); - mHistBarProgram = initShaders(gHistBarVertexShaderSrc, gHistBarFragmentShaderSrc); - - mPointIndex = glGetAttribLocation (mHistBarProgram, "point"); - mFreqIndex = glGetAttribLocation (mHistBarProgram, "freq"); - mHistBarColorIndex = glGetUniformLocation(mHistBarProgram, "barColor"); - mHistBarMatIndex = glGetUniformLocation(mHistBarProgram, "transform"); - mHistBarNBinsIndex = glGetUniformLocation(mHistBarProgram, "nbins"); - mHistBarYMaxIndex = glGetUniformLocation(mHistBarProgram, "ymax"); - - switch(mGLType) { - case GL_FLOAT: - mHistogramVBO = createBuffer(GL_ARRAY_BUFFER, mNBins, NULL, GL_DYNAMIC_DRAW); - mHistogramVBOSize = mNBins*sizeof(float); - break; - case GL_INT: - mHistogramVBO = createBuffer(GL_ARRAY_BUFFER, mNBins, NULL, GL_DYNAMIC_DRAW); - mHistogramVBOSize = mNBins*sizeof(int); - break; - case GL_UNSIGNED_INT: - mHistogramVBO = createBuffer(GL_ARRAY_BUFFER, mNBins, NULL, GL_DYNAMIC_DRAW); - mHistogramVBOSize = mNBins*sizeof(unsigned); - break; - case GL_SHORT: - mHistogramVBO = createBuffer(GL_ARRAY_BUFFER, mNBins, NULL, GL_DYNAMIC_DRAW); - mHistogramVBOSize = mNBins*sizeof(short); - break; - case GL_UNSIGNED_SHORT: - mHistogramVBO = createBuffer(GL_ARRAY_BUFFER, mNBins, NULL, GL_DYNAMIC_DRAW); - mHistogramVBOSize = mNBins*sizeof(unsigned short); - break; - case GL_UNSIGNED_BYTE: - mHistogramVBO = createBuffer(GL_ARRAY_BUFFER, mNBins, NULL, GL_DYNAMIC_DRAW); - mHistogramVBOSize = mNBins*sizeof(unsigned char); - break; - default: fg::TypeError("Plot::Plot", __LINE__, 1, mDataType); - } - CheckGL("End hist_impl::hist_impl"); -} - -hist_impl::~hist_impl() -{ - CheckGL("Begin hist_impl::~hist_impl"); - for (auto it = mVAOMap.begin(); it!=mVAOMap.end(); ++it) { - GLuint vao = it->second; - glDeleteVertexArrays(1, &vao); - } - glDeleteBuffers(1, &mHistogramVBO); - glDeleteProgram(mHistBarProgram); - CheckGL("End hist_impl::~hist_impl"); -} - -void hist_impl::setBarColor(float r, float g, float b) -{ - mBarColor[0] = r; - mBarColor[1] = g; - mBarColor[2] = b; - mBarColor[3] = 1.0f; -} - -GLuint hist_impl::vbo() const -{ - return mHistogramVBO; -} - -size_t hist_impl::size() const -{ - return mHistogramVBOSize; -} - -void hist_impl::render(int pWindowId, int pX, int pY, int pVPW, int pVPH) -{ - float w = float(pVPW - (mLeftMargin+mRightMargin+mTickSize)); - float h = float(pVPH - (mBottomMargin+mTopMargin+mTickSize)); - float offset_x = (2.0f * (mLeftMargin+mTickSize) + (w - pVPW)) / pVPW; - float offset_y = (2.0f * (mBottomMargin+mTickSize) + (h - pVPH)) / pVPH; - float scale_x = w / pVPW; - float scale_y = h / pVPH; - - CheckGL("Begin Histogram::render"); - /* Enavle scissor test to discard anything drawn beyond viewport. - * Set scissor rectangle to clip fragments outside of viewport */ - glScissor(pX+mLeftMargin+mTickSize, pY+mBottomMargin+mTickSize, - pVPW - (mLeftMargin+mRightMargin+mTickSize), - pVPH - (mBottomMargin+mTopMargin+mTickSize)); - glEnable(GL_SCISSOR_TEST); - - glm::mat4 trans = glm::translate(glm::scale(glm::mat4(1), - glm::vec3(scale_x, scale_y, 1)), - glm::vec3(offset_x, offset_y, 0)); - - glUseProgram(mHistBarProgram); - glUniformMatrix4fv(mHistBarMatIndex, 1, GL_FALSE, glm::value_ptr(trans)); - glUniform4fv(mHistBarColorIndex, 1, mBarColor); - glUniform1f(mHistBarNBinsIndex, (GLfloat)mNBins); - glUniform1f(mHistBarYMaxIndex, ymax()); - - /* render a rectangle for each bin. Same - * rectangle is scaled and translated accordingly - * for each bin. This is done by OpenGL feature of - * instanced rendering */ - hist_impl::bindResources(pWindowId); - glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, mNBins); - hist_impl::unbindResources(); - - glUseProgram(0); - /* Stop clipping */ - glDisable(GL_SCISSOR_TEST); - - renderChart(pWindowId, pX, pY, pVPW, pVPH); - CheckGL("End Histogram::render"); -} - -} - -namespace fg -{ - -Histogram::Histogram(unsigned pNBins, fg::dtype pDataType) -{ - value = new internal::_Histogram(pNBins, pDataType); -} - -Histogram::Histogram(const Histogram& other) -{ - value = new internal::_Histogram(*other.get()); -} - -Histogram::~Histogram() -{ - delete value; -} - -void Histogram::setBarColor(fg::Color col) -{ - float r = (((int) col >> 24 ) & 0xFF ) / 255.f; - float g = (((int) col >> 16 ) & 0xFF ) / 255.f; - float b = (((int) col >> 8 ) & 0xFF ) / 255.f; - // float a = (((int) col ) & 0xFF ) / 255.f; - value->setBarColor(r, g, b); -} - -void Histogram::setBarColor(float r, float g, float b) -{ - value->setBarColor(r, g, b); -} - -void Histogram::setAxesLimits(float pXmax, float pXmin, float pYmax, float pYmin) -{ - value->setAxesLimits(pXmax, pXmin, pYmax, pYmin); -} - -void Histogram::setAxesTitles(const char* pXTitle, const char* pYTitle) -{ - value->setAxesTitles(pXTitle, pYTitle); -} - -float Histogram::xmax() const -{ - return value->xmax(); -} - -float Histogram::xmin() const -{ - return value->xmin(); -} - -float Histogram::ymax() const -{ - return value->ymax(); -} - -float Histogram::ymin() const -{ - return value->ymin(); -} - -unsigned Histogram::vbo() const -{ - return value->vbo(); -} - -unsigned Histogram::size() const -{ - return (unsigned)value->size(); -} - -internal::_Histogram* Histogram::get() const -{ - return value; -} - -} diff --git a/src/histogram.hpp b/src/histogram.hpp deleted file mode 100644 index 38f6cb38..00000000 --- a/src/histogram.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/******************************************************* -* 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 - -namespace internal -{ - -class hist_impl : public Chart2D { - private: - /* plot points characteristics */ - fg::dtype mDataType; - GLenum mGLType; - GLuint mNBins; - float mBarColor[4]; - /* OpenGL Objects */ - GLuint mHistogramVBO; - size_t mHistogramVBOSize; - GLuint mHistBarProgram; - /* internal shader attributes for mHistBarProgram - * shader program to render histogram bars for each - * bin*/ - GLuint mHistBarMatIndex; - GLuint mHistBarColorIndex; - GLuint mHistBarNBinsIndex; - GLuint mHistBarYMaxIndex; - GLuint mPointIndex; - GLuint mFreqIndex; - - std::map mVAOMap; - - /* bind and unbind helper functions - * for rendering resources */ - void bindResources(int pWindowId); - void unbindResources() const; - - public: - hist_impl(unsigned pNBins, fg::dtype pDataType); - ~hist_impl(); - - void setBarColor(float r, float g, float b); - GLuint vbo() const; - size_t size() const; - - void render(int pWindowId, int pX, int pY, int pViewPortWidth, int pViewPortHeight); -}; - -class _Histogram { - private: - std::shared_ptr hst; - - public: - _Histogram(unsigned pNBins, fg::dtype pDataType) - : hst(std::make_shared(pNBins, pDataType)) {} - - inline const std::shared_ptr& impl() const { - return hst; - } - - inline void setBarColor(float r, float g, float b) { - hst->setBarColor(r, g, b); - } - - inline void setAxesLimits(float pXmax, float pXmin, float pYmax, float pYmin) { - hst->setAxesLimits(pXmax, pXmin, pYmax, pYmin); - } - - inline void setAxesTitles(const char* pXTitle, const char* pYTitle) { - hst->setAxesTitles(pXTitle, pYTitle); - } - - inline float xmax() const { - return hst->xmax(); - } - - inline float xmin() const { - return hst->xmin(); - } - - inline float ymax() const { - return hst->ymax(); - } - - inline float ymin() const { - return hst->ymin(); - } - - inline GLuint vbo() const { - return hst->vbo(); - } - - inline size_t size() const { - return hst->size(); - } -}; - -} diff --git a/src/image.cpp b/src/image.cpp deleted file mode 100644 index f00019c5..00000000 --- a/src/image.cpp +++ /dev/null @@ -1,298 +0,0 @@ -/******************************************************* - * 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 - -static const char* vertex_shader_code = -"#version 330\n" -"layout(location = 0) in vec3 pos;\n" -"layout(location = 1) in vec2 tex;\n" -"uniform mat4 matrix;\n" -"out vec2 texcoord;\n" -"void main() {\n" -" texcoord = tex;\n" -" gl_Position = matrix * vec4(pos,1.0);\n" -"}\n"; - -static const char* fragment_shader_code = -"#version 330\n" -"const int size = 259;\n" -"uniform float cmaplen;\n" -"layout(std140) uniform ColorMap\n" -"{\n" -" vec4 ch[size];\n" -"};\n" -"uniform sampler2D tex;\n" -"uniform bool isGrayScale;\n" -"in vec2 texcoord;\n" -"out vec4 fragColor;\n" -"void main()\n" -"{\n" -" vec4 tcolor = texture(tex, texcoord);\n" -" vec4 clrs = vec4(1, 0, 0, 1);\n" -" if(isGrayScale)\n" -" clrs = vec4(tcolor.r, tcolor.r, tcolor.r, 1);\n" -" else\n" -" clrs = tcolor;\n" -" vec4 fidx = (cmaplen-1) * clrs;\n" -" ivec4 idx = ivec4(fidx.x, fidx.y, fidx.z, fidx.w);\n" -" float r_ch = ch[idx.x].r;\n" -" float g_ch = ch[idx.y].g;\n" -" float b_ch = ch[idx.z].b;\n" -" fragColor = vec4(r_ch, g_ch , b_ch, 1);\n" -"}\n"; - -GLuint imageQuadVAO(int pWindowId) -{ - static std::map mVAOMap; - - if (mVAOMap.find(pWindowId)==mVAOMap.end()) { - static const float vertices[12] = {-1.0f,-1.0f,0.0, - 1.0f,-1.0f,0.0, - 1.0f, 1.0f,0.0, - -1.0f, 1.0f,0.0}; - static const float texcords[8] = {0.0,1.0,1.0,1.0,1.0,0.0,0.0,0.0}; - static const unsigned indices[6]= {0,1,2,0,2,3}; - GLuint vbo = createBuffer(GL_ARRAY_BUFFER, 12, vertices, GL_STATIC_DRAW); - GLuint tbo = createBuffer(GL_ARRAY_BUFFER, 8, texcords, GL_STATIC_DRAW); - GLuint ibo = createBuffer(GL_ELEMENT_ARRAY_BUFFER, 6, indices, GL_STATIC_DRAW); - - GLuint vao = 0; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - // attach vbo - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); - // attach tbo - glBindBuffer(GL_ARRAY_BUFFER, tbo); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL); - // attach ibo - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); - glBindVertexArray(0); - /* store the vertex array object corresponding to - * the window instance in the map */ - mVAOMap[pWindowId] = vao; - } - - return mVAOMap[pWindowId]; -} - -namespace internal -{ - -void image_impl::bindResources(int pWindowId) -{ - glBindVertexArray(imageQuadVAO(pWindowId)); -} - -void image_impl::unbindResources() const -{ - glBindVertexArray(0); -} - -image_impl::image_impl(unsigned pWidth, unsigned pHeight, - fg::ChannelFormat pFormat, fg::dtype pDataType) - : mWidth(pWidth), mHeight(pHeight), - mFormat(pFormat), mGLformat(gl_ctype(mFormat)), mGLiformat(gl_ictype(mFormat)), - mDataType(pDataType), mGLType(gl_dtype(mDataType)) -{ - CheckGL("Begin image_impl::image_impl"); - - // Initialize OpenGL Items - glGenTextures(1, &(mTex)); - glBindTexture(GL_TEXTURE_2D, mTex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - glTexImage2D(GL_TEXTURE_2D, 0, mGLiformat, mWidth, mHeight, 0, mGLformat, mGLType, NULL); - - CheckGL("Before PBO Initialization"); - glGenBuffers(1, &mPBO); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO); - size_t typeSize = 0; - switch(mGLType) { - case GL_INT: typeSize = sizeof(int ); break; - case GL_UNSIGNED_INT: typeSize = sizeof(unsigned int); break; - case GL_SHORT: typeSize = sizeof(short ); break; - case GL_UNSIGNED_SHORT: typeSize = sizeof(unsigned short); break; - case GL_BYTE: typeSize = sizeof(char ); break; - case GL_UNSIGNED_BYTE: typeSize = sizeof(unsigned char); break; - default: typeSize = sizeof(float); break; - } - size_t formatSize = 0; - switch(mFormat) { - case fg::FG_GRAYSCALE: formatSize = 1; break; - case fg::FG_RG: formatSize = 2; break; - case fg::FG_RGB: formatSize = 3; break; - case fg::FG_BGR: formatSize = 3; break; - case fg::FG_RGBA: formatSize = 4; break; - case fg::FG_BGRA: formatSize = 4; break; - default: formatSize = 1; break; - } - mPBOsize = mWidth * mHeight * formatSize * typeSize; - glBufferData(GL_PIXEL_UNPACK_BUFFER, mPBOsize, NULL, GL_STREAM_COPY); - - glBindTexture(GL_TEXTURE_2D, 0); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - CheckGL("After PBO Initialization"); - - mProgram = initShaders(vertex_shader_code, fragment_shader_code); - - CheckGL("End image_impl::image_impl"); -} - -image_impl::~image_impl() -{ - CheckGL("Begin image_impl::~image_impl"); - glDeleteBuffers(1, &mPBO); - glDeleteTextures(1, &mTex); - glDeleteProgram(mProgram); - CheckGL("End image_impl::~image_impl"); -} - -void image_impl::setColorMapUBOParams(GLuint ubo, GLuint size) -{ - mColorMapUBO = ubo; - mUBOSize = size; -} - -void image_impl::keepAspectRatio(const bool keep) -{ - mKeepARatio = keep; -} - -unsigned image_impl::width() const { return mWidth; } - -unsigned image_impl::height() const { return mHeight; } - -fg::ChannelFormat image_impl::pixelFormat() const { return mFormat; } - -fg::dtype image_impl::channelType() const { return mDataType; } - -unsigned image_impl::pbo() const { return mPBO; } - -unsigned image_impl::size() const { return (unsigned)mPBOsize; } - -void image_impl::render(int pWindowId, int pX, int pY, int pViewPortWidth, int pViewPortHeight) -{ - float xscale = 1.f; - float yscale = 1.f; - if (mKeepARatio) { - if (mWidth > mHeight) { - float trgtH = pViewPortWidth * float(mHeight)/float(mWidth); - float trgtW = trgtH * float(mWidth)/float(mHeight); - xscale = trgtW/pViewPortWidth; - yscale = trgtH/pViewPortHeight; - } else { - float trgtW = pViewPortHeight * float(mWidth)/float(mHeight); - float trgtH = trgtW * float(mHeight)/float(mWidth); - xscale = trgtW/pViewPortWidth; - yscale = trgtH/pViewPortHeight; - } - } - glm::mat4 strans = glm::scale(glm::mat4(1.0f), glm::vec3(xscale, yscale, 1)); - - glUseProgram(mProgram); - // get uniform locations - int mat_loc = glGetUniformLocation(mProgram, "matrix"); - int tex_loc = glGetUniformLocation(mProgram, "tex"); - int chn_loc = glGetUniformLocation(mProgram, "isGrayScale"); - int cml_loc = glGetUniformLocation(mProgram, "cmaplen"); - int ubo_idx = glGetUniformBlockIndex(mProgram, "ColorMap"); - - glUniform1i(chn_loc, mFormat==fg::FG_GRAYSCALE); - // load texture from PBO - glActiveTexture(GL_TEXTURE0); - glUniform1i(tex_loc, 0); - glBindTexture(GL_TEXTURE_2D, mTex); - // bind PBO to load data into texture - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mWidth, mHeight, mGLformat, mGLType, 0); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - - glUniformMatrix4fv(mat_loc, 1, GL_FALSE, glm::value_ptr(strans)); - - glUniform1f(cml_loc, (GLfloat)mUBOSize); - glBindBufferBase(GL_UNIFORM_BUFFER, 0, mColorMapUBO); - glUniformBlockBinding(mProgram, ubo_idx, 0); - - CheckGL("Before render"); - - // Draw to screen - bindResources(pWindowId); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); - unbindResources(); - - glBindTexture(GL_TEXTURE_2D, 0); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - - // ubind the shader program - glUseProgram(0); - CheckGL("After render"); -} - -} - -namespace fg -{ - -Image::Image(unsigned pWidth, unsigned pHeight, fg::ChannelFormat pFormat, fg::dtype pDataType) { - value = new internal::_Image(pWidth, pHeight, pFormat, pDataType); -} - -Image::Image(const Image& other) { - value = new internal::_Image(*other.get()); -} - -Image::~Image() { - delete value; -} - -unsigned Image::width() const { - return value->width(); -} - -unsigned Image::height() const { - return value->height(); -} - -ChannelFormat Image::pixelFormat() const { - return value->pixelFormat(); -} - -fg::dtype Image::channelType() const { - return value->channelType(); -} - -GLuint Image::pbo() const { - return value->pbo(); -} - -unsigned Image::size() const { - return (unsigned)value->size(); -} - -internal::_Image* Image::get() const { - return value; -} - -} diff --git a/src/image.hpp b/src/image.hpp deleted file mode 100644 index 4485c081..00000000 --- a/src/image.hpp +++ /dev/null @@ -1,84 +0,0 @@ -/******************************************************* -* 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 - -namespace internal -{ - -class image_impl : public AbstractRenderable { - private: - unsigned mWidth; - unsigned mHeight; - fg::ChannelFormat mFormat; - GLenum mGLformat; - GLenum mGLiformat; - fg::dtype mDataType; - GLenum mGLType; - /* internal resources for interop */ - size_t mPBOsize; - GLuint mPBO; - GLuint mTex; - GLuint mProgram; - - GLuint mColorMapUBO; - GLuint mUBOSize; - bool mKeepARatio; - - /* helper functions to bind and unbind - * resources for render quad primitive */ - void bindResources(int pWindowId); - void unbindResources() const; - - public: - image_impl(unsigned pWidth, unsigned pHeight, fg::ChannelFormat pFormat, fg::dtype pDataType); - ~image_impl(); - - void setColorMapUBOParams(GLuint ubo, GLuint size); - void keepAspectRatio(const bool keep=true); - - unsigned width() const; - unsigned height() const; - fg::ChannelFormat pixelFormat() const; - fg::dtype channelType() const; - unsigned pbo() const; - unsigned size() const; - - void render(int pWindowId, int pX, int pY, int pViewPortWidth, int pViewPortHeight); -}; - -class _Image { - private: - std::shared_ptr img; - - public: - _Image(unsigned pWidth, unsigned pHeight, fg::ChannelFormat pFormat, fg::dtype pDataType) - : img(std::make_shared(pWidth, pHeight, pFormat, pDataType)) {} - - inline const std::shared_ptr& impl() const { return img; } - - inline void keepAspectRatio(const bool keep) { img->keepAspectRatio(keep); } - - inline unsigned width() const { return img->width(); } - - inline unsigned height() const { return img->height(); } - - inline fg::ChannelFormat pixelFormat() const { return img->pixelFormat(); } - - inline fg::dtype channelType() const { return img->channelType(); } - - inline GLuint pbo() const { return img->pbo(); } - - inline size_t size() const { return img->size(); } -}; - -} diff --git a/src/plot.cpp b/src/plot.cpp deleted file mode 100644 index 15383a69..00000000 --- a/src/plot.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/******************************************************* - * 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 - -using namespace std; - -static const char *gMarkerVertexShaderSrc = -"#version 330\n" -"in vec2 point;\n" -"uniform mat4 transform;\n" -"void main(void) {\n" -" gl_Position = transform * vec4(point.xy, 0, 1);\n" -" gl_PointSize = 10;\n" -"}"; - - -static const char *gMarkerSpriteFragmentShaderSrc = -"#version 330\n" -"uniform int marker_type;\n" -"uniform vec4 marker_color;\n" -"out vec4 outputColor;\n" -"void main(void) {\n" -" float dist = sqrt( (gl_PointCoord.x - 0.5) * (gl_PointCoord.x-0.5) + (gl_PointCoord.y-0.5) * (gl_PointCoord.y-0.5) );\n" -" bool in_bounds;\n" -" switch(marker_type) {\n" -" case 1:\n" -" in_bounds = dist < 0.3;\n" -" break;\n" -" case 2:\n" -" in_bounds = ( (dist > 0.3) && (dist<0.5) );\n" -" break;\n" -" case 3:\n" -" in_bounds = ((gl_PointCoord.x < 0.15) || (gl_PointCoord.x > 0.85)) ||\n" -" ((gl_PointCoord.y < 0.15) || (gl_PointCoord.y > 0.85));\n" -" break;\n" -" case 4:\n" -" in_bounds = (2*(gl_PointCoord.x - 0.25) - (gl_PointCoord.y + 0.5) < 0) && (2*(gl_PointCoord.x - 0.25) + (gl_PointCoord.y + 0.5) > 1);\n" -" break;\n" -" case 5:\n" -" in_bounds = abs((gl_PointCoord.x - 0.5) + (gl_PointCoord.y - 0.5) ) < 0.13 ||\n" -" abs((gl_PointCoord.x - 0.5) - (gl_PointCoord.y - 0.5) ) < 0.13 ;\n" -" break;\n" -" case 6:\n" -" in_bounds = abs((gl_PointCoord.x - 0.5)) < 0.07 ||\n" -" abs((gl_PointCoord.y - 0.5)) < 0.07;\n" -" break;\n" -" case 7:\n" -" in_bounds = abs((gl_PointCoord.x - 0.5) + (gl_PointCoord.y - 0.5) ) < 0.07 ||\n" -" abs((gl_PointCoord.x - 0.5) - (gl_PointCoord.y - 0.5) ) < 0.07 ||\n" -" abs((gl_PointCoord.x - 0.5)) < 0.07 ||\n" -" abs((gl_PointCoord.y - 0.5)) < 0.07;\n" -" break;\n" -" default:\n" -" in_bounds = true;\n" -" }\n" -" if(!in_bounds)\n" -" discard;\n" -" else\n" -" outputColor = marker_color;\n" -"}"; - -namespace internal -{ - -void plot_impl::bindResources(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 plot vertices - glEnableVertexAttribArray(mPointIndex); - glBindBuffer(GL_ARRAY_BUFFER, mMainVBO); - glVertexAttribPointer(mPointIndex, 2, mGLType, 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 plot_impl::unbindResources() const -{ - glBindVertexArray(0); -} - -plot_impl::plot_impl(unsigned pNumPoints, fg::dtype pDataType, - fg::PlotType pPlotType, fg::MarkerType pMarkerType) - : Chart2D(), mNumPoints(pNumPoints), - mDataType(pDataType), mGLType(gl_dtype(mDataType)), - mMarkerType(pMarkerType), mPlotType(pPlotType), - mMainVBO(0), mMainVBOsize(0), mPointIndex(0) -{ - mMarkerProgram = initShaders(gMarkerVertexShaderSrc, gMarkerSpriteFragmentShaderSrc); - mMarkerColIndex = glGetUniformLocation(mMarkerProgram, "marker_color"); - mMarkerTypeIndex = glGetUniformLocation(mMarkerProgram, "marker_type"); - mSpriteTMatIndex = glGetUniformLocation(mMarkerProgram, "transform"); - mPointIndex = mBorderAttribPointIndex; - - unsigned total_points = 2*mNumPoints; - // buffersubdata calls on mMainVBO - // will only update the points data - switch(mGLType) { - case GL_FLOAT: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(float); - break; - case GL_INT: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(int); - break; - case GL_UNSIGNED_INT: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(unsigned); - break; - case GL_SHORT: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(short); - break; - case GL_UNSIGNED_SHORT: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(unsigned short); - break; - case GL_UNSIGNED_BYTE: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(unsigned char); - break; - default: fg::TypeError("Plot::Plot", __LINE__, 1, mDataType); - } -} - -plot_impl::~plot_impl() -{ - CheckGL("Begin Plot::~Plot"); - for (auto it = mVAOMap.begin(); it!=mVAOMap.end(); ++it) { - GLuint vao = it->second; - glDeleteVertexArrays(1, &vao); - } - glDeleteBuffers(1, &mMainVBO); - glDeleteProgram(mMarkerProgram); - CheckGL("End Plot::~Plot"); -} - -void plot_impl::setColor(fg::Color col) -{ - mLineColor[0] = (((int) col >> 24 ) & 0xFF ) / 255.f; - mLineColor[1] = (((int) col >> 16 ) & 0xFF ) / 255.f; - mLineColor[2] = (((int) col >> 8 ) & 0xFF ) / 255.f; - mLineColor[3] = (((int) col ) & 0xFF ) / 255.f; -} - -void plot_impl::setColor(float r, float g, float b) -{ - mLineColor[0] = clampTo01(r); - mLineColor[1] = clampTo01(g); - mLineColor[2] = clampTo01(b); - mLineColor[3] = 1.0f; -} - -GLuint plot_impl::vbo() const -{ - return mMainVBO; -} - -size_t plot_impl::size() const -{ - return mMainVBOsize; -} - -void plot_impl::render(int pWindowId, int pX, int pY, int pVPW, int pVPH) -{ - float range_x = xmax() - xmin(); - float range_y = ymax() - ymin(); - // set scale to zero if input is constant array - // otherwise compute scale factor by standard equation - float graph_scale_x = std::abs(range_x) < 1.0e-3 ? 0.0f : 2/(xmax() - xmin()); - float graph_scale_y = std::abs(range_y) < 1.0e-3 ? 0.0f : 2/(ymax() - ymin()); - - CheckGL("Begin Plot::render"); - float viewWidth = pVPW - (mLeftMargin + mRightMargin + mTickSize/2 ); - float viewHeight = pVPH - (mBottomMargin + mTopMargin + mTickSize ); - float view_scale_x = viewWidth/pVPW; - float view_scale_y = viewHeight/pVPH; - float view_offset_x = (2.0f * (mLeftMargin + mTickSize/2 )/ pVPW ) ; - float view_offset_y = (2.0f * (mBottomMargin + mTickSize )/ pVPH ) ; - /* Enable scissor test to discard anything drawn beyond viewport. - * Set scissor rectangle to clip fragments outside of viewport */ - glScissor(pX + mLeftMargin + mTickSize/2, pY+mBottomMargin + mTickSize/2, - pVPW - mLeftMargin - mRightMargin - mTickSize/2, - pVPH - mBottomMargin - mTopMargin - mTickSize/2); - glEnable(GL_SCISSOR_TEST); - - float coor_offset_x = ( -xmin() * graph_scale_x * view_scale_x); - float coor_offset_y = ( -ymin() * graph_scale_y * view_scale_y); - glm::mat4 transform = glm::translate(glm::mat4(1.f), - glm::vec3(-1 + view_offset_x + coor_offset_x , -1 + view_offset_y + coor_offset_y, 0)); - transform = glm::scale(transform, - glm::vec3(graph_scale_x * view_scale_x , graph_scale_y * view_scale_y ,1)); - - if(mPlotType == fg::FG_LINE) { - glUseProgram(mBorderProgram); - glUniformMatrix4fv(mBorderUniformMatIndex, 1, GL_FALSE, glm::value_ptr(transform)); - glUniform4fv(mBorderUniformColorIndex, 1, mLineColor); - plot_impl::bindResources(pWindowId); - glDrawArrays(GL_LINE_STRIP, 0, mNumPoints); - plot_impl::unbindResources(); - glUseProgram(0); - } - - if(mMarkerType != fg::FG_NONE){ - glEnable(GL_PROGRAM_POINT_SIZE); - glUseProgram(mMarkerProgram); - - glUniformMatrix4fv(mSpriteTMatIndex, 1, GL_FALSE, glm::value_ptr(transform)); - glUniform4fv(mMarkerColIndex, 1, mLineColor); - glUniform1i(mMarkerTypeIndex, mMarkerType); - - plot_impl::bindResources(pWindowId); - glDrawArrays(GL_POINTS, 0, mNumPoints); - plot_impl::unbindResources(); - glUseProgram(0); - glDisable(GL_PROGRAM_POINT_SIZE); - } - - /* Stop clipping and reset viewport to window dimensions */ - glDisable(GL_SCISSOR_TEST); - /* render graph border and axes */ - renderChart(pWindowId, pX, pY, pVPW, pVPH); - - CheckGL("End Plot::render"); -} - -} - -namespace fg -{ - -Plot::Plot(unsigned pNumPoints, fg::dtype pDataType, - fg::PlotType pPlotType, fg::MarkerType pMarkerType) -{ - value = new internal::_Plot(pNumPoints, pDataType, pPlotType, pMarkerType); -} - -Plot::Plot(const Plot& other) -{ - value = new internal::_Plot(*other.get()); -} - -Plot::~Plot() -{ - delete value; -} - -void Plot::setColor(fg::Color col) -{ - value->setColor(col); -} - -void Plot::setColor(float r, float g, float b) -{ - value->setColor(r, g, b); -} - -void Plot::setAxesLimits(float pXmax, float pXmin, float pYmax, float pYmin) -{ - value->setAxesLimits(pXmax, pXmin, pYmax, pYmin); -} - -void Plot::setAxesTitles(const char* pXTitle, const char* pYTitle) -{ - value->setAxesTitles(pXTitle, pYTitle); -} - -float Plot::xmax() const -{ - return value->xmax(); -} - -float Plot::xmin() const -{ - return value->xmin(); -} - -float Plot::ymax() const -{ - return value->ymax(); -} - -float Plot::ymin() const -{ - return value->ymin(); -} - -unsigned Plot::vbo() const -{ - return value->vbo(); -} - -unsigned Plot::size() const -{ - return (unsigned)value->size(); -} - -internal::_Plot* Plot::get() const -{ - return value; -} - -} diff --git a/src/plot.hpp b/src/plot.hpp deleted file mode 100644 index 0ca4e319..00000000 --- a/src/plot.hpp +++ /dev/null @@ -1,112 +0,0 @@ -/******************************************************* -* 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 - -namespace internal -{ - -class plot_impl : public Chart2D { - protected: - /* plot points characteristics */ - GLuint mNumPoints; - fg::dtype mDataType; - GLenum mGLType; - float mLineColor[4]; - fg::MarkerType mMarkerType; - fg::PlotType mPlotType; - /* OpenGL Objects */ - GLuint mMainVBO; - size_t mMainVBOsize; - GLuint mMarkerProgram; - /* shared variable index locations */ - GLuint mPointIndex; - GLuint mMarkerColIndex; - GLuint mMarkerTypeIndex; - GLuint mSpriteTMatIndex; - - std::map mVAOMap; - - /* bind and unbind helper functions - * for rendering resources */ - void bindResources(int pWindowId); - void unbindResources() const; - - public: - plot_impl(unsigned pNumPoints, fg::dtype pDataType, fg::PlotType, fg::MarkerType); - ~plot_impl(); - - void setColor(fg::Color col); - void setColor(float r, float g, float b); - GLuint vbo() const; - size_t size() const; - - void render(int pWindowId, int pX, int pY, int pViewPortWidth, int pViewPortHeight); -}; - -class _Plot { - private: - std::shared_ptr plt; - - public: - _Plot(unsigned pNumPoints, fg::dtype pDataType, fg::PlotType pType, fg::MarkerType mType) - : plt(std::make_shared(pNumPoints, pDataType, pType, mType)) {} - - inline const std::shared_ptr& impl() const { - return plt; - } - - inline void setColor(fg::Color col) { - plt->setColor(col); - } - - inline void setColor(float r, float g, float b) { - plt->setColor(r, g, b); - } - - inline void setAxesLimits(float pXmax, float pXmin, float pYmax, float pYmin) { - plt->setAxesLimits(pXmax, pXmin, pYmax, pYmin); - } - - inline void setAxesTitles(const char* pXTitle, const char* pYTitle) { - plt->setAxesTitles(pXTitle, pYTitle); - } - - inline float xmax() const { - return plt->xmax(); - } - - inline float xmin() const { - return plt->xmin(); - } - - inline float ymax() const { - return plt->ymax(); - } - - inline float ymin() const { - return plt->ymin(); - } - - inline GLuint vbo() const { - return plt->vbo(); - } - - inline size_t size() const { - return plt->size(); - } -}; - -} diff --git a/src/plot3.cpp b/src/plot3.cpp deleted file mode 100644 index 75238840..00000000 --- a/src/plot3.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/******************************************************* - * 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 - -using namespace std; - -static const char *gMarkerVertexShaderSrc = -"#version 330\n" -"in vec3 point;\n" -"uniform vec2 minmaxs[3];\n" -"out vec4 hpoint;\n" -"uniform mat4 transform;\n" -"void main(void) {\n" -" gl_Position = transform * vec4(point.xyz, 1);\n" -" hpoint=vec4(point.xyz,1);\n" -" gl_PointSize=10;\n" -"}"; - -const char *gPlot3FragmentShaderSrc = -"#version 330\n" -"uniform vec2 minmaxs[3];\n" -"in vec4 hpoint;\n" -"out vec4 outputColor;\n" -"vec3 hsv2rgb(vec3 c){\n" -" vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n" -" vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n" -" return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n" -"}\n" -"void main(void) {\n" -" bool nin_bounds = (hpoint.x > minmaxs[0].x || hpoint.x < minmaxs[0].y ||\n" -" hpoint.y > minmaxs[1].x || hpoint.y < minmaxs[1].y || hpoint.z < minmaxs[2].y);\n" -" float height = (minmaxs[2].x- hpoint.z)/(minmaxs[2].x-minmaxs[2].y);\n" -" if(nin_bounds) discard;\n" -" outputColor = vec4(hsv2rgb(vec3(height, 1.f, 1.f)),1);\n" -"}"; - -static const char *gMarkerSpriteFragmentShaderSrc = -"#version 330\n" -"uniform int marker_type;\n" -"uniform vec4 line_color;\n" -"in vec4 hpoint;\n" -"out vec4 outputColor;\n" -"void main(void) {\n" -" vec4 unused = hpoint;\n" -" float dist = sqrt( (gl_PointCoord.x - 0.5) * (gl_PointCoord.x-0.5) + (gl_PointCoord.y-0.5) * (gl_PointCoord.y-0.5) );\n" -" bool in_bounds;\n" -" switch(marker_type) {\n" -" case 1:\n" -" in_bounds = dist < 0.3;\n" -" break;\n" -" case 2:\n" -" in_bounds = ( (dist > 0.3) && (dist<0.5) );\n" -" break;\n" -" case 3:\n" -" in_bounds = ((gl_PointCoord.x < 0.15) || (gl_PointCoord.x > 0.85)) ||\n" -" ((gl_PointCoord.y < 0.15) || (gl_PointCoord.y > 0.85));\n" -" break;\n" -" case 4:\n" -" in_bounds = (2*(gl_PointCoord.x - 0.25) - (gl_PointCoord.y + 0.5) < 0) && (2*(gl_PointCoord.x - 0.25) + (gl_PointCoord.y + 0.5) > 1);\n" -" break;\n" -" case 5:\n" -" in_bounds = abs((gl_PointCoord.x - 0.5) + (gl_PointCoord.y - 0.5) ) < 0.13 ||\n" -" abs((gl_PointCoord.x - 0.5) - (gl_PointCoord.y - 0.5) ) < 0.13 ;\n" -" break;\n" -" case 6:\n" -" in_bounds = abs((gl_PointCoord.x - 0.5)) < 0.07 ||\n" -" abs((gl_PointCoord.y - 0.5)) < 0.07;\n" -" break;\n" -" case 7:\n" -" in_bounds = abs((gl_PointCoord.x - 0.5) + (gl_PointCoord.y - 0.5) ) < 0.07 ||\n" -" abs((gl_PointCoord.x - 0.5) - (gl_PointCoord.y - 0.5) ) < 0.07 ||\n" -" abs((gl_PointCoord.x - 0.5)) < 0.07 ||\n" -" abs((gl_PointCoord.y - 0.5)) < 0.07;\n" -" break;\n" -" case 8:\n" -" in_bounds = true;\n" -" break;\n" -" default:\n" -" in_bounds = true;\n" -" }\n" -" if(!in_bounds)\n" -" discard;\n" -" else\n" -" outputColor = line_color;\n" -"}"; - - -namespace internal -{ - -void plot3_impl::bindResources(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 plot vertices - glEnableVertexAttribArray(mPointIndex); - glBindBuffer(GL_ARRAY_BUFFER, mMainVBO); - glVertexAttribPointer(mPointIndex, 3, mDataType, GL_FALSE, 0, 0); - //attach indices - glBindVertexArray(0); - /* store the vertex array object corresponding to - * the window instance in the map */ - mVAOMap[pWindowId] = vao; - } - - glBindVertexArray(mVAOMap[pWindowId]); -} - -void plot3_impl::unbindResources() const { glBindVertexArray(0); } - -plot3_impl::plot3_impl(unsigned pNumPoints, fg::dtype pDataType, fg::PlotType pPlotType, fg::MarkerType pMarkerType) - : Chart3D(), mNumPoints(pNumPoints), - mDataType(gl_dtype(pDataType)), mPlotType(pPlotType), - mMainVBO(0), mMainVBOsize(0), - mIndexVBOsize(0), mPointIndex(0), mMarkerTypeIndex(0), - mMarkerColIndex(0), mSpriteTMatIndex(0), mPlot3PointIndex(0), - mPlot3TMatIndex(0), mPlot3RangeIndex(0) -{ - CheckGL("Begin plot3_impl::plot3_impl"); - mPointIndex = mBorderAttribPointIndex; - mMarkerType = pMarkerType; - mPlot3Program = initShaders(gMarkerVertexShaderSrc, gPlot3FragmentShaderSrc); - mMarkerProgram = initShaders(gMarkerVertexShaderSrc, gMarkerSpriteFragmentShaderSrc); - - mPlot3PointIndex = glGetAttribLocation (mPlot3Program, "point"); - mPlot3TMatIndex = glGetUniformLocation(mPlot3Program, "transform"); - mPlot3RangeIndex = glGetUniformLocation(mPlot3Program, "minmaxs"); - - mMarkerTypeIndex = glGetUniformLocation(mMarkerProgram, "marker_type"); - mMarkerColIndex = glGetUniformLocation(mMarkerProgram, "line_color"); - mSpriteTMatIndex = glGetUniformLocation(mMarkerProgram, "transform"); - - unsigned total_points = 3 * mNumPoints; - - // buffersubdata calls on mMainVBO - // will only update the points data - switch(mDataType) { - case GL_FLOAT: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(float); - break; - case GL_INT: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(int); - break; - case GL_UNSIGNED_INT: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(unsigned); - break; - case GL_UNSIGNED_BYTE: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(unsigned char); - break; - default: fg::TypeError("Plot::Plot", __LINE__, 1, pDataType); - } - CheckGL("End plot3_impl::plot3_impl"); -} - -plot3_impl::~plot3_impl() -{ - CheckGL("Begin Plot::~Plot"); - for (auto it = mVAOMap.begin(); it!=mVAOMap.end(); ++it) { - GLuint vao = it->second; - glDeleteVertexArrays(1, &vao); - } - glDeleteBuffers(1, &mMainVBO); - glDeleteProgram(mMarkerProgram); - glDeleteProgram(mPlot3Program); - CheckGL("End Plot::~Plot"); -} - -void plot3_impl::setColor(fg::Color col) -{ - mLineColor[0] = (((int) col >> 24 ) & 0xFF ) / 255.f; - mLineColor[1] = (((int) col >> 16 ) & 0xFF ) / 255.f; - mLineColor[2] = (((int) col >> 8 ) & 0xFF ) / 255.f; - mLineColor[3] = (((int) col ) & 0xFF ) / 255.f; -} - -void plot3_impl::setColor(float r, float g, float b) -{ - mLineColor[0] = clampTo01(r); - mLineColor[1] = clampTo01(g); - mLineColor[2] = clampTo01(b); - mLineColor[3] = 1.0f; -} - -GLuint plot3_impl::vbo() const { return mMainVBO; } - -size_t plot3_impl::size() const { return mMainVBOsize; } - -void plot3_impl::render(int pWindowId, int pX, int pY, int pVPW, int pVPH) -{ - float range_x = xmax() - xmin(); - float range_y = ymax() - ymin(); - float range_z = zmax() - zmin(); - // set scale to zero if input is constant array - // otherwise compute scale factor by standard equation - float graph_scale_x = std::abs(range_x) < 1.0e-3 ? 0.0f : 2/(xmax() - xmin()); - float graph_scale_y = std::abs(range_y) < 1.0e-3 ? 0.0f : 2/(ymax() - ymin()); - float graph_scale_z = std::abs(range_z) < 1.0e-3 ? 0.0f : 2/(zmax() - zmin()); - - CheckGL("Begin plot3_impl::render"); - - float coor_offset_x = ( -xmin() * graph_scale_x); - float coor_offset_y = ( -ymin() * graph_scale_y); - float coor_offset_z = ( -zmin() * graph_scale_z); - - glm::mat4 model = glm::rotate(glm::mat4(1.0f), -glm::radians(90.f), glm::vec3(1,0,0)) * glm::translate(glm::mat4(1.f), glm::vec3(-1 + coor_offset_x , -1 + coor_offset_y, -1 + coor_offset_z)) * glm::scale(glm::mat4(1.f), glm::vec3(1.0f * graph_scale_x, -1.0f * graph_scale_y, 1.0f * graph_scale_z)); - glm::mat4 view = glm::lookAt(glm::vec3(-1,0.5f,1.0f), glm::vec3(1,-1,-1),glm::vec3(0,1,0)); - glm::mat4 projection = glm::ortho(-2.f, 2.f, -2.f, 2.f, -1.1f, 100.f); - glm::mat4 mvp = projection * view * model; - glm::mat4 transform = mvp; - - if(mPlotType != fg::FG_SCATTER) { - glUseProgram(mPlot3Program); - GLfloat range[] = {xmax(), xmin(), ymax(), ymin(), zmax(), zmin()}; - - glUniform2fv(mPlot3RangeIndex, 3, range); - glUniformMatrix4fv(mPlot3TMatIndex, 1, GL_FALSE, glm::value_ptr(transform)); - - bindResources(pWindowId); - glDrawArrays(GL_LINE_STRIP, 0, mNumPoints); - unbindResources(); - glUseProgram(0); - } - - if(mMarkerType != fg::FG_NONE) { - glEnable(GL_PROGRAM_POINT_SIZE); - glUseProgram(mMarkerProgram); - - glUniformMatrix4fv(mSpriteTMatIndex, 1, GL_FALSE, glm::value_ptr(transform)); - glUniform4fv(mMarkerColIndex, 1, WHITE); - glUniform1i(mMarkerTypeIndex, mMarkerType); - - bindResources(pWindowId); - glDrawArrays(GL_POINTS, 0, mNumPoints); - unbindResources(); - glUseProgram(0); - glDisable(GL_PROGRAM_POINT_SIZE); - } - - /* render graph border and axes */ - renderChart(pWindowId, pX, pY, pVPW, pVPH); - - CheckGL("End plot3_impl::render"); -} - -} - - -namespace fg -{ - -Plot3::Plot3(unsigned pNumPoints, dtype pDataType, PlotType pPlotType, MarkerType pMarkerType) -{ - value = new internal::_Plot3(pNumPoints, pDataType, pPlotType, pMarkerType); -} - -Plot3::Plot3(const Plot3& other) -{ - value = new internal::_Plot3(*other.get()); -} - -Plot3::~Plot3() -{ - delete value; -} - -void Plot3::setColor(fg::Color col) -{ - value->setColor(col); -} - -void Plot3::setColor(float r, float g, float b) -{ - value->setColor(r, g, b); -} - -void Plot3::setAxesLimits(float pXmax, float pXmin, float pYmax, float pYmin, float pZmax, float pZmin) -{ - value->setAxesLimits(pXmax, pXmin, pYmax, pYmin, pZmax, pZmin); -} - -void Plot3::setAxesTitles(const char* pXTitle, const char* pYTitle, const char* pZTitle) -{ - value->setAxesTitles(pXTitle, pYTitle, pZTitle); -} - -float Plot3::xmax() const -{ - return value->xmax(); -} - -float Plot3::xmin() const -{ - return value->xmin(); -} - -float Plot3::ymax() const -{ - return value->ymax(); -} - -float Plot3::ymin() const -{ - return value->ymin(); -} - -float Plot3::zmax() const -{ - return value->zmax(); -} - -float Plot3::zmin() const -{ - return value->zmin(); -} - -unsigned Plot3::vbo() const -{ - return value->vbo(); -} - -unsigned Plot3::size() const -{ - return (unsigned)value->size(); -} - -internal::_Plot3* Plot3::get() const -{ - return value; -} - -} diff --git a/src/plot3.hpp b/src/plot3.hpp deleted file mode 100644 index 9da7528e..00000000 --- a/src/plot3.hpp +++ /dev/null @@ -1,126 +0,0 @@ -/******************************************************* -* 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 - -namespace internal -{ - -class plot3_impl : public Chart3D { - protected: - /* plot points characteristics */ - GLuint mNumPoints; - GLenum mDataType; - float mLineColor[4]; - fg::MarkerType mMarkerType; - fg::PlotType mPlotType; - /* OpenGL Objects */ - GLuint mMainVBO; - size_t mMainVBOsize; - size_t mIndexVBOsize; - GLuint mMarkerProgram; - GLuint mPlot3Program; - /* shared variable index locations */ - GLuint mPointIndex; - GLuint mMarkerTypeIndex; - GLuint mMarkerColIndex; - GLuint mSpriteTMatIndex; - GLuint mPlot3PointIndex; - GLuint mPlot3TMatIndex; - GLuint mPlot3RangeIndex; - - std::map mVAOMap; - - /* bind and unbind helper functions - * for rendering resources */ - void bindResources(int pWindowId); - void unbindResources() const; - - public: - plot3_impl(unsigned pNumPoints, fg::dtype pDataType, fg::PlotType pPlotType, fg::MarkerType pMarkerType); - ~plot3_impl(); - - void setColor(fg::Color col); - void setColor(float r, float g, float b); - GLuint vbo() const; - size_t size() const; - - void render(int pWindowId, int pX, int pY, int pViewPortWidth, int pViewPortHeight); -}; - -class _Plot3 { - private: - std::shared_ptr plt; - - public: - _Plot3(unsigned pNumPoints, fg::dtype pDataType, fg::PlotType pPlotType=fg::FG_LINE, fg::MarkerType pMarkerType=fg::FG_NONE) { - plt = std::make_shared(pNumPoints, pDataType, pPlotType, pMarkerType); - } - - inline const std::shared_ptr& impl() const { - return plt; - } - - inline void setColor(fg::Color col) { - plt->setColor(col); - } - - inline void setColor(float r, float g, float b) { - plt->setColor(r, g, b); - } - - inline void setAxesLimits(float pXmax, float pXmin, float pYmax, float pYmin, float pZmax, float pZmin) { - plt->setAxesLimits(pXmax, pXmin, pYmax, pYmin, pZmax, pZmin); - } - - inline void setAxesTitles(const char* pXTitle, const char* pYTitle, const char* pZTitle) - { - plt->setAxesTitles(pXTitle, pYTitle, pZTitle); - } - - inline float xmax() const { - return plt->xmax(); - } - - inline float xmin() const { - return plt->xmin(); - } - - inline float ymax() const { - return plt->ymax(); - } - - inline float ymin() const { - return plt->ymin(); - } - - inline float zmax() const { - return plt->zmax(); - } - - inline float zmin() const { - return plt->zmin(); - } - - inline GLuint vbo() const { - return plt->vbo(); - } - - inline size_t size() const { - return plt->size(); - } -}; - -} diff --git a/src/sdl/window.cpp b/src/sdl/window.cpp deleted file mode 100644 index 11787190..00000000 --- a/src/sdl/window.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/******************************************************* -* 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 - -#ifndef OS_WIN -#include -#else -#include -#endif - -#include - -#define SDL_THROW_ERROR(msg, err) \ - throw fg::Error("Window constructor", __LINE__, msg, err); - -namespace wtk -{ - -Widget::Widget() - : mWindow(nullptr), mClose(false) -{ -} - -Widget::Widget(int pWidth, int pHeight, const char* pTitle, const Widget* pWindow, const bool invisible) - : mWindow(nullptr), mClose(false) -{ - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - std::cerr << "ERROR: SDL wasn't able to initalize\n"; - SDL_THROW_ERROR("SDL initilization failed", fg::FG_ERR_GL_ERROR) - } - - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); - if (pWindow != nullptr) { - pWindow->makeContextCurrent(); - SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); - } else { - //SDL_GL_MakeCurrent(NULL, NULL); - SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 0); - } - - mWindow = SDL_CreateWindow( - pTitle, - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - pWidth, pHeight, - (invisible ? SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN - : SDL_WINDOW_OPENGL) | SDL_WINDOW_RESIZABLE - ); - mContext = SDL_GL_CreateContext(mWindow); - - if (mWindow==NULL) { - std::cerr<<"Error: Could not Create SDL Window!\n"; - SDL_THROW_ERROR("sdl window creation failed", fg::FG_ERR_GL_ERROR) - } - - SDL_GL_SetSwapInterval(1); - mWindowId = SDL_GetWindowID(mWindow); -} - -Widget::~Widget() -{ - SDL_DestroyWindow(mWindow); - SDL_GL_DeleteContext(mContext); -} - -SDL_Window* Widget::getNativeHandle() const -{ - return mWindow; -} - -void Widget::makeContextCurrent() const -{ - SDL_GL_MakeCurrent(mWindow, mContext); -} - -long long Widget::getGLContextHandle() -{ -#ifdef OS_WIN - return reinterpret_cast(wglGetCurrentContext()); -#endif -#ifdef OS_LNX - return reinterpret_cast(glXGetCurrentContext()); -#endif -} - -long long Widget::getDisplayHandle() -{ -#ifdef OS_WIN - return reinterpret_cast(wglGetCurrentDC()); -#endif -#ifdef OS_LNX - return reinterpret_cast(glXGetCurrentDisplay()); -#endif -} - -void Widget::getFrameBufferSize(int* pW, int* pH) -{ - /* FIXME this needs to be framebuffer size */ - SDL_GetWindowSize(mWindow, pW, pH); -} - -void Widget::setTitle(const char* pTitle) -{ - SDL_SetWindowTitle(mWindow, pTitle); -} - -void Widget::setPos(int pX, int pY) -{ - SDL_SetWindowPosition(mWindow, pX, pY); -} - -void Widget::setSize(unsigned pW, unsigned pH) -{ - SDL_SetWindowSize(mWindow, pW, pH); -} - -void Widget::swapBuffers() -{ - SDL_GL_SwapWindow(mWindow); -} - -void Widget::hide() -{ - mClose = true; - SDL_HideWindow(mWindow); -} - -void Widget::show() -{ - mClose = false; - SDL_ShowWindow(mWindow); -} - -bool Widget::close() -{ - return mClose; -} - -void Widget::resetCloseFlag() -{ - if(mClose==true) { - show(); - } -} - -void Widget::pollEvents() -{ - SDL_Event evnt; - SDL_PollEvent(&evnt); - - /* handle window events that are triggered - when 'this' window was in focus - */ - if (evnt.type == SDL_WINDOWEVENT && evnt.window.windowID == mWindowId) { - switch(evnt.window.event) { - case SDL_WINDOWEVENT_CLOSE: - hide(); - break; - } - } - - /* handle keyboard press down events that are triggered - when 'this' window was in focus - */ - if (evnt.type == SDL_KEYDOWN && evnt.key.windowID == mWindowId) { - switch(evnt.key.keysym.sym) { - case SDLK_ESCAPE: - hide(); - break; - } - } -} - -} diff --git a/src/surface.cpp b/src/surface.cpp deleted file mode 100644 index d5d349e7..00000000 --- a/src/surface.cpp +++ /dev/null @@ -1,414 +0,0 @@ -/******************************************************* - * 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 - -using namespace std; - -static const char *gMarkerVertexShaderSrc = -"#version 330\n" -"in vec3 point;\n" -"uniform vec2 minmaxs[3];\n" -"out vec4 hpoint;\n" -"uniform mat4 transform;\n" -"void main(void) {\n" -" gl_Position = transform * vec4(point.xyz, 1);\n" -" hpoint=vec4(point.xyz,1);\n" -" gl_PointSize=10;\n" -"}"; - -const char *gSurfFragmentShaderSrc = -"#version 330\n" -"uniform vec2 minmaxs[3];\n" -"in vec4 hpoint;\n" -"out vec4 outputColor;\n" -"vec3 hsv2rgb(vec3 c){\n" -" vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n" -" vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n" -" return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n" -"}\n" -"void main(void) {\n" -" bool nin_bounds = (hpoint.x > minmaxs[0].x || hpoint.x < minmaxs[0].y ||\n" -" hpoint.y > minmaxs[1].x || hpoint.y < minmaxs[1].y || hpoint.z < minmaxs[2].y);\n" -" float height = (minmaxs[2].x- hpoint.z)/(minmaxs[2].x-minmaxs[2].y);\n" -" if(nin_bounds) discard;\n" -" outputColor = vec4(hsv2rgb(vec3(height, 1.f, 1.f)),1);\n" -"}"; - -static const char *gMarkerSpriteFragmentShaderSrc = -"#version 330\n" -"uniform int marker_type;\n" -"uniform vec4 line_color;\n" -"in vec4 hpoint;\n" -"out vec4 outputColor;\n" -"void main(void) {\n" -" vec4 unused = hpoint;\n" -" float dist = sqrt( (gl_PointCoord.x - 0.5) * (gl_PointCoord.x-0.5) + (gl_PointCoord.y-0.5) * (gl_PointCoord.y-0.5) );\n" -" bool in_bounds;\n" -" switch(marker_type) {\n" -" case 1:\n" -" in_bounds = dist < 0.3;\n" -" break;\n" -" case 2:\n" -" in_bounds = ( (dist > 0.3) && (dist<0.5) );\n" -" break;\n" -" case 3:\n" -" in_bounds = ((gl_PointCoord.x < 0.15) || (gl_PointCoord.x > 0.85)) ||\n" -" ((gl_PointCoord.y < 0.15) || (gl_PointCoord.y > 0.85));\n" -" break;\n" -" case 4:\n" -" in_bounds = (2*(gl_PointCoord.x - 0.25) - (gl_PointCoord.y + 0.5) < 0) && (2*(gl_PointCoord.x - 0.25) + (gl_PointCoord.y + 0.5) > 1);\n" -" break;\n" -" case 5:\n" -" in_bounds = abs((gl_PointCoord.x - 0.5) + (gl_PointCoord.y - 0.5) ) < 0.13 ||\n" -" abs((gl_PointCoord.x - 0.5) - (gl_PointCoord.y - 0.5) ) < 0.13 ;\n" -" break;\n" -" case 6:\n" -" in_bounds = abs((gl_PointCoord.x - 0.5)) < 0.07 ||\n" -" abs((gl_PointCoord.y - 0.5)) < 0.07;\n" -" break;\n" -" case 7:\n" -" in_bounds = abs((gl_PointCoord.x - 0.5) + (gl_PointCoord.y - 0.5) ) < 0.07 ||\n" -" abs((gl_PointCoord.x - 0.5) - (gl_PointCoord.y - 0.5) ) < 0.07 ||\n" -" abs((gl_PointCoord.x - 0.5)) < 0.07 ||\n" -" abs((gl_PointCoord.y - 0.5)) < 0.07;\n" -" break;\n" -" case 8:\n" -" in_bounds = true;\n" -" break;\n" -" default:\n" -" in_bounds = true;\n" -" }\n" -" if(!in_bounds)\n" -" discard;\n" -" else\n" -" outputColor = line_color;\n" -"}"; - - -namespace internal -{ - -void surface_impl::bindResources(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 plot vertices - glEnableVertexAttribArray(mPointIndex); - glBindBuffer(GL_ARRAY_BUFFER, mMainVBO); - glVertexAttribPointer(mPointIndex, 3, mDataType, GL_FALSE, 0, 0); - //attach indices - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexVBO); - glBindVertexArray(0); - /* store the vertex array object corresponding to - * the window instance in the map */ - mVAOMap[pWindowId] = vao; - } - - glBindVertexArray(mVAOMap[pWindowId]); -} - -void surface_impl::unbindResources() const { glBindVertexArray(0); } - -void generate_grid_indices(unsigned short rows, unsigned short cols, unsigned short *indices){ - unsigned short idx = 0; - for(unsigned short r = 0; r < rows-1; ++r){ - for(unsigned short c = 0; c < cols*2; ++c){ - unsigned short i = c + (r * (cols*2)); - - if(c == cols * 2 - 1) { - *indices++ = idx; - }else{ - *indices++ = idx; - if(i%2 == 0){ - idx += cols; - } else { - idx -= (r%2 == 0) ? (cols-1) : (cols+1); - } - } - } - } -} - -surface_impl::surface_impl(unsigned pNumXPoints, unsigned pNumYPoints, - fg::dtype pDataType, fg::MarkerType pMarkerType) - : Chart3D(), mNumXPoints(pNumXPoints),mNumYPoints(pNumYPoints), - mDataType(gl_dtype(pDataType)), mMainVBO(0), mMainVBOsize(0), - mIndexVBO(0), mIndexVBOsize(0), mPointIndex(0), mMarkerTypeIndex(0), - mMarkerColIndex(0), mSpriteTMatIndex(0), mSurfPointIndex(0), - mSurfTMatIndex(0), mSurfRangeIndex(0) -{ - CheckGL("Begin surface_impl::surface_impl"); - mPointIndex = mBorderAttribPointIndex; - mMarkerType = pMarkerType; - mSurfProgram = initShaders(gMarkerVertexShaderSrc, gSurfFragmentShaderSrc); - mMarkerProgram = initShaders(gMarkerVertexShaderSrc, gMarkerSpriteFragmentShaderSrc); - - mSurfPointIndex = glGetAttribLocation (mSurfProgram, "point"); - mSurfTMatIndex = glGetUniformLocation(mSurfProgram, "transform"); - mSurfRangeIndex = glGetUniformLocation(mSurfProgram, "minmaxs"); - - mMarkerTypeIndex = glGetUniformLocation(mMarkerProgram, "marker_type"); - mMarkerColIndex = glGetUniformLocation(mMarkerProgram, "line_color"); - mSpriteTMatIndex = glGetUniformLocation(mMarkerProgram, "transform"); - - unsigned total_points = 3*(mNumXPoints * mNumYPoints); - - mIndexVBOsize = (2 * mNumYPoints) * (mNumXPoints - 1); - unsigned short* indices = new unsigned short[mIndexVBOsize]; - generate_grid_indices(mNumXPoints, mNumYPoints, indices); - mIndexVBO = createBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexVBOsize, NULL, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexVBO); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, mIndexVBOsize * sizeof(unsigned short), indices); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - delete[] indices; - - // buffersubdata calls on mMainVBO - // will only update the points data - switch(mDataType) { - case GL_FLOAT: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(float); - break; - case GL_INT: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(int); - break; - case GL_UNSIGNED_INT: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(unsigned); - break; - case GL_UNSIGNED_BYTE: - mMainVBO = createBuffer(GL_ARRAY_BUFFER, total_points, NULL, GL_DYNAMIC_DRAW); - mMainVBOsize = total_points*sizeof(unsigned char); - break; - default: fg::TypeError("Plot::Plot", __LINE__, 1, pDataType); - } - CheckGL("End surface_impl::surface_impl"); -} - -surface_impl::~surface_impl() -{ - CheckGL("Begin Plot::~Plot"); - glDeleteBuffers(1, &mMainVBO); - CheckGL("End Plot::~Plot"); -} - -void surface_impl::setColor(fg::Color col) -{ - mLineColor[0] = (((int) col >> 24 ) & 0xFF ) / 255.f; - mLineColor[1] = (((int) col >> 16 ) & 0xFF ) / 255.f; - mLineColor[2] = (((int) col >> 8 ) & 0xFF ) / 255.f; - mLineColor[3] = (((int) col ) & 0xFF ) / 255.f; -} - -void surface_impl::setColor(float r, float g, float b) -{ - mLineColor[0] = clampTo01(r); - mLineColor[1] = clampTo01(g); - mLineColor[2] = clampTo01(b); - mLineColor[3] = 1.0f; -} - -GLuint surface_impl::vbo() const { return mMainVBO; } - -size_t surface_impl::size() const { return mMainVBOsize; } - -void surface_impl::render(int pWindowId, int pX, int pY, int pVPW, int pVPH) -{ - float range_x = xmax() - xmin(); - float range_y = ymax() - ymin(); - float range_z = zmax() - zmin(); - // set scale to zero if input is constant array - // otherwise compute scale factor by standard equation - float graph_scale_x = std::abs(range_x) < 1.0e-3 ? 0.0f : 2/(xmax() - xmin()); - float graph_scale_y = std::abs(range_y) < 1.0e-3 ? 0.0f : 2/(ymax() - ymin()); - float graph_scale_z = std::abs(range_z) < 1.0e-3 ? 0.0f : 2/(zmax() - zmin()); - - CheckGL("Begin surface_impl::render"); - - float coor_offset_x = ( -xmin() * graph_scale_x); - float coor_offset_y = ( -ymin() * graph_scale_y); - float coor_offset_z = ( -zmin() * graph_scale_z); - - glm::mat4 model = glm::rotate(glm::mat4(1.0f), -glm::radians(90.f), glm::vec3(0,1,0)) * glm::rotate(glm::mat4(1.0f), -glm::radians(90.f), glm::vec3(1,0,0)) * glm::translate(glm::mat4(1.f), glm::vec3(-1 + coor_offset_x , -1 + coor_offset_y, -1 + coor_offset_z)) * glm::scale(glm::mat4(1.f), glm::vec3(1.0f * graph_scale_x, 1.0f * graph_scale_y, 1.0f * graph_scale_z)); - glm::mat4 view = glm::lookAt(glm::vec3(-1,0.5f,1.0f), glm::vec3(1,-1,-1),glm::vec3(0,1,0)); - glm::mat4 projection = glm::ortho(-2.f, 2.f, -2.f, 2.f, -1.1f, 100.f); - glm::mat4 mvp = projection * view * model; - glm::mat4 transform = mvp; - renderGraph(pWindowId, transform); - - /* render graph border and axes */ - renderChart(pWindowId, pX, pY, pVPW, pVPH); - - CheckGL("End surface_impl::render"); -} - -void surface_impl::renderGraph(int pWindowId, glm::mat4 transform) -{ - CheckGL("Begin surface_impl::renderGraph"); - bindSurfProgram(); - GLfloat range[] = {xmax(), xmin(), ymax(), ymin(), zmax(), zmin()}; - - glUniform2fv(surfRangeIndex(), 3, range); - glUniformMatrix4fv(surfMatIndex(), 1, GL_FALSE, glm::value_ptr(transform)); - - bindResources(pWindowId); - glDrawElements(GL_TRIANGLE_STRIP, mIndexVBOsize, GL_UNSIGNED_SHORT, (void*)0 ); - unbindResources(); - unbindSurfProgram(); - - if(mMarkerType != fg::FG_NONE) { - glEnable(GL_PROGRAM_POINT_SIZE); - glUseProgram(mMarkerProgram); - - glUniformMatrix4fv(spriteMatIndex(), 1, GL_FALSE, glm::value_ptr(transform)); - glUniform4fv(markerColIndex(), 1, WHITE); - glUniform1i(markerTypeIndex(), mMarkerType); - - bindResources(pWindowId); - glDrawElements(GL_POINTS, mIndexVBOsize, GL_UNSIGNED_SHORT, (void*)0 ); - unbindResources(); - glUseProgram(0); - glDisable(GL_PROGRAM_POINT_SIZE); - } - CheckGL("End surface_impl::renderGraph"); -} - -GLuint surface_impl::markerTypeIndex() const { return mMarkerTypeIndex; } - -GLuint surface_impl::spriteMatIndex() const { return mSpriteTMatIndex; } - -GLuint surface_impl::markerColIndex() const { return mMarkerColIndex; } - -GLuint surface_impl::surfMatIndex() const { return mSurfTMatIndex; } - -GLuint surface_impl::surfRangeIndex() const { return mSurfRangeIndex; } - -void surface_impl::bindSurfProgram() const { glUseProgram(mSurfProgram); } - -void surface_impl::unbindSurfProgram() const { glUseProgram(0); } - - -void scatter3_impl::renderGraph(int pWindowId, glm::mat4 transform) -{ - if(mMarkerType != fg::FG_NONE) { - glEnable(GL_PROGRAM_POINT_SIZE); - glUseProgram(mMarkerProgram); - - glUniformMatrix4fv(spriteMatIndex(), 1, GL_FALSE, glm::value_ptr(transform)); - glUniform4fv(markerColIndex(), 1, mLineColor); - glUniform1i(markerTypeIndex(), mMarkerType); - - bindResources(pWindowId); - glDrawElements(GL_POINTS, mIndexVBOsize, GL_UNSIGNED_SHORT, (void*)0); - unbindResources(); - glUseProgram(0); - glDisable(GL_PROGRAM_POINT_SIZE); - } -} - -} - -namespace fg -{ - -Surface::Surface(unsigned pNumXPoints, unsigned pNumYPoints, dtype pDataType, PlotType pPlotType, MarkerType pMarkerType) -{ - value = new internal::_Surface(pNumXPoints, pNumYPoints, pDataType, pPlotType, pMarkerType); -} - -Surface::Surface(const Surface& other) -{ - value = new internal::_Surface(*other.get()); -} - -Surface::~Surface() -{ - delete value; -} - -void Surface::setColor(fg::Color col) -{ - value->setColor(col); -} - -void Surface::setColor(float r, float g, float b) -{ - value->setColor(r, g, b); -} - -void Surface::setAxesLimits(float pXmax, float pXmin, float pYmax, float pYmin, float pZmax, float pZmin) -{ - value->setAxesLimits(pXmax, pXmin, pYmax, pYmin, pZmax, pZmin); -} - -void Surface::setAxesTitles(const char* pXTitle, const char* pYTitle, const char* pZTitle) -{ - value->setAxesTitles(pXTitle, pYTitle, pZTitle); -} - -float Surface::xmax() const -{ - return value->xmax(); -} - -float Surface::xmin() const -{ - return value->xmin(); -} - -float Surface::ymax() const -{ - return value->ymax(); -} - -float Surface::ymin() const -{ - return value->ymin(); -} - -float Surface::zmax() const -{ - return value->zmax(); -} - -float Surface::zmin() const -{ - return value->zmin(); -} - -unsigned Surface::vbo() const -{ - return value->vbo(); -} - -unsigned Surface::size() const -{ - return (unsigned)value->size(); -} - -internal::_Surface* Surface::get() const -{ - return value; -} - -} diff --git a/src/surface.hpp b/src/surface.hpp deleted file mode 100644 index 7f0288de..00000000 --- a/src/surface.hpp +++ /dev/null @@ -1,155 +0,0 @@ -/******************************************************* -* 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 - -namespace internal -{ - -class surface_impl : public Chart3D { - protected: - /* plot points characteristics */ - GLuint mNumXPoints; - GLuint mNumYPoints; - GLenum mDataType; - float mLineColor[4]; - fg::MarkerType mMarkerType; - /* OpenGL Objects */ - GLuint mMainVBO; - size_t mMainVBOsize; - GLuint mIndexVBO; - size_t mIndexVBOsize; - GLuint mMarkerProgram; - GLuint mSurfProgram; - /* shared variable index locations */ - GLuint mPointIndex; - GLuint mMarkerTypeIndex; - GLuint mMarkerColIndex; - GLuint mSpriteTMatIndex; - GLuint mSurfPointIndex; - GLuint mSurfTMatIndex; - GLuint mSurfRangeIndex; - - std::map mVAOMap; - - /* bind and unbind helper functions - * for rendering resources */ - void bindResources(int pWindowId); - void unbindResources() const; - void bindSurfProgram() const; - void unbindSurfProgram() const; - GLuint markerTypeIndex() const; - GLuint spriteMatIndex() const; - GLuint markerColIndex() const; - GLuint surfRangeIndex() const; - GLuint surfMatIndex() const; - virtual void renderGraph(int pWindowId, glm::mat4 transform); - - public: - surface_impl(unsigned pNumXpoints, unsigned pNumYpoints, fg::dtype pDataType, fg::MarkerType pMarkerType); - ~surface_impl(); - - void setColor(fg::Color col); - void setColor(float r, float g, float b); - GLuint vbo() const; - size_t size() const; - - void render(int pWindowId, int pX, int pY, int pViewPortWidth, int pViewPortHeight); -}; - -class scatter3_impl : public surface_impl { - private: - void renderGraph(int pWindowId, glm::mat4 transform); - - public: - scatter3_impl(unsigned pNumXPoints, unsigned pNumYPoints, fg::dtype pDataType, fg::MarkerType pMarkerType=fg::FG_NONE) - : surface_impl(pNumXPoints, pNumYPoints, pDataType, pMarkerType) {} - - ~scatter3_impl() {} -}; - -class _Surface { - private: - std::shared_ptr plt; - - public: - _Surface(unsigned pNumXPoints, unsigned pNumYPoints, fg::dtype pDataType, fg::PlotType pPlotType=fg::FG_SURFACE, fg::MarkerType pMarkerType=fg::FG_NONE) { - switch(pPlotType){ - case(fg::FG_SURFACE): - plt = std::make_shared(pNumXPoints, pNumYPoints, pDataType, pMarkerType); - break; - case(fg::FG_SCATTER): - plt = std::make_shared(pNumXPoints, pNumYPoints, pDataType, pMarkerType); - break; - default: - plt = std::make_shared(pNumXPoints, pNumYPoints, pDataType, pMarkerType); - }; - } - - inline const std::shared_ptr& impl() const { - return plt; - } - - inline void setColor(fg::Color col) { - plt->setColor(col); - } - - inline void setColor(float r, float g, float b) { - plt->setColor(r, g, b); - } - - inline void setAxesLimits(float pXmax, float pXmin, float pYmax, float pYmin, float pZmax, float pZmin) { - plt->setAxesLimits(pXmax, pXmin, pYmax, pYmin, pZmax, pZmin); - } - - inline void setAxesTitles(const char* pXTitle, const char* pYTitle, const char* pZTitle) - { - plt->setAxesTitles(pXTitle, pYTitle, pZTitle); - } - - inline float xmax() const { - return plt->xmax(); - } - - inline float xmin() const { - return plt->xmin(); - } - - inline float ymax() const { - return plt->ymax(); - } - - inline float ymin() const { - return plt->ymin(); - } - - inline float zmax() const { - return plt->zmax(); - } - - inline float zmin() const { - return plt->zmin(); - } - - inline GLuint vbo() const { - return plt->vbo(); - } - - inline size_t size() const { - return plt->size(); - } -}; - -} diff --git a/src/window.hpp b/src/window.hpp deleted file mode 100644 index c4153dfa..00000000 --- a/src/window.hpp +++ /dev/null @@ -1,206 +0,0 @@ -/******************************************************* -* 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 - -#if defined(USE_GLFW) -#include -#elif defined(USE_SDL) -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace internal -{ - -class window_impl { - private: - long long mCxt; - long long mDsp; - int mID; - int mWidth; - int mHeight; - wtk::Widget* mWindow; - int mRows; - int mCols; - int mCellWidth; - int mCellHeight; - GLEWContext* mGLEWContext; - - std::shared_ptr mFont; - std::shared_ptr mCMap; - - GLuint mColorMapUBO; - GLuint mUBOSize; - - public: - window_impl(int pWidth, int pHeight, const char* pTitle, - std::weak_ptr pWindow, const bool invisible=false); - - ~window_impl(); - - void setFont(const std::shared_ptr& pFont); - void setTitle(const char* pTitle); - void setPos(int pX, int pY); - void setSize(unsigned pWidth, unsigned pHeight); - void setColorMap(fg::ColorMap cmap); - - long long context() const; - long long display() const; - int width() const; - int height() const; - GLEWContext* glewContext() const; - const wtk::Widget* get() const; - const std::shared_ptr& colorMapPtr() const; - - void hide(); - void show(); - bool close(); - - void draw(const std::shared_ptr& pRenderable); - - void grid(int pRows, int pCols); - - void draw(int pColId, int pRowId, - const std::shared_ptr& pRenderable, - const char* pTitle); - - void swapBuffers(); -}; - -void MakeContextCurrent(const window_impl* pWindow); - -class _Window { - private: - std::shared_ptr wnd; - - _Window() {} - - public: - - _Window(int pWidth, int pHeight, const char* pTitle, - const _Window* pWindow, const bool invisible = false) { - if (pWindow) { - wnd = std::make_shared(pWidth, pHeight, pTitle, - pWindow->impl(), invisible); - } else { - std::shared_ptr other; - wnd = std::make_shared(pWidth, pHeight, pTitle, - other, invisible); - } - } - - inline const std::shared_ptr& impl () const { - return wnd; - } - - inline void setFont (_Font* pFont) { - wnd->setFont (pFont->impl()); - } - - inline void setTitle(const char* pTitle) { - wnd->setTitle(pTitle); - } - - inline void setPos(int pX, int pY) { - wnd->setPos(pX, pY); - } - - inline void setSize(unsigned pWidth, int pHeight) { - wnd->setSize(pWidth, pHeight); - } - - inline void setColorMap(fg::ColorMap cmap) { - wnd->setColorMap(cmap); - } - - inline long long context() const { - return wnd->context() ; - } - - inline long long display() const { - return wnd->display(); - } - - inline int width() const { - return wnd->width(); - } - - inline int height() const { - return wnd->height(); - } - - inline void makeCurrent() { - MakeContextCurrent(wnd.get()); - } - - inline void hide() { - wnd->hide(); - } - - inline void show() { - wnd->show(); - } - - inline bool close() { - return wnd->close(); - } - - inline void draw(_Image* pImage, const bool pKeepAspectRatio) { - pImage->keepAspectRatio(pKeepAspectRatio); - wnd->draw(pImage->impl()) ; - } - - inline void draw(const _Plot* pPlot) { - wnd->draw(pPlot->impl()) ; - } - - inline void draw(const _Plot3* pPlot3) { - wnd->draw(pPlot3->impl()) ; - } - - inline void draw(const _Surface* pSurface) { - wnd->draw(pSurface->impl()) ; - } - - inline void draw(const _Histogram* pHist) { - wnd->draw(pHist->impl()) ; - } - - inline void swapBuffers() { - wnd->swapBuffers(); - } - - inline void grid(int pRows, int pCols) { - wnd->grid(pRows, pCols); - } - - template - void draw(int pColId, int pRowId, T* pRenderable, const char* pTitle) { - wnd->draw(pColId, pRowId, pRenderable->impl(), pTitle); - } - - void draw(int pColId, int pRowId, _Image* pRenderable, const char* pTitle, const bool pKeepAspectRatio) { - pRenderable->keepAspectRatio(pKeepAspectRatio); - wnd->draw(pColId, pRowId, pRenderable->impl(), pTitle); - } -}; - -}