1 // Hyperbolic Rogue -- low-level OpenGL routines
2 // Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
3 
4 /** \file glhr.cpp
5  *  \brief low-level OpenGL routines
6  *
7  *  If CAP_SHADER is 0, OpenGL 1.0 is used.
8  *  If CAP_SHADER is 1, we are using GLSL shaders.
9  */
10 
11 #include "hyper.h"
12 namespace hr {
13 
14 EX bool detailed_shader = false;
15 
16 EX namespace glhr {
pointtogl(const hyperpoint & t)17 EX glvertex pointtogl(const hyperpoint& t) {
18   glvertex h;
19   h[0] = t[0]; h[1] = t[1]; h[2] = t[2];
20   if(SHDIM == 4) h[3] = (MDIM == 4) ? t[3] : 1;
21   return h;
22   }
23 
gltopoint(const glvertex & t)24 EX hyperpoint gltopoint(const glvertex& t) {
25   hyperpoint h;
26   h[0] = t[0]; h[1] = t[1]; h[2] = t[2];
27   if(SHDIM == 4 && MAXMDIM == 4) h[3] = t[3];
28   return h;
29   }
30 
31 #if CAP_SHADER
32 EX bool noshaders = false;
33 #endif
34 #if !CAP_SHADER
35 EX bool noshaders = true;
36 #endif
37 
38 #if HDR
makevertex(GLfloat x,GLfloat y,GLfloat z)39   inline glvertex makevertex(GLfloat x, GLfloat y, GLfloat z) {
40     #if SHDIM == 3
41     return make_array(x, y, z);
42     #else
43     return make_array<GLfloat>(x, y, z, 1);
44     #endif
45     }
46 #endif
47 
48 EX }
49 
50 #if CAP_GL
51 #ifndef DEBUG_GL
52 #define DEBUG_GL 0
53 #endif
54 
55 // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
56 
glError(const char * GLcall,const char * file,const int line)57 EX void glError(const char* GLcall, const char* file, const int line) {
58   GLenum errCode = glGetError();
59   if(errCode!=GL_NO_ERROR) {
60     println(hlog, format("OPENGL ERROR #%i: in file %s on line %i :: %s",errCode,file, line, GLcall));
61     }
62   }
63 
64 #if HDR
65 struct glwrap {
66   const char* msg;
67   int line;
68   void act(const char *when);
glwraphr::glwrap69   glwrap(const char *m, int l) : msg(m), line(l) { act("before"); }
~glwraphr::glwrap70   ~glwrap() { act("after"); }
71   };
72 #define GLWRAP glwrap w##__line(__FILE__, __LINE__)
73 #endif
74 
act(const char * when)75 void glwrap::act(const char *when) {
76   GLenum errCode = glGetError();
77   if(errCode!=GL_NO_ERROR) {
78     println(hlog, format("GL error %i %s: %s:%i", errCode, when, msg, line));
79     }
80   }
81 
82 #if HDR
83 #if CAP_SHADER && CAP_NOSHADER
84 #define WITHSHADER(x, y) if(glhr::noshaders) y else x
85 #else
86 #if CAP_NOSHADER
87 #define WITHSHADER(x, y) if(1) y
88 #else
89 #define WITHSHADER(x, y) if(1) x
90 #endif
91 #endif
92 #endif
93 
94 EX namespace glhr {
95 
to_glsl(ld x)96 EX string to_glsl(ld x) {
97   char buf[64];
98   snprintf(buf, 64, "float(%.10e)", x);
99   return buf;
100   }
101 
102 #if HDR
103 struct glmatrix {
104   GLfloat a[4][4];
operator []hr::glhr::glmatrix105   GLfloat* operator[] (int i) { return a[i]; }
operator []hr::glhr::glmatrix106   const GLfloat* operator[] (int i) const { return a[i]; }
as_arrayhr::glhr::glmatrix107   GLfloat* as_array() { return a[0]; }
as_arrayhr::glhr::glmatrix108   const GLfloat* as_array() const { return a[0]; }
as_stdarrayhr::glhr::glmatrix109   array<float, 16>& as_stdarray() { return *(array<float, 16>*)this; }
as_stdarrayhr::glhr::glmatrix110   const array<float, 16>& as_stdarray() const { return *(array<float, 16>*)this; }
111   };
112 
113   struct colored_vertex {
114     glvertex coords;
115     glvec4 color;
colored_vertexhr::glhr::colored_vertex116     colored_vertex() {}
colored_vertexhr::glhr::colored_vertex117     colored_vertex(GLfloat x, GLfloat y, GLfloat r, GLfloat g, GLfloat b) {
118       coords[0] = x;
119       coords[1] = y;
120       coords[2] = 0;
121       coords[3] = 1;
122       color[0] = r;
123       color[1] = g;
124       color[2] = b;
125       color[3] = 1;
126       }
colored_vertexhr::glhr::colored_vertex127     colored_vertex(hyperpoint h, color_t col) {
128       coords = pointtogl(h);
129       for(int i=0; i<4; i++)
130         color[i] = part(col, 3-i) / 255.0;
131       }
132     };
133 
134   struct textured_vertex {
135     glvertex coords;
136     /* texture uses the 'z' for shading with POLY_SHADE_TEXTURE */
137     glvec3 texture;
138     };
139 
140   struct ct_vertex {
141     glvertex coords;
142     glvec4 color;
143     glvec2 texture;
ct_vertexhr::glhr::ct_vertex144     ct_vertex() {}
ct_vertexhr::glhr::ct_vertex145     ct_vertex(const hyperpoint& h, ld x1, ld y1, ld col) {
146       coords = pointtogl(h);
147       texture[0] = x1;
148       texture[1] = y1;
149       color[0] = color[1] = color[2] = col;
150       color[3] = 1;
151       }
152     };
153 
154 #endif
155 
156 bool glew   = false;
157 
158 bool current_depthtest, current_depthwrite;
159 ld fogbase;
160 
161 #if HDR
162 typedef const void *constvoidptr;
163 #endif
164 
165 EX constvoidptr current_vertices, buffered_vertices;
166 EX ld current_linewidth;
167 
168 GLuint buf_current, buf_buffered;
169 
display(const glmatrix & m)170 void display(const glmatrix& m) {
171   for(int i=0; i<4; i++) {
172     for(int j=0; j<4; j++)
173       printf("%10.5f", m[i][j]);
174     printf("\n");
175     }
176   printf("\n");
177   }
178 
operator *(glmatrix m1,glmatrix m2)179 EX glmatrix operator * (glmatrix m1, glmatrix m2) {
180   glmatrix res;
181   for(int i=0; i<4; i++)
182   for(int j=0; j<4; j++) {
183     res[i][j] = 0;
184     for(int k=0; k<4; k++)
185       res[i][j] += m1[i][k] * m2[k][j];
186     }
187   return res;
188   }
189 
190 EX glmatrix id = {{{1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1}}};
191 
scale(ld x,ld y,ld z)192 EX glmatrix scale(ld x, ld y, ld z) {
193   glmatrix tmp;
194   for(int i=0; i<4; i++)
195   for(int j=0; j<4; j++)
196     tmp[i][j] = (i==j);
197   tmp[0][0] = x;
198   tmp[1][1] = y;
199   tmp[2][2] = z;
200   return tmp;
201   }
202 
tmtogl(const transmatrix & T)203 EX glmatrix tmtogl(const transmatrix& T) {
204   glmatrix tmp;
205   for(int i=0; i<4; i++)
206   for(int j=0; j<4; j++)
207     tmp[i][j] = T[i][j];
208   return tmp;
209   }
210 
tmtogl_transpose(const transmatrix & T)211 EX glmatrix tmtogl_transpose(const transmatrix& T) {
212   glmatrix tmp;
213   for(int i=0; i<4; i++)
214   for(int j=0; j<4; j++)
215     tmp[i][j] = T[j][i];
216   return tmp;
217   }
218 
tmtogl_transpose3(const transmatrix & T)219 EX glmatrix tmtogl_transpose3(const transmatrix& T) {
220   glmatrix tmp;
221   for(int i=0; i<4; i++)
222   for(int j=0; j<4; j++)
223     tmp[i][j] = T[j][i];
224   if(MDIM == 3)
225     for(int i=0; i<4; i++)
226     for(int j=0; j<4; j++)
227       if(i == 3 || j == 3) tmp[j][i] = 0;
228   return tmp;
229   }
230 
ortho(ld x,ld y,ld z)231 EX glmatrix ortho(ld x, ld y, ld z) {
232   return scale(1/x, 1/y, 1/z);
233   }
234 
as_glmatrix(GLfloat o[16])235 EX glmatrix& as_glmatrix(GLfloat o[16]) {
236   glmatrix& tmp = (glmatrix&) (o[0]);
237   return tmp;
238   }
239 
240 #if HDR
241 constexpr ld vnear_default = 1e-3;
242 constexpr ld vfar_default = 1e9;
243 #endif
244 
frustum(ld x,ld y,ld vnear IS (vnear_default),ld vfar IS (vfar_default))245 EX glmatrix frustum(ld x, ld y, ld vnear IS(vnear_default), ld vfar IS(vfar_default)) {
246   GLfloat frustum[16] = {
247     GLfloat(1 / x), 0, 0, 0,
248     0, GLfloat(1 / y), 0, 0,
249     0, 0, GLfloat(-(vnear+vfar)/(vfar-vnear)), -1,
250     0, 0, GLfloat(-2*vnear*vfar/(vfar-vnear)), 0};
251   return as_glmatrix(frustum);
252   }
253 
translate(ld x,ld y,ld z)254 EX glmatrix translate(ld x, ld y, ld z) {
255   glmatrix tmp;
256   for(int i=0; i<4; i++)
257   for(int j=0; j<4; j++)
258     tmp[i][j] = (i==j);
259   tmp[3][0] = x;
260   tmp[3][1] = y;
261   tmp[3][2] = z;
262   return tmp;
263   }
264 
265 // ** legacy **
266 
267 // /* shaders */
268 
269 glmatrix projection;
270 
new_projection()271 EX void new_projection() {
272   WITHSHADER({
273     projection = id;
274     }, {
275     glMatrixMode(GL_MODELVIEW);
276     glLoadIdentity();
277     glMatrixMode(GL_PROJECTION);
278     glLoadIdentity();
279     return;
280     })
281   }
282 
projection_multiply(const glmatrix & m)283 EX void projection_multiply(const glmatrix& m) {
284   WITHSHADER({
285     projection = m * projection;
286     }, {
287     glMatrixMode(GL_PROJECTION);
288     glMultMatrixf(m.as_array());
289     })
290   }
291 
292 EX void init();
293 
294 #if HDR
295 struct GLprogram {
296   GLuint _program;
297   GLuint vertShader, fragShader;
298 
299   GLint uFog, uFogColor, uColor, tTexture, tInvExpTable, tAirMap, uMV, uProjection, uAlpha, uFogBase, uPP;
300   GLint uPRECX, uPRECY, uPRECZ, uIndexSL, uIterations, uLevelLines, uSV, uRadarTransform;
301   GLint uRotSin, uRotCos, uRotNil;
302   GLint uDepthScaling, uCamera, uDepth;
303 
304   flagtype shader_flags;
305 
306   string _vsh, _fsh;
307 
308   GLprogram(string vsh, string fsh);
309 
310   ~GLprogram();
311   };
312 #endif
313 
314 EX shared_ptr<GLprogram> current_glprogram = nullptr;
315 
316 EX bool debug_gl;
317 
compileShader(int type,const string & s)318 EX int compileShader(int type, const string& s) {
319   GLint status;
320 
321   if(debug_gl) {
322     println(hlog, "===\n");
323     int lineno = 1;
324     string cline = "";
325     for(char c: s+"\n") {
326       if(c == '\n') println(hlog, format("%4d : ", lineno), cline), lineno++, cline = "";
327       else cline += c;
328       }
329     println(hlog, "===");
330     }
331 
332   GLint shader = glCreateShader(type);
333   const char *ss = s.c_str();
334   glShaderSource(shader, 1, &ss, NULL);
335   glCompileShader(shader);
336 
337   GLint logLength;
338   glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
339   if (logLength > 0) {
340     std::vector<char> log(logLength);
341     glGetShaderInfoLog(shader, logLength, &logLength, log.data());
342     string s = log.data();
343     if(logLength > 0)
344       println(hlog, "compiler log (", logLength, "): \n", s);
345     if(debug_gl) {
346       println(hlog, "failed to compile shader -- exit called");
347       exit(1);
348       }
349     }
350 
351   glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
352   if (status == 0) {
353     glDeleteShader(shader);
354     printf("failed to compile shader\n");
355     println(hlog, s);
356     shader = 0;
357     }
358 
359   return shader;
360   }
361 
GLprogram(string vsh,string fsh)362 GLprogram::GLprogram(string vsh, string fsh) {
363   if(noshaders || !vid.usingGL) {
364     uFog = -1;
365     uProjection = -1;
366     uPP = -1;
367     uMV = -1;
368     uPRECX = -1;
369     uIterations = -1;
370     uAlpha = -1;
371     uLevelLines = -1;
372     uFogColor = -1;
373     uDepthScaling = uCamera = uDepth = -1;
374 
375     uColor = tTexture = tInvExpTable = tAirMap = -1;
376     uFogBase = -1;
377     uPRECX = uPRECY = uPRECZ = uIndexSL = -1;
378     uSV = uRadarTransform = -1;
379 
380     uRotCos = -1;
381     uRotSin = -1;
382     uRotNil = -1;
383     return;
384     }
385 
386   _vsh = vsh; _fsh = fsh;
387   _program = glCreateProgram();
388 
389   add_fixed_functions(vsh);
390   add_fixed_functions(fsh);
391 
392   // printf("creating program %d\n", _program);
393   vertShader = compileShader(GL_VERTEX_SHADER, vsh.c_str());
394   fragShader = compileShader(GL_FRAGMENT_SHADER, fsh.c_str());
395 
396   // Attach vertex shader to program.
397   glAttachShader(_program, vertShader);
398 
399   // Attach fragment shader to program.
400   glAttachShader(_program, fragShader);
401 
402   glBindAttribLocation(_program, aPosition, "aPosition");
403   glBindAttribLocation(_program, aTexture, "aTexture");
404   glBindAttribLocation(_program, aColor, "aColor");
405 
406   GLint status;
407   glLinkProgram(_program);
408 
409   GLint logLength;
410   glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &logLength);
411   if (logLength > 0) {
412     std::vector<char> log(logLength);
413     glGetProgramInfoLog(_program, logLength, &logLength, log.data());
414     if(logLength > 0)
415       printf("linking log (%d): %s\n", logLength, log.data());
416     }
417 
418   glGetProgramiv(_program, GL_LINK_STATUS, &status);
419   if (status == 0) {
420     printf("failed to link shader\n");
421     exit(1);
422     }
423 
424   uMV = glGetUniformLocation(_program, "uMV");
425   uProjection = glGetUniformLocation(_program, "uP");
426   uPP = glGetUniformLocation(_program, "uPP");
427   uFog = glGetUniformLocation(_program, "uFog");
428   uFogColor = glGetUniformLocation(_program, "uFogColor");
429   uFogBase = glGetUniformLocation(_program, "uFogBase");
430   uAlpha = glGetUniformLocation(_program, "uAlpha");
431   uColor = glGetUniformLocation(_program, "uColor");
432   tTexture = glGetUniformLocation(_program, "tTexture");
433   tInvExpTable = glGetUniformLocation(_program, "tInvExpTable");
434   tAirMap = glGetUniformLocation(_program, "tAirMap");
435 
436   uDepth = glGetUniformLocation(_program, "uDepth");
437   uDepthScaling = glGetUniformLocation(_program, "uDepthScaling");
438   uCamera = glGetUniformLocation(_program, "uCamera");
439 
440   uPRECX = glGetUniformLocation(_program, "PRECX");
441   uPRECY = glGetUniformLocation(_program, "PRECY");
442   uPRECZ = glGetUniformLocation(_program, "PRECZ");
443   uIndexSL = glGetUniformLocation(_program, "uIndexSL");
444   uSV = glGetUniformLocation(_program, "uSV");
445   uIterations = glGetUniformLocation(_program, "uIterations");
446   uLevelLines = glGetUniformLocation(_program, "uLevelLines");
447   uRadarTransform = glGetUniformLocation(_program, "uRadarTransform");
448 
449   uRotCos = glGetUniformLocation(_program, "uRotCos");
450   uRotSin = glGetUniformLocation(_program, "uRotSin");
451   uRotNil = glGetUniformLocation(_program, "uRotNil");
452   }
453 
~GLprogram()454 GLprogram::~GLprogram() {
455   glDeleteProgram(_program);
456   if(vertShader) glDeleteShader(vertShader), vertShader = 0;
457   if(fragShader) glDeleteShader(fragShader), fragShader = 0;
458   }
459 
set_index_sl(ld x)460 EX void set_index_sl(ld x) {
461   glUniform1f(glhr::current_glprogram->uIndexSL, x);
462   }
463 
set_sv(ld x)464 EX void set_sv(ld x) {
465   glUniform1f(glhr::current_glprogram->uSV, x);
466   }
467 
set_sl_iterations(int steps)468 EX void set_sl_iterations(int steps) {
469   glUniform1i(glhr::current_glprogram->uIterations, steps);
470   }
471 
set_solv_prec(int x,int y,int z)472 EX void set_solv_prec(int x, int y, int z) {
473   glUniform1i(glhr::current_glprogram->tInvExpTable, INVERSE_EXP_BINDING);
474   glUniform1f(glhr::current_glprogram->uPRECX, x);
475   glUniform1f(glhr::current_glprogram->uPRECY, y);
476   glUniform1f(glhr::current_glprogram->uPRECZ, z);
477   }
478 
479 EX glmatrix current_matrix, current_modelview, current_projection;
480 
operator ==(const glmatrix & m1,const glmatrix & m2)481 bool operator == (const glmatrix& m1, const glmatrix& m2) {
482   for(int i=0; i<4; i++)
483     for(int j=0; j<4; j++)
484       if(m1[i][j] != m2[i][j]) return false;
485   return true;
486   }
487 
operator !=(const glmatrix & m1,const glmatrix & m2)488 bool operator != (const glmatrix& m1, const glmatrix& m2) {
489   return !(m1 == m2);
490   }
491 
492 EX glmatrix eyeshift;
493 EX bool using_eyeshift;
494 
set_modelview(const glmatrix & modelview)495 EX void set_modelview(const glmatrix& modelview) {
496   #if CAP_NOSHADER
497   if(noshaders) {
498     glMatrixMode(GL_MODELVIEW);
499     glLoadMatrixf(modelview.as_array());
500     return;
501     }
502   #endif
503   auto& cur = current_glprogram;
504   if(!cur) return;
505 
506   if(detailed_shader) println(hlog, "\n*** ENABLING MODELVIEW:\n", modelview.as_stdarray());
507   if(detailed_shader) println(hlog, "\n*** ENABLING PROJECTION:\n", projection.as_stdarray());
508 
509   if(using_eyeshift) {
510     glmatrix mvp = modelview * eyeshift;
511     #if MINIMIZE_GL_CALLS
512     if(mvp == current_matrix) return;
513     current_matrix = mvp;
514     #endif
515     glUniformMatrix4fv(cur->uMV, 1, 0, mvp.as_array());
516     }
517   else if(modelview != current_modelview) {
518     current_modelview = modelview;
519     glUniformMatrix4fv(cur->uMV, 1, 0, modelview.as_array());
520     }
521   if(projection != current_projection) {
522     current_projection = projection;
523     glUniformMatrix4fv(cur->uProjection, 1, 0, projection.as_array());
524     }
525   }
526 
id_modelview()527 EX void id_modelview() {
528   #if CAP_NOSHADER
529   if(noshaders) {
530     glMatrixMode(GL_MODELVIEW);
531     glLoadIdentity();
532     return;
533     }
534   #endif
535   set_modelview(id);
536   }
537 
538 EX array<GLfloat, 4> acolor(color_t color, ld scale IS(1)) {
539   array<GLfloat, 4> cols;
540   for(int i=0; i<4; i++)
541     cols[i] = part(color, 3-i) / 255.0 * scale;
542   return cols;
543   }
544 
545 
546 EX void color2(color_t color, ld scale IS(1)) {
547   auto cols = acolor(color, scale);
548 
549   WITHSHADER({
550     if(!current_glprogram) return;
551     glUniform4f(current_glprogram->uColor, cols[0], cols[1], cols[2], cols[3]);
552     }, {
553     glColor4f(cols[0], cols[1], cols[2], cols[3]);
554     }
555     )
556   }
557 
colorClear(color_t color)558 EX void colorClear(color_t color) {
559   glClearColor(part(color, 3) / 255.0, part(color, 2) / 255.0, part(color, 1) / 255.0, part(color, 0) / 255.0);
560 }
561 
full_enable(shared_ptr<GLprogram> p)562 EX void full_enable(shared_ptr<GLprogram> p) {
563   auto& cur = current_glprogram;
564   flagtype oldflags = cur ? cur->shader_flags : 0;
565   if(p == cur) return;
566   if(!vid.usingGL) return;
567   cur = p;
568   GLERR("pre_switch_mode");
569   WITHSHADER({
570     if(detailed_shader) println(hlog, "\n*** ENABLING VERTEX SHADER:\n", cur->_vsh, "\n\nENABLING FRAGMENT SHADER:\n", cur->_fsh, "\n");
571     glUseProgram(cur->_program);
572     GLERR("after_enable");
573     }, {
574     });
575   reset_projection();
576   flagtype newflags = cur->shader_flags;
577   tie(oldflags, newflags) = make_pair(oldflags & ~newflags, newflags & ~oldflags);
578 
579   if(newflags & GF_TEXTURE) {
580     GLERR("xsm");
581     WITHSHADER({
582       glEnableVertexAttribArray(aTexture);
583       GLERR("xsm");
584       }, {
585       glEnable(GL_TEXTURE_2D);
586       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
587       GLERR("xsm");
588       })
589     }
590   if(oldflags & GF_TEXTURE) {
591     GLERR("xsm");
592     WITHSHADER({
593       glDisableVertexAttribArray(aTexture);
594       GLERR("xsm");
595       }, {
596       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
597       glDisable(GL_TEXTURE_2D);
598       GLERR("xsm");
599       })
600     }
601   if(newflags & GF_VARCOLOR) {
602     WITHSHADER({
603       GLERR("xsm");
604       glEnableVertexAttribArray(aColor);
605       }, {
606       GLERR("xsm");
607       glEnableClientState(GL_COLOR_ARRAY);
608       GLERR("xsm");
609       })
610     }
611   if(oldflags & GF_VARCOLOR) {
612     WITHSHADER({
613       glDisableVertexAttribArray(aColor);
614       GLERR("xsm");
615       }, {
616       glDisableClientState(GL_COLOR_ARRAY);
617       GLERR("xsm");
618       })
619     }
620   if(newflags & GF_LIGHTFOG) {
621     #ifdef GLES_ONLY
622     #define glFogi glFogx
623     #endif
624     WITHSHADER({}, {
625     /*GLfloat light_ambient[] = { 3.5, 3.5, 3.5, 1.0 };
626     GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
627     GLfloat light_position[] = { 0.0, 0.0, 0.0, 1.0 };
628 
629     glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
630     glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
631     glLightfv(GL_LIGHT0, GL_POSITION, light_position);
632 
633     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
634     GLERR("lighting");
635 
636     glEnable(GL_LIGHTING);
637     glEnable(GL_LIGHT0); */
638 
639     glEnable(GL_FOG);
640     glFogi(GL_FOG_MODE, GL_LINEAR);
641     glFogf(GL_FOG_START, 0);
642     })
643     }
644   if(oldflags & GF_LIGHTFOG) {
645     WITHSHADER({}, {glDisable(GL_FOG);})
646     }
647   WITHSHADER({
648     glUniform1f(cur->uFogBase, 1); fogbase = 1;
649     }, {})
650   GLERR("after_switch_mode");
651   current_vertices = NULL;
652   WITHSHADER({
653     current_matrix[0][0] = -1e8; // invalid
654     current_modelview[0][0] = -1e8;
655     current_projection[0][0] = -1e8;
656     }, {})
657   id_modelview();
658   current_linewidth = -1;
659   /* if(current_depthwrite) glDepthMask(GL_TRUE);
660   else glDepthMask(GL_FALSE);
661   if(current_depthtest) glEnable(GL_DEPTH_TEST);
662   else glDisable(GL_DEPTH_TEST); */
663   }
664 
fog_max(ld fogmax,color_t fogcolor)665 EX void fog_max(ld fogmax, color_t fogcolor) {
666   WITHSHADER({
667     if(current_glprogram->uFog != -1)
668       glUniform1f(current_glprogram->uFog, 1 / fogmax);
669 
670     if(current_glprogram->uFogColor != -1) {
671       GLfloat cols[4];
672       for(int i=0; i<4; i++) cols[i] = part(fogcolor, 3-i) / 255.0;
673         glUniform4f(current_glprogram->uFogColor, cols[0], cols[1], cols[2], cols[3]);
674       }
675     }, {
676     glFogf(GL_FOG_END, fogmax);
677     })
678   }
679 
set_fogbase(ld _fogbase)680 EX void set_fogbase(ld _fogbase) {
681   WITHSHADER({
682     if(fogbase != _fogbase) {
683       fogbase = _fogbase;
684       glUniform1f(current_glprogram->uFogBase, fogbase);
685       }
686     }, {})
687   }
688 
set_ualpha(ld alpha)689 EX void set_ualpha(ld alpha) {
690   WITHSHADER({
691     glUniform1f(current_glprogram->uAlpha, alpha);
692     }, {})
693   }
694 
init()695 void init() {
696 
697   #if CAP_GLEW
698     if(!glew) {
699       glew = true;
700       printf("Initializing GLEW\n");
701       GLenum err = glewInit();
702       if (GLEW_OK != err) {
703         addMessage("Failed to initialize GLEW");
704         printf("Failed to initialize GLEW\n");
705         return;
706         }
707       printf("CreateProgram = %p\n", reinterpret_cast<void*>(__glewCreateProgram));
708       if(!__glewCreateProgram) noshaders = true;
709       }
710   #endif
711 
712   projection = id;
713 
714   WITHSHADER(glEnableVertexAttribArray(aPosition);, glEnableClientState(GL_VERTEX_ARRAY);)
715   GLERR("aPosition");
716   // #endif
717 
718   glDisableVertexAttribArray(aTexture);
719   glDisableVertexAttribArray(aColor);
720 
721   #if CAP_VERTEXBUFFER
722   glGenBuffers(1, &buf_current);
723   glGenBuffers(1, &buf_buffered);
724   current_vertices = NULL;
725   buffered_vertices = (void*) &buffered_vertices; // point to nothing
726   glBindBuffer(GL_ARRAY_BUFFER, buf_current);
727   #endif
728   }
729 
730 #if CAP_VERTEXBUFFER
bindbuffer(T & v)731 template<class T> void bindbuffer(T& v) {
732   if(current_vertices == buffered_vertices || current_vertices == nullptr) {
733     glBindBuffer(GL_ARRAY_BUFFER, buf_current);
734     }
735   current_vertices = &v[0];
736   glBufferData(GL_ARRAY_BUFFER, isize(v) * sizeof(v[0]), &v[0], GL_DYNAMIC_DRAW);
737   }
738 
739 #define PTR(attrib, q, field) \
740   glVertexAttribPointer(attrib, q, GL_FLOAT, GL_FALSE, sizeof(v[0]), (void*) ((char*) &v[0].field - (char*) &v[0]));
741 
bindbuffer_vertex(vector<glvertex> & v)742 EX void bindbuffer_vertex(vector<glvertex>& v) {
743   bindbuffer(v);
744   }
745 
746 #endif
747 
748 EX void vertices(const vector<glvertex>& v, int vshift IS(0)) {
749   #if CAP_VERTEXBUFFER
750   if(&v[0] == buffered_vertices) {
751     if(&v[0] == current_vertices) return;
752     current_vertices = buffered_vertices;
753     glBindBuffer(GL_ARRAY_BUFFER, buf_buffered);
754     glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), 0);
755     return;
756     }
757   bindbuffer(v);
758   glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), 0);
759   #else
760   if(current_vertices == &v[vshift]) return;
761   current_vertices = &v[vshift];
762   WITHSHADER(
763     glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), &v[vshift]);,
764     glVertexPointer(SHDIM, GL_FLOAT, sizeof(glvertex), &v[0]);
765     )
766   #endif
767   }
768 
769 EX void vertices_texture(const vector<glvertex>& v, const vector<glvertex>& t, int vshift IS(0), int tshift IS(0)) {
770   #if CAP_VERTEXBUFFER
771   int q = min(isize(v)-vshift, isize(t)-tshift);
772   vector<textured_vertex> tv(q);
773   for(int i=0; i<q; i++)
774     tv[i].coords = v[vshift+i],
775     tv[i].texture[0] = t[tshift+i][0],
776     tv[i].texture[1] = t[tshift+i][1],
777     tv[i].texture[2] = t[tshift+i][2];
778   prepare(tv);
779   #else
780   vertices(v, vshift);
781   WITHSHADER(
782     glVertexAttribPointer(aTexture, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), &t[tshift]);,
783     glTexCoordPointer(SHDIM, GL_FLOAT, 0, &t[tshift]);
784     )
785   #endif
786   }
787 
788 EX void vertices_texture_color(const vector<glvertex>& v, const vector<glvertex>& t, const vector<glvertex>& c, int vshift IS(0), int tshift IS(0)) {
789   #if CAP_VERTEXBUFFER
790   int q = min(isize(v)-vshift, isize(t)-tshift);
791   vector<ct_vertex> tv(q);
792   for(int i=0; i<q; i++) {
793     tv[i].coords = v[vshift+i],
794     tv[i].texture[0] = t[tshift+i][0],
795     tv[i].texture[1] = t[tshift+i][1];
796     for(int i=0; i<SHDIM; i++)
797       tv[i].color[i] = c[tshift+i][i];
798     if(SHDIM == 3) tv[i].color[3] = 1;
799     }
800   prepare(tv);
801   #else
802   vertices(v, vshift);
803   WITHSHADER({
804     glVertexAttribPointer(aTexture, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), &t[tshift]);
805     glVertexAttribPointer(aColor, 4, GL_FLOAT, GL_FALSE, sizeof(glvertex), &c[tshift]);
806     }, {
807     glTexCoordPointer(SHDIM, GL_FLOAT, 0, &t[tshift]);
808     glColorPointer(4, GL_FLOAT, sizeof(colored_vertex), &c[0]);
809     }
810     )
811   #endif
812   }
813 
prepare(vector<colored_vertex> & v)814 EX void prepare(vector<colored_vertex>& v) {
815   #if CAP_VERTEXBUFFER
816   bindbuffer(v);
817   PTR(aPosition, SHDIM, coords);
818   PTR(aColor, 4, color);
819   #else
820   if(current_vertices == &v[0]) return;
821   current_vertices = &v[0];
822   WITHSHADER({
823     glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(colored_vertex), &v[0].coords);
824     glVertexAttribPointer(aColor, 4, GL_FLOAT, GL_FALSE, sizeof(colored_vertex), &v[0].color);
825     }, {
826     glVertexPointer(SHDIM, GL_FLOAT, sizeof(colored_vertex), &v[0].coords);
827     glColorPointer(4, GL_FLOAT, sizeof(colored_vertex), &v[0].color);
828     })
829   #endif
830   }
831 
prepare(vector<textured_vertex> & v)832 EX void prepare(vector<textured_vertex>& v) {
833   #if CAP_VERTEXBUFFER
834   bindbuffer(v);
835   PTR(aPosition, SHDIM, coords);
836   PTR(aTexture, 3, texture);
837   #else
838   if(current_vertices == &v[0]) return;
839   current_vertices = &v[0];
840   WITHSHADER({
841     glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(textured_vertex), &v[0].coords);
842     glVertexAttribPointer(aTexture, SHDIM, GL_FLOAT, GL_FALSE, sizeof(textured_vertex), &v[0].texture);
843     }, {
844     glVertexPointer(SHDIM, GL_FLOAT, sizeof(textured_vertex), &v[0].coords);
845     glTexCoordPointer(3, GL_FLOAT, sizeof(textured_vertex), &v[0].texture);
846     })
847   #endif
848   // color2(col);
849   }
850 
prepare(vector<ct_vertex> & v)851 EX void prepare(vector<ct_vertex>& v) {
852   #if CAP_VERTEXBUFFER
853   bindbuffer(v);
854   PTR(aPosition, SHDIM, coords);
855   PTR(aColor, 4, color);
856   PTR(aTexture, 2, texture);
857   #else
858   if(current_vertices == &v[0]) return;
859   current_vertices = &v[0];
860   WITHSHADER({
861     glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(ct_vertex), &v[0].coords);
862     glVertexAttribPointer(aColor, 4, GL_FLOAT, GL_FALSE, sizeof(ct_vertex), &v[0].color);
863     glVertexAttribPointer(aTexture, 2, GL_FLOAT, GL_FALSE, sizeof(ct_vertex), &v[0].texture);
864     }, {
865     glVertexPointer(SHDIM, GL_FLOAT, sizeof(ct_vertex), &v[0].coords);
866     glTexCoordPointer(2, GL_FLOAT, sizeof(ct_vertex), &v[0].texture);
867     glColorPointer(4, GL_FLOAT, sizeof(ct_vertex), &v[0].color);
868     })
869   #endif
870   }
871 
store_in_buffer(vector<glvertex> & v)872 EX void store_in_buffer(vector<glvertex>& v) {
873 #if CAP_VERTEXBUFFER
874   if(!buf_buffered) {
875     printf("no buffer yet\n");
876     return;
877     }
878   printf("storing %d in buffer: %p\n", isize(v), &v[0]);
879   current_vertices = buffered_vertices = &v[0];
880   glBindBuffer(GL_ARRAY_BUFFER, buf_buffered);
881   glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, sizeof(glvertex), 0);
882   glBufferData(GL_ARRAY_BUFFER, isize(v) * sizeof(glvertex), &v[0], GL_STATIC_DRAW);
883   printf("Stored.\n");
884 #endif
885   }
886 
set_depthtest(bool b)887 EX void set_depthtest(bool b) {
888   if(b != current_depthtest) {
889     current_depthtest = b;
890     if(b) glEnable(GL_DEPTH_TEST);
891     else glDisable(GL_DEPTH_TEST);
892     }
893   }
894 
895 
set_depthwrite(bool b)896 EX void set_depthwrite(bool b) {
897   if(b != current_depthwrite) { // <- this does not work ask intended for some reason...
898     current_depthwrite = b;
899     if(b) glDepthMask(GL_TRUE);
900     else glDepthMask(GL_FALSE);
901     }
902   }
903 
set_linewidth(ld lw)904 EX void set_linewidth(ld lw) {
905   if(lw != current_linewidth) {
906     current_linewidth = lw;
907     glLineWidth(lw);
908     }
909   }
910 
switch_to_text(const vector<glvertex> & v,const vector<glvertex> & t)911 EX void switch_to_text(const vector<glvertex>& v, const vector<glvertex>& t) {
912   current_display->next_shader_flags = GF_TEXTURE;
913   dynamicval<eModel> pm(pmodel, mdPixel);
914   if(!svg::in) current_display->set_all(0, 0);
915   vertices_texture(v, t, 0, 0);
916   }
917 
be_nontextured()918 EX void be_nontextured() { current_display->next_shader_flags = 0; }
be_textured()919 EX void be_textured() { current_display->next_shader_flags = GF_TEXTURE; }
be_color_textured()920 EX void be_color_textured() { current_display->next_shader_flags = GF_TEXTURE | GF_VARCOLOR; }
921 
922 EX }
923 
924 EX vector<glhr::textured_vertex> text_vertices;
925 
926 EX void texture_vertices(GLfloat *f, int qty, int stride IS(2)) {
927   WITHSHADER(
928     glVertexAttribPointer(aTexture, stride, GL_FLOAT, GL_FALSE, stride * sizeof(GLfloat), f);,
929     glTexCoordPointer(stride, GL_FLOAT, 0, f);
930     )
931   }
932 
oldvertices(GLfloat * f,int qty)933 EX void oldvertices(GLfloat *f, int qty) {
934   WITHSHADER(
935    glVertexAttribPointer(aPosition, SHDIM, GL_FLOAT, GL_FALSE, SHDIM * sizeof(GLfloat), f);,
936    glVertexPointer(SHDIM, GL_FLOAT, 0, f);
937    )
938   }
939 
940 #endif
941 }
942 
943 #define glMatrixMode DISABLED
944 #define glLoadIdentity DISABLED
945 #define glMultMatrixf DISABLED
946 #define glScalef DISABLED
947 #define glTranslatef DISABLED
948 #define glPushMatrix DISABLED
949 #define glPopMatrix DISABLED
950 
951