GCC Code Coverage Report


Directory: ./
File: lib/geogram_gfx/GLUP/GLUP_context.cpp
Date: 2026-09-07 02:37:58
Exec Total Coverage
Lines: 0 1136 0.0%
Functions: 0 90 0.0%
Branches: 0 1066 0.0%

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