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 |