├── .gitignore ├── LICENSE.md ├── README.md ├── images ├── demo0.png └── demo1.gif ├── sr_graph.h └── test ├── Makefile ├── Makefile.linux ├── sr_graph_test.sln ├── sr_graph_test.vcxproj ├── sr_graph_test.vcxproj.filters └── src ├── Renderer.cpp ├── Renderer.h ├── Utilities.cpp ├── Utilities.h ├── libs ├── gl3w │ ├── gl3w.cpp │ ├── gl3w.h │ └── glcorearb.h └── glfw │ ├── include │ └── GLFW │ │ ├── glfw3.h │ │ └── glfw3native.h │ ├── lib-mac │ └── libglfw3.a │ ├── lib-win-vc2015-64 │ ├── glfw3.dll │ ├── glfw3.lib │ └── glfw3dll.lib │ └── lib-win-vc2015 │ ├── glfw3.dll │ ├── glfw3.lib │ └── glfw3dll.lib └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.xcodeproj/ 2 | /resources/ 3 | /src/ 4 | build/ -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | *This software is available under 2 licenses -- choose whichever you prefer.* 3 | 4 | **ALTERNATIVE A - MIT License** 5 | Copyright (c) 2017 Simon Rodriguez 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | of the Software, and to permit persons to whom the Software is furnished to do 11 | so, subject to the following conditions: 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | **ALTERNATIVE B - Public Domain (www.unlicense.org)** 23 | This is free and unencumbered software released into the public domain. 24 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 25 | software, either in source code form or as a compiled binary, for any purpose, 26 | commercial or non-commercial, and by any means. 27 | In jurisdictions that recognize copyright laws, the author or authors of this 28 | software dedicate any and all copyright interest in the software to the public 29 | domain. We make this dedication for the benefit of the public at large and to 30 | the detriment of our heirs and successors. We intend this dedication to be an 31 | overt act of relinquishment in perpetuity of all present and future rights to 32 | this software under copyright law. 33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 34 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 35 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 36 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 37 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 38 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sr_graph 2 | A simple, one-file, header-only, C++ utility for graphs, curves and histograms. 3 | 4 | ![](images/demo1.gif) 5 | 6 | See sr_graph.h for documentation and license. 7 | Another example: 8 | 9 | ![](images/demo0.png) 10 | -------------------------------------------------------------------------------- /images/demo0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosua20/sr_graph/e96e3ac356f0211bd0a0c5a1fd2bd5bcba3fff46/images/demo0.png -------------------------------------------------------------------------------- /images/demo1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosua20/sr_graph/e96e3ac356f0211bd0a0c5a1fd2bd5bcba3fff46/images/demo1.gif -------------------------------------------------------------------------------- /sr_graph.h: -------------------------------------------------------------------------------- 1 | /* sr_graph - v1.0 - public domain plot tracer ; 2 | no warranties implied, use at your own risk. 3 | 4 | Do this: 5 | #define SRG_IMPLEMENTATION_SR_GRAPH 6 | before you include this file in *one* C++ file to create the implementation. 7 | You will need to include OpenGL headers (or glew, gl3w,...) before including 8 | this one. In other files you should simply include "sr_graph.h" without using 9 | the above define. 10 | 11 | // i.e. it should look like this: 12 | #include // or glew header, gl3w header,... 13 | #include ... 14 | #include ... 15 | #define SRG_IMPLEMENTATION_SR_GRAPH 16 | #include "srg_graph.h" 17 | 18 | In the file where the implementation is activated, SR_GRAPH_LOGGING can be 19 | defined to log errors in OpenGL setup (stdio.h will be included). 20 | 21 | Usage: 22 | Make sure that an OpenGL context has been setup before calling any sr_graph 23 | functions. All colors are defined by their red, green, blue components 24 | taking values in [0.0,1.0]. 25 | Start by creating a graph using: 26 | 27 | setup(min x, max x, min y, max y, ratio, margin, red, green, blue); 28 | 29 | You specify the bounds of the graph (minimal and maximal values on both 30 | axes), the screen ratio, the margin (between 0 - no margin - and 1 - no 31 | graph -), and the background color. This will return an integer ID that 32 | you will use as a reference to the graph for later calls. 33 | 34 | The graph can be customized by adding axes with arrows (automatically 35 | oriented toward the increasing values on both axes). You can specify their 36 | width (in [0,1]) and set their color. By default the axes will pass through 37 | the (0,0) point or stick to the sides of the graph the closest to it. You 38 | can also force them to stick on the side by setting 'side axis' to true. 39 | 40 | add_axes(graphID, width, red, green, blue, side axis); 41 | 42 | A regular grid can also be added. Specify the spacing between grid lines on 43 | both axis, the width (in [0,1]) and color. The grid can either start from 44 | the left and bottom side of the graph, or be centered on the (0,0) point by 45 | setting 'zero align' to true. 46 | 47 | add_grid(graphID, step x, step y, width, red, green, blue, zero align); 48 | 49 | You can plot continuous curves by specifying lists of X and Y coordinates, 50 | along with the width ([0,1]) and color of the lines. Points clouds can be 51 | added in a similar manner, by specifying X and Y coordinates, a point size 52 | and color. Finally you can also add histograms, by specifying a set of 53 | values and a number of bins ; spacing between bars and their color should 54 | also be specified. 55 | 56 | add_curve(graphID, x values, y values, line width, red, green, blue); 57 | add_points(graphID, x values, y values, point size, red, green, blue); 58 | add_hist(graphID, number of bins, values, spacing, red, green, blue); 59 | 60 | These three functions return integers IDs that can then be used to update a 61 | given plot on a given graph at a later time by calling respectively: 62 | 63 | update_points(graphID, points cloud id, new x values, new y values); 64 | update_curve(graphID, curve id, new x values, new y values); 65 | update_hist(graphID, histogram id, new values); 66 | 67 | All settings (width, size, bins, colors) are preserved. The IDs are managed 68 | separately for each graph and each type of plot. 69 | 70 | Call: 71 | 72 | draw(graphID, screen ratio); 73 | 74 | to draw a graph in the current viewport. If a screen ratio is specified, 75 | the graph will be rescaled to avoid any deformation ; else, nothing is done 76 | to prevent deformations when resizing the window. 77 | 78 | You can delete a graph and free its resources, or free all graphs and 79 | resources (including OpenGL buffers and programs) by calling respectively: 80 | 81 | free(graphID); 82 | free(); 83 | 84 | See below the exact list of types and functions expected from OpenGL headers. 85 | GLuint, GLsizei, Glint 86 | GL_DEPTH_TEST, GL_TRUE, GL_FALSE, GL_CULL_FACE, GL_BLEND, GL_FRONT_FACE, 87 | GL_CULL_FACE_MODE, GL_BLEND_SRC, GL_BLEND_DST, GL_POLYGON_MODE, GL_CCW, 88 | GL_BACK, GL_FRONT, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_FRONT_AND_BACK, 89 | GL_FILL, GL_TRIANGLES, GL_ARRAY_BUFFER, GL_STATIC_DRAW, GL_FLOAT, 90 | GL_COMPILE_STATUS, GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, GL_LINK_STATUS 91 | glDeleteVertexArrays, glDeleteBuffers, glIsEnabled, glBlendFunc, glDisable, 92 | glEnable, glFrontFace, glCullFace, glGetIntegerv, glPolygonMode, 93 | glUseProgram, glUniform1f, glUniform1i, glUniform3f, glBindVertexArray, 94 | glDrawArrays, glDeleteProgram, glGenVertexArrays, glGenBuffers, 95 | glBindBuffer, glBufferData, glEnableVertexAttribArray, glCreateShader, 96 | glShaderSource, glVertexAttribPointer, glCompileShader, glGetShaderiv, 97 | glCreateProgram, glAttachShader, glLinkProgram, glGetProgramiv, 98 | glDetachShader, glDeleteShader, glGetUniformLocation 99 | 100 | Revision history 101 | 1.0 First public version! Support for curves, bar charts, points, axes with 102 | arrows, grid, real-time updates. 103 | 104 | License: 105 | See end of file. 106 | */ 107 | 108 | #ifndef SRG_INCLUDE_SR_GRAPH_H 109 | #define SRG_INCLUDE_SR_GRAPH_H 110 | 111 | #include 112 | 113 | #ifdef SR_GRAPH_STATIC 114 | #define SRG_EXTERN static 115 | #else 116 | #define SRG_EXTERN extern 117 | #endif 118 | 119 | namespace sr_graph { 120 | 121 | SRG_EXTERN int setup(const float minx, const float maxx, const float miny, const float maxy, const float ratio, const float margins, const float bg_r, const float bg_g, const float bg_b); 122 | 123 | SRG_EXTERN void add_axes(const int graph_id, const float width, const float axis_r, const float axis_g, const float axis_b, const bool axisOnSide); 124 | 125 | SRG_EXTERN void add_grid(const int graph_id, const float stepx, const float stepy, const float width, const float lines_r, const float lines_g, const float lines_b, const bool fromZero); 126 | 127 | SRG_EXTERN int add_curve(const int graph_id, const std::vector & xs, const std::vector & ys, const float width, const float color_r, const float color_g, const float color_b); 128 | 129 | SRG_EXTERN void update_curve(const int graph_id, const int curve_id, const std::vector & xs, const std::vector & ys); 130 | 131 | SRG_EXTERN int add_hist(const int graph_id, const unsigned int bins, const std::vector & ys, const float spacing, const float color_r, const float color_g, const float color_b); 132 | 133 | SRG_EXTERN void update_hist(const int graph_id, const int hist_id, const std::vector & ys); 134 | 135 | SRG_EXTERN int add_points(const int graph_id, const std::vector & xs, const std::vector & ys, const float size, const float color_r, const float color_g, const float color_b); 136 | 137 | SRG_EXTERN void update_points(const int graph_id, const int points_id, const std::vector & xs, const std::vector & ys); 138 | 139 | SRG_EXTERN void draw(const int graph_id, const float ratio = 0.0f); 140 | 141 | SRG_EXTERN void free(const int graph_id); 142 | 143 | SRG_EXTERN void free(); 144 | 145 | } 146 | 147 | #endif 148 | 149 | #ifdef SRG_IMPLEMENTATION_SR_GRAPH 150 | 151 | #ifdef SR_GRAPH_LOGGING 152 | #include 153 | #endif 154 | 155 | #include 156 | #include 157 | 158 | namespace sr_graph { 159 | 160 | /// Internal structs. 161 | 162 | typedef struct { 163 | float r; 164 | float g; 165 | float b; 166 | } _srg_Color; 167 | 168 | typedef struct { 169 | GLuint id; 170 | GLuint bid; 171 | GLsizei count; 172 | } _srg_Buffers; 173 | 174 | typedef struct { 175 | _srg_Buffers buffer; 176 | _srg_Color color; 177 | float param0; 178 | unsigned int param1; 179 | } _srg_Curve; 180 | 181 | typedef struct { 182 | _srg_Color color; 183 | float minx; 184 | float maxx; 185 | float miny; 186 | float maxy; 187 | float ratio; 188 | float margin; 189 | bool freed; 190 | _srg_Buffers bufferAxes; 191 | _srg_Color colorAxes; 192 | _srg_Buffers bufferGrid; 193 | _srg_Color colorGrid; 194 | std::vector<_srg_Curve> curves; 195 | std::vector<_srg_Curve> curvespoints; 196 | std::vector<_srg_Curve> points; 197 | std::vector<_srg_Curve> hists; 198 | } _srg_Graph; 199 | 200 | typedef struct { 201 | _srg_Buffers bufferQuad; 202 | GLuint pid; 203 | GLuint ppid; 204 | GLuint lpid; 205 | GLuint cid; 206 | GLuint pcid; 207 | GLuint lcid; 208 | GLuint rid; 209 | GLuint prid; 210 | GLuint lrid; 211 | GLuint psid; 212 | } _srg_InternalState ; 213 | 214 | enum _srg_Orientation { 215 | VERTICAL, HORIZONTAL 216 | }; 217 | 218 | 219 | /// Internal variables. 220 | 221 | static bool _srg_isInit = false; 222 | static _srg_InternalState _srg_state; 223 | static std::vector<_srg_Graph> _srg_graphs; 224 | 225 | 226 | /// Foreward declarations. 227 | 228 | static void _srg_internalSetup(); 229 | static _srg_Buffers _srg_setDataBuffer(const float * data, const unsigned int count); 230 | static void _srg_getLine(const float p0x, const float p0y, const float p1x, const float p1y, const float w, const float ratio, std::vector & points); 231 | static void _srg_getRectangle(const float p0x, const float p0y, const float p1x, const float p1y, const float w, std::vector & points); 232 | static void _srg_getPoint(const float p0x, const float p0y, const float radius, const float ratio, std::vector & points); 233 | static void _srg_generateAxis(const _srg_Orientation orientation, const float margin, const float ratio, const float width, const float mini, const float maxi, const bool axisOnSide, const bool reverse, std::vector & axisData); 234 | static void _srg_generateCurve(const _srg_Graph & graph, const std::vector & xs, const std::vector & ys, _srg_Curve & curve); 235 | static void _srg_generatePoints(const _srg_Graph & graph, const std::vector & xs, const std::vector & ys, _srg_Curve & curve); 236 | static void _srg_generateHist(const _srg_Graph & graph, const std::vector & ys, _srg_Curve & curve); 237 | 238 | 239 | /// Exposed functions. 240 | 241 | SRG_EXTERN int setup(const float minx, const float maxx, const float miny, const float maxy, const float ratio, const float margins, const float bg_r, const float bg_g, const float bg_b){ 242 | // If we haven't initialized our GL programs, do it. 243 | if (!_srg_isInit) { 244 | _srg_internalSetup(); 245 | } 246 | // Create a graph with the given infos. 247 | _srg_Graph graph; 248 | graph.color = {bg_r, bg_g, bg_b }; 249 | graph.minx = minx; 250 | graph.maxx = maxx; 251 | graph.miny = miny; 252 | graph.maxy = maxy; 253 | graph.ratio = fabs(ratio); 254 | graph.margin = fmin(1.0f, fmax(0.0f, fabs(margins*2.0f))); 255 | graph.freed = false; 256 | graph.bufferAxes = { 0, 0, 0 }; 257 | graph.colorAxes = graph.color; 258 | graph.bufferGrid = { 0, 0, 0 }; 259 | graph.colorGrid = graph.color; 260 | graph.curves.clear(); 261 | graph.curvespoints.clear(); 262 | graph.points.clear(); 263 | graph.hists.clear(); 264 | 265 | // Store it. 266 | _srg_graphs.push_back(graph); 267 | return (int)_srg_graphs.size() - 1; 268 | 269 | } 270 | 271 | 272 | SRG_EXTERN void add_axes(const int graph_id, const float width, const float axis_r, const float axis_g, const float axis_b, const bool axisOnSide){ 273 | if(graph_id < 0 || graph_id >= _srg_graphs.size() || _srg_graphs[graph_id].freed){ 274 | return; 275 | } 276 | _srg_Graph & graph = _srg_graphs[graph_id]; 277 | /// Generate data for axis. 278 | std::vector axisData; 279 | _srg_generateAxis(HORIZONTAL, graph.margin, graph.ratio, width, graph.miny, graph.maxy, axisOnSide, graph.minx > graph.maxx, axisData); 280 | _srg_generateAxis(VERTICAL, graph.margin, graph.ratio, width, graph.minx, graph.maxx, axisOnSide, graph.miny > graph.maxy, axisData); 281 | 282 | graph.colorAxes = { axis_r, axis_g, axis_b }; 283 | graph.bufferAxes = _srg_setDataBuffer(&axisData[0], (unsigned int)axisData.size() / 2); 284 | } 285 | 286 | 287 | SRG_EXTERN void add_grid(const int graph_id, const float stepx, const float stepy, const float width, const float lines_r, const float lines_g, const float lines_b, const bool fromZero) { 288 | if(graph_id < 0 || graph_id >= _srg_graphs.size() || _srg_graphs[graph_id].freed){ 289 | return; 290 | } 291 | _srg_Graph & graph = _srg_graphs[graph_id]; 292 | std::vector gridData; 293 | 294 | const float ax = (2.0f*(1.0f-graph.margin))/(graph.maxx - graph.minx); 295 | const float bx = -1.0f + graph.margin - ax * graph.minx; 296 | const float ay = (2.0f*(1.0f-graph.margin))/(graph.maxy - graph.miny); 297 | const float by = -1.0f + graph.margin - ay * graph.miny; 298 | 299 | if(stepx != 0.0f && graph.maxx != graph.minx){ 300 | float shiftH = fabs(ax)*fabs(stepx); 301 | if(fromZero){ 302 | float xZero = bx; 303 | while(xZero < -1.0f + graph.margin){ 304 | xZero += shiftH; 305 | } 306 | while(xZero > 1.0f - graph.margin){ 307 | xZero -= shiftH; 308 | } 309 | for(float xi = xZero; xi >= -1.0f+graph.margin-0.0001f; xi -= shiftH){ 310 | _srg_getLine(xi, -1.0f+graph.margin, xi, 1.0f-graph.margin, width, graph.ratio, gridData); 311 | } 312 | for(float xi = xZero+shiftH; xi <= 1.0f-graph.margin+0.0001f; xi += shiftH){ 313 | _srg_getLine(xi, -1.0f+graph.margin, xi, 1.0f-graph.margin, width, graph.ratio, gridData); 314 | } 315 | } else { 316 | for(float x = -1.0f+graph.margin; x <= 1.0f-graph.margin; x += shiftH){ 317 | _srg_getLine(x, -1.0f+graph.margin, x, 1.0f-graph.margin, width, graph.ratio, gridData); 318 | } 319 | _srg_getLine(1.0f - graph.margin, -1.0f+graph.margin, 1.0f - graph.margin, 1.0f-graph.margin, width, graph.ratio, gridData); 320 | } 321 | } 322 | if(stepy != 0.0f && graph.maxy != graph.miny){ 323 | float shiftV = fabs(ay)*fabs(stepy); 324 | if(fromZero){ 325 | float yZero = by; 326 | while(yZero < -1.0f + graph.margin){ 327 | yZero += shiftV; 328 | } 329 | while(yZero > 1.0f - graph.margin){ 330 | yZero -= shiftV; 331 | } 332 | for(float yi = yZero; yi >= -1.0f+graph.margin - 0.0001f; yi -= shiftV){ 333 | _srg_getLine(-1.0f+graph.margin, yi, 1.0f-graph.margin, yi, width, graph.ratio, gridData); 334 | } 335 | for(float yi = yZero+shiftV; yi <= 1.0f-graph.margin + 0.0001f; yi += shiftV){ 336 | _srg_getLine(-1.0f+graph.margin, yi, 1.0f-graph.margin, yi, width, graph.ratio, gridData); 337 | } 338 | } else { 339 | for(float y = -1.0f+graph.margin; y < 1.0f-graph.margin; y += shiftV){ 340 | _srg_getLine(-1.0f+graph.margin, y, 1.0f-graph.margin, y, width, graph.ratio, gridData); 341 | } 342 | _srg_getLine(-1.0f+graph.margin, 1.0f - graph.margin, 1.0f-graph.margin, 1.0f - graph.margin, width, graph.ratio, gridData); 343 | } 344 | } 345 | graph.colorGrid = { lines_r, lines_g, lines_b }; 346 | graph.bufferGrid = _srg_setDataBuffer(&gridData[0], (unsigned int)gridData.size() / 2); 347 | } 348 | 349 | 350 | SRG_EXTERN int add_curve(const int graph_id, const std::vector & xs, const std::vector & ys, const float width, const float color_r, const float color_g, const float color_b){ 351 | 352 | if(graph_id < 0 || graph_id >= _srg_graphs.size() || _srg_graphs[graph_id].freed){ 353 | return -1; 354 | } 355 | _srg_Graph & graph = _srg_graphs[graph_id]; 356 | // Generate the lines. 357 | _srg_Curve curve; 358 | curve.color = {color_r, color_g, color_b}; 359 | curve.param0 = width; 360 | _srg_generateCurve(graph, xs, ys, curve); 361 | graph.curves.push_back(curve); 362 | // Generate the points junctions. 363 | _srg_Curve curvepoints; 364 | curvepoints.color = { color_r, color_g, color_b }; 365 | curvepoints.param0 = width; 366 | _srg_generatePoints(graph, xs, ys, curvepoints); 367 | graph.curvespoints.push_back(curvepoints); 368 | return (int)graph.curves.size()-1; 369 | } 370 | 371 | 372 | SRG_EXTERN void update_curve(const int graph_id, const int curve_id, const std::vector & xs, const std::vector & ys) { 373 | 374 | if(graph_id < 0 || graph_id >= _srg_graphs.size() || _srg_graphs[graph_id].freed){ 375 | return; 376 | } 377 | _srg_Graph & graph = _srg_graphs[graph_id]; 378 | if(curve_id < 0 || curve_id >= graph.curves.size()){ 379 | return; 380 | } 381 | // Update the lines. 382 | _srg_Curve & curve = graph.curves[curve_id]; 383 | glDeleteVertexArrays(1, &(curve.buffer.id)); 384 | glDeleteBuffers(1, &(curve.buffer.bid)); 385 | _srg_generateCurve(graph, xs, ys, curve); 386 | // Update the points junctions. 387 | _srg_Curve & curvepoints = graph.curvespoints[curve_id]; 388 | glDeleteVertexArrays(1, &(curvepoints.buffer.id)); 389 | glDeleteBuffers(1, &(curvepoints.buffer.bid)); 390 | _srg_generatePoints(graph, xs, ys, curvepoints); 391 | } 392 | 393 | 394 | SRG_EXTERN int add_points(const int graph_id, const std::vector & xs, const std::vector & ys, const float size, const float color_r, const float color_g, const float color_b) { 395 | 396 | if(graph_id < 0 || graph_id >= _srg_graphs.size() || _srg_graphs[graph_id].freed){ 397 | return -1; 398 | } 399 | _srg_Graph & graph = _srg_graphs[graph_id]; 400 | _srg_Curve curve; 401 | curve.color = {color_r, color_g, color_b}; 402 | curve.param0 = size; 403 | _srg_generatePoints(graph, xs, ys, curve); 404 | graph.points.push_back(curve); 405 | return (int)graph.points.size()-1; 406 | } 407 | 408 | 409 | SRG_EXTERN void update_points(const int graph_id, const int curve_id, const std::vector & xs, const std::vector & ys) { 410 | 411 | if(graph_id < 0 || graph_id >= _srg_graphs.size() || _srg_graphs[graph_id].freed){ 412 | return; 413 | } 414 | _srg_Graph & graph = _srg_graphs[graph_id]; 415 | if(curve_id < 0 || curve_id >= graph.points.size()){ 416 | return; 417 | } 418 | _srg_Curve & curve = graph.points[curve_id]; 419 | glDeleteVertexArrays(1, &(curve.buffer.id)); 420 | glDeleteBuffers(1, &(curve.buffer.bid)); 421 | _srg_generatePoints(graph, xs, ys, curve); 422 | } 423 | 424 | 425 | SRG_EXTERN int add_hist(const int graph_id, const unsigned int bins, const std::vector & ys, const float spacing, const float color_r, const float color_g, const float color_b) { 426 | 427 | if(graph_id < 0 || graph_id >= _srg_graphs.size() || _srg_graphs[graph_id].freed){ 428 | return -1; 429 | } 430 | _srg_Graph & graph = _srg_graphs[graph_id]; 431 | _srg_Curve curve; 432 | curve.color = {color_r, color_g, color_b}; 433 | curve.param0 = spacing; 434 | curve.param1 = bins; 435 | _srg_generateHist(graph, ys, curve); 436 | graph.hists.push_back(curve); 437 | return (int)graph.hists.size()-1; 438 | } 439 | 440 | SRG_EXTERN void update_hist(const int graph_id, const int curve_id, const std::vector & ys) { 441 | 442 | if(graph_id < 0 || graph_id >= _srg_graphs.size() || _srg_graphs[graph_id].freed){ 443 | return; 444 | } 445 | _srg_Graph & graph = _srg_graphs[graph_id]; 446 | if(curve_id < 0 || curve_id >= graph.hists.size()){ 447 | return; 448 | } 449 | _srg_Curve & curve = graph.hists[curve_id]; 450 | glDeleteVertexArrays(1, &(curve.buffer.id)); 451 | glDeleteBuffers(1, &(curve.buffer.bid)); 452 | _srg_generateHist(graph, ys, curve); 453 | } 454 | 455 | 456 | SRG_EXTERN void draw(const int graph_id, float ratio) { 457 | 458 | if(graph_id < 0 || graph_id >= _srg_graphs.size() || _srg_graphs[graph_id].freed){ 459 | return; 460 | } 461 | 462 | // Copy OpenGL states. 463 | bool depthState = glIsEnabled(GL_DEPTH_TEST) == GL_TRUE; 464 | bool cullState = glIsEnabled(GL_CULL_FACE) == GL_TRUE; 465 | bool blendState = glIsEnabled(GL_BLEND) == GL_TRUE; 466 | GLint faceMode, cullFaceMode, blendSrcMode, blendDstMode; 467 | glGetIntegerv(GL_FRONT_FACE, &faceMode); 468 | glGetIntegerv(GL_CULL_FACE_MODE, &cullFaceMode); 469 | glGetIntegerv(GL_BLEND_SRC, &blendSrcMode); 470 | glGetIntegerv(GL_BLEND_DST, &blendDstMode); 471 | GLint polygonModes[2]; 472 | glGetIntegerv(GL_POLYGON_MODE, polygonModes); 473 | 474 | // Set states. 475 | glDisable(GL_DEPTH_TEST); 476 | glEnable(GL_CULL_FACE); 477 | glFrontFace(GL_CCW); 478 | glCullFace(GL_BACK); 479 | glEnable(GL_BLEND); 480 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 481 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) ; 482 | 483 | // Set ratios. 484 | const _srg_Graph & graph = _srg_graphs[graph_id]; 485 | const float finalRatio = (ratio == 0.0) ? 1.0f : ratio/graph.ratio; 486 | glUseProgram(_srg_state.pid); 487 | glUniform1f(_srg_state.rid, finalRatio); 488 | glUseProgram(_srg_state.lpid); 489 | glUniform1f(_srg_state.lrid, finalRatio); 490 | glUseProgram(_srg_state.ppid); 491 | glUniform1f(_srg_state.prid, finalRatio); 492 | glUniform1i(_srg_state.psid, 1); 493 | 494 | // Draw quad to clear. 495 | glUseProgram(_srg_state.pid); 496 | glUniform3f(_srg_state.cid, graph.color.r, graph.color.g, graph.color.b); 497 | glBindVertexArray(_srg_state.bufferQuad.id); 498 | glDrawArrays(GL_TRIANGLES, 0, _srg_state.bufferQuad.count); 499 | glBindVertexArray(0); 500 | 501 | // Draw grid. 502 | glUseProgram(_srg_state.lpid); 503 | glUniform3f(_srg_state.lcid, graph.colorGrid.r, graph.colorGrid.g, graph.colorGrid.b); 504 | glBindVertexArray(graph.bufferGrid.id); 505 | glDrawArrays(GL_TRIANGLES, 0, graph.bufferGrid.count); 506 | glBindVertexArray(0); 507 | 508 | // Draw histograms. 509 | glUseProgram(_srg_state.pid); 510 | for(unsigned int i = 0; i < graph.hists.size(); ++i){ 511 | glUniform3f(_srg_state.cid, graph.hists[i].color.r, graph.hists[i].color.g, graph.hists[i].color.b); 512 | glBindVertexArray(graph.hists[i].buffer.id); 513 | glDrawArrays(GL_TRIANGLES, 0, graph.hists[i].buffer.count); 514 | } 515 | 516 | // Draw curves. 517 | for(unsigned int i = 0; i < graph.curves.size(); ++i){ 518 | // Draw the lines. 519 | glUseProgram(_srg_state.lpid); 520 | glUniform3f(_srg_state.lcid, graph.curves[i].color.r, graph.curves[i].color.g, graph.curves[i].color.b); 521 | glBindVertexArray(graph.curves[i].buffer.id); 522 | glDrawArrays(GL_TRIANGLES, 0, graph.curves[i].buffer.count); 523 | // Draw the points junctions (soft point smoothing enabled). // @IMPROVEMENT: enhance line junctions again. 524 | glUseProgram(_srg_state.ppid); 525 | glUniform3f(_srg_state.pcid, graph.curvespoints[i].color.r, graph.curvespoints[i].color.g, graph.curvespoints[i].color.b); 526 | glBindVertexArray(graph.curvespoints[i].buffer.id); 527 | glDrawArrays(GL_TRIANGLES, 0, graph.curvespoints[i].buffer.count); 528 | } 529 | 530 | // Draw axes. 531 | glUseProgram(_srg_state.lpid); 532 | glUniform3f(_srg_state.lcid, graph.colorAxes.r, graph.colorAxes.g, graph.colorAxes.b); 533 | glBindVertexArray(graph.bufferAxes.id); 534 | glDrawArrays(GL_TRIANGLES, 0, graph.bufferAxes.count); 535 | 536 | // Draw points (crisp point smoothing enabled). 537 | glUseProgram(_srg_state.ppid); 538 | glUniform1i(_srg_state.psid, 0); 539 | for(unsigned int i = 0; i < graph.points.size(); ++i){ 540 | glUniform3f(_srg_state.pcid, graph.points[i].color.r, graph.points[i].color.g, graph.points[i].color.b); 541 | glBindVertexArray(graph.points[i].buffer.id); 542 | glDrawArrays(GL_TRIANGLES, 0, graph.points[i].buffer.count); 543 | } 544 | 545 | // Restore OpenGL state. 546 | glBindVertexArray(0); 547 | glUseProgram(0); 548 | if(blendState){ 549 | glEnable(GL_BLEND); 550 | } else { 551 | glDisable(GL_BLEND); 552 | } 553 | if(cullState){ 554 | glEnable(GL_CULL_FACE); 555 | } else { 556 | glDisable(GL_CULL_FACE); 557 | } 558 | if(depthState){ 559 | glEnable(GL_DEPTH_TEST); 560 | } else { 561 | glDisable(GL_DEPTH_TEST); 562 | } 563 | glFrontFace(faceMode); 564 | glCullFace(cullFaceMode); 565 | glBlendFunc(blendSrcMode, blendDstMode); 566 | glPolygonMode(GL_FRONT, polygonModes[0] ); 567 | glPolygonMode(GL_BACK, polygonModes[1] ); 568 | 569 | } 570 | 571 | 572 | SRG_EXTERN void free(const int graph_id) { 573 | if(graph_id < 0 || graph_id >= _srg_graphs.size() || _srg_graphs[graph_id].freed){ 574 | return; 575 | } 576 | _srg_Graph & graph = _srg_graphs[graph_id]; 577 | // Free vertex arrays. 578 | glDeleteVertexArrays(1, &graph.bufferGrid.id); 579 | glDeleteVertexArrays(1, &graph.bufferAxes.id); 580 | glDeleteBuffers(1, &(graph.bufferGrid.bid)); 581 | glDeleteBuffers(1, &(graph.bufferAxes.bid)); 582 | 583 | for(unsigned int i = 0; i < graph.curves.size(); ++i){ 584 | glDeleteVertexArrays(1, &(graph.curves[i].buffer.id)); 585 | glDeleteBuffers(1, &(graph.curves[i].buffer.bid)); 586 | } 587 | for (unsigned int i = 0; i < graph.curvespoints.size(); ++i) { 588 | glDeleteVertexArrays(1, &(graph.curvespoints[i].buffer.id)); 589 | glDeleteBuffers(1, &(graph.curvespoints[i].buffer.bid)); 590 | } 591 | for(unsigned int i = 0; i < graph.hists.size(); ++i){ 592 | glDeleteVertexArrays(1, &(graph.hists[i].buffer.id)); 593 | glDeleteBuffers(1, &(graph.hists[i].buffer.bid)); 594 | } 595 | for(unsigned int i = 0; i < graph.points.size(); ++i){ 596 | glDeleteVertexArrays(1, &(graph.points[i].buffer.id)); 597 | glDeleteBuffers(1, &(graph.points[i].buffer.bid)); 598 | } 599 | graph.freed = true; 600 | } 601 | 602 | SRG_EXTERN void free(){ 603 | // Free each graph and then clear the map. 604 | for(unsigned int i = 0; i < _srg_graphs.size(); ++i){ 605 | free(i); 606 | } 607 | _srg_graphs.clear(); 608 | // Delete the programs and quad data. 609 | glDeleteProgram(_srg_state.pid); 610 | glDeleteProgram(_srg_state.lpid); 611 | glDeleteProgram(_srg_state.ppid); 612 | glDeleteVertexArrays(1, &_srg_state.bufferQuad.id); 613 | glDeleteBuffers(1, &_srg_state.bufferQuad.bid); 614 | } 615 | 616 | 617 | /// Internal functions. 618 | 619 | static void _srg_getLine(const float p0x, const float p0y, const float p1x, const float p1y, const float w, const float ratio, std::vector & points) { 620 | // Compute normal vector. 621 | float dirx = p1x - p0x; float diry = p1y - p0y; 622 | const float dirNorm = sqrtf(dirx*dirx+diry*diry); 623 | if(dirNorm != 0.0f){ 624 | dirx /= dirNorm; diry /= dirNorm; 625 | } 626 | 627 | const float norx = -diry; const float nory = dirx; 628 | const float sdx = w; const float sdy = ratio * w; 629 | const float dNx = sdx * norx; const float dNy = sdy * nory; 630 | 631 | const float ax = p0x - dNx; const float ay = p0y - dNy; 632 | const float bx = p1x - dNx; const float by = p1y - dNy; 633 | const float cx = p1x + dNx; const float cy = p1y + dNy; 634 | const float dx = p0x + dNx; const float dy = p0y + dNy; 635 | points.push_back(ax); points.push_back(ay); 636 | points.push_back(bx); points.push_back(by); 637 | points.push_back(cx); points.push_back(cy); 638 | points.push_back(ax); points.push_back(ay); 639 | points.push_back(cx); points.push_back(cy); 640 | points.push_back(dx); points.push_back(dy); 641 | } 642 | 643 | 644 | static void _srg_getRectangle(const float p0x, const float p0y, const float p1x, const float p1y, const float w, std::vector & points) { 645 | const float wx = w * 0.5f; 646 | const float ax = p0x - wx; const float ay = p0y; 647 | const float bx = p0x + wx; const float by = p0y; 648 | const float cx = p1x + wx; const float cy = p1y; 649 | const float dx = p1x - wx; const float dy = p1y; 650 | points.push_back(ax); points.push_back(ay); 651 | points.push_back(bx); points.push_back(by); 652 | points.push_back(cx); points.push_back(cy); 653 | points.push_back(ax); points.push_back(ay); 654 | points.push_back(cx); points.push_back(cy); 655 | points.push_back(dx); points.push_back(dy); 656 | } 657 | 658 | 659 | static void _srg_getPoint(const float p0x, const float p0y, const float radius, const float ratio, std::vector & points) { 660 | const float wx = radius; const float wy = radius * ratio; 661 | const float ax = p0x - wx; const float ay = p0y - wy; 662 | const float bx = p0x + wx; const float by = p0y - wy; 663 | const float cx = p0x + wx; const float cy = p0y + wy; 664 | const float dx = p0x - wx; const float dy = p0y + wy; 665 | points.push_back(ax); points.push_back(ay); 666 | points.push_back(bx); points.push_back(by); 667 | points.push_back(cx); points.push_back(cy); 668 | points.push_back(ax); points.push_back(ay); 669 | points.push_back(cx); points.push_back(cy); 670 | points.push_back(dx); points.push_back(dy); 671 | } 672 | 673 | 674 | static void _srg_generateAxis(const _srg_Orientation orientation, const float margin, const float ratio, const float width, const float mini, const float maxi, const bool axisOnSide, const bool reverse, std::vector & axisData){ 675 | float hy; 676 | // Three positions. 677 | if(axisOnSide || 0.0 <= fmin(mini, maxi)){ 678 | // Axis on the bottom 679 | hy = -1.0f+margin; 680 | if(!axisOnSide && maxi < mini){ 681 | hy *= -1.0f; 682 | } 683 | } else if (0 >= fmax(maxi, mini)){ 684 | // Axis on the top 685 | hy = 1.0f-margin; 686 | if(maxi < mini){ 687 | hy *= -1.0f; 688 | } 689 | } else { 690 | // Need to find 0 y coord. 691 | hy = -2.0f*(1.0f - margin)*(mini/(maxi-mini))+margin-1.0f; 692 | } 693 | 694 | const float ld = fmin(0.03f, 0.3f*margin); 695 | const float rv = orientation == VERTICAL ? ratio : 1.0f; 696 | const float rh = orientation == HORIZONTAL ? ratio : 1.0f; 697 | const int sh = orientation == VERTICAL ? 0 : 1; 698 | const float hx0 = -1.0f + margin - (reverse ? 1.5f*ld*rv : 0.75f*width*rv); 699 | const float hx1 = 1.0f - margin + (reverse ? 0.75f*width*rv : 1.5f*ld*rv); 700 | const float ord = reverse ? hx0 : hx1; 701 | const float sn = reverse ? -1.0f : 1.0f; 702 | const float s0 = sn * (1.0f + sqrtf(2.0)*rv)*width; 703 | const float s1 = sn * ld * rv; 704 | const float s2 = (-sh*2.0f+1.0f) * sn * (ld - sqrt(2.0f)*width)*rh; 705 | const float s3 = (-sh*2.0f+1.0f) * sn * (ld + sqrt(2.0f)*width)*rh; 706 | 707 | if (orientation == VERTICAL) { 708 | _srg_getLine(hy, hx0, hy, hx1, width, ratio, axisData); 709 | _srg_getLine(hy, ord + sn*width, hy + sn*ld, ord - sn*ld*ratio, width, ratio, axisData); 710 | } else { 711 | _srg_getLine(hx0, hy, hx1, hy, width, ratio, axisData); 712 | _srg_getLine(ord + sn * width, hy, ord - sn * ld, hy - sn * ld*ratio, width, ratio, axisData); 713 | } 714 | // Correct vertices positions to join the point of the arrow and the tail angles. 715 | axisData[axisData.size() - 2 + sh] = hy; 716 | axisData[axisData.size() - 1 - sh] = ord + s0; 717 | axisData[axisData.size() - 10 + sh] = hy + s2; 718 | axisData[axisData.size() - 8 + sh] = hy + s3; 719 | axisData[axisData.size() - 4 + sh] = hy + s3; 720 | axisData[axisData.size() - 9 - sh] = ord - s1; 721 | axisData[axisData.size() - 7 - sh] = ord - s1; 722 | axisData[axisData.size() - 3 - sh] = ord - s1; 723 | 724 | if (orientation == VERTICAL) { 725 | _srg_getLine(hy, ord + sn * width, hy - sn * ld, ord - sn * ld * ratio, width, ratio, axisData); 726 | } else { 727 | _srg_getLine(ord + sn*width, hy, ord - sn*ld, hy + sn * ld*ratio, width, ratio, axisData); 728 | } 729 | // Correct vertices positions to join the point of the arrow and the tail angles. 730 | axisData[axisData.size() - 6 + sh] = hy; 731 | axisData[axisData.size() - 12 + sh] = hy; 732 | axisData[axisData.size() - 5 - sh] = ord + s0; 733 | axisData[axisData.size() - 11 - sh] = ord + s0; 734 | axisData[axisData.size() - 10 + sh] = hy - s3; 735 | axisData[axisData.size() - 8 + sh] = hy - s2; 736 | axisData[axisData.size() - 4 + sh] = hy - s2; 737 | axisData[axisData.size() - 9 - sh] = ord - s1; 738 | axisData[axisData.size() - 7 - sh] = ord - s1; 739 | axisData[axisData.size() - 3 - sh] = ord - s1; 740 | } 741 | 742 | static void _srg_generateCurve(const _srg_Graph & graph, const std::vector & xs, const std::vector & ys, _srg_Curve & curve) { 743 | if(xs.size() != ys.size() || xs.size() == 0){ 744 | return; 745 | } 746 | 747 | const float ax = (2.0f*(1.0f-graph.margin))/(graph.maxx - graph.minx); 748 | const float bx = -1.0f + graph.margin - ax * graph.minx; 749 | const float ay = (2.0f*(1.0f-graph.margin))/(graph.maxy - graph.miny); 750 | const float by = -1.0f + graph.margin - ay * graph.miny; 751 | std::vector curveData; 752 | float x0 = ax*xs[0]+bx; 753 | float y0 = ay*ys[0]+by; 754 | for(unsigned int i = 1; i < xs.size(); ++i){ 755 | const float x1 = ax*xs[i]+bx; 756 | const float y1 = ay*ys[i]+by; 757 | _srg_getLine(x0, y0, x1, y1, curve.param0, graph.ratio, curveData); 758 | x0 = x1; 759 | y0 = y1; 760 | } 761 | 762 | curve.buffer = _srg_setDataBuffer(&curveData[0], (unsigned int)curveData.size() / 2); 763 | } 764 | 765 | static void _srg_generatePoints(const _srg_Graph & graph, const std::vector & xs, const std::vector & ys, _srg_Curve & curve){ 766 | 767 | if(xs.size() != ys.size() || xs.size() == 0){ 768 | return; 769 | } 770 | const float ax = (2.0f*(1.0f-graph.margin))/(graph.maxx - graph.minx); 771 | const float bx = -1.0f + graph.margin - ax * graph.minx; 772 | const float ay = (2.0f*(1.0f-graph.margin))/(graph.maxy - graph.miny); 773 | const float by = -1.0f + graph.margin - ay * graph.miny; 774 | 775 | std::vector curveData; 776 | 777 | for(unsigned int i = 0; i < xs.size(); ++i){ 778 | const float x0 = ax*xs[i]+bx; 779 | const float y0 = ay*ys[i]+by; 780 | _srg_getPoint(x0, y0, curve.param0, graph.ratio, curveData); 781 | } 782 | 783 | curve.buffer = _srg_setDataBuffer(&curveData[0], (unsigned int)curveData.size() / 2); 784 | } 785 | 786 | static void _srg_generateHist(const _srg_Graph & graph, const std::vector & ys, _srg_Curve & curve){ 787 | if(ys.size() == 0){ 788 | return; 789 | } 790 | const float binSize = (graph.maxx - graph.minx)/(float)curve.param1; 791 | std::vector binCounts(curve.param1, 0); 792 | for(unsigned int i = 0; i < ys.size(); ++i){ 793 | const int j = (unsigned int)floor((ys[i] - graph.minx)/binSize); 794 | if(j < 0 || j >= binCounts.size()){ 795 | continue; 796 | } 797 | binCounts[j] += 1; 798 | } 799 | 800 | std::vector histData; 801 | const float ax = (2.0f*(1.0f-graph.margin))/(graph.maxx - graph.minx); 802 | const float bx = -1.0f + graph.margin - ax * graph.minx; 803 | const float ay = (2.0f*(1.0f-graph.margin))/(graph.maxy - graph.miny); 804 | const float by = -1.0f + graph.margin - ay * graph.miny; 805 | const float binWidth = fmax(0.0f, 2.0f*(1.0f - graph.margin)/(float)curve.param1 - curve.param0); 806 | for(unsigned int i = 0; i < curve.param1; ++i){ 807 | if(binCounts[i] == 0){ 808 | continue; 809 | } 810 | float x0 = ax*(graph.minx+(float)(i+0.5f)*binSize) + bx; 811 | float y0 = by; 812 | float y1 = ay * (float)binCounts[i] + by; 813 | _srg_getRectangle(x0, y0, x0, y1, binWidth, histData); 814 | } 815 | curve.buffer = _srg_setDataBuffer(&histData[0], (unsigned int)histData.size() / 2); 816 | } 817 | 818 | 819 | /// Shaders strings. 820 | 821 | static const char * _srg_vstr = 822 | "#version 330\nlayout(location = 0) in vec2 v;\nuniform float ratio;\nout vec2 coords;\nvoid main(){\nvec2 finalRatio = ratio < 1.0 ? vec2(1.0, ratio) : vec2(1.0/ratio, 1.0);\ngl_Position.xy = v * finalRatio;\ngl_Position.zw = vec2(1.0);\nint id = int(mod(gl_VertexID, 6));\nbool uzero = (id == 0) || (id == 3) || (id == 5);\nbool vzero = (id == 0) || (id == 3) || (id == 1);\ncoords = vec2(uzero ? -1.0 : 1.0, vzero ? -1.0 : 1.0);\n}\n"; 823 | 824 | static const char * _srg_fstr = "#version 330\nin vec2 coords;\nuniform vec3 color;\nout vec4 frag_Color;\nvoid main(){\nfrag_Color.rgb = color;\nfrag_Color.a = 1.0;\n}\n"; 825 | 826 | static const char * _srg_lfstr = "#version 330\nin vec2 coords;\nuniform vec3 color;\nout vec4 frag_Color;\nvoid main(){\nfrag_Color.rgb = color;\nfrag_Color.a = 1.0-smoothstep(0.5, 1.0, abs(coords.y));\n}\n"; 827 | 828 | static const char * _srg_pfstr = "#version 330\nin vec2 coords;\nuniform vec3 color;\nuniform bool smoothing;\nout vec4 fragColor;\nvoid main(){\nfragColor = vec4(color, 1.0-smoothstep(smoothing ? 0.5 : 0.9, 1.0, length(coords)));\n}\n"; 829 | 830 | 831 | /// OpenGL helpers. 832 | 833 | static _srg_Buffers _srg_setDataBuffer(const float * data, const unsigned int count){ 834 | // Create a vertex array and a vertex buffer. 835 | GLuint vaId; 836 | glGenVertexArrays(1, &vaId); 837 | glBindVertexArray(vaId); 838 | GLuint bufferPos; 839 | glGenBuffers(1, &bufferPos); 840 | glBindBuffer(GL_ARRAY_BUFFER, bufferPos); 841 | // Populate the buffer with the 2D vertices. 842 | glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 2 * count, data, GL_STATIC_DRAW); 843 | // Setup the corresponding shader attribute at location 0. 844 | glEnableVertexAttribArray(0); 845 | glBindBuffer(GL_ARRAY_BUFFER, bufferPos); 846 | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL); 847 | glBindVertexArray(0); 848 | return { vaId, bufferPos, (GLsizei)count }; 849 | } 850 | 851 | 852 | static GLuint _srg_loadShader(const char * prog, GLuint type) { 853 | // Create shader, setup string as source and compile it. 854 | GLuint id = glCreateShader(type); 855 | glShaderSource(id, 1, &prog, (const GLint*)NULL); 856 | glCompileShader(id); 857 | // Check shader compilation status. 858 | GLint success; 859 | glGetShaderiv(id, GL_COMPILE_STATUS, &success); 860 | // If compilation failed, get information and display it. 861 | if (success != GL_TRUE) { 862 | #ifdef SR_GRAPH_LOGGING 863 | printf("[sr_graph] Failed OpenGL shader setup.\n"); 864 | #endif 865 | // glCreateShader returns 0 if an error happened, so we can too. 866 | return 0; 867 | } 868 | return id; 869 | } 870 | 871 | 872 | static GLuint _srg_createGLProgram(const char* vertexString, const char * fragmentString) { 873 | GLuint id = glCreateProgram(); 874 | // Load and attach shaders, then link them w/ the program. 875 | GLuint vp = _srg_loadShader(vertexString, GL_VERTEX_SHADER); 876 | GLuint fp = _srg_loadShader(fragmentString, GL_FRAGMENT_SHADER); 877 | if(vp==0 || fp == 0){ return 0; } 878 | glAttachShader(id, vp); 879 | glAttachShader(id, fp); 880 | glLinkProgram(id); 881 | //Check linking status. 882 | GLint success = GL_FALSE; 883 | glGetProgramiv(id, GL_LINK_STATUS, &success); 884 | if (!success) { 885 | #ifdef SR_GRAPH_LOGGING 886 | printf("[sr_graph] Failed OpenGL program setup.\n"); 887 | #endif 888 | // glCreateProgram returns 0 if an error happened, so we can too. 889 | return 0; 890 | } 891 | // Clean the shaders objects, detach and delete them. 892 | glDetachShader(id, vp); 893 | glDetachShader(id, fp); 894 | glDeleteShader(vp); 895 | glDeleteShader(fp); 896 | return id; 897 | } 898 | 899 | 900 | static void _srg_internalSetup() { 901 | // Quads program. 902 | _srg_state.pid = _srg_createGLProgram(_srg_vstr, _srg_fstr); 903 | glUseProgram(_srg_state.pid); 904 | _srg_state.cid = glGetUniformLocation(_srg_state.pid, "color"); 905 | _srg_state.rid = glGetUniformLocation(_srg_state.pid, "ratio"); 906 | // Lines program. 907 | _srg_state.lpid = _srg_createGLProgram(_srg_vstr, _srg_lfstr); 908 | glUseProgram(_srg_state.lpid); 909 | _srg_state.lcid = glGetUniformLocation(_srg_state.lpid, "color"); 910 | _srg_state.lrid = glGetUniformLocation(_srg_state.lpid, "ratio"); 911 | // Points program. 912 | _srg_state.ppid = _srg_createGLProgram(_srg_vstr, _srg_pfstr); 913 | glUseProgram(_srg_state.ppid); 914 | _srg_state.pcid = glGetUniformLocation(_srg_state.ppid, "color"); 915 | _srg_state.prid = glGetUniformLocation(_srg_state.ppid, "ratio"); 916 | _srg_state.psid = glGetUniformLocation(_srg_state.ppid, "smoothing"); 917 | glUseProgram(0); 918 | // Quad data for full viewport clearing. 919 | const float quadData[12] = { -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f }; 920 | _srg_state.bufferQuad = _srg_setDataBuffer(quadData, 6); 921 | // Check all programs are ok before considering initialization complete. 922 | if(_srg_state.pid != 0 && _srg_state.lpid != 0 && _srg_state.ppid != 0){ 923 | _srg_isInit = true; 924 | } else { 925 | #ifdef SR_GRAPH_LOGGING 926 | printf("[sr_graph] Failed to init.\n"); 927 | #endif 928 | } 929 | } 930 | 931 | } 932 | 933 | #endif 934 | 935 | 936 | /* 937 | ------------------------------------------------------------------------------ 938 | This software is available under 2 licenses -- choose whichever you prefer. 939 | ------------------------------------------------------------------------------ 940 | ALTERNATIVE A - MIT License 941 | Copyright (c) 2017 Simon Rodriguez 942 | Permission is hereby granted, free of charge, to any person obtaining a copy of 943 | this software and associated documentation files (the "Software"), to deal in 944 | the Software without restriction, including without limitation the rights to 945 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 946 | of the Software, and to permit persons to whom the Software is furnished to do 947 | so, subject to the following conditions: 948 | The above copyright notice and this permission notice shall be included in all 949 | copies or substantial portions of the Software. 950 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 951 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 952 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 953 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 954 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 955 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 956 | SOFTWARE. 957 | ------------------------------------------------------------------------------ 958 | ALTERNATIVE B - Public Domain (www.unlicense.org) 959 | This is free and unencumbered software released into the public domain. 960 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 961 | software, either in source code form or as a compiled binary, for any purpose, 962 | commercial or non-commercial, and by any means. 963 | In jurisdictions that recognize copyright laws, the author or authors of this 964 | software dedicate any and all copyright interest in the software to the public 965 | domain. We make this dedication for the benefit of the public at large and to 966 | the detriment of our heirs and successors. We intend this dedication to be an 967 | overt act of relinquishment in perpetuity of all present and future rights to 968 | this software under copyright law. 969 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 970 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 971 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 972 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 973 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 974 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 975 | ------------------------------------------------------------------------------ 976 | */ 977 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | #Compiler: g++ 2 | CXX = g++ 3 | 4 | #Include directories (for headers): standard include dirs in /usr and /usr/local, and our helper directory. 5 | INCLUDEDIR = -I/usr/include/ -I/usr/local/include/ -Isrc/libs/ #-Isrc/libs/glfw/include/ 6 | 7 | #Libraries needed: OpenGL and glfw3. glfw3 requires Cocoa, IOKit and CoreVideo. 8 | 9 | LIBS = -lglfw3 -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo 10 | 11 | #Compiler flags: C++11 standard, and display 'all' warnings. 12 | CXXFLAGS = -std=c++11 -Wall -O3 13 | 14 | #Build directory 15 | BUILDDIR = build 16 | #Source directory 17 | SRCDIR = src 18 | 19 | #Paths to the source files 20 | #Collect sources from subdirectories (up to depth 3) 21 | SRC_DEPTH_1 = $(wildcard $(SRCDIR)/*.cpp) 22 | SRC_DEPTH_2 = $(wildcard $(SRCDIR)/*/*.cpp) 23 | SRC_DEPTH_3 = $(wildcard $(SRCDIR)/*/*/*.cpp) 24 | SOURCES = $(SRC_DEPTH_3) $(SRC_DEPTH_2) $(SRC_DEPTH_1) 25 | 26 | #Paths to the object files 27 | OBJECTS = $(SOURCES:$(SRCDIR)/%.cpp=$(BUILDDIR)/%.o) 28 | 29 | #Paths to the subdirectories 30 | SUBDIRS_LIST = $(shell find src -type d) 31 | SUBDIRS = $(SUBDIRS_LIST:$(SRCDIR)%=$(BUILDDIR)%) 32 | 33 | #Executable name 34 | EXECNAME = sr_graph_test 35 | 36 | #Re-create the build dir if needed, compile and link. 37 | all: dirs $(EXECNAME) 38 | 39 | #Linking phase: combine all objects files to generate the executable 40 | $(EXECNAME): $(OBJECTS) 41 | @echo "Linking $(EXECNAME)..." 42 | @$(CXX) $(OBJECTS) $(LIBS) -o $(BUILDDIR)/$(EXECNAME) 43 | @echo "Done!" 44 | 45 | #Compiling phase: generate the object files from the source files 46 | $(BUILDDIR)/%.o : $(SRCDIR)/%.cpp 47 | @echo "Compiling $<" 48 | @$(CXX) -c $(CXXFLAGS) $(INCLUDEDIR) $< -o $@ 49 | 50 | #Run the executable 51 | run: 52 | @./$(BUILDDIR)/$(EXECNAME) 53 | 54 | #Create the build directory and its subdirectories 55 | dirs: 56 | @mkdir -p $(SUBDIRS) 57 | 58 | #Remove the whole build directory 59 | .PHONY: clean 60 | clean : 61 | rm -r $(BUILDDIR) 62 | 63 | -------------------------------------------------------------------------------- /test/Makefile.linux: -------------------------------------------------------------------------------- 1 | #Compiler: g++ 2 | CXX = g++ 3 | 4 | #Include directories (for headers): standard include dirs in /usr and /usr/local, and our helper directory. 5 | INCLUDEDIR = -I/usr/include/ -I/usr/local/include/ -Isrc/libs/ 6 | #Library directory (just in case) 7 | #You might have to symlink libGLEW in your standard libdir for use at runtime 8 | LIBDIR = -L/usr/local/lib 9 | #Libraries needed: OpenGL and glfw3. glfw3 require X11, Xi, and so on... 10 | LIBS = -lglfw3 -lGL -lX11 -lXi -lXrandr -lXxf86vm -lXinerama -lXcursor -lrt -lm -pthread -ldl 11 | 12 | #Compiler flags: C++11 standard, and display 'all' warnings. 13 | CXXFLAGS = -std=c++11 -Wall -O3 14 | 15 | #Build directory 16 | BUILDDIR = build 17 | #Source directory 18 | SRCDIR = src 19 | 20 | #Paths to the source files 21 | #Collect sources from subdirectories (up to depth 3) 22 | SRC_DEPTH_1 = $(wildcard $(SRCDIR)/*.cpp) 23 | SRC_DEPTH_2 = $(wildcard $(SRCDIR)/*/*.cpp) 24 | SRC_DEPTH_3 = $(wildcard $(SRCDIR)/*/*/*.cpp) 25 | SOURCES = $(SRC_DEPTH_3) $(SRC_DEPTH_2) $(SRC_DEPTH_1) 26 | 27 | #Paths to the object files 28 | OBJECTS = $(SOURCES:$(SRCDIR)/%.cpp=$(BUILDDIR)/%.o) 29 | 30 | #Paths to the subdirectories 31 | SUBDIRS_LIST = $(shell find src -type d) 32 | SUBDIRS = $(SUBDIRS_LIST:$(SRCDIR)%=$(BUILDDIR)%) 33 | 34 | #Executable name 35 | EXECNAME = sr_graph_test 36 | 37 | #Re-create the build dir if needed, compile and link. 38 | all: dirs $(EXECNAME) 39 | 40 | #Linking phase: combine all objects files to generate the executable 41 | $(EXECNAME): $(OBJECTS) 42 | @echo "Linking $(EXECNAME)..." 43 | @$(CXX) $(LIBDIR) $(OBJECTS) $(LIBS) -o $(BUILDDIR)/$(EXECNAME) 44 | @echo "Done!" 45 | 46 | #Compiling phase: generate the object files from the source files 47 | $(BUILDDIR)/%.o : $(SRCDIR)/%.cpp 48 | @echo "Compiling $<" 49 | @$(CXX) -c $(CXXFLAGS) $(INCLUDEDIR) $< -o $@ 50 | 51 | #Run the executable 52 | run: 53 | @./$(BUILDDIR)/$(EXECNAME) 54 | 55 | #Create the build directory and its subdirectories 56 | dirs: 57 | @mkdir -p $(SUBDIRS) 58 | 59 | #Remove the whole build directory 60 | .PHONY: clean 61 | clean : 62 | rm -r $(BUILDDIR) 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /test/sr_graph_test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.3 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sr_graph_test", "sr_graph_test.vcxproj", "{F6DD60FB-C5DD-45B5-8DA0-626FE0210ACB}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {F6DD60FB-C5DD-45B5-8DA0-626FE0210ACB}.Debug|x64.ActiveCfg = Debug|x64 17 | {F6DD60FB-C5DD-45B5-8DA0-626FE0210ACB}.Debug|x64.Build.0 = Debug|x64 18 | {F6DD60FB-C5DD-45B5-8DA0-626FE0210ACB}.Debug|x86.ActiveCfg = Debug|Win32 19 | {F6DD60FB-C5DD-45B5-8DA0-626FE0210ACB}.Debug|x86.Build.0 = Debug|Win32 20 | {F6DD60FB-C5DD-45B5-8DA0-626FE0210ACB}.Release|x64.ActiveCfg = Release|x64 21 | {F6DD60FB-C5DD-45B5-8DA0-626FE0210ACB}.Release|x64.Build.0 = Release|x64 22 | {F6DD60FB-C5DD-45B5-8DA0-626FE0210ACB}.Release|x86.ActiveCfg = Release|Win32 23 | {F6DD60FB-C5DD-45B5-8DA0-626FE0210ACB}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {E25D6905-C6F6-4E19-A051-0580A06402E3} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /test/sr_graph_test.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {F6DD60FB-C5DD-45B5-8DA0-626FE0210ACB} 23 | GL_Template 24 | 8.1 25 | 26 | 27 | 28 | Application 29 | true 30 | v141 31 | MultiByte 32 | 33 | 34 | Application 35 | false 36 | v141 37 | true 38 | MultiByte 39 | 40 | 41 | Application 42 | true 43 | v141 44 | MultiByte 45 | 46 | 47 | Application 48 | false 49 | v141 50 | true 51 | MultiByte 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | $(VC_IncludePath);$(WindowsSDK_IncludePath); 73 | 74 | 75 | $(VC_IncludePath);$(WindowsSDK_IncludePath); 76 | 77 | 78 | $(VC_IncludePath);$(WindowsSDK_IncludePath); 79 | 80 | 81 | $(VC_IncludePath);$(WindowsSDK_IncludePath); 82 | 83 | 84 | 85 | Level3 86 | Disabled 87 | true 88 | src\helpers;src\libs;src\libs\glfw\include\; 89 | 90 | 91 | true 92 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;glfw3.lib;%(AdditionalDependencies) 93 | src\libs\glfw\lib-win-vc2015\ 94 | 95 | 96 | 97 | 98 | Level3 99 | Disabled 100 | true 101 | src\helpers;src\libs;src\libs\glfw\include\; 102 | 103 | 104 | true 105 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;glfw3.lib;%(AdditionalDependencies) 106 | src\libs\glfw\lib-win-vc2015-64\ 107 | 108 | 109 | 110 | 111 | Level3 112 | MaxSpeed 113 | true 114 | true 115 | true 116 | src\helpers;src\libs;src\libs\glfw\include\; 117 | 118 | 119 | true 120 | true 121 | true 122 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;glfw3.lib;%(AdditionalDependencies) 123 | src\libs\glfw\lib-win-vc2015\ 124 | 125 | 126 | 127 | 128 | Level3 129 | MaxSpeed 130 | true 131 | true 132 | true 133 | src\helpers;src\libs;src\libs\glfw\include\; 134 | 135 | 136 | true 137 | true 138 | true 139 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;glfw3.lib;%(AdditionalDependencies) 140 | src\libs\glfw\lib-win-vc2015-64\ 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /test/sr_graph_test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {022dfdaf-a21f-4749-8160-eb46aa1fca27} 10 | 11 | 12 | {3a188a85-59e0-4bd6-a559-e3030e24b4ac} 13 | 14 | 15 | 16 | 17 | Source Files 18 | 19 | 20 | Source Files 21 | 22 | 23 | Source Files\libs\gl3w 24 | 25 | 26 | Source Files 27 | 28 | 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files\libs\gl3w 35 | 36 | 37 | Source Files\libs\gl3w 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | -------------------------------------------------------------------------------- /test/src/Renderer.cpp: -------------------------------------------------------------------------------- 1 | // Include sr_graph here. 2 | #include 3 | #define SRG_IMPLEMENTATION_SR_GRAPH 4 | #include "../../sr_graph.h" 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "Utilities.h" 13 | #include "Renderer.h" 14 | 15 | 16 | #ifndef M_PI 17 | #define M_PI 3.14159265359f 18 | #endif 19 | 20 | int gr1, gr2, gr3, gr4, gr5; 21 | 22 | Renderer::~Renderer(){} 23 | 24 | Renderer::Renderer(int width, int height){ 25 | 26 | // Initialize the timer. 27 | _timer = glfwGetTime(); 28 | // Initialize random generator; 29 | Random::seed(); 30 | // Setup projection matrix. 31 | _width = width; 32 | _height = height; 33 | 34 | // Query the renderer identifier, and the supported OpenGL version. 35 | const GLubyte* renderer = glGetString(GL_RENDERER); 36 | const GLubyte* version = glGetString(GL_VERSION); 37 | std::cout << "Renderer: " << renderer << std::endl; 38 | std::cout << "OpenGL version supported: " << version << std::endl; 39 | checkGLError(); 40 | 41 | // GL options 42 | glEnable(GL_DEPTH_TEST); 43 | glEnable(GL_CULL_FACE); 44 | glFrontFace(GL_CCW); 45 | glCullFace(GL_BACK); 46 | glBlendEquation(GL_FUNC_ADD); 47 | glBlendFunc(GL_ONE, GL_ONE); 48 | checkGLError(); 49 | 50 | 51 | // Create graphs. 52 | const float ratio = (float)width / (float)height; 53 | 54 | 55 | // Graph 1: plotting two curves with data points. 56 | std::vector xs11 = { -198.0f, -121.0f, -112.0f, -51.0f, -2.0f, 18.0f, 49.5f, 75.0f, 79.0f, 94.0f }; 57 | std::vector ys11 = { 112.0f, 121.0f, 202.0f, 238.0f, 198.0f, 197.0f, 220.0f, 289.0f, 143.0f, 138.0f }; 58 | std::vector xs12 = { -190.0f, -172.0f, -168.0f, -154.0f, -115.0f, -98.0f, -84.0f, -33.0f, 7.0f, 67.0f, 71.0f, 100.0f }; 59 | std::vector ys12 = { 289.0f, 232.0f, 225.0f, 200.0f, 212.0f, 180.0f, 184.0f, 133.0f, 218.0f, 218.0f, 176.0f, 120.0f }; 60 | 61 | gr1 = sr_graph::setup(-200.0f, 100.0f, 100.0f, 300.0f, ratio, 0.1f, 1.0f, 1.0f, 1.0f); 62 | sr_graph::add_axes(gr1, 0.007f, 0.1f, 0.1f, 0.1f, false); 63 | sr_graph::add_curve(gr1, xs11, ys11, 0.007f, 0.9f, 0.1f, 0.2f); 64 | sr_graph::add_points(gr1, xs11, ys11, 0.03f, 0.9f, 0.1f, 0.2f); 65 | sr_graph::add_curve(gr1, xs12, ys12, 0.007f, 0.6f, 0.8f, 0.3f); 66 | sr_graph::add_points(gr1, xs12, ys12, 0.03f, 0.6f, 0.8f, 0.3f); 67 | 68 | 69 | // Graph 2: histogram of the distribution of 1000 random numbers in [0,1]. 70 | std::vector ys2; 71 | for(int i = 0; i < 1000; ++i){ 72 | ys2.push_back(Random::Float()); 73 | } 74 | 75 | gr2 = sr_graph::setup(0.0f, 1.0f, 0.0f, 100.0f, ratio, 0.2f, 0.1f, 0.1f, 0.1f); 76 | sr_graph::add_axes(gr2, 0.01f, 0.9f, 0.9f, 0.9f, true); 77 | sr_graph::add_grid(gr2, 0.0f, 10.0f, 0.0045f, 0.5f, 0.5f, 0.5f, false); 78 | sr_graph::add_hist(gr2, 25, ys2, 0.0f, 0.35f, 0.95f, 0.48f); 79 | 80 | 81 | // Graph 3: sinus curve. 82 | std::vector xs3; 83 | std::vector ys3; 84 | for(float theta = -M_PI; theta <= M_PI; theta += 2.0f*M_PI/200.0f){ 85 | xs3.push_back(theta); 86 | ys3.push_back(sinf(theta*3.5f)); 87 | } 88 | 89 | gr3 = sr_graph::setup(-M_PI, M_PI, -1.1f, 1.1f, ratio, 0.05f, 0.2f, 0.4f, 0.9f); 90 | sr_graph::add_axes(gr3, 0.005f, 0.9f, 0.9f, 0.9f, false); 91 | sr_graph::add_grid(gr3, 1.0f, 0.2f, 0.004f, 0.8f, 0.8f, 0.8f, true); 92 | sr_graph::add_curve(gr3, xs3, ys3, 0.01f, 1.0f, 0.53f, 0.1f); 93 | 94 | 95 | // Graph 4: Lemniscate point plot. 96 | std::vector xs4; 97 | std::vector ys4; 98 | 99 | for (float theta = -M_PI; theta <= M_PI; theta += 2.0f*M_PI / 100.0f) { 100 | const float cs = cosf(theta + (float)_timer); 101 | const float sn = sinf(theta); 102 | xs4.push_back(sn / (1 + cs*cs)); 103 | ys4.push_back(sn * cs / (1 + cs*cs)); 104 | } 105 | 106 | gr4 = sr_graph::setup(-1.0f, 1.0f, -1.0f, 1.0f, ratio, 0.05f, 0.5f, 0.0f, 0.0f); 107 | sr_graph::add_grid(gr4, 0.1f, 0.1f, 0.0035f, 0.7f, 0.2f, 0.0f, false); 108 | sr_graph::add_points(gr4, xs4, ys4, 0.008f, 1.0f, 1.0f, 1.0f); 109 | 110 | /* 111 | // Graph 5: Charging a condensator. 112 | const float tau = 0.9f; 113 | const float E = 0.93f; 114 | 115 | gr5 = sr_graph::setup(0.0f, 5.0f, 0.0f, 1.0f, ratio, 0.05f, 1.0f, 1.0f, 1.0f); 116 | sr_graph::add_grid(gr5, 0.5f, 0.1f, 0.0035f, 0.6f, 0.6f, 0.6f, true); 117 | sr_graph::add_axes(gr5, 0.006f, 0.0f,0.0f,0.0f, true); 118 | 119 | // Limit and initial tangent. 120 | std::vector xs5b = {0.0f, 5.0f}; 121 | std::vector ys5b = {E, E}; 122 | sr_graph::add_curve(gr5, xs5b, ys5b, 0.0075f, 0.05f, 0.1f, 0.8f); 123 | std::vector xs5c = {0.0f, tau}; 124 | std::vector ys5c = {0.0f, E}; 125 | sr_graph::add_curve(gr5, xs5c, ys5c, 0.0075f, 0.8f, 0.05f, 0.1f); 126 | 127 | // Theoretical curve. 128 | std::vector xs5a; 129 | std::vector ys5a; 130 | for(float t = 0.0f; t < 5.0f;t+=0.1f){ 131 | xs5a.push_back(t); 132 | const float tension = E*(1.0f - exp(-t/tau)); 133 | ys5a.push_back(tension); 134 | } 135 | sr_graph::add_curve(gr5, xs5a, ys5a, 0.0075f, 0.05f, 0.8f, 0.1f); 136 | 137 | // Experimental points. 138 | std::vector xs5d = { 0.654898f, 1.93642f, 3.12904f, 1.05706f, 3.70182f, 4.06798f, 2.7657f, 0.390208f, 4.62793f, 0.795069f, 2.34131f, 3.61451f, 1.14334f, 2.41359f, 4.79167f, 3.04445f, 1.36835f, 1.41364f, 4.43056f, 0.747874f, 3.58727f, 1.01217f, 2.99215f, 0.12714f, 4.17702f, 0.51538f, 0.180101f, 1.98563f}; 139 | std::vector ys5d = { 0.511335f, 0.780862f, 0.925034f, 0.604544f, 0.901932f, 0.943024f, 0.920169f, 0.37064f, 0.959532f, 0.525493f, 0.888619f, 0.937215f, 0.650272f, 0.896746f, 0.925192f, 0.88925f, 0.739788f, 0.703377f, 0.960619f, 0.535305f, 0.881215f, 0.617891f, 0.881836f, 0.12358f, 0.95223f, 0.449745f, 0.119746f, 0.820037f}; 140 | sr_graph::add_points(gr5, xs5d, ys5d, 0.013f, 0.2f, 0.2f, 0.2f); 141 | */ 142 | } 143 | 144 | 145 | void Renderer::draw() { 146 | 147 | // Compute the time elapsed since last frame 148 | _timer = glfwGetTime(); 149 | 150 | // Update the histogram by drawing 1000 new random numbers. 151 | std::vector ys2; 152 | for(int i = 0; i < 1000; ++i){ 153 | ys2.push_back(Random::Float()); 154 | } 155 | sr_graph::update_hist(gr2, 0, ys2); 156 | ys2.clear(); 157 | 158 | // Update the sine, shifting its phase to translate it. 159 | std::vector xs3; 160 | std::vector ys3; 161 | for(float theta = -M_PI; theta <= M_PI; theta += 2.0f*M_PI/(200.0f)){ 162 | xs3.push_back(theta); 163 | ys3.push_back(sinf(theta*3.5f+4.0f*(float)_timer)); 164 | } 165 | sr_graph::update_curve(gr3, 0, xs3, ys3); 166 | xs3.clear(); 167 | ys3.clear(); 168 | 169 | // Update the lemniscate by dephasing the sinus. 170 | std::vector xs4; 171 | std::vector ys4; 172 | 173 | for (float theta = -M_PI; theta <= M_PI; theta += 2.0f*M_PI / 200.0f) { 174 | const float cs = cosf(theta+(float)_timer); 175 | const float sn = sinf(theta); 176 | xs4.push_back(sn / (1 + cs*cs)); 177 | ys4.push_back(sn * cs / (1 + cs*cs)); 178 | } 179 | sr_graph::update_points(gr4, 0, xs4, ys4); 180 | xs4.clear(); 181 | ys4.clear(); 182 | 183 | 184 | // Set screen viewport. 185 | glViewport(0, 0, GLsizei(_width), GLsizei(_height)); 186 | 187 | // Draw the fullscreen quad. Just a basic OpenGL thing before drawing the graphs. 188 | glClearColor(0.5f, 0.5f, 0.5f, 1.0f); 189 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 190 | 191 | 192 | GLsizei halfWidth = (GLsizei)floor(_width*0.5); 193 | GLsizei halfHeight = (GLsizei)floor(_height*0.5); 194 | float ratio = (float)_width/(float)_height; 195 | 196 | // Draw the four graphs, each in a quarter of the viewport. 197 | glViewport(0, halfHeight, halfWidth, halfHeight); 198 | sr_graph::draw(gr1, ratio); 199 | glViewport(0, 0, halfWidth, halfHeight); 200 | sr_graph::draw(gr2, ratio); 201 | glViewport(halfWidth, 0, halfWidth, halfHeight); 202 | sr_graph::draw(gr3, ratio); 203 | glViewport(halfWidth, halfHeight, halfWidth, halfHeight); 204 | sr_graph::draw(gr4, ratio); 205 | /* 206 | glViewport(0, 0, _width, _height); 207 | sr_graph::draw(gr5, ratio); 208 | */ 209 | 210 | // Update timer 211 | _timer = glfwGetTime(); 212 | } 213 | 214 | 215 | void Renderer::clean() const { 216 | // Clean objects. 217 | sr_graph::free(); 218 | } 219 | 220 | 221 | void Renderer::resize(int width, int height){ 222 | //Update the size of the viewport. 223 | glViewport(0, 0, width, height); 224 | // Update the projection matrix. 225 | _width = width; 226 | _height = height; 227 | } 228 | 229 | 230 | -------------------------------------------------------------------------------- /test/src/Renderer.h: -------------------------------------------------------------------------------- 1 | #ifndef Renderer_h 2 | #define Renderer_h 3 | 4 | class Renderer { 5 | 6 | public: 7 | 8 | 9 | ~Renderer(); 10 | 11 | /// Init function 12 | Renderer(int width, int height); 13 | 14 | /// Draw function 15 | void draw(); 16 | 17 | /// Clean function 18 | void clean() const; 19 | 20 | /// Handle screen resizing 21 | void resize(int width, int height); 22 | 23 | 24 | private: 25 | 26 | double _timer; 27 | int _width; 28 | int _height; 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /test/src/Utilities.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Utilities.h" 3 | 4 | void Random::seed(){ 5 | std::random_device rd; 6 | _seed = rd(); 7 | _mt = std::mt19937(_seed); 8 | _realDist = std::uniform_real_distribution(0,1); 9 | } 10 | 11 | void Random::seed(unsigned int seedValue){ 12 | _seed = seedValue; 13 | _mt = std::mt19937(_seed); 14 | _realDist = std::uniform_real_distribution(0,1); 15 | } 16 | 17 | int Random::Int(int min, int max){ 18 | return (int)(floor(Float() * (max+1 - min)) + min); 19 | } 20 | 21 | float Random::Float(){ 22 | return _realDist(_mt); 23 | } 24 | 25 | float Random::Float(float min, float max){ 26 | return _realDist(_mt)*(max-min)+min; 27 | } 28 | 29 | unsigned int Random::getSeed(){ 30 | return _seed; 31 | } 32 | 33 | std::mt19937 Random::_mt; 34 | std::uniform_real_distribution Random::_realDist; 35 | unsigned int Random::_seed; 36 | 37 | std::string getGLErrorString(GLenum error) { 38 | std::string msg; 39 | switch (error) { 40 | case GL_INVALID_ENUM: 41 | msg = "GL_INVALID_ENUM"; 42 | break; 43 | case GL_INVALID_VALUE: 44 | msg = "GL_INVALID_VALUE"; 45 | break; 46 | case GL_INVALID_OPERATION: 47 | msg = "GL_INVALID_OPERATION"; 48 | break; 49 | case GL_INVALID_FRAMEBUFFER_OPERATION: 50 | msg = "GL_INVALID_FRAMEBUFFER_OPERATION"; 51 | break; 52 | case GL_NO_ERROR: 53 | msg = "GL_NO_ERROR"; 54 | break; 55 | case GL_OUT_OF_MEMORY: 56 | msg = "GL_OUT_OF_MEMORY"; 57 | break; 58 | default: 59 | msg = "UNKNOWN_GL_ERROR"; 60 | } 61 | return msg; 62 | } 63 | 64 | int _checkGLError(const char *file, int line){ 65 | GLenum glErr = glGetError(); 66 | if (glErr != GL_NO_ERROR){ 67 | std::cerr << "glError in " << file << " (" << line << ") : " << getGLErrorString(glErr) << std::endl; 68 | return 1; 69 | } 70 | return 0; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /test/src/Utilities.h: -------------------------------------------------------------------------------- 1 | #ifndef Utilities_h 2 | #define Utilities_h 3 | #include 4 | #include 5 | #include 6 | 7 | class Random { 8 | public: 9 | 10 | static void seed(); 11 | 12 | static void seed(unsigned int seedValue); 13 | 14 | static int Int(int min, int max); 15 | 16 | static float Float(); 17 | 18 | static float Float(float min, float max); 19 | 20 | static unsigned int getSeed(); 21 | 22 | private: 23 | 24 | static unsigned int _seed; 25 | static std::mt19937 _mt; 26 | static std::uniform_real_distribution _realDist; 27 | }; 28 | 29 | /// This macro is used to check for OpenGL errors with access to the file and line number where the error is detected. 30 | #define checkGLError() _checkGLError(__FILE__, __LINE__) 31 | 32 | /// Converts a GLenum error number into a human-readable string. 33 | std::string getGLErrorString(GLenum error); 34 | 35 | /// Check if any OpenGL error has been detected and log it. 36 | int _checkGLError(const char *file, int line); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /test/src/libs/glfw/include/GLFW/glfw3native.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * GLFW 3.2 - www.glfw.org 3 | * A library for OpenGL, window and input 4 | *------------------------------------------------------------------------ 5 | * Copyright (c) 2002-2006 Marcus Geelnard 6 | * Copyright (c) 2006-2016 Camilla Berglund 7 | * 8 | * This software is provided 'as-is', without any express or implied 9 | * warranty. In no event will the authors be held liable for any damages 10 | * arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, 13 | * including commercial applications, and to alter it and redistribute it 14 | * freely, subject to the following restrictions: 15 | * 16 | * 1. The origin of this software must not be misrepresented; you must not 17 | * claim that you wrote the original software. If you use this software 18 | * in a product, an acknowledgment in the product documentation would 19 | * be appreciated but is not required. 20 | * 21 | * 2. Altered source versions must be plainly marked as such, and must not 22 | * be misrepresented as being the original software. 23 | * 24 | * 3. This notice may not be removed or altered from any source 25 | * distribution. 26 | * 27 | *************************************************************************/ 28 | 29 | #ifndef _glfw3_native_h_ 30 | #define _glfw3_native_h_ 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | 37 | /************************************************************************* 38 | * Doxygen documentation 39 | *************************************************************************/ 40 | 41 | /*! @file glfw3native.h 42 | * @brief The header of the native access functions. 43 | * 44 | * This is the header file of the native access functions. See @ref native for 45 | * more information. 46 | */ 47 | /*! @defgroup native Native access 48 | * 49 | * **By using the native access functions you assert that you know what you're 50 | * doing and how to fix problems caused by using them. If you don't, you 51 | * shouldn't be using them.** 52 | * 53 | * Before the inclusion of @ref glfw3native.h, you may define exactly one 54 | * window system API macro and zero or more context creation API macros. 55 | * 56 | * The chosen backends must match those the library was compiled for. Failure 57 | * to do this will cause a link-time error. 58 | * 59 | * The available window API macros are: 60 | * * `GLFW_EXPOSE_NATIVE_WIN32` 61 | * * `GLFW_EXPOSE_NATIVE_COCOA` 62 | * * `GLFW_EXPOSE_NATIVE_X11` 63 | * * `GLFW_EXPOSE_NATIVE_WAYLAND` 64 | * * `GLFW_EXPOSE_NATIVE_MIR` 65 | * 66 | * The available context API macros are: 67 | * * `GLFW_EXPOSE_NATIVE_WGL` 68 | * * `GLFW_EXPOSE_NATIVE_NSGL` 69 | * * `GLFW_EXPOSE_NATIVE_GLX` 70 | * * `GLFW_EXPOSE_NATIVE_EGL` 71 | * 72 | * These macros select which of the native access functions that are declared 73 | * and which platform-specific headers to include. It is then up your (by 74 | * definition platform-specific) code to handle which of these should be 75 | * defined. 76 | */ 77 | 78 | 79 | /************************************************************************* 80 | * System headers and types 81 | *************************************************************************/ 82 | 83 | #if defined(GLFW_EXPOSE_NATIVE_WIN32) 84 | // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for 85 | // example to allow applications to correctly declare a GL_ARB_debug_output 86 | // callback) but windows.h assumes no one will define APIENTRY before it does 87 | #undef APIENTRY 88 | #include 89 | #elif defined(GLFW_EXPOSE_NATIVE_COCOA) 90 | #include 91 | #if defined(__OBJC__) 92 | #import 93 | #else 94 | typedef void* id; 95 | #endif 96 | #elif defined(GLFW_EXPOSE_NATIVE_X11) 97 | #include 98 | #include 99 | #elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) 100 | #include 101 | #elif defined(GLFW_EXPOSE_NATIVE_MIR) 102 | #include 103 | #endif 104 | 105 | #if defined(GLFW_EXPOSE_NATIVE_WGL) 106 | /* WGL is declared by windows.h */ 107 | #endif 108 | #if defined(GLFW_EXPOSE_NATIVE_NSGL) 109 | /* NSGL is declared by Cocoa.h */ 110 | #endif 111 | #if defined(GLFW_EXPOSE_NATIVE_GLX) 112 | #include 113 | #endif 114 | #if defined(GLFW_EXPOSE_NATIVE_EGL) 115 | #include 116 | #endif 117 | 118 | 119 | /************************************************************************* 120 | * Functions 121 | *************************************************************************/ 122 | 123 | #if defined(GLFW_EXPOSE_NATIVE_WIN32) 124 | /*! @brief Returns the adapter device name of the specified monitor. 125 | * 126 | * @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) 127 | * of the specified monitor, or `NULL` if an [error](@ref error_handling) 128 | * occurred. 129 | * 130 | * @thread_safety This function may be called from any thread. Access is not 131 | * synchronized. 132 | * 133 | * @since Added in version 3.1. 134 | * 135 | * @ingroup native 136 | */ 137 | GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); 138 | 139 | /*! @brief Returns the display device name of the specified monitor. 140 | * 141 | * @return The UTF-8 encoded display device name (for example 142 | * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an 143 | * [error](@ref error_handling) occurred. 144 | * 145 | * @thread_safety This function may be called from any thread. Access is not 146 | * synchronized. 147 | * 148 | * @since Added in version 3.1. 149 | * 150 | * @ingroup native 151 | */ 152 | GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); 153 | 154 | /*! @brief Returns the `HWND` of the specified window. 155 | * 156 | * @return The `HWND` of the specified window, or `NULL` if an 157 | * [error](@ref error_handling) occurred. 158 | * 159 | * @thread_safety This function may be called from any thread. Access is not 160 | * synchronized. 161 | * 162 | * @since Added in version 3.0. 163 | * 164 | * @ingroup native 165 | */ 166 | GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); 167 | #endif 168 | 169 | #if defined(GLFW_EXPOSE_NATIVE_WGL) 170 | /*! @brief Returns the `HGLRC` of the specified window. 171 | * 172 | * @return The `HGLRC` of the specified window, or `NULL` if an 173 | * [error](@ref error_handling) occurred. 174 | * 175 | * @thread_safety This function may be called from any thread. Access is not 176 | * synchronized. 177 | * 178 | * @since Added in version 3.0. 179 | * 180 | * @ingroup native 181 | */ 182 | GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); 183 | #endif 184 | 185 | #if defined(GLFW_EXPOSE_NATIVE_COCOA) 186 | /*! @brief Returns the `CGDirectDisplayID` of the specified monitor. 187 | * 188 | * @return The `CGDirectDisplayID` of the specified monitor, or 189 | * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. 190 | * 191 | * @thread_safety This function may be called from any thread. Access is not 192 | * synchronized. 193 | * 194 | * @since Added in version 3.1. 195 | * 196 | * @ingroup native 197 | */ 198 | GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); 199 | 200 | /*! @brief Returns the `NSWindow` of the specified window. 201 | * 202 | * @return The `NSWindow` of the specified window, or `nil` if an 203 | * [error](@ref error_handling) occurred. 204 | * 205 | * @thread_safety This function may be called from any thread. Access is not 206 | * synchronized. 207 | * 208 | * @since Added in version 3.0. 209 | * 210 | * @ingroup native 211 | */ 212 | GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); 213 | #endif 214 | 215 | #if defined(GLFW_EXPOSE_NATIVE_NSGL) 216 | /*! @brief Returns the `NSOpenGLContext` of the specified window. 217 | * 218 | * @return The `NSOpenGLContext` of the specified window, or `nil` if an 219 | * [error](@ref error_handling) occurred. 220 | * 221 | * @thread_safety This function may be called from any thread. Access is not 222 | * synchronized. 223 | * 224 | * @since Added in version 3.0. 225 | * 226 | * @ingroup native 227 | */ 228 | GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); 229 | #endif 230 | 231 | #if defined(GLFW_EXPOSE_NATIVE_X11) 232 | /*! @brief Returns the `Display` used by GLFW. 233 | * 234 | * @return The `Display` used by GLFW, or `NULL` if an 235 | * [error](@ref error_handling) occurred. 236 | * 237 | * @thread_safety This function may be called from any thread. Access is not 238 | * synchronized. 239 | * 240 | * @since Added in version 3.0. 241 | * 242 | * @ingroup native 243 | */ 244 | GLFWAPI Display* glfwGetX11Display(void); 245 | 246 | /*! @brief Returns the `RRCrtc` of the specified monitor. 247 | * 248 | * @return The `RRCrtc` of the specified monitor, or `None` if an 249 | * [error](@ref error_handling) occurred. 250 | * 251 | * @thread_safety This function may be called from any thread. Access is not 252 | * synchronized. 253 | * 254 | * @since Added in version 3.1. 255 | * 256 | * @ingroup native 257 | */ 258 | GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); 259 | 260 | /*! @brief Returns the `RROutput` of the specified monitor. 261 | * 262 | * @return The `RROutput` of the specified monitor, or `None` if an 263 | * [error](@ref error_handling) occurred. 264 | * 265 | * @thread_safety This function may be called from any thread. Access is not 266 | * synchronized. 267 | * 268 | * @since Added in version 3.1. 269 | * 270 | * @ingroup native 271 | */ 272 | GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); 273 | 274 | /*! @brief Returns the `Window` of the specified window. 275 | * 276 | * @return The `Window` of the specified window, or `None` if an 277 | * [error](@ref error_handling) occurred. 278 | * 279 | * @thread_safety This function may be called from any thread. Access is not 280 | * synchronized. 281 | * 282 | * @since Added in version 3.0. 283 | * 284 | * @ingroup native 285 | */ 286 | GLFWAPI Window glfwGetX11Window(GLFWwindow* window); 287 | #endif 288 | 289 | #if defined(GLFW_EXPOSE_NATIVE_GLX) 290 | /*! @brief Returns the `GLXContext` of the specified window. 291 | * 292 | * @return The `GLXContext` of the specified window, or `NULL` if an 293 | * [error](@ref error_handling) occurred. 294 | * 295 | * @thread_safety This function may be called from any thread. Access is not 296 | * synchronized. 297 | * 298 | * @since Added in version 3.0. 299 | * 300 | * @ingroup native 301 | */ 302 | GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); 303 | 304 | /*! @brief Returns the `GLXWindow` of the specified window. 305 | * 306 | * @return The `GLXWindow` of the specified window, or `None` if an 307 | * [error](@ref error_handling) occurred. 308 | * 309 | * @thread_safety This function may be called from any thread. Access is not 310 | * synchronized. 311 | * 312 | * @since Added in version 3.2. 313 | * 314 | * @ingroup native 315 | */ 316 | GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window); 317 | #endif 318 | 319 | #if defined(GLFW_EXPOSE_NATIVE_WAYLAND) 320 | /*! @brief Returns the `struct wl_display*` used by GLFW. 321 | * 322 | * @return The `struct wl_display*` used by GLFW, or `NULL` if an 323 | * [error](@ref error_handling) occurred. 324 | * 325 | * @thread_safety This function may be called from any thread. Access is not 326 | * synchronized. 327 | * 328 | * @since Added in version 3.2. 329 | * 330 | * @ingroup native 331 | */ 332 | GLFWAPI struct wl_display* glfwGetWaylandDisplay(void); 333 | 334 | /*! @brief Returns the `struct wl_output*` of the specified monitor. 335 | * 336 | * @return The `struct wl_output*` of the specified monitor, or `NULL` if an 337 | * [error](@ref error_handling) occurred. 338 | * 339 | * @thread_safety This function may be called from any thread. Access is not 340 | * synchronized. 341 | * 342 | * @since Added in version 3.2. 343 | * 344 | * @ingroup native 345 | */ 346 | GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); 347 | 348 | /*! @brief Returns the main `struct wl_surface*` of the specified window. 349 | * 350 | * @return The main `struct wl_surface*` of the specified window, or `NULL` if 351 | * an [error](@ref error_handling) occurred. 352 | * 353 | * @thread_safety This function may be called from any thread. Access is not 354 | * synchronized. 355 | * 356 | * @since Added in version 3.2. 357 | * 358 | * @ingroup native 359 | */ 360 | GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); 361 | #endif 362 | 363 | #if defined(GLFW_EXPOSE_NATIVE_MIR) 364 | /*! @brief Returns the `MirConnection*` used by GLFW. 365 | * 366 | * @return The `MirConnection*` used by GLFW, or `NULL` if an 367 | * [error](@ref error_handling) occurred. 368 | * 369 | * @thread_safety This function may be called from any thread. Access is not 370 | * synchronized. 371 | * 372 | * @since Added in version 3.2. 373 | * 374 | * @ingroup native 375 | */ 376 | GLFWAPI MirConnection* glfwGetMirDisplay(void); 377 | 378 | /*! @brief Returns the Mir output ID of the specified monitor. 379 | * 380 | * @return The Mir output ID of the specified monitor, or zero if an 381 | * [error](@ref error_handling) occurred. 382 | * 383 | * @thread_safety This function may be called from any thread. Access is not 384 | * synchronized. 385 | * 386 | * @since Added in version 3.2. 387 | * 388 | * @ingroup native 389 | */ 390 | GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor); 391 | 392 | /*! @brief Returns the `MirSurface*` of the specified window. 393 | * 394 | * @return The `MirSurface*` of the specified window, or `NULL` if an 395 | * [error](@ref error_handling) occurred. 396 | * 397 | * @thread_safety This function may be called from any thread. Access is not 398 | * synchronized. 399 | * 400 | * @since Added in version 3.2. 401 | * 402 | * @ingroup native 403 | */ 404 | GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window); 405 | #endif 406 | 407 | #if defined(GLFW_EXPOSE_NATIVE_EGL) 408 | /*! @brief Returns the `EGLDisplay` used by GLFW. 409 | * 410 | * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an 411 | * [error](@ref error_handling) occurred. 412 | * 413 | * @thread_safety This function may be called from any thread. Access is not 414 | * synchronized. 415 | * 416 | * @since Added in version 3.0. 417 | * 418 | * @ingroup native 419 | */ 420 | GLFWAPI EGLDisplay glfwGetEGLDisplay(void); 421 | 422 | /*! @brief Returns the `EGLContext` of the specified window. 423 | * 424 | * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an 425 | * [error](@ref error_handling) occurred. 426 | * 427 | * @thread_safety This function may be called from any thread. Access is not 428 | * synchronized. 429 | * 430 | * @since Added in version 3.0. 431 | * 432 | * @ingroup native 433 | */ 434 | GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); 435 | 436 | /*! @brief Returns the `EGLSurface` of the specified window. 437 | * 438 | * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an 439 | * [error](@ref error_handling) occurred. 440 | * 441 | * @thread_safety This function may be called from any thread. Access is not 442 | * synchronized. 443 | * 444 | * @since Added in version 3.0. 445 | * 446 | * @ingroup native 447 | */ 448 | GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); 449 | #endif 450 | 451 | #ifdef __cplusplus 452 | } 453 | #endif 454 | 455 | #endif /* _glfw3_native_h_ */ 456 | 457 | -------------------------------------------------------------------------------- /test/src/libs/glfw/lib-mac/libglfw3.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosua20/sr_graph/e96e3ac356f0211bd0a0c5a1fd2bd5bcba3fff46/test/src/libs/glfw/lib-mac/libglfw3.a -------------------------------------------------------------------------------- /test/src/libs/glfw/lib-win-vc2015-64/glfw3.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosua20/sr_graph/e96e3ac356f0211bd0a0c5a1fd2bd5bcba3fff46/test/src/libs/glfw/lib-win-vc2015-64/glfw3.dll -------------------------------------------------------------------------------- /test/src/libs/glfw/lib-win-vc2015-64/glfw3.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosua20/sr_graph/e96e3ac356f0211bd0a0c5a1fd2bd5bcba3fff46/test/src/libs/glfw/lib-win-vc2015-64/glfw3.lib -------------------------------------------------------------------------------- /test/src/libs/glfw/lib-win-vc2015-64/glfw3dll.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosua20/sr_graph/e96e3ac356f0211bd0a0c5a1fd2bd5bcba3fff46/test/src/libs/glfw/lib-win-vc2015-64/glfw3dll.lib -------------------------------------------------------------------------------- /test/src/libs/glfw/lib-win-vc2015/glfw3.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosua20/sr_graph/e96e3ac356f0211bd0a0c5a1fd2bd5bcba3fff46/test/src/libs/glfw/lib-win-vc2015/glfw3.dll -------------------------------------------------------------------------------- /test/src/libs/glfw/lib-win-vc2015/glfw3.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosua20/sr_graph/e96e3ac356f0211bd0a0c5a1fd2bd5bcba3fff46/test/src/libs/glfw/lib-win-vc2015/glfw3.lib -------------------------------------------------------------------------------- /test/src/libs/glfw/lib-win-vc2015/glfw3dll.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kosua20/sr_graph/e96e3ac356f0211bd0a0c5a1fd2bd5bcba3fff46/test/src/libs/glfw/lib-win-vc2015/glfw3dll.lib -------------------------------------------------------------------------------- /test/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include // to set up the OpenGL context and manage window lifecycle and inputs 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "Renderer.h" 9 | 10 | #define INITIAL_SIZE_WIDTH 800 11 | #define INITIAL_SIZE_HEIGHT 600 12 | 13 | 14 | 15 | /// Callbacks 16 | 17 | void resize_callback(GLFWwindow* window, int width, int height){ 18 | Renderer *rendererPtr = static_cast(glfwGetWindowUserPointer(window)); 19 | rendererPtr->resize(width, height); 20 | } 21 | 22 | void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods){ 23 | // Handle quitting 24 | if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS){ 25 | glfwSetWindowShouldClose(window, GL_TRUE); 26 | return; 27 | } 28 | 29 | } 30 | 31 | 32 | /// The main function 33 | 34 | int main () { 35 | // Initialize glfw, which will create and setup an OpenGL context. 36 | if (!glfwInit()) { 37 | std::cerr << "ERROR: could not start GLFW3" << std::endl; 38 | return 1; 39 | } 40 | 41 | glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3); 42 | glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 2); 43 | glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 44 | glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 45 | 46 | 47 | // Create a window with a given size. Width and height are macros as we will need them again. 48 | GLFWwindow* window = glfwCreateWindow(INITIAL_SIZE_WIDTH, INITIAL_SIZE_HEIGHT,"Test sr_graph", NULL, NULL); 49 | if (!window) { 50 | std::cerr << "ERROR: could not open window with GLFW3" << std::endl; 51 | glfwTerminate(); 52 | return 1; 53 | } 54 | 55 | // Bind the OpenGL context and the new window. 56 | glfwMakeContextCurrent(window); 57 | 58 | if (gl3wInit()) { 59 | std::cerr << "Failed to initialize OpenGL" << std::endl; 60 | return -1; 61 | } 62 | if (!gl3wIsSupported(3, 2)) { 63 | std::cerr << "OpenGL 3.2 not supported\n" << std::endl; 64 | return -1; 65 | } 66 | 67 | // Create the renderer. 68 | Renderer renderer = Renderer(INITIAL_SIZE_WIDTH,INITIAL_SIZE_HEIGHT); 69 | 70 | glfwSetWindowUserPointer(window, &renderer); 71 | // Setup callbacks for various interactions and inputs. 72 | glfwSetFramebufferSizeCallback(window, resize_callback); // Resizing the window 73 | glfwSetKeyCallback(window,key_callback); // Pressing a key 74 | 75 | // On HiDPI screens, we might have to initially resize the framebuffers size. 76 | int width, height; 77 | glfwGetFramebufferSize(window, &width, &height); 78 | renderer.resize(width, height); 79 | 80 | // Start the display/interaction loop. 81 | while (!glfwWindowShouldClose(window)) { 82 | 83 | // Update the content of the window. 84 | renderer.draw(); 85 | 86 | //Display the result fo the current rendering loop. 87 | glfwSwapBuffers(window); 88 | 89 | // Update events (inputs,...). 90 | glfwPollEvents(); 91 | } 92 | 93 | // Remove the window. 94 | glfwDestroyWindow(window); 95 | // Clean other resources 96 | renderer.clean(); 97 | // Close GL context and any other GLFW resources. 98 | glfwTerminate(); 99 | return 0; 100 | } 101 | 102 | 103 | --------------------------------------------------------------------------------