1 /*
2  *  Copyright (c) 2012-2016, Bruno Levy
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *
8  *  * Redistributions of source code must retain the above copyright notice,
9  *  this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright notice,
11  *  this list of conditions and the following disclaimer in the documentation
12  *  and/or other materials provided with the distribution.
13  *  * Neither the name of the ALICE Project-Team nor the names of its
14  *  contributors may be used to endorse or promote products derived from this
15  *  software without specific prior written permission.
16  *
17  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  *  POSSIBILITY OF SUCH DAMAGE.
28  *
29  *  If you modify this software, you should include a notice giving the
30  *  name of the person performing the modification, the date of modification,
31  *  and the reason for such modification.
32  *
33  *  Contact: Bruno Levy
34  *
35  *     Bruno.Levy@inria.fr
36  *     http://www.loria.fr/~levy
37  *
38  *     ALICE Project
39  *     LORIA, INRIA Lorraine,
40  *     Campus Scientifique, BP 239
41  *     54506 VANDOEUVRE LES NANCY CEDEX
42  *     FRANCE
43  *
44  */
45 
46 #include <geogram_gfx/GLUP/GLUP_context.h>
47 #include <geogram_gfx/GLUP/shaders/embedded_shaders.h>
48 #include <geogram_gfx/basic/GLSL.h>
49 
50 #include <geogram/basic/command_line.h>
51 #include <geogram/basic/progress.h>
52 #include <geogram/basic/logger.h>
53 
54 #include <geogram/bibliography/bibliography.h>
55 
56 #ifdef GEO_OS_ANDROID
57 #  pragma GCC diagnostic ignored "-Wpointer-bool-conversion"
58 #  pragma GCC diagnostic ignored "-Wtautological-pointer-compare"
59 #endif
60 
61 // TODO: for points and spheres: early fragment tests, depth greater
62 // (+ vertex shader that "drags the point to the camera" in such a way
63 //  that the frag shader "pushes to the back" and we can have early depth
64 //  cull (this can probably significantly accelerate rendering when there is
65 //  a large number of big spheres/points).
66 //      layout(early_fragment_tests) in;
67 //       layout(depth_greater) out float gl_FragDepth;
68 // -----------------------------------------------------------------------------
69 
70 // TODO: in OpenGL, matrix storage is row major (oh my)... Most of my functions
71 //  that manipulate matrices need to be renamed/rewritten, in the current state
72 //  my code is *VERY CONFUSING* !!!
73 // This concerns:
74 //    -all the functions that create matrices (for now I transpose right after).
75 //    -glupUnProject()
76 //------------------------------------------------------------------------------
77 
78 
79 namespace {
80     using namespace GEO;
81 
82 
vertex_shader_preamble_pseudo_file(GLSL::PseudoFileProvider * provider,std::vector<GLSL::Source> & sources)83     void vertex_shader_preamble_pseudo_file(
84 	GLSL::PseudoFileProvider* provider, std::vector<GLSL::Source>& sources
85     ) {
86 	GLUP::Context* ctxt = dynamic_cast<GLUP::Context*>(provider);
87 	geo_assert(ctxt != nullptr);
88 	ctxt->get_vertex_shader_preamble_pseudo_file(sources);
89 	sources.push_back("#define ");
90 	sources.push_back(ctxt->profile_name());
91 	sources.push_back("\n");
92     }
93 
fragment_shader_preamble_pseudo_file(GLSL::PseudoFileProvider * provider,std::vector<GLSL::Source> & sources)94     void fragment_shader_preamble_pseudo_file(
95 	GLSL::PseudoFileProvider* provider, std::vector<GLSL::Source>& sources
96     ) {
97 	GLUP::Context* ctxt = dynamic_cast<GLUP::Context*>(provider);
98 	geo_assert(ctxt != nullptr);
99 	ctxt->get_fragment_shader_preamble_pseudo_file(sources);
100 	sources.push_back("#define ");
101 	sources.push_back(ctxt->profile_name());
102 	sources.push_back("\n");
103     }
104 
geometry_shader_preamble_pseudo_file(GLSL::PseudoFileProvider * provider,std::vector<GLSL::Source> & sources)105     void geometry_shader_preamble_pseudo_file(
106 	GLSL::PseudoFileProvider* provider, std::vector<GLSL::Source>& sources
107     ) {
108 	GLUP::Context* ctxt = dynamic_cast<GLUP::Context*>(provider);
109 	geo_assert(ctxt != nullptr);
110 	ctxt->get_geometry_shader_preamble_pseudo_file(sources);
111 	sources.push_back("#define ");
112 	sources.push_back(ctxt->profile_name());
113 	sources.push_back("\n");
114     }
115 
marching_cells_pseudo_file(GLSL::PseudoFileProvider * provider,std::vector<GLSL::Source> & sources)116     void marching_cells_pseudo_file(
117 	GLSL::PseudoFileProvider* provider, std::vector<GLSL::Source>& sources
118     ) {
119 	GLUP::Context* ctxt = dynamic_cast<GLUP::Context*>(provider);
120 	geo_assert(ctxt != nullptr);
121 	ctxt->get_marching_cells_pseudo_file(sources);
122 	sources.push_back("#define ");
123 	sources.push_back(ctxt->profile_name());
124 	sources.push_back("\n");
125     }
126 
tess_control_shader_preamble_pseudo_file(GLSL::PseudoFileProvider * provider,std::vector<GLSL::Source> & sources)127     void tess_control_shader_preamble_pseudo_file(
128 	GLSL::PseudoFileProvider* provider, std::vector<GLSL::Source>& sources
129     ) {
130 	GLUP::Context* ctxt = dynamic_cast<GLUP::Context*>(provider);
131 	geo_assert(ctxt != nullptr);
132 	ctxt->get_tess_control_shader_preamble_pseudo_file(sources);
133 	sources.push_back("#define ");
134 	sources.push_back(ctxt->profile_name());
135 	sources.push_back("\n");
136     }
137 
tess_evaluation_shader_preamble_pseudo_file(GLSL::PseudoFileProvider * provider,std::vector<GLSL::Source> & sources)138     void tess_evaluation_shader_preamble_pseudo_file(
139 	GLSL::PseudoFileProvider* provider, std::vector<GLSL::Source>& sources
140     ) {
141 	GLUP::Context* ctxt = dynamic_cast<GLUP::Context*>(provider);
142 	geo_assert(ctxt != nullptr);
143 	ctxt->get_tess_evaluation_shader_preamble_pseudo_file(sources);
144 	sources.push_back("#define ");
145 	sources.push_back(ctxt->profile_name());
146 	sources.push_back("\n");
147     }
148 
toggles_pseudo_file(GLSL::PseudoFileProvider * provider,std::vector<GLSL::Source> & sources)149     void toggles_pseudo_file(
150 	GLSL::PseudoFileProvider* provider, std::vector<GLSL::Source>& sources
151     ) {
152 	GLUP::Context* ctxt = dynamic_cast<GLUP::Context*>(provider);
153 	geo_assert(ctxt != nullptr);
154 	ctxt->get_toggles_pseudo_file(sources);
155     }
156 
primitive_pseudo_file(GLSL::PseudoFileProvider * provider,std::vector<GLSL::Source> & sources)157     void primitive_pseudo_file(
158 	GLSL::PseudoFileProvider* provider, std::vector<GLSL::Source>& sources
159     ) {
160 	GLUP::Context* ctxt = dynamic_cast<GLUP::Context*>(provider);
161 	geo_assert(ctxt != nullptr);
162 	ctxt->get_primitive_pseudo_file(sources);
163     }
164 }
165 
166 namespace GLUP {
167     using namespace GEO;
168 
169     /*************************************************************************/
170 
show_matrix(const GLfloat M[16])171     void show_matrix(const GLfloat M[16]) {
172         for(index_t i=0; i<4; ++i) {
173             for(index_t j=0; j<4; ++j) {
174                 std::cerr << M[4*i+j] << ' ';
175             }
176             std::cerr << std::endl;
177         }
178     }
179 
show_vector(const GLfloat v[4])180     void show_vector(const GLfloat v[4]) {
181         for(index_t i=0; i<4; ++i) {
182             std::cerr << v[i] << ' ';
183         }
184         std::cerr << std::endl;
185     }
186 
187     // Used to determine buffer's maximum vertex index, that needs
188     // to be an integer multiple of the number of vertices
189     // per primitive.
190     index_t nb_vertices_per_primitive[GLUP_NB_PRIMITIVES] = {
191         1, // GLUP_POINTS     =0,
192         2, // GLUP_LINES      =1,
193         3, // GLUP_TRIANGLES  =2,
194         4, // GLUP_QUADS      =3,
195         4, // GLUP_TETRAHEDRA =4,
196         8, // GLUP_HEXAHEDRA  =5,
197         6, // GLUP_PRISMS     =6,
198         5, // GLUP_PYRAMIDS   =7,
199         4, // GLUP_CONNECTORS =8,
200 	1  // GLUP_SPHERES    =9
201     };
202 
nb_vertices_per_GL_primitive(GLenum primitive)203     static index_t nb_vertices_per_GL_primitive(GLenum primitive) {
204         index_t result = 0;
205         switch(primitive) {
206         case GL_POINTS:
207             result = 1;
208             break;
209         case GL_LINES:
210             result = 2;
211             break;
212         case GL_TRIANGLES:
213             result = 3;
214             break;
215 #ifdef GEO_GL_150
216         case GL_LINES_ADJACENCY:
217             result = 4;
218             break;
219         case GL_TRIANGLES_ADJACENCY:
220             result = 6;
221             break;
222 #endif
223         default:
224             geo_assert_not_reached;
225         }
226         return result;
227     }
228 
extension_is_supported(const std::string & extension)229     bool Context::extension_is_supported(const std::string& extension) {
230 #ifndef GEO_OS_EMSCRIPTEN
231         // This is the new way of testing for an extension: first get
232         // the number of extensions, then extension names one extension
233         // at a time using glGetStringi
234         if(use_core_profile_) {
235             if(glGetStringi != nullptr) {
236                 GLuint num_ext;
237                 glGetIntegerv(GL_NUM_EXTENSIONS, (GLint*)&num_ext);
238                 if(num_ext != 0) {
239                     for(GLuint i=0; i<num_ext; ++i) {
240                         const GLubyte* cur_extension =
241                             glGetStringi(GL_EXTENSIONS, i);
242                         if(!strcmp(
243                                extension.c_str(),
244                                (const char*)cur_extension)
245                         ) {
246                             return true;
247                         }
248                     }
249                 }
250             }
251         }
252 #endif
253 
254         // If new way is unsupported or if using an old-style OpenGL
255         // context, then we do it the old way.
256 
257         // It can happen for instance with OpenGL ES 2.0, that does not
258         // support glGetStringi...
259 
260         const char* extensions = (const char*)(glGetString(GL_EXTENSIONS));
261         if(extensions == nullptr) {
262             return false;
263         }
264         return (strstr(extensions, extension.c_str()) != nullptr);
265     }
266 
267     static const char* primitive_name[GLUP_NB_PRIMITIVES] = {
268         "GLUP_POINTS",
269         "GLUP_LINES",
270         "GLUP_TRIANGLES",
271         "GLUP_QUADS",
272         "GLUP_TETRAHEDRA",
273         "GLUP_HEXAHEDRA",
274         "GLUP_PRISMS",
275         "GLUP_PYRAMIDS",
276         "GLUP_CONNECTORS",
277 	"GLUP_SPHERES"
278     };
279 
glup_primitive_name(GLUPprimitive prim)280     const char* Context::glup_primitive_name(GLUPprimitive prim) {
281         return primitive_name[prim];
282     }
283 
284     static index_t primitive_dimension[GLUP_NB_PRIMITIVES] = {
285         0, // GLUP_POINTS     =0,
286         1, // GLUP_LINES      =1,
287         2, // GLUP_TRIANGLES  =2,
288         2, // GLUP_QUADS      =3,
289         3, // GLUP_TETRAHEDRA =4,
290         3, // GLUP_HEXAHEDRA  =5,
291         3, // GLUP_PRISMS     =6,
292         3, // GLUP_PYRAMIDS   =7,
293         3, // GLUP_CONNECTORS =8,
294 	0  // GLUP_SPHERES    =9
295     };
296 
297 
298     /*
299     ** Invert 4x4 matrix.
300     ** Contributed by David Moore (See Mesa bug #6748)
301     */
302     template <class T> inline
invert_matrix_generic(T inv[16],const T m[16])303     GLboolean invert_matrix_generic(T inv[16], const T m[16]) {
304 
305         inv[0]  = m[5]*m[10]*m[15] - m[5]*m[11]*m[14] - m[9]*m[6]*m[15]
306                 + m[9]*m[7]*m[14] + m[13]*m[6]*m[11] - m[13]*m[7]*m[10];
307         inv[4]  = -m[4]*m[10]*m[15] + m[4]*m[11]*m[14] + m[8]*m[6]*m[15]
308                 - m[8]*m[7]*m[14] - m[12]*m[6]*m[11] + m[12]*m[7]*m[10];
309         inv[8]  = m[4]*m[9]*m[15] - m[4]*m[11]*m[13] - m[8]*m[5]*m[15]
310                 + m[8]*m[7]*m[13] + m[12]*m[5]*m[11] - m[12]*m[7]*m[9];
311         inv[12] = -m[4]*m[9]*m[14] + m[4]*m[10]*m[13] + m[8]*m[5]*m[14]
312                 - m[8]*m[6]*m[13] - m[12]*m[5]*m[10] + m[12]*m[6]*m[9];
313         inv[1]  = -m[1]*m[10]*m[15] + m[1]*m[11]*m[14] + m[9]*m[2]*m[15]
314                 - m[9]*m[3]*m[14] - m[13]*m[2]*m[11] + m[13]*m[3]*m[10];
315         inv[5]  = m[0]*m[10]*m[15] - m[0]*m[11]*m[14] - m[8]*m[2]*m[15]
316                 + m[8]*m[3]*m[14] + m[12]*m[2]*m[11] - m[12]*m[3]*m[10];
317         inv[9]  = -m[0]*m[9]*m[15] + m[0]*m[11]*m[13] + m[8]*m[1]*m[15]
318                 - m[8]*m[3]*m[13] - m[12]*m[1]*m[11] + m[12]*m[3]*m[9];
319         inv[13] = m[0]*m[9]*m[14] - m[0]*m[10]*m[13] - m[8]*m[1]*m[14]
320                 + m[8]*m[2]*m[13] + m[12]*m[1]*m[10] - m[12]*m[2]*m[9];
321         inv[2]  = m[1]*m[6]*m[15] - m[1]*m[7]*m[14] - m[5]*m[2]*m[15]
322                 + m[5]*m[3]*m[14] + m[13]*m[2]*m[7] - m[13]*m[3]*m[6];
323         inv[6]  = -m[0]*m[6]*m[15] + m[0]*m[7]*m[14] + m[4]*m[2]*m[15]
324                 - m[4]*m[3]*m[14] - m[12]*m[2]*m[7] + m[12]*m[3]*m[6];
325         inv[10] = m[0]*m[5]*m[15] - m[0]*m[7]*m[13] - m[4]*m[1]*m[15]
326                 + m[4]*m[3]*m[13] + m[12]*m[1]*m[7] - m[12]*m[3]*m[5];
327         inv[14] = -m[0]*m[5]*m[14] + m[0]*m[6]*m[13] + m[4]*m[1]*m[14]
328                 - m[4]*m[2]*m[13] - m[12]*m[1]*m[6] + m[12]*m[2]*m[5];
329         inv[3]  = -m[1]*m[6]*m[11] + m[1]*m[7]*m[10] + m[5]*m[2]*m[11]
330                 - m[5]*m[3]*m[10] - m[9]*m[2]*m[7] + m[9]*m[3]*m[6];
331         inv[7]  = m[0]*m[6]*m[11] - m[0]*m[7]*m[10] - m[4]*m[2]*m[11]
332                 + m[4]*m[3]*m[10] + m[8]*m[2]*m[7] - m[8]*m[3]*m[6];
333         inv[11] = -m[0]*m[5]*m[11] + m[0]*m[7]*m[9] + m[4]*m[1]*m[11]
334                 - m[4]*m[3]*m[9] - m[8]*m[1]*m[7] + m[8]*m[3]*m[5];
335         inv[15] = m[0]*m[5]*m[10] - m[0]*m[6]*m[9] - m[4]*m[1]*m[10]
336                 + m[4]*m[2]*m[9] + m[8]*m[1]*m[6] - m[8]*m[2]*m[5];
337 
338         T det = m[0]*inv[0] + m[1]*inv[4] + m[2]*inv[8] + m[3]*inv[12];
339 
340         if (det == T(0.0)) {
341             return GL_FALSE;
342         }
343 
344         det = T(1.0) / det;
345 
346         for (index_t i = 0; i < 16; ++i) {
347             inv[i] *= det;
348         }
349 
350         return GL_TRUE;
351     }
352 
invert_matrix(GLfloat inv[16],const GLfloat m[16])353     GLboolean invert_matrix(GLfloat inv[16], const GLfloat m[16]) {
354 	return invert_matrix_generic(inv,m);
355     }
356 
invert_matrix(GLdouble inv[16],const GLdouble m[16])357     GLboolean invert_matrix(GLdouble inv[16], const GLdouble m[16]) {
358 	return invert_matrix_generic(inv,m);
359     }
360 
mult_matrices(GLfloat out[16],const GLfloat m1[16],const GLfloat m2[16])361     void mult_matrices(
362         GLfloat out[16], const GLfloat m1[16], const GLfloat m2[16]
363     ) {
364         Memory::clear(out, sizeof(GLfloat)*16);
365         for(index_t i=0; i<4; ++i) {
366             for(index_t j=0; j<4; ++j) {
367                 for(index_t k=0; k<4; ++k) {
368                     out[i*4+j] += m1[i*4+k]*m2[k*4+j];
369                 }
370             }
371         }
372     }
373 
mult_matrices(GLdouble out[16],const GLdouble m1[16],const GLdouble m2[16])374     void mult_matrices(
375         GLdouble out[16], const GLdouble m1[16], const GLdouble m2[16]
376     ) {
377         Memory::clear(out, sizeof(GLdouble)*16);
378         for(index_t i=0; i<4; ++i) {
379             for(index_t j=0; j<4; ++j) {
380                 for(index_t k=0; k<4; ++k) {
381                     out[i*4+j] += m1[i*4+k]*m2[k*4+j];
382                 }
383             }
384         }
385     }
386 
mult_matrix_vector(GLfloat out[4],const GLfloat m[16],const GLfloat v[4])387     void mult_matrix_vector(
388         GLfloat out[4], const GLfloat m[16], const GLfloat v[4]
389     ) {
390         Memory::clear(out, sizeof(GLfloat)*4);
391         for(index_t i=0; i<4; ++i) {
392             for(index_t j=0; j<4; ++j) {
393                 out[i] += v[j] * m[4*i+j];
394             }
395         }
396     }
397 
mult_transpose_matrix_vector(GLfloat out[4],const GLfloat m[16],const GLfloat v[4])398     void mult_transpose_matrix_vector(
399         GLfloat out[4], const GLfloat m[16], const GLfloat v[4]
400     ) {
401         Memory::clear(out, sizeof(GLfloat)*4);
402         for(index_t i=0; i<4; ++i) {
403             for(index_t j=0; j<4; ++j) {
404                 out[i] += v[j] * m[4*j+i];
405             }
406         }
407     }
408 
mult_transpose_matrix_vector(GLdouble out[4],const GLdouble m[16],const GLdouble v[4])409     void mult_transpose_matrix_vector(
410         GLdouble out[4], const GLdouble m[16], const GLdouble v[4]
411     ) {
412         Memory::clear(out, sizeof(GLdouble)*4);
413         for(index_t i=0; i<4; ++i) {
414             for(index_t j=0; j<4; ++j) {
415                 out[i] += v[j] * m[4*j+i];
416             }
417         }
418     }
419 
mult_matrix_vector(GLdouble out[4],const GLdouble m[16],const GLdouble v[4])420     void mult_matrix_vector(
421         GLdouble out[4], const GLdouble m[16], const GLdouble v[4]
422     ) {
423         Memory::clear(out, sizeof(GLdouble)*4);
424         for(index_t i=0; i<4; ++i) {
425             for(index_t j=0; j<4; ++j) {
426                 out[i] += v[j] * m[4*i+j];
427             }
428         }
429     }
430 
transpose_matrix(GLUPfloat M[16])431     void transpose_matrix(GLUPfloat M[16]) {
432         for(int i=0; i<4; ++i) {
433             for(int j=0; j<4; ++j) {
434                 if(i < j) {
435                     GLUPfloat tmp = M[4*i+j];
436                     M[4*i+j] = M[4*j+i];
437                     M[4*j+i] = tmp;
438                 }
439             }
440         }
441     }
442 
transpose_matrix(GLUPdouble M[16])443     void transpose_matrix(GLUPdouble M[16]) {
444         for(int i=0; i<4; ++i) {
445             for(int j=0; j<4; ++j) {
446                 if(i < j) {
447                     GLUPdouble tmp = M[4*i+j];
448                     M[4*i+j] = M[4*j+i];
449                     M[4*j+i] = tmp;
450                 }
451             }
452         }
453     }
454 
load_identity_matrix(GLfloat out[16])455     void load_identity_matrix(GLfloat out[16]) {
456         for(index_t i=0; i<4; ++i) {
457             for(index_t j=0; j<4; ++j) {
458                 out[i*4+j] = (i == j) ? 1.0f : 0.0f;
459             }
460         }
461     }
462 
463     /***********************************************************/
464 
initialize(Context * context,const char * name)465     void StateVariableBase::initialize(
466         Context* context, const char* name
467     ) {
468         context_ = context;
469         name_ = name;
470         address_ = context_->get_state_variable_address(name);
471     }
472 
flag_uniform_buffer_as_dirty()473     void StateVariableBase::flag_uniform_buffer_as_dirty() {
474         context_->flag_uniform_buffer_as_dirty();
475     }
476 
477     /***********************************************************/
478 
uniform_state_declaration()479     const char* Context::uniform_state_declaration() {
480         return GLSL::get_GLSL_include_file("GLUPGLSL/state.h");
481     }
482 
483 
Context()484     Context::Context() :
485         marching_tet_(GLUP_TETRAHEDRA),
486         marching_hex_(GLUP_HEXAHEDRA),
487         marching_prism_(GLUP_PRISMS),
488         marching_pyramid_(GLUP_PYRAMIDS),
489         marching_connector_(GLUP_CONNECTORS) {
490 
491 	geo_cite("DBLP:conf/isvc/ToledoLP07");
492 
493         matrices_dirty_=true;
494         default_program_ = 0;
495         uniform_buffer_=0;
496         uniform_binding_point_=0;
497         uniform_buffer_size_=0;
498         uniform_buffer_data_=nullptr;
499         uniform_buffer_dirty_=true;
500 	lighting_dirty_=true;
501 
502         matrix_mode_ = GLUP_MODELVIEW_MATRIX;
503         matrices_dirty_ = true;
504 
505         precompile_shaders_ =
506             CmdLine::get_arg_bool("gfx:GLUP_precompile_shaders");
507 
508         use_core_profile_ =
509             (CmdLine::get_arg("gfx:GL_profile") != "compatibility");
510 
511         use_ES_profile_ =
512             (CmdLine::get_arg("gfx:GL_profile") == "ES");
513 
514         user_program_ = 0;
515         world_clip_plane_ = nullptr;
516         latest_program_ = 0;
517         toggles_config_ = 0;
518 
519         vertex_id_VBO_ = 0;
520 
521         toggles_source_state_ = 0;
522         toggles_source_undetermined_ = 0;
523 
524         initialize();
525     }
526 
~Context()527     Context::~Context() {
528         if(default_program_ != 0) {
529             glDeleteProgram(default_program_);
530         }
531         glDeleteBuffers(1, &uniform_buffer_);
532         delete[] uniform_buffer_data_;
533         if(vertex_id_VBO_ != 0) {
534             glDeleteBuffers(1, &vertex_id_VBO_);
535             vertex_id_VBO_ = 0;
536         }
537     }
538 
primitive_supports_array_mode(GLUPprimitive prim) const539     bool Context::primitive_supports_array_mode(GLUPprimitive prim) const {
540         return
541             primitive_info_[prim].implemented &&
542             primitive_info_[prim].VAO == 0;
543     }
544 
545 #ifdef GEO_GL_150
546     /**
547      * \brief Creates a GLSL vertex program that uses all the variables
548      *  of the uniform state.
549      * \details Some OpenGL drivers have a compiler that optimizes-out
550      *  variables that are not used in the shader. This function creates
551      *  a dummy shader that uses all the variables, so that their offsets
552      *  can be reliably queried using GLSL program introspection
553      *  with glGetUniformIndices().
554      */
create_vertex_program_that_uses_all_UBO_variables()555     static std::string create_vertex_program_that_uses_all_UBO_variables() {
556         std::ostringstream output;
557 
558         output << "in vec3 position;\n";
559         output << "void main() {\n";
560         output << "   mat4 M = GLUP.modelviewprojection_matrix;\n";
561 
562         // Parse uniform state declaration in order to use all variables.
563 
564         std::istringstream input(Context::uniform_state_declaration());
565         std::string line;
566         while(std::getline(input,line)) {
567             std::vector<std::string> words;
568             GEO::String::split_string(line, ' ', words);
569             if(
570                 (words.size() == 2 && words[1][words[1].length()-1] == ';') ||
571                 (words.size() == 3 && words[2] == ";")
572             ) {
573                 std::string vartype = words[0];
574                 std::string varname = words[1];
575                 if(varname[varname.length()-1] == ';') {
576                     varname = varname.substr(0, varname.length()-1);
577                 }
578                 if(vartype == "bool") {
579                     output << "   M[0].x += float(GLUP." << varname << ");\n";
580                 } else if(vartype == "int") {
581                     output << "   M[0].x += float(GLUP." << varname << ");\n";
582                 } else if(vartype == "float") {
583                     output << "   M[0].x += GLUP." << varname << ";\n";
584                 } else if(vartype == "vec3") {
585                     output << "   M[0].xyz += GLUP." << varname << ";\n";
586                 } else if(vartype == "vec4") {
587                     output << "   M[0] += GLUP." << varname << ";\n";
588                 } else if(vartype == "mat3") {
589                     output << "   M[0].xyz += GLUP." << varname << "[0];\n";
590                 } else if(vartype == "mat4") {
591                     output << "   M += GLUP." << varname << ";\n";
592                 }
593             }
594         }
595 
596         output << "   gl_Position = M*vec4(position,1.0);\n";
597         output << "}\n";
598 
599         return output.str();
600     }
601 #endif
602 
setup()603     void Context::setup() {
604 
605         uniform_buffer_dirty_=true;
606         matrices_dirty_=true;
607         uniform_binding_point_=1;
608 
609 #ifdef GEO_GL_150
610 
611         // A minimalistic GLSL program that uses the GLUP context.
612         // It is there just to use GLSL introspection API to lookup
613         // the offsets of GLUP context state variables.
614         // Note: it needs to use all the variables of the uniform state,
615         // else, depending on the OpenGL driver / library,
616         // some variables may be optimized-out and glGetUniformIndices()
617         // returns GL_INVALID_INDEX (stupid !), this is why there is
618         // this (weird) function
619         //  create_vertex_program_that_uses_all_UBO_variables()
620 
621         static const char* shader_source_header_ =
622 #ifdef GEO_OS_ANDROID
623             "#version 300 es\n"
624 	    "precision highp float;\n"
625             "precision lowp sampler3D;\n" ;
626 #else
627             "#version 150 core\n" ;
628 #endif
629 
630         static const char* fragment_shader_source_ =
631             "out vec4 colorOut;                      \n"
632             "void main() {                           \n"
633             "   colorOut = vec4(1.0, 1.0, 1.0, 1.0); \n"
634             "}                                       \n";
635 
636         GLuint GLUP_vertex_shader = GLSL::compile_shader(
637             GL_VERTEX_SHADER,
638             shader_source_header_,
639             Context::uniform_state_declaration(),
640             create_vertex_program_that_uses_all_UBO_variables().c_str(),
641             nullptr
642         );
643 
644         GLuint GLUP_fragment_shader = GLSL::compile_shader(
645             GL_FRAGMENT_SHADER,
646             shader_source_header_,
647             fragment_shader_source_,
648             nullptr
649         );
650 
651         default_program_ = GLSL::create_program_from_shaders(
652             GLUP_vertex_shader,
653             GLUP_fragment_shader,
654             nullptr
655         );
656 
657         // Get UBO size
658 
659         GLuint UBO_index =
660             glGetUniformBlockIndex(default_program_, "GLUPStateBlock");
661 
662         glUniformBlockBinding(
663             default_program_, UBO_index, uniform_binding_point_
664         );
665 
666         glGetActiveUniformBlockiv(
667             default_program_, UBO_index,
668             GL_UNIFORM_BLOCK_DATA_SIZE,
669             &uniform_buffer_size_
670         );
671 
672         // Create UBO
673 
674         uniform_buffer_data_ = new Memory::byte[uniform_buffer_size_];
675         Memory::clear(uniform_buffer_data_, size_t(uniform_buffer_size_));
676         glGenBuffers(1, &uniform_buffer_);
677         glBindBuffer(GL_UNIFORM_BUFFER, uniform_buffer_);
678         glBufferData(
679             GL_UNIFORM_BUFFER,
680             uniform_buffer_size_,
681             uniform_buffer_data_,
682             GL_DYNAMIC_DRAW
683         );
684 
685         glBindBufferBase(
686             GL_UNIFORM_BUFFER,
687             uniform_binding_point_,
688             uniform_buffer_
689         );
690         glBindBuffer(GL_UNIFORM_BUFFER, 0);
691 
692 #endif
693 
694         setup_state_variables();
695         setup_immediate_buffers();
696 
697         //  Indicate that all toggle states should be
698         // read from the state (default mode, superseded later).
699         setup_shaders_source_for_toggles(0,~0);
700         setup_primitives();
701     }
702 
setup_state_variables()703     void Context::setup_state_variables() {
704         uniform_state_.toggle.push_back(
705             StateVariable<GLboolean>(this,"lighting_enabled",GL_TRUE)
706         );
707         uniform_state_.toggle.push_back(
708             StateVariable<GLboolean>(this,"vertex_colors_enabled",GL_FALSE)
709         );
710         uniform_state_.toggle.push_back(
711             StateVariable<GLboolean>(this,"texturing_enabled",GL_FALSE)
712         );
713         uniform_state_.toggle.push_back(
714             StateVariable<GLboolean>(this,"draw_mesh_enabled",GL_FALSE)
715         );
716         uniform_state_.toggle.push_back(
717             StateVariable<GLboolean>(this,"clipping_enabled",GL_FALSE)
718         );
719         uniform_state_.toggle.push_back(
720             StateVariable<GLboolean>(this,"indirect_texturing_enabled",GL_FALSE)
721         );
722         uniform_state_.toggle.push_back(
723             StateVariable<GLboolean>(this,"vertex_normals_enabled",GL_FALSE)
724         );
725         uniform_state_.toggle.push_back(
726             StateVariable<GLboolean>(this,"picking_enabled",GL_FALSE)
727         );
728         uniform_state_.toggle.push_back(
729             StateVariable<GLboolean>(this,"alpha_discard_enabled",GL_FALSE)
730         );
731         uniform_state_.toggle.push_back(
732             StateVariable<GLboolean>(this,"normal_mapping_enabled",GL_FALSE)
733         );
734 
735         uniform_state_.color.push_back(
736             VectorStateVariable(this, "front_color", 4)
737         );
738         uniform_state_.color.push_back(
739             VectorStateVariable(this, "back_color", 4)
740         );
741         uniform_state_.color.push_back(
742             VectorStateVariable(this, "mesh_color", 4)
743         );
744 
745         uniform_state_.light_vector.initialize(this, "light_vector", 3);
746         uniform_state_.light_half_vector.initialize(
747             this, "light_half_vector", 3
748         );
749 
750         uniform_state_.mesh_width.initialize(this, "mesh_width", 1.0f);
751         uniform_state_.cells_shrink.initialize(this, "cells_shrink", 0.0f);
752 
753         uniform_state_.picking_mode.initialize(
754             this, "picking_mode", GLUP_PICK_PRIMITIVE
755         );
756         uniform_state_.picking_id.initialize(this, "picking_id", 0);
757         uniform_state_.base_picking_id.initialize(this, "base_picking_id", 0);
758 
759         uniform_state_.clipping_mode.initialize(
760             this, "clipping_mode", GLUP_CLIP_WHOLE_CELLS
761         );
762         uniform_state_.clip_plane.initialize(this, "clip_plane", 4);
763         uniform_state_.world_clip_plane.initialize(
764             this, "world_clip_plane", 4
765         );
766         uniform_state_.clip_clip_plane.initialize(
767             this, "clip_clip_plane", 4
768         );
769 
770         uniform_state_.texture_mode.initialize(
771             this, "texture_mode", GLUP_TEXTURE_MODULATE
772         );
773 
774         uniform_state_.texture_type.initialize(
775             this, "texture_type", GLUP_TEXTURE_2D
776         );
777 
778 	uniform_state_.alpha_threshold.initialize(
779 	    this, "alpha_threshold", 0.5f
780 	);
781 
782 	uniform_state_.specular.initialize(
783 	    this, "specular", 1.0f
784 	);
785 
786         uniform_state_.modelview_matrix.initialize(this, "modelview_matrix");
787         uniform_state_.modelviewprojection_matrix.initialize(
788             this, "modelviewprojection_matrix"
789         );
790         uniform_state_.projection_matrix.initialize(this, "projection_matrix");
791         uniform_state_.normal_matrix.initialize(this, "normal_matrix");
792         uniform_state_.texture_matrix.initialize(this, "texture_matrix");
793 
794         uniform_state_.inverse_modelviewprojection_matrix.initialize(
795 	    this, "inverse_modelviewprojection_matrix"
796 	);
797         uniform_state_.inverse_modelview_matrix.initialize(
798 	    this, "inverse_modelview_matrix"
799 	);
800         uniform_state_.inverse_projection_matrix.initialize(
801 	    this, "inverse_projection_matrix"
802 	);
803 	uniform_state_.viewport.initialize(this, "viewport", 4);
804 
805         uniform_state_.point_size.initialize(this, "point_size", 1.0f);
806 
807         matrix_mode_ = GLUP_MODELVIEW_MATRIX;
808         update_matrices();
809     }
810 
setup_immediate_buffers()811     void Context::setup_immediate_buffers() {
812 
813         glupGenVertexArrays(1,&immediate_state_.VAO());
814         glupBindVertexArray(immediate_state_.VAO());
815 
816         for(index_t i=0; i<ImmediateState::NB_IMMEDIATE_BUFFERS; ++i) {
817             update_buffer_object(
818                 immediate_state_.buffer[i].VBO(),
819                 GL_ARRAY_BUFFER,
820                 immediate_state_.buffer[i].size_in_bytes(),
821                 nullptr // no need to copy the buffer, it will be overwritten after.
822             );
823         }
824 
825         bind_immediate_state_buffers_to_VAO();
826         glupBindVertexArray(0);
827     }
828 
stream_immediate_buffers()829     void Context::stream_immediate_buffers() {
830 	if(immediate_state_.nb_vertices() == IMMEDIATE_BUFFER_SIZE) {
831 	    for(index_t i=0; i<ImmediateState::NB_IMMEDIATE_BUFFERS; ++i) {
832 		if(
833 		    immediate_state_.buffer[i].is_enabled() &&
834 		    immediate_state_.buffer[i].VBO() != 0
835 		) {
836 		    stream_buffer_object(
837 			immediate_state_.buffer[i].VBO(),
838 			GL_ARRAY_BUFFER,
839 			immediate_state_.buffer[i].size_in_bytes(),
840 			immediate_state_.buffer[i].data()
841 		    );
842 		}
843 	    }
844 	} else {
845 	    for(index_t i=0; i<ImmediateState::NB_IMMEDIATE_BUFFERS; ++i) {
846 		if(
847 		    immediate_state_.buffer[i].is_enabled() &&
848 		    immediate_state_.buffer[i].VBO() != 0
849 		) {
850 		    size_t bytes =
851 			immediate_state_.nb_vertices() *
852 			immediate_state_.buffer[i].dimension() *
853 			sizeof(GLfloat);
854 		    glBindBuffer(
855 			GL_ARRAY_BUFFER, immediate_state_.buffer[i].VBO()
856 		    );
857 		    glBufferSubData(
858 			GL_ARRAY_BUFFER,
859 			0,
860 			GLsizeiptr(bytes),
861 			immediate_state_.buffer[i].data()
862 		    );
863 		}
864 	    }
865 	}
866         glBindBuffer(GL_ARRAY_BUFFER,0);
867     }
868 
869 
get_state_variable_address(const char * name_in)870     Memory::pointer Context::get_state_variable_address(const char* name_in) {
871         std::string name = std::string("GLUPStateBlock.") + name_in;
872         GLint offset = GLSL::get_uniform_variable_offset(
873             default_program_, name.c_str()
874         );
875         return uniform_buffer_data_ + offset;
876     }
877 
bind_uniform_state(GLuint program)878     void Context::bind_uniform_state(GLuint program) {
879 #ifndef GEO_GL_150
880         geo_argused(program);
881 #else
882         GLuint UBO_index = glGetUniformBlockIndex(
883             program, "GLUPStateBlock"
884         );
885         if(UBO_index != GL_INVALID_INDEX) {
886             glUniformBlockBinding(
887                 program, UBO_index, uniform_binding_point_
888             );
889         }
890 #endif
891     }
892 
begin(GLUPprimitive primitive)893     void Context::begin(GLUPprimitive primitive) {
894         update_toggles_config();
895         create_program_if_needed(primitive);
896         if(!primitive_info_[primitive].implemented) {
897             Logger::warn("GLUP")
898                 << "glupBegin(): "
899                 << primitive_name[primitive]
900                 << " not implemented in this profile" << std::endl;
901         }
902 
903         GEO_CHECK_GL();
904         update_uniform_buffer();
905         GEO_CHECK_GL();
906 
907         //   If the primitive has a special VAO to be used for immediate
908         // mode, then bind it.
909         if(primitive_info_[primitive].VAO != 0) {
910             GEO_CHECK_GL();
911             glupBindVertexArray(
912                 primitive_info_[primitive].VAO
913             );
914         } else {
915             GEO_CHECK_GL();
916             // Else use the regular VAO used by all immediate-mode primitives
917             // (if there is one).
918             if(immediate_state_.VAO() != 0) {
919                 glupBindVertexArray(immediate_state_.VAO());
920             }
921         }
922 
923         GEO_CHECK_GL();
924 
925         if(uniform_state_.toggle[GLUP_VERTEX_COLORS].get()) {
926             immediate_state_.buffer[GLUP_COLOR_ATTRIBUTE].enable();
927         } else {
928             immediate_state_.buffer[GLUP_COLOR_ATTRIBUTE].disable();
929         }
930 
931         GEO_CHECK_GL();
932 
933         if(uniform_state_.toggle[GLUP_TEXTURING].get()) {
934             immediate_state_.buffer[GLUP_TEX_COORD_ATTRIBUTE].enable();
935         } else {
936             immediate_state_.buffer[GLUP_TEX_COORD_ATTRIBUTE].disable();
937         }
938 
939         GEO_CHECK_GL();
940 
941         if(
942 	    uniform_state_.toggle[GLUP_LIGHTING].get() &&
943 	    uniform_state_.toggle[GLUP_VERTEX_NORMALS].get()
944 	) {
945             immediate_state_.buffer[GLUP_NORMAL_ATTRIBUTE].enable();
946         } else {
947             immediate_state_.buffer[GLUP_NORMAL_ATTRIBUTE].disable();
948         }
949 
950         GEO_CHECK_GL();
951 
952         immediate_state_.begin(primitive);
953 
954         GEO_CHECK_GL();
955 
956         if(primitive_info_[primitive].vertex_gather_mode) {
957             index_t n = nb_vertices_per_primitive[primitive];
958             GLenum GL_primitive = primitive_info_[primitive].GL_primitive;
959             n /= nb_vertices_per_GL_primitive(GL_primitive);
960 
961             for(index_t i=0; i<ImmediateState::NB_IMMEDIATE_BUFFERS; ++i) {
962                 if(immediate_state_.buffer[i].is_enabled()) {
963                     for(index_t j=0; j<n; ++j) {
964                         glEnableVertexAttribArray(i*n+j);
965                     }
966                 }
967             }
968         } else {
969             for(index_t i=0; i<ImmediateState::NB_IMMEDIATE_BUFFERS; ++i) {
970                 if(immediate_state_.buffer[i].is_enabled()) {
971                     glEnableVertexAttribArray(i);
972 
973                     // If not using VBO, specify vertex attrib pointer
974                     // using old style API.
975 
976                     if(immediate_state_.buffer[i].VBO() == 0) {
977                         glVertexAttribPointer(
978                             i,
979                             GLint(immediate_state_.buffer[i].dimension()),
980                             GL_FLOAT, GL_FALSE, 0,
981                             immediate_state_.buffer[i].data()
982                         );
983                     }
984                 }
985             }
986         }
987 
988         GEO_CHECK_GL();
989 
990         prepare_to_draw(primitive);
991 
992         GEO_CHECK_GL();
993 
994         if(user_program_ != 0) {
995             use_program(user_program_);
996         } else {
997             use_program(primitive_info_[primitive].program(toggles_config_));
998         }
999 
1000         GEO_CHECK_GL();
1001     }
1002 
end()1003     void Context::end() {
1004         GEO_CHECK_GL();
1005         flush_immediate_buffers();
1006         GEO_CHECK_GL();
1007         use_program(0);
1008         GEO_CHECK_GL();
1009 
1010         if(primitive_info_[immediate_state_.primitive()].vertex_gather_mode) {
1011             index_t n = nb_vertices_per_primitive[immediate_state_.primitive()];
1012             GLenum GL_primitive =
1013                 primitive_info_[immediate_state_.primitive()].GL_primitive;
1014             n /= nb_vertices_per_GL_primitive(GL_primitive);
1015             for(index_t i=0; i<ImmediateState::NB_IMMEDIATE_BUFFERS; ++i) {
1016                 if(immediate_state_.buffer[i].is_enabled()) {
1017 		    for(index_t j=0; j<n; ++j) {
1018 			GEO_CHECK_GL();
1019 			glDisableVertexAttribArray(i*n+j);
1020 			GEO_CHECK_GL();
1021 		    }
1022 		}
1023             }
1024         } else {
1025             for(index_t i=0; i<ImmediateState::NB_IMMEDIATE_BUFFERS; ++i) {
1026                 if(immediate_state_.buffer[i].is_enabled()) {
1027 		    GEO_CHECK_GL();
1028 		    glDisableVertexAttribArray(i);
1029 		    GEO_CHECK_GL();
1030 		}
1031             }
1032         }
1033 
1034         if(
1035             uniform_state_.toggle[GLUP_PICKING].get() &&
1036             uniform_state_.picking_mode.get() == GLUP_PICK_PRIMITIVE
1037         ) {
1038             GEO_CHECK_GL();
1039             update_base_picking_id(0);
1040             GEO_CHECK_GL();
1041         }
1042 
1043         if(
1044             primitive_info_[immediate_state_.primitive()].VAO != 0 ||
1045             immediate_state_.VAO() != 0
1046         ) {
1047             GEO_CHECK_GL();
1048             glupBindVertexArray(0);
1049             GEO_CHECK_GL();
1050         }
1051         GEO_CHECK_GL();
1052         done_draw(immediate_state_.primitive());
1053         GEO_CHECK_GL();
1054     }
1055 
draw_arrays(GLUPprimitive primitive,GLUPint first,GLUPsizei count)1056     void Context::draw_arrays(
1057         GLUPprimitive primitive, GLUPint first, GLUPsizei count
1058     ) {
1059         update_toggles_config();
1060         create_program_if_needed(primitive);
1061         if(!primitive_supports_array_mode(primitive)) {
1062             Logger::warn("GLUP")
1063                 << profile_name()
1064                 << "::glupDrawArrays(): "
1065                 << primitive_name[primitive]
1066                 << " does not support array mode." << std::endl;
1067             return;
1068         }
1069         prepare_to_draw(primitive);
1070         update_uniform_buffer();
1071         if(user_program_ != 0) {
1072             use_program(user_program_);
1073         } else {
1074             use_program(primitive_info_[primitive].program(toggles_config_));
1075         }
1076         glDrawArrays(primitive_info_[primitive].GL_primitive, first, count);
1077         GEO_CHECK_GL();
1078         use_program(0);
1079         GEO_CHECK_GL();
1080         done_draw(primitive);
1081         GEO_CHECK_GL();
1082     }
1083 
draw_elements(GLUPprimitive primitive,GLUPsizei count,GLUPenum type,const GLUPvoid * indices)1084     void Context::draw_elements(
1085         GLUPprimitive primitive, GLUPsizei count,
1086         GLUPenum type, const GLUPvoid* indices
1087     ) {
1088         GEO_CHECK_GL();
1089         update_toggles_config();
1090         GEO_CHECK_GL();
1091         create_program_if_needed(primitive);
1092         GEO_CHECK_GL();
1093         if(!primitive_supports_array_mode(primitive)) {
1094             Logger::warn("GLUP")
1095                 << profile_name()
1096                 << "::glupDrawElements(): "
1097                 << primitive_name[primitive]
1098                 << " does not support array mode." << std::endl;
1099             return;
1100         }
1101         GEO_CHECK_GL();
1102         prepare_to_draw(primitive);
1103         GEO_CHECK_GL();
1104         update_uniform_buffer();
1105         GEO_CHECK_GL();
1106         if(user_program_ != 0) {
1107             use_program(user_program_);
1108         } else {
1109             use_program(primitive_info_[primitive].program(toggles_config_));
1110         }
1111         GEO_CHECK_GL();
1112         glDrawElements(
1113             primitive_info_[primitive].GL_primitive, count, type, indices
1114         );
1115         GEO_CHECK_GL();
1116         use_program(0);
1117         GEO_CHECK_GL();
1118         done_draw(primitive);
1119         GEO_CHECK_GL();
1120     }
1121 
prepare_to_draw(GLUPprimitive primitive)1122     void Context::prepare_to_draw(GLUPprimitive primitive) {
1123 #ifndef GEO_GL_440
1124         geo_argused(primitive);
1125 #else
1126 
1127         if(primitive == GLUP_POINTS || primitive == GLUP_SPHERES) {
1128             glEnable(GL_PROGRAM_POINT_SIZE);
1129         } else if(primitive == GLUP_LINES && !use_core_profile_) {
1130             // Note: glLineWidth is deprecated in OpenGL core profile,
1131             // for now we still use it if we got a compatibility profile,
1132             // but for core profile, we are for now unable to display
1133             // thick lines (TODO: develop a shader for that, painful...)
1134             glLineWidth(uniform_state_.mesh_width.get());
1135         }
1136 
1137         if(primitive_info_[primitive].GL_primitive == GL_PATCHES) {
1138             // We generate an isoline for each patch, with the
1139             // minimum tesselation level. This generates two
1140             // vertices (we discard one of them in the geometry
1141             // shader).
1142             static float levels[4] = {1.0, 1.0, 0.0, 0.0};
1143             glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, levels);
1144 
1145             // Specify number of vertices for GL_PATCH.
1146             glPatchParameteri(
1147                 GL_PATCH_VERTICES, GLint(nb_vertices_per_primitive[primitive])
1148             );
1149         }
1150 #endif
1151     }
1152 
done_draw(GLUPprimitive primitive)1153     void Context::done_draw(GLUPprimitive primitive) {
1154         geo_argused(primitive);
1155     }
1156 
update_matrices()1157     void Context::update_matrices() {
1158 
1159         if(!matrices_dirty_) {
1160             return;
1161         }
1162 
1163         GLfloat* modelview = matrix_stack_[GLUP_MODELVIEW_MATRIX].top();
1164         GLfloat* projection = matrix_stack_[GLUP_PROJECTION_MATRIX].top();
1165 	GLfloat* modelviewproject =
1166 	    uniform_state_.modelviewprojection_matrix.get_pointer();
1167 	GLfloat* modelviewproject_invert =
1168 	    uniform_state_.inverse_modelviewprojection_matrix.get_pointer();
1169 	GLfloat* modelview_invert =
1170 	    uniform_state_.inverse_modelview_matrix.get_pointer();
1171 	GLfloat* projection_invert =
1172 	    uniform_state_.inverse_projection_matrix.get_pointer();
1173 
1174         copy_vector(
1175             uniform_state_.modelview_matrix.get_pointer(), modelview, 16
1176         );
1177         mult_matrices(modelviewproject, modelview, projection);
1178 
1179         GLboolean OK = invert_matrix(projection_invert, projection);
1180         if(!OK) {
1181             Logger::warn("GLUP") << "Singular Projection matrix"
1182                                  << std::endl;
1183             show_matrix(projection);
1184         }
1185 
1186         OK = invert_matrix(modelview_invert, modelview);
1187         if(!OK) {
1188             Logger::warn("GLUP") << "Singular ModelView matrix"
1189                                  << std::endl;
1190             show_matrix(modelview);
1191         }
1192 
1193 	OK = invert_matrix(modelviewproject_invert, modelviewproject);
1194         if(!OK) {
1195             Logger::warn("GLUP") << "Singular ModelViewProjection matrix"
1196                                  << std::endl;
1197             show_matrix(modelviewproject);
1198         }
1199 
1200         GLfloat* normal_matrix = uniform_state_.normal_matrix.get_pointer();
1201         //   Copy the upper leftmost 3x3 part of the transpose of
1202         // modelview_invert_matrix to normal_matrix
1203         for(index_t i=0; i<3; ++i) {
1204             for(index_t j=0; j<3; ++j) {
1205                 // Yes, it is i*4
1206                 //   (with a '4' though it is a mat3 with a '3'),
1207                 // mat3 rows are padded-aligned in UBOs !
1208                 // TODO: query padding in UBO using introspection
1209                 // (is it possible ? does not seem to work, so
1210                 //  is padding with 4 universal ??)
1211                 normal_matrix[i*4+j] = modelview_invert[j*4+i];
1212             }
1213         }
1214 
1215         copy_vector(
1216             uniform_state_.texture_matrix.get_pointer(),
1217             matrix_stack_[GLUP_TEXTURE_MATRIX].top(),
1218             16
1219         );
1220 
1221         copy_vector(
1222             uniform_state_.projection_matrix.get_pointer(),
1223             matrix_stack_[GLUP_PROJECTION_MATRIX].top(),
1224             16
1225         );
1226 
1227         mult_matrix_vector(
1228             uniform_state_.world_clip_plane.get_pointer(),
1229             uniform_state_.modelview_matrix.get_pointer(),
1230             uniform_state_.clip_plane.get_pointer()
1231         );
1232 
1233 	OK = invert_matrix(
1234 	    projection_invert,
1235 	    uniform_state_.projection_matrix.get_pointer()
1236 	);
1237 	if(!OK) {
1238 	    Logger::warn("GLUP") << "Singular projection matrix"
1239 				 << std::endl;
1240 	    show_matrix(uniform_state_.projection_matrix.get_pointer());
1241 	}
1242 	mult_matrix_vector(
1243 	    uniform_state_.clip_clip_plane.get_pointer(),
1244 	    projection_invert,
1245 	    uniform_state_.clip_plane.get_pointer()
1246 	);
1247 
1248 	GLint viewport[4];
1249 	glGetIntegerv(GL_VIEWPORT, viewport);
1250 	for(index_t i=0; i<4; ++i) {
1251 	    uniform_state_.viewport.get_pointer()[i] = GLfloat(viewport[i]);
1252 	}
1253 
1254         matrices_dirty_ = false;
1255     }
1256 
update_lighting()1257     void Context::update_lighting() {
1258         if(!lighting_dirty_) {
1259             return;
1260         }
1261 
1262         GLfloat* light_vector =
1263             uniform_state_.light_vector.get_pointer();
1264 
1265         GLfloat* light_half_vector =
1266             uniform_state_.light_half_vector.get_pointer();
1267 
1268         // Normalize light vector
1269 
1270         normalize_vector(light_vector);
1271 
1272         // Compute half vector
1273 
1274         copy_vector(light_half_vector, light_vector, 3);
1275         light_half_vector[2] += 1.0f;
1276         normalize_vector(light_half_vector);
1277 
1278         lighting_dirty_ = false;
1279     }
1280 
update_base_picking_id(GLint new_value)1281     void Context::update_base_picking_id(GLint new_value) {
1282 #ifndef GEO_GL_150
1283         geo_argused(new_value);
1284 #else
1285         Memory::pointer address = uniform_state_.base_picking_id.address();
1286         index_t offset = index_t(address - uniform_buffer_data_);
1287         uniform_state_.base_picking_id.set(new_value);
1288         glBindBuffer(GL_UNIFORM_BUFFER, uniform_buffer_);
1289         glBufferSubData(
1290             GL_UNIFORM_BUFFER,
1291             offset,
1292             sizeof(int),
1293             address
1294         );
1295         glBindBuffer(GL_UNIFORM_BUFFER, 0);
1296 #endif
1297     }
1298 
do_update_uniform_buffer()1299     void Context::do_update_uniform_buffer() {
1300         if(!uniform_buffer_dirty_) {
1301             return;
1302         }
1303         if(matrices_dirty_) {
1304             update_matrices();
1305         }
1306         if(lighting_dirty_) {
1307             update_lighting();
1308         }
1309 #ifdef GEO_GL_150
1310 	#ifdef GL_CLIP_DISTANCE0
1311         if(!use_ES_profile_) {
1312             if(uniform_state_.toggle[GLUP_CLIPPING].get()) {
1313                 glEnable(GL_CLIP_DISTANCE0);
1314             } else {
1315                 glDisable(GL_CLIP_DISTANCE0);
1316             }
1317         }
1318 	#endif
1319         if(uniform_buffer_ != 0) {
1320             glBindBuffer(GL_UNIFORM_BUFFER, uniform_buffer_);
1321             glBufferSubData(
1322                 GL_UNIFORM_BUFFER,
1323                 0,
1324                 uniform_buffer_size_,
1325                 uniform_buffer_data_
1326             );
1327             glBindBuffer(GL_UNIFORM_BUFFER, 0);
1328         }
1329 #endif
1330         uniform_buffer_dirty_ = false;
1331     }
1332 
flush_immediate_buffers()1333     void Context::flush_immediate_buffers() {
1334 
1335 
1336         if(immediate_state_.nb_vertices() == 0) {
1337             return;
1338         }
1339 
1340         // Sends the data from the buffers to OpenGL if VBO are used.
1341         stream_immediate_buffers();
1342 
1343         bool vertex_id_attrib_enabled = false;
1344 
1345         if(vertex_id_VBO_ != 0) {
1346             if(
1347                 uniform_state_.toggle[GLUP_PICKING].get() || (
1348                     primitive_dimension[immediate_state_.primitive()] >= 2 &&
1349                     uniform_state_.toggle[GLUP_DRAW_MESH].get()
1350                 )
1351             ) {
1352                 glEnableVertexAttribArray(GLUP_VERTEX_ID_ATTRIBUTE);
1353                 vertex_id_attrib_enabled = true;
1354             }
1355         }
1356 
1357         GLsizei nb_vertices = GLsizei(immediate_state_.nb_vertices());
1358 
1359         if(primitive_info_[immediate_state_.primitive()].vertex_gather_mode) {
1360             nb_vertices /= GLsizei(
1361                 nb_vertices_per_primitive[immediate_state_.primitive()]
1362             );
1363             nb_vertices *= GLsizei(
1364                 nb_vertices_per_GL_primitive(
1365                     primitive_info_[immediate_state_.primitive()].GL_primitive
1366                 )
1367             );
1368         }
1369 
1370         GEO_CHECK_GL();
1371         if(primitive_info_[immediate_state_.primitive()].elements_VBO != 0) {
1372             index_t nb_primitives = index_t(nb_vertices) /
1373                 nb_vertices_per_primitive[immediate_state_.primitive()];
1374             index_t nb_elements = nb_primitives *
1375                 primitive_info_[immediate_state_.primitive()].
1376                 nb_elements_per_primitive ;
1377 
1378             glDrawElements(
1379                 primitive_info_[immediate_state_.primitive()].GL_primitive,
1380                 GLsizei(nb_elements),
1381                 GL_UNSIGNED_SHORT,
1382                 nullptr
1383             );
1384         } else {
1385             glDrawArrays(
1386                 primitive_info_[immediate_state_.primitive()].GL_primitive,
1387                 0,
1388                 nb_vertices
1389             );
1390         }
1391         GEO_CHECK_GL();
1392 
1393         // Picking mode uses GLSL primitive_id variable, and add
1394         // GLUP state base_picking_id to it. This code updates
1395         // GLUP state base_picking_id and adds the number of drawn
1396         // primitives to it, so that the next batch will start with
1397         // the correct base_picking_id
1398         if(
1399             uniform_state_.toggle[GLUP_PICKING].get() &&
1400             uniform_state_.picking_mode.get() == GLUP_PICK_PRIMITIVE
1401         ) {
1402             update_base_picking_id(
1403                 uniform_state_.base_picking_id.get() +
1404                 GLint(immediate_state_.nb_primitives())
1405             );
1406         }
1407         immediate_state_.reset();
1408 
1409         if(vertex_id_attrib_enabled) {
1410             glDisableVertexAttribArray(GLUP_VERTEX_ID_ATTRIBUTE);
1411         }
1412     }
1413 
1414     /***********************************************************************/
1415 
set_primitive_info(GLUPprimitive glup_primitive,GLenum gl_primitive,GLuint program,bool bind_attrib_loc)1416     void Context::set_primitive_info(
1417         GLUPprimitive glup_primitive, GLenum gl_primitive, GLuint program,
1418         bool bind_attrib_loc
1419     ) {
1420         primitive_info_[glup_primitive].implemented = true;
1421         primitive_info_[glup_primitive].GL_primitive = gl_primitive;
1422         primitive_info_[glup_primitive].shader_map[toggles_config_] = program;
1423 
1424         if(!bind_attrib_loc) {
1425             return;
1426         }
1427 
1428         GEO_CHECK_GL();
1429         glBindAttribLocation(program, GLUP_VERTEX_ATTRIBUTE, "vertex_in");
1430         glBindAttribLocation(program, GLUP_COLOR_ATTRIBUTE, "color_in");
1431         glBindAttribLocation(program, GLUP_TEX_COORD_ATTRIBUTE, "tex_coord_in");
1432         glBindAttribLocation(program, GLUP_NORMAL_ATTRIBUTE, "normal_in");
1433         if(vertex_id_VBO_ != 0) {
1434             glBindAttribLocation(
1435 		program, GLUP_VERTEX_ID_ATTRIBUTE, "vertex_id_in"
1436 	    );
1437         }
1438         GEO_CHECK_GL();
1439         GLSL::link_program(program);
1440         GEO_CHECK_GL();
1441         bind_uniform_state(program);
1442         GEO_CHECK_GL();
1443 
1444         //  Bind default texture units. We use different texture
1445         // units because there is a mode where both a 1D and another
1446         // texture is bound ("indirect texturing").
1447 
1448         GLSL::set_program_uniform_by_name(
1449             program, "texture2Dsampler", GLint(GLUP_TEXTURE_2D_UNIT)
1450         );
1451         GLSL::set_program_uniform_by_name(
1452             program, "texture1Dsampler", GLint(GLUP_TEXTURE_1D_UNIT)
1453         );
1454         GLSL::set_program_uniform_by_name(
1455             program, "texture3Dsampler", GLint(GLUP_TEXTURE_3D_UNIT)
1456         );
1457 
1458         GEO_CHECK_GL();
1459     }
1460 
set_primitive_info_vertex_gather_mode(GLUPprimitive glup_primitive,GLenum GL_primitive,GLuint program)1461     void Context::set_primitive_info_vertex_gather_mode(
1462         GLUPprimitive glup_primitive, GLenum GL_primitive, GLuint program
1463     ) {
1464         set_primitive_info(glup_primitive, GL_primitive, program, false);
1465         index_t n = nb_vertices_per_primitive[glup_primitive];
1466         n /= nb_vertices_per_GL_primitive(GL_primitive);
1467 
1468         // Attribute location are bound here, programmatically,
1469         // since their index depends on the number of vertices,
1470         // and GLSL does not like to have that in the declaration
1471         // (when saying layout(binding = nb_vertices), the GLSL
1472         // compiler does not "see" that nb_vertices is a constant).
1473 
1474         GEO_CHECK_GL();
1475         glBindAttribLocation(program, 0, "vertex_in");
1476         glBindAttribLocation(program, n, "color_in");
1477         glBindAttribLocation(program, 2*n, "tex_coord_in");
1478         glBindAttribLocation(program, 3*n, "normal_in");
1479 
1480         GEO_CHECK_GL();
1481         GLSL::link_program(program);
1482 
1483         GEO_CHECK_GL();
1484         bind_uniform_state(program);
1485 
1486         //  Bind default texture units. We use different texture
1487         // units because there is a mode where both a 1D and another
1488         // texture is bound ("indirect texturing").
1489 
1490         GEO_CHECK_GL();
1491         GLSL::set_program_uniform_by_name(
1492             program, "texture2Dsampler", GLint(GLUP_TEXTURE_2D_UNIT)
1493         );
1494         GLSL::set_program_uniform_by_name(
1495             program, "texture1Dsampler", GLint(GLUP_TEXTURE_1D_UNIT)
1496         );
1497         GLSL::set_program_uniform_by_name(
1498             program, "texture3Dsampler", GLint(GLUP_TEXTURE_3D_UNIT)
1499         );
1500 
1501         primitive_info_[glup_primitive].vertex_gather_mode = true;
1502 
1503         //   We need a special VAO: memory layout is different since
1504         // we use a single vertex with an array of n attributes...
1505         //   Note: since the function can be called several times (one
1506         // per toggles configuration), make sure the VAO does not already
1507         // exists.
1508         GEO_CHECK_GL();
1509         if(primitive_info_[glup_primitive].VAO == 0) {
1510 	    GEO_CHECK_GL();
1511             glupGenVertexArrays(
1512                 1, &(primitive_info_[glup_primitive].VAO)
1513             );
1514 	    GEO_CHECK_GL();
1515             glupBindVertexArray(
1516                 primitive_info_[glup_primitive].VAO
1517             );
1518 	    GEO_CHECK_GL();
1519             for(index_t i=0; i<ImmediateState::NB_IMMEDIATE_BUFFERS; ++i) {
1520                 glBindBuffer(GL_ARRAY_BUFFER,immediate_state_.buffer[i].VBO());
1521 		GEO_CHECK_GL();
1522                 for(index_t j=0; j<n; ++j) {
1523                     glVertexAttribPointer(
1524                         i*n+j,
1525                         4,
1526                         GL_FLOAT,
1527                         GL_FALSE,
1528                         GLsizei(sizeof(GL_FLOAT)*4*n),        // stride
1529                         (const GLvoid*)(sizeof(GL_FLOAT)*4*j) // pointer
1530                     );
1531 		    GEO_CHECK_GL();
1532                 }
1533             }
1534 
1535             glBindBuffer(GL_ARRAY_BUFFER,0);
1536             glupBindVertexArray(0);
1537         }
1538     }
1539 
set_primitive_info_immediate_index_mode(GLUPprimitive glup_primitive,GLenum GL_primitive,GLuint program,index_t nb_elements_per_glup_primitive,index_t * element_indices)1540     void Context::set_primitive_info_immediate_index_mode(
1541         GLUPprimitive glup_primitive, GLenum GL_primitive, GLuint program,
1542         index_t nb_elements_per_glup_primitive,
1543         index_t* element_indices
1544     ) {
1545 
1546         set_primitive_info(glup_primitive, GL_primitive, program);
1547 
1548         if(primitive_info_[glup_primitive].elements_VBO == 0) {
1549 
1550             index_t nb_glup_primitives =
1551                 IMMEDIATE_BUFFER_SIZE /
1552                 nb_vertices_per_primitive[glup_primitive];
1553 
1554             index_t nb_elements =
1555                 nb_glup_primitives * nb_elements_per_glup_primitive;
1556 
1557             GLuint elements_VBO = 0;
1558             glGenBuffers(1, &elements_VBO);
1559             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elements_VBO);
1560 
1561             Numeric::uint16* indices = new Numeric::uint16[nb_elements];
1562             index_t cur_element=0;
1563             index_t cur_vertex_offset=0;
1564             for(
1565                 index_t glup_prim=0; glup_prim<nb_glup_primitives; ++glup_prim
1566             ) {
1567                 for(index_t le=0; le<nb_elements_per_glup_primitive; ++le) {
1568                     indices[cur_element] = Numeric::uint16(
1569                         cur_vertex_offset + element_indices[le]
1570                     );
1571                     ++cur_element;
1572                 }
1573                 cur_vertex_offset += nb_vertices_per_primitive[glup_primitive];
1574             }
1575 
1576             glBufferData(
1577                 GL_ELEMENT_ARRAY_BUFFER,
1578                 GLsizeiptr(sizeof(Numeric::uint16) * nb_elements),
1579                 indices, GL_STATIC_DRAW
1580             );
1581 
1582             delete[] indices;
1583 
1584             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1585 
1586             primitive_info_[glup_primitive].elements_VBO = elements_VBO;
1587             primitive_info_[glup_primitive].nb_elements_per_primitive =
1588                 nb_elements_per_glup_primitive;
1589             primitive_info_[glup_primitive].primitive_elements =
1590                 element_indices;
1591         }
1592 
1593         if(primitive_info_[glup_primitive].VAO == 0) {
1594             glupGenVertexArrays(1,&primitive_info_[glup_primitive].VAO);
1595             glupBindVertexArray(primitive_info_[glup_primitive].VAO);
1596 
1597             bind_immediate_state_buffers_to_VAO();
1598 
1599             glBindBuffer(
1600                 GL_ELEMENT_ARRAY_BUFFER,
1601                 primitive_info_[glup_primitive].elements_VBO
1602             );
1603 
1604             if(vertex_id_VBO_ != 0) {
1605                 glBindBuffer(GL_ARRAY_BUFFER, vertex_id_VBO_);
1606                 glVertexAttribPointer(
1607                     GLUP_VERTEX_ID_ATTRIBUTE,
1608                     1,                 // 1 component per attribute
1609                     GL_UNSIGNED_SHORT, // components are bytes
1610                     GL_FALSE,          // do not normalize
1611                     0,                 // stride
1612                     nullptr            // pointer (relative to bound VBO beginning)
1613                 );
1614             }
1615 
1616             glupBindVertexArray(0);
1617             glBindBuffer(GL_ARRAY_BUFFER,0);
1618             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
1619         }
1620     }
1621 
setup_primitives()1622     void Context::setup_primitives() {
1623         primitive_info_.resize(GLUP_NB_PRIMITIVES);
1624     }
1625 
setup_shaders_source_for_toggles(GLUPbitfield toggles_state,GLUPbitfield toggles_undetermined)1626     void Context::setup_shaders_source_for_toggles(
1627         GLUPbitfield toggles_state,
1628         GLUPbitfield toggles_undetermined
1629     ) {
1630         toggles_source_state_ = toggles_state;
1631         toggles_source_undetermined_ = toggles_undetermined;
1632     }
1633 
setup_shaders_source_for_primitive(GLUPprimitive primitive)1634     void Context::setup_shaders_source_for_primitive(
1635         GLUPprimitive primitive
1636     ) {
1637         primitive_source_ = primitive;
1638     }
1639 
1640 
primitive_declaration(GLUPprimitive prim) const1641     std::string Context::primitive_declaration(GLUPprimitive prim) const {
1642         std::string result =
1643             std::string("const int glup_primitive = ") +
1644             primitive_name[prim] + ";\n"                 +
1645             "const int glup_primitive_dimension = "   +
1646             String::to_string(primitive_dimension[prim]) +
1647             ";\n" +
1648             "const int glup_primitive_nb_vertices = " +
1649             String::to_string(nb_vertices_per_primitive[prim]) +
1650             ";\n" +
1651 	    "#define GLUP_PRIMITIVE_DIMENSION " +
1652 	    String::to_string(primitive_dimension[prim]) +
1653             "\n"
1654             ;
1655 
1656         return result;
1657     }
1658 
update_toggles_config()1659     void Context::update_toggles_config() {
1660         if(uniform_state_.toggle[GLUP_PICKING].get()) {
1661             toggles_config_ = (1u << GLUP_PICKING);
1662         } else {
1663             toggles_config_ = 0;
1664             for(index_t i=0; i<uniform_state_.toggle.size(); ++i) {
1665                 if(uniform_state_.toggle[i].get()) {
1666                     toggles_config_ |= ((PrimitiveInfo::ShaderKey)(1) << i);
1667                 }
1668             }
1669         }
1670     }
1671 
create_program_if_needed(GLUPprimitive primitive)1672     void Context::create_program_if_needed(GLUPprimitive primitive) {
1673         primitive_source_ = primitive;
1674         if(
1675 	    !primitive_info_[primitive].program_is_initialized(toggles_config_)
1676 	) {
1677             setup_shaders_source_for_primitive(primitive);
1678             setup_shaders_source_for_toggles_config(toggles_config_);
1679             switch(primitive) {
1680             case GLUP_POINTS:
1681                 setup_GLUP_POINTS();
1682                 break;
1683             case GLUP_LINES:
1684                 setup_GLUP_LINES();
1685                 break;
1686             case GLUP_TRIANGLES:
1687                 setup_GLUP_TRIANGLES();
1688                 break;
1689             case GLUP_QUADS:
1690                 setup_GLUP_QUADS();
1691                 break;
1692             case GLUP_TETRAHEDRA:
1693                 setup_GLUP_TETRAHEDRA();
1694                 break;
1695             case GLUP_HEXAHEDRA:
1696                 setup_GLUP_HEXAHEDRA();
1697                 break;
1698             case GLUP_PRISMS:
1699                 setup_GLUP_PRISMS();
1700                 break;
1701             case GLUP_PYRAMIDS:
1702                 setup_GLUP_PYRAMIDS();
1703                 break;
1704             case GLUP_CONNECTORS:
1705                 setup_GLUP_CONNECTORS();
1706                 break;
1707             case GLUP_SPHERES:
1708                 setup_GLUP_SPHERES();
1709                 break;
1710             case GLUP_NB_PRIMITIVES:
1711                 geo_assert_not_reached;
1712             }
1713         }
1714     }
1715 
setup_GLUP_POINTS()1716     void Context::setup_GLUP_POINTS() {
1717     }
1718 
setup_GLUP_LINES()1719     void Context::setup_GLUP_LINES() {
1720     }
1721 
setup_GLUP_TRIANGLES()1722     void Context::setup_GLUP_TRIANGLES() {
1723     }
1724 
setup_GLUP_QUADS()1725     void Context::setup_GLUP_QUADS() {
1726     }
1727 
setup_GLUP_TETRAHEDRA()1728     void Context::setup_GLUP_TETRAHEDRA() {
1729     }
1730 
setup_GLUP_HEXAHEDRA()1731     void Context::setup_GLUP_HEXAHEDRA() {
1732     }
1733 
setup_GLUP_PRISMS()1734     void Context::setup_GLUP_PRISMS() {
1735     }
1736 
setup_GLUP_PYRAMIDS()1737     void Context::setup_GLUP_PYRAMIDS() {
1738     }
1739 
setup_GLUP_CONNECTORS()1740     void Context::setup_GLUP_CONNECTORS() {
1741     }
1742 
setup_GLUP_SPHERES()1743     void Context::setup_GLUP_SPHERES() {
1744     }
1745 
shrink_cells_in_immediate_buffers()1746     void Context::shrink_cells_in_immediate_buffers() {
1747         if(
1748             uniform_state_.cells_shrink.get() == 0.0f   ||
1749             immediate_state_.primitive() == GLUP_POINTS ||
1750             immediate_state_.primitive() == GLUP_LINES  ||
1751             (uniform_state_.clipping_mode.get() == GLUP_CLIP_SLICE_CELLS &&
1752              uniform_state_.toggle[GLUP_CLIPPING].get())
1753         ) {
1754             return;
1755         }
1756 
1757         GLfloat s = uniform_state_.cells_shrink.get();
1758         GLfloat g[3];
1759         index_t nb_v = nb_vertices_per_primitive[immediate_state_.primitive()];
1760         index_t v=0;
1761         while(v < immediate_state_.nb_vertices()) {
1762             g[0] = 0.0f;
1763             g[1] = 0.0f;
1764             g[2] = 0.0f;
1765             for(index_t lv=0; lv<nb_v; ++lv) {
1766                 GLfloat* p = immediate_state_.buffer[0].element_ptr(v+lv);
1767                 g[0] += p[0];
1768                 g[1] += p[1];
1769                 g[2] += p[2];
1770             }
1771             g[0] /= GLfloat(nb_v);
1772             g[1] /= GLfloat(nb_v);
1773             g[2] /= GLfloat(nb_v);
1774             for(index_t lv=0; lv<nb_v; ++lv) {
1775                 GLfloat* p = immediate_state_.buffer[0].element_ptr(v+lv);
1776                 p[0] = s*g[0] + (1.0f - s)*p[0];
1777                 p[1] = s*g[1] + (1.0f - s)*p[1];
1778                 p[2] = s*g[2] + (1.0f - s)*p[2];
1779             }
1780             v += nb_v;
1781         }
1782     }
1783 
create_CPU_side_uniform_buffer()1784     void Context::create_CPU_side_uniform_buffer() {
1785         uniform_buffer_dirty_=true;
1786         matrices_dirty_=true;
1787         uniform_binding_point_=1;
1788 
1789         std::map<std::string, GLsizei> type_to_size;
1790         type_to_size["bool"] = GLsizei(sizeof(int));
1791         type_to_size["vec4"] = GLsizei(4*sizeof(GLfloat));
1792         type_to_size["vec3"] = GLsizei(3*sizeof(GLfloat));
1793         type_to_size["mat4"] = GLsizei(4*4*sizeof(GLfloat));
1794         type_to_size["mat3"] = GLsizei(4*3*sizeof(GLfloat)); // yes, 4, there is padding
1795         type_to_size["float"] = GLsizei(sizeof(GLfloat));
1796         type_to_size["int"] = GLsizei(sizeof(GLint));
1797 
1798         // Parse uniform state declaration in order to "emulate" it...
1799         uniform_buffer_size_ = 0;
1800         std::istringstream input(uniform_state_declaration());
1801         std::string line;
1802         while(std::getline(input,line)) {
1803             std::vector<std::string> words;
1804             GEO::String::split_string(line, ' ', words);
1805             if(
1806                 (words.size() == 2 && words[1][words[1].length()-1] == ';') ||
1807                 (words.size() == 3 && words[2] == ";")
1808             ) {
1809                 std::string vartype = words[0];
1810                 std::string varname = words[1];
1811                 if(varname[varname.length()-1] == ';') {
1812                     varname = varname.substr(0, varname.length()-1);
1813                 }
1814                 if(type_to_size.find(vartype) != type_to_size.end()) {
1815                     variable_to_offset_[varname] = uniform_buffer_size_;
1816                     uniform_buffer_size_ += type_to_size[vartype];
1817                 }
1818             }
1819         }
1820 
1821         uniform_buffer_data_ = new Memory::byte[uniform_buffer_size_];
1822         Memory::clear(uniform_buffer_data_, size_t(uniform_buffer_size_));
1823 
1824         setup_state_variables();
1825         setup_immediate_buffers();
1826         setup_primitives();
1827 
1828         world_clip_plane_ = uniform_state_.world_clip_plane.get_pointer();
1829     }
1830 
bind_immediate_state_buffers_to_VAO()1831     void Context::bind_immediate_state_buffers_to_VAO() {
1832         for(index_t i=0; i<ImmediateState::NB_IMMEDIATE_BUFFERS; ++i) {
1833             glBindBuffer(
1834                 GL_ARRAY_BUFFER,
1835                 immediate_state_.buffer[i].VBO()
1836             );
1837             glVertexAttribPointer(
1838                 i,
1839                 GLint(immediate_state_.buffer[i].dimension()),
1840                 GL_FLOAT,
1841                 GL_FALSE,
1842                 0,      // stride
1843                 nullptr // pointer (relative to bound VBO beginning)
1844             );
1845         }
1846         glBindBuffer(GL_ARRAY_BUFFER, 0);
1847     }
1848 
classify_vertices_in_immediate_buffers()1849     void Context::classify_vertices_in_immediate_buffers() {
1850         if(!uniform_state_.toggle[GLUP_CLIPPING].get()) {
1851             return;
1852         }
1853         if(uniform_state_.clipping_mode.get() == GLUP_CLIP_STANDARD) {
1854             return;
1855         }
1856         if(
1857             immediate_state_.primitive() == GLUP_POINTS ||
1858             immediate_state_.primitive() == GLUP_LINES  ||
1859             immediate_state_.primitive() == GLUP_TRIANGLES ||
1860             immediate_state_.primitive() == GLUP_QUADS
1861         ) {
1862             return;
1863         }
1864 
1865         for(index_t v=0; v<immediate_state_.nb_vertices(); ++v) {
1866             float* p = immediate_state_.buffer[0].element_ptr(v);
1867             float s = 0.0;
1868             for(index_t i=0; i<4; ++i) {
1869                 s += world_clip_plane_[i]*p[i];
1870             }
1871             v_is_visible_[v] = (s >= 0);
1872         }
1873     }
1874 
1875 
cell_is_clipped(index_t first_v)1876     bool Context::cell_is_clipped(index_t first_v) {
1877         if(!uniform_state_.toggle[GLUP_CLIPPING].get()) {
1878             return false;
1879         }
1880         if(uniform_state_.clipping_mode.get() == GLUP_CLIP_STANDARD) {
1881             return false;
1882         }
1883         index_t nb_visible=0;
1884         index_t nb_in_cell =
1885             nb_vertices_per_primitive[immediate_state_.primitive()];
1886         for(index_t lv=0; lv<nb_in_cell; ++lv) {
1887             nb_visible += (v_is_visible_[first_v + lv]);
1888         }
1889         switch(uniform_state_.clipping_mode.get()) {
1890         case GLUP_CLIP_STRADDLING_CELLS:
1891             return (nb_visible == 0 || nb_visible == nb_in_cell);
1892         case GLUP_CLIP_WHOLE_CELLS:
1893             return (nb_visible == 0);
1894         case GLUP_CLIP_SLICE_CELLS:
1895             return false;
1896         }
1897         return false;
1898     }
1899 
copy_uniform_state_to_current_program()1900     void Context::copy_uniform_state_to_current_program() {
1901     }
1902 
create_vertex_id_VBO()1903     void Context::create_vertex_id_VBO() {
1904 
1905         glGenBuffers(1, &vertex_id_VBO_);
1906         glBindBuffer(GL_ARRAY_BUFFER, vertex_id_VBO_);
1907         GLushort* indices = new GLushort[65536];
1908         for(index_t i=0; i<65536; ++i) {
1909             indices[i] = GLushort(i);
1910         }
1911         glBufferData(
1912             GL_ARRAY_BUFFER,
1913             GLsizeiptr(sizeof(GLushort)*65536),
1914             indices, GL_STATIC_DRAW
1915         );
1916         delete[] indices;
1917         glBindBuffer(GL_ARRAY_BUFFER, 0);
1918 
1919         // Bind the index VBO to the common VAO used by the immediate state.
1920         if(immediate_state_.VAO() != 0) {
1921             glupBindVertexArray(immediate_state_.VAO());
1922             glBindBuffer(GL_ARRAY_BUFFER, vertex_id_VBO_);
1923             glVertexAttribPointer(
1924                 GLUP_VERTEX_ID_ATTRIBUTE,
1925                 1,                 // 1 component per attribute
1926                 GL_UNSIGNED_SHORT, // components are 16 bits integers
1927                 GL_FALSE,          // do not normalize
1928                 0,                 // stride
1929                 nullptr            // pointer (relative to bound VBO beginning)
1930             );
1931             glBindBuffer(GL_ARRAY_BUFFER, 0);
1932             glupBindVertexArray(0);
1933         }
1934 
1935     }
1936 
get_vertex_shader_preamble_pseudo_file(std::vector<GLSL::Source> & sources)1937     void Context::get_vertex_shader_preamble_pseudo_file(
1938         std::vector<GLSL::Source>& sources
1939     ) {
1940         geo_argused(sources);
1941     }
1942 
get_fragment_shader_preamble_pseudo_file(std::vector<GLSL::Source> & sources)1943     void Context::get_fragment_shader_preamble_pseudo_file(
1944         std::vector<GLSL::Source>& sources
1945     ) {
1946         geo_argused(sources);
1947     }
1948 
get_geometry_shader_preamble_pseudo_file(std::vector<GLSL::Source> & sources)1949     void Context::get_geometry_shader_preamble_pseudo_file(
1950         std::vector<GLSL::Source>& sources
1951     ) {
1952         geo_argused(sources);
1953     }
1954 
get_tess_control_shader_preamble_pseudo_file(std::vector<GLSL::Source> & sources)1955     void Context::get_tess_control_shader_preamble_pseudo_file(
1956         std::vector<GLSL::Source>& sources
1957     ) {
1958         geo_argused(sources);
1959     }
1960 
get_tess_evaluation_shader_preamble_pseudo_file(std::vector<GLSL::Source> & sources)1961     void Context::get_tess_evaluation_shader_preamble_pseudo_file(
1962         std::vector<GLSL::Source>& sources
1963     ) {
1964         geo_argused(sources);
1965     }
1966 
get_toggles_pseudo_file(std::vector<GLSL::Source> & sources)1967     void Context::get_toggles_pseudo_file(
1968         std::vector<GLSL::Source>& sources
1969     ) {
1970         std::string toggle_enabled_source =
1971             "bool glupIsEnabled(in int toggle) {\n";
1972         for(index_t i=0; i<uniform_state_.toggle.size(); ++i) {
1973             std::string toggle_var_name = uniform_state_.toggle[i].name();
1974             std::string toggle_name = toggle_var_name;
1975             size_t pos = toggle_name.find("_enabled");
1976             geo_assert(pos != std::string::npos);
1977             toggle_name = "GLUP_" +
1978                 String::to_uppercase(toggle_name.substr(0,pos));
1979             std::string test =
1980                 "   if(toggle=="+toggle_name + ") {\n";
1981             toggle_enabled_source += test;
1982             if(toggles_source_undetermined_ & (1 << i)) {
1983                 toggle_enabled_source +=
1984                     "      return GLUP."+toggle_var_name+";\n";
1985             } else {
1986                 if(toggles_source_state_ & (1 << i)) {
1987                     toggle_enabled_source +=
1988                         "      return true;\n";
1989                 } else {
1990                     toggle_enabled_source +=
1991                         "      return false;\n";
1992                 }
1993             }
1994             toggle_enabled_source += "   }\n";
1995         }
1996         toggle_enabled_source += "   return false; \n}\n";
1997         sources.push_back(toggle_enabled_source);
1998     }
1999 
get_primitive_pseudo_file(std::vector<GLSL::Source> & sources)2000     void Context::get_primitive_pseudo_file(
2001         std::vector<GLSL::Source>& sources
2002     ) {
2003         sources.push_back(primitive_declaration(primitive_source_));
2004     }
2005 
get_marching_cells_pseudo_file(std::vector<GLSL::Source> & sources)2006     void Context::get_marching_cells_pseudo_file(
2007         std::vector<GLSL::Source>& sources
2008     ) {
2009         const MarchingCell& marching_cell = get_marching_cell();
2010         sources.push_back(
2011             marching_cell.GLSL_uniform_state_declaration()
2012         );
2013         sources.push_back(
2014             marching_cell.GLSL_compute_intersections()
2015         );
2016     }
2017 
get_marching_cell() const2018     const MarchingCell& Context::get_marching_cell() const {
2019         const MarchingCell* result = nullptr;
2020         switch(primitive_source_) {
2021         case GLUP_TETRAHEDRA:
2022             result = &marching_tet_;
2023             break;
2024         case GLUP_HEXAHEDRA:
2025             result = &marching_hex_;
2026             break;
2027         case GLUP_PRISMS:
2028             result = &marching_prism_;
2029             break;
2030         case GLUP_PYRAMIDS:
2031             result = &marching_pyramid_;
2032             break;
2033         case GLUP_CONNECTORS:
2034             result = &marching_connector_;
2035             break;
2036         case GLUP_POINTS:
2037         case GLUP_LINES:
2038         case GLUP_TRIANGLES:
2039         case GLUP_QUADS:
2040 	case GLUP_SPHERES:
2041         case GLUP_NB_PRIMITIVES:
2042             geo_assert_not_reached;
2043         }
2044         return *result;
2045     }
2046 
initialize()2047     void Context::initialize() {
2048         static bool initialized = false;
2049         if(initialized) {
2050             return;
2051         }
2052 
2053         GLSL::register_GLSL_include_file(
2054             "GLUP/current_profile/vertex_shader_preamble.h",
2055 	    vertex_shader_preamble_pseudo_file
2056         );
2057 
2058         GLSL::register_GLSL_include_file(
2059             "GLUP/current_profile/fragment_shader_preamble.h",
2060 	    fragment_shader_preamble_pseudo_file
2061         );
2062 
2063         GLSL::register_GLSL_include_file(
2064             "GLUP/current_profile/geometry_shader_preamble.h",
2065 	    geometry_shader_preamble_pseudo_file
2066         );
2067 
2068         GLSL::register_GLSL_include_file(
2069             "GLUP/current_profile/marching_cells.h",
2070 	    marching_cells_pseudo_file
2071         );
2072 
2073         GLSL::register_GLSL_include_file(
2074             "GLUP/current_profile/tess_control_shader_preamble.h",
2075 	    tess_control_shader_preamble_pseudo_file
2076         );
2077 
2078         GLSL::register_GLSL_include_file(
2079             "GLUP/current_profile/tess_evaluation_shader_preamble.h",
2080 	    tess_evaluation_shader_preamble_pseudo_file
2081         );
2082 
2083         GLSL::register_GLSL_include_file(
2084             "GLUP/current_profile/toggles.h",
2085 	    toggles_pseudo_file
2086         );
2087 
2088         GLSL::register_GLSL_include_file(
2089             "GLUP/current_profile/primitive.h",
2090 	    primitive_pseudo_file
2091         );
2092 
2093         GLUP::register_embedded_shaders_GLUP();
2094 
2095         initialized = true;
2096     }
2097 
2098 }
2099 
2100