1 /*
2 * Copyright (c) 2012-2014, 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.h>
47 #include <geogram_gfx/GLUP/GLUP_context_GLSL.h>
48 #include <geogram_gfx/GLUP/GLUP_context_ES.h>
49 #include <geogram_gfx/basic/GLSL.h>
50 #include <geogram/basic/logger.h>
51 #include <geogram/basic/file_system.h>
52 #include <geogram/basic/command_line.h>
53
54 #ifdef GEO_OS_EMSCRIPTEN
55 #include <emscripten.h>
56 #pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
57 #endif
58
59 #ifdef GEO_OS_ANDROID
60 # pragma GCC diagnostic ignored "-Wpointer-bool-conversion"
61 #endif
62
63
64 /*****************************************************************************/
65
66 namespace {
67 using namespace GEO;
downgrade_message()68 void downgrade_message() {
69 static bool done = false;
70 if(!done) {
71 done = true;
72 Logger::out("GLUP") << "Something happened, trying to fix (by downgrading)" << std::endl;
73 Logger::out("GLUP") << "If this does not work, try the following options:" << std::endl;
74 Logger::out("GLUP") << " (1) make sure your OpenGL driver is up to date" << std::endl;
75 Logger::out("GLUP") << " (2) create a file named \'"
76 << CmdLine::get_config_file_name() << "\' in " << std::endl;
77 Logger::out("GLUP") << " your home directory (" << FileSystem::home_directory() << ")" << std::endl;
78 Logger::out("GLUP") << " with: " << std::endl;
79 Logger::out("GLUP") << " gfx:GLUP_profile=GLUPES2" << std::endl;
80 }
81 }
82 }
83
84 /*****************************************************************************/
85
86 namespace GLUP {
87 using namespace GEO;
88
89 extern GLUP_API Context* current_context_;
90 Context* current_context_ = nullptr;
91
92 static std::set<Context*> all_contexts_;
93 static bool initialized_ = false;
cleanup()94 static void cleanup() {
95 #ifdef GEO_OS_ANDROID
96 // Note: removal of context from all_contexts_
97 // is done in glupDeleteContext() (not in Context
98 // destructor), so we can direcly iterate on all_contexts_
99 // and delete.
100 // TODO: check that GLUP contexts are really destroyed *before*
101 // the OpenGL context. (yes it is, because if I output
102 // something to the logger here, it appears in the app's temrinal).
103 for(auto ctxt: all_contexts_) {
104 delete ctxt;
105 }
106 all_contexts_.clear();
107 return;
108 #endif
109
110 // Note: remaining contexts are not deallocated here because:
111 // (1) there should be no remaining context (it is Application's
112 // job to deallocate them).
113 // (2) when cleanup() is called, Application's delete_window() was
114 // called before, as well as glfwDeleteWindow() / glfwTerminate()
115 // so the OpenGL context is destroyed (and it is not legal to destroy
116 // it before the OpenGL objects in the GLUP context)
117 if(all_contexts_.size() != 0) {
118 Logger::warn("GLUP") << "Some GLUP contexts were not deallocated"
119 << std::endl;
120 Logger::warn("GLUP") << "App\'s GL_terminate() probably forgot to"
121 << std::endl;
122 Logger::warn("GLUP") << "call SimpleApplication\'s GL_terminate()"
123 << std::endl;
124 Logger::warn("GLUP") << "(needs to be at then end of the function)"
125 << std::endl;
126 }
127 }
128
129 }
130
131 /*****************************************************************************/
132
glupUniformStateDeclaration()133 const char* glupUniformStateDeclaration() {
134 GEO_CHECK_GL();
135 return GLUP::current_context_->uniform_state_declaration();
136 }
137
glupCompileShader(GLUPenum target,const char * source)138 GLUPuint glupCompileShader(GLUPenum target, const char* source) {
139 GEO_CHECK_GL();
140 GLUP::current_context_->setup_shaders_source_for_primitive(GLUP_TRIANGLES);
141 // First param: ignored.
142 // Second param: all toggle states are unknown.
143 GLUP::current_context_->setup_shaders_source_for_toggles(0,~0);
144 GEO_CHECK_GL();
145 GLUPuint result = GLSL::compile_shader_with_includes(
146 target, source, GLUP::current_context_
147 );
148 GEO_CHECK_GL();
149 return result;
150 }
151
152 namespace {
153 /**
154 * \brief Converts a comment //stage GL_VERTEX_SHADER into
155 * the associated GLUPenum value.
156 * \param[in,out] comment_str on entry, a pointer to the comment.
157 * on exit, the next line. A '\0' terminator is inserted in
158 * the string (replaces the '\n' that ends the line).
159 * \return the target or 0 if an error was encountered.
160 */
stage_to_target(char * & comment_str)161 static GLUPenum stage_to_target(char*& comment_str) {
162 char* p1 = comment_str + 8;
163 char* p2 = strchr(p1, '\n');
164 if(p2 == nullptr) {
165 Logger::err("GLSL")
166 << "Missing CR in //stage GL_xxxxx declaration"
167 << std::endl;
168 return 0;
169 }
170 std::string stage_str(p1, size_t(p2-p1));
171
172 GLenum stage = 0;
173 if(stage_str == "GL_VERTEX_SHADER") {
174 stage = GL_VERTEX_SHADER;
175 } else if(stage_str == "GL_FRAGMENT_SHADER") {
176 stage = GL_FRAGMENT_SHADER;
177 }
178
179 #ifndef GEO_OS_EMSCRIPTEN
180 else if(stage_str == "GL_GEOMETRY_SHADER") {
181 stage = GL_GEOMETRY_SHADER;
182 } else if(stage_str == "GL_TESS_CONTROL_SHADER") {
183 stage = GL_TESS_CONTROL_SHADER;
184 } else if(stage_str == "GL_TESS_EVALUATION_SHADER") {
185 stage = GL_TESS_EVALUATION_SHADER;
186 }
187 #endif
188 else {
189 Logger::err("GLSL") << stage_str << ": unknown stage"
190 << std::endl;
191 }
192 *comment_str = '\0';
193 comment_str = p2+1;
194 return stage;
195 }
196 }
197
glupCompileProgram(const char * source_in)198 GLUPuint glupCompileProgram(const char* source_in) {
199 std::string source(source_in);
200 std::vector<const char*> sources;
201 std::vector<GLUPenum> targets;
202 std::vector<GLuint> shaders;
203
204 char* p = const_cast<char*>(source.c_str());
205
206 bool has_vertex_shader = false;
207 for(
208 p = strstr(p,"//stage");
209 (p != nullptr) && (*p != '\0');
210 p = strstr(p,"//stage ")
211 ) {
212 GLUPenum target = stage_to_target(p);
213 if(target == 0) {
214 return 0;
215 }
216 sources.push_back(p);
217 targets.push_back(target);
218 has_vertex_shader = has_vertex_shader || (target == GL_VERTEX_SHADER);
219 }
220
221 // Use default vertex shader if no vertex shader was specified.
222 if(!has_vertex_shader) {
223 if(!strcmp(glupCurrentProfileName(),"GLUPES2")) {
224 targets.push_back(GL_VERTEX_SHADER);
225 sources.push_back("//import <GLUPES/vertex_shader.h>\n");
226 } else if(
227 !strcmp(glupCurrentProfileName(),"GLUP150") ||
228 !strcmp(glupCurrentProfileName(),"GLUP440")
229 ) {
230 targets.push_back(GL_VERTEX_SHADER);
231 sources.push_back("//import <GLUPGLSL/vertex_shader.h>\n");
232 }
233 }
234
235 GLuint program = 0;
236 try {
237 for(index_t i=0; i<index_t(sources.size()); ++i) {
238 GLUPuint shader = glupCompileShader(targets[i], sources[i]);
239 if(shader == 0) {
240 #ifdef GEO_OS_EMSCRIPTEN
241 return 0;
242 #else
243 throw(GLSL::GLSLCompileError());
244 #endif
245 }
246 shaders.push_back(shader);
247 }
248
249 program = glCreateProgram();
250
251 for(index_t i=0; i<index_t(shaders.size()); ++i) {
252 glAttachShader(program, shaders[i]);
253 }
254
255 GEO_CHECK_GL();
256 glBindAttribLocation(program, GLUP::GLUP_VERTEX_ATTRIBUTE, "vertex_in");
257 glBindAttribLocation(program, GLUP::GLUP_COLOR_ATTRIBUTE, "color_in");
258 glBindAttribLocation(
259 program, GLUP::GLUP_TEX_COORD_ATTRIBUTE, "tex_coord_in"
260 );
261 glBindAttribLocation(program, GLUP::GLUP_NORMAL_ATTRIBUTE, "normal_in");
262
263 GEO_CHECK_GL();
264 GLSL::link_program(program);
265 GEO_CHECK_GL();
266 GLUP::current_context_->bind_uniform_state(program);
267 GEO_CHECK_GL();
268 } catch(...) {
269 if(program != 0) {
270 Logger::err("GLSL") << "Could not compile program"
271 << std::endl;
272 glDeleteProgram(program);
273 program = 0;
274 }
275 }
276
277 // Shaders are reference-counted, now they are attached
278 // to the program.
279 for(index_t i=0; i<index_t(shaders.size()); ++i) {
280 glDeleteShader(shaders[i]);
281 }
282
283 return program;
284 }
285
glupBindUniformState(GLUPuint program)286 void glupBindUniformState(GLUPuint program) {
287 GEO_CHECK_GL();
288 GLUP::current_context_->bind_uniform_state(program);
289 GEO_CHECK_GL();
290 }
291
292
293 #if !defined(GEO_OS_EMSCRIPTEN) && \
294 !defined(GEO_OS_APPLE) && \
295 !defined(GEO_OS_ANDROID)
296
297 /**
298 * \brief Tests whether tessellation shaders are supported by OpenGL.
299 * \details Some drivers may declare to be OpenGL 4.5 compliant whereas
300 * they do not have tesselation shader (for instance, I have an old
301 * NVidia quadro that does that...)
302 * \retval true if tessellation shaders are supported
303 * \retval false otherwise
304 */
supports_tessellation_shader()305 static bool supports_tessellation_shader() {
306 GEO_CHECK_GL();
307
308 #ifndef GEO_GL_150
309 return false;
310 #else
311 bool result = true;
312
313 // Note: I experienced crashes with glPatchParameterfv() with
314 // the OpenGL es profile, so I'm deactivating it if detected.
315 if(GEO::CmdLine::get_arg("gfx:GL_profile") == "ES") {
316 GEO::Logger::out("GLUP")
317 << "Deactivating tesselation shader under OpenGL ES profile"
318 << std::endl;
319 return false;
320 }
321
322 GLuint s_handle = glCreateShader(GL_TESS_CONTROL_SHADER);
323 result = result && (s_handle != 0);
324 if (s_handle != 0) {
325 glDeleteShader(s_handle);
326 }
327
328 // Clear OpenGL error flag.
329 while(glGetError() != GL_NO_ERROR) {
330 }
331
332 return result;
333 #endif
334 }
335
336 #endif
337
glupCreateContext()338 GLUPcontext glupCreateContext() {
339
340
341 if(!GLUP::initialized_) {
342 GLUP::initialized_ = true;
343 atexit(GLUP::cleanup);
344 }
345
346
347 GEO_CHECK_GL();
348
349 std::string GLUP_profile = GEO::CmdLine::get_arg("gfx:GLUP_profile");
350 GLUP::Context* result = nullptr;
351
352 if(GLUP_profile == "auto") {
353
354 #if defined(GEO_OS_EMSCRIPTEN) || defined(GEO_OS_APPLE) || defined(GEO_OS_ANDROID)
355 GLUP_profile = "GLUPES2";
356 // GLUP_profile = "GLUP150"; // Does something but bugged / not fully functional.
357 #else
358 GEO_CHECK_GL();
359 double GLSL_version = GEO::GLSL::supported_language_version();
360 GEO_CHECK_GL();
361 if (GLSL_version >= 4.4) {
362 GEO_CHECK_GL();
363 if (!supports_tessellation_shader()) {
364 GEO::Logger::out("GLUP")
365 << "GLSL version >= 4.4 but tessellation unsupported"
366 << std::endl;
367 downgrade_message();
368 GEO::Logger::out("GLUP") << "Downgrading to GLUP 150..."
369 << std::endl;
370 GLSL_version = 1.5;
371 }
372 GEO_CHECK_GL();
373 }
374
375 if(GLSL_version >= 4.4) {
376 GLUP_profile = "GLUP440";
377 } else if(GLSL_version >= 1.5) {
378 GLUP_profile = "GLUP150";
379 } else {
380 GLUP_profile = "GLUPES2";
381 }
382
383 #endif
384 }
385
386
387 GEO::Logger::out("GLUP") << "Using " << GLUP_profile << " profile"
388 << std::endl;
389
390 #ifdef GEO_GL_440
391 if(GLUP_profile == "GLUP440") {
392 try {
393 result = new GLUP::Context_GLSL440;
394 result->setup();
395 } catch(...) {
396 GEO::Logger::warn("GLUP")
397 << "Caught an exception in GLUP440, downgrading to GLUP150"
398 << std::endl;
399 downgrade_message();
400 GLUP_profile = "GLUP150";
401 delete result;
402 result = nullptr;
403 }
404 }
405 #endif
406
407 #ifdef GEO_GL_150
408 if(GLUP_profile == "GLUP150") {
409 try {
410 result = new GLUP::Context_GLSL150;
411 result->setup();
412 } catch(...) {
413 GEO::Logger::warn("GLUP")
414 << "Caught an exception in GLUP150, downgrading to GLUPES2"
415 << std::endl;
416 downgrade_message();
417 GLUP_profile = "GLUPES2";
418 delete result;
419 result = nullptr;
420 }
421 }
422 #endif
423
424 #ifdef GEO_GL_ES2
425 if(GLUP_profile == "GLUPES2") {
426 try {
427 result = new GLUP::Context_ES2;
428 result->setup();
429 } catch(...) {
430 GEO::Logger::warn("GLUP")
431 << "Caught an exception in GLUPES2"
432 << std::endl;
433 downgrade_message();
434 delete result;
435 result = nullptr;
436 }
437 }
438 #endif
439
440 if(result == nullptr) {
441 GEO::Logger::err("GLUP") << "Could not create context"
442 << std::endl;
443 } else {
444 GLUP::all_contexts_.insert(result);
445 }
446
447 return result;
448 }
449
glupDeleteContext(GLUPcontext context_in)450 void glupDeleteContext(GLUPcontext context_in) {
451 GEO_CHECK_GL();
452
453 GLUP::Context* context =
454 reinterpret_cast<GLUP::Context*>(context_in);
455
456 auto it = GLUP::all_contexts_.find(context);
457 geo_assert(it != GLUP::all_contexts_.end());
458 GLUP::all_contexts_.erase(it);
459
460 if(GLUP::current_context_ == context) {
461 GLUP::current_context_ = nullptr;
462 }
463 delete context;
464 }
465
466
glupCurrentContext()467 GLUPcontext glupCurrentContext() {
468 // Note: we cannot check GL state if OpenGL
469 // is not initialized.
470 if(GLUP::current_context_ != nullptr) {
471 GEO_CHECK_GL();
472 }
473 return GLUP::current_context_;
474 }
475
glupCurrentProfileName()476 const char* glupCurrentProfileName() {
477 GEO_CHECK_GL();
478 return GLUP::current_context_->profile_name();
479 }
480
glupMakeCurrent(GLUPcontext context)481 void glupMakeCurrent(GLUPcontext context) {
482 GEO_CHECK_GL();
483 GLUP::current_context_ = reinterpret_cast<GLUP::Context*>(context);
484 }
485
glupPrimitiveSupportsArrayMode(GLUPprimitive prim)486 GLUPboolean glupPrimitiveSupportsArrayMode(GLUPprimitive prim) {
487 GEO_CHECK_GL();
488 return GLUP::current_context_->primitive_supports_array_mode(prim) ?
489 GL_TRUE : GL_FALSE ;
490 }
491
492 /****************** Enable / Disable ***************************/
493
494 namespace GLUP {
495 extern bool vertex_array_emulate;
496 }
497
glupEnable(GLUPtoggle toggle)498 void glupEnable(GLUPtoggle toggle) {
499 GEO_CHECK_GL();
500 GLUP::current_context_->uniform_state().toggle[toggle].set(GL_TRUE);
501 }
502
glupDisable(GLUPtoggle toggle)503 void glupDisable(GLUPtoggle toggle) {
504 GEO_CHECK_GL();
505 GLUP::current_context_->uniform_state().toggle[toggle].set(GL_FALSE);
506 }
507
glupIsEnabled(GLUPtoggle toggle)508 GLUPboolean glupIsEnabled(GLUPtoggle toggle) {
509 GEO_CHECK_GL();
510 return GLUP::current_context_->uniform_state().toggle[toggle].get();
511 }
512
513 /********************** Texturing ******************************/
514
glupTextureType(GLUPtextureType type)515 void glupTextureType(GLUPtextureType type) {
516 GEO_CHECK_GL();
517 GLUP::current_context_->uniform_state().texture_type.set(type);
518 }
519
glupGetTextureType()520 GLUPtextureType glupGetTextureType() {
521 GEO_CHECK_GL();
522 return GLUPtextureType(
523 GLUP::current_context_->uniform_state().texture_type.get()
524 );
525 }
526
glupTextureMode(GLUPtextureMode mode)527 void glupTextureMode(GLUPtextureMode mode) {
528 GEO_CHECK_GL();
529 GLUP::current_context_->uniform_state().texture_mode.set(mode);
530 }
531
glupGetTextureMode()532 GLUPtextureMode glupGetTextureMode() {
533 GEO_CHECK_GL();
534 return GLUPtextureMode(
535 GLUP::current_context_->uniform_state().texture_mode.get()
536 );
537 }
538
539 /****************** Drawing state ******************************/
540
glupSetColor4fv(GLUPcolor color,const GLUPfloat * rgba)541 void glupSetColor4fv(GLUPcolor color, const GLUPfloat* rgba) {
542 GEO_CHECK_GL();
543 if(color == GLUP_FRONT_AND_BACK_COLOR) {
544 glupSetColor4fv(GLUP_FRONT_COLOR, rgba);
545 glupSetColor4fv(GLUP_BACK_COLOR, rgba);
546 } else {
547 GLUP::current_context_->uniform_state().color[color].set(rgba);
548 }
549 }
550
glupGetColor4fv(GLUPcolor color,float * rgba)551 void glupGetColor4fv(GLUPcolor color, float* rgba) {
552 GEO_CHECK_GL();
553 geo_assert(color != GLUP_FRONT_AND_BACK_COLOR);
554 GLUP::current_context_->uniform_state().color[color].get(rgba);
555 }
556
glupSetColor3fv(GLUPcolor color,const GLUPfloat * rgba)557 void glupSetColor3fv(GLUPcolor color, const GLUPfloat* rgba) {
558 GEO_CHECK_GL();
559 glupSetColor4f(color, rgba[0], rgba[1], rgba[2], 1.0);
560 }
561
glupSetColor4f(GLUPcolor color,GLUPfloat r,GLUPfloat g,GLUPfloat b,GLUPfloat a)562 void glupSetColor4f(
563 GLUPcolor color, GLUPfloat r, GLUPfloat g, GLUPfloat b, GLUPfloat a
564 ) {
565 GEO_CHECK_GL();
566 if(color == GLUP_FRONT_AND_BACK_COLOR) {
567 glupSetColor4f(GLUP_FRONT_COLOR, r, g, b, a);
568 glupSetColor4f(GLUP_BACK_COLOR, r, g, b, a);
569 } else {
570 GLUPfloat* ptr =
571 GLUP::current_context_->uniform_state().color[color].get_pointer();
572 ptr[0] = r;
573 ptr[1] = g;
574 ptr[2] = b;
575 ptr[3] = a;
576 }
577 }
578
glupSetColor3f(GLUPcolor color,GLUPfloat r,GLUPfloat g,GLUPfloat b)579 void glupSetColor3f(GLUPcolor color, GLUPfloat r, GLUPfloat g, GLUPfloat b) {
580 GEO_CHECK_GL();
581 glupSetColor4f(color, r, g, b, 1.0f);
582 }
583
glupSetColor4dv(GLUPcolor color,const GLUPdouble * rgba)584 void glupSetColor4dv(GLUPcolor color, const GLUPdouble* rgba) {
585 GEO_CHECK_GL();
586 glupSetColor4f(
587 color,
588 GLUPfloat(rgba[0]),
589 GLUPfloat(rgba[1]),
590 GLUPfloat(rgba[2]),
591 GLUPfloat(rgba[3])
592 );
593 }
594
glupSetColor3dv(GLUPcolor color,const GLUPdouble * rgba)595 void glupSetColor3dv(GLUPcolor color, const GLUPdouble* rgba) {
596 GEO_CHECK_GL();
597 glupSetColor4f(
598 color,
599 GLUPfloat(rgba[0]),
600 GLUPfloat(rgba[1]),
601 GLUPfloat(rgba[2]),
602 1.0f
603 );
604 }
605
glupSetColor4d(GLUPcolor color,GLUPdouble r,GLUPdouble g,GLUPdouble b,GLUPdouble a)606 void glupSetColor4d(
607 GLUPcolor color, GLUPdouble r, GLUPdouble g, GLUPdouble b, GLUPdouble a
608 ) {
609 GEO_CHECK_GL();
610 glupSetColor4f(
611 color,
612 GLUPfloat(r),
613 GLUPfloat(g),
614 GLUPfloat(b),
615 GLUPfloat(a)
616 );
617 }
618
glupSetColor3d(GLUPcolor color,GLUPdouble r,GLUPdouble g,GLUPdouble b)619 void glupSetColor3d(
620 GLUPcolor color, GLUPdouble r, GLUPdouble g, GLUPdouble b
621 ) {
622 GEO_CHECK_GL();
623 glupSetColor4f(
624 color,
625 GLUPfloat(r),
626 GLUPfloat(g),
627 GLUPfloat(b),
628 1.0f
629 );
630 }
631
glupLightVector3f(GLUPfloat x,GLUPfloat y,GLUPfloat z)632 void glupLightVector3f(GLUPfloat x, GLUPfloat y, GLUPfloat z) {
633 GEO_CHECK_GL();
634 GLUPfloat* ptr =
635 GLUP::current_context_->uniform_state().light_vector.get_pointer();
636 ptr[0] = x;
637 ptr[1] = y;
638 ptr[2] = z;
639 GLUP::current_context_->flag_lighting_as_dirty();
640 }
641
glupLightVector3fv(GLUPfloat * xyz)642 void glupLightVector3fv(GLUPfloat* xyz) {
643 GEO_CHECK_GL();
644 GLUP::current_context_->uniform_state().light_vector.set(xyz);
645 GLUP::current_context_->flag_lighting_as_dirty();
646 }
647
glupGetLightVector3fv(GLUPfloat * xyz)648 void glupGetLightVector3fv(GLUPfloat* xyz) {
649 GEO_CHECK_GL();
650 GLUPfloat* ptr =
651 GLUP::current_context_->uniform_state().light_vector.get_pointer();
652 xyz[0] = ptr[0];
653 xyz[1] = ptr[1];
654 xyz[2] = ptr[2];
655 }
656
glupSetPointSize(GLUPfloat size)657 void glupSetPointSize(GLUPfloat size) {
658 GEO_CHECK_GL();
659 GLUP::current_context_->uniform_state().point_size.set(size);
660 }
661
glupGetPointSize()662 GLUPfloat glupGetPointSize() {
663 GEO_CHECK_GL();
664 return GLUP::current_context_->uniform_state().point_size.get();
665 }
666
glupSetMeshWidth(GLUPint width)667 void glupSetMeshWidth(GLUPint width) {
668 GEO_CHECK_GL();
669 GLUP::current_context_->uniform_state().mesh_width.set(GLfloat(width));
670 }
671
glupGetMeshWidth()672 GLUPint glupGetMeshWidth() {
673 GEO_CHECK_GL();
674 return GLUPint(GLUP::current_context_->uniform_state().mesh_width.get());
675 }
676
glupSetCellsShrink(GLUPfloat x)677 void glupSetCellsShrink(GLUPfloat x) {
678 GEO_CHECK_GL();
679 x = std::min(x, 1.0f);
680 x = std::max(x, 0.0f);
681 GLUP::current_context_->uniform_state().cells_shrink.set(x);
682 }
683
glupGetCellsShrink()684 GLUPfloat glupGetCellsShrink() {
685 GEO_CHECK_GL();
686 return GLUP::current_context_->uniform_state().cells_shrink.get();
687 }
688
glupSetAlphaThreshold(GLUPfloat x)689 void glupSetAlphaThreshold(GLUPfloat x) {
690 GEO_CHECK_GL();
691 GLUP::current_context_->uniform_state().alpha_threshold.set(x);
692 }
693
glupGetAlphaThreshold()694 GLUPfloat glupGetAlphaThreshold() {
695 GEO_CHECK_GL();
696 return GLUP::current_context_->uniform_state().alpha_threshold.get();
697 }
698
glupSetSpecular(GLUPfloat x)699 void glupSetSpecular(GLUPfloat x) {
700 GEO_CHECK_GL();
701 GLUP::current_context_->uniform_state().specular.set(x);
702 }
703
glupGetSpecular()704 GLUPfloat glupGetSpecular() {
705 GEO_CHECK_GL();
706 return GLUP::current_context_->uniform_state().specular.get();
707 }
708
709
710 /****************** Picking ******************************/
711
glupPickingMode(GLUPpickingMode mode)712 void glupPickingMode(GLUPpickingMode mode) {
713 GEO_CHECK_GL();
714 GLUP::current_context_->uniform_state().picking_mode.set(mode);
715 }
716
glupGetPickingMode()717 GLUPpickingMode glupGetPickingMode() {
718 GEO_CHECK_GL();
719 return GLUPpickingMode(
720 GLUP::current_context_->uniform_state().picking_mode.get()
721 );
722 }
723
glupPickingId(GLUPuint64 id)724 void glupPickingId(GLUPuint64 id) {
725 // TODO: uint64
726 GEO_CHECK_GL();
727 GLUP::current_context_->uniform_state().picking_id.set(GLint(id));
728 }
729
glupGetPickingId()730 GLUPuint64 glupGetPickingId() {
731 // TODO: uint64
732 GEO_CHECK_GL();
733 return GLUPuint64(
734 GLUP::current_context_->uniform_state().picking_id.get()
735 );
736 }
737
glupBasePickingId(GLUPuint64 id)738 void glupBasePickingId(GLUPuint64 id) {
739 // TODO: uint64
740 GEO_CHECK_GL();
741 GLUP::current_context_->uniform_state().base_picking_id.set(GLint(id));
742 }
743
glupGetBasePickingId()744 GLUPuint64 glupGetBasePickingId() {
745 // TODO: uint64
746 GEO_CHECK_GL();
747 return GLUPuint64(
748 GLUP::current_context_->uniform_state().base_picking_id.get()
749 );
750 }
751
752 /****************** Clipping ******************************/
753
glupClipMode(GLUPclipMode mode)754 void glupClipMode(GLUPclipMode mode) {
755 GEO_CHECK_GL();
756 GLUP::current_context_->uniform_state().clipping_mode.set(mode);
757 }
758
glupGetClipMode()759 GLUPclipMode glupGetClipMode() {
760 GEO_CHECK_GL();
761 return GLUPclipMode(
762 GLUP::current_context_->uniform_state().clipping_mode.get()
763 );
764 }
765
glupClipPlane(const GLUPdouble * eqn_in)766 void glupClipPlane(const GLUPdouble* eqn_in) {
767 GEO_CHECK_GL();
768
769 const GLfloat* modelview =
770 GLUP::current_context_->get_matrix(GLUP_MODELVIEW_MATRIX);
771 GLfloat modelview_invert[16];
772 if(!GLUP::invert_matrix(modelview_invert,modelview)) {
773 GEO::Logger::warn("GLUP") << "Singular ModelView matrix"
774 << std::endl;
775 GLUP::show_matrix(modelview);
776 }
777 GLfloat* state_world_clip_plane =
778 GLUP::current_context_->uniform_state().world_clip_plane.get_pointer();
779 GLfloat* state_clip_plane =
780 GLUP::current_context_->uniform_state().clip_plane.get_pointer();
781 for(GEO::index_t i=0; i<4; ++i) {
782 state_world_clip_plane[i] = float(eqn_in[i]);
783 }
784 GLUP::mult_matrix_vector(
785 state_clip_plane,modelview_invert,state_world_clip_plane
786 );
787 // TODO? clip_clip_plane update ?
788 }
789
glupGetClipPlane(GLUPdouble * eqn)790 void glupGetClipPlane(GLUPdouble* eqn) {
791 GEO_CHECK_GL();
792
793 const GLfloat* ptr =
794 GLUP::current_context_->uniform_state().clip_plane.get_pointer();
795 eqn[0] = GLdouble(ptr[0]);
796 eqn[1] = GLdouble(ptr[1]);
797 eqn[2] = GLdouble(ptr[2]);
798 eqn[3] = GLdouble(ptr[3]);
799 }
800
801 /******************* Matrices ***************************/
802
803
glupMatrixMode(GLUPmatrix matrix)804 void glupMatrixMode(GLUPmatrix matrix) {
805 GEO_CHECK_GL();
806 GLUP::current_context_->set_matrix_mode(matrix);
807 }
808
glupGetMatrixMode()809 GLUPmatrix glupGetMatrixMode() {
810 GEO_CHECK_GL();
811 return GLUP::current_context_->get_matrix_mode();
812 }
813
glupPushMatrix()814 void glupPushMatrix() {
815 GEO_CHECK_GL();
816 GLUP::current_context_->push_matrix();
817 }
818
glupPopMatrix()819 void glupPopMatrix() {
820 GEO_CHECK_GL();
821 GLUP::current_context_->pop_matrix();
822 }
823
glupGetMatrixdv(GLUPmatrix matrix,GLUPdouble * ptr)824 void glupGetMatrixdv(GLUPmatrix matrix, GLUPdouble* ptr) {
825 GEO_CHECK_GL();
826 for(GEO::index_t i=0; i<16; ++i) {
827 ptr[i] = GLUPdouble(
828 GLUP::current_context_->get_matrix(matrix)[i]
829 );
830 }
831 }
832
glupGetMatrixfv(GLUPmatrix matrix,GLUPfloat * ptr)833 void glupGetMatrixfv(GLUPmatrix matrix, GLUPfloat* ptr) {
834 GEO_CHECK_GL();
835 for(GEO::index_t i=0; i<16; ++i) {
836 GLUP::copy_vector(
837 ptr, GLUP::current_context_->get_matrix(matrix), 16
838 );
839 }
840 }
841
glupLoadIdentity()842 void glupLoadIdentity() {
843 GEO_CHECK_GL();
844 GLUP::current_context_->load_identity();
845 }
846
glupLoadMatrixf(const GLUPfloat * M)847 void glupLoadMatrixf(const GLUPfloat* M) {
848 GEO_CHECK_GL();
849 GLUP::current_context_->load_matrix(M);
850 }
851
glupLoadMatrixd(const GLUPdouble * M)852 void glupLoadMatrixd(const GLUPdouble* M) {
853 GEO_CHECK_GL();
854 GLfloat Mf[16];
855 for(GEO::index_t i=0; i<16; ++i) {
856 Mf[i] = GLfloat(M[i]);
857 }
858 glupLoadMatrixf(Mf);
859 }
860
glupMultMatrixf(const GLUPfloat * M)861 void glupMultMatrixf(const GLUPfloat* M) {
862 GEO_CHECK_GL();
863 GLUP::current_context_->mult_matrix(M);
864 }
865
glupMultMatrixd(const GLUPdouble * M)866 void glupMultMatrixd(const GLUPdouble* M) {
867 GEO_CHECK_GL();
868 GLfloat Mf[16];
869 for(GEO::index_t i=0; i<16; ++i) {
870 Mf[i] = GLfloat(M[i]);
871 }
872 glupMultMatrixf(Mf);
873 }
874
glupTranslatef(GLUPfloat x,GLUPfloat y,GLUPfloat z)875 void glupTranslatef(GLUPfloat x, GLUPfloat y, GLUPfloat z) {
876 GEO_CHECK_GL();
877
878 GLfloat M[16];
879
880 M[4*0+0] = 1.0f;
881 M[4*0+1] = 0.0f;
882 M[4*0+2] = 0.0f;
883 M[4*0+3] = x;
884
885 M[4*1+0] = 0.0f;
886 M[4*1+1] = 1.0f;
887 M[4*1+2] = 0.0f;
888 M[4*1+3] = y;
889
890 M[4*2+0] = 0.0f;
891 M[4*2+1] = 0.0f;
892 M[4*2+2] = 1.0f;
893 M[4*2+3] = z;
894
895 M[4*3+0] = 0.0f;
896 M[4*3+1] = 0.0f;
897 M[4*3+2] = 0.0f;
898 M[4*3+3] = 1.0f;
899
900 GLUP::transpose_matrix(M);
901
902 glupMultMatrixf(M);
903 }
904
glupTranslated(GLUPdouble x,GLUPdouble y,GLUPdouble z)905 void glupTranslated(GLUPdouble x, GLUPdouble y, GLUPdouble z) {
906 GEO_CHECK_GL();
907
908 glupTranslatef(GLfloat(x), GLfloat(y), GLfloat(z));
909 }
910
glupScalef(GLUPfloat sx,GLUPfloat sy,GLUPfloat sz)911 void glupScalef(GLUPfloat sx, GLUPfloat sy, GLUPfloat sz) {
912 GEO_CHECK_GL();
913
914 GLfloat M[16];
915
916 M[4*0+0] = sx;
917 M[4*0+1] = 0.0f;
918 M[4*0+2] = 0.0f;
919 M[4*0+3] = 0.0f;
920
921 M[4*1+0] = 0.0f;
922 M[4*1+1] = sy;
923 M[4*1+2] = 0.0f;
924 M[4*1+3] = 0.0f;
925
926 M[4*2+0] = 0.0f;
927 M[4*2+1] = 0.0f;
928 M[4*2+2] = sz;
929 M[4*2+3] = 0.0f;
930
931 M[4*3+0] = 0.0f;
932 M[4*3+1] = 0.0f;
933 M[4*3+2] = 0.0f;
934 M[4*3+3] = 1.0f;
935
936 glupMultMatrixf(M);
937 }
938
glupScaled(GLUPdouble sx,GLUPdouble sy,GLUPdouble sz)939 void glupScaled(GLUPdouble sx, GLUPdouble sy, GLUPdouble sz) {
940 GEO_CHECK_GL();
941
942 glupScalef(GLfloat(sx), GLfloat(sy), GLfloat(sz));
943 }
944
glupRotatef(GLUPfloat angle,GLUPfloat x,GLUPfloat y,GLUPfloat z)945 void glupRotatef(
946 GLUPfloat angle, GLUPfloat x, GLUPfloat y, GLUPfloat z
947 ) {
948 GEO_CHECK_GL();
949
950 GLUPfloat l = 1.0f / ::sqrtf(x*x+y*y+z*z);
951 x *= l;
952 y *= l;
953 z *= l;
954 GLUPfloat s = ::sinf(angle * GLUPfloat(M_PI) / 180.0f);
955 GLUPfloat c = ::cosf(angle * GLUPfloat(M_PI) / 180.0f);
956 GLUPfloat M[16];
957
958 M[4*0+0] = x*x*(1.0f-c)+c;
959 M[4*0+1] = x*y*(1.0f-c)-z*s;
960 M[4*0+2] = x*z*(1.0f-c)+y*s;
961 M[4*0+3] = 0.0f;
962
963 M[4*1+0] = y*x*(1.0f-c)+z*s;
964 M[4*1+1] = y*y*(1.0f-c)+c;
965 M[4*1+2] = y*z*(1.0f-c)-x*s;
966 M[4*1+3] = 0.0f;
967
968 M[4*2+0] = z*x*(1.0f-c)-y*s;
969 M[4*2+1] = z*y*(1.0f-c)+x*s;
970 M[4*2+2] = z*z*(1.0f-c)+c;
971 M[4*2+3] = 0.0f;
972
973 M[4*3+0] = 0.0f;
974 M[4*3+1] = 0.0f;
975 M[4*3+2] = 0.0f;
976 M[4*3+3] = 1.0f;
977
978 GLUP::transpose_matrix(M);
979
980 glupMultMatrixf(M);
981 }
982
glupRotated(GLUPdouble angle,GLUPdouble x,GLUPdouble y,GLUPdouble z)983 void glupRotated(
984 GLUPdouble angle, GLUPdouble x, GLUPdouble y, GLUPdouble z
985 ) {
986 GEO_CHECK_GL();
987
988 glupRotatef(GLfloat(angle), GLfloat(x), GLfloat(y), GLfloat(z));
989 }
990
991
glupOrtho(GLUPdouble left,GLUPdouble right,GLUPdouble bottom,GLUPdouble top,GLUPdouble nearVal,GLUPdouble farVal)992 void glupOrtho(
993 GLUPdouble left, GLUPdouble right,
994 GLUPdouble bottom, GLUPdouble top,
995 GLUPdouble nearVal, GLUPdouble farVal
996 ) {
997 GEO_CHECK_GL();
998
999 GLfloat M[16];
1000
1001 GLdouble tx = -(right+left)/(right-left);
1002 GLdouble ty = -(top+bottom)/(top-bottom);
1003 GLdouble tz = -(farVal+nearVal)/(farVal-nearVal);
1004
1005 M[4*0+0] = GLfloat(2.0 / (right-left));
1006 M[4*0+1] = 0.0f;
1007 M[4*0+2] = 0.0f;
1008 M[4*0+3] = GLfloat(tx);
1009
1010 M[4*1+0] = 0.0f;
1011 M[4*1+1] = GLfloat(2.0 / (top-bottom));
1012 M[4*1+2] = 0.0f;
1013 M[4*1+3] = GLfloat(ty);
1014
1015 M[4*2+0] = 0.0f;
1016 M[4*2+1] = 0.0f;
1017 M[4*2+2] = GLfloat(-2.0 / (farVal - nearVal));
1018 M[4*2+3] = GLfloat(tz);
1019
1020 M[4*3+0] = 0.0f;
1021 M[4*3+1] = 0.0f;
1022 M[4*3+2] = 0.0f;
1023 M[4*3+3] = 1.0f;
1024
1025 GLUP::transpose_matrix(M);
1026 glupMultMatrixf(M);
1027 }
1028
glupOrtho2D(GLUPdouble left,GLUPdouble right,GLUPdouble bottom,GLUPdouble top)1029 void glupOrtho2D(
1030 GLUPdouble left, GLUPdouble right, GLUPdouble bottom, GLUPdouble top
1031 ) {
1032 GEO_CHECK_GL();
1033
1034 glupOrtho(left, right, bottom, top, -1.0, 1.0);
1035 }
1036
glupFrustum(GLUPdouble left,GLUPdouble right,GLUPdouble bottom,GLUPdouble top,GLUPdouble nearVal,GLUPdouble farVal)1037 void glupFrustum(
1038 GLUPdouble left, GLUPdouble right,
1039 GLUPdouble bottom, GLUPdouble top,
1040 GLUPdouble nearVal, GLUPdouble farVal
1041 ) {
1042 GEO_CHECK_GL();
1043
1044 GLfloat M[16];
1045
1046 GLdouble A = (right + left) / (right - left);
1047 GLdouble B = (top + bottom) / (top - bottom);
1048 GLdouble C = -(farVal + nearVal) / (farVal - nearVal);
1049 GLdouble D = -2.0*farVal*nearVal / (farVal - nearVal);
1050
1051 M[4*0+0] = GLfloat(2.0 * nearVal / (right - left));
1052 M[4*0+1] = 0.0f;
1053 M[4*0+2] = GLfloat(A);
1054 M[4*0+3] = 0.0f;
1055
1056 M[4*1+0] = 0.0f;
1057 M[4*1+1] = GLfloat(2.0 * nearVal / (top - bottom));
1058 M[4*1+2] = GLfloat(B);
1059 M[4*1+3] = 0.0f;
1060
1061 M[4*2+0] = 0.0f;
1062 M[4*2+1] = 0.0f;
1063 M[4*2+2] = GLfloat(C);
1064 M[4*2+3] = GLfloat(D);
1065
1066 M[4*3+0] = 0.0f;
1067 M[4*3+1] = 0.0f;
1068 M[4*3+2] = -1.0f;
1069 M[4*3+3] = 0.0f;
1070
1071 GLUP::transpose_matrix(M);
1072 glupMultMatrixf(M);
1073 }
1074
glupPerspective(GLUPdouble fovy,GLUPdouble aspect,GLUPdouble zNear,GLUPdouble zFar)1075 void glupPerspective(
1076 GLUPdouble fovy, GLUPdouble aspect,
1077 GLUPdouble zNear, GLUPdouble zFar
1078 ) {
1079 GEO_CHECK_GL();
1080
1081 GLfloat M[16];
1082
1083 double f = 1.0 / tan(fovy * M_PI / 180.0);
1084
1085 M[4*0+0] = GLfloat(f / aspect);
1086 M[4*0+1] = 0.0f;
1087 M[4*0+2] = 0.0f;
1088 M[4*0+3] = 0.0f;
1089
1090 M[4*1+0] = 0.0f;
1091 M[4*1+1] = GLfloat(f);
1092 M[4*1+2] = 0.0f;
1093 M[4*1+3] = 0.0f;
1094
1095 M[4*2+0] = 0.0f;
1096 M[4*2+1] = 0.0f;
1097 M[4*2+2] = GLfloat((zFar+zNear)/(zNear-zFar));
1098 M[4*2+3] = GLfloat(2.0*zFar*zNear/(zNear-zFar));
1099
1100 M[4*3+0] = 0.0f;
1101 M[4*3+1] = 0.0f;
1102 M[4*3+2] = -1.0f;
1103 M[4*3+3] = 0.0f;
1104
1105 GLUP::transpose_matrix(M);
1106 glupMultMatrixf(M);
1107 }
1108
glupProject(GLUPdouble objx,GLUPdouble objy,GLUPdouble objz,const GLUPdouble modelMatrix[16],const GLUPdouble projMatrix[16],const GLUPint viewport[4],GLUPdouble * winx,GLUPdouble * winy,GLUPdouble * winz)1109 GLUPint glupProject(
1110 GLUPdouble objx, GLUPdouble objy, GLUPdouble objz,
1111 const GLUPdouble modelMatrix[16],
1112 const GLUPdouble projMatrix[16],
1113 const GLUPint viewport[4],
1114 GLUPdouble* winx, GLUPdouble* winy, GLUPdouble* winz
1115 ) {
1116 GEO_CHECK_GL();
1117
1118 double in[4];
1119 double out[4];
1120
1121 in[0]=objx;
1122 in[1]=objy;
1123 in[2]=objz;
1124 in[3]=1.0;
1125
1126 GLUP::mult_transpose_matrix_vector(out, modelMatrix, in);
1127 GLUP::mult_transpose_matrix_vector(in, projMatrix, out);
1128
1129 if (in[3] == 0.0) {
1130 return(GL_FALSE);
1131 }
1132 in[0] /= in[3];
1133 in[1] /= in[3];
1134 in[2] /= in[3];
1135
1136 // Map x, y and z to range 0-1 */
1137 in[0] = in[0] * 0.5 + 0.5;
1138 in[1] = in[1] * 0.5 + 0.5;
1139 in[2] = in[2] * 0.5 + 0.5;
1140
1141 // Map x,y to viewport
1142 in[0] = in[0] * viewport[2] + viewport[0];
1143 in[1] = in[1] * viewport[3] + viewport[1];
1144
1145 *winx=in[0];
1146 *winy=in[1];
1147 *winz=in[2];
1148 return(GL_TRUE);
1149 }
1150
glupUnProject(GLUPdouble winx,GLUPdouble winy,GLUPdouble winz,const GLUPdouble modelMatrix[16],const GLUPdouble projMatrix[16],const GLUPint viewport[4],GLUPdouble * objx,GLUPdouble * objy,GLUPdouble * objz)1151 GLUPboolean glupUnProject(
1152 GLUPdouble winx, GLUPdouble winy, GLUPdouble winz,
1153 const GLUPdouble modelMatrix[16],
1154 const GLUPdouble projMatrix[16],
1155 const GLUPint viewport[4],
1156 GLUPdouble *objx, GLUPdouble *objy, GLUPdouble *objz
1157 ) {
1158 GEO_CHECK_GL();
1159
1160 double modelviewproject[16];
1161 double modelviewproject_inv[16];
1162 GLUP::mult_matrices(modelviewproject, modelMatrix, projMatrix);
1163 if(!GLUP::invert_matrix(modelviewproject_inv, modelviewproject)) {
1164 return GL_FALSE;
1165 }
1166
1167 double in[4];
1168 in[0] = winx;
1169 in[1] = winy;
1170 in[2] = winz;
1171 in[3] = 1.0;
1172
1173 // Invert viewport transform
1174 in[0] = (in[0] - double(viewport[0])) / double(viewport[2]);
1175 in[1] = (in[1] - double(viewport[1])) / double(viewport[3]);
1176
1177 // Map to [-1, 1]
1178 in[0] = in[0] * 2.0 - 1.0;
1179 in[1] = in[1] * 2.0 - 1.0;
1180 in[2] = in[2] * 2.0 - 1.0;
1181
1182 double out[4];
1183 GLUP::mult_transpose_matrix_vector(out, modelviewproject_inv, in);
1184
1185 if(out[3] == 0.0) {
1186 return GL_FALSE;
1187 }
1188
1189 *objx = out[0] / out[3];
1190 *objy = out[1] / out[3];
1191 *objz = out[2] / out[3];
1192
1193 return GL_TRUE;
1194 }
1195
glupInvertMatrixfv(GLUPfloat Minvert[16],const GLUPfloat M[16])1196 GLUPboolean glupInvertMatrixfv(
1197 GLUPfloat Minvert[16],
1198 const GLUPfloat M[16]
1199 ) {
1200 GEO_CHECK_GL();
1201
1202 return GLUP::invert_matrix(Minvert, M);
1203 }
1204
glupInvertMatrixdv(GLUPdouble Minvert[16],const GLUPdouble M[16])1205 GLUPboolean glupInvertMatrixdv(
1206 GLUPdouble Minvert[16],
1207 const GLUPdouble M[16]
1208 ) {
1209 GEO_CHECK_GL();
1210
1211 return GLUP::invert_matrix(Minvert, M);
1212 }
1213
1214
1215
1216 /******************* Drawing ***************************/
1217
glupDrawArrays(GLUPprimitive primitive,GLUPint first,GLUPsizei count)1218 void glupDrawArrays(
1219 GLUPprimitive primitive, GLUPint first, GLUPsizei count
1220 ) {
1221 GEO_CHECK_GL();
1222
1223 GLUP::current_context_->draw_arrays(
1224 primitive, first, count
1225 );
1226
1227 GEO_CHECK_GL();
1228 }
1229
glupDrawElements(GLUPprimitive primitive,GLUPsizei count,GLUPenum type,const GLUPvoid * indices)1230 void glupDrawElements(
1231 GLUPprimitive primitive, GLUPsizei count,
1232 GLUPenum type, const GLUPvoid* indices
1233 ) {
1234 GEO_CHECK_GL();
1235
1236 GLUP::current_context_->draw_elements(
1237 primitive, count, type, indices
1238 );
1239
1240 GEO_CHECK_GL();
1241 }
1242
glupBegin(GLUPprimitive primitive)1243 void glupBegin(GLUPprimitive primitive) {
1244 GEO_CHECK_GL();
1245 GLUP::current_context_->begin(primitive);
1246 GEO_CHECK_GL();
1247 }
1248
glupEnd()1249 void glupEnd() {
1250 GEO_CHECK_GL();
1251 GLUP::current_context_->end();
1252 GEO_CHECK_GL();
1253 }
1254
glupVertex2fv(const GLUPfloat * xy)1255 void glupVertex2fv(const GLUPfloat* xy) {
1256 GEO_CHECK_GL();
1257 GLUP::current_context_->immediate_vertex(xy[0], xy[1]);
1258 }
1259
glupVertex3fv(const GLUPfloat * xyz)1260 void glupVertex3fv(const GLUPfloat* xyz) {
1261 GEO_CHECK_GL();
1262 GLUP::current_context_->immediate_vertex(xyz[0], xyz[1], xyz[2]);
1263 }
1264
glupVertex4fv(const GLUPfloat * xyzw)1265 void glupVertex4fv(const GLUPfloat* xyzw) {
1266 GEO_CHECK_GL();
1267 GLUP::current_context_->immediate_vertex(
1268 xyzw[0], xyzw[1], xyzw[2], xyzw[3]
1269 );
1270 }
1271
glupVertex2dv(const GLUPdouble * xy)1272 void glupVertex2dv(const GLUPdouble* xy) {
1273 GEO_CHECK_GL();
1274 GLUP::current_context_->immediate_vertex(
1275 GLfloat(xy[0]),
1276 GLfloat(xy[1])
1277 );
1278 }
1279
glupVertex3dv(const GLUPdouble * xyz)1280 void glupVertex3dv(const GLUPdouble* xyz) {
1281 GEO_CHECK_GL();
1282 GLUP::current_context_->immediate_vertex(
1283 GLfloat(xyz[0]),
1284 GLfloat(xyz[1]),
1285 GLfloat(xyz[2])
1286 );
1287 }
1288
glupVertex4dv(const GLUPdouble * xyzw)1289 void glupVertex4dv(const GLUPdouble* xyzw) {
1290 GEO_CHECK_GL();
1291 GLUP::current_context_->immediate_vertex(
1292 GLfloat(xyzw[0]),
1293 GLfloat(xyzw[1]),
1294 GLfloat(xyzw[2]),
1295 GLfloat(xyzw[3])
1296 );
1297 }
1298
glupVertex2f(GLUPfloat x,GLUPfloat y)1299 void glupVertex2f(GLUPfloat x, GLUPfloat y) {
1300 GEO_CHECK_GL();
1301 GLUP::current_context_->immediate_vertex(x,y);
1302 }
1303
glupVertex3f(GLUPfloat x,GLUPfloat y,GLUPfloat z)1304 void glupVertex3f(GLUPfloat x, GLUPfloat y, GLUPfloat z) {
1305 GEO_CHECK_GL();
1306 GLUP::current_context_->immediate_vertex(x,y,z);
1307 }
1308
glupVertex4f(GLUPfloat x,GLUPfloat y,GLUPfloat z,GLUPfloat w)1309 void glupVertex4f(GLUPfloat x, GLUPfloat y, GLUPfloat z, GLUPfloat w) {
1310 GEO_CHECK_GL();
1311 GLUP::current_context_->immediate_vertex(x,y,z,w);
1312 }
1313
glupVertex2d(GLUPdouble x,GLUPdouble y)1314 void glupVertex2d(GLUPdouble x, GLUPdouble y) {
1315 GEO_CHECK_GL();
1316 GLUP::current_context_->immediate_vertex(
1317 GLfloat(x),
1318 GLfloat(y)
1319 );
1320 }
1321
glupVertex3d(GLUPdouble x,GLUPdouble y,GLUPdouble z)1322 void glupVertex3d(GLUPdouble x, GLUPdouble y, GLUPdouble z) {
1323 GEO_CHECK_GL();
1324 GLUP::current_context_->immediate_vertex(
1325 GLfloat(x),
1326 GLfloat(y),
1327 GLfloat(z)
1328 );
1329 }
1330
glupVertex4d(GLUPdouble x,GLUPdouble y,GLUPdouble z,GLUPdouble w)1331 void glupVertex4d(GLUPdouble x, GLUPdouble y, GLUPdouble z, GLUPdouble w) {
1332 GEO_CHECK_GL();
1333 GLUP::current_context_->immediate_vertex(
1334 GLfloat(x),
1335 GLfloat(y),
1336 GLfloat(z),
1337 GLfloat(w)
1338 );
1339 }
1340
glupColor3fv(const GLUPfloat * rgb)1341 void glupColor3fv(const GLUPfloat* rgb) {
1342 GEO_CHECK_GL();
1343 GLUP::current_context_->immediate_color(rgb[0], rgb[1], rgb[2]);
1344 }
1345
glupColor4fv(const GLUPfloat * rgba)1346 void glupColor4fv(const GLUPfloat* rgba) {
1347 GEO_CHECK_GL();
1348 GLUP::current_context_->immediate_color(rgba[0], rgba[1], rgba[2], rgba[3]);
1349 }
1350
glupColor3dv(const GLUPdouble * rgb)1351 void glupColor3dv(const GLUPdouble* rgb) {
1352 GEO_CHECK_GL();
1353 GLUP::current_context_->immediate_color(
1354 GLfloat(rgb[0]),
1355 GLfloat(rgb[1]),
1356 GLfloat(rgb[2])
1357 );
1358 }
1359
glupColor4dv(const GLUPdouble * rgba)1360 void glupColor4dv(const GLUPdouble* rgba) {
1361 GEO_CHECK_GL();
1362 GLUP::current_context_->immediate_color(
1363 GLfloat(rgba[0]),
1364 GLfloat(rgba[1]),
1365 GLfloat(rgba[2]),
1366 GLfloat(rgba[3])
1367 );
1368 }
1369
glupColor3f(GLUPfloat r,GLUPfloat g,GLUPfloat b)1370 void glupColor3f(GLUPfloat r, GLUPfloat g, GLUPfloat b) {
1371 GEO_CHECK_GL();
1372 GLUP::current_context_->immediate_color(r, g, b);
1373 }
1374
glupColor4f(GLUPfloat r,GLUPfloat g,GLUPfloat b,GLUPfloat a)1375 void glupColor4f(GLUPfloat r, GLUPfloat g, GLUPfloat b, GLUPfloat a) {
1376 GEO_CHECK_GL();
1377 GLUP::current_context_->immediate_color(r, g, b, a);
1378 }
1379
glupColor3d(GLUPdouble r,GLUPdouble g,GLUPdouble b)1380 void glupColor3d(GLUPdouble r, GLUPdouble g, GLUPdouble b) {
1381 GEO_CHECK_GL();
1382 GLUP::current_context_->immediate_color(
1383 GLfloat(r),
1384 GLfloat(g),
1385 GLfloat(b)
1386 );
1387 }
1388
glupColor4d(GLUPdouble r,GLUPdouble g,GLUPdouble b,GLUPdouble a)1389 void glupColor4d(GLUPdouble r, GLUPdouble g, GLUPdouble b, GLUPdouble a) {
1390 GEO_CHECK_GL();
1391 GLUP::current_context_->immediate_color(
1392 GLfloat(r),
1393 GLfloat(g),
1394 GLfloat(b),
1395 GLfloat(a)
1396 );
1397 }
1398
glupTexCoord2fv(const GLUPfloat * st)1399 void glupTexCoord2fv(const GLUPfloat* st) {
1400 GEO_CHECK_GL();
1401 GLUP::current_context_->immediate_tex_coord(st[0], st[1]);
1402 }
1403
glupTexCoord3fv(const GLUPfloat * stu)1404 void glupTexCoord3fv(const GLUPfloat* stu) {
1405 GEO_CHECK_GL();
1406 GLUP::current_context_->immediate_tex_coord(stu[0], stu[1], stu[2]);
1407 }
1408
glupTexCoord4fv(const GLUPfloat * stuv)1409 void glupTexCoord4fv(const GLUPfloat* stuv) {
1410 GEO_CHECK_GL();
1411 GLUP::current_context_->immediate_tex_coord(
1412 stuv[0], stuv[1], stuv[2], stuv[3]
1413 );
1414 }
1415
glupTexCoord2dv(const GLUPdouble * st)1416 void glupTexCoord2dv(const GLUPdouble* st) {
1417 GEO_CHECK_GL();
1418 GLUP::current_context_->immediate_tex_coord(
1419 GLfloat(st[0]),
1420 GLfloat(st[1])
1421 );
1422 }
1423
glupTexCoord3dv(const GLUPdouble * stu)1424 void glupTexCoord3dv(const GLUPdouble* stu) {
1425 GEO_CHECK_GL();
1426 GLUP::current_context_->immediate_tex_coord(
1427 GLfloat(stu[0]),
1428 GLfloat(stu[1]),
1429 GLfloat(stu[2])
1430 );
1431 }
1432
glupTexCoord4dv(const GLUPdouble * stuv)1433 void glupTexCoord4dv(const GLUPdouble* stuv) {
1434 GEO_CHECK_GL();
1435 GLUP::current_context_->immediate_tex_coord(
1436 GLfloat(stuv[0]),
1437 GLfloat(stuv[1]),
1438 GLfloat(stuv[2]),
1439 GLfloat(stuv[3])
1440 );
1441 }
1442
glupTexCoord1f(GLUPfloat s)1443 void glupTexCoord1f(GLUPfloat s) {
1444 GEO_CHECK_GL();
1445 GLUP::current_context_->immediate_tex_coord(s);
1446 }
1447
glupTexCoord2f(GLUPfloat s,GLUPfloat t)1448 void glupTexCoord2f(GLUPfloat s, GLUPfloat t) {
1449 GEO_CHECK_GL();
1450 GLUP::current_context_->immediate_tex_coord(s,t);
1451 }
1452
glupTexCoord3f(GLUPfloat s,GLUPfloat t,GLUPfloat u)1453 void glupTexCoord3f(GLUPfloat s, GLUPfloat t, GLUPfloat u) {
1454 GEO_CHECK_GL();
1455 GLUP::current_context_->immediate_tex_coord(s,t,u);
1456 }
1457
glupTexCoord4f(GLUPfloat s,GLUPfloat t,GLUPfloat u,GLUPfloat v)1458 void glupTexCoord4f(GLUPfloat s, GLUPfloat t, GLUPfloat u, GLUPfloat v) {
1459 GEO_CHECK_GL();
1460 GLUP::current_context_->immediate_tex_coord(s,t,u,v);
1461 }
1462
glupTexCoord1d(GLUPdouble s)1463 void glupTexCoord1d(GLUPdouble s) {
1464 GEO_CHECK_GL();
1465 GLUP::current_context_->immediate_tex_coord(
1466 GLfloat(s)
1467 );
1468 }
1469
glupTexCoord2d(GLUPdouble s,GLUPdouble t)1470 void glupTexCoord2d(GLUPdouble s, GLUPdouble t) {
1471 GEO_CHECK_GL();
1472 GLUP::current_context_->immediate_tex_coord(
1473 GLfloat(s),
1474 GLfloat(t)
1475 );
1476 }
1477
glupTexCoord3d(GLUPdouble s,GLUPdouble t,GLUPdouble u)1478 void glupTexCoord3d(GLUPdouble s, GLUPdouble t, GLUPdouble u) {
1479 GEO_CHECK_GL();
1480 GLUP::current_context_->immediate_tex_coord(
1481 GLfloat(s),
1482 GLfloat(t),
1483 GLfloat(u)
1484 );
1485 }
1486
glupTexCoord4d(GLUPdouble s,GLUPdouble t,GLUPdouble u,GLUPdouble v)1487 void glupTexCoord4d(GLUPdouble s, GLUPdouble t, GLUPdouble u, GLUPdouble v) {
1488 GEO_CHECK_GL();
1489 GLUP::current_context_->immediate_tex_coord(
1490 GLfloat(s),
1491 GLfloat(t),
1492 GLfloat(u),
1493 GLfloat(v)
1494 );
1495 }
1496
1497
glupNormal3fv(GLUPfloat * xyz)1498 void glupNormal3fv(GLUPfloat* xyz) {
1499 GEO_CHECK_GL();
1500 GLUP::current_context_->immediate_normal(
1501 xyz[0],xyz[1],xyz[2]
1502 );
1503 }
1504
glupNormal3f(GLUPfloat x,GLUPfloat y,GLUPfloat z)1505 void glupNormal3f(GLUPfloat x, GLUPfloat y, GLUPfloat z) {
1506 GEO_CHECK_GL();
1507 GLUP::current_context_->immediate_normal(
1508 x,y,z
1509 );
1510 }
1511
glupNormal3dv(GLUPdouble * xyz)1512 void glupNormal3dv(GLUPdouble* xyz) {
1513 GEO_CHECK_GL();
1514 GLUP::current_context_->immediate_normal(
1515 GLfloat(xyz[0]),
1516 GLfloat(xyz[1]),
1517 GLfloat(xyz[2])
1518 );
1519 }
1520
glupNormal3d(GLUPdouble x,GLUPdouble y,GLUPdouble z)1521 void glupNormal3d(GLUPdouble x, GLUPdouble y, GLUPdouble z) {
1522 GEO_CHECK_GL();
1523 GLUP::current_context_->immediate_normal(
1524 GLfloat(x),
1525 GLfloat(y),
1526 GLfloat(z)
1527 );
1528 }
1529
glupUseProgram(GLUPuint program)1530 void glupUseProgram(GLUPuint program) {
1531 GEO_CHECK_GL();
1532 GLUP::current_context_->set_user_program(program);
1533 }
1534
1535
1536
1537 /****************************************************************************/
1538
1539 namespace GLUP {
1540
1541 static GLUPuint vertex_array_binding = 0;
1542 static GLint max_vertex_attrib = 0;
1543
1544 /**
1545 * \brief If true, then GLUP uses its own implementation
1546 * of Vertex Array Object.
1547 * \details This is for instance required
1548 * when using GLUP with Emscripten, in a brower that does
1549 * not have the Vertex Array Object extension (see
1550 * Context_GLES.cpp)
1551 */
1552 bool vertex_array_emulate = false;
1553
1554 /**
1555 * \brief Stores the state of a vertex attribute
1556 * binding.
1557 * \details Used to implement emulated vertex array
1558 * objects.
1559 * \see VertexArrayObject.
1560 */
1561 class VertexAttribBinding {
1562
1563 public:
1564
1565 /**
1566 * \brief VertexAttribBinding constructor.
1567 */
VertexAttribBinding()1568 VertexAttribBinding() :
1569 enabled(GL_FALSE),
1570 size(0),
1571 type(GL_FLOAT),
1572 normalized(GL_FALSE),
1573 stride(0),
1574 pointer(nullptr),
1575 buffer_binding(0) {
1576 }
1577
1578 /**
1579 * \brief Copies the binding of a vertex attribute
1580 * from OpenGL state to this VertexAttribBinding.
1581 * \param[in] index the index of the attribute
1582 */
copy_from_GL(GLuint index)1583 void copy_from_GL(GLuint index) {
1584
1585 // From the spec, glGetVertexAttribiv is supposed
1586 // to return 4 values always, even if we are only
1587 // interested in the first one, I guess it is needed
1588 // to read in a buffer with enough space for 4 values.
1589 GLint buff[4];
1590
1591 glGetVertexAttribiv(
1592 index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, buff
1593 );
1594 enabled = buff[0];
1595
1596 // With some webbrowsers, querying a vertex attrib array
1597 // that is not enabled returns the default values instead
1598 // of the actual values.
1599 if(!enabled) {
1600 glEnableVertexAttribArray(index);
1601 }
1602
1603 glGetVertexAttribiv(
1604 index, GL_VERTEX_ATTRIB_ARRAY_SIZE, buff
1605 );
1606 size = buff[0];
1607
1608 glGetVertexAttribiv(
1609 index, GL_VERTEX_ATTRIB_ARRAY_TYPE, buff
1610 );
1611 type = buff[0];
1612
1613 glGetVertexAttribiv(
1614 index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, buff
1615 );
1616 normalized = buff[0];
1617
1618 glGetVertexAttribiv(
1619 index, GL_VERTEX_ATTRIB_ARRAY_STRIDE, buff
1620 );
1621 stride = buff[0];
1622
1623 glGetVertexAttribPointerv(
1624 index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &pointer
1625 );
1626
1627 glGetVertexAttribiv(
1628 index, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, buff
1629 );
1630 buffer_binding = buff[0];
1631
1632 if(!enabled) {
1633 glDisableVertexAttribArray(index);
1634 }
1635 }
1636
1637 /**
1638 * \brief Copies the binding stored in this VertexAttribBinding
1639 * into OpenGL.
1640 * \param[in] index the index of the attribute where the binding
1641 * should be copied.
1642 */
copy_to_GL(GLuint index)1643 void copy_to_GL(GLuint index) {
1644 if(enabled) {
1645 glEnableVertexAttribArray(index);
1646 } else {
1647 glDisableVertexAttribArray(index);
1648 }
1649 glBindBuffer(GL_ARRAY_BUFFER, GLuint(buffer_binding));
1650 if(buffer_binding != 0 || pointer != nullptr ) {
1651 glVertexAttribPointer(
1652 index, size, GLenum(type),
1653 GLboolean(normalized), GLsizei(stride), pointer
1654 );
1655 }
1656 }
1657
1658 /**
1659 * \brief Resets all the stored bindings to default
1660 * values.
1661 */
reset()1662 void reset() {
1663 enabled=GL_FALSE;
1664 size=0;
1665 type=GL_FLOAT;
1666 normalized=GL_FALSE;
1667 stride=0;
1668 pointer=nullptr;
1669 buffer_binding=0;
1670 }
1671
1672 private:
1673 GLint enabled;
1674 GLint size;
1675 GLint type;
1676 GLint normalized;
1677 GLint stride;
1678 GLvoid* pointer;
1679 GLint buffer_binding;
1680 };
1681
1682 /**
1683 * \brief Emulates vertex array objects if not supported
1684 * by OpenGL implementation.
1685 */
1686 class VertexArrayObject {
1687 public:
1688 /**
1689 * \brief The maximum number of vertex attributes
1690 * that we save in a VAO.
1691 * \details For GLUP, only 4 are needed. Can be
1692 * increased if need be.
1693 */
1694 enum {MAX_VERTEX_ATTRIB = 4};
1695
1696 /**
1697 * \brief VertexArrayObject constructor.
1698 */
VertexArrayObject()1699 VertexArrayObject() :
1700 element_array_buffer_binding_(0) {
1701 if(max_vertex_attrib == 0) {
1702 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attrib);
1703 max_vertex_attrib = std::min(
1704 max_vertex_attrib, GLint(MAX_VERTEX_ATTRIB)
1705 );
1706 }
1707 }
1708
1709 /**
1710 * \brief Binds this VertexArrayObject.
1711 * \details This copies the stored element array and vertex attribute
1712 * bindings to OpenGL.
1713 */
bind()1714 void bind() {
1715 glBindBuffer(
1716 GL_ELEMENT_ARRAY_BUFFER, GLuint(element_array_buffer_binding_)
1717 );
1718 for(GLint i=0; i<max_vertex_attrib; ++i) {
1719 attrib_binding_[i].copy_to_GL(GLuint(i));
1720 }
1721 }
1722
1723 /**
1724 * \brief Unbinds this VertexArrayObject.
1725 * \details This copies the currently bound element array and
1726 * vertex attribute bindings from OpenGL to this VertexArrayObject.
1727 */
unbind()1728 void unbind() {
1729 // Note: In Emscripten, glGetIntegerv() does not suffer from the
1730 // same bug as glGetVertexAttribiv(
1731 // ..., GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, ...
1732 // ), therefore there is no special case here.
1733 glGetIntegerv(
1734 GL_ELEMENT_ARRAY_BUFFER_BINDING,
1735 &element_array_buffer_binding_
1736 );
1737 for(GLint i=0; i<max_vertex_attrib; ++i) {
1738 attrib_binding_[i].copy_from_GL(GLuint(i));
1739 }
1740 }
1741
1742 /**
1743 * \brief Resets all the stored bindings to default
1744 * values.
1745 */
reset()1746 void reset() {
1747 element_array_buffer_binding_ = 0;
1748 for(GLint i=0; i<max_vertex_attrib; ++i) {
1749 attrib_binding_[i].reset();
1750 }
1751 }
1752
1753 private:
1754 VertexAttribBinding attrib_binding_[MAX_VERTEX_ATTRIB];
1755 GLint element_array_buffer_binding_;
1756 };
1757
1758
1759 /**
1760 * \brief Manages the emulated vertex array objects.
1761 */
1762 class VertexArrayObjectAllocator {
1763 public:
1764 /**
1765 * \brief VertexArrayObjectAllocator constructor.
1766 */
VertexArrayObjectAllocator()1767 VertexArrayObjectAllocator() {
1768 // Create the dummy slot 0.
1769 slots_.push_back(Slot());
1770 }
1771
1772 /**
1773 * \brief VertexArrayObjectAllocator destructor.
1774 */
~VertexArrayObjectAllocator()1775 ~VertexArrayObjectAllocator() {
1776 for(index_t i=0; i<slots_.size(); ++i) {
1777 if(slots_[i].VAO != nullptr) {
1778 delete slots_[i].VAO;
1779 slots_[i].VAO = nullptr;
1780 }
1781 }
1782 }
1783
1784 /**
1785 * \brief Creates a new vertex array object.
1786 * \return the index of the newly created vertex
1787 * array object.
1788 */
new_VAO()1789 index_t new_VAO() {
1790 index_t result = 0;
1791 if(first_free_ != 0) {
1792 result = first_free_;
1793 first_free_ = slots_[first_free_].next;
1794 slots_[result].VAO->reset();
1795 } else {
1796 slots_.push_back(Slot());
1797 result = index_t(slots_.size()-1);
1798 slots_[result].VAO = new VertexArrayObject();
1799 }
1800 return result;
1801 }
1802
1803 /**
1804 * \brief Deletes a vertex array object.
1805 * \details Vertex array objects are recycled internally.
1806 * \param[in] VAOindex the index of the vertex
1807 * array object to delete.
1808 */
delete_VAO(index_t VAOindex)1809 void delete_VAO(index_t VAOindex) {
1810 slots_[VAOindex].next = first_free_;
1811 first_free_ = VAOindex;
1812 }
1813
1814 /**
1815 * \brief Gets a vertex array object by index.
1816 * \param[in] VAOindex the index of the vertex array object.
1817 * \return a pointer to the vertex array object.
1818 */
get_VAO(index_t VAOindex)1819 VertexArrayObject* get_VAO(index_t VAOindex) {
1820 return slots_[VAOindex].VAO;
1821 }
1822
1823 private:
1824
1825 /**
1826 * \brief The information attached to each vertex
1827 * array object index.
1828 */
1829 struct Slot {
1830 /**
1831 * \brief Slot constructor.
1832 */
SlotGLUP::VertexArrayObjectAllocator::Slot1833 Slot() :
1834 VAO(nullptr), next(0) {
1835 }
1836
1837 /**
1838 * \brief A pointer to the internal representation.
1839 */
1840 VertexArrayObject* VAO;
1841
1842 /**
1843 * \brief The index of the next free element, used
1844 * to have constant-time allocation and deallocation.
1845 */
1846 index_t next;
1847 };
1848
1849 vector<Slot> slots_;
1850
1851 /**
1852 * \brief The head of the free list.
1853 */
1854 GLUPuint first_free_;
1855 };
1856
1857 static VertexArrayObjectAllocator VAO_allocator;
1858
1859 }
1860
1861 // TODO1: ArraysOES()/Arrays() switch based on OpenGL profile
1862 // (runtime) rather than GEO_OS_EMSCRIPTEN macro (compile-time)
1863
glupGenVertexArrays(GLUPsizei n,GLUPuint * arrays)1864 void glupGenVertexArrays(GLUPsizei n, GLUPuint* arrays) {
1865 if(GLUP::vertex_array_emulate) {
1866 for(GLUPsizei i=0; i<n; ++i) {
1867 arrays[i] = GLUP::VAO_allocator.new_VAO();
1868 }
1869
1870 } else {
1871 #ifdef GEO_OS_EMSCRIPTEN
1872 glGenVertexArraysOES(n, arrays);
1873 #else
1874 if(!glGenVertexArrays) {
1875 GLUP::vertex_array_emulate = true;
1876 glupGenVertexArrays(n,arrays);
1877 return;
1878 }
1879 glGenVertexArrays(n, arrays);
1880 #endif
1881 }
1882 }
1883
glupDeleteVertexArrays(GLUPsizei n,const GLUPuint * arrays)1884 void glupDeleteVertexArrays(GLUPsizei n, const GLUPuint *arrays) {
1885 if(GLUP::vertex_array_emulate) {
1886 for(GLUPsizei i=0; i<n; ++i) {
1887 GLUP::VAO_allocator.delete_VAO(arrays[i]);
1888 }
1889 } else {
1890 #if defined(GEO_OS_EMSCRIPTEN)
1891 glDeleteVertexArraysOES(n, arrays);
1892 #else
1893 if(!glDeleteVertexArrays) {
1894 GLUP::vertex_array_emulate = true;
1895 glupDeleteVertexArrays(n,arrays);
1896 return;
1897 }
1898 glDeleteVertexArrays(n, arrays);
1899 #endif
1900 }
1901 }
1902
glupBindVertexArray(GLUPuint array)1903 void glupBindVertexArray(GLUPuint array) {
1904 if(GLUP::vertex_array_emulate) {
1905 if(array != GLUP::vertex_array_binding) {
1906 if(GLUP::vertex_array_binding != 0) {
1907 GLUP::VAO_allocator.get_VAO(
1908 GLUP::vertex_array_binding
1909 )->unbind();
1910 }
1911 GLUP::vertex_array_binding = array;
1912 if(GLUP::vertex_array_binding != 0) {
1913 GLUP::VAO_allocator.get_VAO(
1914 GLUP::vertex_array_binding
1915 )->bind();
1916 }
1917 }
1918 } else {
1919 #if defined(GEO_OS_EMSCRIPTEN)
1920 glBindVertexArrayOES(array);
1921 #else
1922 if(!glBindVertexArray) {
1923 GLUP::vertex_array_emulate = true;
1924 glupBindVertexArray(array);
1925 return;
1926 }
1927 glBindVertexArray(array);
1928 #endif
1929 GLUP::vertex_array_binding = array;
1930 }
1931 }
1932
glupGetVertexArrayBinding()1933 GLUPuint glupGetVertexArrayBinding() {
1934 return GLUP::vertex_array_binding;
1935 }
1936
1937 /****************************************************************************/
1938