"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "layer0/ShaderMgr.cpp" between
pymol-v2.1.0.tar.bz2 and pymol-open-source-2.2.0.tar.gz

About: PyMOL is a Python-enhanced molecular graphics tool. It excels at 3D visualization of proteins, small molecules, density, surfaces, and trajectories. It also includes molecular editing, ray tracing, and movies. Open Source version.

ShaderMgr.cpp  (pymol-v2.1.0.tar.bz2):ShaderMgr.cpp  (pymol-open-source-2.2.0)
skipping to change at line 20 skipping to change at line 20
I* Additional authors of this source file include: I* Additional authors of this source file include:
-* -*
-* -*
-* -*
Z* ------------------------------------------------------------------- Z* -------------------------------------------------------------------
*/ */
#include "os_gl.h" #include "os_gl.h"
#include "os_python.h" #include "os_python.h"
#include <string.h> #include <string.h>
#include <iostream>
#include "ShaderMgr.h" #include "ShaderMgr.h"
#include "OOMac.h" #include "OOMac.h"
#include "ListMacros.h" #include "ListMacros.h"
#include "PyMOLOptions.h" #include "PyMOLOptions.h"
#include "Feedback.h" #include "Feedback.h"
#include "MemoryDebug.h" #include "MemoryDebug.h"
#include "Setting.h" #include "Setting.h"
#include "Scene.h" #include "Scene.h"
#include "Color.h" #include "Color.h"
#include "Vector.h" #include "Vector.h"
#include "Util.h" #include "Util.h"
#include "Util2.h"
#include "Texture.h" #include "Texture.h"
#include "File.h" #include "File.h"
#include "Matrix.h"
#include "Parse.h"
#ifndef _PYMOL_NO_AA_SHADERS
#endif
#include "CGO.h"
#ifdef _WEBGL
#include "Matrix.h"
#include "WebPyMOLLibrary.h"
#endif
#define MAX_LOG_LEN 1024 #define MAX_LOG_LEN 1024
#define SCENEGETIMAGESIZE SceneGetWidthHeight #include <algorithm>
#include <sstream>
#include <stack>
#include <vector>
#include <functional>
/* Texture Usage:
0 - for not-PURE_OPENGL_ES_2: ObjectVolume: volumeTex
for WEBGL: SCHRODINGER logo
1 - for not-PURE_OPENGL_ES_2: Volume: either colorTex1D or colorTex2D
for _PYMOL_PRECOMPUTED_LIGHTING: Lighting Texture (ShaderMgr->lightingTe
xture)
2 - FXAA - color_texture
SMAA1 - colorTex
SMAA3 - colorTex
3 - SMAA3 - blendTex
Label/Indicator Shader : textureMap (both PURE_OPENGL_ES_2 and non-PURE_
OPENGL_ES_2
4 - Background Texture: bgTextureMap
5 - OIT - 2nd pass : accumTex
Volumes - carvemask
6 - OIT - 2nd pass : revealageTex
SMAA2 - edgesTex
7 - SMAA2 - areaTex
OIT Copy - colorTex
8 - SMAA2 - searchTex
#include "ShaderText.h" */
#define DEFAULT_VS_FILENAME "default_es2.vs" using namespace std;
#define DEFAULT_FS_FILENAME "default_es2.fs"
#ifndef _DEAD_CODE_DIE
#define SUPPRESS_GEOMETRY_SHADER_ERRORS
#endif
#define DEFAULTSCREEN_VS_FILENAME "defaultscreen.vs" #define CONNECTOR_GS_NUM_VERTICES 31
#define DEFAULTSCREEN_FS_FILENAME "defaultscreen.fs"
#define CYLINDER_VS_FILENAME "cylinder.vs" #define SCENEGETIMAGESIZE SceneGetWidthHeight
#define CYLINDER_FS_FILENAME "cylinder.fs"
#define SPHERE_VS_FILENAME "sphere.vs"
#define SPHERE_FS_FILENAME "sphere.fs"
#define INDICATOR_VS_FILENAME "indicator.vs" #include "ShaderText.h"
#define INDICATOR_FS_FILENAME "indicator.fs"
#define WARNING_IF_GLERROR(msg) { \ #define WARNING_IF_GLERROR(msg) { \
GLenum err; \ GLenum err; \
if ((err = glGetError())){ \ if ((err = glGetError())){ \
PRINTFB(G, FB_ShaderMgr, FB_Warnings) "GLERROR 0x%04x: " msg "\n", err ENDFB (G); \ PRINTFB(G, FB_ShaderMgr, FB_Warnings) "GLERROR 0x%04x: %s\n", err, msg ENDFB (G); \
} \ } \
} }
static const float mat3identity[] = { 1., 0., 0., 0., 1., 0., 0., 0., 1. }; static void glShaderSource1String(GLuint shad, const string &strobj){
const GLchar *str = (const GLchar *)strobj.c_str();
glShaderSource(shad, 1, (const GLchar **)&str, NULL);
}
void getGLVersion(PyMOLGlobals * G, int *major, int* minor); bool CShaderPrg::reload(){
void getGLSLVersion(PyMOLGlobals * G, int* major, int* minor); // skip programs with empty file names, assume their code is managed
// outside of the reload logic (like ARB shaders).
if (is_valid || vertfile.empty())
return true;
static void disableShaders(PyMOLGlobals * G); string gs, vs, fs;
CShaderMgr *I = G->ShaderMgr;
GLint status;
static if (!geomfile.empty())
bool get_fog_enabled(PyMOLGlobals * G) { gs = I->GetShaderSource(geomfile);
return SettingGet<bool>(G, cSetting_depth_cue) &&
!SettingGet<bool>(G, cSetting_pick_shading);
}
void CShaderPrg_SetFogUniforms(PyMOLGlobals * G, CShaderPrg * shaderPrg){ vs = I->GetShaderSource(vertfile);
int bg_width, bg_height; fs = I->GetShaderSource(fragfile);
int scene_width, scene_height;
int ortho_width, ortho_height;
CShaderPrg_Set3fv(shaderPrg, "fogSolidColor", ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_rgb))); WARNING_IF_GLERROR("CShaderPrg::reload begin");
SceneGetWidthHeight(G, &scene_width, &scene_height); PRINTFB(G, FB_ShaderMgr, FB_Blather)
"Loading shader named: %s\n", name.c_str()
ENDFB(G);
OrthoGetBackgroundSize(G, &bg_width, &bg_height); if (!id) {
OrthoGetSize(G, &ortho_width, &ortho_height); id = glCreateProgram();
CShaderPrg_Set2f(shaderPrg, "viewImageSize", bg_width/(float)scene_width, bg_h }
eight/(float)scene_height);
CShaderPrg_Set2f(shaderPrg, "pixelSize", 2.f/(float)scene_width, 2.f/(float)sc #ifndef PURE_OPENGL_ES_2
ene_height); if (!gs.empty() && SettingGetGlobal_b(G, cSetting_use_geometry_shaders)) {
CShaderPrg_Set2f(shaderPrg, "tPixelSize", 1.f/(float)ortho_width, 1.f/(float)o if (!gid) {
rtho_height); gid = glCreateShader(GL_GEOMETRY_SHADER);
CShaderPrg_Set2f(shaderPrg, "t2PixelSize", 2.f/(float)ortho_width, 2.f/(float)
ortho_height); GLenum err;
if ((err=glGetError()) || !gid) {
PRINTFB(G, FB_ShaderMgr, FB_Errors)
" Error: geometry shader creation failed. name=%s err=0x%x\n", name.c_
str(), err ENDFB(G);
return false;
}
glAttachShader(id, gid);
}
glShaderSource1String(gid, gs);
glCompileShader((GLuint) gid);
glGetShaderiv(gid, GL_COMPILE_STATUS, &status);
if (!status) {
#ifndef SUPPRESS_GEOMETRY_SHADER_ERRORS
ErrorMsgWithShaderInfoLog(gid, "geometry shader compilation failed.");
#endif
glDetachShader(id, gid);
glDeleteShader(gid);
gid = 0;
return false;
}
glProgramParameteriEXT(id, GL_GEOMETRY_INPUT_TYPE_EXT, gsInput);
glProgramParameteriEXT(id, GL_GEOMETRY_OUTPUT_TYPE_EXT, gsOutput);
glProgramParameteriEXT(id, GL_GEOMETRY_VERTICES_OUT_EXT, ngsVertsOut);
PRINTFB(G, FB_ShaderMgr, FB_Debugging)
" ShaderPrg-Debug: geometry shader compiled.\n" ENDFB(G);
} else if (gid) {
// for manually switching off geometry shaders (set use_geometry_shaders, of
f)
glDetachShader(id, gid);
glDeleteShader(gid);
gid = 0;
}
WARNING_IF_GLERROR("CShaderPrg::reload after geometry shader");
#endif
// vertex shader
{
if (!vid) {
vid = glCreateShader(GL_VERTEX_SHADER);
glAttachShader(id, vid);
}
glShaderSource1String(vid, vs);
glCompileShader((GLuint) vid);
glGetShaderiv(vid, GL_COMPILE_STATUS, &status);
if (!status) {
ErrorMsgWithShaderInfoLog(vid, "vertex shader compilation failed.");
return false;
}
}
// fragment shader
{ {
float hpixelx = floor(scene_width / 2.f)/(float)scene_width, if (!fid) {
hpixely = floor(scene_height / 2.f)/(float)scene_height; fid = glCreateShader(GL_FRAGMENT_SHADER);
CShaderPrg_Set2f(shaderPrg, "halfPixel", hpixelx, hpixely); glAttachShader(id, fid);
}
glShaderSource1String(fid, fs);
glCompileShader((GLuint) fid);
glGetShaderiv(fid, GL_COMPILE_STATUS, &status);
if (!status) {
ErrorMsgWithShaderInfoLog(fid, "fragment shader compilation failed.");
return false;
}
}
uniforms.clear();
uniform_set = 0;
// it is valid to bind unused names, and to bind multiple names to the same in
dex
if (!name.compare(0, 8, "cylinder")){
glBindAttribLocation(id, CYLINDER_VERTEX1, "attr_vertex1");
glBindAttribLocation(id, CYLINDER_VERTEX2, "attr_vertex2");
glBindAttribLocation(id, CYLINDER_COLOR, "a_Color");
glBindAttribLocation(id, CYLINDER_COLOR2, "a_Color2");
glBindAttribLocation(id, CYLINDER_RADIUS, "attr_radius");
glBindAttribLocation(id, CYLINDER_CAP, "a_cap");
} else {
glBindAttribLocation(id, VERTEX_POS, "a_Vertex");
glBindAttribLocation(id, VERTEX_COLOR, "a_Color");
glBindAttribLocation(id, VERTEX_NORMAL, "a_Normal");
glBindAttribLocation(id, 0, "attr_worldpos");
} }
WARNING_IF_GLERROR("after glBindAttribLocation");
is_linked = false;
is_valid = true;
return true;
} }
#define MASK_SHADERS_PRESENT_GEOMETRY 0x2;
#define MASK_SHADERS_PRESENT_SMAA 0x4;
void getGLVersion(PyMOLGlobals * G, int *major, int* minor);
void getGLSLVersion(PyMOLGlobals * G, int* major, int* minor);
static void disableShaders(PyMOLGlobals * G);
#ifdef WIN32 #ifdef WIN32
/* REMOVE US */ /* REMOVE US */
PFNGLTEXIMAGE3DPROC getTexImage3D(){ PFNGLTEXIMAGE3DPROC getTexImage3D(){
static PFNGLTEXIMAGE3DPROC my_glTexImage3D = NULL; static PFNGLTEXIMAGE3DPROC my_glTexImage3D = NULL;
if (!my_glTexImage3D) if (!my_glTexImage3D)
my_glTexImage3D = (PFNGLTEXIMAGE3DPROC) wglGetProcAddress("glTexImage3D"); my_glTexImage3D = (PFNGLTEXIMAGE3DPROC) wglGetProcAddress("glTexImage3D");
return my_glTexImage3D; return my_glTexImage3D;
} }
#endif #endif
/* /*
* Use this to turn off shaders if the renderer cannot use them. * Use this to turn off shaders if the renderer cannot use them.
*/ */
void disableShaders(PyMOLGlobals * G) { void disableShaders(PyMOLGlobals * G) {
/* Auto-disable shader-based rendering */ /* Auto-disable shader-based rendering */
SettingSetGlobal_b(G, cSetting_use_shaders, 0); SettingSetGlobal_b(G, cSetting_use_shaders, 0);
} }
int SHADERLEX_LOOKUP(PyMOLGlobals * G, char *strarg){ static void disableGeometryShaders(PyMOLGlobals * G) {
CShaderMgr *I = G->ShaderMgr; SettingSetGlobal_b(G, cSetting_use_geometry_shaders, 0);
OVreturn_word result, result2; if(G->ShaderMgr)
if(!OVreturn_IS_OK((result = OVLexicon_BorrowFromCString(I->ShaderLex, strarg) G->ShaderMgr->SetPreprocVar("use_geometry_shaders", 0);
)))
return -1; if (G->Option && !G->Option->quiet)
result2 = OVOneToOne_GetForward(I->ShaderLexLookup, result.word); PRINTFB(G, FB_ShaderMgr, FB_Warnings)
return result2.word; " Geometry shaders not available\n" ENDFB(G);
} }
void CShaderMgr_Free_Shader_Arrays(CShaderMgr *I){ /*
int i, sz = VLAGetSize(I->shader_replacement_strings); * Replace strings from a list of pairs.
for (i=0; i<sz;i++){ *
if (I->shader_replacement_strings[i]){ * src: string to modify
VLAFreeP(I->shader_replacement_strings[i]); * replaceStrings: map of strings to replace (as consecutive elements in an
I->shader_replacement_strings[i] = 0; * array like {from1, to1, from2, to2, ..., ""}
* returns: new string
*/
static string stringReplaceAll(const string &src, const string * replaceStrings)
{
string dest = src;
for (int i = 0; !replaceStrings[i].empty(); i += 2) {
int slen1 = replaceStrings[i].length();
int slen2 = replaceStrings[i + 1].length();
for (size_t pl = 0;
(pl = dest.find(replaceStrings[i], pl)) != string::npos;
pl += slen2) {
dest.replace(pl, slen1, replaceStrings[i + 1]);
} }
I->shader_include_values[i] = 0;
} }
return dest;
} }
#define MIN_CHAR(x,y) (!x ? y : !y ? x : ((x < y) ? x : y)) /*
* Reload "CallComputeColorForLight" shader replacement string
char *CShaderPrg_ReadFromFile_Or_Use_String(PyMOLGlobals * G, char *name, char * */
fileName, char *fallback_str); void CShaderMgr::Reload_CallComputeColorForLight(){
if ((reload_bits & RELOAD_CALLCOMPUTELIGHTING)) {
char *CShaderPrg_ReadFromFile_Or_Use_String_Replace_Strings(PyMOLGlobals * G, ch reload_bits &= ~RELOAD_CALLCOMPUTELIGHTING;
ar *name, char *fileName, char *fallback_str, char **replaceStrings); } else {
return;
char *CShaderPrg_ReadFromFile_Or_Use_String(PyMOLGlobals * G, char *name, char * }
fileName, char *fallback_str){
return CShaderPrg_ReadFromFile_Or_Use_String_Replace_Strings(G, name, fileName
, fallback_str, NULL);
}
void CShaderPrg_ReplaceStringsInPlace(PyMOLGlobals *G, char *dest_line, char **r if (SettingGetGlobal_b(G, cSetting_precomputed_lighting)) {
eplaceStrings){ Generate_LightingTexture();
int i; return;
OrthoLineType tmp_line;
int slen, rlen;
char *rstr;
if (replaceStrings){
i = 0;
while (replaceStrings[i]){
slen = strlen(replaceStrings[i]);
rlen = strlen(replaceStrings[i+1]);
while((rstr=strstr(dest_line, replaceStrings[i]))){
strcpy(tmp_line, rstr + slen);
strcpy(rstr, replaceStrings[i+1]);
strcpy(rstr+rlen, tmp_line);
}
i+=2;
}
} }
}
void CShaderPrg_Reload_CallComputeColorForLight(PyMOLGlobals * G, char *name){
CShaderMgr *I = G->ShaderMgr;
int light_count = SettingGetGlobal_i(G, cSetting_light_count); int light_count = SettingGetGlobal_i(G, cSetting_light_count);
int spec_count = SettingGetGlobal_i(G, cSetting_spec_count); int spec_count = SettingGetGlobal_i(G, cSetting_spec_count);
char **reparr = Alloc(char*, 5); ostringstream accstr;
char *accstr, *tmpstr ;
int tmpstrlen, accstrlen, i, idx;
reparr[0] = "`light`";
reparr[1] = "0";
reparr[2] = "`postfix`";
reparr[3] = "_0";
reparr[4] = 0 ;
accstr = CShaderPrg_ReadFromFile_Or_Use_String_Replace_Strings(G, name, "call_
compute_color_for_light.fs", (char*)call_compute_color_for_light_fs, reparr);
reparr[3] = ""; string rawtemplate = GetShaderSource("call_compute_color_for_light.fs");
reparr[1] = Alloc(char, 5);
auto pick_shading = SettingGet<bool>(G, cSetting_pick_shading); string lightstrings[] = {
if (pick_shading) { "`light`", "0",
light_count = 1; "`postfix`", "_0",
} ""
};
accstr << stringReplaceAll(rawtemplate, lightstrings);
if (light_count > 8){ if (light_count > 8){
PRINTFB(G, FB_Setting, FB_Warnings) PRINTFB(G, FB_ShaderMgr, FB_Details)
"CShaderPrg-Error: light_count cannot be higher than 8, setting light_coun " ShaderMgr-Detail: using 8 lights (use precomputed_lighting for light_cou
t to 8\n" nt > 8)\n"
ENDFB(G); ENDFB(G);
SettingSet_i(G->Setting, cSetting_light_count, 8);
light_count = 8; light_count = 8;
} }
for (i=1; i<light_count; i++){
sprintf(reparr[1], "%d", i); // no postfix for 1..light_count
lightstrings[3] = "";
for (int i=1; i<light_count; i++){
ostringstream lstr;
lstr << i;
lightstrings[1] = lstr.str(); // std::to_string(i)
if (i == spec_count + 1) { if (i == spec_count + 1) {
reparr[3] = " * 0.0"; // no specular for [spec_count + 1 .. light_count]
lightstrings[3] = " * 0.0";
} }
tmpstr = CShaderPrg_ReadFromFile_Or_Use_String_Replace_Strings(G, name, "cal accstr << stringReplaceAll(rawtemplate, lightstrings);
l_compute_color_for_light.fs", (char*)call_compute_color_for_light_fs, reparr);
tmpstrlen = strlen(tmpstr);
accstrlen = strlen(accstr);
VLASize(accstr, char, tmpstrlen + accstrlen);
strcpy(accstr + accstrlen-1, tmpstr);
VLAFreeP(tmpstr);
} }
FreeP(reparr[1]);
FreeP(reparr); SetShaderSource("CallComputeColorForLight", accstr.str());
idx = SHADERLEX_LOOKUP(G, "CallComputeColorForLight"); }
if (I->shader_replacement_strings[idx]){
VLAFreeP(I->shader_replacement_strings[idx]); void CShaderMgr::Invalidate_All_Shaders(){
for (map<string, CShaderPrg*>::iterator
it = programs.begin(); it != programs.end(); ++it) {
it->second->Invalidate();
} }
I->shader_replacement_strings[idx] = accstr;
} }
void CShaderPrg_Reload_All_Shaders_For_CallComputeColorForLight(PyMOLGlobals * G
){ void CShaderMgr::Reload_All_Shaders(){
CShaderMgr_Reload_Shader_Variables(G); Reload_Shader_Variables();
CShaderMgr_Reload_Default_Shader(G); Reload_CallComputeColorForLight();
CShaderMgr_Reload_Cylinder_Shader(G);
CShaderMgr_Reload_Sphere_Shader(G); if (SettingGetGlobal_i(G, cSetting_transparency_mode) == 3) {
Reload_Derivatives("NO_ORDER_TRANSP");
}
for (auto it = programs.begin(); it != programs.end(); ++it) {
if (it->second->derivative.empty())
it->second->reload();
}
} }
void CShaderPrg_Reload_All_Shaders(PyMOLGlobals * G){ // bitmasks for preprocessor parsing
CShaderMgr_Reload_Shader_Variables(G); #define IFDEF 1 // #ifdef or #ifndef
CShaderMgr_Reload_Default_Shader(G); #define IFNDEF 2 // #ifndef
CShaderMgr_Reload_Cylinder_Shader(G); #define ELSE 4 // #else
CShaderMgr_Reload_Sphere_Shader(G); #define ENDIF 8 // #endif
CShaderMgr_Reload_Indicator_Shader(G); #define INCLUDE 16 // #include
#define LOOKUP 32 // #ifdef or #ifndef or #include
// preprocessor directive (like '#ifdef') -> bitmask
static map<string, short> preprocmap;
// filename -> contents (static filesystem)
static map<string, const char *> shader_cache_raw;
// preproc variable -> NULL terminated list of filenames ("used by")
std::map<std::string, const char **> ifdef_deps;
// filename -> NULL terminated list of filenames ("included by")
std::map<std::string, const char **> include_deps;
/*
* Return a pointer to the next whitespace character or to the end of the string
*/
static const char * nextwhitespace(const char * p) {
for (;; p++) {
switch (*p) {
case ' ': case '\0': case '\n': case '\r': case '\t':
return p;
}
}
} }
char *CShaderPrg_ReadFromFile_Or_Use_String_Replace_Strings(PyMOLGlobals * G, ch /*
ar *name, char *fileName, char *fallback_str, char **replaceStrings){ * Return a pointer to the next line beginning or to the end of the string.
CShaderMgr *I = G->ShaderMgr; * Skips blank lines.
char* buffer = NULL, *pymol_path, *shader_path, *fullFile = NULL, *pl, *newpl, */
*tpl, *chrsp, *chrnl; static const char * nextline(const char * p) {
long res; for (;; p++) {
char *newbuffer; switch (*p) {
int newbuffersize; case '\0': case '\n': case '\r':
short allocated = 0; goto switch2;
int i, len, tlen; }
OrthoLineType tmp_line, tmp_str; }
short *ifdefstack = VLAlloc(short, 10), current_include = 1; for (;; p++) {
int ifdefstacksize = 1; switch2:
ifdefstack[0] = 1; switch (*p) {
case ' ': case '\n': case '\r': case '\t':
pymol_path = getenv("PYMOL_DATA"); break;
if(pymol_path && pymol_path[0]) { default:
shader_path = "/shaders/"; return p;
} else { }
pymol_path = getenv("PYMOL_PATH");
shader_path = "/data/shaders/";
} }
}
if (!pymol_path){ /*
if (I->print_warnings){ * Get the processed shader file contents with all #ifdef and #include
* preprocessors processed.
*
* Note: There must be a single whitespace character between preprocessor
* directive and argument.
*
* Valid:
* #ifdef foo
*
* Invalid:
* # ifdef foo
* #ifdef foo
*
* Function arguments:
* filename: file name of the shader file inside $PYMOL_DATA/shaders
*/
string CShaderMgr::GetShaderSource(const string &filename)
{
// processed cache
auto it = shader_cache_processed.find(filename);
if (it != shader_cache_processed.end()) {
return it->second;
}
char* buffer = NULL;
const char *pl = NULL, *newpl, *tpl;
std::ostringstream newbuffer;
/* "if_depth" counts the level of nesting, and "true_depth" how far the
* if conditions were actually true. So if the current block is true, then
* if_depth == true_depth, otherwise if_depth > true_depth.
*/
int if_depth = 0, true_depth = 0;
#ifndef _PYMOL_IOS
/* read the file from disk */
if (SettingGetGlobal_b(G, cSetting_shaders_from_disk)) {
const char * pymol_data = getenv("PYMOL_DATA");
if (pymol_data && pymol_data[0]) {
string path(pymol_data);
path.append(PATH_SEP).append("shaders").append(PATH_SEP).append(filename);
pl = buffer = FileGetContents(path.c_str(), NULL);
if (!buffer) {
PRINTFB(G, FB_ShaderMgr, FB_Warnings)
" Warning: shaders_from_dist=on, but unable to open file '%s'\n",
path.c_str() ENDFB(G);
}
} else {
PRINTFB(G, FB_ShaderMgr, FB_Warnings) PRINTFB(G, FB_ShaderMgr, FB_Warnings)
" CShaderPrg_ReadFromFile_Or_Use_String: PYMOL_PATH not set, cannot read shader config files from disk\n" ENDFB(G); " Warning: shaders_from_dist=on, but PYMOL_DATA not set\n" ENDFB(G);
} }
} else {
fullFile = Alloc(char, strlen(pymol_path) + strlen(shader_path) + strlen(fil
eName) + 1);
fullFile = strcpy(fullFile, pymol_path);
fullFile = strcat(fullFile, shader_path);
fullFile = strcat(fullFile, fileName);
/* read the file from disk */
buffer = FileGetContents(fullFile, &res);
} }
if (!buffer) { #endif
if (I->print_warnings){
if (!pl) {
pl = shader_cache_raw[filename];
if (!pl) {
PRINTFB(G, FB_ShaderMgr, FB_Errors) PRINTFB(G, FB_ShaderMgr, FB_Errors)
" CShaderPrg_ReadFromFile_Or_Use_String-Error: Unable to open file '%s' l " GetShaderSource-Error: No such file: '%s'\n", filename.c_str() ENDFB(G
oading from memory\n", fullFile ENDFB(G); );
return "";
} }
buffer = fallback_str;
res = strlen(buffer) -1;
} else {
allocated = 1;
} }
newbuffer = VLAlloc(char, 1000);
newbuffer[0] = 0;
newbuffersize = 1;
/* Now we need to read through the shader and do processing if necessary */ /* Now we need to read through the shader and do processing if necessary */
pl = buffer; for (; *pl; pl = newpl) {
i = 1; int preproc = 0;
while (((size_t)(pl - buffer)) < res){ // only do preprocessor lookup if line starts with a hash
short pass_line = 0; if (pl[0] == '#') {
newpl = strchr(pl, '\n'); // next white space
len = newpl - pl + 1; tpl = nextwhitespace(pl);
strncpy(tmp_line, pl, len);
tmp_line[len] = 0; // copy of first word
chrsp = strchr(pl, ' '); string tmp_str(pl, tpl - pl);
chrnl = strchr(pl, '\n');
tpl = (char*)MIN_CHAR(chrsp, chrnl); // lookup word in preprocmap
if (tpl <= newpl){ // && tlen < len){ map<string, short>::const_iterator
short ifl = 0, ifdefl = 0, ifdefnot = 0, elsel = 0, endifl = 0, includel = preprocit = preprocmap.find(tmp_str);
0, lookup = 0; if (preprocit != preprocmap.end()) {
tlen = tpl - pl; preproc = preprocit->second;
strncpy(tmp_str, pl, tlen);
tmp_str[tlen] = 0; if (preproc & LOOKUP) { // #ifdef or #ifndef or #include
if (!strcmp(tmp_str, "#if")){ if (if_depth == true_depth) {
lookup = ifl = 1; // copy of second word
} else if (!strcmp(tmp_str, "#ifdef")){ tpl++;
lookup = ifdefl = 1; tmp_str = string(tpl, nextwhitespace(tpl) - tpl);
} else if (!strcmp(tmp_str, "#ifndef")){
lookup = ifdefl = ifdefnot = 1; if (preproc & IFDEF) { // #ifdef or #ifndef
} else if (!strcmp(tmp_str, "#else")){ bool if_value = false;
pass_line = elsel = 1;
} else if (!strcmp(tmp_str, "#endif")){ // lookup for boolean shader preprocessor values
pass_line = endifl = 1; auto item = preproc_vars.find(tmp_str);
} else if (!strcmp(tmp_str, "#include")){ if (item != preproc_vars.end())
lookup = includel = 1; if_value = item->second;
}
if (lookup){ if (preproc & IFNDEF)
int off; if_value = !if_value; // #ifndef
char *tpl2 = (char*)MIN_CHAR(strchr(tpl + 1, '\n'), strchr(tpl + 1, ' '))
; if (if_value)
int t2len = tpl2 - tpl - 1, is_name; true_depth++;
pass_line = 1;
strncpy(tmp_str, tpl + 1, t2len); } else if (preproc & INCLUDE) { //#include
tmp_str[t2len] = 0; tmp_str = string(tpl, nextwhitespace(tpl) - tpl);
off = SHADERLEX_LOOKUP(G, tmp_str); newbuffer << GetShaderSource(tmp_str);
if (ifl){ }
/* char *op = (char*)MIN_CHAR(strchr(tpl2 + 1, '\n'), strchr(tpl2 }
+ 1, ' '));
char *compval = (char*)MIN_CHAR(strchr(op + 1, '\n'), strchr(op if (preproc & IFDEF)
+ 1, ' ')); if_depth++;
printf("op='%s' compval='%s'\n", op, compval); */
} else { } else if (preproc & ENDIF){ // #endif
is_name = !strcmp(tmp_str, name); if (if_depth-- == true_depth)
if (off >= 0 || is_name){ true_depth--;
if (ifdefl){ } else if (preproc & ELSE){ // #else
int ifr; if (if_depth == true_depth)
if (is_name){ true_depth--;
ifr = 1; else if (if_depth == true_depth + 1)
} else { true_depth++;
ifr = I->shader_include_values[off]; }
}
if (ifdefnot) ifr = !ifr;
VLACheck(ifdefstack, short, ifdefstacksize+1);
ifdefstack[ifdefstacksize++] = ifr;
current_include = ifr;
} else if (includel){
if (I->shader_update_when_include[off]){
I->shader_replacement_strings[off] = CShaderPrg_ReadFromFile_Or_U
se_String(G, name, I->shader_update_when_include_filename[off], (char*)I->shader
_update_when_include[off]);
}
{
int slen = strlen(I->shader_replacement_strings[off]);
VLACheck(newbuffer, char, newbuffersize + slen);
strcpy(&newbuffer[newbuffersize-1], I->shader_replacement_strings
[off]);
newbuffer[newbuffersize + slen-1] = 0;
newbuffersize += slen;
}
}
} else {
/* Lookup doesn't exist, fails check */
VLACheck(ifdefstack, short, ifdefstacksize+1);
ifdefstack[ifdefstacksize++] = 0;
current_include = 0;
}
}
}
if (endifl){
int pl;
ifdefstacksize--;
pl = ifdefstacksize - 1;
current_include = (pl >= 0) ? ifdefstack[pl] : 1;
pass_line = 1;
} else if (elsel){
current_include = !current_include;
pass_line = 1;
} }
} }
if (!pass_line && current_include){
if (replaceStrings){ newpl = nextline(pl);
CShaderPrg_ReplaceStringsInPlace(G, tmp_line, replaceStrings);
len = strlen(tmp_line); // add to the output buffer if this is a regular active line
} if (!preproc && if_depth == true_depth) {
VLACheck(newbuffer, char, newbuffersize + len); newbuffer.write(pl, newpl - pl);
strcpy(&newbuffer[newbuffersize-1], tmp_line); }
newbuffer[newbuffersize + len -1] = 0; }
newbuffersize += len;
} FreeP(buffer);
pl = newpl + 1;
i++; string result = newbuffer.str();
} shader_cache_processed[filename] = result;
if (allocated){ return result;
FreeP(buffer);
}
VLAFreeP(ifdefstack);
if (fullFile)
free(fullFile);
return newbuffer;
} }
#define FREE_AND_REPLACE_WITH(var, with) if (var) free(var); var = with; #define FREE_AND_REPLACE_WITH(var, with) if (var) free(var); var = with;
void CShaderMgr_Reload_Shader_Variables(PyMOLGlobals * G){ void CShaderMgr::Reload_Shader_Variables() {
CShaderMgr *I = G->ShaderMgr; if ((reload_bits & RELOAD_VARIABLES)) {
reload_bits &= ~RELOAD_VARIABLES;
} else {
return;
}
int bg_image_mode = SettingGetGlobal_i(G, cSetting_bg_image_mode);
int bg_gradient = SettingGetGlobal_b(G, cSetting_bg_gradient); int bg_gradient = SettingGetGlobal_b(G, cSetting_bg_gradient);
int bg_image_mode_solid; int bg_image_mode_solid;
int stereo, stereo_mode; int stereo, stereo_mode;
bg_image_mode_solid = !bg_gradient; const char * bg_image_filename = SettingGet_s(G, NULL, NULL, cSetting_bg_image
CShaderMgr_Free_Shader_Arrays(I); _filename);
short bg_image = bg_image_filename && bg_image_filename[0];
bg_image_mode_solid = !(bg_gradient || bg_image || OrthoBackgroundDataIsSet(G)
);
SetPreprocVar("bg_image_mode_solid", bg_image_mode_solid);
if (!bg_image_mode_solid) {
SetPreprocVar("bg_image_mode_1_or_3", (bg_image_mode == 1 || bg_image_mode =
= 3));
SetPreprocVar("bg_image_mode_2_or_3", (bg_image_mode == 2 || bg_image_mode =
= 3));
}
I->shader_include_values[SHADERLEX_LOOKUP(G, "bg_image_mode_solid")] = !bg_gra #ifndef PYMOL_EDU
dient; SetPreprocVar("volume_mode", SettingGetGlobal_i(G, cSetting_volume_mode));
I->shader_include_values[SHADERLEX_LOOKUP(G, "bg_image_mode_stretched")] = bg_ #endif
gradient;
SetPreprocVar("ortho", SettingGetGlobal_i(G, cSetting_ortho));
SetPreprocVar("depth_cue", SettingGetGlobal_b(G, cSetting_depth_cue)
&& SettingGetGlobal_b(G, cSetting_fog) != 0.0F);
#ifndef PURE_OPENGL_ES_2
SetPreprocVar("use_geometry_shaders", SettingGetGlobal_b(G, cSetting_use_geome
try_shaders));
#endif
SetPreprocVar("line_smooth", SettingGetGlobal_b(G, cSetting_line_smooth));
stereo = SettingGetGlobal_i(G, cSetting_stereo); stereo = SettingGetGlobal_i(G, cSetting_stereo);
stereo_mode = SettingGetGlobal_i(G, cSetting_stereo_mode); stereo_mode = SettingGetGlobal_i(G, cSetting_stereo_mode);
I->shader_include_values[SHADERLEX_LOOKUP(G, "ANAGLYPH")] = (stereo && stereo_ SetPreprocVar("ANAGLYPH", (stereo && stereo_mode==cStereo_anaglyph) ? 1 : 0);
mode==cStereo_anaglyph) ? 1 : 0; SetPreprocVar("ray_trace_mode_3", SettingGetGlobal_i(G, cSetting_ray_trace_mod
e) == 3);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "ComputeFogColor")] = CShade SetPreprocVar("transparency_mode_3", SettingGetGlobal_i(G, cSetting_transparen
rPrg_ReadFromFile_Or_Use_String(G, "ComputeFogColor", "compute_fog_color.fs", (c cy_mode)==3);
har*)compute_fog_color_fs);
{ #ifndef _PYMOL_NO_AA_SHADERS
int ComputeColorForLightOffset = SHADERLEX_LOOKUP(G, "ComputeColorForLight") #endif
;
FREE_AND_REPLACE_WITH(I->shader_update_when_include_filename[ComputeColorFor
LightOffset], strdup("compute_color_for_light.fs"));
I->shader_update_when_include[ComputeColorForLightOffset] = (char*)compute_c
olor_for_light_fs;
}
{ SetPreprocVar("precomputed_lighting", SettingGetGlobal_b(G, cSetting_precomput
int anaglyphHeaderOffset = SHADERLEX_LOOKUP(G, "ANAGLYPH_HEADER"); ed_lighting));
FREE_AND_REPLACE_WITH(I->shader_update_when_include_filename[anaglyphHeaderO SetPreprocVar("ray_transparency_oblique", SettingGetGlobal_f(G, cSetting_ray_t
ffset], strdup("anaglyph_header.fs")); ransparency_oblique) > R_SMALL4);
I->shader_update_when_include[anaglyphHeaderOffset] = (char*)anaglyph_header
_fs;
}
{
int anaglyphOffset = SHADERLEX_LOOKUP(G, "ANAGLYPH_BODY");
FREE_AND_REPLACE_WITH(I->shader_update_when_include_filename[anaglyphOffset]
, strdup("anaglyph.fs"));
I->shader_update_when_include[anaglyphOffset] = (char*)anaglyph_fs;
}
int chromadepth = SettingGetGlobal_i(G, cSetting_chromadepth);
SetPreprocVar("chromadepth", chromadepth != 0);
SetPreprocVar("chromadepth_postlighting", chromadepth == 2);
} }
/* ============================================================================ /* ============================================================================
* ShaderMgrInit is called from PyMOL.c during start up; it just allocates * ShaderMgrInit is called from PyMOL.c during start up; it just allocates
* the global ShaderMgr * the global ShaderMgr
*/ */
OVstatus ShaderMgrInit(PyMOLGlobals * G) { bool ShaderMgrInit(PyMOLGlobals * G) {
OVreturn_word result; // initialize some globals (do this only once)
CShaderMgr *I = G->ShaderMgr = CShaderMgr_New(G); if (preprocmap.empty()) {
OVContext *C = G->Context; preprocmap["#ifdef"] = LOOKUP | IFDEF;
preprocmap["#ifndef"] = LOOKUP | IFDEF | IFNDEF;
if(!I) preprocmap["#else"] = ELSE;
return_OVstatus_FAILURE; \ preprocmap["#endif"] = ENDIF;
preprocmap["#include"] = LOOKUP | INCLUDE;
I->reload_bits = 0;
G->ShaderMgr->is_picking = 0;
I->ShaderLex = OVLexicon_New(C->heap);
I->ShaderLexLookup = OVOneToOne_New(C->heap);
#define SHADERLEX(ARG, OFFSET) \
if(!OVreturn_IS_OK( (result= OVLexicon_GetFromCString(I->ShaderLex,#ARG)))) \
return_OVstatus_FAILURE; \
if(!OVreturn_IS_OK( OVOneToOne_Set(I->ShaderLexLookup, result.word, OFFSET)))
\
return_OVstatus_FAILURE;
SHADERLEX(ComputeFogColor, 0);
/* 1-3 reserved for incentive */
SHADERLEX(bg_image_mode_stretched, 4);
SHADERLEX(bg_image_mode_solid, 5);
SHADERLEX(default_vs, 6);
SHADERLEX(default_fs, 7);
SHADERLEX(bg_vs, 8);
SHADERLEX(bg_fs, 9);
SHADERLEX(cylinder_vs, 10);
SHADERLEX(cylinder_fs, 11);
SHADERLEX(label_vs, 13);
SHADERLEX(label_fs, 14);
SHADERLEX(sphere_vs, 15);
SHADERLEX(sphere_fs, 16);
SHADERLEX(volume_vs, 17);
SHADERLEX(volume_fs, 18);
SHADERLEX(ComputeColorForLight, 19);
SHADERLEX(CallComputeColorForLight, 20);
/* 21 reserved for incentive */
SHADERLEX(ANAGLYPH, 22);
SHADERLEX(ANAGLYPH_HEADER, 23);
SHADERLEX(ANAGLYPH_BODY, 24);
SHADERLEX(indicator_vs, 25);
SHADERLEX(indicator_fs, 26);
SHADERLEX(labelscreen_vs, 27);
SHADERLEX(labelscreen_fs, 28);
SHADERLEX(defaultscreen_vs, 29);
SHADERLEX(defaultscreen_fs, 30);
SHADERLEX(screen_vs, 31);
SHADERLEX(screen_fs, 32);
SHADERLEX(ramp_vs, 33);
SHADERLEX(ramp_fs, 34);
{
int nlexvals = 35;
I->shader_replacement_strings = VLACalloc(char*, nlexvals);
I->shader_include_values = VLACalloc(int, nlexvals);
I->shader_update_when_include_filename = VLACalloc(char*, nlexvals);
I->shader_update_when_include = VLACalloc(char*, nlexvals);
}
return_OVstatus_SUCCESS;
}
void CShaderPrg_BindAttribLocations(PyMOLGlobals * G, char *name){
CShaderPrg *I = CShaderMgr_GetShaderPrg_NoSet(G->ShaderMgr, name);
if (I){
glBindAttribLocation(I->id, VERTEX_POS, "a_Vertex");
WARNING_IF_GLERROR("a_Vertex");
glBindAttribLocation(I->id, VERTEX_NORMAL, "a_Normal");
WARNING_IF_GLERROR("a_Normal");
glBindAttribLocation(I->id, VERTEX_COLOR, "a_Color");
WARNING_IF_GLERROR("a_Color");
CShaderPrg_Link(I);
}
}
void CShaderPrg_BindLabelAttribLocations(PyMOLGlobals * G){ // make #include dependency map from flat array
CShaderPrg *I; for (const char ** ptr = _include_deps; *ptr; ++ptr) {
WARNING_IF_GLERROR("BindLabelAttribLocations begin"); include_deps[ptr[0]] = ptr + 1;
I = CShaderMgr_GetShaderPrg_NoSet(G->ShaderMgr, "label"); while (*(++ptr)) {}
if (I){ }
glBindAttribLocation(I->id, 0, "attr_worldpos");
WARNING_IF_GLERROR("attr_worldpos"); // make #ifdef dependency map from flat array
} for (const char ** ptr = _ifdef_deps; *ptr; ++ptr) {
} ifdef_deps[ptr[0]] = ptr + 1;
while (*(++ptr)) {}
}
void CShaderPrg_BindCylinderAttribLocations(PyMOLGlobals * G){ // make shader file cache from flat array
CShaderPrg *I; for (const char ** ptr = _shader_cache_raw; *ptr; ptr += 2) {
WARNING_IF_GLERROR("BindCylinderAttribLocations begin"); shader_cache_raw[ptr[0]] = *(ptr + 1);
I = CShaderPrg_Get_CylinderShader_NoSet(G); }
if (I){
glBindAttribLocation(I->id, CYLINDER_ORIGIN, "attr_origin");
WARNING_IF_GLERROR("attr_origin");
glBindAttribLocation(I->id, CYLINDER_AXIS, "attr_axis");
WARNING_IF_GLERROR("attr_axis");
glBindAttribLocation(I->id, CYLINDER_COLOR, "attr_color");
WARNING_IF_GLERROR("attr_color");
glBindAttribLocation(I->id, CYLINDER_COLOR2, "attr_color2");
WARNING_IF_GLERROR("attr_color2");
CShaderPrg_Link(I);
} }
}
void CShaderMgr_Reload_Sphere_Shader(PyMOLGlobals *G){
CShaderMgr *I = G->ShaderMgr;
char *vs, *fs;
int vs_pl, fs_pl;
CShaderPrg_Reload_CallComputeColorForLight(G, "sphere");
vs_pl = SHADERLEX_LOOKUP(G, "sphere_vs");
fs_pl = SHADERLEX_LOOKUP(G, "sphere_fs");
vs = CShaderPrg_ReadFromFile_Or_Use_String(G, "sphere", SPHERE_VS_FILENAME, (c
har*)sphere_vs);
fs = CShaderPrg_ReadFromFile_Or_Use_String(G, "sphere", SPHERE_FS_FILENAME, (c
har*)sphere_fs);
if (I->shader_replacement_strings[vs_pl])
VLAFreeP(I->shader_replacement_strings[vs_pl]);
if (I->shader_replacement_strings[fs_pl])
VLAFreeP(I->shader_replacement_strings[fs_pl]);
I->shader_replacement_strings[vs_pl] = vs;
I->shader_replacement_strings[fs_pl] = fs;
CShaderPrg_Reload(G, "sphere", vs, fs);
}
void CShaderMgr_Reload_Indicator_Shader(PyMOLGlobals *G){ G->ShaderMgr = new CShaderMgr(G);
CShaderMgr *I = G->ShaderMgr;
char *vs, *fs;
int vs_pl, fs_pl;
CShaderPrg_Reload_CallComputeColorForLight(G, "indicator");
vs_pl = SHADERLEX_LOOKUP(G, "indicator_vs");
fs_pl = SHADERLEX_LOOKUP(G, "indicator_fs");
vs = CShaderPrg_ReadFromFile_Or_Use_String(G, "indicator", INDICATOR_VS_FILENA
ME, (char*)indicator_vs);
fs = CShaderPrg_ReadFromFile_Or_Use_String(G, "indicator", INDICATOR_FS_FILENA
ME, (char*)indicator_fs);
if (I->shader_replacement_strings[vs_pl])
VLAFreeP(I->shader_replacement_strings[vs_pl]);
if (I->shader_replacement_strings[fs_pl])
VLAFreeP(I->shader_replacement_strings[fs_pl]);
I->shader_replacement_strings[vs_pl] = vs;
I->shader_replacement_strings[fs_pl] = fs;
CShaderPrg_Reload(G, "indicator", vs, fs);
}
void CShaderMgr_Reload_Default_Shader(PyMOLGlobals *G){ for (int i = 0; i < 3; ++i)
CShaderMgr *I = G->ShaderMgr; G->ShaderMgr->offscreen_rt[i] = 0;
char *vs, *fs;
int vs_pl, fs_pl; for (int i = 0; i < 2; ++i)
CShaderPrg_Reload_CallComputeColorForLight(G, "default"); G->ShaderMgr->oit_rt[i] = 0;
vs_pl = SHADERLEX_LOOKUP(G, "default_vs");
fs_pl = SHADERLEX_LOOKUP(G, "default_fs"); if(!G->ShaderMgr)
vs = CShaderPrg_ReadFromFile_Or_Use_String(G, "default", DEFAULT_VS_FILENAME, return false;
(char*)default_vs);
fs = CShaderPrg_ReadFromFile_Or_Use_String(G, "default", DEFAULT_FS_FILENAME, return true;
(char*)default_fs);
if (I->shader_replacement_strings[vs_pl])
VLAFreeP(I->shader_replacement_strings[vs_pl]);
if (I->shader_replacement_strings[fs_pl])
VLAFreeP(I->shader_replacement_strings[fs_pl]);
I->shader_replacement_strings[vs_pl] = vs;
I->shader_replacement_strings[fs_pl] = fs;
if (CShaderPrg_Reload(G, "default", vs, fs))
CShaderPrg_BindAttribLocations(G, "default");
CShaderPrg_Reload_CallComputeColorForLight(G, "defaultscreen");
vs_pl = SHADERLEX_LOOKUP(G, "defaultscreen_vs");
fs_pl = SHADERLEX_LOOKUP(G, "defaultscreen_fs");
vs = CShaderPrg_ReadFromFile_Or_Use_String(G, "defaultscreen", "defaultscreen.
vs", (char*)defaultscreen_vs);
fs = CShaderPrg_ReadFromFile_Or_Use_String(G, "defaultscreen", "defaultscreen.
fs", (char*)defaultscreen_fs);
if (I->shader_replacement_strings[vs_pl])
VLAFreeP(I->shader_replacement_strings[vs_pl]);
if (I->shader_replacement_strings[fs_pl])
VLAFreeP(I->shader_replacement_strings[fs_pl]);
I->shader_replacement_strings[vs_pl] = vs;
I->shader_replacement_strings[fs_pl] = fs;
if (CShaderPrg_Reload(G, "defaultscreen", vs, fs))
CShaderPrg_BindAttribLocations(G, "defaultscreen");
}
void CShaderMgr_Reload_Cylinder_Shader(PyMOLGlobals *G){
char *vs, *fs;
int vs_pl, fs_pl;
CShaderMgr *I = G->ShaderMgr;
CShaderPrg_Reload_CallComputeColorForLight(G, "cylinder");
vs_pl = SHADERLEX_LOOKUP(G, "cylinder_vs");
fs_pl = SHADERLEX_LOOKUP(G, "cylinder_fs");
vs = CShaderPrg_ReadFromFile_Or_Use_String(G, "cylinder", "cylinder.vs", (char
*)cylinder_vs);
fs = CShaderPrg_ReadFromFile_Or_Use_String(G, "cylinder", "cylinder.fs", (char
*)cylinder_fs);
if (I->shader_replacement_strings[vs_pl])
VLAFreeP(I->shader_replacement_strings[vs_pl]);
if (I->shader_replacement_strings[fs_pl])
VLAFreeP(I->shader_replacement_strings[fs_pl]);
I->shader_replacement_strings[vs_pl] = vs;
I->shader_replacement_strings[fs_pl] = fs;
CShaderPrg_Reload(G, "cylinder", vs, fs);
CShaderPrg_BindCylinderAttribLocations(G);
} }
void CShaderPrg_Update_Shaders_For_Background(PyMOLGlobals * G) { /*
char *vs, *fs; * Print the given message as ShaderMgr-Error, followed by the shader info log.
CShaderMgr *I = G->ShaderMgr; */
CShaderMgr_Reload_Shader_Variables(G); void CShaderPrg::ErrorMsgWithShaderInfoLog(const GLuint sid, const char * msg) {
if (!I) if (!G->Option || G->Option->quiet)
return; return;
CShaderMgr_Reload_Default_Shader(G);
vs = CShaderPrg_ReadFromFile_Or_Use_String(G, "bg", "bg.vs", (char*)bg_vs); GLint infoLogLength = 0;
fs = CShaderPrg_ReadFromFile_Or_Use_String(G, "bg", "bg.fs", (char*)bg_fs); glGetShaderiv(sid, GL_INFO_LOG_LENGTH, &infoLogLength);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "bg_vs")] = vs; vector<GLchar> infoLog(infoLogLength);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "bg_fs")] = fs; glGetShaderInfoLog(sid, infoLogLength, NULL, infoLog.data());
CShaderPrg_Reload(G, "bg", vs, fs);
PRINTFB(G, FB_ShaderPrg, FB_Errors) " ShaderPrg-Error: %s; name='%s'\n",
vs = CShaderPrg_ReadFromFile_Or_Use_String(G, "label", "label.vs", (char*)labe msg, name.c_str() ENDFB(G);
l_vs);
fs = CShaderPrg_ReadFromFile_Or_Use_String(G, "label", "label.fs", (char*)labe PRINTFB(G, FB_ShaderPrg, FB_Errors) " ShaderPrg-Error-InfoLog:\n%s\n",
l_fs); infoLog.data() ENDFB(G);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "label_vs")] = vs;
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "label_fs")] = fs;
CShaderPrg_Reload(G, "label", vs, fs);
CShaderPrg_BindLabelAttribLocations(G);
vs = CShaderPrg_ReadFromFile_Or_Use_String(G, "labelscreen", "labelscreen.vs",
(char*)labelscreen_vs);
fs = CShaderPrg_ReadFromFile_Or_Use_String(G, "labelscreen", "labelscreen.fs",
(char*)labelscreen_fs);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "labelscreen_vs")] = vs;
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "labelscreen_fs")] = fs;
CShaderPrg_Reload(G, "labelscreen", vs, fs);
CShaderMgr_Reload_Sphere_Shader(G);
CShaderMgr_Reload_Cylinder_Shader(G);
vs = CShaderPrg_ReadFromFile_Or_Use_String(G, "volume", "volume.vs", (char*)vo
lume_vs);
fs = CShaderPrg_ReadFromFile_Or_Use_String(G, "volume", "volume.fs", (char*)vo
lume_fs);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "volume_vs")] = vs;
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "volume_fs")] = fs;
CShaderPrg_Reload(G, "volume", vs, fs);
vs = CShaderPrg_ReadFromFile_Or_Use_String(G, "indicator", "indicator.vs", (ch
ar*)indicator_vs);
fs = CShaderPrg_ReadFromFile_Or_Use_String(G, "indicator", "indicator.fs", (ch
ar*)indicator_fs);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "indicator_vs")] = vs;
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "indicator_fs")] = fs;
CShaderPrg_Reload(G, "indicator", vs, fs);
}
int CShaderPrg_Reload(PyMOLGlobals * G, char *name, char *v, char *f){
int status, howLong;
CShaderPrg * I = CShaderMgr_GetShaderPrg_NoSet(G->ShaderMgr, name);
if (!I){
CShaderMgr *SM = G->ShaderMgr;
if (SM && SM->ShadersPresent){
PRINTFB(G, FB_ShaderMgr, FB_Warnings)
" CShaderPrg_Reload: cannot find shader '%s'\n", name ENDFB(G);
}
return 0;
}
if(v) {
if (I->v)
free(I->v);
I->v = strdup(v);
glShaderSource(I->vid, 1, (const GLchar**) &I->v, NULL);
glCompileShader((GLuint) I->vid);
glGetShaderiv(I->vid, GL_COMPILE_STATUS, &status);
if (!status) {
if (G && G->Option && !G->Option->quiet) {
char *infoLog;
int infoLogLength = 0;
glGetShaderiv(I->vid, GL_INFO_LOG_LENGTH, &infoLogLength);
PRINTFB(G, FB_ShaderMgr, FB_Errors) " CShaderPrg_Reload-Error: vertex sh
ader compilation failed name='%s'; log follows.\n", I->name ENDFB(G);
if (!glGetError() && infoLogLength>0){
infoLog = Alloc(char, infoLogLength);
glGetShaderInfoLog(I->vid, infoLogLength, &howLong, infoLog);
PRINTFB(G, FB_ShaderMgr, FB_Errors)
"infoLog=%s\n", infoLog ENDFB(G);
FreeP(infoLog);
}
}
return 0;
}
PRINTFB(G, FB_ShaderMgr, FB_Debugging)
"CShaderPrg_Reload-Message: vertex shader compiled.\n" ENDFB(G);
}
if (f){
if (I->f)
free(I->f);
I->f = strdup(f);
glShaderSource(I->fid, 1, (const GLchar**) &I->f, NULL);
glCompileShader((GLuint) I->fid);
glGetShaderiv(I->fid, GL_COMPILE_STATUS, &status);
if (!status) {
if (G && G->Option && !G->Option->quiet) {
char *infoLog;
int infoLogLength = 0;
glGetShaderiv(I->fid, GL_INFO_LOG_LENGTH, &infoLogLength);
PRINTFB(G, FB_ShaderMgr, FB_Errors) " CShaderPrg_Reload-Error: fragment
shader compilation failed name='%s'; log follows.\n", I->name ENDFB(G);
if (!glGetError() && infoLogLength>0){
infoLog = Alloc(char, infoLogLength);
glGetShaderInfoLog(I->fid, infoLogLength, &howLong, infoLog);
PRINTFB(G, FB_ShaderMgr, FB_Errors)
"infoLog=%s\n", infoLog ENDFB(G);
FreeP(infoLog);
}
}
return 0;
}
PRINTFB(G, FB_ShaderMgr, FB_Debugging)
"CShaderPrg_Reload-Message: vertex shader compiled.\n" ENDFB(G);
}
if (v && f){
// Link the new program
if (!CShaderPrg_Link(I)){
// CShaderPrg_Delete(I);
return 0;
}
}
I->uniform_set = 0;
return 1;
} }
/* ShaderMgrConfig -- Called from PyMOL.c, configures the global ShaderMgr /* ShaderMgrConfig -- Called from PyMOL.c, configures the global ShaderMgr
* This needs to be called once the OpenGL context has been created, it is * This needs to be called once the OpenGL context has been created, it is
* called from MainInit() for PyMol, and from PyMOL_ConfigureShadersGL() for * called from MainInit() for PyMol, and from PyMOL_ConfigureShadersGL() for
* other programs (i.e., JyMOL, AxPyMOL, etc.). * other programs (i.e., JyMOL, AxPyMOL, etc.).
*/ */
void ShaderMgrConfig(PyMOLGlobals * G) { void CShaderMgr::Config() {
int major, minor; if (!G || !G->HaveGUI) /* && G->ValidContext); */
char buf[50];
CShaderPrg *defaultShader = NULL, *volumeShader = NULL, *sphereShader = NULL,
*defaultScreenShader = NULL,
*cylinderShader = NULL, *labelShader = NULL, *labelScreenShader = NULL, *ind
icatorShader = NULL,
*bgShader = NULL, *screenShader = NULL, *rampShader = NULL;
int ok = 0;
GLenum err;
CShaderMgr *I = G->ShaderMgr;
ok = (G && G->HaveGUI); /* && G->ValidContext); */
if (ok) {
err = glewInit();
} else {
return; return;
}
glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, line_width_range);
#ifndef PURE_OPENGL_ES_2
GLenum err = glewInit();
if (GLEW_OK==err) { if (GLEW_OK==err) {
GLint gl_major = 0, gl_minor = 0;
getGLVersion(G, &gl_major, &gl_minor);
PRINTFB(G, FB_ShaderMgr, FB_Details)
" Detected OpenGL version %d.%d.", gl_major, gl_minor ENDFB(G);
if (GLEW_VERSION_2_0) { if (GLEW_VERSION_2_0) {
FeedbackAdd(G, " Detected OpenGL version 2.0 or greater. Shaders available .\n"); FeedbackAdd(G, " Shaders available.\n");
} }
else { else {
FeedbackAdd(G, " Detected OpenGL version prior to 2.0. Shaders and volumes unavailable.\n"); FeedbackAdd(G, " Shaders and volumes unavailable.\n");
disableShaders(G); disableShaders(G);
return; return;
} }
} }
else { else {
/* print info on glew error? */ /* print info on glew error? */
FeedbackAdd(G, " There was an error intializing GLEW. Basic graphics, inclu ding\n shaders and volumes may be unavailable.\n"); FeedbackAdd(G, " There was an error intializing GLEW. Basic graphics, inclu ding\n shaders and volumes may be unavailable.\n");
disableShaders(G); disableShaders(G);
fprintf(stderr, " GLEW-Error: %s\n", glewGetErrorString(err)); fprintf(stderr, " GLEW-Error: %s\n", glewGetErrorString(err));
return; return;
} }
#endif
// static preprocessor values
preproc_vars["GLEW_VERSION_3_0"] = GLEW_VERSION_3_0 ? 1 : 0;
if (TM3_IS_ONEBUF){
preproc_vars["ONE_DRAW_BUFFER"] = 1;
}
#ifdef PURE_OPENGL_ES_2
preproc_vars["PURE_OPENGL_ES_2"] = 1;
preproc_vars["PYMOL_WEBGL"] = 1;
preproc_vars["PYMOL_WEBGL_IOS"] = 1;
#else
preproc_vars["gl_VertexID_enabled"] = GLEW_EXT_gpu_shader4;
#endif
// shaders
#define make_program(name, ...) programs[name] = new CShaderPrg(G, name, __VA_AR
GS__)
make_program("bg", "bg.vs", "bg.fs");
make_program("indicator", "indicator.vs", "indicator.fs");
make_program("label", "label.vs", "label.fs");
CShaderMgr_Reload_Shader_Variables(G); #ifndef PURE_OPENGL_ES_2
/* First try to load configuration from files in $PYMOL_PATH, if they don't ex make_program("volume", "volume.vs", "volume.fs");
ist #endif
load from const char * */
// FeedbackEnable(G, FB_ShaderMgr, FB_Everything); make_program("default", "default.vs", "default.fs");
make_program("surface", "surface.vs", "surface.fs");
PRINTFB(G, FB_ShaderMgr, FB_Debugging) "reading in %s and %s\n", DEFAULT_VS_FI
LENAME, DEFAULT_FS_FILENAME ENDFB(G); make_program("line", "line.vs", "line.fs");
CShaderPrg_Reload_CallComputeColorForLight(G, "default");
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "default_vs")] = CShaderPrg_ make_program("screen", "screen.vs", "screen.fs");
ReadFromFile_Or_Use_String(G, "default", DEFAULT_VS_FILENAME, (char*)default_vs)
; if (GLEW_EXT_geometry_shader4 && GLEW_EXT_gpu_shader4){
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "default_fs")] = CShaderPrg_ make_program("connector", "connector.vs", "connector.fs",
ReadFromFile_Or_Use_String(G, "default", DEFAULT_FS_FILENAME, (char*)default_fs) "connector.gs", GL_POINTS, GL_TRIANGLE_STRIP, CONNECTOR_GS_NUM_V
; ERTICES);
defaultShader = CShaderPrg_New(G, "default", } else {
I->shader_replacement_strings[SHADERLEX_LOOKUP( make_program("connector", "connector.vs", "connector.fs");
G, "default_vs")],
I->shader_replacement_strings[SHADERLEX_LOOKUP(
G, "default_fs")]);
if (!defaultShader){
PRINTFB(G, FB_ShaderMgr, FB_Results)
" PyMOLShader_NewFromFile-Warning: default shader files not found, loading
from memory.\n" ENDFB(G);
defaultShader = CShaderPrg_New(G, "default", default_vs, default_fs);
}
PRINTFB(G, FB_ShaderMgr, FB_Debugging) "reading in %s and %s\n", DEFAULTSCREEN
_VS_FILENAME, DEFAULTSCREEN_FS_FILENAME ENDFB(G);
CShaderPrg_Reload_CallComputeColorForLight(G, "defaultscreen");
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "defaultscreen_vs")] = CShad
erPrg_ReadFromFile_Or_Use_String(G, "defaultscreen", DEFAULTSCREEN_VS_FILENAME,
(char*)defaultscreen_vs);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "defaultscreen_fs")] = CShad
erPrg_ReadFromFile_Or_Use_String(G, "defaultscreen", DEFAULTSCREEN_FS_FILENAME,
(char*)defaultscreen_fs);
defaultScreenShader = CShaderPrg_New(G, "defaultscreen", I->shader_replacement
_strings[SHADERLEX_LOOKUP(G, "defaultscreen_vs")],
I->shader_replacement_strings[SHADERLEX_LO
OKUP(G, "defaultscreen_fs")]);
if (!defaultScreenShader){
PRINTFB(G, FB_ShaderMgr, FB_Results)
" PyMOLShader_NewFromFile-Warning: defaultscreen shader files not found, l
oading from memory.\n" ENDFB(G);
defaultScreenShader = CShaderPrg_New(G, "defaultscreen", defaultscreen_vs, d
efaultscreen_fs);
}
PRINTFB(G, FB_ShaderMgr, FB_Debugging) "reading in label.vs and label.fs\n" EN
DFB(G);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "label_vs")] = CShaderPrg_Re
adFromFile_Or_Use_String(G, "label", "label.vs", (char*)label_vs);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "label_fs")] = CShaderPrg_Re
adFromFile_Or_Use_String(G, "label", "label.fs", (char*)label_fs);
labelShader = CShaderPrg_New(G, "label",
I->shader_replacement_strings[SHADERLEX_LOOKUP(G,
"label_vs")],
I->shader_replacement_strings[SHADERLEX_LOOKUP(G,
"label_fs")]);
if (labelShader){
CShaderPrg_Link(labelShader);
CShaderMgr_AddShaderPrg(G->ShaderMgr, labelShader);
CShaderPrg_BindLabelAttribLocations(G);
}
PRINTFB(G, FB_ShaderMgr, FB_Debugging) "reading in labelscreen.vs and labelscr
een.fs\n" ENDFB(G);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "labelscreen_vs")] = CShader
Prg_ReadFromFile_Or_Use_String(G, "labelscreen", "labelscreen.vs", (char*)labels
creen_vs);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "labelscreen_fs")] = CShader
Prg_ReadFromFile_Or_Use_String(G, "labelscreen", "labelscreen.fs", (char*)labels
creen_fs);
labelScreenShader = CShaderPrg_New(G, "labelscreen",
I->shader_replacement_strings[SHADERLEX_LOOK
UP(G, "labelscreen_vs")],
I->shader_replacement_strings[SHADERLEX_LOOK
UP(G, "labelscreen_fs")]);
if (labelScreenShader){
CShaderPrg_Link(labelScreenShader);
CShaderMgr_AddShaderPrg(G->ShaderMgr, labelScreenShader);
}
PRINTFB(G, FB_ShaderMgr, FB_Debugging) "reading in screen.vs and screen.fs\n"
ENDFB(G);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "screen_vs")] = CShaderPrg_R
eadFromFile_Or_Use_String(G, "screen", "screen.vs", (char*)screen_vs);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "screen_fs")] = CShaderPrg_R
eadFromFile_Or_Use_String(G, "screen", "screen.fs", (char*)screen_fs);
screenShader = CShaderPrg_New(G, "screen",
I->shader_replacement_strings[SHADERLEX_LOOKUP(G,
"screen_vs")],
I->shader_replacement_strings[SHADERLEX_LOOKUP(G,
"screen_fs")]);
if (screenShader){
CShaderPrg_Link(screenShader);
CShaderMgr_AddShaderPrg(G->ShaderMgr, screenShader);
}
PRINTFB(G, FB_ShaderMgr, FB_Debugging) "reading in ramp.vs and ramp.fs\n" ENDF
B(G);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "ramp_vs")] = CShaderPrg_Rea
dFromFile_Or_Use_String(G, "ramp", "ramp.vs", (char*)ramp_vs);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "ramp_fs")] = CShaderPrg_Rea
dFromFile_Or_Use_String(G, "ramp", "ramp.fs", (char*)ramp_fs);
rampShader = CShaderPrg_New(G, "ramp",
I->shader_replacement_strings[SHADERLEX_LOOKUP(G,
"ramp_vs")],
I->shader_replacement_strings[SHADERLEX_LOOKUP(G,
"ramp_fs")]);
if (rampShader){
CShaderPrg_Link(rampShader);
CShaderMgr_AddShaderPrg(G->ShaderMgr, rampShader);
} }
{ if (GET_FRAGDEPTH_SUPPORT()) {
char *vs, *fs; make_program("cylinder", "cylinder.vs", "cylinder.fs");
vs = CShaderPrg_ReadFromFile_Or_Use_String(G, "indicator", "indicator.vs", ( make_program("sphere", "sphere.vs", "sphere.fs");
char*)indicator_vs);
fs = CShaderPrg_ReadFromFile_Or_Use_String(G, "indicator", "indicator.fs", (
char*)indicator_fs);
indicatorShader = CShaderPrg_New(G, "indicator", vs, fs);
}
if (indicatorShader && defaultShader){
CShaderPrg_Link(indicatorShader);
CShaderMgr_AddShaderPrg(G->ShaderMgr, indicatorShader);
if (indicatorShader){
glBindAttribLocation(indicatorShader->id, VERTEX_POS, "a_Vertex");
WARNING_IF_GLERROR("a_Vertex");
glBindAttribLocation(indicatorShader->id, VERTEX_COLOR, "a_Color");
WARNING_IF_GLERROR("a_Color");
CShaderPrg_Link(indicatorShader);
CShaderMgr_AddShaderPrg(G->ShaderMgr, indicatorShader);
}
} }
PRINTFB(G, FB_ShaderMgr, FB_Debugging) "reading in bg.vs and bg.fs\n" ENDFB(G) make_program("ramp", "ramp.vs", "ramp.fs");
; programs["ramp"]->uniformLocations[RAMP_OFFSETPT] = "offsetPt";
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "bg_vs")] = CShaderPrg_ReadF
romFile_Or_Use_String(G, "bg", "bg.vs", (char*)bg_vs);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "bg_fs")] = CShaderPrg_ReadF
romFile_Or_Use_String(G, "bg", "bg.fs", (char*)bg_fs);
bgShader = CShaderPrg_New(G, "bg",
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "b
g_vs")],
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "b
g_fs")]);
if (bgShader){
CShaderPrg_Link(bgShader);
CShaderMgr_AddShaderPrg(G->ShaderMgr, bgShader);
}
CShaderPrg_BindAttribLocations(G, "default");
CShaderPrg_BindAttribLocations(G, "defaultscreen");
ok_assert(1, defaultShader);
CShaderMgr_AddShaderPrg(G->ShaderMgr, defaultShader);
CShaderMgr_AddShaderPrg(G->ShaderMgr, defaultScreenShader);
PRINTFB(G, FB_ShaderMgr, FB_Debugging) "reading in volume.vs and volume.fs\n"
ENDFB(G);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "volume_vs")] = CShaderPrg_R
eadFromFile_Or_Use_String(G, "volume", "volume.vs", (char*)volume_vs);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "volume_fs")] = CShaderPrg_R
eadFromFile_Or_Use_String(G, "volume", "volume.fs", (char*)volume_fs);
volumeShader = CShaderPrg_New(G, "volume",
I->shader_replacement_strings[SHADERLEX_LOOKUP(G
, "volume_vs")],
I->shader_replacement_strings[SHADERLEX_LOOKUP(G
, "volume_fs")]);
ok_assert(1, volumeShader);
CShaderMgr_AddShaderPrg(G->ShaderMgr, volumeShader);
CShaderPrg_Reload_CallComputeColorForLight(G, "sphere");
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "sphere_vs")] = CShaderPrg_R
eadFromFile_Or_Use_String(G, "sphere", SPHERE_VS_FILENAME, (char*)sphere_vs);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "sphere_fs")] = CShaderPrg_R
eadFromFile_Or_Use_String(G, "sphere", SPHERE_FS_FILENAME, (char*)sphere_fs);
sphereShader = CShaderPrg_New(G, "sphere",
I->shader_replacement_strings[SHADERLEX_LOOKUP(G
, "sphere_vs")],
I->shader_replacement_strings[SHADERLEX_LOOKUP(G
, "sphere_fs")]);
ok_assert(1, sphereShader);
CShaderMgr_AddShaderPrg(G->ShaderMgr, sphereShader);
CShaderPrg_Reload_CallComputeColorForLight(G, "cylinder");
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "cylinder_vs")] = CShaderPrg
_ReadFromFile_Or_Use_String(G, "cylinder", CYLINDER_VS_FILENAME, (char*)cylinder
_vs);
I->shader_replacement_strings[SHADERLEX_LOOKUP(G, "cylinder_fs")] = CShaderPrg
_ReadFromFile_Or_Use_String(G, "cylinder", CYLINDER_FS_FILENAME, (char*)cylinder
_fs);
cylinderShader = CShaderPrg_New(G, "cylinder",
I->shader_replacement_strings[SHADERLEX_LOOKUP
(G, "cylinder_vs")],
I->shader_replacement_strings[SHADERLEX_LOOKUP
(G, "cylinder_fs")]);
CShaderMgr_AddShaderPrg(G->ShaderMgr, cylinderShader);
make_program("oit", "oit.vs", "oit.fs");
make_program("copy", "copy.vs", "copy.fs");
make_program("trilines", "trilines.vs", "trilines.fs");
Reload_Shader_Variables();
Reload_CallComputeColorForLight();
// shaders availability test
ok_assert(1, programs["default"]->reload());
#ifndef PURE_OPENGL_ES_2
// geometry shaders availability test
if (programs["connector"]->reload() && programs["connector"]->gid) {
shaders_present |= MASK_SHADERS_PRESENT_GEOMETRY;
} else {
disableGeometryShaders(G);
}
#else
SettingSetGlobal_b(G, cSetting_use_geometry_shaders, 0);
#endif
#define check_program(name, setting, value) { \
if (!programs[name]->reload()) { \
SettingSetGlobal_i(G, setting, value); \
programs.erase(name); \
}} \
// other shader compilation tests
if (GET_FRAGDEPTH_SUPPORT()) {
check_program("cylinder", cSetting_render_as_cylinders, 0);
check_program("sphere", cSetting_sphere_mode, 0);
}
#ifndef _PYMOL_NO_AA_SHADERS
#endif
// get filename -> shader program dependencies
for (auto it = programs.begin(); it != programs.end(); ++it) {
RegisterDependantFileNames(it->second);
}
// make transparency_mode_3 shader derivatives
MakeDerivatives("_t", "NO_ORDER_TRANSP");
#ifndef PURE_OPENGL_ES_2
/* report GLSL version */ /* report GLSL version */
if (G && G->Option && !G->Option->quiet) { if (G && G->Option && !G->Option->quiet) {
char buf[50];
int major, minor;
getGLSLVersion(G, &major, &minor); getGLSLVersion(G, &major, &minor);
sprintf(buf, " Detected GLSL version %d.%d.\n", major, minor); sprintf(buf, " Detected GLSL version %d.%d.\n", major, minor);
FeedbackAdd(G, buf); FeedbackAdd(G, buf);
} }
#endif
G->ShaderMgr->ShadersPresent |= 0x1; shaders_present |= 0x1;
CShaderPrg_Reload_All_Shaders(G);
SettingSetGlobal_b(G, cSetting_use_shaders, 1); SettingSetGlobal_b(G, cSetting_use_shaders, 1);
I->print_warnings = 0;
is_configured = true;
return; return;
ok_except1: ok_except1:
disableShaders(G); disableShaders(G);
G->ShaderMgr->ShadersPresent = 0; G->ShaderMgr->shaders_present = 0;
is_configured = true;
} }
/* getGLVersion -- determine user's GL version /* getGLVersion -- determine user's GL version
* PARAMS * PARAMS
* major, return value for major * major, return value for major
* minor, return value for minor * minor, return value for minor
* *
* RETURNS * RETURNS
* nothing; writes to major and minor * nothing; writes to major and minor
*/ */
skipping to change at line 959 skipping to change at line 851
PRINTFD(G, FB_ObjectVolume) PRINTFD(G, FB_ObjectVolume)
"Invalid GL_VERSION format.\n" ENDFD; "Invalid GL_VERSION format.\n" ENDFD;
} }
} }
/* getGLSLVersion -- determine user's GLSL version /* getGLSLVersion -- determine user's GLSL version
* PARAMS * PARAMS
* major, rval for major * major, rval for major
* minor, rval for minor * minor, rval for minor
*/ */
#ifndef PURE_OPENGL_ES_2
void getGLSLVersion(PyMOLGlobals * G, int* major, int* minor) { void getGLSLVersion(PyMOLGlobals * G, int* major, int* minor) {
int gl_major, gl_minor; int gl_major, gl_minor;
*major = *minor = 0; *major = *minor = 0;
/* grab the GL version */ /* grab the GL version */
getGLVersion(G, &gl_major, &gl_minor); getGLVersion(G, &gl_major, &gl_minor);
/* GL version 1 */ /* GL version 1 */
if (1==gl_major) { if (1==gl_major) {
const char* extstr = (const char*) glGetString(GL_EXTENSIONS); const char* extstr = (const char*) glGetString(GL_EXTENSIONS);
skipping to change at line 989 skipping to change at line 882
if ((verstr==NULL) || (sscanf(verstr, "%d.%d", major, minor)!=2)){ if ((verstr==NULL) || (sscanf(verstr, "%d.%d", major, minor)!=2)){
*major = *minor = 0; *major = *minor = 0;
if (G && G->Option && !G->Option->quiet) { if (G && G->Option && !G->Option->quiet) {
PRINTFD(G, FB_ObjectVolume) PRINTFD(G, FB_ObjectVolume)
"Invalid GL_SHADING_LANGUAGE_VERSION format.\n" ENDFD; "Invalid GL_SHADING_LANGUAGE_VERSION format.\n" ENDFD;
} }
} }
} }
} }
#endif
/* ============================================================================ /* ============================================================================
* CShaderMgr -- Simple Shader Manager class * CShaderMgr -- Simple Shader Manager class
*/ */
CShaderMgr * CShaderMgr_New(PyMOLGlobals * G) CShaderMgr::CShaderMgr(PyMOLGlobals * G_)
{ {
/* init/alloc the new ShaderMgr, now called 'I' */ G = G_;
OOAlloc(G, CShaderMgr); current_shader = 0;
shaders_present = 0;
stereo_flag = 0;
stereo_blend = 0;
#ifdef _PYMOL_LIB
print_warnings = 0;
#else
print_warnings = 1;
#endif
if (!G) { /* error out */ lightingTexture = 0;
return NULL; is_picking = 0;
} reload_bits = RELOAD_ALL_SHADERS;
if (!I) { #ifndef _WEBGL
/* error out */ vbos_to_free.reserve(256);
if (G && G->Option && !G->Option->quiet) { #endif
PRINTFB(G, FB_ShaderMgr, FB_Errors) }
" CShaderMgr_New-Error: Failed to create the shader manager. Shader disab
led.\n" ENDFB(G) CShaderMgr::~CShaderMgr() {
} for (auto it = programs.begin(); it != programs.end(); ++it) {
return NULL; delete it->second;
} }
programs.clear();
I->G = G; shader_cache_processed.clear();
I->current_shader = 0;
DListInit(I->programs, prev, next, CShaderPrg);
I->ShadersPresent = 0;
I->vbos_to_free = 0;
I->number_of_vbos_to_free = 0;
I->stereo_flag = 0;
I->print_warnings = 1;
return I;
}
void CShaderMgrFree(PyMOLGlobals *G){ for (int i = 0; i < 3; ++i)
CShaderMgr_Delete(G->ShaderMgr); freeGPUBuffer(offscreen_rt[i]);
}
void CShaderMgr_Delete(CShaderMgr * I) for (int i = 0; i < 2; ++i)
{ freeGPUBuffer(oit_rt[i]);
CShaderPrg * ptr, *target;
if (!I) { /* error out */
return;
}
if (I->programs) { freeGPUBuffer(areatex);
ptr = I->programs; freeGPUBuffer(searchtex);
while (ptr != I->programs) {
target = ptr;
ptr = ptr->next;
DListRemove(target, prev, next);
DListElemFree(target);
target=NULL;
}
}
OVLexicon_DEL_AUTO_NULL(I->ShaderLex);
OVOneToOne_Del(I->ShaderLexLookup);
CShaderMgr_Free_Shader_Arrays(I);
VLAFreeP(I->shader_replacement_strings);
VLAFreeP(I->shader_include_values);
{ FreeAllVBOs();
int i, sz = VLAGetSize(I->shader_update_when_include_filename);
for (i=0; i<sz;i++){
if (I->shader_update_when_include_filename[i]){
free(I->shader_update_when_include_filename[i]);
I->shader_update_when_include_filename[i] = 0;
I->shader_update_when_include[i] = 0;
}
}
}
VLAFreeP(I->shader_update_when_include_filename);
VLAFreeP(I->shader_update_when_include);
OOFreeP(I);
} }
int CShaderMgr_AddShaderPrg(CShaderMgr * I, CShaderPrg * s) int CShaderMgr::AddShaderPrg(CShaderPrg * s) {
{ if (!s)
if (!I || !s)
return 0; return 0;
const string& name = s->name;
DListInsert(I->programs, s, prev, next); if (programs.find(name)!=programs.end()){
delete programs[name];
}
programs[name] = s;
return 1; return 1;
} }
int CShaderMgr_RemoveShaderPrg(CShaderMgr * I, const char * name) int CShaderMgr::RemoveShaderPrg(const string& name) {
{ if (programs.find(name) != programs.end()){
CShaderPrg * p = NULL; delete programs[name];
DListIterate(I->programs, p, next) }
{
if (p && strcmp(p->name,name)==0) break;
}
DListRemove(p, prev, next);
return 1; return 1;
} }
CShaderPrg * CShaderMgr_GetShaderPrgImpl(CShaderMgr * I, const char * name, shor /*
t set_current_shader); * Lookup a shader program by name and set it as the `current_shader` of the
* shader manager. If `pass` is provided and is less than zero, and we are
* in transparency_mode 3, then look up the NO_ORDER_TRANSP derivative.h
*/
CShaderPrg * CShaderMgr::GetShaderPrg(std::string name, short set_current_shader
, short pass) {
if (pass < 0 && SettingGetGlobal_i(G, cSetting_transparency_mode) == 3) {
name += "_t";
}
auto it = programs.find(name);
if (it == programs.end())
return NULL;
CShaderPrg * CShaderMgr_GetShaderPrg_NoSet(CShaderMgr * I, const char * name){ if (set_current_shader)
return CShaderMgr_GetShaderPrgImpl(I, name, 0); current_shader = it->second;
}
CShaderPrg * CShaderMgr_GetShaderPrg(CShaderMgr * I, const char * name){ return it->second;
return CShaderMgr_GetShaderPrgImpl(I, name, 1);
} }
CShaderPrg * CShaderMgr_GetShaderPrgImpl(CShaderMgr * I, const char * name, shor int CShaderMgr::ShaderPrgExists(const char * name){
t set_current_shader) return (programs.find(name) != programs.end());
{
CShaderPrg * p = NULL, *ret = NULL;
DListIterate(I->programs, p, next)
{
if (p && strcmp(p->name,name)==0){
ret = p;
break;
}
}
if (set_current_shader){
I->current_shader = ret;
}
return ret;
} }
int CShaderMgr_ShaderPrgExists(CShaderMgr * I, const char * name){ int CShaderMgr::ShadersPresent() {
CShaderPrg * p = NULL, *ret = NULL; return shaders_present;
DListIterate(I->programs, p, next)
{
if (p && strcmp(p->name,name)==0){
ret = p;
break;
}
}
return ret!=NULL;
} }
int CShaderMgr_ShadersPresent(CShaderMgr * I) int CShaderMgr::GeometryShadersPresent() {
{ return shaders_present & MASK_SHADERS_PRESENT_GEOMETRY;
return I->ShadersPresent;
} }
char * CShaderMgr_ReadShaderFromDisk(PyMOLGlobals * G, const char * fileName) { /*
char* buffer = NULL, *pymol_path, *shader_path, *fullFile; * glDeleteBuffers for vbos_to_free
*/
void CShaderMgr::FreeAllVBOs() {
#ifndef _WEBGL
freeAllGPUBuffers();
PRINTFB(G, FB_ShaderMgr, FB_Debugging) LOCK_GUARD_MUTEX(lock, vbos_to_free_mutex);
"CShaderMgr_ReadShaderFromDisk: fileName='%s'\n", fileName
ENDFB(G);
/* check the input */
if (!strlen(fileName)) {
PRINTFB(G, FB_ShaderMgr, FB_Errors)
" PyMOLShader_NewFromFile-Error: empty filename, cannot create shader. " E
NDFB(G);
return NULL;
}
pymol_path = getenv("PYMOL_PATH"); if (vbos_to_free.empty())
if (!pymol_path){ return;
PRINTFB(G, FB_ShaderMgr, FB_Warnings)
" PyMOLShader_NewFromFile-Warning: PYMOL_PATH not set, cannot read shader glDeleteBuffers(vbos_to_free.size(), &vbos_to_free[0]);
config files from disk\n" ENDFB(G);
return NULL;
}
/* make this a setting */
shader_path = "/data/shaders/";
fullFile = Alloc(char, strlen(pymol_path) + strlen(shader_path) + strlen(fileN
ame) + 1);
fullFile = strcpy(fullFile, pymol_path);
fullFile = strcat(fullFile, shader_path);
fullFile = strcat(fullFile, fileName);
buffer = FileGetContents(fullFile, NULL);
if (!buffer) {
PRINTFB(G, FB_ShaderMgr, FB_Errors)
" PyMOLShader_NewFromFile-Error: Unable to open file '%s' PYMOL_PATH='%s'\
n", fullFile, pymol_path ENDFB(G);
return NULL;
} else {
PRINTFB(G, FB_ShaderMgr, FB_Blather)
" PyMOLShader_NewFromFile: Loading shader from '%s'.\n", fullFile ENDFB(G)
;
}
free(fullFile); vbos_to_free.clear();
return buffer; #endif
} }
#ifdef _PYMOL_ARB_SHADERS void CShaderMgr::AddVBOsToFree(GLuint *vboid, int nvbos){
static GLboolean ProgramStringIsNative(PyMOLGlobals * G, int i;
GLenum target, GLenum format, for (i=0; i<nvbos; i++){
GLsizei len, const GLvoid * string) if (vboid[i]>0)
{ AddVBOToFree(vboid[i]);
GLint errorPos, isNative;
glProgramStringARB(target, format, len, string);
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
glGetProgramivARB(target, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &isNative);
if((errorPos == -1) && (isNative == 1))
return GL_TRUE;
else if(errorPos >= 0) {
if(Feedback(G, FB_OpenGL, FB_Errors)) {
printf("OpenGL-Error: ARB shader error at char %d\n---->%s\n", errorPos,
((char *) string) + errorPos);
}
} }
return GL_FALSE;
} }
CShaderPrg * CShaderPrg_NewARB(PyMOLGlobals * G, const char * name, const char * /*
v, const char * f) * thread-safe deferred glDeleteBuffers(1, &vboid)
{ */
/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */ void CShaderMgr::AddVBOToFree(GLuint vboid){
#ifdef WIN32 #ifdef _WEBGL // No threads, immediately delete
if(!(glGenProgramsARB && glBindProgramARB && if (glIsBuffer(vboid)) {
glDeleteProgramsARB && glProgramStringARB && glProgramEnvParameter4fARB)) glDeleteBuffers(1, &vboid);
{ } else {
glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) wglGetProcAddress("glGenProgram PRINTFB(G, FB_ShaderMgr, FB_Warnings) "WARNING: CShaderMgr_AddVBOToFree() bu
sARB"); ffer is not a VBO %d", vboid ENDFB(G);
glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) wglGetProcAddress("glBindProgra
mARB");
glDeleteProgramsARB =
(PFNGLDELETEPROGRAMSARBPROC) wglGetProcAddress("glDeleteProgramsARB");
glProgramStringARB =
(PFNGLPROGRAMSTRINGARBPROC) wglGetProcAddress("glProgramStringARB");
glProgramEnvParameter4fARB =
(PFNGLPROGRAMENVPARAMETER4FARBPROC) wglGetProcAddress("glProgramEnvParamet
er4fARB");
glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) wglGetProcAddress("glGetProgr
amivARB");
} }
#else
if(glGenProgramsARB && glBindProgramARB && LOCK_GUARD_MUTEX(lock, vbos_to_free_mutex);
glDeleteProgramsARB && glProgramStringARB && glProgramEnvParameter4fARB) vbos_to_free.push_back(vboid);
#endif #endif
{ }
/* END PROPRIETARY CODE SEGMENT */
int ok = true;
GLuint programs[2];
glGenProgramsARB(2, programs);
/* load the vertex program */
glBindProgramARB(GL_VERTEX_PROGRAM_ARB, programs[0]);
ok = ok && (ProgramStringIsNative(G, GL_VERTEX_PROGRAM_ARB, CShaderPrg *CShaderMgr::Enable_DefaultShaderWithSettings(
GL_PROGRAM_FORMAT_ASCII_ARB, strlen(v), v)) const CSetting *set1,
; const CSetting *set2, int pass) {
CShaderPrg * shaderPrg = Get_DefaultShader(pass);
return Setup_DefaultShader(shaderPrg, set1, set2);
}
if(Feedback(G, FB_OpenGL, FB_Debugging)) CShaderPrg *CShaderMgr::Enable_DefaultShader(int pass){
PyMOLCheckOpenGLErr("loading vertex program"); CShaderPrg * shaderPrg = Get_DefaultShader(pass);
return Setup_DefaultShader(shaderPrg, NULL, NULL);
}
/* load the fragment program */ CShaderPrg *CShaderMgr::Enable_LineShader(int pass){
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, programs[1]); CShaderPrg * shaderPrg = Get_LineShader(pass);
return Setup_DefaultShader(shaderPrg, NULL, NULL);
}
ok = ok && (ProgramStringIsNative(G, GL_FRAGMENT_PROGRAM_ARB, CShaderPrg *CShaderMgr::Enable_SurfaceShader(int pass){
GL_PROGRAM_FORMAT_ASCII_ARB, strlen(f), f)) CShaderPrg * shaderPrg = Get_SurfaceShader(pass);
; return Setup_DefaultShader(shaderPrg, NULL, NULL);
}
if(Feedback(G, FB_OpenGL, FB_Debugging)) CShaderPrg *CShaderMgr::Enable_ConnectorShader(int pass){
PyMOLCheckOpenGLErr("loading fragment program"); CShaderPrg * shaderPrg = Get_ConnectorShader(pass);
if(ok) { if (!shaderPrg)
CShaderPrg * I = NULL; return 0;
shaderPrg = Setup_DefaultShader(shaderPrg, NULL, NULL);
shaderPrg->SetLightingEnabled(0);
{
float front, back;
front = SceneGetCurrentFrontSafe(G);
back = SceneGetCurrentBackSafe(G);
shaderPrg->Set1f("front", front);
shaderPrg->Set1f("clipRange", back - front);
}
DListElemAlloc(G, I, CShaderPrg); int width, height;
DListElemInit(I, prev, next); SceneGetWidthHeightStereo(G, &width, &height);
shaderPrg->Set2f("screenSize", width, height);
I->G = G; {
I->name = strdup(name); float v_scale = SceneGetScreenVertexScale(G, NULL);
shaderPrg->Set1f("screenOriginVertexScale", v_scale/2.f);
}
I->vid = programs[0]; return shaderPrg;
I->fid = programs[1]; }
CShaderMgr_AddShaderPrg(G->ShaderMgr, I); CShaderPrg *CShaderMgr::Setup_DefaultShader(CShaderPrg * shaderPrg,
const CSetting *set1,
const CSetting *set2) {
if (!shaderPrg){
current_shader = NULL;
return shaderPrg;
}
shaderPrg->Enable();
shaderPrg->SetBgUniforms();
shaderPrg->Set_Stereo_And_AnaglyphMode();
bool two_sided_lighting_enabled = SceneGetTwoSidedLightingSettings(G, set1, se
t2);
shaderPrg->SetLightingEnabled(1); // lighting on by default
shaderPrg->Set1i("two_sided_lighting_enabled", two_sided_lighting_enabled);
shaderPrg->Set1f("ambient_occlusion_scale", 0.f);
shaderPrg->Set1i("accessibility_mode", SettingGetGlobal_i(G, cSetting_ambient_
occlusion_mode) / 4);
shaderPrg->Set1f("accessibility_mode_on", SettingGetGlobal_i(G, cSetting_ambie
nt_occlusion_mode) ? 1.f : 0.f);
return I; // interior_color
{
int interior_color = SettingGet_i(G, set1, set2, cSetting_ray_interior_color
);
if (interior_color == cColorDefault || two_sided_lighting_enabled) {
shaderPrg->Set1i("use_interior_color", 0);
} else { } else {
glDeleteProgramsARB(2, programs); float inter[] = { 0.f, 0.f, 0.f };
ColorGetEncoded(G, interior_color, inter);
shaderPrg->Set1i("use_interior_color", 1);
shaderPrg->Set4f("interior_color", inter[0], inter[1], inter[2], 1.f);
} }
} }
return NULL;
}
int CShaderPrg_DisableARB(CShaderPrg * p) { shaderPrg->Set_Specular_Values();
if (p) shaderPrg->Set_Matrices();
p->G->ShaderMgr->current_shader = 0; return (shaderPrg);
glDisable(GL_FRAGMENT_PROGRAM_ARB); }
glDisable(GL_VERTEX_PROGRAM_ARB); CShaderPrg *CShaderMgr::Enable_CylinderShader(int pass){
return 1; return Enable_CylinderShader("cylinder", pass);
} }
#endif
/* ============================================================================ CShaderPrg *CShaderMgr::Enable_CylinderShader(const char *shader_name, int pass)
* CShaderPrg -- Simple Shader class {
*/ int width, height;
CShaderPrg * CShaderPrg_New(PyMOLGlobals * G, const char * name, const char * v, CShaderPrg *shaderPrg;
const char * f)
{
int status, howLong;
char infoLog[MAX_LOG_LEN];
/* if v == f == NULL, read 'name.vs' and 'name.fs' from disk */
CShaderPrg * I = NULL;
DListElemCalloc(G, I, CShaderPrg);
DListElemInit(I, prev, next);
I->G = G;
I->name = strdup(name);
I->id = glCreateProgram();
PRINTFB(G, FB_ShaderMgr, FB_Debugging)
"Created program with id: %d\n", I->id ENDFB(G);
ok_assert(1, I->id);
if (v){
/* VERTEX shader setup */
I->v = strdup(v);
I->vid = glCreateShader(GL_VERTEX_SHADER);
PRINTFB(G, FB_ShaderMgr, FB_Debugging)
"Created vertex shader with id: %d\n", I->vid ENDFB(G);
glShaderSource(I->vid, 1, (const GLchar**) &I->v, NULL);
glCompileShader((GLuint) I->vid);
/* verify compilation */
glGetShaderiv(I->vid, GL_COMPILE_STATUS, &status);
if (!status) {
if (G && G->Option && !G->Option->quiet) {
PRINTFB(G, FB_ShaderMgr, FB_Errors) " CShaderPrg_New-Error: vertex shader
compilation failed name='%s'; log follows.\n", I->name ENDFB(G);
glGetShaderInfoLog(I->vid, MAX_LOG_LEN-1, &howLong, infoLog);
PRINTFB(G, FB_ShaderMgr, FB_Errors)
"infoLog=%s\n", infoLog ENDFB(G);
PRINTFB(G, FB_ShaderMgr, FB_Errors)
"shader: %s\n", I->v ENDFB(G);
}
ok_raise(1);
}
PRINTFB(G, FB_ShaderMgr, FB_Debugging)
"CShaderPrg_New-Message: vertex shader compiled.\n" ENDFB(G);
glAttachShader(I->id, I->vid);
}
if (f){ SceneGetWidthHeightStereo(G, &width, &height);
/* FRAGMENT source setup */ shaderPrg = GetShaderPrg(shader_name, 1, pass);
/* CShaderPrg_InitShader(I, GL_FRAGMENT_SHADER); */ if (!shaderPrg)
I->f = strdup(f); return NULL;
I->fid = glCreateShader(GL_FRAGMENT_SHADER); shaderPrg->Enable();
PRINTFB(G, FB_ShaderMgr, FB_Debugging)
"Created fragment shader with id: %d\n", I->fid
ENDFB(G);
glShaderSource(I->fid, 1, (const GLchar **) &I->f, NULL); shaderPrg->SetLightingEnabled(1); // lighting on by default
glCompileShader((GLuint) I->fid);
/* verify compilation */
glGetShaderiv(I->fid, GL_COMPILE_STATUS, &status);
if (!status) {
if (G && G->Option && !G->Option->quiet) {
PRINTFB(G, FB_ShaderMgr, FB_Errors)
" CShaderPrg-Error: fragment shader compilation failed name='%s'; log f
ollows.\n", I->name
ENDFB(G);
glGetShaderInfoLog(I->fid, MAX_LOG_LEN-1, &howLong, infoLog);
PRINTFB(G, FB_ShaderMgr, FB_Errors)
"infoLog=%s\n", infoLog ENDFB(G);
}
ok_raise(1);
}
glAttachShader(I->id, I->fid);
}
if (v && f){ shaderPrg->Set1f("uni_radius", 0.f);
/* Link the new program */
ok_assert(1, CShaderPrg_Link(I));
}
I->uniform_set = 0;
return I; shaderPrg->Set_Stereo_And_AnaglyphMode();
ok_except1:
CShaderPrg_Delete(I);
return NULL;
}
CShaderPrg * CShaderPrg_NewFromFile(PyMOLGlobals * G, const char * name, const c shaderPrg->Set1f("inv_height", 1.0/height);
har * vFile, const char * fFile) shaderPrg->Set1i("no_flat_caps", 1);
{ {
char *vFileStr = NULL, *fFileStr = NULL; float smooth_half_bonds = (SettingGetGlobal_i(G, cSetting_smooth_half_bonds)
if (vFile){ ) ? .2f : 0.f;
vFileStr = CShaderMgr_ReadShaderFromDisk(G, vFile); shaderPrg->Set1f("half_bond", smooth_half_bonds);
if (!vFileStr){
return (NULL);
}
}
if (fFile){
fFileStr = CShaderMgr_ReadShaderFromDisk(G, fFile);
if (!fFileStr){
return (NULL);
}
} }
return CShaderPrg_New(G, name, shaderPrg->Set_Specular_Values();
vFileStr, shaderPrg->Set_Matrices();
fFileStr);
}
void CShaderPrg_Delete(CShaderPrg * I) shaderPrg->SetBgUniforms();
{
if (I->vid)
glDeleteShader(I->vid);
if (I->fid)
glDeleteShader(I->fid);
if (I->id)
glDeleteProgram(I->id);
OOFreeP(I->v);
OOFreeP(I->f);
OOFreeP(I->name);
I->next = I->prev = NULL;
DListElemFree(I);
}
int CShaderPrg_Enable(CShaderPrg * I) // always enable backface culling for cylinders
{ glCullFace(GL_BACK);
int howLong, ok; glEnable(GL_CULL_FACE);
PyMOLGlobals * G = I->G; return shaderPrg;
if (!I) return 0;
/* linked? */
ok = CShaderPrg_IsLinked(I);
/* no, so give it a shot */
if (!ok) {
ok = CShaderPrg_Link(I);
}
/* did that work? */
if (!ok) {
if (G && G->Option && !G->Option->quiet) {
int infoLogLength = 0;
glGetProgramiv(I->id, GL_INFO_LOG_LENGTH, &infoLogLength);
PRINTFB(G, FB_ShaderMgr, FB_Errors)
"CShaderPrg_Enable-Error: Cannot enable the shader program; linking faile
d. Shaders disabled. Log follows.\n"
ENDFB(G);
if (!glGetError() && infoLogLength>0){
char *infoLog = Alloc(char, infoLogLength);
glGetProgramInfoLog(I->id, infoLogLength, &howLong, infoLog);
PRINTFB(G, FB_ShaderMgr, FB_Errors)
"%s\n", infoLog
ENDFB(G);
FreeP(infoLog);
}
}
return 0;
}
/* if so, use the program */
glUseProgram(I->id);
return 1;
} }
int CShaderPrg_Disable(CShaderPrg * p) CShaderPrg *CShaderMgr::Get_DefaultSphereShader(int pass){
{ return GetShaderPrg("sphere", 1, pass);
glUseProgram(0);
if (p)
p->G->ShaderMgr->current_shader = 0;
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
return 1;
} }
int CShaderPrg_IsLinked(CShaderPrg * I ) CShaderPrg *CShaderMgr::Enable_DefaultSphereShader(int pass) {
{ CShaderPrg *shaderPrg = Get_DefaultSphereShader(pass);
int status; if (!shaderPrg) return NULL;
glGetProgramiv(I->id, GL_LINK_STATUS, &status); shaderPrg->Enable();
return status==GL_TRUE; shaderPrg->SetLightingEnabled(1);
} shaderPrg->Set1f("sphere_size_scale", 1.f);
int CShaderPrg_Link(CShaderPrg * I) shaderPrg->Set_Stereo_And_AnaglyphMode();
{
PyMOLGlobals * G = I->G;
int howLong;
glLinkProgram(I->id); shaderPrg->Set_Specular_Values();
shaderPrg->Set_Matrices();
if (!CShaderPrg_IsLinked(I)) { shaderPrg->SetBgUniforms();
if (G && G->Option && !G->Option->quiet) {
GLint maxVarFloats;
int infoLogLength = 0;
glGetIntegerv(GL_MAX_VARYING_FLOATS, &maxVarFloats); return (shaderPrg);
PRINTFB(G, FB_ShaderMgr, FB_Errors)
" CShaderPrg_Link-Error: Shader program failed to link name='%s'; GL_MAX
_VARYING_FLOATS=%d log follows.\n", I->name, maxVarFloats
ENDFB(G);
glGetProgramiv(I->id, GL_INFO_LOG_LENGTH, &infoLogLength);
if (!glGetError() && infoLogLength>0){
char *infoLog = Alloc(char, infoLogLength);
glGetProgramInfoLog(I->id, infoLogLength, &howLong, infoLog);
PRINTFB(G, FB_ShaderMgr, FB_Errors)
"%s\n", infoLog
ENDFB(G);
FreeP(infoLog);
}
}
return 0;
}
return 1;
} }
/* accessors/mutators/uniform setters */ #ifdef _PYMOL_ARB_SHADERS
int CShaderPrg_Set1i(CShaderPrg * p, const char * name, int i) CShaderPrg *CShaderMgr::Enable_SphereShaderARB(){
{ CShaderPrg *shaderPrg = NULL;
if (p && p->id) { /* load the vertex program */
GLint loc = glGetUniformLocation(p->id, name); if (current_shader)
if (loc < 0) current_shader->Disable();
return 0; shaderPrg = GetShaderPrg("sphere_arb");
glUniform1i(loc, i); glBindProgramARB(GL_VERTEX_PROGRAM_ARB, shaderPrg->vid);
}
return 1;
}
int CShaderPrg_Set3f(CShaderPrg * p, const char * name, float f1, float f2, floa /* load the fragment program */
t f3) glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shaderPrg->fid);
{
if (p && p->id) {
GLint loc = glGetUniformLocation(p->id, name);
if (loc < 0)
return 0;
glUniform3f(loc, f1, f2, f3);
}
return 1;
}
int CShaderPrg_Set2f(CShaderPrg * p, const char * name, float f1, float f2) /* load some safe initial values */
{ glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, 0, 0.0F, 0.0F, 1.0F, 0.0F);
if (p && p->id) { glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, 0.5F, 2.0F, 0.0F, 0.0F)
GLint loc = glGetUniformLocation(p->id, name); ;
if (loc < 0)
return 0;
glUniform2f(loc, f1, f2);
}
return 1;
}
int CShaderPrg_SetMat3f_Impl(CShaderPrg * p, const char * name, const GLfloat* m glEnable(GL_VERTEX_PROGRAM_ARB);
, GLboolean transpose) { glEnable(GL_FRAGMENT_PROGRAM_ARB);
if (p && p->id) {
GLint loc = glGetUniformLocation(p->id, name);
if (loc < 0)
return 0;
glUniformMatrix3fv(loc, 1, transpose, m);
}
return 1;
}
int CShaderPrg_SetMat4f_Impl(CShaderPrg * p, const char * name, GLfloat* m, GLbo return shaderPrg;
olean transpose) {
if (p && p->id) {
GLint loc = glGetUniformLocation(p->id, name);
if (loc < 0)
return 0;
glUniformMatrix4fv(loc, 1, transpose, m);
}
return 1;
} }
#endif
int CShaderPrg_SetMat3f(CShaderPrg * p, const char * name, const GLfloat * m){ CShaderPrg *CShaderMgr::Get_ConnectorShader(int pass){
return (CShaderPrg_SetMat3f_Impl(p, name, m, GL_TRUE)); return GetShaderPrg("connector", 1, pass);
} }
int CShaderPrg_SetMat4f(CShaderPrg * p, const char * name, GLfloat * m){ CShaderPrg *CShaderMgr::Get_DefaultShader(int pass){
return (CShaderPrg_SetMat4f_Impl(p, name, m, GL_TRUE)); return GetShaderPrg("default", 1, pass);
} }
/* CShaderPrg *CShaderMgr::Get_LineShader(int pass){
int CShaderPrg_SetTexture2D(CShaderPrg * p, const char * name, GLuint i){ return GetShaderPrg("line", 1, pass);
if (p && p->id) {
GLint loc = glGetUniformLocation(p->id, name);
if (loc < 0)
return 0;
glUniform1i(loc, 1, i);
}
return 1;
}
*/
int CShaderPrg_SetMat3fc(CShaderPrg * p, const char * name, GLfloat * m){
return (CShaderPrg_SetMat3f_Impl(p, name, m, GL_FALSE));
} }
int CShaderPrg_SetMat4fc(CShaderPrg * p, const char * name, GLfloat * m){ CShaderPrg *CShaderMgr::Get_SurfaceShader(int pass){
return (CShaderPrg_SetMat4f_Impl(p, name, m, GL_FALSE)); return GetShaderPrg("surface", 1, pass);
} }
int CShaderPrg_Set4fv(CShaderPrg * p, const char * name, float *f){ CShaderPrg *CShaderMgr::Get_CylinderShader(int pass, short set_current_shader) {
return (CShaderPrg_Set4f(p, name, f[0], f[1], f[2], f[3])); return GetShaderPrg("cylinder", set_current_shader, pass);
} }
int CShaderPrg_Set3fv(CShaderPrg * p, const char * name, float *f){
return (CShaderPrg_Set3f(p, name, f[0], f[1], f[2])); CShaderPrg *CShaderMgr::Get_CylinderNewShader(int pass, short set_current_shader
) {
return GetShaderPrg("cylinder_new", set_current_shader, pass);
} }
int CShaderPrg_Set4f(CShaderPrg * p, const char * name, float f1, float f2, floa CShaderPrg *CShaderMgr::Get_Current_Shader(){
t f3, float f4) return current_shader;
{
if (p && p->id) {
GLint loc = glGetUniformLocation(p->id, name);
if (loc < 0)
return 0;
glUniform4f(loc, f1, f2, f3, f4);
}
return 1;
} }
int CShaderPrg_Set1f(CShaderPrg * p, const char * name, float f) CShaderPrg *CShaderMgr::Get_BackgroundShader(){
{ return GetShaderPrg("bg");
if (p && p->id) {
GLint loc = glGetUniformLocation(p->id, name);
if (loc < 0)
return 0;
glUniform1f(loc, f);
}
return 1;
} }
int CShaderPrg_GetAttribLocation(CShaderPrg * p, const char * name) CShaderPrg *CShaderMgr::Enable_BackgroundShader(){
{ CShaderPrg * shaderPrg = Get_BackgroundShader();
GLint loc = -1; if (!shaderPrg) return shaderPrg;
shaderPrg->Enable();
if (p && p->id) { glDisable(GL_DEPTH_TEST);
loc = glGetAttribLocation(p->id, name); shaderPrg->SetBgUniforms();
if (loc < 0)
return -1;
}
return loc;
}
void CShaderPrg_SetAttrib4fLocation(CShaderPrg * p, const char * name, float f1, return shaderPrg;
float f2, float f3, float f4){
if (p){
int attr = CShaderPrg_GetAttribLocation(p, name);
if (attr>=0){
glVertexAttrib4f(attr, f1, f2, f3, f4);
}
}
} }
void CShaderPrg_SetAttrib1fLocation(CShaderPrg * p, const char * name, float f1) CShaderPrg *CShaderMgr::Enable_TriLinesShader() {
{ CShaderPrg * shaderPrg = GetShaderPrg("trilines");
if (p){ if (!shaderPrg) return shaderPrg;
int attr = CShaderPrg_GetAttribLocation(p, name); shaderPrg->Enable();
if (attr>=0){ shaderPrg->SetBgUniforms();
glVertexAttrib1f(attr, f1); shaderPrg->Set_Stereo_And_AnaglyphMode();
} shaderPrg->Set_Matrices();
} {
} int width, height;
SceneGetWidthHeightStereo(G, &width, &height);
void CShaderMgr_FreeAllVBOs(CShaderMgr * I){ shaderPrg->Set2f("inv_dimensions", 1.f/width, 1.f/height);
GLuint *vboids = I->vbos_to_free, nvbos = I->number_of_vbos_to_free;
I->vbos_to_free = 0;
I->number_of_vbos_to_free = 0;
if (I && vboids){
GLuint i, nvbo=0 ;
for (i=0; i<nvbos; i++){
if (glIsBuffer(vboids[i])){
vboids[nvbo++] = vboids[i];
} else {
PRINTFB(I->G, FB_ShaderMgr, FB_Warnings) "WARNING: CShaderMgr_FreeAllVBOs
() buffer is not a VBO i=%d vboids[i]=%d\n", i, vboids[i] ENDFB(I->G);
}
}
if (nvbo){
glDeleteBuffers(nvbo, vboids);
}
VLAFree(vboids);
} }
return shaderPrg;
} }
#define STEP_FOR_BUF 100 #ifndef _PYMOL_NO_AA_SHADERS
#endif
void CShaderMgr_AddVBOsToFree(CShaderMgr * I, GLuint *vboid, int nvbos){ CShaderPrg *CShaderMgr::Enable_OITShader() {
int i; CShaderPrg * shaderPrg = GetShaderPrg("oit");
for (i=0; i<nvbos; i++){ if (!shaderPrg) return shaderPrg;
if (vboid[i]>0) shaderPrg->Enable();
CShaderMgr_AddVBOToFree(I, vboid[i]); glActiveTexture(GL_TEXTURE5);
} bindOffscreenOITTexture(0);
glActiveTexture(GL_TEXTURE6);
bindOffscreenOITTexture(1);
shaderPrg->Set1i("accumTex", 5);
shaderPrg->Set1i("revealageTex", 6);
shaderPrg->Set1f("isRight", stereo_flag > 0 ? 1. : 0);
glEnable(GL_BLEND);
glBlendFuncSeparate(
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
#ifndef PURE_OPENGL_ES_2
glDisable(GL_ALPHA_TEST);
#endif
return shaderPrg;
} }
void CShaderMgr_AddVBOToFree(CShaderMgr * I, GLuint vboid){ CShaderPrg *CShaderMgr::Enable_OITCopyShader() {
if (I && I->vbos_to_free){ CShaderPrg * shaderPrg = GetShaderPrg("copy");
int nvbostofree = I->number_of_vbos_to_free++; if (!shaderPrg) return shaderPrg;
int exp = STEP_FOR_BUF*(1+((nvbostofree+1)/STEP_FOR_BUF)); shaderPrg->Enable();
VLACheck(I->vbos_to_free, GLuint, exp); glActiveTexture(GL_TEXTURE7);
I->vbos_to_free[nvbostofree] = vboid; bindOffscreenTexture(0);
shaderPrg->Set1i("colorTex", 7);
if (G->ShaderMgr->stereo_blend){
// for full-screen stereo
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
} else { } else {
I->vbos_to_free = VLAlloc(GLuint, STEP_FOR_BUF); glDisable(GL_BLEND);
I->vbos_to_free[0] = vboid;
I->number_of_vbos_to_free = 1;
} }
glDisable(GL_DEPTH_TEST);
#ifndef PURE_OPENGL_ES_2
glDisable(GL_ALPHA_TEST);
#endif
return shaderPrg;
} }
void CShaderPrg_Set_Specular_Values(PyMOLGlobals * G, CShaderPrg * shaderPrg){ CShaderPrg *CShaderMgr::Enable_LabelShader(int pass){
float spec_value = SettingGetGlobal_f(G, cSetting_specular); CShaderPrg *shaderPrg;
float settingSpecReflect, settingSpecDirect, settingSpecDirectPower, settingSp shaderPrg = Get_LabelShader(pass);
ecPower; if (!shaderPrg)
return NULL;
shaderPrg->Enable();
return Setup_LabelShader(shaderPrg);
}
settingSpecPower = SettingGetGlobal_f(G, cSetting_spec_power); CShaderPrg *CShaderMgr::Enable_ScreenShader(){
CShaderPrg *shaderPrg;
shaderPrg = Get_ScreenShader();
if (!shaderPrg)
return NULL;
shaderPrg->Enable();
if(settingSpecPower < 0.0F) { int ortho_width, ortho_height;
settingSpecPower = SettingGetGlobal_f(G, cSetting_shininess); OrthoGetSize(G, &ortho_width, &ortho_height);
} shaderPrg->Set2f("t2PixelSize", 2.f / ortho_width, 2.f / ortho_height);
CShaderPrg_Set1f(shaderPrg, "shininess", settingSpecPower); return Setup_LabelShader(shaderPrg);
}
if(spec_value == 1.0F) CShaderPrg *CShaderMgr::Enable_RampShader(){
spec_value = SettingGetGlobal_f(G, cSetting_specular_intensity); CShaderPrg *shaderPrg;
shaderPrg = Get_RampShader();
if (!shaderPrg)
return NULL;
shaderPrg->Enable();
return Setup_LabelShader(shaderPrg);
}
settingSpecReflect = SettingGetGlobal_f(G, cSetting_spec_reflect); CShaderPrg *CShaderMgr::Setup_LabelShader(CShaderPrg *shaderPrg) {
settingSpecReflect = SceneGetSpecularValue(G, settingSpecReflect, 10); int width = 0, height = 0;
settingSpecDirect = SettingGetGlobal_f(G, cSetting_spec_direct);
settingSpecDirectPower = SettingGetGlobal_f(G, cSetting_spec_direct_power);
if(settingSpecReflect < 0.0F) shaderPrg->Set_Matrices();
settingSpecReflect = spec_value;
if(settingSpecDirect < 0.0F)
settingSpecDirect = spec_value;
if(settingSpecDirectPower < 0.0F)
settingSpecDirectPower = settingSpecPower;
if(settingSpecReflect > 1.0F) glActiveTexture(GL_TEXTURE3);
settingSpecReflect = 1.0F; glBindTexture(GL_TEXTURE_2D, TextureGetTextTextureID(G));
if(SettingGetGlobal_f(G, cSetting_specular) < R_SMALL4) { if (!(shaderPrg->uniform_set & 8)){
settingSpecReflect = 0.0F; shaderPrg->uniform_set |= 8;
shaderPrg->Set1i("textureMap", 3);
} }
CShaderPrg_Set1f(shaderPrg, "spec_value_0", settingSpecDirect);
CShaderPrg_Set1f(shaderPrg, "shininess_0", settingSpecDirectPower);
CShaderPrg_Set1f(shaderPrg, "spec_value", settingSpecReflect);
}
void CShaderPrg_Set_AnaglyphMode(PyMOLGlobals * G, CShaderPrg * shaderPrg, int m SceneGetWidthHeightStereo(G, &width, &height);
ode) {
extern float anaglyphR_constants[6][9];
extern float anaglyphL_constants[6][9];
/** Coefficients from: http://3dtv.at/Knowhow/AnaglyphComparison_en.aspx */
/** anaglyph[R|L]_constants are found in Scene.c b/c of ray tracing */
CShaderPrg_SetMat3f
(shaderPrg, "matL", G->ShaderMgr->stereo_flag < 0 ?
anaglyphL_constants[mode] :
anaglyphR_constants[mode]);
CShaderPrg_Set1f(shaderPrg, "gamma", SettingGetGlobal_f(G, cSetting_gamma));
}
void CShaderPrg_Set_Stereo_And_AnaglyphMode(PyMOLGlobals * G, CShaderPrg * shade if (width)
rPrg) { shaderPrg->Set2f("screenSize", width, height);
int stereo, stereo_mode;
stereo = SettingGetGlobal_i(G, cSetting_stereo); shaderPrg->SetBgUniforms();
stereo_mode = SettingGetGlobal_i(G, cSetting_stereo_mode);
if (stereo && stereo_mode==cStereo_anaglyph){ {
CShaderPrg_Set_AnaglyphMode(G, shaderPrg, SettingGetGlobal_i(G, cSetting_ana float v_scale = SceneGetScreenVertexScale(G, NULL);
glyph_mode)); shaderPrg->Set1f("screenOriginVertexScale", v_scale/2.f);
} else { }
CShaderPrg_SetMat3f(shaderPrg, "matL", (GLfloat*)mat3identity); {
CShaderPrg_Set1f(shaderPrg, "gamma", 1.0); float front, back;
front = SceneGetCurrentFrontSafe(G);
back = SceneGetCurrentBackSafe(G);
shaderPrg->Set1f("front", front);
shaderPrg->Set1f("clipRange", back - front);
} }
}
int CShaderPrg_SetLightingEnabled(CShaderPrg *shaderPrg, int lighting_enabled){ return shaderPrg;
return CShaderPrg_Set1i(shaderPrg, "lighting_enabled", lighting_enabled);
} }
static CShaderPrg *CShaderMgr::Get_LabelShader(int pass){
CShaderPrg *CShaderPrg_Enable_DefaultShaderImpl(PyMOLGlobals * G, CShaderPrg * s return GetShaderPrg("label", 1, pass);
haderPrg, }
const CSetting *set1,
const CSetting *set2);
CShaderPrg *CShaderPrg_Enable_DefaultScreenShader(PyMOLGlobals * G){ CShaderPrg *CShaderMgr::Get_ScreenShader() {
CShaderPrg * shaderPrg = CShaderPrg_Get_DefaultScreenShader(G); if (is_picking)
return CShaderPrg_Enable_DefaultShaderImpl(G, shaderPrg, NULL, NULL); return NULL;
return GetShaderPrg("screen");
} }
CShaderPrg *CShaderPrg_Enable_DefaultShaderWithSettings(PyMOLGlobals * G, CShaderPrg *CShaderMgr::Get_RampShader() {
const CSetting *set1, return GetShaderPrg("ramp");
const CSetting *set2){
CShaderPrg * shaderPrg = CShaderPrg_Get_DefaultShader(G);
return CShaderPrg_Enable_DefaultShaderImpl(G, shaderPrg, set1, set2);
} }
CShaderPrg *CShaderPrg_Enable_DefaultShader(PyMOLGlobals * G){ CShaderPrg *CShaderMgr::Get_IndicatorShader() {
CShaderPrg * shaderPrg = CShaderPrg_Get_DefaultShader(G); return GetShaderPrg("indicator");
return CShaderPrg_Enable_DefaultShaderImpl(G, shaderPrg, NULL, NULL);
} }
static CShaderPrg *CShaderMgr::Enable_IndicatorShader() {
CShaderPrg *CShaderPrg_Enable_DefaultShaderImpl(PyMOLGlobals * G, CShaderPrg * s CShaderPrg * shaderPrg = Get_IndicatorShader();
haderPrg, if (!shaderPrg) return shaderPrg;
const CSetting *set1, shaderPrg->Enable();
const CSetting *set2){
float fog_enabled, *fog_color_top, *fog_color_bottom;
int bg_gradient;
if (!shaderPrg){
G->ShaderMgr->current_shader = NULL;
return shaderPrg;
}
CShaderPrg_Enable(shaderPrg);
fog_enabled = get_fog_enabled(G) ? 1.0 : 0.0;
bg_gradient = SettingGetGlobal_b(G, cSetting_bg_gradient);
if (bg_gradient){
fog_color_top = ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_rgb_
top));
fog_color_bottom = ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_r
gb_bottom));
} else {
fog_color_top = ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_rgb)
);
fog_color_bottom = fog_color_top;
}
CShaderPrg_SetFogUniforms(G, shaderPrg); shaderPrg->Set_Stereo_And_AnaglyphMode();
shaderPrg->Set_Matrices();
glActiveTexture(GL_TEXTURE4); glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, OrthoGetBackgroundTextureID(G)); glBindTexture(GL_TEXTURE_2D, TextureGetTextTextureID(G));
if (!(shaderPrg->uniform_set & 8)){ if (!(shaderPrg->uniform_set & 8)){
CShaderPrg_Set1i(shaderPrg, "bgTextureMap", 4); shaderPrg->Set1i("textureMap", 3);
shaderPrg->uniform_set |= 8; shaderPrg->uniform_set |= 8;
} }
#ifdef PURE_OPENGL_ES_2
shaderPrg->SetMat4fc("g_ModelViewMatrix", SceneGetModelViewMatrix(G));
shaderPrg->SetMat4fc("g_ProjectionMatrix", SceneGetProjectionMatrix(G));
#endif
CShaderPrg_Set_Stereo_And_AnaglyphMode(G, shaderPrg); return (shaderPrg);
}
CShaderPrg_Set1i(shaderPrg, "bg_gradient", bg_gradient); void CShaderMgr::ResetUniformSet() {
CShaderPrg_Set3f(shaderPrg, "fog_color_top", fog_color_top[0], fog_color_top[1 for (map<string, CShaderPrg*>::iterator
], fog_color_top[2]); it = programs.begin(),
CShaderPrg_Set3f(shaderPrg, "fog_color_bottom", fog_color_bottom[0], fog_color end = programs.end(); it != end; ++it) {
_bottom[1], fog_color_bottom[2]); it->second->uniform_set = 0;
CShaderPrg_Set1f(shaderPrg, "fog_enabled", fog_enabled);
CShaderPrg_SetLightingEnabled(shaderPrg, 1); // lighting on by default
CShaderPrg_Set1i(shaderPrg, "two_sided_lighting_enabled", SceneGetTwoSidedLigh
tingSettings(G, set1, set2));
CShaderPrg_Set1i(shaderPrg, "light_count", SettingGetGlobal_i(G, cSetting_ligh
t_count));
CShaderPrg_Set1f(shaderPrg, "ambient_occlusion_scale", 0.f);
CShaderPrg_Set1i(shaderPrg, "accessibility_mode", SettingGetGlobal_i(G, cSetti
ng_ambient_occlusion_mode) / 4);
CShaderPrg_Set1f(shaderPrg, "accessibility_mode_on", SettingGetGlobal_i(G, cSe
tting_ambient_occlusion_mode) ? 1.f : 0.f);
{
int interior_color = SettingGet_i(G, set1, set2, cSetting_ray_interior_color
);
float *color, inter[] = { 0.f, 0.f, 0.f }, threshold = 0.f;
if (interior_color < 0){
threshold = .22f; // this is hardcoded for now, need to figure out exactl
y what Ray.c does
// to cull the backfacing polygons
}
CShaderPrg_Set1f(shaderPrg, "interior_color_threshold", threshold);
if (interior_color < 0){
color = inter;
} else {
ColorGetEncoded(G, interior_color, inter);
color = inter;
}
CShaderPrg_Set4f(shaderPrg, "interior_color", color[0], color[1], color[2],
1.f);
} }
CShaderPrg_Set1i(shaderPrg, "use_interior_color_threshold", 0); }
CShaderPrg_Set_Specular_Values(G, shaderPrg); void CShaderMgr::SetIsPicking(int is_picking) {
return (shaderPrg); this->is_picking = is_picking;
}
int CShaderMgr::GetIsPicking() {
return is_picking;
} }
CShaderPrg *CShaderPrg_Enable_CylinderShader(PyMOLGlobals * G){
int fog_enabled, bg_gradient;
float *fog_color_top, *fog_color_bottom;
int ortho;
int width, height;
CShaderPrg *shaderPrg;
float *m;
SceneGetWidthHeight(G, &width, &height); #define LIGHTINGTEXTUREWIDTH 64
m = SceneGetMatrix(G);
shaderPrg = CShaderPrg_Get_CylinderShader(G); /*
if (!shaderPrg) * Lighting setting indices are not contiguous, so we need a mapping array
return NULL; */
CShaderPrg_Enable(shaderPrg); int light_setting_indices[] = {
CShaderPrg_Set1f(shaderPrg, "uni_radius", 0.f); cSetting_light, cSetting_light2, cSetting_light3, cSetting_light4,
fog_enabled = get_fog_enabled(G) ? 1.0 : 0.0; cSetting_light5, cSetting_light6, cSetting_light7, cSetting_light8,
bg_gradient = SettingGetGlobal_b(G, cSetting_bg_gradient); cSetting_light9
if (bg_gradient){ };
fog_color_top = ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_rgb_
top)); /*
fog_color_bottom = ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_r * Generate and upload a precomputed vec2(ambient, specular) lighting texture.
gb_bottom)); *
} else { * Must be equivalent to "ComputeLighting" in "compute_color_for_light.fs"
fog_color_top = ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_rgb) */
); void CShaderMgr::Generate_LightingTexture() {
fog_color_bottom = fog_color_top; const int light_max = 10;
int light_count = SettingGetGlobal_i(G, cSetting_light_count);
int spec_count = SettingGetGlobal_i(G, cSetting_spec_count);
float ambient = SettingGetGlobal_f(G, cSetting_ambient);
float direct = SettingGetGlobal_f(G, cSetting_direct);
float reflect = SettingGetGlobal_f(G, cSetting_reflect) * SceneGetReflectScale
Value(G, light_max);
float shininess, spec_value;
float shininess_0, spec_value_0;
float diffuse, spec, shine;
float power, power_0 = SettingGetGlobal_f(G, cSetting_power);
float reflect_power = SettingGetGlobal_f(G, cSetting_reflect_power);
float light_positions[light_max][3] = {{0.F, 0.F, 1.F}};
// (ambient, specular) 2D texture
unsigned char texture_AS[LIGHTINGTEXTUREWIDTH][LIGHTINGTEXTUREWIDTH][2];
SceneGetAdjustedLightValues(G,
&spec_value,
&shininess,
&spec_value_0,
&shininess_0,
light_max);
if (light_count < 2) {
light_count = 1;
direct += reflect;
} else if (light_count > light_max) {
light_count = light_max;
} }
CShaderPrg_Set_Stereo_And_AnaglyphMode(G, shaderPrg); if(spec_count < 0) {
spec_count = light_count - 1;
}
CShaderPrg_Set1i(shaderPrg, "bg_gradient", bg_gradient); for (int i = 1; i < light_count; ++i) {
CShaderPrg_Set3f(shaderPrg, "fog_color_top", fog_color_top[0], fog_color_top[1 const float * setting = SettingGetGlobal_3fv(G, light_setting_indices[i - 1]
], fog_color_top[2]); );
CShaderPrg_Set3f(shaderPrg, "fog_color_bottom", fog_color_bottom[0], fog_color copy3f(setting, light_positions[i]);
_bottom[1], fog_color_bottom[2]); normalize3f(light_positions[i]);
CShaderPrg_Set1f(shaderPrg, "fog_enabled", fog_enabled); invert3f(light_positions[i]);
CShaderPrg_Set1f(shaderPrg, "inv_height", 1.0/height);
ortho = SettingGetGlobal_b(G, cSetting_ortho);
CShaderPrg_Set1f(shaderPrg, "ortho", ortho ? 1.0 : 0.0);
CShaderPrg_Set1f(shaderPrg, "no_flat_caps", 1.0);
CShaderPrg_Set1i(shaderPrg, "two_sided_lighting_enabled", SceneGetTwoSidedLigh
ting(G));
CShaderPrg_Set1i(shaderPrg, "light_count", SettingGetGlobal_i(G, cSetting_ligh
t_count));
{
float smooth_half_bonds = (SettingGetGlobal_i(G, cSetting_smooth_half_bonds)
) ? .2f : 0.f;
CShaderPrg_Set1f(shaderPrg, "half_bond", smooth_half_bonds);
} }
CShaderPrg_Set_Specular_Values(G, shaderPrg);
CShaderPrg_SetFogUniforms(G, shaderPrg); glGenTextures(1, &lightingTexture);
CShaderPrg_Set1f(shaderPrg, "fog_enabled", get_fog_enabled(G) ? 1.f : 0.f); glActiveTexture(GL_TEXTURE1);
glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_CUBE_MAP, lightingTexture);
glBindTexture(GL_TEXTURE_2D, OrthoGetBackgroundTextureID(G)); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (!(shaderPrg->uniform_set & 4)){ #ifndef PURE_OPENGL_ES_2
CShaderPrg_Set1i(shaderPrg, "bgTextureMap", 4); glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
shaderPrg->uniform_set |= 4; #else
} glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
{ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
float fog[4]; #endif
SceneSetFog(G, fog);
}
return shaderPrg; float normal[3];
} const float vz = LIGHTINGTEXTUREWIDTH / 2;
CShaderPrg *CShaderPrg_Enable_DefaultSphereShader(PyMOLGlobals * G){ for (int face = 0; face < 6; ++face) {
return CShaderPrg_Enable_SphereShader(G, "sphere"); for (int y = 0; y < LIGHTINGTEXTUREWIDTH; ++y) {
} for (int x = 0; x < LIGHTINGTEXTUREWIDTH; ++x) {
float vx = x + .5f - vz;
float vy = -(y + .5f - vz);
switch (face) {
case 0: set3f(normal, vz, vy, -vx); break;
case 1: set3f(normal, -vz, vy, vx); break;
case 2: set3f(normal, vx, vz, -vy); break;
case 3: set3f(normal, vx, -vz, vy); break;
case 4: set3f(normal, vx, vy, vz); break;
case 5: set3f(normal, -vx, vy, -vz); break;
}
CShaderPrg *CShaderPrg_Get_DefaultSphereShader(PyMOLGlobals * G){ normalize3f(normal);
return CShaderMgr_GetShaderPrg(G->ShaderMgr, "sphere");
}
CShaderPrg *CShaderPrg_Enable_SphereShader(PyMOLGlobals * G, char *name){ float ambient_sum = ambient;
int fog_enabled, bg_gradient; float specular_sum = 0.F;
int ortho;
CShaderPrg *shaderPrg;
int width, height;
SceneGetWidthHeight(G, &width, &height);
shaderPrg = CShaderMgr_GetShaderPrg(G->ShaderMgr, name);
if (!shaderPrg) return NULL;
CShaderPrg_Enable(shaderPrg);
CShaderPrg_SetLightingEnabled(shaderPrg, 1);
CShaderPrg_Set1f(shaderPrg, "sphere_size_scale", 1.f);
fog_enabled = get_fog_enabled(G) ? 1.0 : 0.0;
bg_gradient = SettingGetGlobal_b(G, cSetting_bg_gradient);
CShaderPrg_Set_Stereo_And_AnaglyphMode(G, shaderPrg);
CShaderPrg_Set1i(shaderPrg, "bg_gradient", bg_gradient);
CShaderPrg_Set1f(shaderPrg, "inv_height", 1.0/height);
ortho = SettingGetGlobal_b(G, cSetting_ortho);
CShaderPrg_Set1f(shaderPrg, "ortho", ortho ? 1.0 : 0.0);
CShaderPrg_Set1i(shaderPrg, "light_count", SettingGetGlobal_i(G, cSetting_ligh
t_count));
{ for (int i = 0; i < light_count; ++i) {
float adj; if (i == 0) {
float fov = SettingGetGlobal_f(G, cSetting_field_of_view); diffuse = direct;
/* Polynomial fitting for adjustment values relative to the field of view */ spec = spec_value_0;
if (fov <= 90.f){ shine = shininess_0;
adj = 1.0027+0.000111*fov+0.000098*fov*fov; power = power_0;
} else { } else {
adj = 2.02082 - 0.033935*fov + 0.00037854*fov*fov; diffuse = reflect;
} spec = spec_value;
CShaderPrg_Set1f(shaderPrg, "horizontal_adjustment", adj); shine = shininess;
CShaderPrg_Set1f(shaderPrg, "vertical_adjustment", adj); power = reflect_power;
} }
CShaderPrg_Set_Specular_Values(G, shaderPrg);
CShaderPrg_Set1f(shaderPrg, "fog_enabled", fog_enabled); // light direction (normalized)
const float * L = light_positions[i];
// cosine of angle between normal and light
float NdotL = dot_product3f(normal, L);
// normal points away from light
if (NdotL <= 0.0)
continue;
// power/reflect_power, was ray trace only until 1.7.7
NdotL = pow(NdotL, power);
// diffuse
ambient_sum += NdotL * diffuse;
// specular
if (i <= spec_count) {
// H = normalize(L + vec3(0., 0., 1.));
float H[] = {0., 0., 1.};
add3f(L, H, H);
normalize3f(H);
float NdotH = std::max(dot_product3f(normal, H), 0.f);
specular_sum += spec * pow(NdotH, shine);
}
}
CShaderPrg_SetFogUniforms(G, shaderPrg); texture_AS[y][x][0] = pymol_roundf(255.F * std::min(1.F, ambient_sum));
texture_AS[y][x][1] = pymol_roundf(255.F * std::min(1.F, specular_sum));
}
}
glActiveTexture(GL_TEXTURE4); glTexImage2D(
glBindTexture(GL_TEXTURE_2D, OrthoGetBackgroundTextureID(G)); GL_TEXTURE_CUBE_MAP_POSITIVE_X + face,
if (!(shaderPrg->uniform_set & 4)){ /* level */ 0,
CShaderPrg_Set1i(shaderPrg, "bgTextureMap", 4); /* internalformat */ GL_LUMINANCE_ALPHA,
shaderPrg->uniform_set |= 4; /* width */ LIGHTINGTEXTUREWIDTH,
} /* height */ LIGHTINGTEXTUREWIDTH,
{ /* border */ 0,
float fog[4]; /* format */ GL_LUMINANCE_ALPHA,
SceneSetFog(G, fog); /* type */ GL_UNSIGNED_BYTE,
/* data */ (void*) texture_AS);
} }
return (shaderPrg);
} }
#ifdef _PYMOL_ARB_SHADERS void CShaderMgr::Set_Reload_Bits(int bits){
CShaderPrg *CShaderPrg_Enable_SphereShaderARB(PyMOLGlobals * G){ reload_bits |= bits;
CShaderPrg *shaderPrg = NULL; }
/* load the vertex program */
CShaderPrg_Disable(G->ShaderMgr->current_shader);
shaderPrg = CShaderMgr_GetShaderPrg(G->ShaderMgr, "sphere_arb");
glBindProgramARB(GL_VERTEX_PROGRAM_ARB, shaderPrg->vid);
/* load the fragment program */ void CShaderMgr::Check_Reload() {
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shaderPrg->fid); if(!SettingGetGlobal_b(G, cSetting_use_shaders)) {
return;
}
/* load some safe initial values */ if (reload_bits){
glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB, 0, 0.0F, 0.0F, 1.0F, 0.0F); if (reload_bits == RELOAD_ALL_SHADERS) {
glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, 0.5F, 2.0F, 0.0F, 0.0F) for (auto it = programs.begin(); it != programs.end(); ++it)
; it->second->is_valid = false;
shader_cache_processed.clear();
}
glEnable(GL_VERTEX_PROGRAM_ARB); Reload_All_Shaders();
glEnable(GL_FRAGMENT_PROGRAM_ARB); reload_bits = 0;
}
}
return shaderPrg; GLfloat *CShaderMgr::GetLineWidthRange() {
return line_width_range;
} }
#ifndef _PYMOL_NO_AA_SHADERS
#endif #endif
CShaderPrg *CShaderPrg_Get_DefaultShader(PyMOLGlobals * G){ /*
return CShaderMgr_GetShaderPrg(G->ShaderMgr, "default"); * Register filename -> shader dependencies for `shader`
*/
void CShaderMgr::RegisterDependantFileNames(CShaderPrg * shader) {
shader_deps[shader->vertfile].push_back(shader->name);
shader_deps[shader->fragfile].push_back(shader->name);
if (!shader->geomfile.empty())
shader_deps[shader->geomfile].push_back(shader->name);
} }
CShaderPrg *CShaderPrg_Get_DefaultScreenShader(PyMOLGlobals * G){ /*
if (G->ShaderMgr->is_picking) * Recursive function to insert `filename` and all the files where
return NULL; * `filename` is included into the given output vector.
return CShaderMgr_GetShaderPrg(G->ShaderMgr, "defaultscreen"); */
void CShaderMgr::CollectDependantFileNames(const std::string &filename,
std::vector<std::string> &filenames) {
auto it = include_deps.find(filename);
if (it != include_deps.end()) {
for (const char ** filenameptr = it->second;
*filenameptr; ++filenameptr) {
CollectDependantFileNames(*filenameptr, filenames);
}
}
filenames.push_back(filename);
} }
CShaderPrg *CShaderPrg_Get_CylinderShaderImpl(PyMOLGlobals * G, short set_curren /*
t_shader){ * Make derived shaders for all shaders that depend on `variable`
CShaderPrg *shaderPrg; */
shaderPrg = CShaderMgr_GetShaderPrgImpl(G->ShaderMgr, "cylinder", set_current_ void CShaderMgr::MakeDerivatives(const std::string &suffix, const std::string &v
shader); ariable) {
return shaderPrg; std::set<std::string> shadernames;
} std::vector<std::string> filenames;
CShaderPrg *CShaderPrg_Get_CylinderShader(PyMOLGlobals * G){ // variable -> files
return CShaderPrg_Get_CylinderShaderImpl(G, 1); for (const char ** filenameptr = ifdef_deps[variable];
} *filenameptr; ++filenameptr) {
CollectDependantFileNames(*filenameptr, filenames);
}
CShaderPrg *CShaderPrg_Get_CylinderShader_NoSet(PyMOLGlobals * G){ // files -> shaders
return CShaderPrg_Get_CylinderShaderImpl(G, 0); for (auto f_it = filenames.begin(); f_it != filenames.end(); ++f_it) {
} auto &vec = shader_deps[*f_it];
for (auto n_it = vec.begin(); n_it != vec.end(); ++n_it) {
shadernames.insert(*n_it);
}
}
CShaderPrg *CShaderPrg_Get_Current_Shader(PyMOLGlobals * G){ // create shader derivatives
return G->ShaderMgr->current_shader; for (auto s_it = shadernames.begin(); s_it != shadernames.end(); ++s_it) {
} CShaderPrg * shader = programs[*s_it]->DerivativeCopy(*s_it + suffix, variab
le);
programs[shader->name] = shader;
CShaderPrg *CShaderPrg_Get_BackgroundShader(PyMOLGlobals * G){ // register dependency
{ RegisterDependantFileNames(shader);
return CShaderMgr_GetShaderPrg(G->ShaderMgr, "bg");
} }
} }
CShaderPrg *CShaderPrg_Enable_BackgroundShader(PyMOLGlobals * G){ /*
CShaderPrg * shaderPrg = CShaderPrg_Get_BackgroundShader(G); * Reload the derivative shaders for `variable`
if (!shaderPrg) return shaderPrg; */
CShaderPrg_Enable(shaderPrg); void CShaderMgr::Reload_Derivatives(const std::string &variable, bool value) {
SetPreprocVar(variable, value, false);
glBindTexture(GL_TEXTURE_2D, 0); for (auto it = programs.begin(); it != programs.end(); ++it) {
glActiveTexture(GL_TEXTURE4); if (it->second->derivative == variable)
glBindTexture(GL_TEXTURE_2D, OrthoGetBackgroundTextureID(G)); it->second->reload();
}
glDisable(GL_DEPTH_TEST); SetPreprocVar(variable, !value, false);
CShaderPrg_SetFogUniforms(G, shaderPrg); }
if (!(shaderPrg->uniform_set & 8)){ /*
CShaderPrg_Set1i(shaderPrg, "bgTextureMap", 4); * Removes `filename` and all it's parents from the shader source cache,
shaderPrg->uniform_set |= 8; * and if `invshaders` is true, also clear the `is_valid` flag for all
* shader infos that depend on `filename`.
*/
void CShaderMgr::ShaderSourceInvalidate(const char * filename, bool invshaders)
{
// recursion for includes
auto it = include_deps.find(filename);
if (it != include_deps.end()) {
for (const char ** filenameptr = it->second;
*filenameptr; ++filenameptr) {
ShaderSourceInvalidate(*filenameptr, invshaders);
}
} }
return shaderPrg;
}
CShaderPrg *CShaderPrg_Enable_LabelShaderImpl(PyMOLGlobals * G, CShaderPrg *shad // invalidate shaders
erPrg); if (invshaders) {
auto &vec = shader_deps[filename];
for (auto it = vec.begin(); it != vec.end(); ++it) {
programs[*it]->is_valid = false;
}
}
CShaderPrg *CShaderPrg_Enable_LabelScreenShader(PyMOLGlobals * G){ // invalidate source file
CShaderPrg *shaderPrg; auto repl_it = shader_cache_processed.find(filename);
shaderPrg = CShaderPrg_Get_LabelScreenShader(G); if (repl_it != shader_cache_processed.end()) {
if (!shaderPrg) shader_cache_processed.erase(repl_it);
return NULL; }
CShaderPrg_Enable(shaderPrg);
return CShaderPrg_Enable_LabelShaderImpl(G, shaderPrg);
} }
CShaderPrg *CShaderPrg_Enable_LabelShader(PyMOLGlobals * G){ /*
CShaderPrg *shaderPrg; * Set the value for the #ifdef variable `key` and if the value has changed,
shaderPrg = CShaderPrg_Get_LabelShader(G); * then invalidate all its dependant shader source files.
if (!shaderPrg) */
return NULL; void CShaderMgr::SetPreprocVar(const std::string &key, bool value, bool invshade
CShaderPrg_Enable(shaderPrg); rs) {
return CShaderPrg_Enable_LabelShaderImpl(G, shaderPrg); auto &ref = preproc_vars[key];
if (ref != value) {
for (const char ** filenameptr = ifdef_deps[key];
*filenameptr; ++filenameptr) {
ShaderSourceInvalidate(*filenameptr, invshaders);
}
ref = value;
}
} }
CShaderPrg *CShaderPrg_Enable_ScreenShader(PyMOLGlobals * G){ /*
CShaderPrg *shaderPrg; * Insert `filename` -> `contents` (processed source) into the shader source
shaderPrg = CShaderPrg_Get_ScreenShader(G); * cache and invalidate its parents
if (!shaderPrg) */
return NULL; void CShaderMgr::SetShaderSource(const char * filename, const std::string &conte
CShaderPrg_Enable(shaderPrg); nts) {
return CShaderPrg_Enable_LabelShaderImpl(G, shaderPrg); ShaderSourceInvalidate(filename);
shader_cache_processed[filename] = contents;
} }
CShaderPrg *CShaderPrg_Enable_RampShader(PyMOLGlobals * G){ void CShaderMgr::bindGPUBuffer(size_t hashid) {
CShaderPrg *shaderPrg; auto search = _gpu_object_map.find(hashid);
shaderPrg = CShaderPrg_Get_RampShader(G); if (search != _gpu_object_map.end())
if (!shaderPrg) search->second->bind();
return NULL;
CShaderPrg_Enable(shaderPrg);
return CShaderPrg_Enable_LabelShaderImpl(G, shaderPrg);
} }
CShaderPrg *CShaderPrg_Enable_LabelShaderImpl(PyMOLGlobals * G, CShaderPrg *shad void CShaderMgr::freeGPUBuffer(size_t hashid) {
erPrg){ if (!hashid)
glActiveTexture(GL_TEXTURE3); return;
glBindTexture(GL_TEXTURE_2D, TextureGetTextTextureID(G)); LOCK_GUARD_MUTEX(lock, gpu_objects_to_free_mutex);
CShaderPrg_Set1i(shaderPrg, "textureMap", 3); _gpu_objects_to_free_vector.push_back(hashid);
if (!(shaderPrg->uniform_set & 8)){
int width, height;
SCENEGETIMAGESIZE(G, &width, &height);
CShaderPrg_Set2f(shaderPrg, "screenSize", width, height);
CShaderPrg_Set2f(shaderPrg, "pixelSize", 2.f/(float)width, 2.f/(float)height
);
CShaderPrg_Set1f(shaderPrg, "aspectRatioAdjustment", 1.f);
shaderPrg->uniform_set |= 8;
}
if (SceneIsGridModeActive(G)){
int width, height;
SceneGetGridModeSize(G, &width, &height);
CShaderPrg_Set2f(shaderPrg, "screenSize", width, height);
CShaderPrg_Set1f(shaderPrg, "aspectRatioAdjustment", 1.f);
} else if (StereoIsAdjacent(G)){
CShaderPrg_Set1f(shaderPrg, "aspectRatioAdjustment", 2.f);
}
CShaderPrg_Set1f(shaderPrg, "isPicking", G->ShaderMgr->is_picking ? 1.f : 0.f
);
CShaderPrg_SetFogUniforms(G, shaderPrg);
CShaderPrg_Set1f(shaderPrg, "fog_enabled", get_fog_enabled(G) ? 1.f : 0.f);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, OrthoGetBackgroundTextureID(G));
if (!(shaderPrg->uniform_set & 4)){
CShaderPrg_Set1i(shaderPrg, "bgTextureMap", 4);
shaderPrg->uniform_set |= 4;
}
{
float fog[4];
SceneSetFog(G, fog);
}
{
float v_scale = SceneGetScreenVertexScale(G, NULL);
CShaderPrg_Set1f(shaderPrg, "screenOriginVertexScale", v_scale/2.f);
}
return shaderPrg;
}
CShaderPrg *CShaderPrg_Get_LabelShader(PyMOLGlobals * G){ #ifdef _WEBGL
return CShaderMgr_GetShaderPrg(G->ShaderMgr, "label"); freeAllGPUBuffers(); // immediate free on web
#endif
} }
CShaderPrg *CShaderPrg_Get_LabelScreenShader(PyMOLGlobals * G){ void CShaderMgr::freeGPUBuffers(std::vector<size_t> &&hashids) {
if (G->ShaderMgr->is_picking) LOCK_GUARD_MUTEX(lock, gpu_objects_to_free_mutex);
return NULL; _gpu_objects_to_free_vector.insert(_gpu_objects_to_free_vector.end(),
return CShaderMgr_GetShaderPrg(G->ShaderMgr, "labelscreen"); hashids.begin(), hashids.end());
#ifdef _WEBGL
freeAllGPUBuffers(); // immediate free on web
#endif
} }
CShaderPrg *CShaderPrg_Get_ScreenShader(PyMOLGlobals * G){ void CShaderMgr::freeGPUBuffers(size_t * arr, size_t len) {
if (G->ShaderMgr->is_picking) for (unsigned int i = 0; i < len; ++i)
return NULL; freeGPUBuffer(arr[i]);
return CShaderMgr_GetShaderPrg(G->ShaderMgr, "screen");
} }
CShaderPrg *CShaderPrg_Get_RampShader(PyMOLGlobals * G){ void CShaderMgr::freeAllGPUBuffers() {
return CShaderMgr_GetShaderPrg(G->ShaderMgr, "ramp"); LOCK_GUARD_MUTEX(lock, gpu_objects_to_free_mutex);
for (auto hashid : _gpu_objects_to_free_vector) {
auto search = _gpu_object_map.find(hashid);
if (search != _gpu_object_map.end()) {
if (search->second)
delete search->second;
_gpu_object_map.erase(search);
}
}
_gpu_objects_to_free_vector.clear();
} }
CShaderPrg *CShaderPrg_Get_IndicatorShader(PyMOLGlobals * G){ int CShaderMgr::GetAttributeUID(const char * name)
return CShaderMgr_GetShaderPrg(G->ShaderMgr, "indicator"); {
auto uloc = attribute_uids_by_name.find(name);
if (uloc != attribute_uids_by_name.end())
return uloc->second;
int uid = attribute_uids_by_name.size() + 1;
attribute_uids_by_name[name] = uid;
attribute_uids[uid] = name;
return uid;
}
const char *CShaderMgr::GetAttributeName(int uid)
{
auto uloc = attribute_uids.find(uid);
if (uloc == attribute_uids.end())
return NULL;
return attribute_uids[uid].c_str();
} }
CShaderPrg *CShaderPrg_Enable_IndicatorShader(PyMOLGlobals * G){ // SceneRenderBindToOffscreen
CShaderPrg * shaderPrg = CShaderPrg_Get_IndicatorShader(G); void CShaderMgr::bindOffscreen(int width, int height, GridInfo *grid) {
if (!shaderPrg) return shaderPrg; using namespace tex;
CShaderPrg_Enable(shaderPrg); ivec2 req_size(width, height);
CShaderPrg_Set_Stereo_And_AnaglyphMode(G, shaderPrg); #ifndef _PYMOL_NO_AA_SHADERS
#endif
glActiveTexture(GL_TEXTURE3); // Doesn't exist, create
glBindTexture(GL_TEXTURE_2D, TextureGetTextTextureID(G)); if (!offscreen_rt[0]) {
if (!(shaderPrg->uniform_set & 8)){ CGOFree(G->Scene->offscreenCGO);
CShaderPrg_Set1i(shaderPrg, "textureMap", 3); offscreen_size = req_size;
shaderPrg->uniform_set |= 8; auto rt0 = newGPUBuffer<renderTarget_t>(req_size);
rt0->layout({ { 4, rt_layout_t::UBYTE } });
offscreen_rt[0] = rt0->get_hash_id();
auto rt1 = newGPUBuffer<renderTarget_t>(req_size);
rt1->layout({ { 4, rt_layout_t::UBYTE } });
offscreen_rt[1] = rt1->get_hash_id();
auto rt2 = newGPUBuffer<renderTarget_t>(req_size);
rt2->layout({ { 4, rt_layout_t::UBYTE } });
offscreen_rt[2] = rt2->get_hash_id();
} else {
// resize
if (req_size != offscreen_size) {
for (int i = 0; i < 3; ++i)
getGPUBuffer<renderTarget_t>(offscreen_rt[i])->resize(req_size);
offscreen_size = req_size;
}
}
auto rt = getGPUBuffer<renderTarget_t>(offscreen_rt[0]);
if (rt)
rt->bind(!stereo_blend);
glEnable(GL_BLEND);
SceneInitializeViewport(G, 1);
if (grid->active) {
grid->cur_view[0] = grid->cur_view[1] = 0;
grid->cur_view[2] = offscreen_size.x;
grid->cur_view[3] = offscreen_size.y;
} }
return (shaderPrg);
} }
void ShaderMgrResetUniformSet(PyMOLGlobals * G){ // SceneRenderBindToOffscreenOIT
CShaderPrg * p = NULL; void CShaderMgr::bindOffscreenOIT(int width, int height, int drawbuf) {
DListIterate(G->ShaderMgr->programs, p, next) using namespace tex;
{
p->uniform_set = 0; ivec2 req_size(width, height);
if (!oit_rt[0] || (req_size != oit_size)) {
if (oit_rt[0]) {
freeGPUBuffers({ oit_rt[0], oit_rt[1] });
} }
} if (TM3_IS_ONEBUF){
auto rt0 = newGPUBuffer<renderTarget_t>(req_size);
rt0->layout({ { 4, rt_layout_t::FLOAT } }, getGPUBuffer<renderTarget_t>(of
fscreen_rt[0])->_rbo);
oit_rt[0] = rt0->get_hash_id();
void CShaderPrg_SetIsPicking(PyMOLGlobals * G, int is_picking){ auto rt1 = newGPUBuffer<renderTarget_t>(req_size);
G->ShaderMgr->is_picking = is_picking; rt1->layout({ { 1, rt_layout_t::FLOAT } }, rt0->_rbo);
} oit_rt[1] = rt1->get_hash_id();
int CShaderPrg_GetIsPicking(PyMOLGlobals * G){ } else {
return G->ShaderMgr->is_picking; std::vector<rt_layout_t> layout;
layout.emplace_back(4, rt_layout_t::FLOAT);
if (GLEW_VERSION_3_0)
layout.emplace_back(1, rt_layout_t::FLOAT);
else
layout.emplace_back(2, rt_layout_t::FLOAT);
auto rt0 = newGPUBuffer<renderTarget_t>(req_size);
rt0->layout(std::move(layout), getGPUBuffer<renderTarget_t>(offscreen_rt[0
])->_rbo);
oit_rt[0] = rt0->get_hash_id();
}
oit_size = req_size;
} else {
if (!TM3_IS_ONEBUF){
drawbuf = 1;
}
getGPUBuffer<renderTarget_t>(oit_rt[drawbuf - 1])->_fbo->bind();
getGPUBuffer<renderTarget_t>(oit_rt[drawbuf - 1])->_rbo->bind();
}
} }
void CShaderMgr_Set_Reload_Bits(PyMOLGlobals *G, int bits){ void CShaderMgr::bindOffscreenFBO(int index) {
CShaderMgr *I = G->ShaderMgr; bool clear = true;
if (I) if (index == 0)
I->reload_bits |= bits; clear = !stereo_blend;
auto t = getGPUBuffer<renderTarget_t>(offscreen_rt[index]);
if (t)
t->bind(clear);
} }
void CShaderMgr_Check_Reload(PyMOLGlobals *G){ void CShaderMgr::bindOffscreenOITFBO(int index) {
CShaderMgr *I = G->ShaderMgr; #if !defined(PURE_OPENGL_ES_2) || defined(_WEBGL)
if (TM3_IS_ONEBUF){
auto rt = getGPUBuffer<renderTarget_t>(oit_rt[index - 1]);
if (rt)
rt->_fbo->bind();
} else {
const GLenum bufs[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT }
;
auto rt = getGPUBuffer<renderTarget_t>(oit_rt[0]);
if (rt)
rt->_fbo->bind();
glDrawBuffers(2, bufs);
}
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
glDepthMask(GL_FALSE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFuncSeparate(
GL_ONE, GL_ONE,
GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
#endif
}
if(!SettingGetGlobal_b(G, cSetting_use_shaders)) { void CShaderMgr::bindOffscreenTexture(int index) {
return; auto t = getGPUBuffer<renderTarget_t>(offscreen_rt[index]);
} if (t->_textures[0])
t->_textures[0]->bind();
}
if (I->reload_bits){ void CShaderMgr::bindOffscreenOITTexture(int index) {
if (I->reload_bits & RELOAD_ALL_SHADERS){ if (TM3_IS_ONEBUF){
CShaderPrg_Reload_All_Shaders(G); auto t = getGPUBuffer<renderTarget_t>(oit_rt[index]);
} else { if (t->_textures[0])
if (I->reload_bits & RELOAD_SHADERS_FOR_LIGHTING){ t->_textures[0]->bind();
CShaderPrg_Reload_All_Shaders_For_CallComputeColorForLight(G); } else {
} auto t = getGPUBuffer<renderTarget_t>(oit_rt[0]);
if (I->reload_bits & RELOAD_SHADERS_UPDATE_FOR_BACKGROUND){ if (t)
CShaderPrg_Update_Shaders_For_Background(G); t->_textures[index]->bind();
}
if (I->reload_bits & RELOAD_SHADERS_CYLINDER){
CShaderMgr_Reload_Shader_Variables(G);
CShaderMgr_Reload_Cylinder_Shader(G);
}
}
I->reload_bits = 0;
} }
} }
 End of changes. 254 change blocks. 
1888 lines changed or deleted 1494 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)