1 /*
2 A* -------------------------------------------------------------------
3 B* This file contains source code for the PyMOL computer program
4 C* copyright Schrodinger, LLC.
5 D* -------------------------------------------------------------------
6 E* It is unlawful to modify or remove this copyright notice.
7 F* -------------------------------------------------------------------
8 G* Please see the accompanying LICENSE file for further information.
9 H* -------------------------------------------------------------------
10 I* Additional authors of this source file include:
11 -*
12 -*
13 -*
14 Z* -------------------------------------------------------------------
15 */
16 
17 #include "os_gl.h"
18 #include "os_python.h"
19 #include <string.h>
20 #include <iostream>
21 #include "ShaderMgr.h"
22 #include "OOMac.h"
23 #include "ListMacros.h"
24 #include "PyMOLOptions.h"
25 #include "Feedback.h"
26 #include "MemoryDebug.h"
27 #include "Setting.h"
28 #include "Scene.h"
29 #include "Color.h"
30 #include "Vector.h"
31 #include "Util.h"
32 #include "Util2.h"
33 #include "Texture.h"
34 #include "FileStream.h"
35 #include "Matrix.h"
36 #include "Parse.h"
37 
38 #ifndef _PYMOL_NO_AA_SHADERS
39 #endif
40 
41 #include "CGO.h"
42 #ifdef _WEBGL
43 #include "Matrix.h"
44 #include "WebPyMOLLibrary.h"
45 #endif
46 #define MAX_LOG_LEN 1024
47 
48 #include <algorithm>
49 #include <sstream>
50 #include <stack>
51 #include <vector>
52 #include <functional>
53 /*  Texture Usage:
54 
55     0 - for not-PURE_OPENGL_ES_2: ObjectVolume: volumeTex
56         for WEBGL: SCHRODINGER logo
57     1 - for not-PURE_OPENGL_ES_2: Volume: either colorTex1D or colorTex2D
58         for _PYMOL_PRECOMPUTED_LIGHTING: Lighting Texture (ShaderMgr->lightingTexture)
59     2 - FXAA - color_texture
60         SMAA1 - colorTex
61         SMAA3 - colorTex
62     3 - SMAA3 - blendTex
63         Label/Indicator Shader : textureMap (both PURE_OPENGL_ES_2 and non-PURE_OPENGL_ES_2
64     4 - Background Texture: bgTextureMap
65     5 - OIT - 2nd pass : accumTex
66         Volumes - carvemask
67     6 - OIT - 2nd pass : revealageTex
68         SMAA2 - edgesTex
69     7 - SMAA2 - areaTex
70         OIT Copy - colorTex
71     8 - SMAA2 - searchTex
72 
73  */
74 
75 using namespace std;
76 
77 #ifndef _DEAD_CODE_DIE
78 #define SUPPRESS_GEOMETRY_SHADER_ERRORS
79 #endif
80 
81 #define CONNECTOR_GS_NUM_VERTICES  31
82 
83 #define SCENEGETIMAGESIZE SceneGetWidthHeight
84 
85 #include "ShaderText.h"
86 
87 #define WARNING_IF_GLERROR(msg) {		\
88   GLenum err; \
89   if ((err = glGetError())){ \
90     PRINTFB(G, FB_ShaderMgr, FB_Warnings) "GLERROR 0x%04x: %s\n", err, msg ENDFB(G); \
91   } \
92 }
93 
glShaderSource1String(GLuint shad,const string & strobj)94 static void glShaderSource1String(GLuint shad, const string &strobj){
95   const GLchar *str = (const GLchar *)strobj.c_str();
96   glShaderSource(shad, 1, (const GLchar **)&str, nullptr);
97 }
98 
reload()99 bool CShaderPrg::reload(){
100   // skip programs with empty file names, assume their code is managed
101   // outside of the reload logic (like ARB shaders).
102   if (is_valid || vertfile.empty())
103     return true;
104 
105   string gs, vs, fs;
106   CShaderMgr *I = G->ShaderMgr;
107   GLint status;
108 
109   if (!geomfile.empty())
110     gs = I->GetShaderSource(geomfile);
111 
112   vs = I->GetShaderSource(vertfile);
113   fs = I->GetShaderSource(fragfile);
114 
115   WARNING_IF_GLERROR("CShaderPrg::reload begin");
116 
117   PRINTFB(G, FB_ShaderMgr, FB_Blather)
118     "Loading shader named: %s\n", name.c_str()
119     ENDFB(G);
120 
121   if (!id) {
122     id = glCreateProgram();
123   }
124 
125 #ifndef PURE_OPENGL_ES_2
126   if (!gs.empty() && SettingGetGlobal_b(G, cSetting_use_geometry_shaders)) {
127     if (!gid) {
128       gid = glCreateShader(GL_GEOMETRY_SHADER);
129 
130       GLenum err;
131       if ((err=glGetError()) || !gid) {
132         PRINTFB(G, FB_ShaderMgr, FB_Errors)
133           " Error: geometry shader creation failed. name=%s err=0x%x\n", name.c_str(), err ENDFB(G);
134         return false;
135       }
136 
137       glAttachShader(id, gid);
138     }
139 
140     glShaderSource1String(gid, gs);
141     glCompileShader((GLuint) gid);
142     glGetShaderiv(gid, GL_COMPILE_STATUS, &status);
143 
144     if (!status) {
145 #ifndef SUPPRESS_GEOMETRY_SHADER_ERRORS
146       ErrorMsgWithShaderInfoLog(gid, "geometry shader compilation failed.");
147 #endif
148       glDetachShader(id, gid);
149       glDeleteShader(gid);
150       gid = 0;
151       return false;
152     }
153 
154     glProgramParameteriEXT(id, GL_GEOMETRY_INPUT_TYPE_EXT, gsInput);
155     glProgramParameteriEXT(id, GL_GEOMETRY_OUTPUT_TYPE_EXT, gsOutput);
156     glProgramParameteriEXT(id, GL_GEOMETRY_VERTICES_OUT_EXT, ngsVertsOut);
157 
158     PRINTFB(G, FB_ShaderMgr, FB_Debugging)
159       " ShaderPrg-Debug: geometry shader compiled.\n" ENDFB(G);
160   } else if (gid) {
161     // for manually switching off geometry shaders (set use_geometry_shaders, off)
162     glDetachShader(id, gid);
163     glDeleteShader(gid);
164     gid = 0;
165   }
166 
167   WARNING_IF_GLERROR("CShaderPrg::reload after geometry shader");
168 #endif
169 
170   // vertex shader
171   {
172     if (!vid) {
173       vid = glCreateShader(GL_VERTEX_SHADER);
174       glAttachShader(id, vid);
175     }
176 
177     glShaderSource1String(vid, vs);
178     glCompileShader((GLuint) vid);
179     glGetShaderiv(vid, GL_COMPILE_STATUS, &status);
180 
181     if (!status) {
182       ErrorMsgWithShaderInfoLog(vid, "vertex shader compilation failed.");
183       return false;
184     }
185   }
186 
187   // fragment shader
188   {
189     if (!fid) {
190       fid = glCreateShader(GL_FRAGMENT_SHADER);
191       glAttachShader(id, fid);
192     }
193 
194     glShaderSource1String(fid, fs);
195     glCompileShader((GLuint) fid);
196     glGetShaderiv(fid, GL_COMPILE_STATUS, &status);
197 
198     if (!status) {
199       ErrorMsgWithShaderInfoLog(fid, "fragment shader compilation failed.");
200       return false;
201     }
202   }
203 
204   uniforms.clear();
205   uniform_set = 0;
206 
207   // it is valid to bind unused names, and to bind multiple names to the same index
208   if (!name.compare(0, 8, "cylinder")){
209     glBindAttribLocation(id, CYLINDER_VERTEX1, "attr_vertex1");
210     glBindAttribLocation(id, CYLINDER_VERTEX2, "attr_vertex2");
211     glBindAttribLocation(id, CYLINDER_COLOR, "a_Color");
212     glBindAttribLocation(id, CYLINDER_COLOR2, "a_Color2");
213     glBindAttribLocation(id, CYLINDER_RADIUS, "attr_radius");
214     glBindAttribLocation(id, CYLINDER_CAP, "a_cap");
215   } else {
216     glBindAttribLocation(id, VERTEX_POS, "a_Vertex");
217     glBindAttribLocation(id, VERTEX_COLOR, "a_Color");
218     glBindAttribLocation(id, VERTEX_NORMAL, "a_Normal");
219     glBindAttribLocation(id, 0, "attr_worldpos");
220   }
221   WARNING_IF_GLERROR("after glBindAttribLocation");
222 
223   is_linked = false;
224   is_valid = true;
225 
226   return true;
227 }
228 
229 #define MASK_SHADERS_PRESENT_GEOMETRY 0x2;
230 #define MASK_SHADERS_PRESENT_SMAA 0x4;
231 
232 static void getGLVersion(PyMOLGlobals * G, int *major, int* minor);
233 static void getGLSLVersion(PyMOLGlobals * G, int* major, int* minor);
234 
235 static void disableShaders(PyMOLGlobals * G);
236 
237 #ifdef WIN32
238 /* REMOVE US */
getTexImage3D()239 PFNGLTEXIMAGE3DPROC getTexImage3D(){
240   static PFNGLTEXIMAGE3DPROC my_glTexImage3D = NULL;
241   if (!my_glTexImage3D)
242     my_glTexImage3D = (PFNGLTEXIMAGE3DPROC) wglGetProcAddress("glTexImage3D");
243   return my_glTexImage3D;
244 }
245 #endif
246 
247 /*
248  * Use this to turn off shaders if the renderer cannot use them.
249  */
disableShaders(PyMOLGlobals * G)250 void disableShaders(PyMOLGlobals * G) {
251     /* Auto-disable shader-based rendering */
252     SettingSetGlobal_b(G, cSetting_use_shaders, false);
253 }
254 
disableGeometryShaders(PyMOLGlobals * G)255 static void disableGeometryShaders(PyMOLGlobals * G) {
256   SettingSetGlobal_b(G, cSetting_use_geometry_shaders, false);
257   if(G->ShaderMgr)
258     G->ShaderMgr->SetPreprocVar("use_geometry_shaders", false);
259 
260   if (G->Option && !G->Option->quiet)
261     PRINTFB(G, FB_ShaderMgr, FB_Warnings)
262       " Geometry shaders not available\n" ENDFB(G);
263 }
264 
265 /*
266  * Replace strings from a list of pairs.
267  *
268  * src: string to modify
269  * replaceStrings: map of strings to replace (as consecutive elements in an
270  *                 array like {from1, to1, from2, to2, ..., ""}
271  * returns: new string
272  */
stringReplaceAll(const string & src,const string * replaceStrings)273 static string stringReplaceAll(const string &src, const string * replaceStrings) {
274   string dest = src;
275   for (int i = 0; !replaceStrings[i].empty(); i += 2) {
276     int slen1 = replaceStrings[i].length();
277     int slen2 = replaceStrings[i + 1].length();
278     for (size_t pl = 0;
279         (pl = dest.find(replaceStrings[i], pl)) != string::npos;
280         pl += slen2) {
281       dest.replace(pl, slen1, replaceStrings[i + 1]);
282     }
283   }
284   return dest;
285 }
286 
287 /*
288  * Reload "CallComputeColorForLight" shader replacement string
289  */
Reload_CallComputeColorForLight()290 void CShaderMgr::Reload_CallComputeColorForLight(){
291   if ((reload_bits & RELOAD_CALLCOMPUTELIGHTING)) {
292     reload_bits &= ~RELOAD_CALLCOMPUTELIGHTING;
293   } else {
294     return;
295   }
296 
297   if (SettingGetGlobal_b(G, cSetting_precomputed_lighting)) {
298     Generate_LightingTexture();
299     return;
300   }
301 
302   int light_count = SettingGetGlobal_i(G, cSetting_light_count);
303   int spec_count = SettingGetGlobal_i(G, cSetting_spec_count);
304   ostringstream accstr;
305 
306   string rawtemplate = GetShaderSource("call_compute_color_for_light.fs");
307 
308   string lightstrings[] = {
309     "`light`", "0",
310     "`postfix`", "_0",
311     ""
312   };
313 
314   accstr << stringReplaceAll(rawtemplate, lightstrings);
315 
316   if (light_count > 8){
317     PRINTFB(G, FB_ShaderMgr, FB_Details)
318       " ShaderMgr-Detail: using 8 lights (use precomputed_lighting for light_count > 8)\n"
319       ENDFB(G);
320     light_count = 8;
321   }
322 
323   // no postfix for 1..light_count
324   lightstrings[3] = "";
325 
326   for (int i=1; i<light_count; i++){
327     ostringstream lstr;
328     lstr << i;
329     lightstrings[1] = lstr.str(); // std::to_string(i)
330 
331     if (i == spec_count + 1) {
332       // no specular for [spec_count + 1 .. light_count]
333       lightstrings[3] = " * 0.0";
334     }
335 
336     accstr << stringReplaceAll(rawtemplate, lightstrings);
337   }
338 
339   SetShaderSource("CallComputeColorForLight", accstr.str());
340 }
341 
Invalidate_All_Shaders()342 void CShaderMgr::Invalidate_All_Shaders(){
343   for (auto& prog : programs) {
344     prog.second->Invalidate();
345   }
346 }
347 
Reload_All_Shaders()348 void CShaderMgr::Reload_All_Shaders(){
349   Reload_Shader_Variables();
350   Reload_CallComputeColorForLight();
351 
352   if (SettingGetGlobal_i(G, cSetting_transparency_mode) == 3) {
353     Reload_Derivatives("NO_ORDER_TRANSP");
354   }
355 
356   for (auto& prog : programs) {
357     if (prog.second->derivative.empty())
358       prog.second->reload();
359   }
360 }
361 
362 // bitmasks for preprocessor parsing
363 #define IFDEF    1   // #ifdef or #ifndef
364 #define IFNDEF   2   // #ifndef
365 #define ELSE     4   // #else
366 #define ENDIF    8   // #endif
367 #define INCLUDE 16   // #include
368 #define LOOKUP  32   // #ifdef or #ifndef or #include
369 
370 // preprocessor directive (like '#ifdef') -> bitmask
371 static map<string, short> preprocmap;
372 
373 // filename -> contents (static filesystem)
374 static map<string, const char *> shader_cache_raw;
375 
376 // preproc variable -> NULL terminated list of filenames ("used by")
377 std::map<std::string, const char **> ifdef_deps;
378 
379 // filename -> NULL terminated list of filenames ("included by")
380 std::map<std::string, const char **> include_deps;
381 
382 /*
383  * Return a pointer to the next whitespace character or to the end of the string
384  */
nextwhitespace(const char * p)385 static const char * nextwhitespace(const char * p) {
386   for (;; p++) {
387     switch (*p) {
388       case ' ': case '\0': case '\n': case '\r': case '\t':
389         return p;
390     }
391   }
392 }
393 
394 /*
395  * Return a pointer to the next line beginning or to the end of the string.
396  * Skips blank lines.
397  */
nextline(const char * p)398 static const char * nextline(const char * p) {
399   for (;; p++) {
400     switch (*p) {
401       case '\0': case '\n': case '\r':
402         goto switch2;
403     }
404   }
405   for (;; p++) {
406 switch2:
407     switch (*p) {
408       case ' ': case '\n': case '\r': case '\t':
409         break;
410       default:
411         return p;
412     }
413   }
414 }
415 
416 /*
417  * Get the processed shader file contents with all #ifdef and #include
418  * preprocessors processed.
419  *
420  * Note: There must be a single whitespace character between preprocessor
421  * directive and argument.
422  *
423  * Valid:
424  * #ifdef foo
425  *
426  * Invalid:
427  * # ifdef foo
428  * #ifdef  foo
429  *
430  * Function arguments:
431  * filename: file name of the shader file inside $PYMOL_DATA/shaders
432  */
GetShaderSource(const string & filename)433 string CShaderMgr::GetShaderSource(const string &filename)
434 {
435   // processed cache
436   auto it = shader_cache_processed.find(filename);
437   if (it != shader_cache_processed.end()) {
438     return it->second;
439   }
440 
441   std::string buffer;
442   const char *pl = nullptr, *newpl, *tpl;
443   std::ostringstream newbuffer;
444 
445   /* "if_depth" counts the level of nesting, and "true_depth" how far the
446    * if conditions were actually true. So if the current block is true, then
447    * if_depth == true_depth, otherwise if_depth > true_depth.
448    */
449   int if_depth = 0, true_depth = 0;
450 
451 #ifndef _PYMOL_IOS
452   /* read the file from disk */
453   if (SettingGetGlobal_b(G, cSetting_shaders_from_disk)) {
454     const char * pymol_data = getenv("PYMOL_DATA");
455 
456     if (pymol_data && pymol_data[0]) {
457       string path(pymol_data);
458       path.append(PATH_SEP).append("shaders").append(PATH_SEP).append(filename);
459 
460       try {
461         buffer = pymol::file_get_contents(path);
462         pl = buffer.c_str();
463       } catch (...) {
464         PRINTFB(G, FB_ShaderMgr, FB_Warnings)
465           " Warning: shaders_from_dist=on, but unable to open file '%s'\n",
466           path.c_str() ENDFB(G);
467       }
468     } else {
469       PRINTFB(G, FB_ShaderMgr, FB_Warnings)
470         " Warning: shaders_from_dist=on, but PYMOL_DATA not set\n" ENDFB(G);
471     }
472   }
473 #endif
474 
475   if (!pl) {
476     pl = shader_cache_raw[filename];
477     if (!pl) {
478       PRINTFB(G, FB_ShaderMgr, FB_Errors)
479         " GetShaderSource-Error: No such file: '%s'\n", filename.c_str() ENDFB(G);
480       return "";
481     }
482   }
483 
484   /* Now we need to read through the shader and do processing if necessary */
485   for (; *pl; pl = newpl) {
486     int preproc = 0;
487 
488     // only do preprocessor lookup if line starts with a hash
489     if (pl[0] == '#') {
490       // next white space
491       tpl = nextwhitespace(pl);
492 
493       // copy of first word
494       string tmp_str(pl, tpl - pl);
495 
496       // lookup word in preprocmap
497       map<string, short>::const_iterator
498         preprocit = preprocmap.find(tmp_str);
499       if (preprocit != preprocmap.end()) {
500         preproc = preprocit->second;
501 
502         if (preproc & LOOKUP) { // #ifdef or #ifndef or #include
503           if (if_depth == true_depth) {
504             // copy of second word
505             tpl++;
506             tmp_str = string(tpl, nextwhitespace(tpl) - tpl);
507 
508             if (preproc & IFDEF) { // #ifdef or #ifndef
509               bool if_value = false;
510 
511               // lookup for boolean shader preprocessor values
512               auto item = preproc_vars.find(tmp_str);
513               if (item != preproc_vars.end())
514                 if_value = item->second;
515 
516               if (preproc & IFNDEF)
517                 if_value = !if_value; // #ifndef
518 
519               if (if_value)
520                 true_depth++;
521 
522             } else if (preproc & INCLUDE) { //#include
523               tmp_str = string(tpl, nextwhitespace(tpl) - tpl);
524               newbuffer << GetShaderSource(tmp_str);
525             }
526           }
527 
528           if (preproc & IFDEF)
529             if_depth++;
530 
531         } else if (preproc & ENDIF){ // #endif
532           if (if_depth-- == true_depth)
533             true_depth--;
534         } else if (preproc & ELSE){ // #else
535           if (if_depth == true_depth)
536             true_depth--;
537           else if (if_depth == true_depth + 1)
538             true_depth++;
539         }
540       }
541     }
542 
543     newpl = nextline(pl);
544 
545     // add to the output buffer if this is a regular active line
546     if (!preproc && if_depth == true_depth) {
547       newbuffer.write(pl, newpl - pl);
548     }
549   }
550 
551   string result = newbuffer.str();
552   shader_cache_processed[filename] = result;
553   return result;
554 }
555 
556 #define FREE_AND_REPLACE_WITH(var, with) if (var) free(var);  var = with;
557 
Reload_Shader_Variables()558 void CShaderMgr::Reload_Shader_Variables() {
559   if ((reload_bits & RELOAD_VARIABLES)) {
560     reload_bits &= ~RELOAD_VARIABLES;
561   } else {
562     return;
563   }
564 
565   int bg_image_mode = SettingGetGlobal_i(G, cSetting_bg_image_mode);
566   int bg_gradient = SettingGetGlobal_b(G, cSetting_bg_gradient);
567   int bg_image_mode_solid;
568   int stereo, stereo_mode;
569   const char * bg_image_filename = SettingGet_s(G, nullptr, nullptr, cSetting_bg_image_filename);
570   short bg_image = bg_image_filename && bg_image_filename[0];
571   bg_image_mode_solid = !(bg_gradient || bg_image || OrthoBackgroundDataIsSet(*G->Ortho));
572 
573   SetPreprocVar("bg_image_mode_solid", bg_image_mode_solid);
574   if (!bg_image_mode_solid) {
575     SetPreprocVar("bg_image_mode_1_or_3", (bg_image_mode == 1 || bg_image_mode == 3));
576     SetPreprocVar("bg_image_mode_2_or_3", (bg_image_mode == 2 || bg_image_mode == 3));
577   }
578 
579 #ifndef PYMOL_EDU
580   SetPreprocVar("volume_mode", SettingGetGlobal_i(G, cSetting_volume_mode));
581 #endif
582 
583   SetPreprocVar("ortho", SettingGetGlobal_i(G, cSetting_ortho));
584   SetPreprocVar("depth_cue", SettingGetGlobal_b(G, cSetting_depth_cue)
585       && SettingGetGlobal_b(G, cSetting_fog) != 0.0F);
586 
587 #ifndef PURE_OPENGL_ES_2
588   SetPreprocVar("use_geometry_shaders", SettingGetGlobal_b(G, cSetting_use_geometry_shaders));
589 #endif
590 
591   SetPreprocVar("line_smooth", SettingGetGlobal_b(G, cSetting_line_smooth));
592 
593   stereo = SettingGetGlobal_i(G, cSetting_stereo);
594   stereo_mode = SettingGetGlobal_i(G, cSetting_stereo_mode);
595 
596 #ifdef _PYMOL_OPENVR
597   SetPreprocVar("openvr_enabled", stereo && stereo_mode == cStereo_openvr);
598 #endif
599 
600   SetPreprocVar("ANAGLYPH", stereo && stereo_mode == cStereo_anaglyph);
601   SetPreprocVar("ray_trace_mode_3", SettingGetGlobal_i(G, cSetting_ray_trace_mode) == 3);
602   SetPreprocVar("transparency_mode_3", SettingGetGlobal_i(G, cSetting_transparency_mode)==3);
603 
604 #ifndef _PYMOL_NO_AA_SHADERS
605 #endif
606 
607   SetPreprocVar("precomputed_lighting", SettingGetGlobal_b(G, cSetting_precomputed_lighting));
608   SetPreprocVar("ray_transparency_oblique", SettingGetGlobal_f(G, cSetting_ray_transparency_oblique) > R_SMALL4);
609 
610   int chromadepth = SettingGetGlobal_i(G, cSetting_chromadepth);
611   SetPreprocVar("chromadepth", chromadepth != 0);
612   SetPreprocVar("chromadepth_postlighting", chromadepth == 2);
613 }
614 
615 /* ============================================================================
616  * ShaderMgrInit is called from PyMOL.c during start up; it just allocates
617  * the global ShaderMgr
618  */
ShaderMgrInit(PyMOLGlobals * G)619 bool ShaderMgrInit(PyMOLGlobals * G) {
620   // initialize some globals (do this only once)
621   if (preprocmap.empty()) {
622     preprocmap["#ifdef"] = LOOKUP | IFDEF;
623     preprocmap["#ifndef"] = LOOKUP | IFDEF | IFNDEF;
624     preprocmap["#else"] = ELSE;
625     preprocmap["#endif"] = ENDIF;
626     preprocmap["#include"] = LOOKUP | INCLUDE;
627 
628     // make #include dependency map from flat array
629     for (const char ** ptr = _include_deps; *ptr; ++ptr) {
630       include_deps[ptr[0]] = ptr + 1;
631       while (*(++ptr)) {}
632     }
633 
634     // make #ifdef dependency map from flat array
635     for (const char ** ptr = _ifdef_deps; *ptr; ++ptr) {
636       ifdef_deps[ptr[0]] = ptr + 1;
637       while (*(++ptr)) {}
638     }
639 
640     // make shader file cache from flat array
641     for (const char ** ptr = _shader_cache_raw; *ptr; ptr += 2) {
642       shader_cache_raw[ptr[0]] = *(ptr + 1);
643     }
644   }
645 
646   G->ShaderMgr = new CShaderMgr(G);
647 
648   if(!G->ShaderMgr)
649     return false;
650 
651   return true;
652 }
653 
654 /*
655  * Print the given message as ShaderMgr-Error, followed by the shader info log.
656  */
ErrorMsgWithShaderInfoLog(const GLuint sid,const char * msg)657 void CShaderPrg::ErrorMsgWithShaderInfoLog(const GLuint sid, const char * msg) {
658   if (!G->Option || G->Option->quiet)
659     return;
660 
661   GLint infoLogLength = 0;
662   glGetShaderiv(sid, GL_INFO_LOG_LENGTH, &infoLogLength);
663   vector<GLchar> infoLog(infoLogLength);
664   glGetShaderInfoLog(sid, infoLogLength, nullptr, infoLog.data());
665 
666   PRINTFB(G, FB_ShaderPrg, FB_Errors) " ShaderPrg-Error: %s; name='%s'\n",
667     msg, name.c_str() ENDFB(G);
668 
669   PRINTFB(G, FB_ShaderPrg, FB_Errors) " ShaderPrg-Error-InfoLog:\n%s\n",
670     infoLog.data() ENDFB(G);
671 }
672 
673 /* ShaderMgrConfig -- Called from PyMOL.c, configures the global ShaderMgr
674  * This needs to be called once the OpenGL context has been created, it is
675  * called from MainInit() for PyMol, and from PyMOL_ConfigureShadersGL() for
676  * other programs (i.e., JyMOL, AxPyMOL, etc.).
677  */
Config()678 void CShaderMgr::Config() {
679   if (!G || !G->HaveGUI) /* && G->ValidContext); */
680     return;
681 
682   glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, line_width_range);
683 
684 #ifndef PURE_OPENGL_ES_2
685   GLenum err = glewInit();
686 
687   if (GLEW_OK==err) {
688     GLint gl_major = 0, gl_minor = 0;
689     getGLVersion(G, &gl_major, &gl_minor);
690 
691     PRINTFB(G, FB_ShaderMgr, FB_Details)
692       " Detected OpenGL version %d.%d.", gl_major, gl_minor ENDFB(G);
693 
694     if (GLEW_VERSION_2_0) {
695       G->Feedback->add(" Shaders available.\n");
696     }
697     else {
698       G->Feedback->add(" Shaders and volumes unavailable.\n");
699       disableShaders(G);
700       return;
701     }
702   }
703   else {
704     /* print info on glew error? */
705     G->Feedback->add(" There was an error intializing GLEW.  Basic graphics, including\n shaders and volumes may be unavailable.\n");
706     disableShaders(G);
707     fprintf(stderr, " GLEW-Error: %s\n", glewGetErrorString(err));
708     return;
709   }
710 #endif
711 
712   // static preprocessor values
713   preproc_vars["GLEW_VERSION_3_0"] = GLEW_VERSION_3_0 ? true : false;
714   if (TM3_IS_ONEBUF){
715     preproc_vars["ONE_DRAW_BUFFER"] = true;
716   }
717 #ifdef PURE_OPENGL_ES_2
718   preproc_vars["PURE_OPENGL_ES_2"] = 1;
719   preproc_vars["PYMOL_WEBGL"] = 1;
720   preproc_vars["PYMOL_WEBGL_IOS"] = 1;
721 #else
722   preproc_vars["gl_VertexID_enabled"] = GLEW_EXT_gpu_shader4;
723 #endif
724 
725   // shaders
726 #define make_program(name, ...) programs[name] = new CShaderPrg(G, name, __VA_ARGS__)
727 
728   make_program("bg", "bg.vs", "bg.fs");
729   make_program("indicator", "indicator.vs", "indicator.fs");
730   make_program("label", "label.vs", "label.fs");
731 
732 #ifndef PURE_OPENGL_ES_2
733   make_program("volume", "volume.vs", "volume.fs");
734 #endif
735 
736   make_program("default", "default.vs", "default.fs");
737   make_program("surface", "surface.vs", "surface.fs");
738 
739   make_program("line", "line.vs", "line.fs");
740 
741   make_program("screen", "screen.vs", "screen.fs");
742 
743   if (GLEW_EXT_geometry_shader4 && GLEW_EXT_gpu_shader4){
744     make_program("connector", "connector.vs", "connector.fs",
745 		 "connector.gs", GL_POINTS, GL_TRIANGLE_STRIP, CONNECTOR_GS_NUM_VERTICES);
746   } else {
747     make_program("connector", "connector.vs", "connector.fs");
748   }
749 
750   if (GET_FRAGDEPTH_SUPPORT()) {
751     make_program("cylinder", "cylinder.vs", "cylinder.fs");
752     make_program("sphere", "sphere.vs", "sphere.fs");
753   }
754 
755   make_program("ramp", "ramp.vs", "ramp.fs");
756   programs["ramp"]->uniformLocations[RAMP_OFFSETPT] = "offsetPt";
757 
758   make_program("oit", "oit.vs", "oit.fs");
759   make_program("copy", "copy.vs", "copy.fs");
760   make_program("trilines", "trilines.vs", "trilines.fs");
761 
762   Reload_Shader_Variables();
763   Reload_CallComputeColorForLight();
764 
765   // shaders availability test
766   ok_assert(1, programs["default"]->reload());
767 
768 #ifndef PURE_OPENGL_ES_2
769   // geometry shaders availability test
770   if (programs["connector"]->reload() && programs["connector"]->gid) {
771     shaders_present |= MASK_SHADERS_PRESENT_GEOMETRY;
772   } else {
773     disableGeometryShaders(G);
774   }
775 #else
776   SettingSetGlobal_b(G, cSetting_use_geometry_shaders, 0);
777 #endif
778 
779 #define check_program(name, setting, value) {   \
780     if (!programs[name]->reload()) {            \
781       SettingSetGlobal_i(G, setting, value);    \
782       programs.erase(name);                     \
783     }}                                          \
784   // other shader compilation tests
785   if (GET_FRAGDEPTH_SUPPORT()) {
786   check_program("cylinder", cSetting_render_as_cylinders, 0);
787   check_program("sphere", cSetting_sphere_mode, 0);
788   }
789 
790 #ifndef _PYMOL_NO_AA_SHADERS
791 #endif
792 
793   // get filename -> shader program dependencies
794   for (auto& prog : programs) {
795     RegisterDependantFileNames(prog.second);
796   }
797 
798   // make transparency_mode_3 shader derivatives
799   MakeDerivatives("_t", "NO_ORDER_TRANSP");
800 
801 #ifndef PURE_OPENGL_ES_2
802   /* report GLSL version */
803   if (G && G->Option && !G->Option->quiet) {
804     char buf[50];
805     int major, minor;
806     getGLSLVersion(G, &major, &minor);
807     sprintf(buf, " Detected GLSL version %d.%d.\n", major, minor);
808     G->Feedback->add(buf);
809   }
810 #endif
811   shaders_present |= 0x1;
812   SettingSetGlobal_b(G, cSetting_use_shaders, true);
813 
814   is_configured = true;
815   return;
816 ok_except1:
817   disableShaders(G);
818   G->ShaderMgr->shaders_present = 0;
819   is_configured = true;
820 }
821 
822 /* getGLVersion -- determine user's GL version
823  * PARAMS
824  * major, return value for major
825  * minor, return value for minor
826  *
827  * RETURNS
828  * nothing; writes to major and minor
829  */
getGLVersion(PyMOLGlobals * G,int * major,int * minor)830 void getGLVersion(PyMOLGlobals * G, int *major, int* minor) {
831   /* query the version string */
832   const char* verstr = (const char*) glGetString(GL_VERSION);
833   /* attempt to store the values into major and minor */
834   if (!verstr || sscanf(verstr, "%d.%d", major, minor) != 2) {
835     *major = *minor = 0;
836     /* Use PyMOL FB system, instead of fprintf */
837     PRINTFD(G, FB_ObjectVolume)
838       "Invalid GL_VERSION format.\n" ENDFD;
839   }
840 }
841 
842 
843 /* getGLSLVersion -- determine user's GLSL version
844  * PARAMS
845  * major, rval for major
846  * minor, rval for minor
847  */
848 #ifndef PURE_OPENGL_ES_2
getGLSLVersion(PyMOLGlobals * G,int * major,int * minor)849 void getGLSLVersion(PyMOLGlobals * G, int* major, int* minor) {
850   int gl_major, gl_minor;
851   *major = *minor = 0;
852 
853   /* grab the GL version */
854   getGLVersion(G, &gl_major, &gl_minor);
855 
856   /* GL version 1 */
857   if (1==gl_major) {
858     const char* extstr = (const char*) glGetString(GL_EXTENSIONS);
859     if (extstr && strstr(extstr, "GL_ARB_shading_language_100")) {
860       *major = 1;
861       *minor = 0;
862     }
863   }
864   /* GL > version 1 */
865   else if (gl_major>=2) {
866     const char* verstr = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION);
867 
868     if (!verstr || sscanf(verstr, "%d.%d", major, minor) != 2) {
869       *major = *minor = 0;
870 
871       if (G && G->Option && !G->Option->quiet) {
872         PRINTFD(G, FB_ObjectVolume)
873           "Invalid GL_SHADING_LANGUAGE_VERSION format.\n" ENDFD;
874       }
875     }
876   }
877 }
878 #endif
879 
880 
881 
882 /* ============================================================================
883  * CShaderMgr -- Simple Shader Manager class
884  */
CShaderMgr(PyMOLGlobals * G_)885 CShaderMgr::CShaderMgr(PyMOLGlobals * G_)
886 {
887   G = G_;
888   current_shader = nullptr;
889   shaders_present = 0;
890   stereo_flag = 0;
891   stereo_blend = 0;
892 #ifdef _PYMOL_LIB
893   print_warnings = 0;
894 #else
895   print_warnings = 1;
896 #endif
897 
898   lightingTexture = 0;
899   is_picking = 0;
900   reload_bits = RELOAD_ALL_SHADERS;
901 
902 #ifndef _WEBGL
903   vbos_to_free.reserve(256);
904 #endif
905 }
906 
~CShaderMgr()907 CShaderMgr::~CShaderMgr() {
908   for (auto& prog : programs) {
909     delete prog.second;
910   }
911   programs.clear();
912 
913   shader_cache_processed.clear();
914 
915   freeGPUBuffer(offscreen_rt);
916 
917   FreeAllVBOs();
918 }
919 
AddShaderPrg(CShaderPrg * s)920 int CShaderMgr::AddShaderPrg(CShaderPrg * s) {
921   if (!s)
922     return 0;
923   const string& name = s->name;
924   if (programs.find(name)!=programs.end()){
925     delete programs[name];
926   }
927   programs[name] = s;
928   return 1;
929 }
930 
RemoveShaderPrg(const string & name)931 int CShaderMgr::RemoveShaderPrg(const string& name) {
932   if (programs.find(name) != programs.end()){
933     delete programs[name];
934   }
935   return 1;
936 }
937 
938 /*
939  * Lookup a shader program by name and set it as the `current_shader` of the
940  * shader manager. If `pass` is provided and is less than zero, and we are
941  * in transparency_mode 3, then look up the NO_ORDER_TRANSP derivative.h
942  */
GetShaderPrg(std::string name,short set_current_shader,short pass)943 CShaderPrg * CShaderMgr::GetShaderPrg(std::string name, short set_current_shader, short pass) {
944   if (pass < 0 && SettingGetGlobal_i(G, cSetting_transparency_mode) == 3) {
945     name += "_t";
946   }
947 
948   auto it = programs.find(name);
949   if (it == programs.end())
950     return nullptr;
951 
952   if (set_current_shader)
953     current_shader = it->second;
954 
955   return it->second;
956 }
957 
ShaderPrgExists(const char * name)958 int CShaderMgr::ShaderPrgExists(const char * name){
959   return (programs.find(name) != programs.end());
960 }
961 
ShadersPresent()962 int CShaderMgr::ShadersPresent() {
963   return shaders_present;
964 }
965 
GeometryShadersPresent()966 int CShaderMgr::GeometryShadersPresent() {
967   return shaders_present & MASK_SHADERS_PRESENT_GEOMETRY;
968 }
969 
970 /*
971  * glDeleteBuffers for vbos_to_free
972  */
FreeAllVBOs()973 void CShaderMgr::FreeAllVBOs() {
974 #ifndef _WEBGL
975   freeAllGPUBuffers();
976 
977   LOCK_GUARD_MUTEX(lock, vbos_to_free_mutex);
978 
979   if (vbos_to_free.empty())
980     return;
981 
982   glDeleteBuffers(vbos_to_free.size(), &vbos_to_free[0]);
983 
984   vbos_to_free.clear();
985 #endif
986 }
987 
AddVBOsToFree(GLuint * vboid,int nvbos)988 void CShaderMgr::AddVBOsToFree(GLuint *vboid, int nvbos){
989   int i;
990   for (i=0; i<nvbos; i++){
991     if (vboid[i]>0)
992         AddVBOToFree(vboid[i]);
993   }
994 }
995 
996 /*
997  * thread-safe deferred glDeleteBuffers(1, &vboid)
998  */
AddVBOToFree(GLuint vboid)999 void CShaderMgr::AddVBOToFree(GLuint vboid){
1000 #ifdef _WEBGL // No threads, immediately delete
1001   if (glIsBuffer(vboid)) {
1002     glDeleteBuffers(1, &vboid);
1003   } else {
1004     PRINTFB(G, FB_ShaderMgr, FB_Warnings) "WARNING: CShaderMgr_AddVBOToFree() buffer is not a VBO %d", vboid ENDFB(G);
1005   }
1006 #else
1007   LOCK_GUARD_MUTEX(lock, vbos_to_free_mutex);
1008   vbos_to_free.push_back(vboid);
1009 #endif
1010 }
1011 
Enable_DefaultShaderWithSettings(const CSetting * set1,const CSetting * set2,int pass)1012 CShaderPrg *CShaderMgr::Enable_DefaultShaderWithSettings(
1013     const CSetting *set1,
1014     const CSetting *set2, int pass) {
1015   CShaderPrg * shaderPrg = Get_DefaultShader(pass);
1016   return Setup_DefaultShader(shaderPrg, set1, set2);
1017 }
1018 
Enable_DefaultShader(int pass)1019 CShaderPrg *CShaderMgr::Enable_DefaultShader(int pass){
1020   CShaderPrg * shaderPrg = Get_DefaultShader(pass);
1021   return Setup_DefaultShader(shaderPrg, nullptr, nullptr);
1022 }
1023 
Enable_LineShader(int pass)1024 CShaderPrg *CShaderMgr::Enable_LineShader(int pass){
1025   CShaderPrg * shaderPrg = Get_LineShader(pass);
1026   return Setup_DefaultShader(shaderPrg, nullptr, nullptr);
1027 }
1028 
Enable_SurfaceShader(int pass)1029 CShaderPrg *CShaderMgr::Enable_SurfaceShader(int pass){
1030   CShaderPrg * shaderPrg = Get_SurfaceShader(pass);
1031   return Setup_DefaultShader(shaderPrg, nullptr, nullptr);
1032 }
1033 
Enable_ConnectorShader(int pass)1034 CShaderPrg *CShaderMgr::Enable_ConnectorShader(int pass){
1035   CShaderPrg * shaderPrg = Get_ConnectorShader(pass);
1036   if (!shaderPrg)
1037     return nullptr;
1038   shaderPrg = Setup_DefaultShader(shaderPrg, nullptr, nullptr);
1039   shaderPrg->SetLightingEnabled(0);
1040   {
1041     float front, back;
1042     front = SceneGetCurrentFrontSafe(G);
1043     back = SceneGetCurrentBackSafe(G);
1044     shaderPrg->Set1f("front", front);
1045     shaderPrg->Set1f("clipRange", back - front);
1046   }
1047 
1048   int width, height;
1049   SceneGetWidthHeightStereo(G, &width, &height);
1050   shaderPrg->Set2f("screenSize", width, height);
1051 
1052   {
1053     float v_scale = SceneGetScreenVertexScale(G, nullptr);
1054     shaderPrg->Set1f("screenOriginVertexScale", v_scale/2.f);
1055   }
1056 
1057   return shaderPrg;
1058 }
1059 
Setup_DefaultShader(CShaderPrg * shaderPrg,const CSetting * set1,const CSetting * set2)1060 CShaderPrg *CShaderMgr::Setup_DefaultShader(CShaderPrg * shaderPrg,
1061     const CSetting *set1,
1062     const CSetting *set2) {
1063   if (!shaderPrg){
1064     current_shader = nullptr;
1065     return shaderPrg;
1066   }
1067   shaderPrg->Enable();
1068   shaderPrg->SetBgUniforms();
1069   shaderPrg->Set_Stereo_And_AnaglyphMode();
1070 
1071   bool two_sided_lighting_enabled = SceneGetTwoSidedLightingSettings(G, set1, set2);
1072 
1073   shaderPrg->SetLightingEnabled(1); // lighting on by default
1074   shaderPrg->Set1i("two_sided_lighting_enabled", two_sided_lighting_enabled);
1075   shaderPrg->Set1f("ambient_occlusion_scale", 0.f);
1076   shaderPrg->Set1i("accessibility_mode", SettingGetGlobal_i(G, cSetting_ambient_occlusion_mode) / 4);
1077   shaderPrg->Set1f("accessibility_mode_on", SettingGetGlobal_i(G, cSetting_ambient_occlusion_mode) ? 1.f : 0.f);
1078 
1079   // interior_color
1080   {
1081     int interior_color = SettingGet_i(G, set1, set2, cSetting_ray_interior_color);
1082     if (interior_color == cColorDefault || two_sided_lighting_enabled) {
1083       shaderPrg->Set1i("use_interior_color", 0);
1084     } else {
1085       float inter[] = { 0.f, 0.f, 0.f };
1086       ColorGetEncoded(G, interior_color, inter);
1087       shaderPrg->Set1i("use_interior_color", 1);
1088       shaderPrg->Set4f("interior_color", inter[0], inter[1], inter[2], 1.f);
1089     }
1090   }
1091 
1092   shaderPrg->Set_Specular_Values();
1093   shaderPrg->Set_Matrices();
1094   return (shaderPrg);
1095 }
Enable_CylinderShader(int pass)1096 CShaderPrg *CShaderMgr::Enable_CylinderShader(int pass){
1097   return Enable_CylinderShader("cylinder", pass);
1098 }
1099 
Enable_CylinderShader(const char * shader_name,int pass)1100 CShaderPrg *CShaderMgr::Enable_CylinderShader(const char *shader_name, int pass){
1101   int width, height;
1102   CShaderPrg *shaderPrg;
1103 
1104   SceneGetWidthHeightStereo(G, &width, &height);
1105   shaderPrg = GetShaderPrg(shader_name, 1, pass);
1106   if (!shaderPrg)
1107       return nullptr;
1108   shaderPrg->Enable();
1109 
1110   shaderPrg->SetLightingEnabled(1); // lighting on by default
1111 
1112   shaderPrg->Set1f("uni_radius", 0.f);
1113 
1114   shaderPrg->Set_Stereo_And_AnaglyphMode();
1115 
1116   shaderPrg->Set1f("inv_height", 1.0/height);
1117   shaderPrg->Set1i("no_flat_caps", 1);
1118   {
1119     float smooth_half_bonds = (SettingGetGlobal_i(G, cSetting_smooth_half_bonds)) ? .2f : 0.f;
1120     shaderPrg->Set1f("half_bond", smooth_half_bonds);
1121   }
1122   shaderPrg->Set_Specular_Values();
1123   shaderPrg->Set_Matrices();
1124 
1125   shaderPrg->SetBgUniforms();
1126 
1127   // always enable backface culling for cylinders
1128   glCullFace(GL_BACK);
1129   glEnable(GL_CULL_FACE);
1130   return shaderPrg;
1131 }
1132 
Get_DefaultSphereShader(int pass)1133 CShaderPrg *CShaderMgr::Get_DefaultSphereShader(int pass){
1134   return GetShaderPrg("sphere", 1, pass);
1135 }
1136 
1137 
Enable_DefaultSphereShader(int pass)1138 CShaderPrg *CShaderMgr::Enable_DefaultSphereShader(int pass) {
1139   CShaderPrg *shaderPrg = Get_DefaultSphereShader(pass);
1140   if (!shaderPrg) return nullptr;
1141   shaderPrg->Enable();
1142   shaderPrg->SetLightingEnabled(1);
1143   shaderPrg->Set1f("sphere_size_scale", 1.f);
1144 
1145   shaderPrg->Set_Stereo_And_AnaglyphMode();
1146 
1147   shaderPrg->Set_Specular_Values();
1148   shaderPrg->Set_Matrices();
1149 
1150   shaderPrg->SetBgUniforms();
1151 
1152   return (shaderPrg);
1153 }
1154 
1155 #ifdef _PYMOL_ARB_SHADERS
Enable_SphereShaderARB()1156 CShaderPrg *CShaderMgr::Enable_SphereShaderARB(){
1157   CShaderPrg *shaderPrg = nullptr;
1158   /* load the vertex program */
1159   Disable_Current_Shader();
1160   shaderPrg = GetShaderPrg("sphere_arb");
1161   glBindProgramARB(GL_VERTEX_PROGRAM_ARB, shaderPrg->vid);
1162 
1163   /* load the fragment program */
1164   glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shaderPrg->fid);
1165 
1166   /* load some safe initial values  */
1167   glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, 0, 0.0F, 0.0F, 1.0F, 0.0F);
1168   glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, 0.5F, 2.0F, 0.0F, 0.0F);
1169 
1170   glEnable(GL_VERTEX_PROGRAM_ARB);
1171   glEnable(GL_FRAGMENT_PROGRAM_ARB);
1172 
1173   return shaderPrg;
1174 }
1175 #endif
1176 
Get_ConnectorShader(int pass)1177 CShaderPrg *CShaderMgr::Get_ConnectorShader(int pass){
1178   return GetShaderPrg("connector", 1, pass);
1179 }
1180 
Get_DefaultShader(int pass)1181 CShaderPrg *CShaderMgr::Get_DefaultShader(int pass){
1182   return GetShaderPrg("default", 1, pass);
1183 }
1184 
Get_LineShader(int pass)1185 CShaderPrg *CShaderMgr::Get_LineShader(int pass){
1186   return GetShaderPrg("line", 1, pass);
1187 }
1188 
Get_SurfaceShader(int pass)1189 CShaderPrg *CShaderMgr::Get_SurfaceShader(int pass){
1190   return GetShaderPrg("surface", 1, pass);
1191 }
1192 
Get_CylinderShader(int pass,short set_current_shader)1193 CShaderPrg *CShaderMgr::Get_CylinderShader(int pass, short set_current_shader) {
1194   return GetShaderPrg("cylinder", set_current_shader, pass);
1195 }
1196 
Get_CylinderNewShader(int pass,short set_current_shader)1197 CShaderPrg *CShaderMgr::Get_CylinderNewShader(int pass, short set_current_shader) {
1198   return GetShaderPrg("cylinder_new", set_current_shader, pass);
1199 }
1200 
Get_Current_Shader()1201 CShaderPrg *CShaderMgr::Get_Current_Shader(){
1202   return current_shader;
1203 }
1204 
Get_BackgroundShader()1205 CShaderPrg *CShaderMgr::Get_BackgroundShader(){
1206   return GetShaderPrg("bg");
1207 }
1208 
Enable_BackgroundShader()1209 CShaderPrg *CShaderMgr::Enable_BackgroundShader(){
1210   CShaderPrg * shaderPrg = Get_BackgroundShader();
1211   if (!shaderPrg) return shaderPrg;
1212   shaderPrg->Enable();
1213 
1214   glDisable(GL_DEPTH_TEST);
1215   shaderPrg->SetBgUniforms();
1216 
1217   return shaderPrg;
1218 }
1219 
Enable_TriLinesShader()1220 CShaderPrg *CShaderMgr::Enable_TriLinesShader() {
1221   CShaderPrg * shaderPrg = GetShaderPrg("trilines");
1222   if (!shaderPrg) return shaderPrg;
1223   shaderPrg->Enable();
1224   shaderPrg->SetBgUniforms();
1225   shaderPrg->Set_Stereo_And_AnaglyphMode();
1226   shaderPrg->Set_Matrices();
1227   {
1228     int width, height;
1229     SceneGetWidthHeightStereo(G, &width, &height);
1230 
1231       shaderPrg->Set2f("inv_dimensions", 1.f/width, 1.f/height);
1232   }
1233   return shaderPrg;
1234 }
1235 
1236 #ifndef _PYMOL_NO_AA_SHADERS
1237 #endif
1238 
Enable_OITShader()1239 CShaderPrg *CShaderMgr::Enable_OITShader() {
1240   CShaderPrg * shaderPrg = GetShaderPrg("oit");
1241   if (!shaderPrg) return shaderPrg;
1242   shaderPrg->Enable();
1243 
1244   constexpr GLuint accumTexUnit = 5;
1245   constexpr GLuint revealageTexUnit = 6;
1246   oit_pp->activateRTAsTexture(OIT_PostProcess::OITRT::ACCUM, accumTexUnit);
1247   oit_pp->activateRTAsTexture(OIT_PostProcess::OITRT::REVEALAGE, revealageTexUnit);
1248   shaderPrg->Set1i("accumTex", accumTexUnit);
1249   shaderPrg->Set1i("revealageTex", revealageTexUnit);
1250   shaderPrg->Set1f("isRight", stereo_flag > 0 ? 1. : 0);
1251   glEnable(GL_BLEND);
1252   glBlendFuncSeparate(
1253       GL_SRC_ALPHA,   GL_ONE_MINUS_SRC_ALPHA,
1254       GL_ONE,         GL_ONE_MINUS_SRC_ALPHA);
1255 
1256   glDisable(GL_DEPTH_TEST);
1257 #ifndef PURE_OPENGL_ES_2
1258   glDisable(GL_ALPHA_TEST);
1259 #endif
1260   return shaderPrg;
1261 }
1262 
Enable_OITCopyShader()1263 CShaderPrg *CShaderMgr::Enable_OITCopyShader() {
1264   CShaderPrg * shaderPrg = GetShaderPrg("copy");
1265   if (!shaderPrg) return shaderPrg;
1266   shaderPrg->Enable();
1267 
1268   constexpr GLuint colorTexUnit = 7;
1269   activateOffscreenTexture(colorTexUnit);
1270   shaderPrg->Set1i("colorTex", colorTexUnit);
1271   if (G->ShaderMgr->stereo_blend){
1272     // for full-screen stereo
1273     glEnable(GL_BLEND);
1274     glBlendFunc(GL_ONE, GL_ONE);
1275   } else {
1276     glDisable(GL_BLEND);
1277   }
1278   glDisable(GL_DEPTH_TEST);
1279 #ifndef PURE_OPENGL_ES_2
1280   glDisable(GL_ALPHA_TEST);
1281 #endif
1282   return shaderPrg;
1283 }
1284 
Enable_LabelShader(int pass)1285 CShaderPrg *CShaderMgr::Enable_LabelShader(int pass){
1286   CShaderPrg *shaderPrg;
1287   shaderPrg = Get_LabelShader(pass);
1288   if (!shaderPrg)
1289       return nullptr;
1290   shaderPrg->Enable();
1291   return Setup_LabelShader(shaderPrg);
1292 }
1293 
Enable_ScreenShader()1294 CShaderPrg *CShaderMgr::Enable_ScreenShader(){
1295   CShaderPrg *shaderPrg;
1296   shaderPrg = Get_ScreenShader();
1297   if (!shaderPrg)
1298       return nullptr;
1299   shaderPrg->Enable();
1300 
1301   int ortho_width, ortho_height;
1302   std::tie(ortho_width, ortho_height) = OrthoGetSize(*G->Ortho);
1303   shaderPrg->Set2f("t2PixelSize", 2.f / ortho_width, 2.f / ortho_height);
1304 
1305   return Setup_LabelShader(shaderPrg);
1306 }
1307 
Enable_RampShader()1308 CShaderPrg *CShaderMgr::Enable_RampShader(){
1309   CShaderPrg *shaderPrg;
1310   shaderPrg = Get_RampShader();
1311   if (!shaderPrg)
1312       return nullptr;
1313   shaderPrg->Enable();
1314   return Setup_LabelShader(shaderPrg);
1315 }
1316 
Setup_LabelShader(CShaderPrg * shaderPrg)1317 CShaderPrg *CShaderMgr::Setup_LabelShader(CShaderPrg *shaderPrg) {
1318   int width = 0, height = 0;
1319 
1320   shaderPrg->Set_Matrices();
1321 
1322   glActiveTexture(GL_TEXTURE3);
1323   glBindTexture(GL_TEXTURE_2D, TextureGetTextTextureID(G));
1324   if (!(shaderPrg->uniform_set & 8)){
1325     shaderPrg->uniform_set |= 8;
1326     shaderPrg->Set1i("textureMap", 3);
1327   }
1328 
1329   SceneGetWidthHeightStereo(G, &width, &height);
1330 
1331   if (width)
1332     shaderPrg->Set2f("screenSize", width, height);
1333 
1334   shaderPrg->SetBgUniforms();
1335 
1336   {
1337     float v_scale = SceneGetScreenVertexScale(G, nullptr);
1338     shaderPrg->Set1f("screenOriginVertexScale", v_scale/2.f);
1339   }
1340   {
1341     float front, back;
1342     front = SceneGetCurrentFrontSafe(G);
1343     back = SceneGetCurrentBackSafe(G);
1344     shaderPrg->Set1f("front", front);
1345     shaderPrg->Set1f("clipRange", back - front);
1346   }
1347 
1348   return shaderPrg;
1349 }
1350 
Get_LabelShader(int pass)1351 CShaderPrg *CShaderMgr::Get_LabelShader(int pass){
1352   return GetShaderPrg("label", 1, pass);
1353 }
1354 
Get_ScreenShader()1355 CShaderPrg *CShaderMgr::Get_ScreenShader() {
1356   if (is_picking)
1357     return nullptr;
1358   return GetShaderPrg("screen");
1359 }
1360 
Get_RampShader()1361 CShaderPrg *CShaderMgr::Get_RampShader() {
1362   return GetShaderPrg("ramp");
1363 }
1364 
Get_IndicatorShader()1365 CShaderPrg *CShaderMgr::Get_IndicatorShader() {
1366   return GetShaderPrg("indicator");
1367 }
1368 
Enable_IndicatorShader()1369 CShaderPrg *CShaderMgr::Enable_IndicatorShader() {
1370   CShaderPrg * shaderPrg = Get_IndicatorShader();
1371   if (!shaderPrg) return shaderPrg;
1372   shaderPrg->Enable();
1373 
1374   shaderPrg->Set_Stereo_And_AnaglyphMode();
1375   shaderPrg->Set_Matrices();
1376 
1377   glActiveTexture(GL_TEXTURE3);
1378   glBindTexture(GL_TEXTURE_2D, TextureGetTextTextureID(G));
1379   if (!(shaderPrg->uniform_set & 8)){
1380     shaderPrg->Set1i("textureMap", 3);
1381     shaderPrg->uniform_set |= 8;
1382   }
1383 #ifdef PURE_OPENGL_ES_2
1384   shaderPrg->SetMat4fc("g_ModelViewMatrix", SceneGetModelViewMatrix(G));
1385   shaderPrg->SetMat4fc("g_ProjectionMatrix", SceneGetProjectionMatrix(G));
1386 #endif
1387 
1388   return (shaderPrg);
1389 }
1390 
1391 
ResetUniformSet()1392 void CShaderMgr::ResetUniformSet() {
1393   for (auto & prog : programs) {
1394     prog.second->uniform_set = 0;
1395   }
1396 }
1397 
SetIsPicking(int is_picking)1398 void CShaderMgr::SetIsPicking(int is_picking) {
1399   this->is_picking = is_picking;
1400 }
GetIsPicking()1401 int CShaderMgr::GetIsPicking() {
1402   return is_picking;
1403 }
1404 
1405 #define LIGHTINGTEXTUREWIDTH 64
1406 
1407 /*
1408  * Lighting setting indices are not contiguous, so we need a mapping array
1409  */
1410 int light_setting_indices[] = {
1411   cSetting_light, cSetting_light2, cSetting_light3, cSetting_light4,
1412   cSetting_light5, cSetting_light6, cSetting_light7, cSetting_light8,
1413   cSetting_light9
1414 };
1415 
1416 /*
1417  * Generate and upload a precomputed vec2(ambient, specular) lighting texture.
1418  *
1419  * Must be equivalent to "ComputeLighting" in "compute_color_for_light.fs"
1420  */
Generate_LightingTexture()1421 void CShaderMgr::Generate_LightingTexture() {
1422   const int light_max = 10;
1423   int light_count = SettingGetGlobal_i(G, cSetting_light_count);
1424   int spec_count = SettingGetGlobal_i(G, cSetting_spec_count);
1425   float ambient = SettingGetGlobal_f(G, cSetting_ambient);
1426   float direct = SettingGetGlobal_f(G, cSetting_direct);
1427   float reflect = SettingGetGlobal_f(G, cSetting_reflect) * SceneGetReflectScaleValue(G, light_max);
1428   float shininess, spec_value;
1429   float shininess_0, spec_value_0;
1430   float diffuse, spec, shine;
1431   float power, power_0 = SettingGetGlobal_f(G, cSetting_power);
1432   float reflect_power = SettingGetGlobal_f(G, cSetting_reflect_power);
1433 
1434   float light_positions[light_max][3] = {{0.F, 0.F, 1.F}};
1435 
1436   // (ambient, specular) 2D texture
1437   unsigned char texture_AS[LIGHTINGTEXTUREWIDTH][LIGHTINGTEXTUREWIDTH][2];
1438 
1439   SceneGetAdjustedLightValues(G,
1440       &spec_value,
1441       &shininess,
1442       &spec_value_0,
1443       &shininess_0,
1444       light_max);
1445 
1446   if (light_count < 2) {
1447     light_count = 1;
1448     direct += reflect;
1449   } else if (light_count > light_max) {
1450     light_count = light_max;
1451   }
1452 
1453   if(spec_count < 0) {
1454     spec_count = light_count - 1;
1455   }
1456 
1457   for (int i = 1; i < light_count; ++i) {
1458     const float * setting = SettingGetGlobal_3fv(G, light_setting_indices[i - 1]);
1459     copy3f(setting, light_positions[i]);
1460     normalize3f(light_positions[i]);
1461     invert3f(light_positions[i]);
1462   }
1463 
1464   glGenTextures(1, &lightingTexture);
1465 
1466   glActiveTexture(GL_TEXTURE1);
1467   glBindTexture(GL_TEXTURE_CUBE_MAP, lightingTexture);
1468   glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1469   glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1470 
1471 #ifndef PURE_OPENGL_ES_2
1472   glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
1473 #else
1474   glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1475   glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1476 #endif
1477 
1478   float normal[3];
1479   const float vz = LIGHTINGTEXTUREWIDTH / 2;
1480 
1481   for (int face = 0; face < 6; ++face) {
1482     for (int y = 0; y < LIGHTINGTEXTUREWIDTH; ++y) {
1483       for (int x = 0; x < LIGHTINGTEXTUREWIDTH; ++x) {
1484 
1485         float vx =   x + .5f - vz;
1486         float vy = -(y + .5f - vz);
1487 
1488         switch (face) {
1489           case 0: set3f(normal,  vz,  vy, -vx); break;
1490           case 1: set3f(normal, -vz,  vy,  vx); break;
1491           case 2: set3f(normal,  vx,  vz, -vy); break;
1492           case 3: set3f(normal,  vx, -vz,  vy); break;
1493           case 4: set3f(normal,  vx,  vy,  vz); break;
1494           case 5: set3f(normal, -vx,  vy, -vz); break;
1495         }
1496 
1497         normalize3f(normal);
1498 
1499         float ambient_sum = ambient;
1500         float specular_sum = 0.F;
1501 
1502         for (int i = 0; i < light_count; ++i) {
1503           if (i == 0) {
1504             diffuse = direct;
1505             spec = spec_value_0;
1506             shine = shininess_0;
1507             power = power_0;
1508           } else {
1509             diffuse = reflect;
1510             spec = spec_value;
1511             shine = shininess;
1512             power = reflect_power;
1513           }
1514 
1515           // light direction (normalized)
1516           const float * L = light_positions[i];
1517 
1518           // cosine of angle between normal and light
1519           float NdotL = dot_product3f(normal, L);
1520 
1521           // normal points away from light
1522           if (NdotL <= 0.0)
1523             continue;
1524 
1525           // power/reflect_power, was ray trace only until 1.7.7
1526           NdotL = pow(NdotL, power);
1527 
1528           // diffuse
1529           ambient_sum += NdotL * diffuse;
1530 
1531           // specular
1532           if (i <= spec_count) {
1533             // H = normalize(L + vec3(0., 0., 1.));
1534             float H[] = {0., 0., 1.};
1535             add3f(L, H, H);
1536             normalize3f(H);
1537 
1538             float NdotH = std::max(dot_product3f(normal, H), 0.f);
1539             specular_sum += spec * pow(NdotH, shine);
1540           }
1541         }
1542 
1543         texture_AS[y][x][0] = pymol_roundf(255.F * std::min(1.F, ambient_sum));
1544         texture_AS[y][x][1] = pymol_roundf(255.F * std::min(1.F, specular_sum));
1545       }
1546     }
1547 
1548     glTexImage2D(
1549         GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
1550         /* level */ 0,
1551         /* internalformat */ GL_LUMINANCE_ALPHA,
1552         /* width  */ LIGHTINGTEXTUREWIDTH,
1553         /* height */ LIGHTINGTEXTUREWIDTH,
1554         /* border */ 0,
1555         /* format */ GL_LUMINANCE_ALPHA,
1556         /* type */ GL_UNSIGNED_BYTE,
1557         /* data */ (void*) texture_AS);
1558   }
1559 }
1560 
Set_Reload_Bits(int bits)1561 void CShaderMgr::Set_Reload_Bits(int bits){
1562   reload_bits |= bits;
1563 }
1564 
Check_Reload()1565 void CShaderMgr::Check_Reload() {
1566   if(!SettingGetGlobal_b(G, cSetting_use_shaders)) {
1567     return;
1568   }
1569 
1570   if (reload_bits){
1571     if (reload_bits == RELOAD_ALL_SHADERS) {
1572       for (auto& prog : programs)
1573         prog.second->is_valid = false;
1574       shader_cache_processed.clear();
1575     }
1576 
1577     Reload_All_Shaders();
1578     reload_bits = 0;
1579   }
1580 }
1581 
GetLineWidthRange()1582 GLfloat *CShaderMgr::GetLineWidthRange() {
1583   return line_width_range;
1584 }
1585 
1586 #ifndef _PYMOL_NO_AA_SHADERS
1587 #endif
1588 
1589 /*
1590  * Register filename -> shader dependencies for `shader`
1591  */
RegisterDependantFileNames(CShaderPrg * shader)1592 void CShaderMgr::RegisterDependantFileNames(CShaderPrg * shader) {
1593   shader_deps[shader->vertfile].push_back(shader->name);
1594   shader_deps[shader->fragfile].push_back(shader->name);
1595   if (!shader->geomfile.empty())
1596     shader_deps[shader->geomfile].push_back(shader->name);
1597 }
1598 
1599 /*
1600  * Recursive function to insert `filename` and all the files where
1601  * `filename` is included into the given output vector.
1602  */
CollectDependantFileNames(const std::string & filename,std::vector<std::string> & filenames)1603 void CShaderMgr::CollectDependantFileNames(const std::string &filename,
1604     std::vector<std::string> &filenames) {
1605   auto it = include_deps.find(filename);
1606   if (it != include_deps.end()) {
1607     for (const char ** filenameptr = it->second;
1608         *filenameptr; ++filenameptr) {
1609       CollectDependantFileNames(*filenameptr, filenames);
1610     }
1611   }
1612   filenames.push_back(filename);
1613 }
1614 
1615 /*
1616  * Make derived shaders for all shaders that depend on `variable`
1617  */
MakeDerivatives(const std::string & suffix,const std::string & variable)1618 void CShaderMgr::MakeDerivatives(const std::string &suffix, const std::string &variable) {
1619   std::set<std::string> shadernames;
1620   std::vector<std::string> filenames;
1621 
1622   // variable -> files
1623   for (const char ** filenameptr = ifdef_deps[variable];
1624       *filenameptr; ++filenameptr) {
1625     CollectDependantFileNames(*filenameptr, filenames);
1626   }
1627 
1628   // files -> shaders
1629   for (auto& filename : filenames) {
1630     auto &vec = shader_deps[filename];
1631     for (auto& n_it : vec) {
1632       shadernames.insert(n_it);
1633     }
1634   }
1635 
1636   // create shader derivatives
1637   for (const auto& shadername : shadernames) {
1638     auto shader = programs[shadername]->DerivativeCopy(shadername + suffix, variable);
1639     programs[shader->name] = shader;
1640 
1641     // register dependency
1642     RegisterDependantFileNames(shader);
1643   }
1644 }
1645 
1646 /*
1647  * Reload the derivative shaders for `variable`
1648  */
Reload_Derivatives(const std::string & variable,bool value)1649 void CShaderMgr::Reload_Derivatives(const std::string &variable, bool value) {
1650   SetPreprocVar(variable, value, false);
1651 
1652   for (auto& prog : programs) {
1653     if (prog.second->derivative == variable)
1654       prog.second->reload();
1655   }
1656 
1657   SetPreprocVar(variable, !value, false);
1658 }
1659 
1660 /*
1661  * Removes `filename` and all it's parents from the shader source cache,
1662  * and if `invshaders` is true, also clear the `is_valid` flag for all
1663  * shader infos that depend on `filename`.
1664  */
ShaderSourceInvalidate(const char * filename,bool invshaders)1665 void CShaderMgr::ShaderSourceInvalidate(const char * filename, bool invshaders) {
1666   // recursion for includes
1667   auto it = include_deps.find(filename);
1668   if (it != include_deps.end()) {
1669     for (const char ** filenameptr = it->second;
1670         *filenameptr; ++filenameptr) {
1671       ShaderSourceInvalidate(*filenameptr, invshaders);
1672     }
1673   }
1674 
1675   // invalidate shaders
1676   if (invshaders) {
1677     auto &vec = shader_deps[filename];
1678     for (const auto& shadername : vec) {
1679       programs[shadername]->is_valid = false;
1680     }
1681   }
1682 
1683   // invalidate source file
1684   auto repl_it = shader_cache_processed.find(filename);
1685   if (repl_it != shader_cache_processed.end()) {
1686     shader_cache_processed.erase(repl_it);
1687   }
1688 }
1689 
1690 /*
1691  * Set the value for the #ifdef variable `key` and if the value has changed,
1692  * then invalidate all its dependant shader source files.
1693  */
SetPreprocVar(const std::string & key,bool value,bool invshaders)1694 void CShaderMgr::SetPreprocVar(const std::string &key, bool value, bool invshaders) {
1695   auto &ref = preproc_vars[key];
1696   if (ref != value) {
1697     for (const char ** filenameptr = ifdef_deps[key];
1698         *filenameptr; ++filenameptr) {
1699       ShaderSourceInvalidate(*filenameptr, invshaders);
1700     }
1701     ref = value;
1702   }
1703 }
1704 
1705 /*
1706  * Insert `filename` -> `contents` (processed source) into the shader source
1707  * cache and invalidate its parents
1708  */
SetShaderSource(const char * filename,const std::string & contents)1709 void CShaderMgr::SetShaderSource(const char * filename, const std::string &contents) {
1710   ShaderSourceInvalidate(filename);
1711   shader_cache_processed[filename] = contents;
1712 }
1713 
bindGPUBuffer(size_t hashid)1714 void CShaderMgr::bindGPUBuffer(size_t hashid) {
1715   auto search = _gpu_object_map.find(hashid);
1716   if (search != _gpu_object_map.end())
1717     search->second->bind();
1718 }
1719 
freeGPUBuffer(size_t hashid)1720 void CShaderMgr::freeGPUBuffer(size_t hashid) {
1721   if (!hashid)
1722     return;
1723   LOCK_GUARD_MUTEX(lock, gpu_objects_to_free_mutex);
1724   _gpu_objects_to_free_vector.push_back(hashid);
1725 
1726 #ifdef _WEBGL
1727   freeAllGPUBuffers(); // immediate free on web
1728 #endif
1729 }
1730 
freeGPUBuffers(std::vector<size_t> && hashids)1731 void CShaderMgr::freeGPUBuffers(std::vector<size_t> &&hashids) {
1732   LOCK_GUARD_MUTEX(lock, gpu_objects_to_free_mutex);
1733   _gpu_objects_to_free_vector.insert(_gpu_objects_to_free_vector.end(),
1734                                      hashids.begin(), hashids.end());
1735 #ifdef _WEBGL
1736   freeAllGPUBuffers(); // immediate free on web
1737 #endif
1738 }
1739 
freeGPUBuffers(size_t * arr,size_t len)1740 void CShaderMgr::freeGPUBuffers(size_t * arr, size_t len) {
1741   for (unsigned int i = 0; i < len; ++i)
1742     freeGPUBuffer(arr[i]);
1743 }
1744 
freeAllGPUBuffers()1745 void CShaderMgr::freeAllGPUBuffers() {
1746   LOCK_GUARD_MUTEX(lock, gpu_objects_to_free_mutex);
1747   for (auto hashid : _gpu_objects_to_free_vector) {
1748     auto search = _gpu_object_map.find(hashid);
1749     if (search != _gpu_object_map.end()) {
1750       if (search->second)
1751         delete search->second;
1752       _gpu_object_map.erase(search);
1753     }
1754   }
1755   _gpu_objects_to_free_vector.clear();
1756 }
1757 
GetAttributeUID(const char * name)1758 int CShaderMgr::GetAttributeUID(const char * name)
1759 {
1760   auto uloc = attribute_uids_by_name.find(name);
1761   if (uloc != attribute_uids_by_name.end())
1762     return uloc->second;
1763 
1764   int uid = attribute_uids_by_name.size() + 1;
1765   attribute_uids_by_name[name] = uid;
1766   attribute_uids[uid] = name;
1767   return uid;
1768 }
GetAttributeName(int uid)1769 const char *CShaderMgr::GetAttributeName(int uid)
1770 {
1771   auto uloc = attribute_uids.find(uid);
1772   if (uloc == attribute_uids.end())
1773     return nullptr;
1774   return attribute_uids[uid].c_str();
1775 }
1776 
1777 // SceneRenderBindToOffscreen
bindOffscreen(int width,int height,GridInfo * grid)1778 void CShaderMgr::bindOffscreen(int width, int height, GridInfo *grid) {
1779   using namespace tex;
1780   renderTarget_t::shape_type req_size(width, height);
1781   renderTarget_t* rt = nullptr;
1782 
1783 #ifndef _PYMOL_NO_AA_SHADERS
1784 #endif
1785 
1786   // Doesn't exist, create
1787   if (!offscreen_rt) {
1788     CGOFree(G->Scene->offscreenCGO);
1789     rt = newGPUBuffer<renderTarget_t>(req_size);
1790     rt->layout({ { 4, rt_layout_t::UBYTE } });
1791     offscreen_rt = rt->get_hash_id();
1792   } else {
1793     rt = getGPUBuffer<renderTarget_t>(offscreen_rt);
1794 
1795     // resize
1796     if (req_size != rt->size()) {
1797       rt->resize(req_size);
1798 #ifndef _PYMOL_NO_AA_SHADERS
1799 #endif
1800     }
1801   }
1802 
1803   if (rt)
1804     rt->bind(!stereo_blend);
1805   glEnable(GL_BLEND);
1806 
1807   SceneInitializeViewport(G, 1);
1808   if (grid->active) {
1809     grid->cur_view[0] = grid->cur_view[1] = 0;
1810     grid->cur_view[2] = req_size.x;
1811     grid->cur_view[3] = req_size.y;
1812   }
1813 }
1814 
1815 // SceneRenderBindToOffscreenOIT
bindOffscreenOIT(int width,int height,int drawbuf)1816 void CShaderMgr::bindOffscreenOIT(int width, int height, int drawbuf) {
1817   using namespace tex;
1818 
1819   renderTarget_t::shape_type req_size(width, height);
1820 
1821   if(!oit_pp || oit_pp->size() != req_size) {
1822     oit_pp = pymol::make_unique<OIT_PostProcess>(
1823         width, height, getGPUBuffer<renderTarget_t>(offscreen_rt)->_rbo);
1824   } else {
1825     if (!TM3_IS_ONEBUF) {
1826       drawbuf = 1;
1827     }
1828     oit_pp->bindFBORBO(drawbuf - 1);
1829   }
1830 }
1831 
activateOffscreenTexture(GLuint textureIdx)1832 void CShaderMgr::activateOffscreenTexture(GLuint textureIdx) {
1833   glActiveTexture(GL_TEXTURE0 + textureIdx);
1834   auto t = getGPUBuffer<renderTarget_t>(offscreen_rt);
1835   if (t->_textures[0])
1836     t->_textures[0]->bind();
1837 }
1838 
Disable_Current_Shader()1839 void CShaderMgr::Disable_Current_Shader()
1840 {
1841   if(current_shader){
1842     current_shader->Disable();
1843   }
1844 }
1845