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