Scene.cpp (pymol-v2.1.0.tar.bz2) | : | Scene.cpp (pymol-open-source-2.2.0) | ||
---|---|---|---|---|
skipping to change at line 33 | skipping to change at line 33 | |||
#include"Word.h" | #include"Word.h" | |||
#include"main.h" | #include"main.h" | |||
#include"Base.h" | #include"Base.h" | |||
#include"MemoryDebug.h" | #include"MemoryDebug.h" | |||
#include"Err.h" | #include"Err.h" | |||
#include"Matrix.h" | #include"Matrix.h" | |||
#include"ListMacros.h" | #include"ListMacros.h" | |||
#include"PyMOLObject.h" | #include"PyMOLObject.h" | |||
#include"Scene.h" | #include"Scene.h" | |||
#include"SceneRay.h" | ||||
#include"ScenePicking.h" | ||||
#include"Ortho.h" | #include"Ortho.h" | |||
#include"Vector.h" | #include"Vector.h" | |||
#include"ButMode.h" | #include"ButMode.h" | |||
#include"Control.h" | #include"Control.h" | |||
#include"Selector.h" | #include"Selector.h" | |||
#include"Setting.h" | #include"Setting.h" | |||
#include"Movie.h" | #include"Movie.h" | |||
#include"MyPNG.h" | #include"MyPNG.h" | |||
#include"P.h" | #include"P.h" | |||
#include"Editor.h" | #include"Editor.h" | |||
skipping to change at line 57 | skipping to change at line 59 | |||
#include"Seq.h" | #include"Seq.h" | |||
#include"Menu.h" | #include"Menu.h" | |||
#include"View.h" | #include"View.h" | |||
#include"ObjectSlice.h" | #include"ObjectSlice.h" | |||
#include"Text.h" | #include"Text.h" | |||
#include"PyMOLOptions.h" | #include"PyMOLOptions.h" | |||
#include"PyMOL.h" | #include"PyMOL.h" | |||
#include"PConv.h" | #include"PConv.h" | |||
#include"ScrollBar.h" | #include"ScrollBar.h" | |||
#include "ShaderMgr.h" | #include "ShaderMgr.h" | |||
#include "PopUp.h" | ||||
#include "MacPyMOL.h" | ||||
#include <string> | #include <string> | |||
#include <vector> | #include <vector> | |||
#include <algorithm> | ||||
#ifdef _PYMOL_IP_EXTRAS | #ifdef _PYMOL_IP_EXTRAS | |||
#include "IncentiveCopyToClipboard.h" | #include "IncentiveCopyToClipboard.h" | |||
#endif | #endif | |||
#include <algorithm> | #include <algorithm> | |||
#include <iostream> | #include <iostream> | |||
using namespace std; | using namespace std; | |||
static void glReadBufferError(PyMOLGlobals *G, GLenum b, GLenum e){ | static void glReadBufferError(PyMOLGlobals *G, GLenum b, GLenum e){ | |||
PRINTFB(G, FB_OpenGL, FB_Warnings) | PRINTFB(G, FB_OpenGL, FB_Warnings) | |||
" WARNING: glReadBuffer caused GL error 0x%04x\n", e ENDFB(G); | " WARNING: glReadBuffer caused GL error 0x%04x\n", e ENDFB(G); | |||
} | } | |||
// TH 2013-11-01: glReadBuffer fails in JyMOL when picking, OSX 10.9, Intel Grap hics | // TH 2013-11-01: glReadBuffer fails in JyMOL when picking, OSX 10.9, Intel Grap hics | |||
// for minor cases (i.e., png is called) this might get called outside of the ma in | // for minor cases (i.e., png is called) this might get called outside of the ma in | |||
// thread (from ExecutiveDrawNow()) in this case, just don't call glReadBuffer f or | // thread (from ExecutiveDrawNow()) in this case, just don't call glReadBuffer f or | |||
// now, it should be ok because i believe it is used to figure out the size of t he | // now, it should be ok because i believe it is used to figure out the size of t he | |||
// 3D window (using SceneImagePrepareImpl) in situations where the size gets cha nged. | // 3D window (using SceneImagePrepareImpl) in situations where the size gets cha nged. | |||
#define glReadBuffer(b) { int e; if (PIsGlutThread()) glReadBuffer(b); \ | #define glReadBuffer(b) { int e; if (PIsGlutThread()) glReadBuffer(b); \ | |||
if((e = glGetError())) glReadBufferError(G, b, e); } | if((e = glGetError())) glReadBufferError(G, b, e); } | |||
#ifdef _PYMOL_SHARP3D | #ifdef _PYMOL_SHARP3D | |||
#define cSliceMin 0.1F | #define cSliceMin 0.1F | |||
#else | #else | |||
#define cSliceMin 1.0F | #define cSliceMin 1.0F | |||
#endif | #endif | |||
#define SceneLineHeight 127 | #define SceneLineHeight 127 | |||
#define SceneTopMargin 0 | #define SceneTopMargin 0 | |||
#define SceneBottomMargin 3 | #define SceneBottomMargin 3 | |||
#define SceneLeftMargin 3 | #define SceneLeftMargin 3 | |||
/* Shared with ShaderMgr */ | /* Shared with ShaderMgr */ | |||
/** Coefficients from: http://3dtv.at/Knowhow/AnaglyphComparison_en.aspx */ | /** Coefficients from: http://3dtv.at/Knowhow/AnaglyphComparison_en.aspx */ | |||
/** Optimize the look and feel of anaglyph 3D */ | /** Optimize the look and feel of anaglyph 3D */ | |||
/* the last mode is the 3x3 identity */ | /* the last mode is the 3x3 identity */ | |||
float anaglyphL_constants[6][9] = { { 0.299, 0.587, 0.114, 0.000, 0.000, 0.000, | // matrices are column major | |||
0.000, 0.000, 0.000 }, | float anaglyphL_constants[6][9] = { { 0.299, 0.000, 0.000, 0.587, 0.000, 0.000, | |||
{ 0.299, 0.587, 0.114, 0.000, 0.000, 0.000, 0 | 0.114, 0.000, 0.000 }, | |||
.000, 0.000, 0.000 }, | { 0.299, 0.000, 0.000, 0.587, 0.000, 0.000, 0 | |||
.114, 0.000, 0.000 }, | ||||
{ 1.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0 .000, 0.000, 0.000 }, | { 1.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0 .000, 0.000, 0.000 }, | |||
{ 0.299, 0.587, 0.114, 0.000, 0.000, 0.000, 0 | { 0.299, 0.000, 0.000, 0.587, 0.000, 0.000, 0 | |||
.000, 0.000, 0.000 }, | .114, 0.000, 0.000 }, | |||
{ 0.000, 0.700, 0.300, 0.000, 0.000, 0.000, 0 | { 0.000, 0.000, 0.000, 0.700, 0.000, 0.000, 0 | |||
.000, 0.000, 0.000 }, | .300, 0.000, 0.000 }, | |||
{ 1.000, 0.000, 0.000, 0.000, 1.000, 0.000, 0 .000, 0.000, 1.000 } }; | { 1.000, 0.000, 0.000, 0.000, 1.000, 0.000, 0 .000, 0.000, 1.000 } }; | |||
float anaglyphR_constants[6][9] = { { 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, | float anaglyphR_constants[6][9] = { { 0.000, 0.000, 0.299, 0.000, 0.000, 0.587, | |||
0.299, 0.587, 0.114 }, | 0.000, 0.000, 0.114 }, | |||
{ 0.000, 0.000, 0.000, 0.299, 0.587, 0.114, 0 | { 0.000, 0.299, 0.299, 0.000, 0.587, 0.587, 0 | |||
.299, 0.587, 0.114 }, | .000, 0.114, 0.114 }, | |||
{ 0.000, 0.000, 0.000, 0.000, 1.000, 0.000, 0 .000, 0.000, 1.000 }, | { 0.000, 0.000, 0.000, 0.000, 1.000, 0.000, 0 .000, 0.000, 1.000 }, | |||
{ 0.000, 0.000, 0.000, 0.000, 1.000, 0.000, 0 .000, 0.000, 1.000 }, | { 0.000, 0.000, 0.000, 0.000, 1.000, 0.000, 0 .000, 0.000, 1.000 }, | |||
{ 0.000, 0.000, 0.000, 0.000, 1.000, 0.000, 0 .000, 0.000, 1.000 }, | { 0.000, 0.000, 0.000, 0.000, 1.000, 0.000, 0 .000, 0.000, 1.000 }, | |||
{ 1.000, 0.000, 0.000, 0.000, 1.000, 0.000, 0 .000, 0.000, 1.000 } }; | { 1.000, 0.000, 0.000, 0.000, 1.000, 0.000, 0 .000, 0.000, 1.000 } }; | |||
#define F2UI(a) (unsigned int) ((a) * 255.0) | #define F2UI(a) (unsigned int) ((a) * 255.0) | |||
typedef struct ObjRec { | ||||
CObject *obj; | ||||
struct ObjRec *next; | ||||
int slot; | ||||
} ObjRec; | ||||
typedef struct { | ||||
CDeferred deferred; | ||||
Block *block; | ||||
int button; | ||||
int x; | ||||
int y; | ||||
int mod; | ||||
double when; | ||||
int mode_override; | ||||
} DeferredMouse; | ||||
typedef struct { | ||||
CDeferred deferred; | ||||
PyMOLGlobals *G; | ||||
int width; | ||||
int height; | ||||
char *filename; /* NOTE: on heap! must free when done */ | ||||
int quiet; | ||||
int antialias; | ||||
float dpi; | ||||
int entire_window; | ||||
int format; | ||||
} DeferredImage; | ||||
typedef struct { | ||||
CDeferred deferred; | ||||
PyMOLGlobals *G; | ||||
int ray_width; | ||||
int ray_height; | ||||
int mode; | ||||
float angle; | ||||
float shift; | ||||
int quiet; | ||||
int show_timing; | ||||
int antialias; | ||||
} DeferredRay; | ||||
typedef struct { | ||||
int len; | ||||
const char *name; | ||||
int x1, y1, x2, y2, drawn; | ||||
} SceneElem; | ||||
/* allow up to 10 seconds at 30 FPS */ | /* allow up to 10 seconds at 30 FPS */ | |||
#define TRN_BKG 0x30 | ||||
#define MAX_ANI_ELEM 300 | ||||
class CScene { | ||||
public: | ||||
::Block *Block; | ||||
ObjRec *Obj; | ||||
float RotMatrix[16]; /* WARNING: column major, as per OpenGL spec */ | ||||
float InvMatrix[16]; /* WARNING: column major, as per OpenGL spec */ | ||||
float ModMatrix[16]; /* WARNING: column major, as per OpenGL spec */ | ||||
float ProMatrix[16]; /* WARNING: column major, as per OpenGL spec */ | ||||
float PmvMatrix[16]; | ||||
float Scale; | ||||
int Width, Height; | ||||
int Button; | ||||
int LastX, LastY; | ||||
int StartX, StartY; | ||||
int LastWinX, LastWinY; | ||||
double LastClickTime; | ||||
int LastButton, LastMod; | ||||
int PossibleSingleClick; | ||||
double LastReleaseTime; | ||||
double SingleClickDelay; | ||||
float ViewNormal[3], LinesNormal[3]; | ||||
float Pos[3], Origin[3]; | ||||
float H; | ||||
float Front, Back, FrontSafe, BackSafe; | ||||
float TextColor[3]; | ||||
double SweepTime; | ||||
int DirtyFlag; | ||||
int ChangedFlag; | ||||
int CopyType, CopyNextFlag, CopyForced; | ||||
int NFrame, HasMovie; | ||||
ImageType *Image; | ||||
int MovieOwnsImageFlag; | ||||
int MovieFrameFlag; | ||||
double LastRender, RenderTime, LastFrameTime, LastFrameAdjust; | ||||
double LastSweep, LastSweepTime; | ||||
float LastSweepX, LastSweepY; | ||||
int RockFrame; | ||||
Picking LastPicked; | ||||
int StereoMode; | ||||
OrthoLineType vendor, renderer, version; | ||||
int SculptingFlag, SculptingSave; | ||||
int RovingDirtyFlag; | ||||
int RovingCleanupFlag; | ||||
double RovingLastUpdate; | ||||
int Threshold, ThresholdX, ThresholdY; | ||||
CView *View; | ||||
float LastPickVertex[3], LastClickVertex[3]; | ||||
int LastPickVertexFlag; | ||||
int LoopFlag; | ||||
int LoopMod; | ||||
BlockRect LoopRect; | ||||
CViewElem ani_elem[MAX_ANI_ELEM + 1]; | ||||
int cur_ani_elem, n_ani_elem; | ||||
int LastStateBuilt; | ||||
int AnimationStartFlag; | ||||
double AnimationStartTime; | ||||
double AnimationLagTime; | ||||
int AnimationStartFrame; | ||||
double ApproxRenderTime; | ||||
float VertexScale; | ||||
float FogStart; | ||||
float FogEnd; | ||||
/* Scene Names */ | ||||
int ButtonsShown, ButtonDrag, ButtonMargin, ButtonsValid; | ||||
int Over, Pressed, PressMode, HowFarDown, NSkip; | ||||
int ScrollBarActive; | ||||
int ReorderFlag; | ||||
OrthoLineType ReorderLog; | ||||
struct CScrollBar *ScrollBar; | ||||
char *SceneNameVLA; | ||||
SceneElem *SceneVLA; | ||||
int NScene; | ||||
CGO *AlphaCGO; | ||||
int *SlotVLA; | ||||
int StencilValid, StencilParity; | ||||
int ReinterpolateFlag; | ||||
CObject *ReinterpolateObj; | ||||
CObject *MotionGrabbedObj; | ||||
GLuint offscreen_fb, offscreen_depth_rb, offscreen_color_rb; | ||||
int offscreen_width, offscreen_height; | ||||
short offscreen_error; | ||||
short prev_no_z_rotation1, prev_no_z_rotation2; | ||||
int orig_x_rotation, orig_y_rotation; | ||||
GridInfo grid; | ||||
int last_grid_size; | ||||
// This structure used to be calloc-ed, this replicates that | ||||
void *operator new(size_t size) { | ||||
void *mem = ::operator new(size); | ||||
memset(mem, 0, size); | ||||
return mem; | ||||
} | ||||
}; | ||||
/* EXPERIMENTAL VOLUME RAYTRACING DATA */ | /* EXPERIMENTAL VOLUME RAYTRACING DATA */ | |||
extern float *rayDepthPixels; | extern float *rayDepthPixels; | |||
extern int rayVolume; | extern int rayVolume, rayWidth, rayHeight; | |||
static void ScenePrepareUnitContext(SceneUnitContext * context, int width, int h | ||||
eight); | ||||
static void SceneDoRoving(PyMOLGlobals * G, float old_front, | static void SceneDoRoving(PyMOLGlobals * G, float old_front, | |||
float old_back, float old_origin, | float old_back, float old_origin, | |||
int adjust_flag, int zoom_flag); | int adjust_flag, int zoom_flag); | |||
#define SceneGetExactScreenVertexScale SceneGetScreenVertexScale | #define SceneGetExactScreenVertexScale SceneGetScreenVertexScale | |||
static void SceneRestartPerfTimer(PyMOLGlobals * G); | static void SceneRestartPerfTimer(PyMOLGlobals * G); | |||
static void SceneRotateWithDirty(PyMOLGlobals * G, float angle, float x, float y , float z, | static void SceneRotateWithDirty(PyMOLGlobals * G, float angle, float x, float y , float z, | |||
int dirty); | int dirty); | |||
skipping to change at line 291 | skipping to change at line 145 | |||
int SceneViewEqual(SceneViewType left, SceneViewType right) | int SceneViewEqual(SceneViewType left, SceneViewType right) | |||
{ | { | |||
int i; | int i; | |||
for(i = 0; i < cSceneViewSize; i++) { | for(i = 0; i < cSceneViewSize; i++) { | |||
if(fabs(left[i] - right[i]) > R_SMALL4) | if(fabs(left[i] - right[i]) > R_SMALL4) | |||
return false; | return false; | |||
} | } | |||
return true; | return true; | |||
} | } | |||
static void GridSetRayViewport(GridInfo * I, int slot, int *x, int *y, int *widt | void GridSetRayViewport(GridInfo * I, int slot, int *x, int *y, int *width, | |||
h, | int *height) | |||
int *height) | ||||
{ | { | |||
if(slot) | if(slot) | |||
I->slot = slot + I->first_slot - 1; | I->slot = slot + I->first_slot - 1; | |||
else | else | |||
I->slot = slot; | I->slot = slot; | |||
/* if we are in grid mode, then prepare the grid slot viewport */ | /* if we are in grid mode, then prepare the grid slot viewport */ | |||
if(slot < 0) { | if(slot < 0) { | |||
*x = I->cur_view[0]; | *x = I->cur_view[0]; | |||
*y = I->cur_view[1]; | *y = I->cur_view[1]; | |||
*width = I->cur_view[2]; | *width = I->cur_view[2]; | |||
skipping to change at line 339 | skipping to change at line 193 | |||
int vh = (I->cur_view[3] - ((grid_row) * I->cur_view[3]) / I->n_row) - vy; | int vh = (I->cur_view[3] - ((grid_row) * I->cur_view[3]) / I->n_row) - vy; | |||
vx += I->cur_view[0]; | vx += I->cur_view[0]; | |||
vy += I->cur_view[1]; | vy += I->cur_view[1]; | |||
*x = vx; | *x = vx; | |||
*y = vy; | *y = vy; | |||
*width = vw; | *width = vw; | |||
*height = vh; | *height = vh; | |||
} | } | |||
} | } | |||
static void GridSetGLViewport(GridInfo * I, int slot) | void GridGetRayViewport(GridInfo * I, int width, int height) | |||
{ | ||||
if(slot) | ||||
I->slot = slot + I->first_slot - 1; | ||||
else | ||||
I->slot = slot; | ||||
/* if we are in grid mode, then prepare the grid slot viewport */ | ||||
if(slot < 0) { | ||||
glViewport(I->cur_view[0], I->cur_view[1], I->cur_view[2], I->cur_view[3]); | ||||
} else if(!slot) { /* slot 0 is the full screen */ | ||||
int vx = 0; | ||||
int vw = I->cur_view[2] / I->n_col; | ||||
int vy = 0; | ||||
int vh = I->cur_view[3] / I->n_row; | ||||
if(I->n_col < I->n_row) { | ||||
vw *= I->n_col; | ||||
vh *= I->n_col; | ||||
} else { | ||||
vw *= I->n_row; | ||||
vh *= I->n_row; | ||||
} | ||||
vx += I->cur_view[0] + (I->cur_view[2] - vw) / 2; | ||||
vy += I->cur_view[1]; | ||||
glViewport(vx, vy, vw, vh); | ||||
ScenePrepareUnitContext(&I->context, vw, vh); | ||||
} else { | ||||
int abs_grid_slot = slot - I->first_slot; | ||||
int grid_col = abs_grid_slot % I->n_col; | ||||
int grid_row = (abs_grid_slot / I->n_col); | ||||
int vx = (grid_col * I->cur_view[2]) / I->n_col; | ||||
int vw = ((grid_col + 1) * I->cur_view[2]) / I->n_col - vx; | ||||
int vy = I->cur_view[3] - ((grid_row + 1) * I->cur_view[3]) / I->n_row; | ||||
int vh = (I->cur_view[3] - ((grid_row) * I->cur_view[3]) / I->n_row) - vy; | ||||
vx += I->cur_view[0]; | ||||
vy += I->cur_view[1]; | ||||
I->cur_viewport_size[0] = vw; | ||||
I->cur_viewport_size[1] = vh; | ||||
glViewport(vx, vy, vw, vh); | ||||
ScenePrepareUnitContext(&I->context, vw, vh); | ||||
} | ||||
} | ||||
static void GridGetRayViewport(GridInfo * I, int width, int height) | ||||
{ | { | |||
I->cur_view[0] = 0; | I->cur_view[0] = 0; | |||
I->cur_view[1] = 0; | I->cur_view[1] = 0; | |||
I->cur_view[2] = width; | I->cur_view[2] = width; | |||
I->cur_view[3] = height; | I->cur_view[3] = height; | |||
} | } | |||
static void GridGetGLViewport(PyMOLGlobals * G, GridInfo * I) | void GridUpdate(GridInfo * I, float asp_ratio, int mode, int size) | |||
{ | ||||
glGetIntegerv(GL_VIEWPORT, I->cur_view); | ||||
} | ||||
static void GridUpdate(GridInfo * I, float asp_ratio, int mode, int size) | ||||
{ | { | |||
if(mode) { | if(mode) { | |||
I->size = size; | I->size = size; | |||
I->mode = mode; | I->mode = mode; | |||
{ | { | |||
int n_row = 1; | int n_row = 1; | |||
int n_col = 1; | int n_col = 1; | |||
int r_size = size; | int r_size = size; | |||
while((n_row * n_col) < r_size) { | while((n_row * n_col) < r_size) { | |||
float asp1 = asp_ratio * (n_row + 1.0) / n_col; | float asp1 = asp_ratio * (n_row + 1.0) / n_col; | |||
skipping to change at line 437 | skipping to change at line 244 | |||
I->active = false; | I->active = false; | |||
} | } | |||
} | } | |||
void SceneInvalidateStencil(PyMOLGlobals * G) | void SceneInvalidateStencil(PyMOLGlobals * G) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
I->StencilValid = false; | I->StencilValid = false; | |||
} | } | |||
static int SceneGetGridSize(PyMOLGlobals * G, int grid_mode) | int SceneGetGridSize(PyMOLGlobals * G, int grid_mode) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
int slot; | int slot; | |||
int size = 0; | int size = 0; | |||
switch (grid_mode) { | switch (grid_mode) { | |||
case 1: | case 1: | |||
if(!I->SlotVLA) | if(!I->SlotVLA) | |||
I->SlotVLA = VLACalloc(int, 1); | I->SlotVLA = VLACalloc(int, 1); | |||
else { | else { | |||
UtilZeroMem(I->SlotVLA, sizeof(int) * VLAGetSize(I->SlotVLA)); | UtilZeroMem(I->SlotVLA, sizeof(int) * VLAGetSize(I->SlotVLA)); | |||
} | } | |||
{ | { | |||
int max_slot = 0; | int max_slot = 0; | |||
ObjRec *rec = NULL; | for ( auto it = I->Obj.begin(); it != I->Obj.end(); ++it) { | |||
while(ListIterate(I->Obj, rec, next)) { | if((slot = (*it)->grid_slot)) { | |||
if((slot = rec->obj->grid_slot)) { | ||||
slot = rec->obj->grid_slot; | ||||
if(max_slot < slot) | if(max_slot < slot) | |||
max_slot = slot; | max_slot = slot; | |||
if(slot > 0) { | if(slot > 0) { | |||
VLACheck(I->SlotVLA, int, slot); | VLACheck(I->SlotVLA, int, slot); | |||
I->SlotVLA[slot] = 1; | I->SlotVLA[slot] = 1; | |||
} | } | |||
} | } | |||
} | } | |||
for(slot = 0; slot <= max_slot; slot++) { | for(slot = 0; slot <= max_slot; slot++) { | |||
if(I->SlotVLA[slot]) | if(I->SlotVLA[slot]) | |||
skipping to change at line 478 | skipping to change at line 283 | |||
} | } | |||
break; | break; | |||
case 2: | case 2: | |||
case 3: | case 3: | |||
if(I->SlotVLA) { | if(I->SlotVLA) { | |||
VLAFreeP(I->SlotVLA); | VLAFreeP(I->SlotVLA); | |||
I->SlotVLA = NULL; | I->SlotVLA = NULL; | |||
} | } | |||
{ | { | |||
int max_slot = 0; | int max_slot = 0; | |||
ObjRec *rec = NULL; | for ( auto it = I->Obj.begin(); it != I->Obj.end(); ++it) { | |||
while(ListIterate(I->Obj, rec, next)) { | if((*it)->fGetNFrame) { | |||
if(rec->obj->fGetNFrame) { | slot = (*it)->fGetNFrame(*it); | |||
slot = rec->obj->fGetNFrame(rec->obj); | ||||
if(grid_mode == 3) { | if(grid_mode == 3) { | |||
rec->obj->grid_slot = max_slot; // slot offset for 1st state | (*it)->grid_slot = max_slot; // slot offset for 1st state | |||
max_slot += slot; | max_slot += slot; | |||
} else if(max_slot < slot) { | } else if(max_slot < slot) { | |||
max_slot = slot; | max_slot = slot; | |||
} | } | |||
} | } | |||
} | } | |||
size = max_slot; | size = max_slot; | |||
} | } | |||
break; | break; | |||
} | } | |||
skipping to change at line 531 | skipping to change at line 335 | |||
{ | { | |||
switch (stereo_mode) { | switch (stereo_mode) { | |||
case cStereo_crosseye: | case cStereo_crosseye: | |||
case cStereo_walleye: | case cStereo_walleye: | |||
case cStereo_sidebyside: | case cStereo_sidebyside: | |||
return true; | return true; | |||
} | } | |||
return false; | return false; | |||
} | } | |||
static int stereo_via_stencil(int stereo_mode) | ||||
{ | ||||
switch (stereo_mode) { | ||||
case cStereo_stencil_by_row: | ||||
case cStereo_stencil_by_column: | ||||
case cStereo_stencil_checkerboard: | ||||
case cStereo_stencil_custom: | ||||
return true; | ||||
} | ||||
return false; | ||||
} | ||||
int StereoIsAdjacent(PyMOLGlobals * G){ | int StereoIsAdjacent(PyMOLGlobals * G){ | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
return stereo_via_adjacent_array(I->StereoMode); | return stereo_via_adjacent_array(I->StereoMode); | |||
} | } | |||
static int get_stereo_x(int x, int *last_x, int width, int *click_side) | static int get_stereo_x(int x, int *last_x, int width, int *click_side) | |||
{ | { | |||
int width_2 = width / 2; | int width_2 = width / 2; | |||
int width_3 = width / 3; | int width_3 = width / 3; | |||
if(!last_x) { | if(!last_x) { | |||
skipping to change at line 619 | skipping to change at line 411 | |||
else /* 0 fps means use movie_delay instead */ | else /* 0 fps means use movie_delay instead */ | |||
minTime = SettingGetGlobal_f(G, cSetting_movie_delay) / 1000.0; | minTime = SettingGetGlobal_f(G, cSetting_movie_delay) / 1000.0; | |||
if(minTime >= 0.0F) | if(minTime >= 0.0F) | |||
fps = 1.0F / minTime; | fps = 1.0F / minTime; | |||
else | else | |||
fps = 1000.0F; | fps = 1000.0F; | |||
} | } | |||
return fps; | return fps; | |||
} | } | |||
void ScenePurgeImageImpl(PyMOLGlobals * G, int noinvalid); | ||||
static void ScenePurgeImage(PyMOLGlobals * G) | static void ScenePurgeImage(PyMOLGlobals * G) | |||
{ | { | |||
ScenePurgeImageImpl(G, 0); | ||||
} | ||||
void ScenePurgeImageImpl(PyMOLGlobals * G, int noinvalid) | ||||
{ | ||||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
if(I->MovieOwnsImageFlag) { | if(I->MovieOwnsImageFlag) { | |||
I->MovieOwnsImageFlag = false; | I->MovieOwnsImageFlag = false; | |||
I->Image = NULL; | I->Image = NULL; | |||
} else { | } else { | |||
if(I->Image) { | if(I->Image) { | |||
FreeP(I->Image->data); | FreeP(I->Image->data); | |||
} | } | |||
FreeP(I->Image); | FreeP(I->Image); | |||
} | } | |||
I->CopyType = false; | I->CopyType = false; | |||
OrthoInvalidateDoDraw(G); // right now, need to invalidate since text could be | if (!noinvalid) | |||
shown | OrthoInvalidateDoDraw(G); // right now, need to invalidate since text could | |||
be shown | ||||
} | } | |||
void SceneInvalidateCopy(PyMOLGlobals * G, int free_buffer) | void SceneInvalidateCopy(PyMOLGlobals * G, int free_buffer) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
if(I) { | if(I) { | |||
if(I->MovieOwnsImageFlag) { | if(I->MovieOwnsImageFlag) { | |||
I->MovieOwnsImageFlag = false; | I->MovieOwnsImageFlag = false; | |||
I->Image = NULL; | I->Image = NULL; | |||
} else if(free_buffer) { | } else if(free_buffer) { | |||
skipping to change at line 979 | skipping to change at line 779 | |||
void SceneCleanupStereo(PyMOLGlobals * G) | void SceneCleanupStereo(PyMOLGlobals * G) | |||
{ | { | |||
#ifndef _PYMOL_NOPY | #ifndef _PYMOL_NOPY | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
if(I->StereoMode == 1) | if(I->StereoMode == 1) | |||
PSGIStereo(G, 0); | PSGIStereo(G, 0); | |||
#endif | #endif | |||
} | } | |||
static void ScenePrepareUnitContext(SceneUnitContext * context, int width, int h eight) | void ScenePrepareUnitContext(SceneUnitContext * context, int width, int height) | |||
{ | { | |||
float tw = 1.0F; | float tw = 1.0F; | |||
float th = 1.0F; | float th = 1.0F; | |||
float aspRat; | float aspRat; | |||
if(height) { | if(height) { | |||
aspRat = width / (float) height; | aspRat = width / (float) height; | |||
} else { | } else { | |||
aspRat = 1.0F; | aspRat = 1.0F; | |||
} | } | |||
skipping to change at line 1032 | skipping to change at line 832 | |||
*height = I->Height; | *height = I->Height; | |||
} | } | |||
/* | /* | |||
* Get the actual current (sub-)viewport size, considering grid mode and | * Get the actual current (sub-)viewport size, considering grid mode and | |||
* side-by-side stereo | * side-by-side stereo | |||
*/ | */ | |||
void SceneGetWidthHeightStereo(PyMOLGlobals * G, int *width, int *height) | void SceneGetWidthHeightStereo(PyMOLGlobals * G, int *width, int *height) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
if (I->grid.active) { | ||||
// TODO: this considers "draw W, H" (PYMOL-2775) | ||||
*width = I->grid.cur_viewport_size[0]; | ||||
*height = I->grid.cur_viewport_size[1]; | ||||
return; | ||||
} | ||||
// TODO: this does NOT consider "draw W, H" (PYMOL-2775) | ||||
*width = I->Width; | *width = I->Width; | |||
*height = I->Height; | *height = I->Height; | |||
if (stereo_via_adjacent_array(I->StereoMode)) | if (stereo_via_adjacent_array(I->StereoMode)) | |||
*width /= 2.f; | *width /= 2.f; | |||
} | } | |||
void SceneSetCardInfo(PyMOLGlobals * G, | void SceneSetCardInfo(PyMOLGlobals * G, | |||
const char *vendor, | const char *vendor, | |||
const char *renderer, | const char *renderer, | |||
const char *version) | const char *version) | |||
skipping to change at line 1088 | skipping to change at line 897 | |||
MatrixTransformC44fAs33f3f(I->RotMatrix, I->Origin, pos); | MatrixTransformC44fAs33f3f(I->RotMatrix, I->Origin, pos); | |||
pos[0] -= I->Pos[0]; | pos[0] -= I->Pos[0]; | |||
pos[1] -= I->Pos[1]; | pos[1] -= I->Pos[1]; | |||
MatrixInvTransformC44fAs33f3f(I->RotMatrix, pos, pos); | MatrixInvTransformC44fAs33f3f(I->RotMatrix, pos, pos); | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
void SceneApplyRotMatrix(PyMOLGlobals * G, float *src, float *dst) | ||||
{ | ||||
CScene *I = G->Scene; | ||||
MatrixTransformC44fAs33f3f(I->RotMatrix, src, dst); | ||||
} | ||||
/*========================================================================*/ | ||||
int SceneMultipick(PyMOLGlobals * G, Multipick * smp) | ||||
{ | ||||
CScene *I = G->Scene; | ||||
int click_side = 0; | ||||
int defer_builds_mode = SettingGetGlobal_i(G, cSetting_defer_builds_mode); | ||||
if(defer_builds_mode == 5) /* force generation of a pickable version */ | ||||
SceneUpdate(G, true); | ||||
if(OrthoGetOverlayStatus(G) || SettingGetGlobal_i(G, cSetting_text)) | ||||
SceneRender(G, NULL, 0, 0, NULL, 0, 0, 0, 0, 0); /* remove overlay if | ||||
present */ | ||||
SceneDontCopyNext(G); | ||||
if(stereo_via_adjacent_array(I->StereoMode)) { | ||||
if(smp->x > (I->Width / 2)) | ||||
click_side = 1; | ||||
else | ||||
click_side = -1; | ||||
smp->x = smp->x % (I->Width / 2); | ||||
} | ||||
SceneRender(G, NULL, 0, 0, smp, 0, 0, click_side, 0, 0); | ||||
SceneDirty(G); | ||||
return (1); | ||||
} | ||||
/*========================================================================*/ | ||||
int SceneGetNFrame(PyMOLGlobals * G, int *has_movie) | int SceneGetNFrame(PyMOLGlobals * G, int *has_movie) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
if(has_movie) | if(has_movie) | |||
*has_movie = I->HasMovie; | *has_movie = I->HasMovie; | |||
return (I->NFrame); | return (I->NFrame); | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
/* SceneGetView: all information required to define the geometry | ||||
of a particular view, for shipping to and from python | ||||
as a list of floats | ||||
0-15 = 4x4 rotation matrix | ||||
16-18 = position | ||||
19-21 = origin | ||||
22 = front plane | ||||
23 = rear plane | ||||
24 = orthoscopic flag | ||||
*/ | ||||
void SceneGetView(PyMOLGlobals * G, SceneViewType view) | void SceneGetView(PyMOLGlobals * G, SceneViewType view) | |||
{ | { | |||
float *p; | float *p; | |||
int a; | int a; | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
p = view; | p = view; | |||
for(a = 0; a < 16; a++) | for(a = 0; a < 16; a++) | |||
*(p++) = I->RotMatrix[a]; | *(p++) = I->RotMatrix[a]; | |||
*(p++) = I->Pos[0]; | *(p++) = I->Pos[0]; | |||
*(p++) = I->Pos[1]; | *(p++) = I->Pos[1]; | |||
skipping to change at line 1231 | skipping to change at line 1018 | |||
{ | { | |||
if(G->Scene->StereoMode) { | if(G->Scene->StereoMode) { | |||
SceneSetStereo(G, true); | SceneSetStereo(G, true); | |||
} | } | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
void SceneSetStereo(PyMOLGlobals * G, int flag) | void SceneSetStereo(PyMOLGlobals * G, int flag) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
int cur_stereo = I->StereoMode; | int cur_stereo, cur_stereo_mode = I->StereoMode, reload = 0; | |||
cur_stereo = SettingGetGlobal_b(G, cSetting_stereo); | ||||
if(flag) { | if(flag) { | |||
I->StereoMode = SettingGetGlobal_i(G, cSetting_stereo_mode); | I->StereoMode = SettingGetGlobal_i(G, cSetting_stereo_mode); | |||
} else { | } else { | |||
I->StereoMode = 0; | I->StereoMode = 0; | |||
} | } | |||
if((cur_stereo != I->StereoMode) && (cur_stereo == cStereo_geowall || I->Stere | SettingSetGlobal_b(G, cSetting_stereo, flag); | |||
oMode == cStereo_geowall)) { | ||||
if((cur_stereo_mode != I->StereoMode) && (cur_stereo_mode == cStereo_geowall | | ||||
| I->StereoMode == cStereo_geowall)) { | ||||
reload = 1; | ||||
OrthoReshape(G, G->Option->winX, G->Option->winY, true); | OrthoReshape(G, G->Option->winX, G->Option->winY, true); | |||
#ifndef _PYMOL_NOPY | #ifndef _PYMOL_NOPY | |||
if(cur_stereo == cStereo_geowall) { | if(cur_stereo_mode == cStereo_geowall) { | |||
PParse(G, "viewport"); | PParse(G, "viewport"); | |||
} | } | |||
#endif | #endif | |||
} | } | |||
SettingSetGlobal_b(G, cSetting_stereo, flag); | ||||
SceneInvalidateStencil(G); | SceneInvalidateStencil(G); | |||
SceneInvalidate(G); | SceneInvalidate(G); | |||
if (cur_stereo != flag || (flag && reload)){ | ||||
CShaderMgr_Set_Reload_Bits(G, RELOAD_ALL_SHADERS); | G->ShaderMgr->Set_Reload_Bits(RELOAD_VARIABLES); | |||
} | ||||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
void SceneTranslate(PyMOLGlobals * G, float x, float y, float z) | void SceneTranslate(PyMOLGlobals * G, float x, float y, float z) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
I->Pos[0] += x; | I->Pos[0] += x; | |||
I->Pos[1] += y; | I->Pos[1] += y; | |||
I->Pos[2] += z; | I->Pos[2] += z; | |||
SceneClipSet(G, I->Front - z, I->Back - z); | SceneClipSet(G, I->Front - z, I->Back - z); | |||
skipping to change at line 1564 | skipping to change at line 1355 | |||
return (SettingGetGlobal_i(G, cSetting_state) - 1); | return (SettingGetGlobal_i(G, cSetting_state) - 1); | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
float *SceneGetMatrix(PyMOLGlobals * G) | float *SceneGetMatrix(PyMOLGlobals * G) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
return (I->RotMatrix); | return (I->RotMatrix); | |||
} | } | |||
float *SceneGetModMatrix(PyMOLGlobals * G) | ||||
{ | ||||
return G->Scene->ModMatrix; | ||||
} | ||||
float *SceneGetPmvMatrix(PyMOLGlobals * G) | float *SceneGetPmvMatrix(PyMOLGlobals * G) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
multiply44f44f44f(I->ModelViewMatrix, I->ProjectionMatrix, I->PmvMatrix); | ||||
return (I->PmvMatrix); | return (I->PmvMatrix); | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
int SceneCaptureWindow(PyMOLGlobals * G) | int SceneCaptureWindow(PyMOLGlobals * G) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
int ok = true; | int ok = true; | |||
skipping to change at line 1737 | skipping to change at line 1524 | |||
OrthoBusyPrime(G); | OrthoBusyPrime(G); | |||
/* so the trick here is that we need to move the camera around | /* so the trick here is that we need to move the camera around | |||
so that we get a pixel-perfect mosaic */ | so that we get a pixel-perfect mosaic */ | |||
for(y = 0; y < nYStep; y++) { | for(y = 0; y < nYStep; y++) { | |||
int y_offset = -(I->Height * y); | int y_offset = -(I->Height * y); | |||
for(x = 0; x < nXStep; x++) { | for(x = 0; x < nXStep; x++) { | |||
int x_offset = -(I->Width * x); | int x_offset = -(I->Width * x); | |||
int a, b; | int a, b; | |||
// float *v; | ||||
// float alpha = | ||||
// (SettingGetGlobal_b(G, cSetting_opaque_background) ? | ||||
1.0F : 0.0F); | ||||
unsigned int *p, *q, *qq, *pp; | unsigned int *p, *q, *qq, *pp; | |||
OrthoBusyFast(G, y * nXStep + x, total_steps); | OrthoBusyFast(G, y * nXStep + x, total_steps); | |||
if(draw_both) { | if(draw_both) { | |||
OrthoDrawBuffer(G, GL_BACK_LEFT); | OrthoDrawBuffer(G, GL_BACK_LEFT); | |||
} else { | } else { | |||
OrthoDrawBuffer(G, GL_BACK); | OrthoDrawBuffer(G, GL_BACK); | |||
} | } | |||
// SceneGLClearColor(v[0], v[1], v[2], alpha); | ||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); | glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); | |||
SceneInvalidateCopy(G, false); | SceneInvalidateCopy(G, false); | |||
SceneRender(G, NULL, x_offset, y_offset, NULL, width, height, 0, 0, 0); | SceneRender(G, NULL, x_offset, y_offset, NULL, width, height, 0, 0); | |||
SceneGLClearColor(0.0, 0.0, 0.0, 1.0); | SceneGLClearColor(0.0, 0.0, 0.0, 1.0); | |||
if(draw_both) { | if(draw_both) { | |||
SceneCopy(G, GL_BACK_LEFT, true, false); | SceneCopy(G, GL_BACK_LEFT, true, false); | |||
} else { | } else { | |||
SceneCopy(G, GL_BACK, true, false); | SceneCopy(G, GL_BACK, true, false); | |||
} | } | |||
if(I->Image) { /* the image into place */ | if(I->Image) { /* the image into place */ | |||
p = (unsigned int *) I->Image->data; | p = (unsigned int *) I->Image->data; | |||
skipping to change at line 1900 | skipping to change at line 1683 | |||
} | } | |||
if(save_flag) { | if(save_flag) { | |||
I->Width = save_width; | I->Width = save_width; | |||
I->Height = save_height; | I->Height = save_height; | |||
} | } | |||
return ok; | return ok; | |||
} | } | |||
/*========================================================================*/ | #define SceneImagePrepareImpl SceneImagePrepare | |||
static unsigned char *SceneImagePrepare(PyMOLGlobals * G, int prior_only) | ||||
unsigned char *SceneImagePrepareImpl(PyMOLGlobals * G, int prior_only, int noinv | ||||
alid) | ||||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
unsigned char *image = NULL; | unsigned char *image = NULL; | |||
int save_stereo = (I->StereoMode == 1); | int save_stereo = (I->StereoMode == 1); | |||
int ok = true; | int ok = true; | |||
if(!(I->CopyType || prior_only)) { | if(!noinvalid && !(I->CopyType || prior_only)) { | |||
if(G->HaveGUI && G->ValidContext) { | if(G->HaveGUI && G->ValidContext) { | |||
unsigned int buffer_size; | unsigned int buffer_size; | |||
buffer_size = 4 * I->Width * I->Height; | buffer_size = 4 * I->Width * I->Height; | |||
if(save_stereo) | if(save_stereo) | |||
image = Alloc(unsigned char, buffer_size * 2); | image = Alloc(unsigned char, buffer_size * 2); | |||
else | else | |||
image = Alloc(unsigned char, buffer_size); | image = Alloc(unsigned char, buffer_size); | |||
CHECKOK(ok, image); | CHECKOK(ok, image); | |||
if (!ok) | if (!ok) | |||
skipping to change at line 1932 | skipping to change at line 1716 | |||
} else { | } else { | |||
glReadBuffer(GL_BACK); | glReadBuffer(GL_BACK); | |||
} | } | |||
PyMOLReadPixels(I->Block->rect.left, I->Block->rect.bottom, I->Width, I->H eight, | PyMOLReadPixels(I->Block->rect.left, I->Block->rect.bottom, I->Width, I->H eight, | |||
GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) (image)); | GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) (image)); | |||
if(save_stereo) { | if(save_stereo) { | |||
glReadBuffer(GL_BACK_RIGHT); | glReadBuffer(GL_BACK_RIGHT); | |||
PyMOLReadPixels(I->Block->rect.left, I->Block->rect.bottom, I->Width, I- >Height, | PyMOLReadPixels(I->Block->rect.left, I->Block->rect.bottom, I->Width, I- >Height, | |||
GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) (image + buffer_si ze)); | GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) (image + buffer_si ze)); | |||
} | } | |||
ScenePurgeImage(G); | ScenePurgeImageImpl(G, noinvalid); | |||
I->Image = Calloc(ImageType, 1); | I->Image = Calloc(ImageType, 1); | |||
I->Image->needs_alpha_reset = true; | I->Image->needs_alpha_reset = true; | |||
I->Image->data = image; | I->Image->data = image; | |||
I->Image->height = I->Height; | I->Image->height = I->Height; | |||
I->Image->width = I->Width; | I->Image->width = I->Width; | |||
I->Image->size = buffer_size; | I->Image->size = buffer_size; | |||
if(save_stereo) | if(save_stereo) | |||
I->Image->stereo = 1; | I->Image->stereo = 1; | |||
} | } | |||
} else if(I->Image) { | } else if(I->Image) { | |||
skipping to change at line 1957 | skipping to change at line 1741 | |||
if(opaque_back && I->Image->needs_alpha_reset) { | if(opaque_back && I->Image->needs_alpha_reset) { | |||
int i, s = 4 * I->Image->width * I->Image->height; | int i, s = 4 * I->Image->width * I->Image->height; | |||
for(i = 3; i < s; i += 4) | for(i = 3; i < s; i += 4) | |||
image[i] = 0xFF; | image[i] = 0xFF; | |||
I->Image->needs_alpha_reset = false; | I->Image->needs_alpha_reset = false; | |||
} | } | |||
} | } | |||
return (unsigned char *) image; | return (unsigned char *) image; | |||
} | } | |||
static void SceneImageFinish(PyMOLGlobals * G, GLvoid *image) | void SceneImageFinish(PyMOLGlobals * G, GLvoid *image) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
if(I->Image) { | if(I->Image) { | |||
if(I->Image->data != (unsigned char *) image) /* purge the image if th is isn't the active copy */ | if(I->Image->data != (unsigned char *) image) /* purge the image if th is isn't the active copy */ | |||
FreeP(image); | FreeP(image); | |||
} else { | } else { | |||
FreeP(image); | FreeP(image); | |||
} | } | |||
} | } | |||
skipping to change at line 1979 | skipping to change at line 1763 | |||
* Get the size of the rendered image. This is either identical to | * Get the size of the rendered image. This is either identical to | |||
* cmd.get_viewport(), or the dimensions which were last passed to | * cmd.get_viewport(), or the dimensions which were last passed to | |||
* cmd.draw(), cmd.ray() or cmd.png(). | * cmd.draw(), cmd.ray() or cmd.png(). | |||
*/ | */ | |||
void SceneGetImageSize(PyMOLGlobals * G, int *width, int *height) | void SceneGetImageSize(PyMOLGlobals * G, int *width, int *height) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
// TODO: calling ImagePrepare looks like a heavy side effect. Need to | // TODO: calling ImagePrepare looks like a heavy side effect. Need to | |||
// clarify if checking (CopyType && Image && Image->data) here would | // clarify if checking (CopyType && Image && Image->data) here would | |||
// be sufficient. | // be sufficient. | |||
GLvoid *image = SceneImagePrepare(G, false); | GLvoid *image = SceneImagePrepareImpl(G, false, false); | |||
if(image && I->Image) { | if(image && I->Image) { | |||
*width = I->Image->width; | *width = I->Image->width; | |||
*height = I->Image->height; | *height = I->Image->height; | |||
} else { | } else { | |||
*width = I->Width; | *width = I->Width; | |||
*height = I->Height; | *height = I->Height; | |||
} | } | |||
SceneImageFinish(G, image); /* don't leak if(image != I->Image) */ | SceneImageFinish(G, image); /* don't leak if(image != I->Image) */ | |||
} | } | |||
skipping to change at line 2161 | skipping to change at line 1945 | |||
/*========================================================================*/ | /*========================================================================*/ | |||
int SceneGetFrame(PyMOLGlobals * G) | int SceneGetFrame(PyMOLGlobals * G) | |||
{ | { | |||
if(MovieDefined(G)) | if(MovieDefined(G)) | |||
return (SettingGetGlobal_i(G, cSetting_frame) - 1); | return (SettingGetGlobal_i(G, cSetting_frame) - 1); | |||
else | else | |||
return (SettingGetGlobal_i(G, cSetting_state) - 1); | return (SettingGetGlobal_i(G, cSetting_state) - 1); | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
void SceneCountFrames(PyMOLGlobals * G) | /* GM: | |||
* Returns the number of movie frames, or the number of states if no movie | ||||
* is defined. | ||||
*/ | ||||
int SceneCountFrames(PyMOLGlobals * G) | ||||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
ObjRec *rec = NULL; | ||||
int n; | int n; | |||
int mov_len; | int mov_len; | |||
I->NFrame = 0; | I->NFrame = 0; | |||
while(ListIterate(I->Obj, rec, next)) { | for ( auto it = I->Obj.begin(); it != I->Obj.end(); ++it) { | |||
if(rec->obj->fGetNFrame) | n = (*it)->getNFrame(); | |||
n = rec->obj->fGetNFrame(rec->obj); | ||||
else | ||||
n = 0; | ||||
if(n > I->NFrame) | if(n > I->NFrame) | |||
I->NFrame = n; | I->NFrame = n; | |||
} | } | |||
mov_len = MovieGetLength(G); | mov_len = MovieGetLength(G); | |||
I->HasMovie = (mov_len != 0); | I->HasMovie = (mov_len != 0); | |||
if(mov_len > 0) { | if(mov_len > 0) { | |||
I->NFrame = mov_len; | I->NFrame = mov_len; | |||
} else if(mov_len < 0) { | } else if(mov_len < 0) { | |||
mov_len = -mov_len; | mov_len = -mov_len; | |||
if(I->NFrame < mov_len) /* allows you to see cached movie even w/o objec t */ | if(I->NFrame < mov_len) /* allows you to see cached movie even w/o objec t */ | |||
I->NFrame = mov_len; | I->NFrame = mov_len; | |||
} | } | |||
PRINTFD(G, FB_Scene) | PRINTFD(G, FB_Scene)" SceneCountFrames: leaving... I->NFrame %d\n", I->NFrame | |||
" SceneCountFrames: leaving... I->NFrame %d\n", I->NFrame ENDFD} | ENDFD | |||
return I->NFrame; | ||||
} | ||||
/*========================================================================*/ | /*========================================================================*/ | |||
void SceneSetFrame(PyMOLGlobals * G, int mode, int frame) | void SceneSetFrame(PyMOLGlobals * G, int mode, int frame) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
int newFrame; | int newFrame; | |||
int newState = 0; | int newState = 0; | |||
int movieCommand = false; | int movieCommand = false; | |||
int suppress = false; | int suppress = false; | |||
skipping to change at line 2271 | skipping to change at line 2056 | |||
if(newFrame == 0) { | if(newFrame == 0) { | |||
if(MovieMatrix(G, cMovieMatrixRecall)) { | if(MovieMatrix(G, cMovieMatrixRecall)) { | |||
SceneAbortAnimation(G); /* if we have a programmed initial | SceneAbortAnimation(G); /* if we have a programmed initial | |||
orientation, don't allow animation | orientation, don't allow animation | |||
to override it */ | to override it */ | |||
} | } | |||
} | } | |||
SettingSetGlobal_i(G, cSetting_frame, newFrame + 1); | SettingSetGlobal_i(G, cSetting_frame, newFrame + 1); | |||
SettingSetGlobal_i(G, cSetting_state, newState + 1); | SettingSetGlobal_i(G, cSetting_state, newState + 1); | |||
ExecutiveInvalidateSelectionIndicatorsCGO(G); | ExecutiveInvalidateSelectionIndicatorsCGO(G); | |||
SceneInvalidatePicking(G); | ||||
if(movieCommand) { | if(movieCommand) { | |||
#ifndef _PYMOL_NO_UNDO | ||||
int suspend_undo = SettingGetGlobal_b(G, cSetting_suspend_undo); | int suspend_undo = SettingGetGlobal_b(G, cSetting_suspend_undo); | |||
if (!suspend_undo){ | if (!suspend_undo){ | |||
SettingSetGlobal_i(G, cSetting_suspend_undo, 1); | SettingSetGlobal_i(G, cSetting_suspend_undo, 1); | |||
} | } | |||
#endif | ||||
MovieDoFrameCommand(G, newFrame); | MovieDoFrameCommand(G, newFrame); | |||
MovieFlushCommands(G); | MovieFlushCommands(G); | |||
#ifndef _PYMOL_NO_UNDO | ||||
SettingSetGlobal_i(G, cSetting_suspend_undo, suspend_undo); | SettingSetGlobal_i(G, cSetting_suspend_undo, suspend_undo); | |||
#endif | ||||
} | } | |||
if(SettingGetGlobal_b(G, cSetting_cache_frames)) | if(SettingGetGlobal_b(G, cSetting_cache_frames)) | |||
I->MovieFrameFlag = true; | I->MovieFrameFlag = true; | |||
} else { | } else { | |||
SettingSetGlobal_i(G, cSetting_frame, newFrame + 1); | SettingSetGlobal_i(G, cSetting_frame, newFrame + 1); | |||
SettingSetGlobal_i(G, cSetting_state, newState + 1); | SettingSetGlobal_i(G, cSetting_state, newState + 1); | |||
ExecutiveInvalidateSelectionIndicatorsCGO(G); | ExecutiveInvalidateSelectionIndicatorsCGO(G); | |||
SceneInvalidatePicking(G); | ||||
} | } | |||
MovieSetScrollBarFrame(G, newFrame); | MovieSetScrollBarFrame(G, newFrame); | |||
SeqChanged(G); // SceneInvalidate(G); | SeqChanged(G); // SceneInvalidate(G); | |||
} | } | |||
PRINTFD(G, FB_Scene) | PRINTFD(G, FB_Scene) | |||
" SceneSetFrame: leaving...\n" ENDFD; | " SceneSetFrame: leaving...\n" ENDFD; | |||
OrthoInvalidateDoDraw(G); | OrthoInvalidateDoDraw(G); | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
skipping to change at line 2418 | skipping to change at line 2209 | |||
{ | { | |||
int draw_both = SceneMustDrawBoth(G); | int draw_both = SceneMustDrawBoth(G); | |||
if(G->HaveGUI && G->ValidContext) { | if(G->HaveGUI && G->ValidContext) { | |||
if(draw_both) { | if(draw_both) { | |||
OrthoDrawBuffer(G, GL_BACK_LEFT); | OrthoDrawBuffer(G, GL_BACK_LEFT); | |||
} else { | } else { | |||
OrthoDrawBuffer(G, GL_BACK); | OrthoDrawBuffer(G, GL_BACK); | |||
} | } | |||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); | glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); | |||
/* insert OpenGL context validation code here? */ | /* insert OpenGL context validation code here? */ | |||
SceneRender(G, NULL, 0, 0, NULL, 0, 0, 0, 0, 0); | SceneRender(G, NULL, 0, 0, NULL, 0, 0, 0, 0); | |||
SceneGLClearColor(0.0, 0.0, 0.0, 1.0); | SceneGLClearColor(0.0, 0.0, 0.0, 1.0); | |||
if(draw_both) { | if(draw_both) { | |||
SceneCopy(G, GL_BACK_LEFT, true, false); | SceneCopy(G, GL_BACK_LEFT, true, false); | |||
} else { | } else { | |||
SceneCopy(G, GL_BACK, true, false); | SceneCopy(G, GL_BACK, true, false); | |||
} | } | |||
/* insert OpenGL context validation code here? */ | /* insert OpenGL context validation code here? */ | |||
} | } | |||
} | } | |||
break; | break; | |||
skipping to change at line 2573 | skipping to change at line 2364 | |||
} else | } else | |||
MoviePlay(G, cMovieStop); | MoviePlay(G, cMovieStop); | |||
} else { | } else { | |||
SceneSetFrame(G, 5, 1); | SceneSetFrame(G, 5, 1); | |||
} | } | |||
PyMOL_NeedRedisplay(G->PyMOL); | PyMOL_NeedRedisplay(G->PyMOL); | |||
} | } | |||
} | } | |||
} | } | |||
/* | ||||
* Get the field-of-view width at a depth of 1.0 | ||||
*/ | ||||
static float GetFovWidth(PyMOLGlobals * G) | ||||
{ | ||||
float fov = SettingGetGlobal_f(G, cSetting_field_of_view); | ||||
return 2.f * tanf(fov * PI / 360.f); | ||||
} | ||||
/*========================================================================*/ | /*========================================================================*/ | |||
/* | /* | |||
* Zoom to location and radius | * Zoom to location and radius | |||
*/ | */ | |||
void SceneWindowSphere(PyMOLGlobals * G, float *location, float radius) | void SceneWindowSphere(PyMOLGlobals * G, float *location, float radius) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
float v0[3]; | float v0[3]; | |||
float dist = 2.f * radius / GetFovWidth(G); | float dist = 2.f * radius / GetFovWidth(G); | |||
skipping to change at line 2671 | skipping to change at line 2453 | |||
I->Origin[0] = origin[0]; /* move origin */ | I->Origin[0] = origin[0]; /* move origin */ | |||
I->Origin[1] = origin[1]; | I->Origin[1] = origin[1]; | |||
I->Origin[2] = origin[2]; | I->Origin[2] = origin[2]; | |||
SceneInvalidate(G); | SceneInvalidate(G); | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
int SceneObjectAdd(PyMOLGlobals * G, CObject * obj) | int SceneObjectAdd(PyMOLGlobals * G, CObject * obj) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
ObjRec *rec = NULL; | ||||
ListElemAlloc(G, rec, ObjRec); | ||||
rec->next = NULL; | ||||
obj->Enabled = true; | obj->Enabled = true; | |||
rec->obj = obj; | I->Obj.push_back(obj); | |||
ListAppend(I->Obj, rec, next, ObjRec); | if(obj->type == cObjectGadget) { | |||
I->GadgetObjs.push_back(obj); | ||||
} else { | ||||
I->NonGadgetObjs.push_back(obj); | ||||
} | ||||
SceneCountFrames(G); | SceneCountFrames(G); | |||
SceneChanged(G); | SceneChanged(G); | |||
SceneInvalidatePicking(G); // PYMOL-2793 | ||||
return 1; | return 1; | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
int SceneObjectIsActive(PyMOLGlobals * G, CObject * obj) | int SceneObjectIsActive(PyMOLGlobals * G, CObject * obj) | |||
{ | { | |||
int result = false; | int result = false; | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
ObjRec *rec = NULL; | if (find(I->Obj.begin(), I->Obj.end(), obj) != I->Obj.end()) | |||
while(ListIterate(I->Obj, rec, next)) | ||||
if(rec->obj == obj) { | ||||
result = true; | result = true; | |||
break; | ||||
} | ||||
return result; | return result; | |||
} | } | |||
int SceneObjectDel(PyMOLGlobals * G, CObject * obj, int allow_purge) | int SceneObjectDel(PyMOLGlobals * G, CObject * obj, int allow_purge) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
ObjRec *rec = NULL; | ||||
int defer_builds_mode = SettingGetGlobal_i(G, cSetting_defer_builds_mode); | int defer_builds_mode = SettingGetGlobal_i(G, cSetting_defer_builds_mode); | |||
if(!obj) { /* deletes all members */ | if(!obj) { /* deletes all members */ | |||
while(ListIterate(I->Obj, rec, next)) { | if(allow_purge && (defer_builds_mode >= 3)) { | |||
if(rec) { | for ( auto it = I->Obj.begin(); it != I->Obj.end(); ++it) { | |||
if(allow_purge && (defer_builds_mode >= 3)) { | /* purge graphics representation when no longer used */ | |||
/* purge graphics representation when no longer used */ | (*it)->invalidate(cRepAll, cRepInvPurge, -1); | |||
if(rec->obj->fInvalidate) | ||||
rec->obj->fInvalidate(rec->obj, cRepAll, cRepInvPurge, -1); | ||||
} | ||||
ListDetach(I->Obj, rec, next, ObjRec); | ||||
ListElemFree(rec); | ||||
} | } | |||
} | } | |||
I->Obj.clear(); | ||||
I->GadgetObjs.clear(); | ||||
I->NonGadgetObjs.clear(); | ||||
} else { | } else { | |||
while(ListIterate(I->Obj, rec, next)) | auto &obj_list = (obj->type == cObjectGadget) ? I->GadgetObjs : I->NonGadget | |||
if(rec->obj == obj) | Objs; | |||
break; | auto itg = find(obj_list.begin(), obj_list.end(), obj); | |||
if(rec) { | if (itg != obj_list.end()) | |||
obj_list.erase(itg); | ||||
auto it = find(I->Obj.begin(), I->Obj.end(), obj); | ||||
if (it != I->Obj.end()){ | ||||
if(allow_purge && (defer_builds_mode >= 3)) { | if(allow_purge && (defer_builds_mode >= 3)) { | |||
/* purge graphics representation when no longer used */ | /* purge graphics representation when no longer used */ | |||
if(rec->obj->fInvalidate) | (*it)->invalidate(cRepAll, cRepInvPurge, -1); | |||
rec->obj->fInvalidate(rec->obj, cRepAll, cRepInvPurge, -1); | ||||
} | } | |||
rec->obj->Enabled = false; | obj->Enabled = false; | |||
ListDetach(I->Obj, rec, next, ObjRec); | I->Obj.erase(it); | |||
ListElemFree(rec); | ||||
} | } | |||
} | } | |||
SceneCountFrames(G); | SceneCountFrames(G); | |||
SceneInvalidate(G); | SceneInvalidate(G); | |||
return 0; | return 0; | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
int SceneLoadPNG(PyMOLGlobals * G, const char *fname, int movie_flag, int stereo , int quiet) | int SceneLoadPNG(PyMOLGlobals * G, const char *fname, int movie_flag, int stereo , int quiet) | |||
{ | { | |||
skipping to change at line 2900 | skipping to change at line 2678 | |||
glColor3f(0.1F, 1.0F, 0.1F); | glColor3f(0.1F, 1.0F, 0.1F); | |||
glVertex3i(x2 + 1, y2 + h - 1, z); | glVertex3i(x2 + 1, y2 + h - 1, z); | |||
glColor3f(1.0F, 1.0F, 0.1F); | glColor3f(1.0F, 1.0F, 0.1F); | |||
glVertex3i(x2 + w - 1, y2 + h - 1, z); | glVertex3i(x2 + w - 1, y2 + h - 1, z); | |||
glColor3f(0.1F, 0.1F, 1.0F); | glColor3f(0.1F, 0.1F, 1.0F); | |||
glVertex3i(x2 + w - 1, y2 + 1, z); | glVertex3i(x2 + w - 1, y2 + 1, z); | |||
glEnd(); | glEnd(); | |||
} | } | |||
} | } | |||
} | } | |||
#endif | ||||
/* | /* | |||
* Update the G->Scene->SceneVLA names array which is used for scene buttons | * Update the G->Scene->SceneVLA names array which is used for scene buttons | |||
*/ | */ | |||
void SceneSetNames(PyMOLGlobals * G, const std::vector<std::string> &list) | void SceneSetNames(PyMOLGlobals * G, const std::vector<std::string> &list) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
I->NScene = list.size(); | I->NScene = (int)list.size(); | |||
VLACheck(I->SceneVLA, SceneElem, I->NScene); | VLACheck(I->SceneVLA, SceneElem, I->NScene); | |||
SceneElem *elem = I->SceneVLA; | SceneElem *elem = I->SceneVLA; | |||
for(int a = 0; a < I->NScene; ++a) { | for(int a = 0; a < I->NScene; ++a) { | |||
elem->name = (char*) list[a].c_str(); | elem->name = (char*) list[a].c_str(); | |||
elem->len = list[a].length(); | elem->len = (int)list[a].length(); | |||
elem->drawn = false; | elem->drawn = false; | |||
elem++; | elem++; | |||
} | } | |||
OrthoDirty(G); | OrthoDirty(G); | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
static void SceneDrawButtons(Block * block, int draw_for_real ORTHOCGOARG) | static void SceneDrawButtons(Block * block, int draw_for_real ORTHOCGOARG) | |||
{ | { | |||
skipping to change at line 3108 | skipping to change at line 2887 | |||
break; | break; | |||
} | } | |||
} | } | |||
} | } | |||
I->HowFarDown = y; | I->HowFarDown = y; | |||
I->ButtonsValid = true; | I->ButtonsValid = true; | |||
} | } | |||
#endif | #endif | |||
} | } | |||
int SceneDrawImageOverlay(PyMOLGlobals * G ORTHOCGOARG){ | int SceneDrawImageOverlay(PyMOLGlobals * G, int override ORTHOCGOARG){ | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
int drawn = false; | int drawn = false; | |||
int text = SettingGetGlobal_b(G, cSetting_text); | int text = SettingGetGlobal_b(G, cSetting_text); | |||
/* is the text/overlay (ESC) on? */ | /* is the text/overlay (ESC) on? */ | |||
int overlay = OrthoGetOverlayStatus(G); | int overlay = OrthoGetOverlayStatus(G); | |||
if(((!text) || overlay) && (I->CopyType == true) && I->Image && I->Image->data ) { | if(((!text) || overlay) && (override || I->CopyType == true) && I->Image && I- >Image->data) { | |||
/* show transparent bg as checkboard? */ | /* show transparent bg as checkboard? */ | |||
int show_alpha = SettingGetGlobal_b(G, cSetting_show_alpha_checker); | int show_alpha = SettingGetGlobal_b(G, cSetting_show_alpha_checker); | |||
float *bg_color = ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_rg b)); | const float *bg_color = ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting _bg_rgb)); | |||
unsigned int bg_rr, bg_r = (unsigned int) (255 * bg_color[0]); | unsigned int bg_rr, bg_r = (unsigned int) (255 * bg_color[0]); | |||
unsigned int bg_gg, bg_g = (unsigned int) (255 * bg_color[1]); | unsigned int bg_gg, bg_g = (unsigned int) (255 * bg_color[1]); | |||
unsigned int bg_bb, bg_b = (unsigned int) (255 * bg_color[2]); | unsigned int bg_bb, bg_b = (unsigned int) (255 * bg_color[2]); | |||
int width = I->Image->width; | int width = I->Image->width; | |||
int height = I->Image->height; | int height = I->Image->height; | |||
unsigned char *data = I->Image->data; | unsigned char *data = I->Image->data; | |||
if(I->Image->stereo) { | if(I->Image->stereo) { | |||
int buffer; | int buffer; | |||
glGetIntegerv(GL_DRAW_BUFFER, (GLint *) & buffer); | glGetIntegerv(GL_DRAW_BUFFER, (GLint *) & buffer); | |||
skipping to change at line 3366 | skipping to change at line 3145 | |||
} | } | |||
glRasterPos3i((int) ((I->Width - tmp_width) / 2 + I->Block->rect.left), | glRasterPos3i((int) ((I->Width - tmp_width) / 2 + I->Block->rect.left), | |||
(int) ((I->Height - tmp_height) / 2 + I->Block->rect.bottom ), | (int) ((I->Height - tmp_height) / 2 + I->Block->rect.bottom ), | |||
-10); | -10); | |||
PyMOLDrawPixels(tmp_width, tmp_height, GL_RGBA, GL_UNSIGNED_BYTE, tmp_buf fer); | PyMOLDrawPixels(tmp_width, tmp_height, GL_RGBA, GL_UNSIGNED_BYTE, tmp_buf fer); | |||
drawn = true; | drawn = true; | |||
} | } | |||
FreeP(tmp_buffer); | FreeP(tmp_buffer); | |||
} else if(I->CopyForced) { /* near-exact fit */ | } else if(I->CopyForced) { /* near-exact fit */ | |||
unsigned int color_word; | ||||
float rgba[4] = { 0.0F, 0.0F, 0.0F, 1.0F }; | float rgba[4] = { 0.0F, 0.0F, 0.0F, 1.0F }; | |||
unsigned int n_word = height * width; | unsigned int n_word = height * width; | |||
unsigned int *tmp_buffer = Alloc(unsigned int, n_word); | unsigned int *tmp_buffer = Alloc(unsigned int, n_word); | |||
ColorGetBkrdContColor(G, rgba, false); | ColorGetBkrdContColor(G, rgba, false); | |||
color_word = ColorGet32BitWord(G, rgba); | ||||
if(tmp_buffer) { | if(tmp_buffer) { | |||
unsigned int a, b; | unsigned int a, b; | |||
unsigned int *p = (unsigned int *) data; | unsigned int *p = (unsigned int *) data; | |||
unsigned int *q = tmp_buffer; | unsigned int *q = tmp_buffer; | |||
for(a = 0; a < (unsigned int) height; a++) { | for(a = 0; a < (unsigned int) height; a++) { | |||
for(b = 0; b < (unsigned int) width; b++) { | for(b = 0; b < (unsigned int) width; b++) { | |||
unsigned char *qq = (unsigned char *) q; | unsigned char *qq = (unsigned char *) q; | |||
unsigned char *pp = (unsigned char *) p; | unsigned char *pp = (unsigned char *) p; | |||
unsigned char bg; | unsigned char bg; | |||
skipping to change at line 3435 | skipping to change at line 3212 | |||
void SceneDraw(Block * block ORTHOCGOARG) /* returns true if scene was drawn (us ing a cached image) */ | void SceneDraw(Block * block ORTHOCGOARG) /* returns true if scene was drawn (us ing a cached image) */ | |||
{ | { | |||
PyMOLGlobals *G = block->G; | PyMOLGlobals *G = block->G; | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
int drawn = false; | int drawn = false; | |||
if(G->HaveGUI && G->ValidContext) { | if(G->HaveGUI && G->ValidContext) { | |||
I->ButtonsShown = false; | I->ButtonsShown = false; | |||
drawn = SceneDrawImageOverlay(G ORTHOCGOARGVAR); | drawn = SceneDrawImageOverlay(G, 0 ORTHOCGOARGVAR); | |||
if(SettingGetGlobal_b(G, cSetting_scene_buttons)) { | if(SettingGetGlobal_b(G, cSetting_scene_buttons)) { | |||
SceneDrawButtons(block, true ORTHOCGOARGVAR); | SceneDrawButtons(block, true ORTHOCGOARGVAR); | |||
} else { | } else { | |||
I->ButtonMargin = 0; | I->ButtonMargin = 0; | |||
} | } | |||
} | } | |||
if(drawn) | if(drawn) | |||
OrthoDrawWizardPrompt(G ORTHOCGOARGVAR); /* ugly hack necessitated because w izard | OrthoDrawWizardPrompt(G ORTHOCGOARGVAR); /* ugly hack necessitated because w izard | |||
prompt is overwritten when image is drawn */ | prompt is overwritten when image is drawn */ | |||
} | } | |||
int SceneGetButtonMargin(PyMOLGlobals * G) | int SceneGetButtonMargin(PyMOLGlobals * G) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
return I->ButtonMargin; | return I->ButtonMargin; | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
typedef unsigned char pix[4]; | ||||
#define cRange 7 | ||||
/*typedef pix pix_array[cRange*2+1][cRange*2+1];*/ | ||||
unsigned int SceneFindTriplet(PyMOLGlobals * G, int x, int y, GLenum gl_buffer) | ||||
{ | ||||
int result = 0; | ||||
/*int before_check[100]; | ||||
int *int_ptr; | ||||
*/ | ||||
pix *buffer = NULL; | ||||
pix *extra_safe_buffer = NULL; | ||||
/*int after_check[100]; */ | ||||
/* pix_array *array_ptr; | ||||
char *safe_place; | ||||
*/ | ||||
int a, b, d, flag; | ||||
float contentScaleFactor = DIP2PIXEL(1); | ||||
int cRangeVal = contentScaleFactor < 1.5 ? 7 : 21; | ||||
int h = (cRangeVal * 2 + 1), w = (cRangeVal * 2 + 1); | ||||
int debug = false; | ||||
unsigned char *c; | ||||
int strict = false, bits15 = false; | ||||
GLint rb, gb, bb, ab; | ||||
int bkrd_alpha = 0xFF; | ||||
int check_alpha = false; | ||||
if(G->HaveGUI && G->ValidContext) { /*just in case */ | ||||
glGetIntegerv(GL_RED_BITS, &rb); | ||||
glGetIntegerv(GL_GREEN_BITS, &gb); | ||||
glGetIntegerv(GL_BLUE_BITS, &bb); | ||||
glGetIntegerv(GL_ALPHA_BITS, &ab); | ||||
if((rb >= 8) && (gb >= 8) && (bb >= 8)) | ||||
strict = true; | ||||
bits15 = (rb == 5) && (gb == 5) && (bb == 5); | ||||
if((rb < 4) && (gb < 4) && (bb < 4)){ | ||||
PRINTFB(G, FB_Scene, FB_Errors) "SceneFindTriplet: ERROR: not enough color | ||||
s to pick: rb=%d gb=%d bb=%d\n", rb, gb, bb ENDFB(G); | ||||
return 0; | ||||
} | ||||
if(Feedback(G, FB_Scene, FB_Debugging)) | ||||
debug = true; | ||||
glReadBuffer(gl_buffer); | ||||
extra_safe_buffer = Alloc(pix, w * h * 21); | ||||
buffer = extra_safe_buffer + (w * h * 10); | ||||
PyMOLReadPixels(x - cRangeVal, y - cRangeVal, cRangeVal * 2 + 1, cRangeVal * | ||||
2 + 1, GL_RGBA, | ||||
GL_UNSIGNED_BYTE, &buffer[0][0]); | ||||
if(debug) { | ||||
for(a = 0; a <= (cRangeVal * 2); a++) { | ||||
for(b = 0; b <= (cRangeVal * 2); b++) | ||||
printf("%2x ", | ||||
(buffer[a + b * w][0] + buffer[a + b * w][1] + | ||||
buffer[a + b * w][2]) & 0xFF); | ||||
printf("\n"); | ||||
} | ||||
printf("\n"); | ||||
for(a = 0; a <= (cRangeVal * 2); a++) { | ||||
for(b = 0; b <= (cRangeVal * 2); b++) | ||||
printf("%02x ", (buffer[a + b * w][3]) & 0xFF); | ||||
printf("\n"); | ||||
} | ||||
printf("\n"); | ||||
for(a = 0; a <= (cRangeVal * 2); a++) { | ||||
for(b = 0; b <= (cRangeVal * 2); b++) | ||||
printf("%02x%02x%02x ", (buffer[a + b * w][0]) & 0xFF, | ||||
(buffer[a + b * w][1]) & 0xFF, (buffer[a + b * w][2]) & 0xFF); | ||||
printf("\n"); | ||||
} | ||||
printf("\n"); | ||||
} | ||||
/* first, check to make sure bkrd_alpha is correct | ||||
(this is a bug for systems with broken alpha, such as Extreme 3D on Solar | ||||
is 8 */ | ||||
flag = true; | ||||
for(d = 0; ab && flag && (d < cRangeVal); d++) | ||||
for(a = -d; flag && (a <= d); a++) | ||||
for(b = -d; flag && (b <= d); b++) { | ||||
c = &buffer[(a + cRangeVal) + (b + cRangeVal) * w][0]; | ||||
if(c[3] == bkrd_alpha) { | ||||
check_alpha = true; | ||||
flag = false; | ||||
} | ||||
} | ||||
/* now find the correct pixel */ | ||||
flag = true; | ||||
for(d = 0; flag && (d < cRangeVal); d++) | ||||
for(a = -d; flag && (a <= d); a++) | ||||
for(b = -d; flag && (b <= d); b++) { | ||||
c = &buffer[(a + cRangeVal) + (b + cRangeVal) * w][0]; | ||||
if(((c[3] == bkrd_alpha) || (!check_alpha)) && | ||||
( ( (bits15 && c[1]) || (c[1] & 0x8)) && | ||||
((!strict) || | ||||
(((c[1] & 0xF) == 8) && ((c[0] & 0xF) == 0) && ((c[2] & 0xF) == 0 | ||||
) | ||||
)))) { /* only consider intact, saturated pixels */ | ||||
flag = false; | ||||
if (bits15){ /* workaround for 15 bit rendering, for some reason red | ||||
/green need rounding */ | ||||
c[0] += 0x8; | ||||
c[2] += 0x8; | ||||
} | ||||
result = ((c[0] >> 4) & 0xF) + (c[1] & 0xF0) + ((c[2] << 4) & 0xF00); | ||||
if(debug) { | ||||
printf("%2x %2x %2x %d\n", c[0], c[1], c[2], result); | ||||
} | ||||
} | ||||
} | ||||
FreeP(extra_safe_buffer); | ||||
} | ||||
return (result); | ||||
} | ||||
/*========================================================================*/ | ||||
unsigned int *SceneReadTriplets(PyMOLGlobals * G, int x, int y, int w, int h, | ||||
GLenum gl_buffer) | ||||
{ | ||||
unsigned int *result = NULL; | ||||
pix *buffer = NULL; | ||||
pix *extra_safe_buffer = NULL; | ||||
int a, b; | ||||
unsigned char *c; | ||||
int cc = 0; | ||||
int dim[3]; | ||||
int strict = false, bits15 = false; | ||||
int bkrd_alpha = 0xFF; | ||||
int check_alpha = false; | ||||
GLint rb, gb, bb, ab; | ||||
dim[0] = w; | ||||
dim[1] = h; | ||||
if(w < 1) | ||||
w = 1; | ||||
if(h < 1) | ||||
h = 1; | ||||
if(G->HaveGUI && G->ValidContext) { /*just in case */ | ||||
glGetIntegerv(GL_RED_BITS, &rb); | ||||
glGetIntegerv(GL_GREEN_BITS, &gb); | ||||
glGetIntegerv(GL_BLUE_BITS, &bb); | ||||
glGetIntegerv(GL_ALPHA_BITS, &ab); | ||||
if((rb >= 8) && (gb >= 8) && (bb >= 8)) | ||||
strict = true; | ||||
bits15 = (rb == 5) && (gb == 5) && (bb == 5); | ||||
if((rb < 4) && (gb < 4) && (bb < 4)){ | ||||
PRINTFB(G, FB_Scene, FB_Errors) "SceneReadTriplet: ERROR: not enough color | ||||
s to pick: rb=%d gb=%d bb=%d\n", rb, gb, bb ENDFB(G); | ||||
return 0; | ||||
} | ||||
/* create some safe RAM on either side of the read buffer -- buggy | ||||
ReadPixels implementations tend to trash RAM surrounding the | ||||
target block */ | ||||
extra_safe_buffer = Alloc(pix, w * h * 11); | ||||
buffer = extra_safe_buffer + (w * h * 5); | ||||
result = VLAlloc(unsigned int, w * h); | ||||
glReadBuffer(gl_buffer); | ||||
PyMOLReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0][0]); | ||||
/* first, check to make sure bkrd_alpha is correct | ||||
(this is a bug for systems with broken alpha, such as Extreme 3D on Solar | ||||
is 8 */ | ||||
for(a = 0; ab && a < w; a++) | ||||
for(b = 0; b < h; b++) { | ||||
c = &buffer[a + b * w][0]; | ||||
if(c[3] == bkrd_alpha) { | ||||
check_alpha = true; | ||||
} | ||||
} | ||||
/* now read pixels */ | ||||
for(a = 0; a < w; a++) | ||||
for(b = 0; b < h; b++) { | ||||
c = &buffer[a + b * w][0]; | ||||
if((((c[3] == bkrd_alpha) || (!check_alpha))) && | ||||
((bits15 || (c[1] & 0x8)) && | ||||
((!strict) || | ||||
(((c[1] & 0xF) == 8) && ((c[0] & 0xF) == 0) && ((c[2] & 0xF) == 0) | ||||
)))) { /* only consider intact, saturated pixels */ | ||||
VLACheck(result, unsigned int, cc + 1); | ||||
if (bits15){ /* workaround for 15 bit rendering, for some reason red/g | ||||
reen need rounding */ | ||||
c[0] += 0x8; | ||||
c[2] += 0x8; | ||||
} | ||||
result[cc] = ((c[0] >> 4) & 0xF) + (c[1] & 0xF0) + ((c[2] << 4) & 0xF0 | ||||
0); | ||||
result[cc + 1] = b + a * h; | ||||
/*printf("%2x %2x %2x %d\n",c[0],c[1],c[2],result[cc]); */ | ||||
cc += 2; | ||||
} | ||||
} | ||||
FreeP(extra_safe_buffer); | ||||
VLASize(result, unsigned int, cc); | ||||
} | ||||
return (result); | ||||
} | ||||
/*========================================================================*/ | ||||
static int SceneRelease(Block * block, int button, int x, int y, int mod, double when) | static int SceneRelease(Block * block, int button, int x, int y, int mod, double when) | |||
{ | { | |||
PyMOLGlobals *G = block->G; | PyMOLGlobals *G = block->G; | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
int release_handled = false; | int release_handled = false; | |||
if(I->ButtonsShown && I->PressMode) { | if(I->ButtonsShown && I->PressMode) { | |||
if(I->ScrollBarActive) { | if(I->ScrollBarActive) { | |||
if((x - I->Block->rect.left) < (SceneScrollBarWidth + SceneScrollBarMargin )) { | if((x - I->Block->rect.left) < (SceneScrollBarWidth + SceneScrollBarMargin )) { | |||
ScrollBarDoRelease(I->ScrollBar, button, x, y, mod); | ScrollBarDoRelease(I->ScrollBar, button, x, y, mod); | |||
release_handled = true; | release_handled = true; | |||
skipping to change at line 3717 | skipping to change at line 3285 | |||
OrthoLineType buffer; | OrthoLineType buffer; | |||
sprintf(buffer, "cmd.scene('''%s''')", elem->name); | sprintf(buffer, "cmd.scene('''%s''')", elem->name); | |||
PParse(G, buffer); | PParse(G, buffer); | |||
PFlush(G); | PFlush(G); | |||
PLog(G, buffer, cPLog_pym); | PLog(G, buffer, cPLog_pym); | |||
} | } | |||
} | } | |||
break; | break; | |||
case 3: | case 3: | |||
if(I->Pressed == I->Over) { | if(I->Pressed == I->Over) { | |||
MenuActivate1Arg(G, I->LastWinX, I->LastWinY + 20, /* scene | Block *block = MenuActivate1Arg(G, I->LastWinX, I->LastWinY + 20, | |||
menu */ | /* scene menu */ | |||
I->LastWinX, I->LastWinY, true, "scene_menu", ele | I->LastWinX, I->LastWinY, true, "sc | |||
m->name); | ene_menu", elem->name); | |||
if (block) | ||||
PopUpDrag(block, x, y, mod); | ||||
ungrab = false; | ungrab = false; | |||
} | } | |||
break; | break; | |||
} | } | |||
} | } | |||
} | } | |||
I->LastPickVertexFlag = false; | I->LastPickVertexFlag = false; | |||
I->Pressed = -1; | I->Pressed = -1; | |||
I->Over = -1; | I->Over = -1; | |||
I->PressMode = 0; | I->PressMode = 0; | |||
skipping to change at line 3892 | skipping to change at line 3462 | |||
if((adjust_flag) && SettingGetGlobal_b(G, cSetting_roving_detail)) { | if((adjust_flag) && SettingGetGlobal_b(G, cSetting_roving_detail)) { | |||
SceneRovingPostpone(G); | SceneRovingPostpone(G); | |||
} | } | |||
if(SettingGetGlobal_b(G, cSetting_roving_detail)) { | if(SettingGetGlobal_b(G, cSetting_roving_detail)) { | |||
SceneRovingDirty(G); | SceneRovingDirty(G); | |||
} | } | |||
} | } | |||
#define cDoubleTime 0.35 | #define cDoubleTime 0.35 | |||
static int SceneDoXYPick(PyMOLGlobals * G, int x, int y, int click_side) | ||||
{ | ||||
CScene *I = G->Scene; | ||||
int defer_builds_mode = SettingGetGlobal_i(G, cSetting_defer_builds_mode); | ||||
if(defer_builds_mode == 5) /* force generation of a pickable version */ | ||||
SceneUpdate(G, true); | ||||
CShaderPrg_SetIsPicking(G, true); | ||||
if(OrthoGetOverlayStatus(G) || SettingGetGlobal_i(G, cSetting_text)) | ||||
SceneRender(G, NULL, 0, 0, NULL, 0, 0, 0, 0, 0); /* remove overlay if | ||||
present */ | ||||
SceneDontCopyNext(G); | ||||
I->LastPicked.context.object = NULL; | ||||
SceneRender(G, &I->LastPicked, x, y, NULL, 0, 0, click_side, 0, 0); | ||||
CShaderPrg_SetIsPicking(G, false); | ||||
return (I->LastPicked.context.object != NULL); | ||||
/* did we pick something? */ | ||||
} | ||||
static void SceneNoteMouseInteraction(PyMOLGlobals * G) | static void SceneNoteMouseInteraction(PyMOLGlobals * G) | |||
{ | { | |||
SceneAbortAnimation(G); | SceneAbortAnimation(G); | |||
if(SettingGet_b(G, NULL, NULL, cSetting_mouse_restart_movie_delay)) { | if(SettingGet_b(G, NULL, NULL, cSetting_mouse_restart_movie_delay)) { | |||
SceneRestartFrameTimer(G); | SceneRestartFrameTimer(G); | |||
} | } | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
static int SceneClick(Block * block, int button, int x, int y, int mod, double w hen) | static int SceneClick(Block * block, int button, int x, int y, int mod, double w hen) | |||
skipping to change at line 4286 | skipping to change at line 3837 | |||
PLog(G, buf2, cPLog_pym); | PLog(G, buf2, cPLog_pym); | |||
} | } | |||
OrthoRestorePrompt(G); | OrthoRestorePrompt(G); | |||
sprintf(buffer, "%s`%d", obj->Name, I->LastPicked.src.index + 1); | sprintf(buffer, "%s`%d", obj->Name, I->LastPicked.src.index + 1); | |||
EditorInactivate(G); | EditorInactivate(G); | |||
SelectorCreate(G, cEditorSele1, buffer, NULL, true, NULL); | SelectorCreate(G, cEditorSele1, buffer, NULL, true, NULL); | |||
EditorActivate(G, SettingGetGlobal_i(G, cSetting_state) - 1, false ); | EditorActivate(G, SettingGetGlobal_i(G, cSetting_state) - 1, false ); | |||
if(EditorActive(G)) { | if(EditorActive(G)) { | |||
EditorDefineExtraPks(G); | EditorDefineExtraPks(G); | |||
} | } | |||
WizardDoPick(G, 0); | WizardDoPick(G, 0, I->LastPicked.context.state); | |||
} | } | |||
break; | break; | |||
case cButModePickAtom: | case cButModePickAtom: | |||
if(obj && obj->type == cObjectMolecule) { | if(obj && obj->type == cObjectMolecule) { | |||
WordType name; | WordType name; | |||
if(obj->fDescribeElement) | if(obj->fDescribeElement) | |||
obj->fDescribeElement(obj, I->LastPicked.src.index, buffer); | obj->fDescribeElement(obj, I->LastPicked.src.index, buffer); | |||
if(EditorIsBondMode(G) | if(EditorIsBondMode(G) | |||
/* &&!(EditorIsAnActiveObject(G,(ObjectMolecule*)obj)) */ | /* &&!(EditorIsAnActiveObject(G,(ObjectMolecule*)obj)) */ | |||
) { | ) { | |||
skipping to change at line 4329 | skipping to change at line 3880 | |||
/* TODO: logging */ | /* TODO: logging */ | |||
sprintf(buffer, "%s`%d", obj->Name, I->LastPicked.src.index + 1) ; | sprintf(buffer, "%s`%d", obj->Name, I->LastPicked.src.index + 1) ; | |||
ExecutiveDelete(G, name); | ExecutiveDelete(G, name); | |||
SelectorCreate(G, name, buffer, NULL, true, NULL); | SelectorCreate(G, name, buffer, NULL, true, NULL); | |||
EditorActivate(G, SettingGetGlobal_i(G, cSetting_state) - 1, fal se); | EditorActivate(G, SettingGetGlobal_i(G, cSetting_state) - 1, fal se); | |||
if(EditorActive(G)) { | if(EditorActive(G)) { | |||
EditorDefineExtraPks(G); | EditorDefineExtraPks(G); | |||
} | } | |||
EditorLogState(G, false); | EditorLogState(G, false); | |||
WizardDoPick(G, 0); | WizardDoPick(G, 0, I->LastPicked.context.state); | |||
} | } | |||
} | } | |||
break; | break; | |||
} | } | |||
break; | break; | |||
case cObjectGadget: | case cObjectGadget: | |||
break; | break; | |||
default: | default: | |||
EditorInactivate(G); | EditorInactivate(G); | |||
break; | break; | |||
skipping to change at line 4430 | skipping to change at line 3981 | |||
case cObjectMolecule: | case cObjectMolecule: | |||
objMol = (ObjectMolecule *) obj; | objMol = (ObjectMolecule *) obj; | |||
EditorPrepareDrag(G, obj, -1, I->LastPicked.src.index, | EditorPrepareDrag(G, obj, -1, I->LastPicked.src.index, | |||
SettingGetGlobal_i(G, cSetting_state) - 1, mod e); | SettingGetGlobal_i(G, cSetting_state) - 1, mod e); | |||
I->SculptingFlag = 1; | I->SculptingFlag = 1; | |||
I->SculptingSave = objMol->AtomInfo[I->LastPicked.src.index].pro tekted; | I->SculptingSave = objMol->AtomInfo[I->LastPicked.src.index].pro tekted; | |||
objMol->AtomInfo[I->LastPicked.src.index].protekted = 2; | objMol->AtomInfo[I->LastPicked.src.index].protekted = 2; | |||
break; | break; | |||
} | } | |||
} | } | |||
WizardDoPick(G, 1); | WizardDoPick(G, 1, I->LastPicked.context.state); | |||
} else { | } else { | |||
WizardDoPick(G, 0); | WizardDoPick(G, 0, I->LastPicked.context.state); | |||
} | } | |||
if(SettingGetGlobal_b(G, cSetting_auto_hide_selections)) | if(SettingGetGlobal_b(G, cSetting_auto_hide_selections)) | |||
ExecutiveHideSelections(G); | ExecutiveHideSelections(G); | |||
break; | break; | |||
case cObjectGadget: | case cObjectGadget: | |||
break; | break; | |||
default: | default: | |||
EditorInactivate(G); | EditorInactivate(G); | |||
break; | break; | |||
} | } | |||
skipping to change at line 4672 | skipping to change at line 4223 | |||
} | } | |||
break; | break; | |||
} | } | |||
switch (mode) { | switch (mode) { | |||
case cButModeSimpleClick: | case cButModeSimpleClick: | |||
{ | { | |||
float pos_store[3], *pos = pos_store; | float pos_store[3], *pos = pos_store; | |||
int index = I->LastPicked.src.index; /* 1-based */ | int index = I->LastPicked.src.index; /* 1-based */ | |||
int state = ObjectGetCurrentState(obj, true); | int state = ObjectGetCurrentState(obj, true); | |||
if(!( (obj->type == cObjectMolecule) && | if(!( (obj->type == cObjectMolecule) && | |||
(I->LastPicked.src.index >= 0 ) && | (I->LastPicked.src.bond != cPickableNoPick ) && | |||
ObjectMoleculeGetAtomTxfVertex((ObjectMolecule *)obj,-1,index , pos))) | ObjectMoleculeGetAtomTxfVertex((ObjectMolecule *)obj,-1,index , pos))) | |||
pos = NULL; | pos = NULL; | |||
PyMOL_SetClickReady(G->PyMOL, obj->Name, I->LastPicked.src.index, | PyMOL_SetClickReady(G->PyMOL, obj->Name, I->LastPicked.src.index, | |||
button, mod, I->LastWinX, I->Height - (I->LastW inY + 1), | button, mod, I->LastWinX, I->Height - (I->LastW inY + 1), | |||
pos, state + 1); /* send a 1-based state index */ | pos, state + 1); /* send a 1-based state index */ | |||
} | } | |||
break; | break; | |||
case cButModeLB: | case cButModeLB: | |||
case cButModeMB: | case cButModeMB: | |||
case cButModeRB: | case cButModeRB: | |||
skipping to change at line 4700 | skipping to change at line 4251 | |||
if(obj->type == cObjectMolecule) { | if(obj->type == cObjectMolecule) { | |||
if(SettingGetGlobal_i(G, cSetting_logging)) { | if(SettingGetGlobal_i(G, cSetting_logging)) { | |||
objMol = (ObjectMolecule *) obj; | objMol = (ObjectMolecule *) obj; | |||
ObjectMoleculeGetAtomSeleLog(objMol, I->LastPicked.src.index, bu f1, | ObjectMoleculeGetAtomSeleLog(objMol, I->LastPicked.src.index, bu f1, | |||
false); | false); | |||
sprintf(buffer, "cmd.select('%s',\"%s(%s)\",enable=1)", selName, | sprintf(buffer, "cmd.select('%s',\"%s(%s)\",enable=1)", selName, | |||
sel_mode_kw, buf1); | sel_mode_kw, buf1); | |||
PLog(G, buffer, cPLog_pym); | PLog(G, buffer, cPLog_pym); | |||
} | } | |||
} | } | |||
WizardDoSelect(G, selName); | WizardDoSelect(G, selName, I->LastPicked.context.state); | |||
break; | break; | |||
case cButModeAddToLB: | case cButModeAddToLB: | |||
case cButModeAddToMB: | case cButModeAddToMB: | |||
case cButModeAddToRB: | case cButModeAddToRB: | |||
case cButModeSeleToggle: | case cButModeSeleToggle: | |||
if(SelectorIndexByName(G, selName) >= 0) { | if(SelectorIndexByName(G, selName) >= 0) { | |||
sprintf(buf2, "(((%s) or %s(%s)) and not ((%s(%s)) and %s(%s)))", | sprintf(buf2, "(((%s) or %s(%s)) and not ((%s(%s)) and %s(%s)))", | |||
selName, sel_mode_kw, buffer, sel_mode_kw, buffer, sel_mod e_kw, | selName, sel_mode_kw, buffer, sel_mode_kw, buffer, sel_mod e_kw, | |||
selName); | selName); | |||
SelectorCreate(G, selName, buf2, NULL, false, NULL); | SelectorCreate(G, selName, buf2, NULL, false, NULL); | |||
skipping to change at line 4742 | skipping to change at line 4293 | |||
sprintf(buffer, "cmd.select('%s',\"%s(%s)\")", selName, sel_mo de_kw, | sprintf(buffer, "cmd.select('%s',\"%s(%s)\")", selName, sel_mo de_kw, | |||
buf1); | buf1); | |||
PLog(G, buffer, cPLog_pym); | PLog(G, buffer, cPLog_pym); | |||
} | } | |||
} | } | |||
} | } | |||
if(SettingGetGlobal_b(G, cSetting_auto_hide_selections)) | if(SettingGetGlobal_b(G, cSetting_auto_hide_selections)) | |||
ExecutiveHideSelections(G); | ExecutiveHideSelections(G); | |||
if(SettingGetGlobal_b(G, cSetting_auto_show_selections)) | if(SettingGetGlobal_b(G, cSetting_auto_show_selections)) | |||
ExecutiveSetObjVisib(G, selName, 1, false); | ExecutiveSetObjVisib(G, selName, 1, false); | |||
WizardDoSelect(G, selName); | WizardDoSelect(G, selName, I->LastPicked.context.state); | |||
break; | break; | |||
} | } | |||
case cObjectGadget: | case cObjectGadget: | |||
break; | break; | |||
default: | default: | |||
EditorInactivate(G); | EditorInactivate(G); | |||
break; | break; | |||
} | } | |||
} else { | } else { | |||
switch (mode) { | switch (mode) { | |||
skipping to change at line 4802 | skipping to change at line 4353 | |||
OrthoRestorePrompt(G); | OrthoRestorePrompt(G); | |||
} | } | |||
} | } | |||
I->StartX = I->LastX; | I->StartX = I->LastX; | |||
I->StartY = I->LastY; | I->StartY = I->LastY; | |||
} | } | |||
return (1); | return (1); | |||
} | } | |||
void ScenePushRasterMatrix(PyMOLGlobals * G, float *v) | float ScenePushRasterMatrix(PyMOLGlobals * G, float *v) | |||
{ | { | |||
float scale = SceneGetExactScreenVertexScale(G, v); | float scale = SceneGetExactScreenVertexScale(G, v); | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
glMatrixMode(GL_MODELVIEW); | glMatrixMode(GL_MODELVIEW); | |||
glPushMatrix(); | glPushMatrix(); | |||
glTranslatef(v[0], v[1], v[2]); /* go to this position */ | glTranslatef(v[0], v[1], v[2]); /* go to this position */ | |||
glMultMatrixf(I->InvMatrix); | glMultMatrixf(I->InvMatrix); | |||
glScalef(scale, scale, scale); | glScalef(scale, scale, scale); | |||
/* glTranslatef(-0.33F,-0.33F,0.0F); */ | return scale; | |||
} | } | |||
void ScenePopRasterMatrix(PyMOLGlobals * G) | void ScenePopRasterMatrix(PyMOLGlobals * G) | |||
{ | { | |||
glMatrixMode(GL_MODELVIEW); | glMatrixMode(GL_MODELVIEW); | |||
glPopMatrix(); | glPopMatrix(); | |||
} | } | |||
/* | /* | |||
* Compose the ModelViewMatrix from Pos, RotMatrix and Origin | * Compose the ModelViewMatrix from Pos, RotMatrix and Origin | |||
skipping to change at line 4851 | skipping to change at line 4401 | |||
copy3f(v1, p1); | copy3f(v1, p1); | |||
p1[3] = 1.0; | p1[3] = 1.0; | |||
MatrixTransformC44f4f(modelView, p1, p2); /* modelview transformation */ | MatrixTransformC44f4f(modelView, p1, p2); /* modelview transformation */ | |||
copy3f(p2, p1); | copy3f(p2, p1); | |||
normalize3f(p1); | normalize3f(p1); | |||
MatrixInvTransformC44fAs33f3f(I->RotMatrix, p1, p2); | MatrixInvTransformC44fAs33f3f(I->RotMatrix, p1, p2); | |||
invert3f3f(p2, normal); | invert3f3f(p2, normal); | |||
} | } | |||
/* | /* | |||
* Return true if the v1 is within the safe clipping planes | ||||
*/ | ||||
short SceneGetVisible(PyMOLGlobals * G, float *v1) | ||||
{ | ||||
CScene *I = G->Scene; | ||||
float depth = SceneGetRawDepth(G, v1); | ||||
return (I->BackSafe >= depth && depth >= I->FrontSafe); | ||||
} | ||||
/* | ||||
* Get the depth (camera space Z) of v1 | * Get the depth (camera space Z) of v1 | |||
* | * | |||
* v1: point (3f) in world space or NULL (= origin) | * v1: point (3f) in world space or NULL (= origin) | |||
*/ | */ | |||
float SceneGetRawDepth(PyMOLGlobals * G, float *v1) | float SceneGetRawDepth(PyMOLGlobals * G, float *v1) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
float vt[3]; | float vt[3]; | |||
float modelView[16]; | float modelView[16]; | |||
if(!v1 || SettingGetGlobal_i(G, cSetting_ortho)) | if(!v1 || SettingGetGlobal_i(G, cSetting_ortho)) | |||
return -I->Pos[2]; | return -I->Pos[2]; | |||
SceneComposeModelViewMatrix(I, modelView); | SceneComposeModelViewMatrix(I, modelView); | |||
MatrixTransformC44f3f(modelView, v1, vt); | MatrixTransformC44f3f(modelView, v1, vt); | |||
return -vt[2]; | return -vt[2]; | |||
} | } | |||
/* | ||||
* Get the depth (camera space Z) of v1 in normalized clip space | ||||
* from 0.0 (near) to 1.0 (far) | ||||
* | ||||
* v1: point (3f) in world space or NULL (= origin) | ||||
*/ | ||||
float SceneGetDepth(PyMOLGlobals * G, float *v1) | ||||
{ | ||||
CScene *I = G->Scene; | ||||
float rawDepth = SceneGetRawDepth(G, v1); | ||||
return ((rawDepth - I->FrontSafe)/(I->BackSafe-I->FrontSafe)); | ||||
} | ||||
/*========================================================================*/ | /*========================================================================*/ | |||
/* | /* | |||
* Get the angstrom per pixel factor at v1. If v1 is NULL, return the | * Get the angstrom per pixel factor at v1. If v1 is NULL, return the | |||
* factor at the origin, but clamped to an empirical positive value. | * factor at the origin, but clamped to an empirical positive value. | |||
* | * | |||
* v1: point (3f) in world space or NULL (= origin) | * v1: point (3f) in world space or NULL (= origin) | |||
*/ | */ | |||
float SceneGetScreenVertexScale(PyMOLGlobals * G, float *v1) | float SceneGetScreenVertexScale(PyMOLGlobals * G, float *v1) | |||
/* does not require OpenGL-provided matrices */ | /* does not require OpenGL-provided matrices */ | |||
skipping to change at line 5239 | skipping to change at line 4812 | |||
float scale, vScale; | float scale, vScale; | |||
float v1[3], v2[3], n1[3], n2[3], r1, r2, cp[3], v3[3]; | float v1[3], v2[3], n1[3], n2[3], r1, r2, cp[3], v3[3]; | |||
float dx, dy, dt; | float dx, dy, dt; | |||
float axis[3], axis2[3], theta, omega; | float axis[3], axis2[3], theta, omega; | |||
float old_front, old_back, old_origin; | float old_front, old_back, old_origin; | |||
int mode; | int mode; | |||
int eff_width; | int eff_width; | |||
int moved_flag; | int moved_flag; | |||
int adjust_flag; | int adjust_flag; | |||
int drag_handled = false; | int drag_handled = false; | |||
int virtual_trackball; | ||||
CObject *obj; | CObject *obj; | |||
if(I->PossibleSingleClick) { | if(I->PossibleSingleClick) { | |||
double slowest_single_click_drag = 0.15; | double slowest_single_click_drag = 0.15; | |||
if((when - I->LastClickTime) > slowest_single_click_drag) { | if((when - I->LastClickTime) > slowest_single_click_drag) { | |||
I->PossibleSingleClick = 0; | I->PossibleSingleClick = 0; | |||
} | } | |||
} | } | |||
if(I->LoopFlag) { | if(I->LoopFlag) { | |||
skipping to change at line 5376 | skipping to change at line 4950 | |||
case 0: | case 0: | |||
v2[0] = (x - I->LastX) * vScale; | v2[0] = (x - I->LastX) * vScale; | |||
v2[1] = (y - I->LastY) * vScale; | v2[1] = (y - I->LastY) * vScale; | |||
v2[2] = 0; | v2[2] = 0; | |||
MatrixInvTransformC44fAs33f3f(I->RotMatrix, v2, v2); | MatrixInvTransformC44fAs33f3f(I->RotMatrix, v2, v2); | |||
break; | break; | |||
} | } | |||
add3f(v1, v2, v2); | add3f(v1, v2, v2); | |||
ObjectGadgetSetVertex(gad, I->LastPicked.src.index, I->LastPicked.sr c.bond, | ObjectGadgetSetVertex(gad, I->LastPicked.src.index, I->LastPicked.sr c.bond, | |||
v2); | v2); | |||
SceneChanged(G); | if (I->LastPicked.src.index){ // pick id on gadget is 1 for band (to | |||
change values), | ||||
// 0 for everything else (to move it a | ||||
round) | ||||
SceneChanged(G); // changing values, need to update gadget text | ||||
} else { | ||||
PyMOL_NeedRedisplay(G->PyMOL); // moving gadget, just re-draw | ||||
} | ||||
} | } | |||
break; | break; | |||
} | } | |||
I->LastX = x; | I->LastX = x; | |||
I->LastY = y; | I->LastY = y; | |||
break; | break; | |||
case cButModeRotDrag: | case cButModeRotDrag: | |||
eff_width = I->Width; | eff_width = I->Width; | |||
if(stereo_via_adjacent_array(I->StereoMode)) { | if(stereo_via_adjacent_array(I->StereoMode)) { | |||
eff_width = I->Width / 2; | eff_width = I->Width / 2; | |||
x = get_stereo_x(x, &I->LastX, I->Width, NULL); | x = get_stereo_x(x, &I->LastX, I->Width, NULL); | |||
} | } | |||
if(SettingGet_b(G, NULL, NULL, cSetting_virtual_trackball)) { | virtual_trackball = SettingGet_i(G, NULL, NULL, cSetting_virtual_trackball | |||
); | ||||
if (virtual_trackball==2 && | ||||
(!I->prev_no_z_rotation1 || !I->prev_no_z_rotation2)) { | ||||
/* when virtual_trackball=2 and twisting, need to set v1,v2 relative to o | ||||
rig */ | ||||
v2[0] = (float) (eff_width / 2) - I->orig_x_rotation; | ||||
v2[1] = (float) (I->Height / 2) - I->orig_y_rotation; | ||||
v1[0] = v2[0] - (float) (x - I->LastX); | ||||
v1[1] = v2[1] - (float) (y - I->LastY); | ||||
} else if(virtual_trackball==1){ | ||||
v1[0] = (float) (eff_width / 2) - x; | v1[0] = (float) (eff_width / 2) - x; | |||
v1[1] = (float) (I->Height / 2) - y; | v1[1] = (float) (I->Height / 2) - y; | |||
v2[0] = (float) (eff_width / 2) - I->LastX; | v2[0] = (float) (eff_width / 2) - I->LastX; | |||
v2[1] = (float) (I->Height / 2) - I->LastY; | v2[1] = (float) (I->Height / 2) - I->LastY; | |||
} else { | } else { | |||
v1[0] = (float) (I->LastX) - x; | v1[0] = (float) (I->LastX) - x; | |||
v1[1] = (float) (I->LastY) - y; | v1[1] = (float) (I->LastY) - y; | |||
v2[0] = 0; | v2[0] = 0; | |||
v2[1] = 0; | v2[1] = 0; | |||
} | } | |||
r1 = (float) sqrt1f(v1[0] * v1[0] + v1[1] * v1[1]); | r1 = (float) sqrt1f(v1[0] * v1[0] + v1[1] * v1[1]); | |||
r2 = (float) sqrt1f(v2[0] * v2[0] + v2[1] * v2[1]); | r2 = (float) sqrt1f(v2[0] * v2[0] + v2[1] * v2[1]); | |||
if(r1 < scale) { | { | |||
v1[2] = (float) sqrt1f(scale * scale - r1 * r1); | short r1lt, r2lt; | |||
} else { | if(virtual_trackball==2) { | |||
v1[2] = 0.0; | r1lt = I->prev_no_z_rotation1; | |||
} | r2lt = I->prev_no_z_rotation2; | |||
} else { | ||||
if(r2 < scale) { | r1lt = r1 < scale; | |||
v2[2] = (float) sqrt1f(scale * scale - r2 * r2); | r2lt = r2 < scale; | |||
} else { | I->prev_no_z_rotation1 = r1 < scale; | |||
v2[2] = 0.0; | I->prev_no_z_rotation2 = r2 < scale; | |||
I->orig_x_rotation = x; | ||||
I->orig_y_rotation = y; | ||||
} | ||||
if(r1lt) { | ||||
v1[2] = (float) sqrt1f(scale * scale - r1 * r1); | ||||
} else { | ||||
v1[2] = 0.0; | ||||
} | ||||
if(r2lt) { | ||||
v2[2] = (float) sqrt1f(scale * scale - r2 * r2); | ||||
} else { | ||||
v2[2] = 0.0; | ||||
} | ||||
} | } | |||
normalize23f(v1, n1); | normalize23f(v1, n1); | |||
normalize23f(v2, n2); | normalize23f(v2, n2); | |||
cross_product3f(n1, n2, cp); | cross_product3f(n1, n2, cp); | |||
theta = (float) (SettingGet_f(G, NULL, NULL, cSetting_mouse_scale) * | theta = (float) (SettingGet_f(G, NULL, NULL, cSetting_mouse_scale) * | |||
2 * 180 * | 2 * 180 * | |||
asin(sqrt1f(cp[0] * cp[0] + cp[1] * cp[1] + cp[2] * cp[2] )) / cPI); | asin(sqrt1f(cp[0] * cp[0] + cp[1] * cp[1] + cp[2] * cp[2] )) / cPI); | |||
dx = (v1[0] - v2[0]); | dx = (v1[0] - v2[0]); | |||
dy = (v1[1] - v2[1]); | dy = (v1[1] - v2[1]); | |||
dt = | dt = | |||
skipping to change at line 5548 | skipping to change at line 5151 | |||
case 0: | case 0: | |||
v2[0] = (x - I->LastX) * vScale; | v2[0] = (x - I->LastX) * vScale; | |||
v2[1] = (y - I->LastY) * vScale; | v2[1] = (y - I->LastY) * vScale; | |||
v2[2] = 0; | v2[2] = 0; | |||
MatrixInvTransformC44fAs33f3f(I->RotMatrix, v2, v2); | MatrixInvTransformC44fAs33f3f(I->RotMatrix, v2, v2); | |||
break; | break; | |||
} | } | |||
add3f(v1, v2, v2); | add3f(v1, v2, v2); | |||
ObjectGadgetSetVertex(gad, I->LastPicked.src.index, I->LastPicked. src.bond, | ObjectGadgetSetVertex(gad, I->LastPicked.src.index, I->LastPicked. src.bond, | |||
v2); | v2); | |||
SceneChanged(G); | if (I->LastPicked.src.index){ // pick id on gadget is 1 for band ( | |||
to change values), | ||||
// 0 for everything else (to move it | ||||
around) | ||||
SceneChanged(G); // changing values, need to update gadget tex | ||||
t | ||||
} else { | ||||
PyMOL_NeedRedisplay(G->PyMOL); // moving gadget, just re-draw | ||||
} | ||||
} | } | |||
break; | break; | |||
case cObjectMolecule: | case cObjectMolecule: | |||
if(ObjectMoleculeGetAtomTxfVertex((ObjectMolecule *) obj, | if(ObjectMoleculeGetAtomTxfVertex((ObjectMolecule *) obj, | |||
I->LastPicked.context.state, | I->LastPicked.context.state, | |||
I->LastPicked.src.index, v1)) { | I->LastPicked.src.index, v1)) { | |||
/* scale properly given the current projection matrix */ | /* scale properly given the current projection matrix */ | |||
vScale = SceneGetExactScreenVertexScale(G, v1); | vScale = SceneGetExactScreenVertexScale(G, v1); | |||
if(stereo_via_adjacent_array(I->StereoMode)) { | if(stereo_via_adjacent_array(I->StereoMode)) { | |||
skipping to change at line 5603 | skipping to change at line 5211 | |||
case cButModeMovView: | case cButModeMovView: | |||
if(SettingGetGlobal_i(G,cSetting_movie_auto_store) && | if(SettingGetGlobal_i(G,cSetting_movie_auto_store) && | |||
SettingGetGlobal_i(G,cSetting_movie_auto_interpolate)) { | SettingGetGlobal_i(G,cSetting_movie_auto_interpolate)) { | |||
I->ReinterpolateFlag = true; | I->ReinterpolateFlag = true; | |||
I->ReinterpolateObj = obj; | I->ReinterpolateObj = obj; | |||
} | } | |||
break; | break; | |||
} | } | |||
} else { | } else { | |||
int log_trans = SettingGetGlobal_b(G, cSetting_log_conformatio ns); | int log_trans = SettingGetGlobal_b(G, cSetting_log_conformatio ns); | |||
ObjectMoleculeMoveAtom((ObjectMolecule *) obj, | ObjectMolecule *objOM = (ObjectMolecule *) obj; | |||
ObjectMoleculeMoveAtom(objOM, | ||||
I->LastPicked.context.state, | I->LastPicked.context.state, | |||
I->LastPicked.src.index, v2, 1, log_tra ns); | I->LastPicked.src.index, v2, 1, log_tra ns); | |||
/* -- JV - if this object knows about distances, then move them if necessary */ | /* -- JV - if this object knows about distances, then move them if necessary */ | |||
/* check the dynamic_measures setting and make sure the object has a distance measure, first */ | /* check the dynamic_measures setting and make sure the object has a distance measure, first */ | |||
/* obviated by new method | /* obviated by new method | |||
if (SettingGetGlobal_i(G, cSetting_dynamic_measures)) | if (SettingGetGlobal_i(G, cSetting_dynamic_measures)) | |||
ObjectMoleculeMoveDist( (ObjectMolecule *) obj, SettingGetGlo bal_i(G, cSetting_state)-1, I->LastPicked.src.index, v2, 1, log_trans); | ObjectMoleculeMoveDist( (ObjectMolecule *) obj, SettingGetGlo bal_i(G, cSetting_state)-1, I->LastPicked.src.index, v2, 1, log_trans); | |||
*/ | */ | |||
SceneInvalidate(G); | SceneInvalidate(G); | |||
} | } | |||
} else { | } else { | |||
int log_trans = SettingGetGlobal_b(G, cSetting_log_conformations ); | int log_trans = SettingGetGlobal_b(G, cSetting_log_conformations ); | |||
ObjectMoleculeMoveAtomLabel((ObjectMolecule *) obj, | ObjectMolecule *objOM = (ObjectMolecule *) obj; | |||
float diffInPixels[2]; | ||||
diffInPixels[0] = (x - I->LastX); | ||||
diffInPixels[1] = (y - I->LastY); | ||||
ObjectMoleculeMoveAtomLabel(objOM, | ||||
I->LastPicked.context.state, | I->LastPicked.context.state, | |||
I->LastPicked.src.index, v2, 1, log_ trans); | I->LastPicked.src.index, v2, log_tra ns, diffInPixels); | |||
SceneInvalidate(G); | SceneInvalidate(G); | |||
} | } | |||
} | } | |||
break; | break; | |||
case cObjectSlice: | case cObjectSlice: | |||
{ | { | |||
ObjectSlice *slice = (ObjectSlice *) obj; | ObjectSlice *slice = (ObjectSlice *) obj; | |||
if(I->LastPickVertexFlag) { | if(I->LastPickVertexFlag) { | |||
skipping to change at line 5752 | skipping to change at line 5365 | |||
case cButModeInvRotZ: | case cButModeInvRotZ: | |||
case cButModeTransZ: | case cButModeTransZ: | |||
case cButModeClipNF: | case cButModeClipNF: | |||
case cButModeClipN: | case cButModeClipN: | |||
case cButModeClipF: | case cButModeClipF: | |||
case cButModeRotL: | case cButModeRotL: | |||
case cButModeMovL: | case cButModeMovL: | |||
case cButModeMvzL: | case cButModeMvzL: | |||
SceneNoteMouseInteraction(G); | SceneNoteMouseInteraction(G); | |||
virtual_trackball = SettingGet_i(G, NULL, NULL, cSetting_virtual_trackball ); | ||||
eff_width = I->Width; | eff_width = I->Width; | |||
if(stereo_via_adjacent_array(I->StereoMode)) { | if(stereo_via_adjacent_array(I->StereoMode)) { | |||
eff_width = I->Width / 2; | eff_width = I->Width / 2; | |||
x = get_stereo_x(x, &I->LastX, I->Width, NULL); | x = get_stereo_x(x, &I->LastX, I->Width, NULL); | |||
} | } | |||
if (virtual_trackball==2 && | ||||
(!I->prev_no_z_rotation1 || !I->prev_no_z_rotation2)) { | ||||
/* when virtual_trackball=2 and twisting, need to set v1,v2 relative to o | ||||
rig */ | ||||
v2[0] = (float) (eff_width / 2) - I->orig_x_rotation; | ||||
v2[1] = (float) (I->Height / 2) - I->orig_y_rotation; | ||||
v1[0] = v2[0] - (float) (x - I->LastX); | ||||
v1[1] = v2[1] - (float) (y - I->LastY); | ||||
if(SettingGet_b(G, NULL, NULL, cSetting_virtual_trackball)) { | } else if(virtual_trackball==1){ | |||
v1[0] = (float) (eff_width / 2) - x; | v1[0] = (float) (eff_width / 2) - x; | |||
v1[1] = (float) (I->Height / 2) - y; | v1[1] = (float) (I->Height / 2) - y; | |||
v2[0] = (float) (eff_width / 2) - I->LastX; | v2[0] = (float) (eff_width / 2) - I->LastX; | |||
v2[1] = (float) (I->Height / 2) - I->LastY; | v2[1] = (float) (I->Height / 2) - I->LastY; | |||
} else { | } else { | |||
v1[0] = (float) (I->LastX) - x; | v1[0] = (float) (I->LastX) - x; | |||
v1[1] = (float) (I->LastY) - y; | v1[1] = (float) (I->LastY) - y; | |||
v2[0] = 0; | v2[0] = 0; | |||
v2[1] = 0; | v2[1] = 0; | |||
} | } | |||
r1 = (float) sqrt1f(v1[0] * v1[0] + v1[1] * v1[1]); | r1 = (float) sqrt1f(v1[0] * v1[0] + v1[1] * v1[1]); | |||
r2 = (float) sqrt1f(v2[0] * v2[0] + v2[1] * v2[1]); | r2 = (float) sqrt1f(v2[0] * v2[0] + v2[1] * v2[1]); | |||
if(r1 < scale) { | { | |||
v1[2] = (float) sqrt1f(scale * scale - r1 * r1); | short r1lt, r2lt; | |||
} else { | if(SettingGet_i(G, NULL, NULL, cSetting_virtual_trackball)==2) { | |||
v1[2] = 0.0; | r1lt = I->prev_no_z_rotation1; | |||
} | r2lt = I->prev_no_z_rotation2; | |||
} else { | ||||
if(r2 < scale) { | r1lt = r1 < scale; | |||
v2[2] = (float) sqrt1f(scale * scale - r2 * r2); | r2lt = r2 < scale; | |||
} else { | I->prev_no_z_rotation1 = r1 < scale; | |||
v2[2] = 0.0; | I->prev_no_z_rotation2 = r2 < scale; | |||
I->orig_x_rotation = x; | ||||
I->orig_y_rotation = y; | ||||
} | ||||
if(r1lt) { | ||||
float val = scale * scale - r1 * r1; | ||||
short isNeg = val < 0.f; | ||||
v1[2] = (float) sqrt(fabs(val)) * (isNeg ? -1.f : 1.f); | ||||
} else { | ||||
v1[2] = 0.0; | ||||
} | ||||
if(r2lt) { | ||||
float val = scale * scale - r2 * r2; | ||||
short isNeg = val < 0.f; | ||||
v2[2] = (float) sqrt(fabs(val)) * (isNeg ? -1.f : 1.f); | ||||
} else { | ||||
v2[2] = 0.0; | ||||
} | ||||
} | } | |||
normalize23f(v1, n1); | normalize23f(v1, n1); | |||
normalize23f(v2, n2); | normalize23f(v2, n2); | |||
cross_product3f(n1, n2, cp); | cross_product3f(n1, n2, cp); | |||
theta = (float) (SettingGet_f(G, NULL, NULL, cSetting_mouse_scale) * | theta = (float) (SettingGet_f(G, NULL, NULL, cSetting_mouse_scale) * | |||
2 * 180 * | 2 * 180 * | |||
asin(sqrt1f(cp[0] * cp[0] + cp[1] * cp[1] + cp[2] * cp[2] )) / cPI); | asin(sqrt1f(cp[0] * cp[0] + cp[1] * cp[1] + cp[2] * cp[2] )) / cPI); | |||
dx = (v1[0] - v2[0]); | dx = (v1[0] - v2[0]); | |||
dy = (v1[1] - v2[1]); | dy = (v1[1] - v2[1]); | |||
skipping to change at line 5921 | skipping to change at line 5559 | |||
/* when light_count == 1, there is an ambient light; | /* when light_count == 1, there is an ambient light; | |||
* when light_count == 2, there are two lights, the ambient and | * when light_count == 2, there are two lights, the ambient and | |||
* a directional, called "light". When there are three, it's the | * a directional, called "light". When there are three, it's the | |||
* ambient, light and the third is light2, and so on. | * ambient, light and the third is light2, and so on. | |||
* | * | |||
* Should we use an off-by-one here to make this easier for the | * Should we use an off-by-one here to make this easier for the | |||
* user to understand? light1 is ambient, light2 is first directional | * user to understand? light1 is ambient, light2 is first directional | |||
* | * | |||
*/ | */ | |||
float pos[3]; | float pos[3]; | |||
int result, which_light; | int which_light; | |||
float ms = 0.01; | float ms = 0.01; | |||
switch(SettingGet_i(G, NULL, NULL, cSetting_edit_light)) { | which_light = light_setting_indices[glm::clamp( | |||
case 2: | SettingGetGlobal_i(G, cSetting_edit_light), 1, 9) - 1]; | |||
which_light = cSetting_light2; | ||||
break; | ||||
case 3: | ||||
which_light = cSetting_light3; | ||||
break; | ||||
case 4: | ||||
which_light = cSetting_light4; | ||||
break; | ||||
case 5: | ||||
which_light = cSetting_light5; | ||||
break; | ||||
case 6: | ||||
which_light = cSetting_light6; | ||||
break; | ||||
case 7: | ||||
which_light = cSetting_light7; | ||||
break; | ||||
case 8: | ||||
which_light = cSetting_light8; | ||||
break; | ||||
case 9: | ||||
which_light = cSetting_light9; | ||||
break; | ||||
case 0: | ||||
case 1: | ||||
default: | ||||
which_light = cSetting_light; | ||||
break; | ||||
} | ||||
copy3f(SettingGet<const float *>(G, which_light), pos); | copy3f(SettingGet<const float *>(G, which_light), pos); | |||
pos[0] += (float) dx * ms; | pos[0] += (float) dx * ms; | |||
pos[1] += (float) dy * ms; | pos[1] += (float) dy * ms; | |||
result = SettingSet_3fv(G->Setting, which_light, pos); | SettingSet_3fv(G->Setting, which_light, pos); | |||
SettingGenerateSideEffects(G, which_light, NULL, 0, 1); | ||||
I->LastX = x; | I->LastX = x; | |||
I->LastY = y; | I->LastY = y; | |||
} | } | |||
break; | break; | |||
case cButModeMvzL: | case cButModeMvzL: | |||
{ | { | |||
float pos[3]; | float pos[3]; | |||
int result, which_light; | int which_light; | |||
float ms = 0.01; | float ms = 0.01; | |||
float factor = 0.f; | float factor = 0.f; | |||
/* when light_count == 1, there is an ambient light; | /* when light_count == 1, there is an ambient light; | |||
* when light_count == 2, there are two lights, the ambient and | * when light_count == 2, there are two lights, the ambient and | |||
* a directional, called "light". When there are three, it's the | * a directional, called "light". When there are three, it's the | |||
* ambient, light and the third is light2, and so on. | * ambient, light and the third is light2, and so on. | |||
*/ | */ | |||
switch(SettingGet_i(G, NULL, NULL, cSetting_edit_light)) { | which_light = light_setting_indices[glm::clamp( | |||
case 2: | SettingGetGlobal_i(G, cSetting_edit_light), 1, 9) - 1]; | |||
which_light = cSetting_light2; | ||||
break; | ||||
case 3: | ||||
which_light = cSetting_light3; | ||||
break; | ||||
case 4: | ||||
which_light = cSetting_light4; | ||||
break; | ||||
case 5: | ||||
which_light = cSetting_light5; | ||||
break; | ||||
case 6: | ||||
which_light = cSetting_light6; | ||||
break; | ||||
case 7: | ||||
which_light = cSetting_light7; | ||||
break; | ||||
case 8: | ||||
which_light = cSetting_light8; | ||||
break; | ||||
case 9: | ||||
which_light = cSetting_light9; | ||||
break; | ||||
case 0: | ||||
case 1: | ||||
default: | ||||
which_light = cSetting_light; | ||||
break; | ||||
} | ||||
if(I->LastY != y) { | if(I->LastY != y) { | |||
factor = 400 / ((I->FrontSafe + I->BackSafe) / 2); | factor = 400 / ((I->FrontSafe + I->BackSafe) / 2); | |||
if(factor >= 0.0F) { | if(factor >= 0.0F) { | |||
factor = SettingGetGlobal_f(G, cSetting_mouse_z_scale) * | factor = SettingGetGlobal_f(G, cSetting_mouse_z_scale) * | |||
(((float) y) - I->LastY) / factor; | (((float) y) - I->LastY) / factor; | |||
if(!SettingGetGlobal_b(G, cSetting_legacy_mouse_zoom)) | if(!SettingGetGlobal_b(G, cSetting_legacy_mouse_zoom)) | |||
factor = -factor; | factor = -factor; | |||
} | } | |||
} | } | |||
copy3f(SettingGet<const float *>(G, which_light), pos); | copy3f(SettingGet<const float *>(G, which_light), pos); | |||
SettingGenerateSideEffects(G, which_light, NULL, 0, 1); | ||||
pos[2] -= factor * ms; | pos[2] -= factor * ms; | |||
result = SettingSet_3fv(G->Setting, which_light, pos); | SettingSet_3fv(G->Setting, which_light, pos); | |||
I->LastX = x; | I->LastX = x; | |||
I->LastY = y; | I->LastY = y; | |||
} | } | |||
break; | break; | |||
} | } | |||
if(moved_flag) | if(moved_flag) | |||
SceneDoRoving(G, old_front, old_back, old_origin, adjust_flag, false); | SceneDoRoving(G, old_front, old_back, old_origin, adjust_flag, false); | |||
} | } | |||
} | } | |||
if(I->PossibleSingleClick) { | if(I->PossibleSingleClick) { | |||
skipping to change at line 6142 | skipping to change at line 5724 | |||
di->filename = Alloc(char, stlen + 1); | di->filename = Alloc(char, stlen + 1); | |||
strcpy(di->filename, filename); | strcpy(di->filename, filename); | |||
} | } | |||
} | } | |||
OrthoDefer(G, &di->deferred); | OrthoDefer(G, &di->deferred); | |||
return 1; | return 1; | |||
} | } | |||
int SceneDeferClick(Block * block, int button, int x, int y, int mod) | int SceneDeferClick(Block * block, int button, int x, int y, int mod) | |||
{ | { | |||
PyMOLGlobals *G = block->G; | return SceneDeferClickWhen(block, button, x, y, UtilGetSeconds(block->G), mod) | |||
DeferredMouse *dm = Calloc(DeferredMouse, 1); | ; | |||
if(dm) { | ||||
DeferredInit(G, &dm->deferred); | ||||
dm->block = block; | ||||
dm->button = button; | ||||
dm->x = x; | ||||
dm->y = y; | ||||
dm->mod = mod; | ||||
dm->when = UtilGetSeconds(G); | ||||
dm->deferred.fn = (DeferredFn *) SceneDeferredClick; | ||||
} | ||||
OrthoDefer(G, &dm->deferred); | ||||
return 1; | ||||
} | } | |||
static int SceneDeferClickWhen(Block * block, int button, int x, int y, double w hen, | static int SceneDeferClickWhen(Block * block, int button, int x, int y, double w hen, | |||
int mod) | int mod) | |||
{ | { | |||
PyMOLGlobals *G = block->G; | PyMOLGlobals *G = block->G; | |||
DeferredMouse *dm = Calloc(DeferredMouse, 1); | DeferredMouse *dm = Calloc(DeferredMouse, 1); | |||
if(dm) { | if(dm) { | |||
DeferredInit(G, &dm->deferred); | DeferredInit(G, &dm->deferred); | |||
dm->block = block; | dm->block = block; | |||
skipping to change at line 6228 | skipping to change at line 5797 | |||
dm->deferred.fn = (DeferredFn *) SceneDeferredRelease; | dm->deferred.fn = (DeferredFn *) SceneDeferredRelease; | |||
} | } | |||
OrthoDefer(G, &dm->deferred); | OrthoDefer(G, &dm->deferred); | |||
return 1; | return 1; | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
void SceneFree(PyMOLGlobals * G) | void SceneFree(PyMOLGlobals * G) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
short created = I->offscreen_width && I->offscreen_height; | #if !defined(PURE_OPENGL_ES_2) || defined(_WEBGL) | |||
if (created){ | CGOFree(I->offscreenCGO); | |||
/* Cleaning up offscreen buffer if exists */ | #endif | |||
if (I->offscreen_fb){ | ||||
glDeleteFramebuffersEXT(1, &I->offscreen_fb); | ||||
I->offscreen_fb = 0; | ||||
} | ||||
if (I->offscreen_color_rb){ | ||||
glDeleteRenderbuffersEXT(1, &I->offscreen_color_rb); | ||||
I->offscreen_color_rb = 0; | ||||
} | ||||
if (I->offscreen_depth_rb){ | ||||
glDeleteRenderbuffersEXT(1, &I->offscreen_depth_rb); | ||||
I->offscreen_depth_rb = 0; | ||||
} | ||||
} | ||||
if(I->ScrollBar) | if(I->ScrollBar) | |||
ScrollBarFree(I->ScrollBar); | ScrollBarFree(I->ScrollBar); | |||
CGOFree(I->AlphaCGO); | CGOFree(I->AlphaCGO); | |||
CGOFree(I->offscreenCGO); | ||||
CGOFree(I->offscreenOIT_CGO); | ||||
CGOFree(I->offscreenOIT_CGO_copy); | ||||
VLAFreeP(I->SceneVLA); | VLAFreeP(I->SceneVLA); | |||
VLAFreeP(I->SceneNameVLA); | VLAFreeP(I->SceneNameVLA); | |||
VLAFreeP(I->SlotVLA); | VLAFreeP(I->SlotVLA); | |||
VLAFreeP(I->pickVLA); | ||||
OrthoFreeBlock(G, I->Block); | OrthoFreeBlock(G, I->Block); | |||
ListFree(I->Obj, next, ObjRec); | I->Obj.clear(); | |||
I->GadgetObjs.clear(); | ||||
I->NonGadgetObjs.clear(); | ||||
ScenePurgeImage(G); | ScenePurgeImage(G); | |||
CGOFree(G->DebugCGO); | CGOFree(G->DebugCGO); | |||
delete G->Scene; | delete G->Scene; | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
void SceneResetMatrix(PyMOLGlobals * G) | void SceneResetMatrix(PyMOLGlobals * G) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
identity44f(I->RotMatrix); | identity44f(I->RotMatrix); | |||
SceneUpdateInvMatrix(G); | SceneUpdateInvMatrix(G); | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
void SceneSetDefaultView(PyMOLGlobals * G) | void SceneSetDefaultView(PyMOLGlobals * G) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
identity44f(I->RotMatrix); | identity44f(I->RotMatrix); | |||
identity44f(I->ModMatrix); | ||||
identity44f(I->ProMatrix); | ||||
SceneUpdateInvMatrix(G); | SceneUpdateInvMatrix(G); | |||
I->ViewNormal[0] = 0.0F; | I->ViewNormal[0] = 0.0F; | |||
I->ViewNormal[1] = 0.0F; | I->ViewNormal[1] = 0.0F; | |||
I->ViewNormal[2] = 1.0F; | I->ViewNormal[2] = 1.0F; | |||
I->Pos[0] = 0.0F; | I->Pos[0] = 0.0F; | |||
I->Pos[1] = 0.0F; | I->Pos[1] = 0.0F; | |||
I->Pos[2] = -50.0F; | I->Pos[2] = -50.0F; | |||
skipping to change at line 6318 | skipping to change at line 5878 | |||
/*========================================================================*/ | /*========================================================================*/ | |||
int SceneInit(PyMOLGlobals * G) | int SceneInit(PyMOLGlobals * G) | |||
{ | { | |||
CScene *I = NULL; | CScene *I = NULL; | |||
I = (G->Scene = new CScene()); | I = (G->Scene = new CScene()); | |||
if(I) { | if(I) { | |||
/* all defaults to zero, so only initialize non-zero elements */ | /* all defaults to zero, so only initialize non-zero elements */ | |||
G->DebugCGO = CGONew(G); | G->DebugCGO = CGONew(G); | |||
ListInit(I->Obj); | ||||
I->TextColor[0] = 0.2F; | I->TextColor[0] = 0.2F; | |||
I->TextColor[1] = 1.0F; | I->TextColor[1] = 1.0F; | |||
I->TextColor[2] = 0.2F; | I->TextColor[2] = 0.2F; | |||
I->LastClickTime = UtilGetSeconds(G); | I->LastClickTime = UtilGetSeconds(G); | |||
SceneSetDefaultView(G); | SceneSetDefaultView(G); | |||
I->Scale = 1.0; | I->Scale = 1.0; | |||
I->Block = OrthoNewBlock(G, NULL); | I->Block = OrthoNewBlock(G, NULL); | |||
skipping to change at line 6348 | skipping to change at line 5906 | |||
I->DirtyFlag = true; | I->DirtyFlag = true; | |||
I->LastRender = UtilGetSeconds(G); | I->LastRender = UtilGetSeconds(G); | |||
I->LastFrameTime = UtilGetSeconds(G); | I->LastFrameTime = UtilGetSeconds(G); | |||
I->LastSweepTime = UtilGetSeconds(G); | I->LastSweepTime = UtilGetSeconds(G); | |||
I->LastStateBuilt = -1; | I->LastStateBuilt = -1; | |||
I->CopyNextFlag = true; | I->CopyNextFlag = true; | |||
I->invPick = true; | ||||
SceneRestartFrameTimer(G); | SceneRestartFrameTimer(G); | |||
SceneRestartPerfTimer(G); | SceneRestartPerfTimer(G); | |||
I->Width = 640; /* standard defaults */ | I->Width = 640; /* standard defaults */ | |||
I->Height = 480; | I->Height = 480; | |||
I->VertexScale = 0.01F; | I->VertexScale = 0.01F; | |||
/* scene list */ | /* scene list */ | |||
skipping to change at line 6444 | skipping to change at line 6003 | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
if(G->HaveGUI && G->ValidContext) { | if(G->HaveGUI && G->ValidContext) { | |||
if(lines) | if(lines) | |||
CGONormalv(cgo, I->LinesNormal); | CGONormalv(cgo, I->LinesNormal); | |||
else | else | |||
CGONormalv(cgo, I->ViewNormal); | CGONormalv(cgo, I->ViewNormal); | |||
} | } | |||
} | } | |||
void SceneResetNormalToViewVector(PyMOLGlobals * G, short use_shader) | ||||
{ | ||||
CScene *I = G->Scene; | ||||
if(G->HaveGUI && G->ValidContext) { | ||||
#if defined(PURE_OPENGL_ES_2) | ||||
glVertexAttrib3f(VERTEX_NORMAL, I->ModMatrix[2], I->ModMatrix[6], I->ModMatr | ||||
ix[10]); | ||||
#else | ||||
if (use_shader){ | ||||
glVertexAttrib3f(VERTEX_NORMAL, I->ModMatrix[2], I->ModMatrix[6], I->ModMa | ||||
trix[10]); | ||||
} else { | ||||
glNormal3f(I->ModMatrix[2], I->ModMatrix[6], I->ModMatrix[10]); | ||||
} | ||||
#endif | ||||
} | ||||
} | ||||
void SceneResetNormalUseShader(PyMOLGlobals * G, int lines, short use_shader) | void SceneResetNormalUseShader(PyMOLGlobals * G, int lines, short use_shader) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
if(G->HaveGUI && G->ValidContext) { | if(G->HaveGUI && G->ValidContext) { | |||
#ifdef PURE_OPENGL_ES_2 | #ifdef PURE_OPENGL_ES_2 | |||
if(lines) | ||||
glVertexAttrib3fv(VERTEX_NORMAL, I->LinesNormal); | ||||
else | ||||
glVertexAttrib3fv(VERTEX_NORMAL, I->ViewNormal); | ||||
#else | #else | |||
if (use_shader){ | if (use_shader){ | |||
if(lines) | if(lines) | |||
glVertexAttrib3fv(VERTEX_NORMAL, I->LinesNormal); | glVertexAttrib3fv(VERTEX_NORMAL, I->LinesNormal); | |||
else | else | |||
glVertexAttrib3fv(VERTEX_NORMAL, I->ViewNormal); | glVertexAttrib3fv(VERTEX_NORMAL, I->ViewNormal); | |||
} else { | } else { | |||
if(lines) | if(lines) | |||
glNormal3fv(I->LinesNormal); | glNormal3fv(I->LinesNormal); | |||
else | else | |||
skipping to change at line 6470 | skipping to change at line 6049 | |||
} | } | |||
#endif | #endif | |||
} | } | |||
} | } | |||
void SceneResetNormalUseShaderAttribute(PyMOLGlobals * G, int lines, short use_s hader, int attr) | void SceneResetNormalUseShaderAttribute(PyMOLGlobals * G, int lines, short use_s hader, int attr) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
if(G->HaveGUI && G->ValidContext) { | if(G->HaveGUI && G->ValidContext) { | |||
#ifdef PURE_OPENGL_ES_2 | #ifdef PURE_OPENGL_ES_2 | |||
if (attr < 0) | ||||
return; | ||||
if(lines) | ||||
glVertexAttrib3fv(attr, I->LinesNormal); | ||||
else | ||||
glVertexAttrib3fv(attr, I->ViewNormal); | ||||
#else | #else | |||
if (use_shader){ | if (use_shader){ | |||
if(lines) | if(lines) | |||
glVertexAttrib3fv(attr, I->LinesNormal); | glVertexAttrib3fv(attr, I->LinesNormal); | |||
else | else | |||
glVertexAttrib3fv(attr, I->ViewNormal); | glVertexAttrib3fv(attr, I->ViewNormal); | |||
} else { | } else { | |||
if(lines) | if(lines) | |||
glNormal3fv(I->LinesNormal); | glNormal3fv(I->LinesNormal); | |||
else | else | |||
skipping to change at line 6500 | skipping to change at line 6085 | |||
if(G->HaveGUI && G->ValidContext) { | if(G->HaveGUI && G->ValidContext) { | |||
if(lines) | if(lines) | |||
norm = I->LinesNormal; | norm = I->LinesNormal; | |||
else | else | |||
norm = I->ViewNormal; | norm = I->ViewNormal; | |||
normal[0] = norm[0]; normal[1] = norm[1]; normal[2] = norm[2]; | normal[0] = norm[0]; normal[1] = norm[1]; normal[2] = norm[2]; | |||
} | } | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
static void SceneApplyImageGamma(PyMOLGlobals * G, unsigned int *buffer, int wid | void SceneApplyImageGamma(PyMOLGlobals * G, unsigned int *buffer, int width, | |||
th, | int height) | |||
int height) | ||||
{ | { | |||
unsigned int test; | ||||
unsigned char *testPtr; | ||||
int big_endian; | ||||
float gamma = SettingGetGlobal_f(G, cSetting_gamma); | float gamma = SettingGetGlobal_f(G, cSetting_gamma); | |||
if(gamma > R_SMALL4) | if(gamma > R_SMALL4) | |||
gamma = 1.0F / gamma; | gamma = 1.0F / gamma; | |||
else | else | |||
gamma = 1.0F; | gamma = 1.0F; | |||
test = 0xFF000000; | ||||
testPtr = (unsigned char *) &test; | ||||
big_endian = (*testPtr) & 0x01; | ||||
if(buffer && height && width) { | if(buffer && height && width) { | |||
float _inv3 = 1 / (255 * 3.0F); | float _inv3 = 1 / (255 * 3.0F); | |||
float _1 = 1 / 3.0F; | float _1 = 1 / 3.0F; | |||
unsigned char *p; | unsigned char *p; | |||
int x, y; | int x, y; | |||
float c1, c2, c3, inp, sig; | float c1, c2, c3, inp, sig; | |||
unsigned int i1, i2, i3; | unsigned int i1, i2, i3; | |||
p = (unsigned char *) buffer; | p = (unsigned char *) buffer; | |||
for(y = 0; y < height; y++) { | for(y = 0; y < height; y++) { | |||
for(x = 0; x < width; x++) { | for(x = 0; x < width; x++) { | |||
skipping to change at line 6553 | skipping to change at line 6131 | |||
i3 = 255; | i3 = 255; | |||
p[0] = i1; | p[0] = i1; | |||
p[1] = i2; | p[1] = i2; | |||
p[2] = i3; | p[2] = i3; | |||
p += 4; | p += 4; | |||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
/*========================================================================*/ | ||||
static double accumTiming = 0.0; | ||||
void SceneDoRay(PyMOLGlobals * G, int width, int height, int mode, | ||||
char **headerVLA, char **charVLA, | ||||
float angle, float shift, int quiet, | ||||
G3dPrimitive ** g3d, int show_timing, int antialias) | ||||
{ | ||||
SceneRay(G, width, height, mode, | ||||
headerVLA, charVLA, angle, shift, quiet, g3d, show_timing, antialias) | ||||
; | ||||
} | ||||
static int SceneDeferredRay(DeferredRay * dr) | ||||
{ | ||||
PyMOLGlobals *G = dr->G; | ||||
SceneRay(G, dr->ray_width, dr->ray_height, dr->mode, | ||||
NULL, NULL, dr->angle, dr->shift, dr->quiet, | ||||
NULL, dr->show_timing, dr->antialias); | ||||
if((dr->mode == 0) && G->HaveGUI && SettingGetGlobal_b(G, cSetting_auto_copy_i | ||||
mages)) { | ||||
#ifdef _PYMOL_IP_EXTRAS | ||||
IncentiveCopyToClipboard(G, dr->quiet); | ||||
#else | ||||
#ifdef PYMOL_EVAL | ||||
PRINTFB(G, FB_Scene, FB_Warnings) | ||||
" Warning: Clipboard image transfers disabled in Evaluation Builds.\n" END | ||||
FB(G); | ||||
#endif | ||||
#endif | ||||
} | ||||
return 1; | ||||
} | ||||
int SceneDeferRay(PyMOLGlobals * G, | ||||
int ray_width, | ||||
int ray_height, | ||||
int mode, | ||||
float angle, float shift, int quiet, int show_timing, int anti | ||||
alias) | ||||
{ | ||||
DeferredRay *dr = Calloc(DeferredRay, 1); | ||||
if(dr) { | ||||
DeferredInit(G, &dr->deferred); | ||||
dr->G = G; | ||||
dr->ray_width = ray_width; | ||||
dr->ray_height = ray_height; | ||||
dr->mode = mode; | ||||
dr->angle = angle; | ||||
dr->shift = shift; | ||||
dr->quiet = quiet; | ||||
dr->show_timing = show_timing; | ||||
dr->antialias = antialias; | ||||
dr->deferred.fn = (DeferredFn *) SceneDeferredRay; | ||||
} | ||||
OrthoDefer(G, &dr->deferred); | ||||
return 1; | ||||
} | ||||
void SceneUpdateAnimation(PyMOLGlobals * G) | void SceneUpdateAnimation(PyMOLGlobals * G) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
int rockFlag = false; | int rockFlag = false; | |||
int dirty = false; | int dirty = false; | |||
int movie_rock = SettingGetGlobal_i(G, cSetting_movie_rock); | int movie_rock = SettingGetGlobal_i(G, cSetting_movie_rock); | |||
if(movie_rock < 0) | if(movie_rock < 0) | |||
movie_rock = ControlRocking(G); | movie_rock = ControlRocking(G); | |||
skipping to change at line 6689 | skipping to change at line 6211 | |||
} | } | |||
I->cur_ani_elem = cur; | I->cur_ani_elem = cur; | |||
SceneFromViewElem(G, I->ani_elem + cur, dirty); | SceneFromViewElem(G, I->ani_elem + cur, dirty); | |||
OrthoDirty(G); | OrthoDirty(G); | |||
} | } | |||
if(rockFlag && (I->RenderTime != 0.0)) { | if(rockFlag && (I->RenderTime != 0.0)) { | |||
SceneUpdateCameraRock(G, dirty); | SceneUpdateCameraRock(G, dirty); | |||
} | } | |||
} | } | |||
static int SceneGetDrawFlag(GridInfo * grid, int *slot_vla, int slot) | int SceneGetDrawFlag(GridInfo * grid, int *slot_vla, int slot) | |||
{ | { | |||
int draw_flag = false; | int draw_flag = false; | |||
if(grid && grid->active) { | if(grid && grid->active) { | |||
switch (grid->mode) { | switch (grid->mode) { | |||
case 1: /* assigned grid slots (usually by group) */ | case 1: /* assigned grid slots (usually by group) */ | |||
{ | { | |||
if(((slot < 0) && grid->slot) || | if(((slot < 0) && grid->slot) || | |||
((slot == 0) && (grid->slot == 0)) || | ((slot == 0) && (grid->slot == 0)) || | |||
(slot_vla && (slot_vla[slot] == grid->slot))) { | (slot_vla && (slot_vla[slot] == grid->slot))) { | |||
draw_flag = true; | draw_flag = true; | |||
skipping to change at line 6720 | skipping to change at line 6242 | |||
} | } | |||
return draw_flag; | return draw_flag; | |||
} | } | |||
int SceneGetDrawFlagGrid(PyMOLGlobals * G, GridInfo * grid, int slot) | int SceneGetDrawFlagGrid(PyMOLGlobals * G, GridInfo * grid, int slot) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
return SceneGetDrawFlag(grid, I->SlotVLA, slot); | return SceneGetDrawFlag(grid, I->SlotVLA, slot); | |||
} | } | |||
bool SceneRay(PyMOLGlobals * G, | ||||
int ray_width, int ray_height, int mode, | ||||
char **headerVLA_ptr, | ||||
char **charVLA_ptr, float angle, | ||||
float shift, int quiet, G3dPrimitive ** g3d, int show_timing, int | ||||
antialias) | ||||
{ | ||||
CScene *I = G->Scene; | ||||
ObjRec *rec = NULL; | ||||
CRay *ray = NULL; | ||||
float height, width; | ||||
float aspRat; | ||||
float rayView[16]; | ||||
int curState; | ||||
double timing; | ||||
char *charVLA = NULL; | ||||
char *headerVLA = NULL; | ||||
float fov; | ||||
int stereo_hand = 0; | ||||
int grid_mode = SettingGetGlobal_i(G, cSetting_grid_mode); | ||||
ImageType *stereo_image = NULL; | ||||
OrthoLineType prefix = ""; | ||||
int ortho = SettingGetGlobal_i(G, cSetting_ray_orthoscopic); | ||||
int last_grid_active = I->grid.active; | ||||
int grid_size = 0; | ||||
if(SettingGetGlobal_i(G, cSetting_defer_builds_mode) == 5) | ||||
SceneUpdate(G, true); | ||||
if(ortho < 0) | ||||
ortho = SettingGetGlobal_b(G, cSetting_ortho); | ||||
if(mode != 0) | ||||
grid_mode = 0; /* only allow grid mode with PyMOL renderer */ | ||||
SceneUpdateAnimation(G); | ||||
if(mode == 0) | ||||
SceneInvalidateCopy(G, true); | ||||
if(antialias < 0) { | ||||
antialias = SettingGetGlobal_i(G, cSetting_antialias); | ||||
} | ||||
if(ray_width < 0) | ||||
ray_width = 0; | ||||
if(ray_height < 0) | ||||
ray_height = 0; | ||||
if((!ray_width) || (!ray_height)) { | ||||
if(ray_width && (!ray_height)) { | ||||
ray_height = (ray_width * I->Height) / I->Width; | ||||
} else if(ray_height && (!ray_width)) { | ||||
ray_width = (ray_height * I->Width) / I->Height; | ||||
} else { | ||||
ray_width = I->Width; | ||||
ray_height = I->Height; | ||||
} | ||||
} | ||||
fov = SettingGetGlobal_f(G, cSetting_field_of_view); | ||||
if(SettingGetGlobal_b(G, cSetting_all_states)) { | ||||
curState = -1; | ||||
} else { | ||||
curState = SettingGetGlobal_i(G, cSetting_state) - 1; | ||||
} | ||||
timing = UtilGetSeconds(G); /* start timing the process */ | ||||
SceneUpdate(G, false); | ||||
switch (I->StereoMode) { | ||||
case cStereo_quadbuffer: | ||||
stereo_hand = 2; | ||||
break; | ||||
case cStereo_crosseye: | ||||
case cStereo_walleye: | ||||
ray_width = ray_width / 2; | ||||
stereo_hand = 2; | ||||
break; | ||||
case cStereo_geowall: | ||||
case cStereo_sidebyside: | ||||
stereo_hand = 2; | ||||
break; | ||||
case cStereo_stencil_by_row: | ||||
case cStereo_stencil_by_column: | ||||
case cStereo_stencil_checkerboard: | ||||
case cStereo_stencil_custom: | ||||
case cStereo_anaglyph: | ||||
stereo_hand = 2; | ||||
break; | ||||
} | ||||
aspRat = ((float) ray_width) / ((float) ray_height); | ||||
if(grid_mode) { | ||||
grid_size = SceneGetGridSize(G, grid_mode); | ||||
GridUpdate(&I->grid, aspRat, grid_mode, grid_size); | ||||
if(I->grid.active) | ||||
aspRat *= I->grid.asp_adjust; | ||||
} | ||||
if (last_grid_active != I->grid.active || grid_size != I->last_grid_size){ | ||||
// ExecutiveInvalidateRep(G, cKeywordAll, cRepLabel, cRepInvAll); | ||||
ShaderMgrResetUniformSet(G); | ||||
} | ||||
I->last_grid_size = grid_size; | ||||
while(1) { | ||||
int slot; | ||||
int tot_width = ray_width; | ||||
int tot_height = ray_height; | ||||
int ray_x = 0, ray_y = 0; | ||||
if(I->grid.active) | ||||
GridGetRayViewport(&I->grid, ray_width, ray_height); | ||||
for(slot = 0; slot <= I->grid.last_slot; slot++) { | ||||
if(I->grid.active) { | ||||
GridSetRayViewport(&I->grid, slot, &ray_x, &ray_y, &ray_width, &ray_heig | ||||
ht); | ||||
OrthoBusySlow(G, slot, I->grid.last_slot); | ||||
} | ||||
/* start afresh, looking in the negative Z direction (0,0,-1) from (0,0,0) | ||||
*/ | ||||
identity44f(rayView); | ||||
ray = RayNew(G, antialias); | ||||
if(!ray) | ||||
break; | ||||
if(stereo_hand) { | ||||
/* stereo */ | ||||
float stAng, stShift; | ||||
stAng = SettingGetGlobal_f(G, cSetting_stereo_angle); | ||||
stShift = SettingGetGlobal_f(G, cSetting_stereo_shift); | ||||
/* right hand */ | ||||
stShift = (float) (stShift * fabs(I->Pos[2]) / 100.0); | ||||
stAng = (float) (stAng * atan(stShift / fabs(I->Pos[2])) * 90.0 / cPI); | ||||
if(stereo_hand == 2) { /* left hand */ | ||||
stAng = -stAng; | ||||
stShift = -stShift; | ||||
} | ||||
angle = stAng; | ||||
{ | ||||
float temp[16]; | ||||
identity44f(temp); | ||||
MatrixRotateC44f(temp, (float) (-PI * stAng / 180), 0.0F, 1.0F, 0.0F); | ||||
/* y-axis rotation */ | ||||
MatrixMultiplyC44f(temp, rayView); | ||||
} | ||||
/* move the camera to the location we are looking at */ | ||||
MatrixTranslateC44f(rayView, I->Pos[0], I->Pos[1], I->Pos[2]); | ||||
MatrixTranslateC44f(rayView, stShift, 0.0, 0.0); | ||||
MatrixMultiplyC44f(I->RotMatrix, rayView); | ||||
} else { /* not stereo mode */ | ||||
/* move the camera to the location we are looking at */ | ||||
MatrixTranslateC44f(rayView, I->Pos[0], I->Pos[1], I->Pos[2]); | ||||
if(shift) { | ||||
MatrixTranslateC44f(rayView, shift, 0.0F, 0.0F); | ||||
} | ||||
/* move the camera so that we can see the origin | ||||
* NOTE, vector is given in the coordinates of the world's motion | ||||
* relative to the camera */ | ||||
/* 4. rotate about the origin (the the center of rotation) */ | ||||
if(angle) { | ||||
float temp[16]; | ||||
identity44f(temp); | ||||
MatrixRotateC44f(temp, (float) (-PI * angle / 180), 0.0F, 1.0F, 0.0F); | ||||
MatrixMultiplyC44f(I->RotMatrix, temp); | ||||
MatrixMultiplyC44f(temp, rayView); | ||||
} else { | ||||
MatrixMultiplyC44f(I->RotMatrix, rayView); | ||||
} | ||||
} | ||||
/* 5. move the origin to the center of rotation */ | ||||
MatrixTranslateC44f(rayView, -I->Origin[0], -I->Origin[1], -I->Origin[2]); | ||||
if(Feedback(G, FB_Scene, FB_Debugging)) { | ||||
fprintf(stderr, "SceneRay: %8.3f %8.3f %8.3f\n", I->Pos[0], I->Pos[1], I | ||||
->Pos[2]); | ||||
fprintf(stderr, "SceneRay: %8.3f %8.3f %8.3f\n", | ||||
I->Origin[0], I->Origin[1], I->Origin[2]); | ||||
fprintf(stderr, "SceneRay: %8.3f %8.3f %8.3f\n", | ||||
I->RotMatrix[0], I->RotMatrix[1], I->RotMatrix[2]); | ||||
} | ||||
/* define the viewing volume */ | ||||
height = (float) (fabs(I->Pos[2]) * tan((fov / 2.0) * cPI / 180.0)); | ||||
width = height * aspRat; | ||||
PyMOL_SetBusy(G->PyMOL, true); | ||||
OrthoBusyFast(G, 0, 20); | ||||
{ | ||||
float pixel_scale_value = SettingGetGlobal_f(G, cSetting_ray_pixel_scale | ||||
); | ||||
if(pixel_scale_value < 0) | ||||
pixel_scale_value = 1.0F; | ||||
pixel_scale_value *= ((float) tot_height) / I->Height; | ||||
if(ortho) { | ||||
const float _1 = 1.0F; | ||||
RayPrepare(ray, -width, width, -height, height, I->FrontSafe, | ||||
I->BackSafe, fov, I->Pos, rayView, I->RotMatrix, | ||||
aspRat, ray_width, ray_height, | ||||
pixel_scale_value, ortho, _1, _1, | ||||
((float) ray_height) / I->Height); | ||||
} else { | ||||
float back_ratio; | ||||
float back_height; | ||||
float back_width; | ||||
float pos; | ||||
pos = I->Pos[2]; | ||||
if((-pos) < I->FrontSafe) { | ||||
pos = -I->FrontSafe; | ||||
} | ||||
back_ratio = -I->Back / pos; | ||||
back_height = back_ratio * height; | ||||
back_width = aspRat * back_height; | ||||
RayPrepare(ray, | ||||
-back_width, back_width, | ||||
-back_height, back_height, | ||||
I->FrontSafe, I->BackSafe, | ||||
fov, I->Pos, | ||||
rayView, I->RotMatrix, aspRat, | ||||
ray_width, ray_height, | ||||
pixel_scale_value, ortho, | ||||
height / back_height, | ||||
I->FrontSafe / I->BackSafe, ((float) ray_height) / I->Heigh | ||||
t); | ||||
} | ||||
} | ||||
{ | ||||
int *slot_vla = I->SlotVLA; | ||||
int state = SceneGetState(G); | ||||
RenderInfo info; | ||||
UtilZeroMem(&info, sizeof(RenderInfo)); | ||||
info.ray = ray; | ||||
info.ortho = ortho; | ||||
info.vertex_scale = SceneGetScreenVertexScale(G, NULL); | ||||
if(SettingGetGlobal_b(G, cSetting_dynamic_width)) { | ||||
info.dynamic_width = true; | ||||
info.dynamic_width_factor = | ||||
SettingGetGlobal_f(G, cSetting_dynamic_width_factor); | ||||
info.dynamic_width_min = SettingGetGlobal_f(G, cSetting_dynamic_width_ | ||||
min); | ||||
info.dynamic_width_max = SettingGetGlobal_f(G, cSetting_dynamic_width_ | ||||
max); | ||||
} | ||||
while(ListIterate(I->Obj, rec, next)) { | ||||
if(rec->obj->fRender) { | ||||
if(SceneGetDrawFlag(&I->grid, slot_vla, rec->obj->grid_slot)) { | ||||
int obj_color = rec->obj->Color; | ||||
float color[3]; | ||||
int icx; | ||||
ColorGetEncoded(G, obj_color, color); | ||||
RaySetContext(ray, rec->obj->Context); | ||||
ray->color3fv(color); | ||||
if(SettingGetIfDefined_i | ||||
(G, rec->obj->Setting, cSetting_ray_interior_color, &icx)) { | ||||
float icolor[3]; | ||||
if(icx != -1) { | ||||
if(icx == cColorObject) { | ||||
ray->interiorColor3fv(color, false); | ||||
} else { | ||||
ColorGetEncoded(G, icx, icolor); | ||||
ray->interiorColor3fv(icolor, false); | ||||
} | ||||
} else { | ||||
ray->interiorColor3fv(color, true); | ||||
} | ||||
} else { | ||||
ray->interiorColor3fv(color, true); | ||||
} | ||||
if((!I->grid.active) || (I->grid.mode != 2)) { | ||||
info.state = ObjectGetCurrentState(rec->obj, false); | ||||
rec->obj->fRender(rec->obj, &info); | ||||
} else if(I->grid.slot) { | ||||
if((info.state = state + I->grid.slot - 1) >= 0) | ||||
rec->obj->fRender(rec->obj, &info); | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
OrthoBusyFast(G, 1, 20); | ||||
if(mode != 2) { /* don't show pixel count for tests */ | ||||
if(!quiet) { | ||||
PRINTFB(G, FB_Ray, FB_Blather) | ||||
" Ray: tracing %dx%d = %d rays against %d primitives.\n", ray_width, | ||||
ray_height, ray_width * ray_height, RayGetNPrimitives(ray) | ||||
ENDFB(G); | ||||
} | ||||
} | ||||
switch (mode) { | ||||
case 0: /* mode 0 is built-in */ | ||||
{ | ||||
unsigned int buffer_size = 4 * ray_width * ray_height; | ||||
unsigned int *buffer = (unsigned int*) Alloc(unsigned int, ray_width * | ||||
ray_height); | ||||
unsigned int background; | ||||
ErrChkPtr(G, buffer); | ||||
RayRender(ray, buffer, timing, angle, antialias, &background); | ||||
/* RayRenderColorTable(ray,ray_width,ray_height,buffer); */ | ||||
if(!I->grid.active) { | ||||
I->Image = Calloc(ImageType, 1); | ||||
I->Image->data = (unsigned char *) buffer; | ||||
I->Image->size = buffer_size; | ||||
I->Image->width = ray_width; | ||||
I->Image->height = ray_height; | ||||
} else { | ||||
if(!I->Image) { /* alloc on first pass */ | ||||
I->Image = Calloc(ImageType, 1); | ||||
if(I->Image) { | ||||
unsigned int tot_size = 4 * tot_width * tot_height; | ||||
I->Image->data = Alloc(unsigned char, tot_size); | ||||
I->Image->size = tot_size; | ||||
I->Image->width = tot_width; | ||||
I->Image->height = tot_height; | ||||
{ /* fill with background color */ | ||||
unsigned int i; | ||||
unsigned int *ptr = (unsigned int *) I->Image->data; | ||||
for(i = 0; i < tot_size; i += 4) { | ||||
*(ptr++) = background; | ||||
} | ||||
} | ||||
} | ||||
} | ||||
/* merge in the latest rendering */ | ||||
if(I->Image && I->Image->data) { | ||||
int i, j; | ||||
unsigned int *src = buffer; | ||||
unsigned int *dst = (unsigned int *) I->Image->data; | ||||
dst += (ray_x + ray_y * tot_width); | ||||
for(i = 0; i < ray_height; i++) { | ||||
for(j = 0; j < ray_width; j++) { | ||||
if(*src != background) | ||||
*(dst) = *(src); | ||||
dst++; | ||||
src++; | ||||
} | ||||
dst += (tot_width - ray_width); | ||||
} | ||||
} | ||||
FreeP(buffer); | ||||
} | ||||
I->DirtyFlag = false; | ||||
I->CopyType = true; | ||||
I->CopyForced = true; | ||||
I->MovieOwnsImageFlag = false; | ||||
} | ||||
break; | ||||
case 1: /* mode 1 is povray */ | ||||
charVLA = VLACalloc(char, 100000); | ||||
headerVLA = VLACalloc(char, 2000); | ||||
RayRenderPOV(ray, ray_width, ray_height, &headerVLA, &charVLA, | ||||
I->FrontSafe, I->BackSafe, fov, angle, antialias); | ||||
if(!(charVLA_ptr && headerVLA_ptr)) { /* immediate mode */ | ||||
strcpy(prefix, SettingGet_s(G, NULL, NULL, cSetting_batch_prefix)); | ||||
#ifndef _PYMOL_NOPY | ||||
if(PPovrayRender(G, headerVLA, charVLA, prefix, ray_width, | ||||
ray_height, antialias)) { | ||||
strcat(prefix, ".png"); | ||||
SceneLoadPNG(G, prefix, false, 0, false); | ||||
I->DirtyFlag = false; | ||||
} | ||||
#endif | ||||
VLAFreeP(charVLA); | ||||
VLAFreeP(headerVLA); | ||||
} else { /* get_povray mode */ | ||||
*charVLA_ptr = charVLA; | ||||
*headerVLA_ptr = headerVLA; | ||||
} | ||||
break; | ||||
case 2: /* mode 2 is for testing of geometries */ | ||||
RayRenderTest(ray, ray_width, ray_height, I->FrontSafe, I->BackSafe, fov | ||||
); | ||||
break; | ||||
case 3: /* mode 3 is for Jmol */ | ||||
{ | ||||
G3dPrimitive *jp = | ||||
RayRenderG3d(ray, ray_width, ray_height, I->FrontSafe, I->BackSafe, | ||||
fov, | ||||
quiet); | ||||
if(0) { | ||||
int cnt = VLAGetSize(jp); | ||||
int a; | ||||
for(a = 0; a < cnt; a++) { | ||||
switch (jp[a].op) { | ||||
case 1: | ||||
printf("g3d.fillSphereCentered(gray,%d,%d,%d,%d);\n", jp[a].r, j | ||||
p[a].x1, | ||||
jp[a].y1, jp[a].z1); | ||||
break; | ||||
case 2: | ||||
printf("triangle(%d,%d,%d,%d,%d,%d,%d,%d,%d);\n", | ||||
jp[a].x1, jp[a].y1, jp[a].z1, | ||||
jp[a].x2, jp[a].y2, jp[a].z2, jp[a].x3, jp[a].y3, jp[a].z | ||||
3); | ||||
break; | ||||
case 3: | ||||
printf("g3d.fillCylinder(gray,gray,(byte)3,%d,%d,%d,%d,%d,%d,%d) | ||||
;\n", | ||||
jp[a].r, | ||||
jp[a].x1, jp[a].y1, jp[a].z1, jp[a].x2, jp[a].y2, jp[a].z | ||||
2); | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
if(g3d) { | ||||
*g3d = jp; | ||||
} else { | ||||
VLAFreeP(jp); | ||||
} | ||||
} | ||||
break; | ||||
case 4: /* VRML2 */ | ||||
{ | ||||
char *vla = VLACalloc(char, 100000); | ||||
RayRenderVRML2(ray, ray_width, ray_height, &vla, | ||||
I->FrontSafe, I->BackSafe, fov, angle, I->Pos[2]); | ||||
*charVLA_ptr = vla; | ||||
} | ||||
break; | ||||
case 5: /* mode 5 is OBJ MTL */ | ||||
{ | ||||
char *objVLA = VLACalloc(char, 100000); | ||||
char *mtlVLA = VLACalloc(char, 1000); | ||||
RayRenderObjMtl(ray, ray_width, ray_height, &objVLA, &mtlVLA, | ||||
I->FrontSafe, I->BackSafe, fov, angle, I->Pos[2]); | ||||
*headerVLA_ptr = objVLA; | ||||
*charVLA_ptr = mtlVLA; | ||||
} | ||||
break; | ||||
case 6: /* VRML1 -- more compatible with tools like blend | ||||
er */ | ||||
{ | ||||
char *vla = VLACalloc(char, 100000); | ||||
RayRenderVRML1(ray, ray_width, ray_height, &vla, | ||||
I->FrontSafe, I->BackSafe, fov, angle, I->Pos[2]); | ||||
*charVLA_ptr = vla; | ||||
} | ||||
break; | ||||
case cSceneRay_MODE_IDTF: | ||||
{ | ||||
*headerVLA_ptr = VLACalloc(char, 10000); | ||||
*charVLA_ptr = VLACalloc(char, 10000); | ||||
RayRenderIDTF(ray, headerVLA_ptr, charVLA_ptr); | ||||
} | ||||
break; | ||||
case 8: /* mode 8 is COLLADA (.dae) */ | ||||
{ | ||||
*charVLA_ptr = VLACalloc(char, 100000); | ||||
RayRenderCOLLADA(ray, ray_width, ray_height, charVLA_ptr, | ||||
I->FrontSafe, I->BackSafe, fov); | ||||
} | ||||
break; | ||||
} | ||||
RayFree(ray); | ||||
} | ||||
if(I->grid.active) | ||||
GridSetRayViewport(&I->grid, -1, &ray_x, &ray_y, &ray_width, &ray_height); | ||||
if((mode == 0) && I->Image && I->Image->data) { | ||||
SceneApplyImageGamma(G, (unsigned int *) I->Image->data, I->Image->width, | ||||
I->Image->height); | ||||
} | ||||
stereo_hand--; | ||||
if((I->StereoMode == 0) || (stereo_hand <= 0)) | ||||
break; | ||||
else { | ||||
stereo_image = I->Image; | ||||
I->Image = NULL; | ||||
} | ||||
} | ||||
if(stereo_image) { | ||||
if(I->Image) { | ||||
switch (I->StereoMode) { | ||||
case cStereo_quadbuffer: | ||||
case cStereo_geowall: | ||||
/* merge the two images into one pointer */ | ||||
I->Image->data = Realloc(I->Image->data, unsigned char, I->Image->size * | ||||
2); | ||||
UtilCopyMem(I->Image->data + I->Image->size, stereo_image->data, I->Imag | ||||
e->size); | ||||
I->Image->stereo = true; | ||||
break; | ||||
case cStereo_crosseye: | ||||
case cStereo_walleye: | ||||
{ | ||||
/* merge the two images into one */ | ||||
unsigned char *merged_image = Alloc(unsigned char, I->Image->size * 2) | ||||
; | ||||
unsigned int *q = (unsigned int *) merged_image; | ||||
unsigned int *l; | ||||
unsigned int *r; | ||||
int height, width; | ||||
int a, b; | ||||
if(I->StereoMode == 2) { | ||||
l = (unsigned int *) stereo_image->data; | ||||
r = (unsigned int *) I->Image->data; | ||||
} else { | ||||
r = (unsigned int *) stereo_image->data; | ||||
l = (unsigned int *) I->Image->data; | ||||
} | ||||
height = I->Image->height; | ||||
width = I->Image->width; | ||||
for(a = 0; a < height; a++) { | ||||
for(b = 0; b < width; b++) | ||||
*(q++) = *(l++); | ||||
for(b = 0; b < width; b++) | ||||
*(q++) = *(r++); | ||||
} | ||||
FreeP(I->Image->data); | ||||
I->Image->data = merged_image; | ||||
I->Image->width *= 2; | ||||
I->Image->size *= 2; | ||||
} | ||||
break; | ||||
case cStereo_anaglyph: | ||||
{ | ||||
int big_endian; | ||||
{ | ||||
unsigned int test; | ||||
unsigned char *testPtr; | ||||
test = 0xFF000000; | ||||
testPtr = (unsigned char *) &test; | ||||
big_endian = (*testPtr) & 0x01; | ||||
} | ||||
{ | ||||
unsigned int *l = (unsigned int *) stereo_image->data; | ||||
unsigned int *r = (unsigned int *) I->Image->data; | ||||
int anaglyph_mode = SettingGetGlobal_i(G, cSetting_anaglyph_mode); | ||||
/* anaglyph scalars */ | ||||
float * a_r = anaglyphR_constants[anaglyph_mode]; | ||||
float * a_l = anaglyphL_constants[anaglyph_mode]; | ||||
int height, width; | ||||
int a, b; | ||||
float _r[3] = {0.F,0.F,0.F}, _l[3] = {0.F,0.F,0.F}, _b[3] = {0.F,0.F, | ||||
0.F}; | ||||
height = I->Image->height; | ||||
width = I->Image->width; | ||||
for(a = 0; a < height; a++) { | ||||
for(b = 0; b < width; b++) { | ||||
if(big_endian) { | ||||
/* original : RGBA | ||||
*r = (*l & 0x00FFFFFF) | (*r & 0xFF000000); | ||||
*/ | ||||
/* UNTESTED */ | ||||
_l[0] = (float)((*r & 0xFF000000)); | ||||
_l[1] = (float)((*r & 0x00FF0000) >> 16); | ||||
_l[2] = (float)((*r & 0x0000FF00) >> 8); | ||||
_r[0] = (float)((*l & 0xFF000000)); | ||||
_r[1] = (float)((*l & 0x00FF0000) >> 16); | ||||
_r[2] = (float)((*l & 0x0000FF00) >> 8); | ||||
_b[0] = (a_l[0] * _l[0] + a_l[1] * _l[1] + a_l[2] * _l[2]); // | ||||
R | ||||
_b[1] = (a_l[3] * _l[0] + a_l[4] * _l[1] + a_l[5] * _l[2]); // | ||||
G | ||||
_b[2] = (a_l[6] * _l[0] + a_l[7] * _l[1] + a_l[8] * _l[2]); // | ||||
B | ||||
*l = (unsigned int) (0x000000FF & *l) | | ||||
(unsigned int) (1.0 * _b[0]) | | ||||
((unsigned int) (1.0 * _b[1]))<<8 | | ||||
((unsigned int) (1.0 * _b[2]))<<16; | ||||
_b[0] = (a_r[0] * _r[0] + a_r[1] * _r[1] + a_r[2] * _r[2]); // | ||||
R | ||||
_b[1] = (a_r[3] * _r[0] + a_r[4] * _r[1] + a_r[5] * _r[2]); // | ||||
G | ||||
_b[2] = (a_r[6] * _r[0] + a_r[7] * _r[1] + a_r[8] * _r[2]); // | ||||
B | ||||
*r = (unsigned int) (0x000000FF & *r) | | ||||
(unsigned int) (1.0 * _b[0]) | | ||||
((unsigned int) (1.0 * _b[1]))<<8 | | ||||
((unsigned int) (1.0 * _b[2]))<<16; | ||||
*r = (*l | *r); | ||||
} else { | ||||
/* original : AGBR | ||||
*r = (*l & 0xFFFFFF00) | (*r & 0x000000FF); | ||||
*/ | ||||
/* Right and Left as unsigned ints */ | ||||
/* CORRECT */ | ||||
_l[0] = (float)((*r & 0x000000FF)); | ||||
_l[1] = (float)((*r & 0x0000FF00) >> 8); | ||||
_l[2] = (float)((*r & 0x00FF0000) >> 16); | ||||
_r[0] = (float)((*l & 0x000000FF)); | ||||
_r[1] = (float)((*l & 0x0000FF00) >> 8); | ||||
_r[2] = (float)((*l & 0x00FF0000) >> 16); | ||||
_b[0] = (a_l[0] * _l[0] + a_l[1] * _l[1] + a_l[2] * _l[2]); // | ||||
R | ||||
_b[1] = (a_l[3] * _l[0] + a_l[4] * _l[1] + a_l[5] * _l[2]); // | ||||
G | ||||
_b[2] = (a_l[6] * _l[0] + a_l[7] * _l[1] + a_l[8] * _l[2]); // | ||||
B | ||||
*l = (unsigned int) (0xFF000000 & *l) | | ||||
(unsigned int) (1.0 * _b[0]) | | ||||
((unsigned int) (1.0 * _b[1]))<<8 | | ||||
((unsigned int) (1.0 * _b[2]))<<16; | ||||
_b[0] = (a_r[0] * _r[0] + a_r[1] * _r[1] + a_r[2] * _r[2]); // | ||||
R | ||||
_b[1] = (a_r[3] * _r[0] + a_r[4] * _r[1] + a_r[5] * _r[2]); // | ||||
G | ||||
_b[2] = (a_r[6] * _r[0] + a_r[7] * _r[1] + a_r[8] * _r[2]); // | ||||
B | ||||
*r = (unsigned int) (0xFF000000 & *r) | | ||||
(unsigned int) (1.0 * _b[0]) | | ||||
((unsigned int) (1.0 * _b[1]))<<8 | | ||||
((unsigned int) (1.0 * _b[2]))<<16; | ||||
*r = (*l | *r); | ||||
} | ||||
l++; | ||||
r++; | ||||
} | ||||
} | ||||
} | ||||
} | ||||
break; | ||||
case cStereo_stencil_by_row: | ||||
case cStereo_stencil_by_column: | ||||
case cStereo_stencil_checkerboard: | ||||
{ | ||||
/* merge the two images into one */ | ||||
unsigned char *merged_image = Alloc(unsigned char, I->Image->size); | ||||
unsigned int *q = (unsigned int *) merged_image; | ||||
unsigned int *l; | ||||
unsigned int *r; | ||||
int height, width; | ||||
int a, b; | ||||
int parity = 0; | ||||
if(I->StereoMode == cStereo_stencil_by_row) { | ||||
parity = I->StencilParity; | ||||
if(I->Block->rect.bottom & 0x1) | ||||
parity = 1 - parity; | ||||
} | ||||
l = (unsigned int *) stereo_image->data; | ||||
r = (unsigned int *) I->Image->data; | ||||
height = I->Image->height; | ||||
width = I->Image->width; | ||||
for(a = 0; a < height; a++) { | ||||
for(b = 0; b < width; b++) { | ||||
switch (I->StereoMode) { | ||||
case cStereo_stencil_by_row: | ||||
if((a + parity) & 0x1) { | ||||
*(q++) = *(l++); | ||||
r++; | ||||
} else { | ||||
*(q++) = *(r++); | ||||
l++; | ||||
} | ||||
break; | ||||
case cStereo_stencil_by_column: | ||||
if(b & 0x1) { | ||||
*(q++) = *(l++); | ||||
r++; | ||||
} else { | ||||
*(q++) = *(r++); | ||||
l++; | ||||
} | ||||
break; | ||||
case cStereo_stencil_checkerboard: | ||||
if((a + b) & 0x1) { | ||||
*(q++) = *(l++); | ||||
r++; | ||||
} else { | ||||
*(q++) = *(r++); | ||||
l++; | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
FreeP(I->Image->data); | ||||
I->Image->data = merged_image; | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
FreeP(stereo_image->data); | ||||
FreeP(stereo_image); | ||||
} | ||||
timing = UtilGetSeconds(G) - timing; | ||||
if(mode != 2) { /* don't show timings for tests */ | ||||
accumTiming += timing; | ||||
if(show_timing && !quiet) { | ||||
if(!G->Interrupt) { | ||||
PRINTFB(G, FB_Ray, FB_Details) | ||||
" Ray: render time: %4.2f sec. = %3.1f frames/hour (%4.2f sec. accum.) | ||||
.\n", | ||||
timing, 3600 / timing, accumTiming ENDFB(G); | ||||
} else { | ||||
PRINTFB(G, FB_Ray, FB_Details) | ||||
" Ray: render aborted.\n" ENDFB(G); | ||||
} | ||||
} | ||||
} | ||||
if(mode != 3) { | ||||
OrthoDirty(G); | ||||
} | ||||
/* EXPERIMENTAL VOLUME CODE */ | ||||
if (rayVolume) { | ||||
SceneUpdate(G, true); | ||||
} | ||||
OrthoBusyFast(G, 20, 20); | ||||
PyMOL_SetBusy(G->PyMOL, false); | ||||
return true; | ||||
} | ||||
/*========================================================================*/ | /*========================================================================*/ | |||
void SceneCopy(PyMOLGlobals * G, GLenum buffer, int force, int entire_window) | void SceneCopy(PyMOLGlobals * G, GLenum buffer, int force, int entire_window) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
unsigned int buffer_size; | unsigned int buffer_size; | |||
if (buffer == GL_BACK) { | ||||
buffer = G->DRAW_BUFFER0; | ||||
} | ||||
if(force || (!(I->StereoMode || | if(force || (!(I->StereoMode || | |||
SettingGetGlobal_b(G, cSetting_stereo_double_pump_mono) || I->B uttonsShown))) { | SettingGetGlobal_b(G, cSetting_stereo_double_pump_mono) || I->B uttonsShown))) { | |||
/* no copies while in stereo mode */ | /* no copies while in stereo mode */ | |||
if(force || ((!I->DirtyFlag) && (!I->CopyType))) { | if(force || ((!I->DirtyFlag) && (!I->CopyType))) { | |||
int x, y, w, h; | int x, y, w, h; | |||
if(entire_window) { | if(entire_window) { | |||
x = 0; | x = 0; | |||
y = 0; | y = 0; | |||
h = OrthoGetHeight(G); | h = OrthoGetHeight(G); | |||
w = OrthoGetWidth(G); | w = OrthoGetWidth(G); | |||
skipping to change at line 7530 | skipping to change at line 6325 | |||
int a, n = 0; | int a, n = 0; | |||
blocked = PAutoBlock(G); | blocked = PAutoBlock(G); | |||
PRINTFB(G, FB_Scene, FB_Blather) | PRINTFB(G, FB_Scene, FB_Blather) | |||
" Scene: updating objects with %d threads...\n", n_thread ENDFB(G); | " Scene: updating objects with %d threads...\n", n_thread ENDFB(G); | |||
info_list = PyList_New(n_total); | info_list = PyList_New(n_total); | |||
for(a = 0; a < n_total; a++) { | for(a = 0; a < n_total; a++) { | |||
PyList_SetItem(info_list, a, PyCObject_FromVoidPtr(Thread + a, NULL)); | PyList_SetItem(info_list, a, PyCObject_FromVoidPtr(Thread + a, NULL)); | |||
n++; | n++; | |||
} | } | |||
PXDecRef(PyObject_CallMethod | PXDecRef(PYOBJECT_CALLMETHOD | |||
(G->P_inst->cmd, "_object_update_spawn", "Oi", info_list, n_thread) ); | (G->P_inst->cmd, "_object_update_spawn", "Oi", info_list, n_thread) ); | |||
Py_DECREF(info_list); | Py_DECREF(info_list); | |||
PAutoUnblock(G, blocked); | PAutoUnblock(G, blocked); | |||
} | } | |||
} | } | |||
#endif | #endif | |||
static void SceneStencilCheck(PyMOLGlobals *G) | static void SceneStencilCheck(PyMOLGlobals *G) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
if( I->StereoMode == cStereo_stencil_by_row ) { | if( I->StereoMode == cStereo_stencil_by_row ) { | |||
int bottom = p_glutGet(P_GLUT_WINDOW_Y) + p_glutGet(P_GLUT_WINDOW_HEIGHT); | int bottom = 0; | |||
#ifndef _PYMOL_PRETEND_GLUT | ||||
if(G->Main) | ||||
#endif | ||||
bottom = p_glutGet(P_GLUT_WINDOW_Y) + p_glutGet(P_GLUT_WINDOW_HEIGHT); | ||||
int parity = bottom & 0x1; | int parity = bottom & 0x1; | |||
if(parity != I->StencilParity) { | if(parity != I->StencilParity) { | |||
I->StencilValid = false; | I->StencilValid = false; | |||
I->StencilParity = parity; | I->StencilParity = parity; | |||
SceneDirty(G); | SceneDirty(G); | |||
} | } | |||
} | } | |||
} | } | |||
void SceneUpdateObjectMoleculesSingleThread(PyMOLGlobals * G) | ||||
{ | ||||
// this function seems to be a relict, see PYMOL-2746 | ||||
// TODO: remove it for good if 1.8.2 beta testing shows no issues. | ||||
#if 0 | ||||
CScene *I = G->Scene; | ||||
ObjRec *rec = NULL; | ||||
while(ListIterate(I->Obj, rec, next)) { | ||||
if(rec->obj->type == cObjectMolecule) { | ||||
if(rec->obj->fUpdate) | ||||
rec->obj->fUpdate(rec->obj); | ||||
} | ||||
} | ||||
#endif | ||||
} | ||||
/*========================================================================*/ | /*========================================================================*/ | |||
void SceneUpdate(PyMOLGlobals * G, int force) | void SceneUpdate(PyMOLGlobals * G, int force) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
ObjRec *rec = NULL; | ||||
int cur_state = SettingGetGlobal_i(G, cSetting_state) - 1; | int cur_state = SettingGetGlobal_i(G, cSetting_state) - 1; | |||
int defer_builds_mode = SettingGetGlobal_i(G, cSetting_defer_builds_mode); | int defer_builds_mode = SettingGetGlobal_i(G, cSetting_defer_builds_mode); | |||
PRINTFD(G, FB_Scene) | PRINTFD(G, FB_Scene) | |||
" SceneUpdate: entered.\n" ENDFD; | " SceneUpdate: entered.\n" ENDFD; | |||
OrthoBusyPrime(G); | OrthoBusyPrime(G); | |||
WizardDoPosition(G, false); | WizardDoPosition(G, false); | |||
WizardDoView(G, false); | WizardDoView(G, false); | |||
EditorUpdate(G); | EditorUpdate(G); | |||
SceneStencilCheck(G); | SceneStencilCheck(G); | |||
if(defer_builds_mode == 0) { | if(defer_builds_mode == 0) { | |||
if(SettingGetGlobal_i(G, cSetting_draw_mode) == -2) { | if(SettingGetGlobal_i(G, cSetting_draw_mode) == -2) { | |||
defer_builds_mode = 1; | defer_builds_mode = 1; | |||
} | } | |||
} | } | |||
/* | ||||
if(defer_builds_mode) { | ||||
rec = NULL; | ||||
while(ListIterate(I->Obj, rec, next)) { | ||||
if(ObjectGetCurrentState(rec->obj, false) != cur_state) { | ||||
force = true; | ||||
break; | ||||
} | ||||
} | ||||
} | ||||
*/ | ||||
if(force || I->ChangedFlag || ((cur_state != I->LastStateBuilt) && | if(force || I->ChangedFlag || ((cur_state != I->LastStateBuilt) && | |||
(defer_builds_mode > 0))) { | (defer_builds_mode > 0))) { | |||
SceneCountFrames(G); | SceneCountFrames(G); | |||
if(force || (defer_builds_mode != 5)) { /* mode 5 == immediate mode */ | if(force || (defer_builds_mode != 5)) { /* mode 5 == immediate mode */ | |||
PyMOL_SetBusy(G->PyMOL, true); /* race condition -- may need to be fix ed */ | PyMOL_SetBusy(G->PyMOL, true); /* race condition -- may need to be fix ed */ | |||
/* update all gadgets first (single-threaded since they're thread-unsafe) */ | /* update all gadgets first (single-threaded since they're thread-unsafe) */ | |||
rec = NULL; | for ( auto it = I->GadgetObjs.begin(); it != I->GadgetObjs.end(); ++it) { | |||
while(ListIterate(I->Obj, rec, next)) { | (*it)->update(); | |||
if(rec->obj->type == cObjectGadget) { | ||||
if(rec->obj->fUpdate) | ||||
rec->obj->fUpdate(rec->obj); | ||||
} | ||||
} | } | |||
{ | { | |||
#ifndef _PYMOL_NOPY | #ifndef _PYMOL_NOPY | |||
int n_thread = SettingGetGlobal_i(G, cSetting_max_threads); | int n_thread = SettingGetGlobal_i(G, cSetting_max_threads); | |||
int multithread = SettingGetGlobal_i(G, cSetting_async_builds); | int multithread = SettingGetGlobal_i(G, cSetting_async_builds); | |||
if(multithread && (n_thread > 1)) { | if(multithread && (n_thread > 1)) { | |||
int min_start = -1; | int min_start = -1; | |||
int max_stop = -1; | int max_stop = -1; | |||
int n_frame = SceneGetNFrame(G, NULL); | int n_frame = SceneGetNFrame(G, NULL); | |||
int n_obj = 0; | int n_obj = 0; | |||
while(ListIterate(I->Obj, rec, next)) { | for ( auto it = I->Obj.begin(); it != I->Obj.end(); ++it) { | |||
int start = 0; | int start = 0; | |||
int stop = n_frame; | int stop = n_frame; | |||
n_obj++; | n_obj++; | |||
if(rec->obj->fGetNFrame) { | if((*it)->fGetNFrame) { | |||
stop = rec->obj->fGetNFrame(rec->obj); | stop = (*it)->fGetNFrame(*it); | |||
} | } | |||
/* set start/stop to define the range for this object | /* set start/stop to define the range for this object | |||
* depending upon various build settings */ | * depending upon various build settings */ | |||
ObjectAdjustStateRebuildRange(rec->obj, &start, &stop); | ObjectAdjustStateRebuildRange(*it, &start, &stop); | |||
if(min_start < 0) { | if(min_start < 0) { | |||
min_start = start; | min_start = start; | |||
max_stop = stop; | max_stop = stop; | |||
} else { | } else { | |||
if(min_start > start) | if(min_start > start) | |||
min_start = start; | min_start = start; | |||
if(max_stop < stop) | if(max_stop < stop) | |||
max_stop = stop; | max_stop = stop; | |||
} | } | |||
} | } | |||
skipping to change at line 7668 | skipping to change at line 6438 | |||
} | } | |||
if(n_thread < 1) | if(n_thread < 1) | |||
n_thread = 1; | n_thread = 1; | |||
} | } | |||
/* Note: we might want to optimize this by doing multi-threaded updates | /* Note: we might want to optimize this by doing multi-threaded updates | |||
for all objects. */ | for all objects. */ | |||
if(multithread && (n_thread > 1)) { | if(multithread && (n_thread > 1)) { | |||
/* multi-threaded geometry update */ | /* multi-threaded geometry update */ | |||
int cnt = 0; | int cnt = I->NonGadgetObjs.size(); | |||
rec = NULL; | ||||
while(ListIterate(I->Obj, rec, next)) | ||||
if(rec->obj->type != cObjectGadget) { | ||||
cnt++; | ||||
} | ||||
if(cnt) { | if(cnt) { | |||
CObjectUpdateThreadInfo *thread_info = Alloc(CObjectUpdateThreadInfo , cnt); | CObjectUpdateThreadInfo *thread_info = Alloc(CObjectUpdateThreadInfo , cnt); | |||
if(thread_info) { | if(thread_info) { | |||
cnt = 0; | cnt = 0; | |||
while(ListIterate(I->Obj, rec, next)) { | for ( auto it = I->NonGadgetObjs.begin(); it != I->NonGadgetObjs.e | |||
if(rec->obj->type != cObjectGadget) | nd(); ++it) { | |||
thread_info[cnt++].obj = rec->obj; | thread_info[cnt++].obj = *it; | |||
} | } | |||
SceneObjectUpdateSpawn(G, thread_info, n_thread, cnt); | SceneObjectUpdateSpawn(G, thread_info, n_thread, cnt); | |||
FreeP(thread_info); | FreeP(thread_info); | |||
} | } | |||
} | } | |||
} else | } else | |||
#endif | #endif | |||
{ | ||||
/* single-threaded update */ | /* single-threaded update */ | |||
rec = NULL; | for ( auto it = I->Obj.begin(); it != I->Obj.end(); ++it) { | |||
while(ListIterate(I->Obj, rec, next)) | (*it)->update(); | |||
if(rec->obj->fUpdate) | } | |||
rec->obj->fUpdate(rec->obj); | ||||
} | ||||
} | } | |||
PyMOL_SetBusy(G->PyMOL, false); /* race condition -- may need to be fix ed */ | PyMOL_SetBusy(G->PyMOL, false); /* race condition -- may need to be fix ed */ | |||
} else { /* defer builds mode == 5 -- for now, only update non-molecular obj ects */ | } else { /* defer builds mode == 5 -- for now, only update non-molecular obj ects */ | |||
/* single-threaded update */ | /* single-threaded update */ | |||
rec = NULL; | for ( auto it = I->Obj.begin(); it != I->Obj.end(); ++it) { | |||
while(ListIterate(I->Obj, rec, next)) { | if((*it)->type != cObjectMolecule) { | |||
if(rec->obj->type != cObjectMolecule) { | (*it)->update(); | |||
if(rec->obj->fUpdate) | ||||
rec->obj->fUpdate(rec->obj); | ||||
} | } | |||
} | } | |||
} | } | |||
I->ChangedFlag = false; | I->ChangedFlag = false; | |||
if((defer_builds_mode >= 2) && (force || (defer_builds_mode != 5)) && | if((defer_builds_mode >= 2) && (force || (defer_builds_mode != 5)) && | |||
(cur_state != I->LastStateBuilt)) { | (cur_state != I->LastStateBuilt)) { | |||
/* purge graphics representation when no longer used */ | /* purge graphics representation when no longer used */ | |||
if(I->LastStateBuilt >= 0) { | if(I->LastStateBuilt >= 0) { | |||
while(ListIterate(I->Obj, rec, next)) { | for ( auto it = I->Obj.begin(); it != I->Obj.end(); ++it) { | |||
if(rec->obj->fInvalidate && | if((*it)->fInvalidate && | |||
((rec->obj->type != cObjectMolecule) || force || defer_builds_mode | (((*it)->type != cObjectMolecule) || force || defer_builds_mode != | |||
!= 5)) { | 5)) { | |||
int static_singletons = | int static_singletons = | |||
SettingGet_b(G, rec->obj->Setting, NULL, cSetting_static_singleton s); | SettingGet_b(G, (*it)->Setting, NULL, cSetting_static_singletons); | |||
int async_builds = | int async_builds = | |||
SettingGet_b(G, rec->obj->Setting, NULL, cSetting_async_builds); | SettingGet_b(G, (*it)->Setting, NULL, cSetting_async_builds); | |||
int max_threads = | int max_threads = | |||
SettingGet_i(G, rec->obj->Setting, NULL, cSetting_max_threads); | SettingGet_i(G, (*it)->Setting, NULL, cSetting_max_threads); | |||
int nFrame = 0; | int nFrame = 0; | |||
if(rec->obj->fGetNFrame) | if((*it)->fGetNFrame) | |||
nFrame = rec->obj->fGetNFrame(rec->obj); | nFrame = (*it)->fGetNFrame(*it); | |||
else | else | |||
nFrame = 0; | nFrame = 0; | |||
if((nFrame > 1) || (!static_singletons)) { | if((nFrame > 1) || (!static_singletons)) { | |||
int start = I->LastStateBuilt; | int start = I->LastStateBuilt; | |||
int stop = start + 1; | int stop = start + 1; | |||
int ste; | int ste; | |||
if(async_builds && (max_threads > 1)) { | if(async_builds && (max_threads > 1)) { | |||
if((start / max_threads) == (cur_state / max_threads)) { | if((start / max_threads) == (cur_state / max_threads)) { | |||
stop = start; /* don't purge current batch */ | stop = start; /* don't purge current batch */ | |||
} else { | } else { | |||
int base = start / max_threads; /* now purge previous ba tch */ | int base = start / max_threads; /* now purge previous ba tch */ | |||
start = base * max_threads; | start = base * max_threads; | |||
stop = (base + 1) * max_threads; | stop = (base + 1) * max_threads; | |||
} | } | |||
} | } | |||
for(ste = start; ste < stop; ste++) { | for(ste = start; ste < stop; ste++) { | |||
rec->obj->fInvalidate(rec->obj, cRepAll, cRepInvPurge, ste); | (*it)->invalidate(cRepAll, cRepInvPurge, ste); | |||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
I->LastStateBuilt = cur_state; | I->LastStateBuilt = cur_state; | |||
WizardDoScene(G); | WizardDoScene(G); | |||
if(!MovieDefined(G)) { | if(!MovieDefined(G)) { | |||
if(SettingGetGlobal_i(G, cSetting_frame) != (cur_state + 1)) | if(SettingGetGlobal_i(G, cSetting_frame) != (cur_state + 1)) | |||
skipping to change at line 7775 | skipping to change at line 6533 | |||
{ | { | |||
/* sets up a cached image buffer is one is available, or if we are | /* sets up a cached image buffer is one is available, or if we are | |||
* using cached images by default */ | * using cached images by default */ | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
ImageType *image; | ImageType *image; | |||
int renderedFlag = false; | int renderedFlag = false; | |||
int draw_mode = SettingGetGlobal_i(G, cSetting_draw_mode); | int draw_mode = SettingGetGlobal_i(G, cSetting_draw_mode); | |||
PRINTFD(G, FB_Scene) | PRINTFD(G, FB_Scene) | |||
" SceneRenderCached: entered.\n" ENDFD; | " SceneRenderCached: entered.\n" ENDFD; | |||
CShaderMgr_Check_Reload(G); | G->ShaderMgr->Check_Reload(); | |||
if(I->DirtyFlag) { | if(I->DirtyFlag) { | |||
int moviePlaying = MoviePlaying(G); | int moviePlaying = MoviePlaying(G); | |||
if(I->MovieFrameFlag || (moviePlaying && SettingGetGlobal_b(G, cSetting_cach e_frames))) { | if(I->MovieFrameFlag || (moviePlaying && SettingGetGlobal_b(G, cSetting_cach e_frames))) { | |||
I->MovieFrameFlag = false; | I->MovieFrameFlag = false; | |||
image = MovieGetImage(G, | image = MovieGetImage(G, | |||
MovieFrameToImage(G, | MovieFrameToImage(G, | |||
SettingGetGlobal_i(G, cSetting_fra me) - 1)); | SettingGetGlobal_i(G, cSetting_fra me) - 1)); | |||
if(image) { | if(image) { | |||
if(I->Image && (!I->MovieOwnsImageFlag)) | if(I->Image && (!I->MovieOwnsImageFlag)) | |||
skipping to change at line 7797 | skipping to change at line 6555 | |||
I->MovieOwnsImageFlag = true; | I->MovieOwnsImageFlag = true; | |||
I->CopyType = true; | I->CopyType = true; | |||
I->Image = image; | I->Image = image; | |||
OrthoDirty(G); | OrthoDirty(G); | |||
renderedFlag = true; | renderedFlag = true; | |||
} else { | } else { | |||
SceneMakeMovieImage(G, true, false, cSceneImage_Default); | SceneMakeMovieImage(G, true, false, cSceneImage_Default); | |||
renderedFlag = true; | renderedFlag = true; | |||
} | } | |||
} else if(draw_mode == 3) { | } else if(draw_mode == 3) { | |||
int show_progress = SettingSetGlobal_i(G,cSetting_show_progress,0); | auto show_progress = SettingGet<int>(G, cSetting_show_progress); | |||
SettingSetGlobal_i(G, cSetting_show_progress, 0); | ||||
SceneRay(G, 0, 0, SettingGetGlobal_i(G, cSetting_ray_default_renderer), | SceneRay(G, 0, 0, SettingGetGlobal_i(G, cSetting_ray_default_renderer), | |||
NULL, NULL, 0.0F, 0.0F, false, NULL, false, -1); | NULL, NULL, 0.0F, 0.0F, false, NULL, false, -1); | |||
SettingSetGlobal_i(G,cSetting_show_progress, show_progress); | SettingSetGlobal_i(G,cSetting_show_progress, show_progress); | |||
} else if(moviePlaying && SettingGetGlobal_b(G, cSetting_ray_trace_frames)) { | } else if(moviePlaying && SettingGetGlobal_b(G, cSetting_ray_trace_frames)) { | |||
SceneRay(G, 0, 0, SettingGetGlobal_i(G, cSetting_ray_default_renderer), | SceneRay(G, 0, 0, SettingGetGlobal_i(G, cSetting_ray_default_renderer), | |||
NULL, NULL, 0.0F, 0.0F, false, NULL, true, -1); | NULL, NULL, 0.0F, 0.0F, false, NULL, true, -1); | |||
} else if((moviePlaying && SettingGetGlobal_b(G, cSetting_draw_frames)) || ( draw_mode == 2)) { | } else if((moviePlaying && SettingGetGlobal_b(G, cSetting_draw_frames)) || ( draw_mode == 2)) { | |||
SceneMakeSizedImage(G, 0, 0, SettingGetGlobal_i(G, cSetting_antialias)); | SceneMakeSizedImage(G, 0, 0, SettingGetGlobal_i(G, cSetting_antialias)); | |||
} else if(I->CopyType == true) { /* true vs. 2 */ | } else if(I->CopyType == true) { /* true vs. 2 */ | |||
renderedFlag = true; | renderedFlag = true; | |||
skipping to change at line 7831 | skipping to change at line 6590 | |||
float SceneGetSpecularValue(PyMOLGlobals * G, float spec, int limit) | float SceneGetSpecularValue(PyMOLGlobals * G, float spec, int limit) | |||
{ | { | |||
int n_light = SettingGetGlobal_i(G, cSetting_spec_count); | int n_light = SettingGetGlobal_i(G, cSetting_spec_count); | |||
if(n_light < 0) | if(n_light < 0) | |||
n_light = SettingGetGlobal_i(G, cSetting_light_count); | n_light = SettingGetGlobal_i(G, cSetting_light_count); | |||
if(n_light > limit) | if(n_light > limit) | |||
n_light = limit; | n_light = limit; | |||
if(n_light > 2) { | if(n_light > 2) { | |||
spec = spec / pow(n_light - 1, 0.6F); | spec = spec / pow(n_light - 1, 0.6F); | |||
} | } | |||
return spec; | return (spec > 1.F) ? 1.F : (spec < 0.F) ? 0.F : spec; | |||
} | } | |||
float SceneGetReflectScaleValue(PyMOLGlobals * G, int limit) | float SceneGetReflectScaleValue(PyMOLGlobals * G, int limit) | |||
{ | { | |||
float result = 1.0F; | float result = 1.0F; | |||
float _1 = 1.0F; | ||||
int n_light = SettingGetGlobal_i(G, cSetting_light_count); | int n_light = SettingGetGlobal_i(G, cSetting_light_count); | |||
if(n_light > limit) | if(n_light > limit) | |||
n_light = limit; | n_light = limit; | |||
if(n_light > 1) { | if(n_light > 1) { | |||
float tmp[3]; | float tmp[3]; | |||
float sum = 0.0F; | float sum = 0.0F; | |||
copy3f(SettingGetGlobal_3fv(G, cSetting_light), tmp); | for (int i = 0; i < n_light - 1; ++i) { | |||
normalize3f(tmp); | copy3f(SettingGetGlobal_3fv(G, light_setting_indices[i]), tmp); | |||
sum = _1 - tmp[2]; | ||||
if(n_light > 2) { | ||||
copy3f(SettingGetGlobal_3fv(G, cSetting_light2), tmp); | ||||
normalize3f(tmp); | normalize3f(tmp); | |||
sum += _1 - tmp[2]; | sum += 1.f - tmp[2]; | |||
if(n_light > 3) { | ||||
copy3f(SettingGetGlobal_3fv(G, cSetting_light3), tmp); | ||||
normalize3f(tmp); | ||||
sum += _1 - tmp[2]; | ||||
if(n_light > 4) { | ||||
copy3f(SettingGetGlobal_3fv(G, cSetting_light4), tmp); | ||||
normalize3f(tmp); | ||||
sum += _1 - tmp[2]; | ||||
if(n_light > 5) { | ||||
copy3f(SettingGetGlobal_3fv(G, cSetting_light5), tmp); | ||||
normalize3f(tmp); | ||||
sum += _1 - tmp[2]; | ||||
if(n_light > 6) { | ||||
copy3f(SettingGetGlobal_3fv(G, cSetting_light6), tmp); | ||||
normalize3f(tmp); | ||||
sum += _1 - tmp[2]; | ||||
if(n_light > 7) { | ||||
copy3f(SettingGetGlobal_3fv(G, cSetting_light7), tmp); | ||||
normalize3f(tmp); | ||||
sum += _1 - tmp[2]; | ||||
if(n_light > 8) { | ||||
copy3f(SettingGetGlobal_3fv(G, cSetting_light8), tmp); | ||||
normalize3f(tmp); | ||||
sum += _1 - tmp[2]; | ||||
} | ||||
if(n_light > 9) { | ||||
copy3f(SettingGetGlobal_3fv(G, cSetting_light9), tmp); | ||||
normalize3f(tmp); | ||||
sum += _1 - tmp[2]; | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | } | |||
sum *= 0.5; | sum *= 0.5; | |||
return result / sum; | return result / sum; | |||
} | } | |||
return result; | return result; | |||
} | } | |||
#define GET_COLOR_POSITION_AND_SET(settingname, gllight) \ | /* | |||
{ \ | * Get specular and shininess, adjusted to the number of lights. | |||
copy3f(SettingGetGlobal_3fv(G, cSetting_ ## settingname ), vv); \ | * | |||
normalize3f(vv); \ | * ptr_spec: specular for lights 2-N | |||
invert3f(vv); \ | * ptr_spec_power: shininess for lights 2-N | |||
glLightfv(GL_LIGHT ## gllight, GL_POSITION, vv); \ | * ptr_spec_direct: specular for light 1 | |||
} | * ptr_spec_direct_power: shininess for light 1 | |||
#define ENABLE_AND_SET_LIGHT_VALUES(gllight, spec_count_cmp) \ | */ | |||
{ \ | void SceneGetAdjustedLightValues(PyMOLGlobals * G, | |||
glEnable(GL_LIGHT ## gllight); \ | float *ptr_spec, | |||
if(spec_count >= spec_count_cmp) { \ | float *ptr_spec_power, | |||
glLightfv(GL_LIGHT ## gllight, GL_SPECULAR, spec); \ | float *ptr_spec_direct, | |||
} else { \ | float *ptr_spec_direct_power, | |||
glLightfv(GL_LIGHT ## gllight, GL_SPECULAR, zero); \ | int limit) | |||
} \ | { | |||
glLightfv(GL_LIGHT ## gllight, GL_AMBIENT, zero); \ | float specular = SettingGetGlobal_f(G, cSetting_specular); | |||
glLightfv(GL_LIGHT ## gllight, GL_DIFFUSE, diff); \ | if (specular == 1.0F) | |||
} | specular = SettingGetGlobal_f(G, cSetting_specular_intensity); | |||
#define DISABLE_LIGHT(gllight) \ | if (specular < R_SMALL4) | |||
glDisable(GL_LIGHT ## gllight); | specular = 0.0F; | |||
void SceneProgramLighting(PyMOLGlobals * G) | float spec_power = SettingGetGlobal_f(G, cSetting_spec_power); | |||
{ | if (spec_power < 0.0F) | |||
spec_power = SettingGetGlobal_f(G, cSetting_shininess); | ||||
/* load up the light positions relative to the camera while | ||||
MODELVIEW still has the identity */ | float spec_reflect = SettingGetGlobal_f(G, cSetting_spec_reflect); | |||
int n_light = SettingGetGlobal_i(G, cSetting_light_count); | if (spec_reflect < 0.0F) | |||
float direct = SettingGetGlobal_f(G, cSetting_direct); | spec_reflect = specular; | |||
float vv[4]; | ||||
float reflect = | float spec_direct = SettingGetGlobal_f(G, cSetting_spec_direct); | |||
SceneGetReflectScaleValue(G, 8) * SettingGetGlobal_f(G, cSetting_reflect); | if (spec_direct < 0.0F) | |||
float spec_value = SettingGetGlobal_f(G, cSetting_specular); | spec_direct = specular; | |||
if(spec_value == 1.0F) { | ||||
spec_value = SettingGetGlobal_f(G, cSetting_specular_intensity); | float spec_direct_power = SettingGetGlobal_f(G, cSetting_spec_direct_power); | |||
} | if (spec_direct_power < 0.0F) | |||
if(spec_value < R_SMALL4) | spec_direct_power = spec_power; | |||
spec_value = 0.0F; | ||||
spec_value = SceneGetSpecularValue(G, spec_value, 8); | *ptr_spec = SceneGetSpecularValue(G, spec_reflect, limit); | |||
*ptr_spec_power = spec_power; | ||||
// for programmable color quantification | *ptr_spec_direct = spec_direct > 1.F ? 1.F : spec_direct; | |||
auto pick_shading = SettingGet<bool>(G, cSetting_pick_shading); | *ptr_spec_direct_power = spec_direct_power; | |||
if (pick_shading) { | } | |||
n_light = 1; | ||||
direct = 0.f; | ||||
reflect = 0.f; | ||||
spec_value = 0.f; | ||||
} | ||||
/* lighting */ | ||||
vv[0] = 0.0F; | ||||
vv[1] = 0.0F; | ||||
vv[2] = 1.0F; | ||||
/* workaround for flickering of specular reflections on Mac OSX 10.3.8 with nV | ||||
idia hardware */ | ||||
vv[3] = 0.0F; | ||||
/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */ | ||||
#ifndef _MACPYMOL_XCODE | ||||
#ifdef _PYMOL_OSX | ||||
vv[3] = 0.000001F; | ||||
#endif | ||||
#endif | ||||
if (n_light < 0) | ||||
n_light = 0; | ||||
else if (n_light > 8){ | ||||
n_light = 8; | ||||
} | ||||
/* END PROPRIETARY CODE SEGMENT */ | ||||
glEnable(GL_LIGHTING); | ||||
glLightfv(GL_LIGHT0, GL_POSITION, vv); | ||||
/* workaround for flickering of specular reflections on Mac OSX 10.3.8 with nV | ||||
idia hardware */ | ||||
vv[3] = 0.0F; | ||||
switch (n_light){ | ||||
case 8: | ||||
GET_COLOR_POSITION_AND_SET(light7, 7); | ||||
case 7: | ||||
GET_COLOR_POSITION_AND_SET(light6, 6); | ||||
case 6: | ||||
GET_COLOR_POSITION_AND_SET(light5, 5); | ||||
case 5: | ||||
GET_COLOR_POSITION_AND_SET(light4, 4); | ||||
case 4: | ||||
GET_COLOR_POSITION_AND_SET(light3, 3); | ||||
case 3: | ||||
GET_COLOR_POSITION_AND_SET(light2, 2); | ||||
case 2: | ||||
GET_COLOR_POSITION_AND_SET(light, 1); | ||||
break; | ||||
default: | ||||
direct += reflect; | ||||
if(direct > 1.0F) | ||||
direct = 1.0F; | ||||
} | ||||
{ | ||||
int two_sided_lighting = SettingGetGlobal_b(G, cSetting_two_sided_lighting); | ||||
if(two_sided_lighting<0) { | ||||
if(SettingGetGlobal_i(G, cSetting_surface_cavity_mode)) | ||||
two_sided_lighting = true; | ||||
else | ||||
two_sided_lighting = false; | ||||
} | ||||
if(two_sided_lighting || | ||||
(SettingGetGlobal_i(G, cSetting_transparency_mode) == 1)) { | ||||
GLLIGHTMODELI(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); | ||||
} else { | ||||
GLLIGHTMODELI(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); | ||||
} | ||||
} | ||||
/* ambient lighting */ | ||||
white4f(vv, pick_shading ? 1.f : SettingGetGlobal_f(G, cSetting_ambient)); | ||||
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vv); | ||||
/* LIGHT0 is our direct light (eminating from the camera -- minus Z) */ | ||||
glEnable(GL_LIGHT0); | ||||
white4f(vv, 0.f); | ||||
glLightfv(GL_LIGHT0, GL_AMBIENT, vv); | ||||
white4f(vv, direct); | ||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, vv); | ||||
{ | ||||
float spec_direct = SettingGetGlobal_f(G, cSetting_spec_direct); | ||||
float spec[4] ; | ||||
if(spec_direct < 0.0F) { | ||||
white4f(spec, spec_value); | ||||
} else if(spec_direct > 0.0F) { | ||||
white4f(spec, spec_direct); | ||||
} else { | ||||
white4f(spec, 0.f); | ||||
} | ||||
glLightfv(GL_LIGHT0, GL_SPECULAR, spec); | ||||
} | ||||
/* LIGHTS1-3 are our reflected light (specular and diffuse | ||||
reflections from a movable directional lights) */ | ||||
{ | ||||
float spec[4]; | ||||
if(n_light > 1) { | ||||
float diff[4]; | ||||
float zero[4] = { 0.0F, 0.0F, 0.0F, 1.0F }; /* no ambient */ | ||||
int spec_count = SettingGetGlobal_i(G, cSetting_spec_count); | ||||
if(spec_count < 0) | ||||
spec_count = SettingGetGlobal_i(G, cSetting_light_count); | ||||
white4f(spec, spec_value); | ||||
white4f(diff, reflect); | ||||
switch (n_light){ | ||||
case 8: | ||||
ENABLE_AND_SET_LIGHT_VALUES(7, 7); | ||||
case 7: | ||||
ENABLE_AND_SET_LIGHT_VALUES(6, 6); | ||||
case 6: | ||||
ENABLE_AND_SET_LIGHT_VALUES(5, 5); | ||||
case 5: | ||||
ENABLE_AND_SET_LIGHT_VALUES(4, 4); | ||||
case 4: | ||||
ENABLE_AND_SET_LIGHT_VALUES(3, 3); | ||||
case 3: | ||||
ENABLE_AND_SET_LIGHT_VALUES(2, 2); | ||||
case 2: | ||||
ENABLE_AND_SET_LIGHT_VALUES(1, 1); | ||||
} | ||||
} | ||||
switch (n_light){ | ||||
case 0: | ||||
case 1: | ||||
DISABLE_LIGHT(1); | ||||
case 2: | ||||
DISABLE_LIGHT(2); | ||||
case 3: | ||||
DISABLE_LIGHT(3); | ||||
case 4: | ||||
DISABLE_LIGHT(4); | ||||
case 5: | ||||
DISABLE_LIGHT(5); | ||||
case 6: | ||||
DISABLE_LIGHT(6); | ||||
case 7: | ||||
DISABLE_LIGHT(7); | ||||
} | ||||
} | ||||
{ | ||||
float ones[4]; | ||||
white4f(ones, 1.0F); | ||||
glMaterialfv(GL_FRONT, GL_SPECULAR, ones); | ||||
} | ||||
glMaterialf(GL_FRONT, GL_SHININESS, SettingGetGlobal_f(G, cSetting_shininess)) | ||||
; | ||||
} | ||||
void SceneRenderAllObject(PyMOLGlobals * G, CScene *I, SceneUnitContext * contex | ||||
t, RenderInfo *info, float *normal, Picking ** pickVLA, int state, ObjRec *rec, | ||||
GridInfo * grid, int *slot_vla, int fat){ | ||||
short use_shader = (short) SettingGetGlobal_b(G, cSetting_use_shaders); | ||||
if(Feedback(G, FB_OpenGL, FB_Debugging)) | ||||
PyMOLCheckOpenGLErr("Before fRender iteration"); | ||||
if(SceneGetDrawFlag(grid, slot_vla, rec->obj->grid_slot)) { | ||||
glPushMatrix(); | ||||
if(fat) | ||||
glLineWidth(3.0); | ||||
switch (rec->obj->Context) { | ||||
case 1: /* unit context */ | ||||
{ | ||||
#ifndef _PYMOL_OSX | ||||
/* workaround for MacOSX 10.4.3 */ | ||||
glPushAttrib(GL_LIGHTING_BIT); | ||||
#endif | ||||
glMatrixMode(GL_PROJECTION); | ||||
glPushMatrix(); | ||||
glLoadIdentity(); | ||||
glMatrixMode(GL_MODELVIEW); | ||||
glPushMatrix(); | ||||
glLoadIdentity(); | ||||
{ | ||||
float vv[4] = { 0.f, 0.f, -1.f, 0.f }, dif[4] = { 1.f, 1.f, 1.f, 1.f }; | ||||
if (!use_shader){ | ||||
glLightfv(GL_LIGHT0, GL_POSITION, vv); | ||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, dif); | ||||
} | ||||
} | ||||
if(!grid->active) { | ||||
GLORTHO(context->unit_left, | ||||
context->unit_right, | ||||
context->unit_top, | ||||
context->unit_bottom, context->unit_front, context->unit_back); | ||||
} else { /* special unit context */ | ||||
GLORTHO(grid->context.unit_left, | ||||
grid->context.unit_right, | ||||
grid->context.unit_top, | ||||
grid->context.unit_bottom, | ||||
grid->context.unit_front, grid->context.unit_back); | ||||
} | ||||
glNormal3f(0.0F, 0.0F, 1.0F); | ||||
info->state = ObjectGetCurrentState(rec->obj, false); | ||||
rec->obj->fRender(rec->obj, info); | ||||
glMatrixMode(GL_PROJECTION); | ||||
glPopMatrix(); | ||||
glMatrixMode(GL_MODELVIEW); | ||||
glLoadIdentity(); | ||||
#ifndef _PYMOL_OSX | ||||
glPopAttrib(); | ||||
#else | ||||
/* workaround for MacOSX 10.4.3 */ | ||||
/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") | ||||
*/ | ||||
SceneProgramLighting(G); /* an expensive workaround... */ | ||||
if(pickVLA) { | ||||
#ifndef PURE_OPENGL_ES_2 | ||||
glDisable(GL_FOG); | ||||
glDisable(GL_COLOR_MATERIAL); | ||||
glDisable(GL_LIGHTING); | ||||
glDisable(GL_DITHER); | ||||
glDisable(GL_BLEND); | ||||
glDisable(GL_LINE_SMOOTH); | ||||
glDisable(GL_POLYGON_SMOOTH); | ||||
#endif | ||||
if(G->Option->multisample) | ||||
glDisable(0x809D); /* GL_MULTISAMPLE_ARB */ | ||||
glShadeModel(GL_FLAT); | ||||
} | ||||
/* END PROPRIETARY CODE SEGMENT */ | ||||
#endif | ||||
glPopMatrix(); | ||||
} | ||||
break; | ||||
case 2: | ||||
break; | ||||
case 0: /* context/grid 0 is all slots */ | ||||
default: | ||||
if(Feedback(G, FB_OpenGL, FB_Debugging)) | ||||
if(normal) | ||||
#ifdef PURE_OPENGL_ES_2 | ||||
; | ||||
#else | ||||
glNormal3fv(normal); | ||||
#endif | ||||
if((!grid->active) || (grid->mode < 2)) { | ||||
info->state = ObjectGetCurrentState(rec->obj, false); | ||||
rec->obj->fRender(rec->obj, info); | ||||
} else if(grid->slot) { | ||||
auto obj = rec->obj; | ||||
if (grid->mode == 2) { | ||||
if((info->state = state + grid->slot - 1) >= 0) | ||||
obj->fRender(obj, info); | ||||
} else if (grid->mode == 3) { | ||||
info->state = grid->slot - obj->grid_slot - 1; | ||||
if (info->state >= 0 && info->state < obj->getNFrame()) | ||||
obj->fRender(obj, info); | ||||
} | ||||
} | ||||
break; | ||||
} | ||||
glPopMatrix(); | ||||
} | ||||
if(Feedback(G, FB_OpenGL, FB_Debugging)) | ||||
PyMOLCheckOpenGLErr("After fRender iteration"); | ||||
} | ||||
/*========================================================================*/ | ||||
static void SceneRenderAll(PyMOLGlobals * G, SceneUnitContext * context, | ||||
float *normal, Picking ** pickVLA, | ||||
int pass, int fat, float width_scale, | ||||
GridInfo * grid, int dynamic_pass) | ||||
{ | ||||
CScene *I = G->Scene; | ||||
ObjRec *rec = NULL; | ||||
int state = SceneGetState(G); | ||||
RenderInfo info; | ||||
UtilZeroMem(&info, sizeof(RenderInfo)); | ||||
info.pick = pickVLA; | ||||
info.pass = pass; | ||||
info.vertex_scale = I->VertexScale; | ||||
info.fog_start = I->FogStart; | ||||
info.fog_end = I->FogEnd; | ||||
info.pmv_matrix = I->PmvMatrix; | ||||
info.front = I->FrontSafe; | ||||
info.sampling = 1; | ||||
info.alpha_cgo = I->AlphaCGO; | ||||
info.ortho = SettingGetGlobal_b(G, cSetting_ortho); | ||||
if(I->StereoMode && dynamic_pass && (!info.pick)) { | ||||
int stereo_mode = SettingGetGlobal_i(G, cSetting_stereo_mode); | ||||
switch (stereo_mode) { | ||||
case cStereo_dynamic: | ||||
case cStereo_clone_dynamic: | ||||
info.line_lighting = true; | ||||
break; | ||||
} | ||||
} | ||||
if(I->StereoMode) { | ||||
float buffer; | ||||
float stAng, stShift; | ||||
stAng = SettingGetGlobal_f(G, cSetting_stereo_angle); | ||||
stShift = SettingGetGlobal_f(G, cSetting_stereo_shift); | ||||
stShift = (float) (stShift * fabs(I->Pos[2]) / 100.0); | ||||
stAng = (float) (stAng * atan(stShift / fabs(I->Pos[2])) * 90.0 / cPI); | ||||
buffer = fabs(I->Width * I->VertexScale * tan(cPI * stAng / 180.0)); | ||||
info.stereo_front = I->FrontSafe + buffer; | ||||
} else { | ||||
info.stereo_front = I->FrontSafe; | ||||
} | ||||
info.back = I->BackSafe; | ||||
SceneGetViewNormal(G, info.view_normal); | ||||
if(info.alpha_cgo && (pass == 1)) { | ||||
CGOReset(info.alpha_cgo); | ||||
CGOSetZVector(info.alpha_cgo, I->ModMatrix[2], I->ModMatrix[6], I->ModMatrix | ||||
[10]); | ||||
} | ||||
if(SettingGetGlobal_b(G, cSetting_dynamic_width)) { | ||||
info.dynamic_width = true; | ||||
info.dynamic_width_factor = SettingGetGlobal_f(G, cSetting_dynamic_width_fac | ||||
tor); | ||||
info.dynamic_width_min = SettingGetGlobal_f(G, cSetting_dynamic_width_min); | ||||
info.dynamic_width_max = SettingGetGlobal_f(G, cSetting_dynamic_width_max); | ||||
} | ||||
if(width_scale != 0.0F) { | ||||
info.width_scale_flag = true; | ||||
info.width_scale = width_scale; | ||||
info.sampling = (int) info.width_scale; | ||||
if(info.sampling < 1) | ||||
info.sampling = 1; | ||||
} | ||||
{ | ||||
int *slot_vla = I->SlotVLA; | ||||
while(ListIterate(I->Obj, rec, next)) { | ||||
/* EXPERIMENTAL RAY-VOLUME COMPOSITION CODE */ | ||||
/* if(rec->obj->fRender) { */ | ||||
if(rec->obj->fRender && (!rayVolume || rec->obj->type==cObjectVolume)) { | ||||
SceneRenderAllObject(G, I, context, &info, normal, pickVLA, state, rec, g | ||||
rid, slot_vla, fat); | ||||
} | ||||
} | ||||
} | ||||
if(info.alpha_cgo) { | ||||
CGOStop(info.alpha_cgo); | ||||
/* this only works when all objects are rendered in the same frame of refere | ||||
nce */ | ||||
if(pass == -1) { | ||||
CGORenderGLAlpha(info.alpha_cgo, &info); | ||||
} | ||||
} | ||||
} | ||||
#ifdef _PYMOL_SHARP3D | ||||
void sharp3d_begin_left_stereo(void); | ||||
void sharp3d_switch_to_right_stereo(void); | ||||
void sharp3d_end_stereo(void); | ||||
#endif | ||||
int GetPowerOfTwoLargeEnough(float val){ | ||||
int ret, incr = 0; | ||||
while ((ret = pow(2, incr++)) < val); | ||||
return ret; | ||||
} | ||||
void PrepareViewPortForStereo(PyMOLGlobals * G, CScene *I, int stereo_mode, shor | ||||
t offscreen, int times, int x, int y, int oversize_width, int oversize_height){ | ||||
switch (stereo_mode) { | ||||
case cStereo_quadbuffer: /* hardware */ | ||||
OrthoDrawBuffer(G, GL_BACK_LEFT); | ||||
break; | ||||
case cStereo_crosseye: /* side by side, crosseye */ | ||||
if (offscreen){ | ||||
glViewport(I->offscreen_width / 2, 0, I->offscreen_width / 2, | ||||
I->offscreen_height); | ||||
} else if(oversize_width && oversize_height) { | ||||
glViewport(I->Block->rect.left + oversize_width / 2 + x, | ||||
I->Block->rect.bottom + y, | ||||
oversize_width / 2, oversize_height); | ||||
} else { | ||||
glViewport(I->Block->rect.left + I->Width / 2, I->Block->rect.bottom, | ||||
I->Width / 2, I->Height); | ||||
} | ||||
break; | ||||
case cStereo_walleye: | ||||
case cStereo_sidebyside: | ||||
if (offscreen){ | ||||
glViewport(0, 0, I->offscreen_width / 2, | ||||
I->offscreen_height); | ||||
} else if(oversize_width && oversize_height) { | ||||
glViewport(I->Block->rect.left + x, | ||||
I->Block->rect.bottom + y, | ||||
oversize_width / 2, oversize_height); | ||||
} else { | ||||
glViewport(I->Block->rect.left, I->Block->rect.bottom, I->Width / 2, | ||||
I->Height); | ||||
} | ||||
break; | ||||
case cStereo_geowall: | ||||
if (offscreen){ | ||||
glViewport(0, 0, I->offscreen_width / 2, | ||||
I->offscreen_height); | ||||
} else { | ||||
glViewport(I->Block->rect.left, I->Block->rect.bottom, I->Width, I->Height | ||||
); | ||||
} | ||||
break; | ||||
case cStereo_stencil_by_row: | ||||
case cStereo_stencil_by_column: | ||||
case cStereo_stencil_checkerboard: | ||||
if(I->StencilValid) { | ||||
glStencilFunc(GL_EQUAL, 1, 1); | ||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); | ||||
glEnable(GL_STENCIL_TEST); | ||||
} | ||||
break; | ||||
case cStereo_stencil_custom: | ||||
#ifdef _PYMOL_SHARP3D | ||||
sharp3d_begin_left_stereo(); | ||||
#endif | ||||
break; | ||||
case cStereo_anaglyph: | ||||
/* glClear(GL_ACCUM_BUFFER_BIT); */ | ||||
glColorMask(true, false, false, true); | ||||
break; | ||||
case cStereo_clone_dynamic: | ||||
glClear(GL_ACCUM_BUFFER_BIT); | ||||
OrthoDrawBuffer(G, GL_BACK_LEFT); | ||||
if(times) { | ||||
float dynamic_strength = | ||||
SettingGetGlobal_f(G, cSetting_stereo_dynamic_strength); | ||||
float vv[4] = { 0.75F, 0.75F, 0.75F, 1.0F }; | ||||
vv[0] = dynamic_strength; | ||||
vv[1] = dynamic_strength; | ||||
vv[2] = dynamic_strength; | ||||
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, vv); | ||||
glAccum(GL_ADD, 0.5); | ||||
glDisable(GL_FOG); | ||||
} | ||||
break; | ||||
case cStereo_dynamic: | ||||
if(times) { | ||||
float dynamic_strength = | ||||
SettingGetGlobal_f(G, cSetting_stereo_dynamic_strength); | ||||
float vv[4] = { 0.75F, 0.75F, 0.75F, 1.0F }; | ||||
vv[0] = dynamic_strength; | ||||
vv[1] = dynamic_strength; | ||||
vv[2] = dynamic_strength; | ||||
glClearAccum(0.5, 0.5, 0.5, 0.5); | ||||
glClear(GL_ACCUM_BUFFER_BIT); | ||||
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, vv); | ||||
glDisable(GL_FOG); | ||||
glViewport(I->Block->rect.left + G->Option->winX / 2, | ||||
I->Block->rect.bottom, I->Width, I->Height); | ||||
} else { | ||||
glClearAccum(0.0, 0.0, 0.0, 0.0); | ||||
glClear(GL_ACCUM_BUFFER_BIT); | ||||
glViewport(I->Block->rect.left, | ||||
I->Block->rect.bottom, I->Width, I->Height); | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
void PrepareViewPortForStereo2nd(PyMOLGlobals * G, CScene *I, int stereo_mode, s | ||||
hort offscreen, int times, int x, int y, int oversize_width, int oversize_height | ||||
){ | ||||
switch (stereo_mode) { | ||||
case cStereo_quadbuffer: /* hardware */ | ||||
OrthoDrawBuffer(G, GL_BACK_RIGHT); | ||||
break; | ||||
case cStereo_crosseye: /* side by side, crosseye */ | ||||
if (offscreen){ | ||||
glViewport(0, 0, I->offscreen_width / 2, | ||||
I->offscreen_height); | ||||
} else if(oversize_width && oversize_height) { | ||||
glViewport(I->Block->rect.left + x, | ||||
I->Block->rect.bottom + y, | ||||
oversize_width / 2, oversize_height); | ||||
} else { | ||||
glViewport(I->Block->rect.left, I->Block->rect.bottom, I->Width / 2, | ||||
I->Height); | ||||
} | ||||
break; | ||||
case cStereo_walleye: /* side by side, walleye */ | ||||
case cStereo_sidebyside: | ||||
if (offscreen){ | ||||
glViewport(I->offscreen_width / 2, 0, I->offscreen_width / 2, | ||||
I->offscreen_height); | ||||
} else if(oversize_width && oversize_height) { | ||||
glViewport(I->Block->rect.left + oversize_width / 2 + x, | ||||
I->Block->rect.bottom + y, | ||||
oversize_width / 2, oversize_height); | ||||
} else { | ||||
glViewport(I->Block->rect.left + I->Width / 2, I->Block->rect.bottom, | ||||
I->Width / 2, I->Height); | ||||
} | ||||
break; | ||||
case cStereo_geowall: /* geowall */ | ||||
if (offscreen){ | ||||
glViewport(I->offscreen_width / 2, 0, I->offscreen_width / 2, | ||||
I->offscreen_height); | ||||
} else { | ||||
glViewport(I->Block->rect.left + G->Option->winX / 2, | ||||
I->Block->rect.bottom, I->Width, I->Height); | ||||
} | ||||
break; | ||||
case cStereo_stencil_by_row: | ||||
case cStereo_stencil_by_column: | ||||
case cStereo_stencil_checkerboard: | ||||
glStencilFunc(GL_EQUAL, 0, 1); | ||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); | ||||
glEnable(GL_STENCIL_TEST); | ||||
break; | ||||
case cStereo_stencil_custom: | ||||
#ifdef _PYMOL_SHARP3D | ||||
sharp3d_switch_to_right_stereo(); | ||||
#endif | ||||
break; | ||||
case cStereo_anaglyph: | ||||
/* glAccum(GL_ACCUM, 0.5); */ | ||||
glColorMask(false, true, true, true); | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
break; | ||||
case cStereo_clone_dynamic: | ||||
if(times) { | ||||
glAccum(GL_ACCUM, -0.5); | ||||
} else { | ||||
glAccum(GL_ACCUM, 0.5); | ||||
} | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
break; | ||||
case cStereo_dynamic: | ||||
if(times) { | ||||
glAccum(GL_ACCUM, -0.5); | ||||
} else { | ||||
glAccum(GL_ACCUM, 0.5); | ||||
glEnable(GL_SCISSOR_TEST); | ||||
} | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
if(!times) { | ||||
glDisable(GL_SCISSOR_TEST); | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
void SetDrawBufferForStereo(PyMOLGlobals * G, CScene *I, int stereo_mode, int ti | ||||
mes, int fog_active){ | ||||
switch (stereo_mode) { | ||||
case cStereo_quadbuffer: | ||||
OrthoDrawBuffer(G, GL_BACK_LEFT); /* leave us in a stereo context | ||||
(avoids problems with cards than can't h | ||||
andle | ||||
use of mono contexts) */ | ||||
break; | ||||
case cStereo_crosseye: | ||||
case cStereo_walleye: | ||||
case cStereo_sidebyside: | ||||
OrthoDrawBuffer(G, GL_BACK); | ||||
break; | ||||
case cStereo_geowall: | ||||
break; | ||||
case cStereo_stencil_by_row: | ||||
case cStereo_stencil_by_column: | ||||
case cStereo_stencil_checkerboard: | ||||
glDisable(GL_STENCIL_TEST); | ||||
break; | ||||
case cStereo_stencil_custom: | ||||
#ifdef _PYMOL_SHARP3D | ||||
sharp3d_end_stereo(); | ||||
#endif | ||||
break; | ||||
case cStereo_anaglyph: | ||||
glColorMask(true, true, true, true); | ||||
/* glAccum(GL_ACCUM, 0.5); | ||||
glAccum(GL_RETURN, 1.0); */ | ||||
OrthoDrawBuffer(G, GL_BACK_LEFT); | ||||
break; | ||||
case cStereo_clone_dynamic: | ||||
glAccum(GL_ACCUM, 0.5); | ||||
if(times) { | ||||
float vv[4] = { 0.0F, 0.0F, 0.0F, 0.0F }; | ||||
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, vv); | ||||
if(fog_active) | ||||
glEnable(GL_FOG); | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
OrthoDrawBuffer(G, GL_BACK_RIGHT); | ||||
} | ||||
glAccum(GL_RETURN, 1.0); | ||||
OrthoDrawBuffer(G, GL_BACK_LEFT); | ||||
break; | ||||
case cStereo_dynamic: | ||||
glAccum(GL_ACCUM, 0.5); | ||||
if(times) { | ||||
float vv[4] = { 0.0F, 0.0F, 0.0F, 0.0F }; | ||||
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, vv); | ||||
if(fog_active) | ||||
glEnable(GL_FOG); | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
} | ||||
glAccum(GL_RETURN, 1.0); | ||||
if(times) { | ||||
glViewport(I->Block->rect.left, | ||||
I->Block->rect.bottom, I->Width + 2, I->Height + 2); | ||||
glScissor(I->Block->rect.left - 1, | ||||
I->Block->rect.bottom - 1, I->Width + 2, I->Height + 2); | ||||
glEnable(GL_SCISSOR_TEST); | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
glDisable(GL_SCISSOR_TEST); | ||||
} else { | ||||
glDisable(GL_SCISSOR_TEST); | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
void DoRendering(PyMOLGlobals * G, CScene *I, short offscreen, GridInfo *grid, i | ||||
nt times, int curState, float *normal, | ||||
SceneUnitContext *context, float width_scale, short renderTransp | ||||
arent, short onlySelections, short excludeSelections){ | ||||
int pass; | ||||
if(grid->active && !offscreen) | ||||
GridGetGLViewport(G, grid); | ||||
{ | ||||
int slot; | ||||
for(slot = 0; slot <= grid->last_slot; slot++) { | ||||
if(grid->active) { | ||||
GridSetGLViewport(grid, slot); | ||||
} | ||||
/* render picked atoms */ | ||||
/* render the debugging CGO */ | ||||
glPushMatrix(); /* 2 */ | ||||
if (!onlySelections) | ||||
EditorRender(G, curState); | ||||
glPopMatrix(); /* 1 */ | ||||
glPushMatrix(); /* 2 */ | ||||
if (!onlySelections){ | ||||
glNormal3fv(normal); | ||||
CGORenderGL(G->DebugCGO, NULL, NULL, NULL, NULL, NULL); | ||||
} | ||||
glPopMatrix(); /* 1 */ | ||||
glPushMatrix(); /* 2 */ | ||||
/* render all objects */ | ||||
if (!onlySelections){ | ||||
for(pass = 1; pass > -2; pass--) { /* render opaque, then antialia | ||||
sed, then transparent... */ | ||||
SceneRenderAll(G, context, normal, NULL, pass, false, width_scale, grid | ||||
, | ||||
times); | ||||
} | ||||
} | ||||
glPopMatrix(); /* 1 */ | ||||
/* render selections */ | ||||
glPushMatrix(); /* 2 */ | ||||
glNormal3fv(normal); | ||||
if (!excludeSelections){ | ||||
if (!grid->active || slot > 0){ /* slot 0 is the full screen in grid mode | ||||
, so don't render selections */ | ||||
int s = grid->active && grid->mode==1 ? slot : 0; | ||||
ExecutiveRenderSelections(G, curState, s, grid); | ||||
} | ||||
} | ||||
if (!onlySelections && renderTransparent){ | ||||
PRINTFD(G, FB_Scene) | ||||
" SceneRender: rendering transparent objects...\n" ENDFD; | ||||
/* render transparent */ | ||||
SceneRenderAll(G, context, normal, NULL, -1, false, width_scale, grid, 0) | ||||
; | ||||
} | ||||
glPopMatrix(); /* 1 */ | ||||
#endif | ||||
} | ||||
} | ||||
if(grid->active) | ||||
GridSetGLViewport(grid, -1); | ||||
} | ||||
void DoHandedStereo(PyMOLGlobals * G, CScene *I, void (*prepareViewPortForStereo | ||||
)(PyMOLGlobals *, CScene *, int, short, int, int, int, int, int), | ||||
int stereo_mode, short offscreen, int times, int x, int y, in | ||||
t oversize_width, int oversize_height, GLenum mode, int mono_as_quad_stereo, | ||||
int prepare_matrix_arg, GridInfo *grid, int curState, float * | ||||
normal, SceneUnitContext *context, | ||||
float width_scale, short clearDepthAfterPrepareMatrix, short | ||||
onlySelections, short excludeSelections){ | ||||
if(mono_as_quad_stereo) { | ||||
OrthoDrawBuffer(G, mode); | ||||
} else { | ||||
prepareViewPortForStereo(G, I, stereo_mode, offscreen, times, x, y, oversize | ||||
_width, oversize_height); | ||||
} | ||||
/* prepare the stereo transformation matrix */ | ||||
glPushMatrix(); /* 1 */ | ||||
bg_grad(G); | ||||
ScenePrepareMatrix(G, prepare_matrix_arg); | ||||
if (clearDepthAfterPrepareMatrix){ | ||||
/* not sure why this isn't here in the first call, i.e., left handed stereo | ||||
*/ | ||||
glClear(GL_DEPTH_BUFFER_BIT); | ||||
} | ||||
DoRendering(G, I, offscreen, grid, times, curState, normal, context, width_sca | ||||
le, 0, onlySelections, excludeSelections); | ||||
glPopMatrix(); /* 0 */ | ||||
} | ||||
void InitializeViewPort(PyMOLGlobals * G, CScene *I, int x, int y, int oversize_ | ||||
width, int oversize_height, | ||||
int *stereo_mode, int *stereo_using_mono_matrix, float *w | ||||
idth_scale){ | ||||
if(oversize_width && oversize_height) { | ||||
int want_view[4]; | ||||
int got_view[4]; | ||||
want_view[0] = I->Block->rect.left + x; | ||||
want_view[1] = I->Block->rect.bottom + y; | ||||
want_view[2] = oversize_width; | ||||
want_view[3] = oversize_height; | ||||
glViewport(want_view[0], want_view[1], want_view[2], want_view[3]); | ||||
glGetIntegerv(GL_VIEWPORT, (GLint *) (void *) got_view); | ||||
if((got_view[0] != want_view[0]) || | ||||
(got_view[1] != want_view[1]) || | ||||
(got_view[2] != want_view[2]) || (got_view[3] != want_view[3])) { | ||||
PRINTFB(G, FB_Scene, FB_Warnings) | ||||
"Scene-Warning: glViewport failure.\n" ENDFB(G); | ||||
} | ||||
switch (*stereo_mode) { | ||||
case cStereo_geowall: | ||||
*stereo_mode = 0; | ||||
break; | ||||
} | ||||
#if 0 // this disables anaglyph stereo | ||||
*stereo_using_mono_matrix = true; | ||||
#endif | ||||
*width_scale = ((float) (oversize_width)) / I->Width; | ||||
} else { | ||||
glViewport(I->Block->rect.left, I->Block->rect.bottom, I->Width, I->Height); | ||||
} | ||||
} | ||||
int SceneSetFog(PyMOLGlobals *G, float *fog){ | ||||
CScene *I = G->Scene; | ||||
int fog_active = false; | ||||
float *v; | ||||
float fog_density = SettingGetGlobal_f(G, cSetting_fog); | ||||
I->FogStart = (I->BackSafe - I->FrontSafe) * SettingGetGlobal_f(G, cSetting_fo | ||||
g_start) + I->FrontSafe; | ||||
if((fog_density > R_SMALL8) && (fog_density != 1.0F)) { | ||||
I->FogEnd = I->FogStart + (I->BackSafe - I->FogStart) / fog_density; | ||||
} else { | ||||
I->FogEnd = I->BackSafe; | ||||
} | ||||
v = ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_rgb)); | ||||
fog[0] = v[0]; | ||||
fog[1] = v[1]; | ||||
fog[2] = v[2]; | ||||
/* NOTE: this doesn't seem to work :( -- only raytracing can do this */ | ||||
fog[3] = (SettingGetGlobal_b(G, cSetting_opaque_background) ? 1.0F : 0.0F); | ||||
if(SettingGetGlobal_b(G, cSetting_depth_cue) && | ||||
!SettingGetGlobal_b(G, cSetting_pick_shading) && | ||||
(SettingGetGlobal_f(G, cSetting_fog) != 0.0F)) { | ||||
fog_active = true; | ||||
} else { | ||||
fog_active = false; | ||||
} | ||||
{ | ||||
CShaderPrg * shaderPrg = CShaderPrg_Get_Current_Shader(G); | ||||
if (shaderPrg){ | ||||
float fogScale = 1.0f / (I->FogEnd - I->FogStart); | ||||
CShaderPrg_Set1f(shaderPrg, "g_Fog_start", I->FogStart); | ||||
CShaderPrg_Set1f(shaderPrg, "g_Fog_end", I->FogEnd); | ||||
CShaderPrg_Set1f(shaderPrg, "g_Fog_scale", fogScale); | ||||
glDisable(GL_FOG); | ||||
} else { | ||||
glFogf(GL_FOG_MODE, GL_LINEAR); | ||||
glFogf(GL_FOG_START, I->FogStart); | ||||
glFogf(GL_FOG_END, I->FogEnd); | ||||
glFogf(GL_FOG_DENSITY, fog_density); | ||||
glFogfv(GL_FOG_COLOR, fog); | ||||
if (fog_active) | ||||
glEnable(GL_FOG); | ||||
else | ||||
glDisable(GL_FOG); | ||||
} | ||||
} | ||||
return fog_active; | ||||
} | ||||
void SceneDrawStencilInBuffer(PyMOLGlobals * G, CScene *I, int stereo_mode){ | ||||
GLint viewport[4]; | ||||
glGetIntegerv(GL_VIEWPORT, viewport); | ||||
glMatrixMode(GL_PROJECTION); | ||||
glPushMatrix(); | ||||
glLoadIdentity(); | ||||
glOrtho(0, viewport[2], 0, viewport[3], -10.0, 10.0); | ||||
glMatrixMode(GL_MODELVIEW); | ||||
glPushMatrix(); | ||||
glLoadIdentity(); | ||||
glTranslatef(0.33F, 0.33F, 0.0F); | ||||
glDisable(GL_ALPHA_TEST); | ||||
glDisable(GL_LIGHTING); | ||||
glDisable(GL_FOG); | ||||
glDisable(GL_NORMALIZE); | ||||
glDisable(GL_COLOR_MATERIAL); | ||||
glDisable(GL_LINE_SMOOTH); | ||||
glShadeModel(SettingGetGlobal_b(G, cSetting_pick_shading) ? GL_FLAT : GL_SMOOT | ||||
H); | ||||
glDisable(0x809D); /* GL_MULTISAMPLE_ARB */ | ||||
glDisable(GL_DEPTH_TEST); | ||||
glDisable(GL_DITHER); | ||||
glDisable(GL_BLEND); | ||||
glDisable(GL_STENCIL_TEST); | ||||
glClearStencil(0); | ||||
glColorMask(false, false, false, false); | ||||
glDepthMask(false); | ||||
glClear(GL_STENCIL_BUFFER_BIT); | ||||
glEnable(GL_STENCIL_TEST); | ||||
glStencilFunc(GL_ALWAYS, 1, 1); | ||||
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); | ||||
{ | ||||
int h = viewport[3], w = viewport[2]; | ||||
glLineWidth(1.0); | ||||
switch (stereo_mode) { | ||||
case cStereo_stencil_by_row: | ||||
{ | ||||
int parity = I->StencilParity; | ||||
int y; | ||||
#ifdef PURE_OPENGL_ES_2 | ||||
/* TODO */ | ||||
#else | ||||
glBegin(GL_LINES); | ||||
for(y = 0; y < h; y += 2) { | ||||
glVertex2i(0, y + parity); | ||||
glVertex2i(w, y + parity); | ||||
} | ||||
glEnd(); | ||||
#endif | ||||
} | ||||
break; | ||||
case cStereo_stencil_by_column: | ||||
{ | ||||
int x; | ||||
#ifdef PURE_OPENGL_ES_2 | ||||
/* TODO */ | ||||
#else | ||||
glBegin(GL_LINES); | ||||
for(x = 0; x < w; x += 2) { | ||||
glVertex2i(x, 0); | ||||
glVertex2i(x, h); | ||||
} | ||||
glEnd(); | ||||
#endif | ||||
} | ||||
break; | ||||
case cStereo_stencil_checkerboard: | ||||
{ | ||||
int i, m = 2 * ((h > w) ? h : w); | ||||
#ifdef PURE_OPENGL_ES_2 | ||||
/* TODO */ | ||||
#else | ||||
glBegin(GL_LINES); | ||||
for(i = 0; i < m; i += 2) { | ||||
glVertex2i(i, 0); | ||||
glVertex2i(0, i); | ||||
} | ||||
glEnd(); | ||||
#endif | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
glColorMask(true, true, true, true); | ||||
glDepthMask(true); | ||||
glMatrixMode(GL_MODELVIEW); | ||||
glPopMatrix(); | ||||
glMatrixMode(GL_PROJECTION); | ||||
glPopMatrix(); | ||||
} | ||||
void SceneRenderOffscreen(PyMOLGlobals *G, CScene *I, int offscreen, GridInfo *g | ||||
rid){ | ||||
/* Check to see if size needs to be different, if so, create new one */ | ||||
float multiplier = SettingGetGlobal_f(G, cSetting_offscreen_rendering_multipli | ||||
er); | ||||
int w, h; | ||||
short created = I->offscreen_width && I->offscreen_height; | ||||
w = GetPowerOfTwoLargeEnough(I->Width*multiplier); | ||||
h = GetPowerOfTwoLargeEnough(I->Height*multiplier); | ||||
if (I->offscreen_error){ | ||||
if (I->offscreen_width != w || I->offscreen_height != h){ | ||||
I->offscreen_error = 0; | ||||
} else { | ||||
offscreen = 0; | ||||
} | ||||
} | ||||
if (!I->offscreen_error && (!created || I->offscreen_width != w || I->offscree | ||||
n_height != h)){ | ||||
GLenum status; | ||||
if (created){ | ||||
/* need to clean up */ | ||||
PRINTFB(G, FB_Scene, FB_Blather) | ||||
" SceneRender: offscreen_rendering_for_antialiasing: size changed, \n | ||||
screen size: width=%d height=%d \n current offscreen size: width=%d h | ||||
eight=%d \n changing to offscreen size width=%d height=%d multiplier=%f\n | ||||
", I->Width, I->Height, I->offscreen_width, I->offscreen_height, w, h, multiplie | ||||
r ENDFB(G); | ||||
if (I->offscreen_fb){ | ||||
glDeleteFramebuffersEXT(1, &I->offscreen_fb); | ||||
I->offscreen_fb = 0; | ||||
} | ||||
if (I->offscreen_color_rb){ | ||||
glDeleteRenderbuffersEXT(1, &I->offscreen_color_rb); | ||||
I->offscreen_color_rb = 0; | ||||
} | ||||
if (I->offscreen_depth_rb){ | ||||
glDeleteRenderbuffersEXT(1, &I->offscreen_depth_rb); | ||||
I->offscreen_depth_rb = 0; | ||||
} | ||||
} else { | ||||
PRINTFB(G, FB_Scene, FB_Blather) | ||||
" SceneRender: offscreen_rendering_for_antialiasing: \n screen siz | ||||
e: width=%d height=%d\n offscreen size: width=%d height=%d multiplier=%f\ | ||||
n", I->Width, I->Height, w, h, multiplier ENDFB(G); | ||||
} | ||||
glGenFramebuffersEXT(1, &I->offscreen_fb); | ||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, I->offscreen_fb); | ||||
//Create and attach a color buffer | ||||
glGenRenderbuffersEXT(1, &I->offscreen_color_rb); | ||||
//We must bind color_rb before we call glRenderbufferStorageEXT | ||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, I->offscreen_color_rb); | ||||
//The storage format is RGBA8 | ||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, w, h); | ||||
//Attach color buffer to FBO | ||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, G | ||||
L_RENDERBUFFER_EXT, I->offscreen_color_rb); | ||||
//------------------------- | ||||
glGenRenderbuffersEXT(1, &I->offscreen_depth_rb); | ||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, I->offscreen_depth_rb); | ||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, w, h); | ||||
//------------------------- | ||||
//Attach depth buffer to FBO | ||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL | ||||
_RENDERBUFFER_EXT, I->offscreen_depth_rb); | ||||
//------------------------- | ||||
//Does the GPU support current FBO configuration? | ||||
status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); | ||||
/* ERROR CHECKING if offscreen frambuffer not created properly */ | ||||
PRINTFB(G, FB_Scene, FB_Debugging) | ||||
" SceneRender: glCheckFramebufferStatusEXT returns status=%d\n", | ||||
status ENDFB(G); | ||||
if (status!=GL_FRAMEBUFFER_COMPLETE_EXT ){ | ||||
GLint maxRenderbufferSize; | ||||
I->offscreen_error = 1; | ||||
offscreen = 0; | ||||
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &maxRenderbufferSize); | ||||
if (I->offscreen_width != w || I->offscreen_height != h){ | ||||
PRINTFB(G, FB_Scene, FB_Errors) | ||||
" SceneRender: offscreen_rendering_for_antialiasing: multiplier=%f erro | ||||
r creating offscreen buffers w=%d h=%d GL_MAX_RENDERBUFFER_SIZE_EXT=%d status=%d | ||||
\n", | ||||
multiplier, w, h, maxRenderbufferSize, status ENDFB(G); | ||||
} | ||||
I->offscreen_width = I->offscreen_height = 0; | ||||
if (I->offscreen_fb){ | ||||
glDeleteFramebuffersEXT(1, &I->offscreen_fb); | ||||
I->offscreen_fb = 0; | ||||
} | ||||
if (I->offscreen_color_rb){ | ||||
glDeleteRenderbuffersEXT(1, &I->offscreen_color_rb); | ||||
I->offscreen_color_rb = 0; | ||||
} | ||||
if (I->offscreen_depth_rb){ | ||||
glDeleteRenderbuffersEXT(1, &I->offscreen_depth_rb); | ||||
I->offscreen_depth_rb = 0; | ||||
} | ||||
} else { | ||||
I->offscreen_error = 0; | ||||
} | ||||
I->offscreen_width = w; | ||||
I->offscreen_height = h; | ||||
} | ||||
if (offscreen){ | ||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); | ||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, I->offscreen_fb); | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
if(grid->active){ | ||||
grid->cur_view[0] = grid->cur_view[1] = 0; | ||||
grid->cur_view[2] = I->offscreen_width; | ||||
grid->cur_view[3] = I->offscreen_height; | ||||
} | ||||
} | ||||
} | ||||
void SceneRenderRayVolume(CScene *I){ | ||||
glMatrixMode(GL_PROJECTION); | ||||
glPushMatrix(); | ||||
glLoadIdentity(); | ||||
glOrtho(0, I->Width, 0, I->Height, -100, 100); | ||||
glMatrixMode(GL_MODELVIEW); | ||||
glPushMatrix(); | ||||
glLoadIdentity(); | ||||
glRasterPos3f(0, 0, -1); | ||||
glDepthMask(GL_FALSE); | ||||
/* NEED TODO FOR _PYMOL_GL_DRAWARRAYS */ | ||||
if (I->Image && I->Image->data) | ||||
glDrawPixels(I->Width, I->Height, GL_RGBA, GL_UNSIGNED_BYTE, I->Image->data) | ||||
; | ||||
glDepthMask(GL_TRUE); | ||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); | ||||
glDepthFunc(GL_ALWAYS); | ||||
/* NEED TODO FOR _PYMOL_GL_DRAWARRAYS */ | ||||
glDrawPixels(I->Width, I->Height, GL_DEPTH_COMPONENT, GL_FLOAT, rayDepthPixels | ||||
); | ||||
glDepthFunc(GL_LESS); | ||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | ||||
glPopMatrix(); | ||||
glMatrixMode(GL_PROJECTION); | ||||
glPopMatrix(); | ||||
glMatrixMode(GL_MODELVIEW); | ||||
} | ||||
void SceneSetupGLPicking(PyMOLGlobals * G){ | ||||
/* picking mode: we want flat, unshaded, unblended, unsmooth colors */ | ||||
glDisable(GL_FOG); | ||||
glDisable(GL_COLOR_MATERIAL); | ||||
glDisable(GL_LIGHTING); | ||||
glDisable(GL_LINE_SMOOTH); | ||||
glDisable(GL_DITHER); | ||||
glDisable(GL_BLEND); | ||||
glDisable(GL_POLYGON_SMOOTH); | ||||
if(G->Option->multisample) | ||||
glDisable(0x809D); /* GL_MULTISAMPLE_ARB */ | ||||
glShadeModel(GL_FLAT); | ||||
} | ||||
/*========================================================================*/ | ||||
void SceneRender(PyMOLGlobals * G, Picking * pick, int x, int y, | ||||
Multipick * smp, int oversize_width, int oversize_height, | ||||
int click_side, int force_copy, int just_background) | ||||
{ | ||||
/* think in terms of the camera's world */ | ||||
CScene *I = G->Scene; | ||||
float fog[4]; | ||||
unsigned int lowBits, highBits; | ||||
unsigned int *lowBitVLA = NULL, *highBitVLA = NULL; | ||||
int high, low; | ||||
float zAxis[4] = { 0.0, 0.0, 1.0, 0.0 }; | ||||
float normal[4] = { 0.0, 0.0, 1.0, 0.0 }; | ||||
float aspRat = ((float) I->Width) / ((float) I->Height); | ||||
float height, width; | ||||
double start_time = 0.0; | ||||
int view_save[4]; | ||||
Picking *pickVLA, *pik; | ||||
int lastIndex = 0; | ||||
void *lastPtr = NULL; | ||||
int index; | ||||
int curState; | ||||
int nPick, nHighBits, nLowBits; | ||||
int must_render_stereo = false; | ||||
int mono_as_quad_stereo = false; | ||||
int stereo_using_mono_matrix = false; | ||||
int debug_pick = 0; | ||||
GLenum render_buffer; | ||||
SceneUnitContext context; | ||||
float width_scale = 0.0F; | ||||
int stereo_mode = I->StereoMode; | ||||
int stereo = SettingGetGlobal_i(G, cSetting_stereo); | ||||
int grid_mode = SettingGetGlobal_i(G, cSetting_grid_mode); | ||||
int fog_active = false; | ||||
int last_grid_active = I->grid.active; | ||||
int grid_size = 0; | ||||
PRINTFD(G, FB_Scene) | ||||
" SceneRender: entered. pick %p x %d y %d smp %p\n", | ||||
(void *) pick, x, y, (void *) smp ENDFD; | ||||
CShaderMgr_Check_Reload(G); | ||||
if(grid_mode) { | ||||
grid_size = SceneGetGridSize(G, grid_mode); | ||||
GridUpdate(&I->grid, aspRat, grid_mode, grid_size); | ||||
if(I->grid.active) | ||||
aspRat *= I->grid.asp_adjust; | ||||
} else { | ||||
I->grid.active = false; | ||||
} | ||||
if (last_grid_active != I->grid.active || grid_size != I->last_grid_size){ | ||||
// ExecutiveInvalidateRep(G, cKeywordAll, cRepLabel, cRepInvAll); | ||||
ShaderMgrResetUniformSet(G); | ||||
} | ||||
I->last_grid_size = grid_size; | ||||
CShaderMgr_FreeAllVBOs(G->ShaderMgr); | ||||
SceneUpdateAnimation(G); | ||||
if(SceneMustDrawBoth(G)) { | ||||
render_buffer = GL_BACK_LEFT; | ||||
} else { | ||||
render_buffer = GL_BACK; | ||||
} | ||||
switch (stereo_mode) { | ||||
case cStereo_walleye: | ||||
case cStereo_crosseye: | ||||
aspRat = aspRat / 2; | ||||
break; | ||||
} | ||||
if(G->HaveGUI && G->ValidContext) { | ||||
if(Feedback(G, FB_OpenGL, FB_Debugging)) | ||||
PyMOLCheckOpenGLErr("SceneRender checkpoint 0"); | ||||
must_render_stereo = (stereo && stereo_mode != 0); /* are we doing stereo | ||||
? */ | ||||
if(!must_render_stereo) { | ||||
if(G->StereoCapable && | ||||
SettingGet_i(G, NULL, NULL, cSetting_stereo_double_pump_mono)) { | ||||
/* force stereo rendering */ | ||||
must_render_stereo = true; | ||||
if(stereo_mode == 0) { | ||||
mono_as_quad_stereo = true; /* rendering stereo as mono */ | ||||
stereo_using_mono_matrix = true; | ||||
} | ||||
} else { | ||||
int st_mode = SettingGet_i(G, NULL, NULL, cSetting_stereo_mode); | ||||
if(st_mode == cStereo_geowall) { | ||||
stereo_mode = st_mode; | ||||
must_render_stereo = true; | ||||
stereo_using_mono_matrix = true; | ||||
} | ||||
} | ||||
} | ||||
/* if we seem to be configured for hardware stereo, | ||||
but can't actually do it, then fallback on mono -- | ||||
this would happen for instance if fullscreen is stereo-component | ||||
and windowed is not */ | ||||
if(must_render_stereo && (stereo_mode < cStereo_crosseye) && !(G->StereoCapa | ||||
ble)) { | ||||
must_render_stereo = false; | ||||
mono_as_quad_stereo = false; | ||||
} | ||||
if(must_render_stereo && stereo_via_stencil(stereo_mode)) { | ||||
if(!I->StencilValid) { | ||||
SceneDrawStencilInBuffer(G, I, stereo_mode); | ||||
I->StencilValid = true; | ||||
} | ||||
} | ||||
if(must_render_stereo) { | ||||
if(mono_as_quad_stereo) { /* double-pumped mono */ | ||||
OrthoDrawBuffer(G, GL_BACK_LEFT); | ||||
render_buffer = GL_BACK_LEFT; | ||||
} else { | ||||
switch (stereo_mode) { | ||||
case cStereo_quadbuffer: /* hardware stereo */ | ||||
case cStereo_clone_dynamic: | ||||
OrthoDrawBuffer(G, GL_BACK_LEFT); | ||||
render_buffer = GL_BACK_LEFT; | ||||
break; | ||||
default: /* some kind of software stereo */ | ||||
OrthoDrawBuffer(G, GL_BACK); | ||||
render_buffer = GL_BACK; | ||||
break; | ||||
} | ||||
} | ||||
} else { /* normal mono rendering */ | ||||
OrthoDrawBuffer(G, GL_BACK); | ||||
render_buffer = GL_BACK; | ||||
} | ||||
if(Feedback(G, FB_OpenGL, FB_Debugging)) | ||||
PyMOLCheckOpenGLErr("SceneRender checkpoint 1"); | ||||
glGetIntegerv(GL_VIEWPORT, (GLint *) (void *) view_save); | ||||
InitializeViewPort(G, I, x, y, oversize_width, oversize_height, &stereo_mode | ||||
, &stereo_using_mono_matrix, &width_scale); | ||||
if(!(pick || smp)) | ||||
bg_grad(G); | ||||
debug_pick = SettingGetGlobal_i(G, cSetting_debug_pick); | ||||
if(SettingGetGlobal_b(G, cSetting_line_smooth)) { | ||||
if(!(pick || smp || SettingGet<bool>(G, cSetting_pick_shading))) { | ||||
glEnable(GL_LINE_SMOOTH); | ||||
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); | ||||
} | ||||
} else { | ||||
glDisable(GL_LINE_SMOOTH); | ||||
} | ||||
glLineWidth(SettingGetGlobal_f(G, cSetting_line_width)); | ||||
glPointSize(SettingGetGlobal_f(G, cSetting_dot_width)); | ||||
glEnable(GL_NORMALIZE); /* get rid of this to boost performance */ | ||||
glEnable(GL_DEPTH_TEST); | ||||
/* get matrixes for unit objects */ | ||||
glMatrixMode(GL_PROJECTION); | ||||
glLoadIdentity(); | ||||
glMatrixMode(GL_MODELVIEW); | ||||
glLoadIdentity(); | ||||
/* must be done with identity MODELVIEW */ | ||||
SceneProgramLighting(G); | ||||
ScenePrepareUnitContext(&context, I->Width, I->Height); | ||||
/* do standard 3D objects */ | ||||
/* Set up the clipping planes */ | ||||
glMatrixMode(GL_PROJECTION); | ||||
glLoadIdentity(); | ||||
if(SettingGetGlobal_b(G, cSetting_all_states)) { | ||||
curState = -1; | ||||
} else { | ||||
curState = SettingGetGlobal_i(G, cSetting_state) - 1; | ||||
} | ||||
if(!SettingGetGlobal_b(G, cSetting_ortho)) { | ||||
height = I->FrontSafe * GetFovWidth(G) / 2.f; | ||||
width = height * aspRat; | ||||
glFrustum(-width, width, -height, height, I->FrontSafe, I->BackSafe); | ||||
} else { | ||||
height = std::max(R_SMALL4, -I->Pos[2]) * GetFovWidth(G) / 2.f; | ||||
width = height * aspRat; | ||||
GLORTHO(-width, width, -height, height, I->FrontSafe, I->BackSafe); | ||||
} | ||||
glMatrixMode(GL_MODELVIEW); | ||||
ScenePrepareMatrix(G, 0); | ||||
/* Save these for editing operations */ | ||||
glGetFloatv(GL_MODELVIEW_MATRIX, I->ModMatrix); | ||||
glGetFloatv(GL_PROJECTION_MATRIX, I->ProMatrix); | ||||
multiply44f44f44f(I->ModMatrix, I->ProMatrix, I->PmvMatrix); | ||||
/* get the Z axis vector for sorting transparent objects */ | ||||
if(SettingGetGlobal_b(G, cSetting_transparency_global_sort) && | ||||
SettingGetGlobal_b(G, cSetting_transparency_mode)) { | ||||
if(!I->AlphaCGO) | ||||
I->AlphaCGO = CGONew(G); | ||||
} else if(I->AlphaCGO) { | ||||
CGOFree(I->AlphaCGO); | ||||
I->AlphaCGO = NULL; | ||||
} | ||||
/* make note of how large pixels are at the origin */ | ||||
I->VertexScale = SceneGetScreenVertexScale(G, NULL); | ||||
/* determine the direction in which we are looking relative */ | ||||
/* 2. set the normals to reflect light back at the camera */ | ||||
MatrixInvTransformC44fAs33f3f(I->RotMatrix, zAxis, normal); | ||||
copy3f(normal, I->ViewNormal); | ||||
if(SettingGetGlobal_b(G, cSetting_normal_workaround)) { | ||||
I->LinesNormal[0] = 0.0; | ||||
I->LinesNormal[1] = 0.0; | ||||
I->LinesNormal[2] = 1.0; | ||||
/* for versions of GL that don't transform GL_LINES normals */ | ||||
} else { | ||||
I->LinesNormal[0] = I->ViewNormal[0]; | ||||
I->LinesNormal[1] = I->ViewNormal[1]; | ||||
I->LinesNormal[2] = I->ViewNormal[2]; | ||||
} | ||||
if(!(pick || smp)) { | ||||
glEnable(GL_BLEND); | ||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); | ||||
glEnable(GL_COLOR_MATERIAL); | ||||
glShadeModel(SettingGetGlobal_b(G, cSetting_pick_shading) ? GL_FLAT : GL_S | ||||
MOOTH); | ||||
glEnable(GL_DITHER); | ||||
glAlphaFunc(GL_GREATER, 0.05F); | ||||
glEnable(GL_ALPHA_TEST); | ||||
if(G->Option->multisample) | ||||
glEnable(0x809D); /* GL_MULTISAMPLE_ARB */ | ||||
fog_active = SceneSetFog(G, fog); | ||||
glColor4ub(255, 255, 255, 255); | ||||
glNormal3fv(normal); | ||||
} else { | ||||
SceneSetupGLPicking(G); | ||||
} | ||||
PRINTFD(G, FB_Scene) | ||||
" SceneRender: matrices loaded. rendering objects...\n" ENDFD; | ||||
/* 1. render all objects */ | ||||
if(pick || smp) { | ||||
switch (stereo_mode) { | ||||
case cStereo_crosseye: | ||||
case cStereo_walleye: | ||||
case cStereo_sidebyside: | ||||
glViewport(I->Block->rect.left, I->Block->rect.bottom, I->Width / 2, I-> | ||||
Height); | ||||
break; | ||||
case cStereo_geowall: | ||||
click_side = OrthoGetWrapClickSide(G); | ||||
break; | ||||
} | ||||
glPushMatrix(); /* 1 */ | ||||
{ | ||||
if(!stereo_using_mono_matrix) | ||||
switch (stereo_mode) { | ||||
case cStereo_crosseye: | ||||
ScenePrepareMatrix(G, (click_side > 0) ? 1 : 2); | ||||
break; | ||||
case cStereo_walleye: | ||||
case cStereo_geowall: | ||||
case cStereo_sidebyside: | ||||
ScenePrepareMatrix(G, (click_side < 0) ? 1 : 2); | ||||
break; | ||||
} | ||||
} | ||||
if(pick) { | ||||
/* atom picking HACK - obfuscative coding */ | ||||
SceneGLClearColor(0.0, 0.0, 0.0, 0.0); | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
pickVLA = VLACalloc(Picking, 5000); | ||||
pickVLA[0].src.index = 0; | ||||
pickVLA[0].src.bond = 0; | ||||
if(I->grid.active) | ||||
GridGetGLViewport(G, &I->grid); | ||||
{ | ||||
int slot; | ||||
for(slot = 0; slot <= I->grid.last_slot; slot++) { | ||||
if(I->grid.active) { | ||||
GridSetGLViewport(&I->grid, slot); | ||||
} | ||||
SceneRenderAll(G, &context, NULL, &pickVLA, 0, true, 0.0F, &I->grid, | ||||
0); | ||||
} | ||||
if(I->grid.active) | ||||
GridSetGLViewport(&I->grid, -1); | ||||
} | ||||
if(debug_pick) { | ||||
PyMOL_SwapBuffers(G->PyMOL); | ||||
PSleep(G, 1000000 * debug_pick / 4); | ||||
PyMOL_SwapBuffers(G->PyMOL); | ||||
} | ||||
lowBits = SceneFindTriplet(G, x, y, render_buffer); | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
SceneSetupGLPicking(G); | ||||
pickVLA[0].src.index = 0; | ||||
pickVLA[0].src.bond = 1; | ||||
{ | ||||
int slot; | ||||
for(slot = 0; slot <= I->grid.last_slot; slot++) { | ||||
if(I->grid.active) { | ||||
GridSetGLViewport(&I->grid, slot); | ||||
} | ||||
SceneRenderAll(G, &context, NULL, &pickVLA, 0, true, 0.0F, &I->grid, | ||||
0); | ||||
} | ||||
if(I->grid.active) | ||||
GridSetGLViewport(&I->grid, -1); | ||||
} | ||||
if(debug_pick) { | ||||
PyMOL_SwapBuffers(G->PyMOL); | ||||
PSleep(G, 1000000 * debug_pick / 4); | ||||
PyMOL_SwapBuffers(G->PyMOL); | ||||
} | ||||
highBits = SceneFindTriplet(G, x, y, render_buffer); | ||||
index = lowBits + (highBits << 12); | ||||
if(debug_pick) { | ||||
PRINTFB(G, FB_Scene, FB_Details) | ||||
" SceneClick-Detail: lowBits=%d highBits=%d index %d < %d?\n", lowBi | ||||
ts, highBits, index, pickVLA[0].src.index ENDFB(G); | ||||
} | ||||
if(index && (index <= pickVLA[0].src.index)) { | ||||
*pick = pickVLA[index]; /* return object info */ | ||||
if(debug_pick) { | ||||
PRINTFB(G, FB_Scene, FB_Details) | ||||
" SceneClick-Detail: obj %p index %d bond %d\n", | ||||
pick->context.object, pick->src.index, pick->src.bond ENDFB(G); | ||||
} | ||||
} else { | ||||
pick->context.object = NULL; | ||||
} | ||||
/* Picking changes the Shading model to GL_FLAT, | ||||
we need to change it back to GL_SMOOTH. This is because | ||||
bg_grad() might be called in OrthoDoDraw() before GL | ||||
settings are set in SceneRender() */ | ||||
// glEnable(GL_COLOR_MATERIAL); | ||||
glShadeModel(SettingGetGlobal_b(G, cSetting_pick_shading) ? GL_FLAT : GL_ | ||||
SMOOTH); | ||||
VLAFree(pickVLA); | ||||
} else if(smp) { | ||||
/* multiple atom picking HACK - even more obfuscative coding */ | ||||
SceneGLClearColor(0.0, 0.0, 0.0, 0.0); | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
pickVLA = VLACalloc(Picking, 5000); | /* | |||
pickVLA[0].src.index = 0; | * Shader attribute names | |||
pickVLA[0].src.bond = 0; /* this is just a flag for first pass */ | */ | |||
#define TEMPLATE(i) "g_LightSource[" #i "].position" | ||||
const char * lightsource_position_names[] = { | ||||
TEMPLATE(0), TEMPLATE(1), TEMPLATE(2), TEMPLATE(3), TEMPLATE(4), | ||||
TEMPLATE(5), TEMPLATE(6), TEMPLATE(7), TEMPLATE(8), TEMPLATE(9) | ||||
}; | ||||
#undef TEMPLATE | ||||
if(I->grid.active) | #define TEMPLATE(i) "g_LightSource[" #i "].diffuse" | |||
GridGetGLViewport(G, &I->grid); | const char * lightsource_diffuse_names[] = { | |||
{ | TEMPLATE(0), TEMPLATE(1), TEMPLATE(2), TEMPLATE(3), TEMPLATE(4), | |||
int slot; | TEMPLATE(5), TEMPLATE(6), TEMPLATE(7), TEMPLATE(8), TEMPLATE(9) | |||
for(slot = 0; slot <= I->grid.last_slot; slot++) { | }; | |||
if(I->grid.active) { | #undef TEMPLATE | |||
GridSetGLViewport(&I->grid, slot); | ||||
} | ||||
SceneRenderAll(G, &context, NULL, &pickVLA, 0, true, 0.0F, &I->grid, | ||||
0); | ||||
} | ||||
if(I->grid.active) | ||||
GridSetGLViewport(&I->grid, -1); | ||||
} | ||||
lowBitVLA = SceneReadTriplets(G, smp->x, smp->y, smp->w, smp->h, render_ | /* | |||
buffer); | * Sets up lighting for immediate mode if shaderPrg=NULL, otherwise | |||
* sets lighting uniforms for the given shader program. | ||||
* | ||||
* Supports up to light_count=8 | ||||
*/ | ||||
void SceneProgramLighting(PyMOLGlobals * G, CShaderPrg * shaderPrg) | ||||
{ | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | /* load up the light positions relative to the camera while | |||
MODELVIEW still has the identity */ | ||||
int n_light = glm::clamp(SettingGetGlobal_i(G, cSetting_light_count), 0, 8); | ||||
int spec_count = SettingGetGlobal_i(G, cSetting_spec_count); | ||||
float direct = SettingGetGlobal_f(G, cSetting_direct); | ||||
float reflect = SettingGetGlobal_f(G, cSetting_reflect) * SceneGetReflectScale | ||||
Value(G, n_light); | ||||
float spec[4]; | ||||
float diff[4]; | ||||
const float zero[4] = { 0.0F, 0.0F, 0.0F, 1.0F }; | ||||
float vv[4] = {0.F, 0.F, 1.F, 0.F}; // position | ||||
float spec_value, shine, spec_direct, spec_direct_power; | ||||
SceneGetAdjustedLightValues(G, | ||||
&spec_value, | ||||
&shine, | ||||
&spec_direct, | ||||
&spec_direct_power, | ||||
n_light); | ||||
pickVLA[0].src.index = 0; | if (n_light < 2) { | |||
pickVLA[0].src.bond = 1; /* this is just a flag for second pass * | direct += reflect; | |||
/ | if(direct > 1.0F) | |||
direct = 1.0F; | ||||
} | ||||
{ | if(spec_count < 0) { | |||
int slot; | spec_count = n_light; | |||
for(slot = 0; slot <= I->grid.last_slot; slot++) { | } | |||
if(I->grid.active) { | ||||
GridSetGLViewport(&I->grid, slot); | ||||
} | ||||
SceneRenderAll(G, &context, NULL, &pickVLA, 0, true, 0.0F, &I->grid, | ||||
0); | ||||
} | ||||
if(I->grid.active) | ||||
GridSetGLViewport(&I->grid, -1); | ||||
} | ||||
highBitVLA = SceneReadTriplets(G, smp->x, smp->y, smp->w, smp->h, render | ||||
_buffer); | ||||
nLowBits = VLAGetSize(lowBitVLA); | ||||
/* need to scissor this */ nHighBits = VLAGetSize(highBitVLA); | ||||
nPick = 0; | ||||
if(nLowBits && nHighBits) { | ||||
low = 0; | ||||
high = 0; | ||||
while((low < nLowBits) && (high < nHighBits)) { | ||||
if(lowBitVLA[low + 1] == highBitVLA[high + 1]) { | ||||
index = lowBitVLA[low] + (highBitVLA[high] << 12); | ||||
if(index && (index <= pickVLA[0].src.index)) { | ||||
pik = pickVLA + index; /* just using as a tmp */ | ||||
if((pik->src.index != lastIndex) || (pik->context.object != last | ||||
Ptr)) { | ||||
if(((CObject *) pik->context.object)->type == cObjectMolecule) | ||||
{ | ||||
nPick++; /* start from 1 */ | ||||
VLACheck(smp->picked, Picking, nPick); | ||||
smp->picked[nPick] = *pik; /* return atom/object info -- wi | ||||
ll be redundant */ | ||||
} | ||||
lastIndex = pik->src.index; | ||||
lastPtr = pik->context.object; | ||||
} | ||||
} | ||||
low += 2; | ||||
high += 2; | ||||
} else if(lowBitVLA[low + 1] < highBitVLA[high + 1]) | ||||
low += 2; | ||||
else | ||||
high += 2; | ||||
} | ||||
} | ||||
smp->picked[0].src.index = nPick; | // light 0 | |||
/* Picking changes the Shading model to GL_FLAT, | white4f(diff, SettingGetGlobal_f(G, cSetting_ambient)); | |||
we need to change it back to GL_SMOOTH. This is because | ||||
bg_grad() might be called in OrthoDoDraw() before GL | ||||
settings are set in SceneRender() */ | ||||
// glEnable(GL_COLOR_MATERIAL); | ||||
glShadeModel(SettingGetGlobal_b(G, cSetting_pick_shading) ? GL_FLAT : GL_ | ||||
SMOOTH); | ||||
VLAFree(pickVLA); | #ifndef PURE_OPENGL_ES_2 | |||
VLAFreeP(lowBitVLA); | if (!shaderPrg) { | |||
VLAFreeP(highBitVLA); | glEnable(GL_LIGHTING); | |||
} | glLightModelfv(GL_LIGHT_MODEL_AMBIENT, diff); | |||
glPopMatrix(); /* 1 */ | glLightfv(GL_LIGHT0, GL_POSITION, vv); | |||
glLightfv(GL_LIGHT0, GL_AMBIENT, zero); | ||||
if(direct > R_SMALL4) { | ||||
white4f(diff, direct); | ||||
white4f(spec, spec_direct); | ||||
glEnable(GL_LIGHT0); | ||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, diff); | ||||
glLightfv(GL_LIGHT0, GL_SPECULAR, spec); | ||||
} else { | } else { | |||
int times = 1, origtimes; | glLightfv(GL_LIGHT0, GL_DIFFUSE, zero); | |||
short offscreen = 0; | glLightfv(GL_LIGHT0, GL_SPECULAR, zero); | |||
/* STANDARD RENDERING */ | } | |||
} else | ||||
#if 0 | ||||
// DISABLED - implementation is buggy and replaced by SMAA/FXAA in Incenti | ||||
ve PyMOL | ||||
offscreen = SettingGetGlobal_b(G, cSetting_antialias_shader); | ||||
if(offscreen) { | ||||
SceneRenderOffscreen(G, I, offscreen, &I->grid); | ||||
} | ||||
#endif | #endif | |||
/* rendering for visualization */ | { | |||
shaderPrg->Set4fv("g_LightModel.ambient", diff); | ||||
white4f(diff, (direct > R_SMALL4) ? direct : 0.f); | ||||
shaderPrg->Set4fv(lightsource_diffuse_names[0], diff); | ||||
shaderPrg->Set4fv(lightsource_position_names[0], vv); | ||||
} | ||||
// light 1-N | ||||
white4f(spec, spec_value); | ||||
white4f(diff, reflect); | ||||
for (int i = 1; i < n_light; ++i) { | ||||
// normalized/inverted light direction | ||||
copy3f(SettingGetGlobal_3fv(G, light_setting_indices[i - 1]), vv); | ||||
normalize3f(vv); | ||||
invert3f(vv); | ||||
/*** THIS IS AN UGLY EXPERIMENTAL | #ifndef PURE_OPENGL_ES_2 | |||
*** VOLUME + RAYTRACING COMPOSITION CODE | if (!shaderPrg) { | |||
***/ | glEnable(GL_LIGHT0 + i); | |||
if (rayVolume && rayDepthPixels) { | glLightfv(GL_LIGHT0 + i, GL_POSITION, vv); | |||
SceneRenderRayVolume(I); | glLightfv(GL_LIGHT0 + i, GL_SPECULAR, (spec_count >= i) ? spec : zero); | |||
rayVolume--; | glLightfv(GL_LIGHT0 + i, GL_AMBIENT, zero); | |||
} | glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, diff); | |||
/*** END OF EXPERIMENTAL CODE ***/ | } else | |||
#endif | ||||
switch (stereo_mode) { | { | |||
case cStereo_clone_dynamic: | shaderPrg->Set4fv(lightsource_position_names[i], vv); | |||
case cStereo_dynamic: | shaderPrg->Set4fv(lightsource_diffuse_names[i], diff); | |||
times = 2; | } | |||
break; | } | |||
} | ||||
if (just_background) times = 0; | ||||
PRINTFD(G, FB_Scene) | ||||
" SceneRender: I->StereoMode %d must_render_stereo %d\n mono_as_quad_ | ||||
stereo %d StereoCapable %d\n", | ||||
stereo_mode, must_render_stereo, mono_as_quad_stereo, G->StereoCapable E | ||||
NDFD; | ||||
start_time = UtilGetSeconds(G); | #ifndef PURE_OPENGL_ES_2 | |||
origtimes = times; | if (!shaderPrg) { | |||
while(times--) { | // TODO: this was depending on two_sided_lighting, surface_cavity_mode | |||
if(must_render_stereo) { | // and transparency_mode | |||
/* STEREO RENDERING (real or double-pumped) */ | glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); | |||
PRINTFD(G, FB_Scene) | ||||
" SceneRender: left hand stereo...\n" ENDFD; | // disable unused lights | |||
/* LEFT HAND STEREO */ | for (int i = 7; i >= n_light; --i) { | |||
if (G->ShaderMgr && stereo_mode==cStereo_anaglyph) { | glDisable(GL_LIGHT0 + i); | |||
G->ShaderMgr->stereo_flag = -1; | } | |||
} | ||||
DoHandedStereo(G, I, PrepareViewPortForStereo, stereo_mode, offscreen, | ||||
times, x, y, oversize_width, oversize_height, | ||||
GL_BACK_LEFT, mono_as_quad_stereo, stereo_using_mono_mat | ||||
rix ? 0 : 1, &I->grid, curState, normal, &context, width_scale, 0, 0, offscreen) | ||||
; | ||||
PRINTFD(G, FB_Scene) | ||||
" SceneRender: right hand stereo...\n" ENDFD; | ||||
/* RIGHT HAND STEREO */ | ||||
if (G->ShaderMgr && stereo_mode==cStereo_anaglyph) { | ||||
G->ShaderMgr->stereo_flag = 1; | ||||
} | ||||
DoHandedStereo(G, I, PrepareViewPortForStereo2nd, stereo_mode, offscree | ||||
n, times, x, y, oversize_width, oversize_height, | ||||
GL_BACK_RIGHT, mono_as_quad_stereo, stereo_using_mono_ma | ||||
trix ? 0 : 2, &I->grid, curState, normal, &context, width_scale, 1, 0, offscreen | ||||
); | ||||
/* restore draw buffer */ | ||||
if(mono_as_quad_stereo) { /* double pumped mono...can't draw to GL | ||||
_BACK so stick with LEFT */ | ||||
OrthoDrawBuffer(G, GL_BACK_LEFT); | ||||
} else { | ||||
SetDrawBufferForStereo(G, I, stereo_mode, times, fog_active); | ||||
} | ||||
} else { | ||||
if (G->ShaderMgr) { | ||||
G->ShaderMgr->stereo_flag = 0; | ||||
} | ||||
/* MONOSCOPING RENDERING (not double-pumped) */ | // material | |||
if(!I->grid.active && offscreen) { | white4f(spec, 1.F); | |||
glViewport(0, 0, I->offscreen_width, I->offscreen_height); | glMaterialfv(GL_FRONT, GL_SPECULAR, spec); | |||
bg_grad(G); | glMaterialf(GL_FRONT, GL_SHININESS, glm::clamp(shine, 0.F, 128.F)); | |||
} | } | |||
#endif | ||||
} | ||||
if(Feedback(G, FB_OpenGL, FB_Debugging)) | #ifdef _PYMOL_SHARP3D | |||
PyMOLCheckOpenGLErr("Before mono rendering"); | void sharp3d_begin_left_stereo(void); | |||
DoRendering(G, I, offscreen, &I->grid, times, curState, normal, &contex | void sharp3d_switch_to_right_stereo(void); | |||
t, width_scale, 1, 0, offscreen); | void sharp3d_end_stereo(void); | |||
if(Feedback(G, FB_OpenGL, FB_Debugging)) | #endif | |||
PyMOLCheckOpenGLErr("during mono rendering"); | ||||
} | ||||
} | ||||
if(offscreen) { | ||||
int minx, miny; | ||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, I->offscreen_fb); | ||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); | ||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
if (stereo && stereo_mode == cStereo_geowall){ | ||||
minx = I->Block->rect.left; | ||||
miny = I->Block->rect.bottom; | ||||
glBlitFramebufferEXT (0, 0, I->offscreen_width / 2, I->offscreen_height | ||||
, | ||||
minx, miny, I->Width + minx, I->Height + miny, | ||||
GL_COLOR_BUFFER_BIT, GL_LINEAR ); | ||||
minx = I->Block->rect.left + G->Option->winX / 2; | ||||
miny = I->Block->rect.bottom; | ||||
glBlitFramebufferEXT (I->offscreen_width / 2, 0, I->offscreen_width, I- | ||||
>offscreen_height, | ||||
minx, miny, I->Width + minx, I->Height + miny, | ||||
GL_COLOR_BUFFER_BIT, GL_LINEAR ); | ||||
} else if(oversize_width && oversize_height) { | ||||
minx = I->Block->rect.left + x; | ||||
miny = I->Block->rect.bottom + y; | ||||
glBlitFramebufferEXT (0, 0, I->offscreen_width, I->offscreen_height, | ||||
minx, miny, minx + oversize_width, miny + oversiz | ||||
e_height, | ||||
GL_COLOR_BUFFER_BIT, GL_LINEAR ); | ||||
} else { | ||||
minx = I->Block->rect.left; | ||||
miny = I->Block->rect.bottom; | ||||
glBlitFramebufferEXT (0, 0, I->offscreen_width, I->offscreen_height, | ||||
minx, miny, I->Width + minx, I->Height + miny, | ||||
GL_COLOR_BUFFER_BIT, GL_LINEAR ); | ||||
} | ||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); | ||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0); | ||||
/* Here we render ONLY the SELECTED Markers, should we put all of this in | /* | |||
to a function, so it | * Set up the Scene Fog* member variables and immediate mode fog (incl. | |||
can be called above as well? */ | * gl_Fog struct for non-ES2 shaders) | |||
*/ | ||||
int SceneSetFog(PyMOLGlobals *G){ | ||||
CScene *I = G->Scene; | ||||
int fog_active = false; | ||||
float fog_density = SettingGetGlobal_f(G, cSetting_fog); | ||||
I->FogStart = (I->BackSafe - I->FrontSafe) * SettingGetGlobal_f(G, cSetting_fo | ||||
g_start) + I->FrontSafe; | ||||
if((fog_density > R_SMALL8) && (fog_density != 1.0F)) { | ||||
I->FogEnd = I->FogStart + (I->BackSafe - I->FogStart) / fog_density; | ||||
} else { | ||||
I->FogEnd = I->BackSafe; | ||||
} | ||||
InitializeViewPort(G, I, x, y, oversize_width, oversize_height, &stereo_m | if(SettingGetGlobal_b(G, cSetting_depth_cue) && fog_density != 0.0F) { | |||
ode, &stereo_using_mono_matrix, &width_scale); | fog_active = true; | |||
if(!must_render_stereo) | } | |||
bg_grad(G); | ||||
times = origtimes; | ||||
offscreen = 0; | ||||
while(times--) { | ||||
if(must_render_stereo) { | ||||
/* STEREO RENDERING (real or double-pumped) */ | ||||
PRINTFD(G, FB_Scene) | ||||
" SceneRender: left hand stereo...\n" ENDFD; | ||||
/* LEFT HAND STEREO */ | ||||
if (G->ShaderMgr && stereo_mode==cStereo_anaglyph) { | ||||
G->ShaderMgr->stereo_flag = -1; | ||||
} | ||||
DoHandedStereo(G, I, PrepareViewPortForStereo, stereo_mode, offscreen | #ifndef PURE_OPENGL_ES_2 | |||
, times, x, y, oversize_width, oversize_height, | if (ALWAYS_IMMEDIATE_OR(!SettingGetGlobal_b(G, cSetting_use_shaders))) { | |||
GL_BACK_LEFT, mono_as_quad_stereo, stereo_using_mono_m | const float *bg_rgb = ColorGet(G, SettingGetGlobal_color(G, cSetting_bg_rgb)); | |||
atrix ? 0 : 1, | float fog[4] = {bg_rgb[0], bg_rgb[1], bg_rgb[2], 1.0}; | |||
&I->grid, curState, normal, &context, width_scale, 0, | ||||
1 /* onlySelections */, 0); | glFogf(GL_FOG_MODE, GL_LINEAR); | |||
PRINTFD(G, FB_Scene) | glFogf(GL_FOG_START, I->FogStart); | |||
" SceneRender: right hand stereo...\n" ENDFD; | glFogf(GL_FOG_END, I->FogEnd); | |||
/* RIGHT HAND STEREO */ | glFogf(GL_FOG_DENSITY, fog_density > R_SMALL8 ? fog_density : 1.0F); | |||
if (G->ShaderMgr && stereo_mode==cStereo_anaglyph) { | glFogfv(GL_FOG_COLOR, fog); | |||
G->ShaderMgr->stereo_flag = 1; | if (fog_active) | |||
} | glEnable(GL_FOG); | |||
DoHandedStereo(G, I, PrepareViewPortForStereo2nd, stereo_mode, offscr | else | |||
een, times, x, y, oversize_width, oversize_height, | glDisable(GL_FOG); | |||
GL_BACK_RIGHT, mono_as_quad_stereo, stereo_using_mono_ | } | |||
matrix ? 0 : 2, | #endif | |||
&I->grid, curState, normal, &context, width_scale, 1, | ||||
1 /* onlySelections */, 0); | ||||
/* restore draw buffer */ | ||||
if(mono_as_quad_stereo) { /* double pumped mono...can't draw to G | ||||
L_BACK so stick with LEFT */ | ||||
OrthoDrawBuffer(G, GL_BACK_LEFT); | ||||
} else { | ||||
SetDrawBufferForStereo(G, I, stereo_mode, times, fog_active); | ||||
} | ||||
} else { | ||||
/* MONOSCOPING RENDERING (not double-pumped) */ | ||||
if(!I->grid.active && offscreen) { | ||||
glViewport(0, 0, I->offscreen_width, I->offscreen_height); | ||||
bg_grad(G); | ||||
} | ||||
if(Feedback(G, FB_OpenGL, FB_Debugging)) | return fog_active; | |||
PyMOLCheckOpenGLErr("Before mono rendering"); | } | |||
DoRendering(G, I, offscreen, &I->grid, times, curState, normal, &cont | ||||
ext, width_scale, 1, 1 /* onlySelections */, 0); | ||||
if(Feedback(G, FB_OpenGL, FB_Debugging)) | ||||
PyMOLCheckOpenGLErr("during mono rendering"); | ||||
} | ||||
} | ||||
/* FINISHED rendering selection markers */ | ||||
} | /* | |||
} | * Set the g_Fog_* uniforms for ES2 shaders | |||
*/ | ||||
void SceneSetFogUniforms(PyMOLGlobals * G, CShaderPrg * shaderPrg) { | ||||
CScene *I = G->Scene; | ||||
if (shaderPrg) { | ||||
float fogScale = 1.0f / (I->FogEnd - I->FogStart); | ||||
shaderPrg->Set1f("g_Fog_end", I->FogEnd); | ||||
shaderPrg->Set1f("g_Fog_scale", fogScale); | ||||
} | ||||
} | ||||
void SceneSetupGLPicking(PyMOLGlobals * G){ | ||||
/* picking mode: we want flat, unshaded, unblended, unsmooth colors */ | ||||
if(!(pick || smp)) { | ||||
glDisable(GL_FOG); | glDisable(GL_FOG); | |||
glDisable(GL_LIGHTING); | ||||
glDisable(GL_LIGHT0); | ||||
glDisable(GL_LIGHT1); | ||||
glDisable(GL_COLOR_MATERIAL); | glDisable(GL_COLOR_MATERIAL); | |||
glDisable(GL_LIGHTING); | ||||
glDisable(GL_LINE_SMOOTH); | ||||
glDisable(GL_DITHER); | glDisable(GL_DITHER); | |||
} | glDisable(GL_BLEND); | |||
glLineWidth(1.0); | glDisable(GL_POLYGON_SMOOTH); | |||
glDisable(GL_LINE_SMOOTH); | if(G->Option->multisample) | |||
glDisable(GL_BLEND); | glDisable(0x809D); /* GL_MULTISAMPLE_ARB */ | |||
glDisable(GL_NORMALIZE); | glShadeModel(GL_FLAT); | |||
glDisable(GL_DEPTH_TEST); | ||||
glDisable(GL_ALPHA_TEST); | ||||
if(G->Option->multisample) | ||||
glDisable(0x809D); /* GL_MULTISAMPLE_ARB */ | ||||
glViewport(view_save[0], view_save[1], view_save[2], view_save[3]); | ||||
if(Feedback(G, FB_OpenGL, FB_Debugging)) | ||||
PyMOLCheckOpenGLErr("SceneRender final checkpoint"); | ||||
} | ||||
PRINTFD(G, FB_Scene) | ||||
" SceneRender: rendering complete.\n" ENDFD; | ||||
if(!(pick || smp)) { /* update frames per second field */ | ||||
I->LastRender = UtilGetSeconds(G); | ||||
I->ApproxRenderTime = I->LastRender - start_time; | ||||
if(I->CopyNextFlag) { | ||||
start_time = I->LastRender - start_time; | ||||
if((start_time > 0.10) || (MainSavingUnderWhileIdle())) | ||||
if(!(ControlIdling(G))) | ||||
if(SettingGetGlobal_b(G, cSetting_cache_display)) { | ||||
if(!I->CopyType) { | ||||
SceneCopy(G, render_buffer, false, false); | ||||
} | ||||
} | ||||
} else { | ||||
I->CopyNextFlag = true; | ||||
} | ||||
if(force_copy && !(I->CopyType)) { | ||||
SceneCopy(G, render_buffer, true, false); | ||||
I->CopyType = 2; /* do not display force copies */ | ||||
} | ||||
} | ||||
PRINTFD(G, FB_Scene) | ||||
" SceneRender: leaving...\n" ENDFD; | ||||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
void SceneRestartFrameTimer(PyMOLGlobals * G) | void SceneRestartFrameTimer(PyMOLGlobals * G) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
I->LastFrameTime = UtilGetSeconds(G); | I->LastFrameTime = UtilGetSeconds(G); | |||
} | } | |||
static void SceneRestartPerfTimer(PyMOLGlobals * G) | static void SceneRestartPerfTimer(PyMOLGlobals * G) | |||
skipping to change at line 9660 | skipping to change at line 6890 | |||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
void ScenePrepareMatrix(PyMOLGlobals * G, int mode) | void ScenePrepareMatrix(PyMOLGlobals * G, int mode) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
float stAng, stShift; | float stAng, stShift; | |||
/* start afresh, looking in the negative Z direction (0,0,-1) from (0,0,0) */ | { | |||
glLoadIdentity(); | if (!mode){ | |||
SceneComposeModelViewMatrix(I, I->ModelViewMatrix); | ||||
if(!mode) { | } else { | |||
/* stereo */ | ||||
/* mono */ | float tmpMatrix[16]; | |||
stAng = SettingGetGlobal_f(G, cSetting_stereo_angle);// * cPI / 180.f; | ||||
/* move the camera to the location we are looking at */ | stShift = SettingGetGlobal_f(G, cSetting_stereo_shift); | |||
glTranslatef(I->Pos[0], I->Pos[1], I->Pos[2]); | ||||
stShift = (float) (stShift * fabs(I->Pos[2]) / 100.0); | ||||
/* rotate about the origin (the the center of rotation) */ | stAng = (float) (-stAng * atan(stShift / fabs(I->Pos[2])) / 2.f); | |||
glMultMatrixf(I->RotMatrix); | ||||
if(mode == 2) { /* left hand */ | ||||
/* move the origin to the center of rotation */ | stAng = -stAng; | |||
glTranslatef(-I->Origin[0], -I->Origin[1], -I->Origin[2]); | stShift = -stShift; | |||
} | ||||
} else { | ||||
/* stereo */ | ||||
stAng = SettingGetGlobal_f(G, cSetting_stereo_angle); | ||||
stShift = SettingGetGlobal_f(G, cSetting_stereo_shift); | ||||
/* right hand */ | ||||
stShift = (float) (stShift * fabs(I->Pos[2]) / 100.0); | PRINTFD(G, FB_Scene) | |||
stAng = (float) (stAng * atan(stShift / fabs(I->Pos[2])) * 90.0 / cPI); | " StereoMatrix-Debug: mode %d stAng %8.3f stShift %8.3f \n", mode, stAng, | |||
stShift | ||||
ENDFD; | ||||
identity44f(tmpMatrix); | ||||
identity44f(I->ModelViewMatrix); | ||||
MatrixRotateC44f(I->ModelViewMatrix, stAng, 0.f, 1.f, 0.f); | ||||
MatrixTranslateC44f(tmpMatrix, I->Pos[0] + stShift, I->Pos[1], I->Pos[2]); | ||||
MatrixMultiplyC44f(tmpMatrix, I->ModelViewMatrix); | ||||
MatrixMultiplyC44f(I->RotMatrix, I->ModelViewMatrix); | ||||
MatrixTranslateC44f(I->ModelViewMatrix, -I->Origin[0], -I->Origin[1], -I-> | ||||
Origin[2]); | ||||
if(mode == 2) { /* left hand */ | ||||
stAng = -stAng; | ||||
stShift = -stShift; | ||||
} | } | |||
} | ||||
PRINTFD(G, FB_Scene) | #ifndef PURE_OPENGL_ES_2 | |||
" StereoMatrix-Debug: mode %d stAng %8.3f stShift %8.3f \n", mode, stAng, | if (ALWAYS_IMMEDIATE_OR(!SettingGetGlobal_b(G, cSetting_use_shaders))) { | |||
stShift | glLoadMatrixf(I->ModelViewMatrix); | |||
ENDFD; | ||||
glRotatef(stAng, 0.0, 1.0, 0.0); | ||||
glTranslatef(I->Pos[0], I->Pos[1], I->Pos[2]); | ||||
glTranslatef(stShift, 0.0, 0.0); | ||||
/* rotate about the origin (the center of rotation) */ | ||||
glMultMatrixf(I->RotMatrix); | ||||
/* move the origin to the center of rotation */ | ||||
glTranslatef(-I->Origin[0], -I->Origin[1], -I->Origin[2]); | ||||
} | } | |||
#endif | ||||
} | } | |||
/*========================================================================*/ | /*========================================================================*/ | |||
static void SceneRotateWithDirty(PyMOLGlobals * G, float angle, float x, float y , float z, | static void SceneRotateWithDirty(PyMOLGlobals * G, float angle, float x, float y , float z, | |||
int dirty) | int dirty) | |||
{ | { | |||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
float temp[16]; | float temp[16]; | |||
int a; | int a; | |||
angle = (float) (-PI * angle / 180.0); | angle = (float) (-PI * angle / 180.0); | |||
skipping to change at line 9826 | skipping to change at line 7045 | |||
float pixel_scale_value = SettingGetGlobal_f(G, cSetting_ray_pixel_scale); | float pixel_scale_value = SettingGetGlobal_f(G, cSetting_ray_pixel_scale); | |||
if(pixel_scale_value < 0) | if(pixel_scale_value < 0) | |||
pixel_scale_value = 1.0F; | pixel_scale_value = 1.0F; | |||
/* the radius of the cylinders is the vertex_scale * ray_pixel_scale */ | /* the radius of the cylinders is the vertex_scale * ray_pixel_scale */ | |||
/* this turns out to be exactly right, but changes if the scene or user | /* this turns out to be exactly right, but changes if the scene or user | |||
moves */ | moves */ | |||
return info->vertex_scale * pixel_scale_value * line_width / 2.f; | return info->vertex_scale * pixel_scale_value * line_width / 2.f; | |||
} | } | |||
void ScenePushModelViewMatrix(PyMOLGlobals * G) { | ||||
CScene *I = G->Scene; | ||||
auto& stack = I->m_ModelViewMatrixStack; | ||||
auto& depth = I->m_ModelViewMatrixStackDepth; | ||||
stack.resize(16 * (depth + 1)); | ||||
copy44f(I->ModelViewMatrix, &stack[16 * depth++]); | ||||
} | ||||
void ScenePopModelViewMatrix(PyMOLGlobals * G, bool immediate) { | ||||
CScene *I = G->Scene; | ||||
auto& stack = I->m_ModelViewMatrixStack; | ||||
auto& depth = I->m_ModelViewMatrixStackDepth; | ||||
if (depth == 0) { | ||||
printf("ERROR: depth == 0\n"); | ||||
return; | ||||
} | ||||
copy44f(&stack[--depth * 16], I->ModelViewMatrix); | ||||
#ifndef PURE_OPENGL_ES_2 | ||||
if (ALWAYS_IMMEDIATE_OR(immediate)) { | ||||
glMatrixMode(GL_MODELVIEW); | ||||
glLoadMatrixf(I->ModelViewMatrix); | ||||
} | ||||
#endif | ||||
} | ||||
float *SceneGetModelViewMatrix(PyMOLGlobals * G){ | ||||
CScene *I = G->Scene; | ||||
return (I->ModelViewMatrix); | ||||
} | ||||
float *SceneGetProjectionMatrix(PyMOLGlobals * G){ | ||||
CScene *I = G->Scene; | ||||
return (I->ProjectionMatrix); | ||||
} | ||||
void SceneSetBackgroundColorAlreadySet(PyMOLGlobals * G, int background_color_al | ||||
ready_set){ | ||||
CScene *I = G->Scene; | ||||
I->background_color_already_set = background_color_already_set; | ||||
} | ||||
int SceneGetBackgroundColorAlreadySet(PyMOLGlobals * G){ | ||||
CScene *I = G->Scene; | ||||
return (I->background_color_already_set); | ||||
} | ||||
void SceneSetDoNotClearBackground(PyMOLGlobals * G, int do_not_clear){ | ||||
CScene *I = G->Scene; | ||||
I->do_not_clear = do_not_clear; | ||||
} | ||||
int SceneGetDoNotClearBackground(PyMOLGlobals * G){ | ||||
CScene *I = G->Scene; | ||||
return (I->do_not_clear); | ||||
} | ||||
#ifdef _PYMOL_IOS | ||||
void SceneTranslateSceneXYWithScale(PyMOLGlobals * G, float x, float y){ | ||||
CScene *I = G->Scene; | ||||
int moved_flag; | ||||
float v2[3], vScale; | ||||
float old_front, old_back, old_origin; | ||||
old_front = I->Front; | ||||
old_back = I->Back; | ||||
old_origin = -I->Pos[2]; | ||||
vScale = SceneGetExactScreenVertexScale(G, I->Origin); | ||||
/* if(stereo_via_adjacent_array(I->StereoMode)) { | ||||
x = get_stereo_x(x, &I->LastX, I->Width, NULL); | ||||
}*/ | ||||
v2[0] = x * vScale; | ||||
v2[1] = y * vScale; | ||||
v2[2] = 0.0F; | ||||
moved_flag = false; | ||||
if(x != 0.f) { | ||||
I->Pos[0] += v2[0]; | ||||
I->LastX = x; | ||||
SceneInvalidate(G); | ||||
moved_flag = true; | ||||
} | ||||
if(y != 0.f) { | ||||
I->Pos[1] += v2[1]; | ||||
I->LastY = y; | ||||
SceneInvalidate(G); | ||||
moved_flag = true; | ||||
} | ||||
EditorFavorOrigin(G, NULL); | ||||
if(moved_flag && SettingGetGlobal_b(G, cSetting_roving_origin)) { | ||||
SceneGetCenter(G, v2); /* gets position of center of screen */ | ||||
SceneOriginSet(G, v2, true); | ||||
} | ||||
if(moved_flag && SettingGetGlobal_b(G, cSetting_roving_detail)) { | ||||
SceneRovingDirty(G); | ||||
} | ||||
if(moved_flag) | ||||
SceneDoRoving(G, old_front, old_back, old_origin, 0 /* adjust flag */, false | ||||
); | ||||
PyMOL_NeedRedisplay(G->PyMOL); | ||||
} | ||||
int SceneIsTwisting(PyMOLGlobals * G){ | ||||
CScene *I = G->Scene; | ||||
return (!I->prev_no_z_rotation1 || !I->prev_no_z_rotation2); | ||||
} | ||||
#endif | ||||
void SceneGLClear(PyMOLGlobals * G, GLbitfield mask){ | void SceneGLClear(PyMOLGlobals * G, GLbitfield mask){ | |||
glClear(mask); | glClear(mask); | |||
} | } | |||
int SceneIsGridModeActive(PyMOLGlobals * G){ | int SceneIncrementTextureRefreshes(PyMOLGlobals * G){ | |||
CScene *I = G->Scene; | ||||
return ++(I->n_texture_refreshes); | ||||
} | ||||
void SceneResetTextureRefreshes(PyMOLGlobals * G){ | ||||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
return I->grid.active; | I->n_texture_refreshes = 0; | |||
} | } | |||
void SceneGetGridModeSize(PyMOLGlobals * G, int *width, int *height){ | void SceneGetScaledAxesAtPoint(PyMOLGlobals * G, float *pt, float *xn, float *yn | |||
) | ||||
{ | ||||
CScene *I = G->Scene; | ||||
float xn0[3] = { 1.0F, 0.0F, 0.0F }; | ||||
float yn0[3] = { 0.0F, 1.0F, 0.0F }; | ||||
float v_scale; | ||||
v_scale = SceneGetScreenVertexScale(G, pt); | ||||
MatrixInvTransformC44fAs33f3f(I->RotMatrix, xn0, xn0); | ||||
MatrixInvTransformC44fAs33f3f(I->RotMatrix, yn0, yn0); | ||||
scale3f(xn0, v_scale, xn); | ||||
scale3f(yn0, v_scale, yn); | ||||
} | ||||
void SceneGetScaledAxes(PyMOLGlobals * G, CObject *obj, float *xn, float *yn) | ||||
{ | ||||
CScene *I = G->Scene; | CScene *I = G->Scene; | |||
*width = I->grid.cur_viewport_size[0]; | float *v; | |||
*height = I->grid.cur_viewport_size[1]; | float vt[3]; | |||
float xn0[3] = { 1.0F, 0.0F, 0.0F }; | ||||
float yn0[3] = { 0.0F, 1.0F, 0.0F }; | ||||
float v_scale; | ||||
v = TextGetPos(G); | ||||
if(obj->TTTFlag) { | ||||
transformTTT44f3f(obj->TTT, v, vt); | ||||
} else { | ||||
copy3f(v, vt); | ||||
} | ||||
v_scale = SceneGetScreenVertexScale(G, vt); | ||||
MatrixInvTransformC44fAs33f3f(I->RotMatrix, xn0, xn0); | ||||
MatrixInvTransformC44fAs33f3f(I->RotMatrix, yn0, yn0); | ||||
scale3f(xn0, v_scale, xn); | ||||
scale3f(yn0, v_scale, yn); | ||||
} | } | |||
int SceneGetCopyType(PyMOLGlobals * G) { | int SceneGetCopyType(PyMOLGlobals * G) { | |||
return G->Scene->CopyType; | return G->Scene->CopyType; | |||
} | } | |||
void SceneGenerateMatrixToAnotherZFromZ(PyMOLGlobals *G, float *convMatrix, floa | ||||
t *curpt, float *pt){ | ||||
CScene *I = G->Scene; | ||||
float scaleMatrix[16]; | ||||
float cscale = SceneGetExactScreenVertexScale(G, curpt); | ||||
float pscale = SceneGetExactScreenVertexScale(G, pt); | ||||
identity44f(scaleMatrix); | ||||
MatrixSetScaleC44f(scaleMatrix, pscale); | ||||
identity44f(convMatrix); | ||||
MatrixSetScaleC44f(convMatrix, 1.f/cscale); | ||||
MatrixMultiplyC44f(I->RotMatrix, convMatrix); | ||||
MatrixTranslateC44f(convMatrix, pt[0]-curpt[0], pt[1]-curpt[1], pt[2]-curpt[2] | ||||
); | ||||
MatrixMultiplyC44f(I->InvMatrix, convMatrix); | ||||
MatrixMultiplyC44f(scaleMatrix, convMatrix); | ||||
} | ||||
void SceneAdjustZtoScreenZ(PyMOLGlobals *G, float *pos, float zarg){ | ||||
CScene *I = G->Scene; | ||||
float clipRange = (I->BackSafe-I->FrontSafe); | ||||
float z = (zarg + 1.f) / 2.f; | ||||
float zInPreProj = -(z * clipRange + I->FrontSafe); | ||||
float pos4[4], tpos[4], npos[4]; | ||||
float InvModMatrix[16]; | ||||
copy3f(pos, pos4); | ||||
pos4[3] = 1.f; | ||||
MatrixTransformC44f4f(I->ModMatrix, pos4, tpos); | ||||
normalize4f(tpos); | ||||
/* NEED TO ACCOUNT FOR ORTHO */ | ||||
if (SettingGetGlobal_b(G, cSetting_ortho)){ | ||||
npos[0] = tpos[0]; | ||||
npos[1] = tpos[1]; | ||||
} else { | ||||
npos[0] = zInPreProj * tpos[0] / tpos[2]; | ||||
npos[1] = zInPreProj * tpos[1] / tpos[2]; | ||||
} | ||||
npos[2] = zInPreProj; | ||||
npos[3] = 1.f; | ||||
MatrixInvertC44f(I->ModMatrix, InvModMatrix); | ||||
MatrixTransformC44f4f(InvModMatrix, npos, npos); | ||||
normalize4f(npos); | ||||
copy3f(npos, pos); | ||||
} | ||||
/* this function takes a screen point, where z is normalized between the clippin | ||||
g | ||||
planes, and converts it to the world coordinates */ | ||||
void SceneSetPointToWorldScreenRelative(PyMOLGlobals *G, float *pos, float *scre | ||||
enPt) | ||||
{ | ||||
float npos[4]; | ||||
float InvPmvMatrix[16]; | ||||
int width, height; | ||||
SceneGetWidthHeightStereo(G, &width, &height); | ||||
npos[0] = (.5f + floor(screenPt[0]*width)) /width ; // add .5, in middle of p | ||||
ixels? | ||||
npos[1] = (.5f + floor(screenPt[1]*height)) /height ; // add .5, in middle of | ||||
pixels? | ||||
npos[2] = 0.f; | ||||
npos[3] = 1.f; | ||||
MatrixInvertC44f(SceneGetPmvMatrix(G), InvPmvMatrix); | ||||
MatrixTransformC44f4f(InvPmvMatrix, npos, npos); | ||||
normalize4f(npos); | ||||
SceneAdjustZtoScreenZ(G, npos, screenPt[2]); | ||||
copy3f(npos, pos); | ||||
} | ||||
float SceneGetCurrentBackSafe(PyMOLGlobals *G){ | ||||
CScene *I = G->Scene; | ||||
return (I->BackSafe); | ||||
} | ||||
float SceneGetCurrentFrontSafe(PyMOLGlobals *G){ | ||||
CScene *I = G->Scene; | ||||
return (I->FrontSafe); | ||||
} | ||||
/* | ||||
* Get the field-of-view width at a depth of 1.0 | ||||
*/ | ||||
float GetFovWidth(PyMOLGlobals * G) | ||||
{ | ||||
float fov = SettingGetGlobal_f(G, cSetting_field_of_view); | ||||
return 2.f * tanf(fov * PI / 360.f); | ||||
} | ||||
void SceneInvalidatePicking(PyMOLGlobals * G){ | ||||
CScene *I = G->Scene; | ||||
I->invPick = true; | ||||
} | ||||
End of changes. 187 change blocks. | ||||
3537 lines changed or deleted | 780 lines changed or added |