1 
2 /*
3 A* -------------------------------------------------------------------
4 B* This file contains source code for the PyMOL computer program
5 C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific.
6 D* -------------------------------------------------------------------
7 E* It is unlawful to modify or remove this copyright notice.
8 F* -------------------------------------------------------------------
9 G* Please see the accompanying LICENSE file for further information.
10 H* -------------------------------------------------------------------
11 I* Additional authors of this source file include:
12 -*
13 -*
14 -*
15 Z* -------------------------------------------------------------------
16 */
17 
18 #include <vector>
19 #include <memory>
20 #include <queue>
21 #include <string>
22 #include <array>
23 
24 #include"os_python.h"
25 
26 #include"os_predef.h"
27 #include"os_std.h"
28 #include"os_gl.h"
29 
30 #include"main.h"
31 #include"Version.h"
32 #include"MemoryDebug.h"
33 #include"Err.h"
34 #include"Util.h"
35 #include"ListMacros.h"
36 #include"Ortho.h"
37 #include"P.h"
38 #include"Scene.h"
39 #include"Executive.h"
40 #include"ButMode.h"
41 #include "Seq.h"
42 #include"Control.h"
43 #include"Setting.h"
44 #include"Wizard.h"
45 #include"Pop.h"
46 #include"Seq.h"
47 #include"Text.h"
48 #include"PyMOLOptions.h"
49 #include"PyMOL.h"
50 #include"Movie.h"
51 #include "ShaderMgr.h"
52 #include "Vector.h"
53 #include "CGO.h"
54 #include "MyPNG.h"
55 #include "File.h"
56 
57 #ifdef _PYMOL_OPENVR
58 #include "OpenVRMode.h"
59 #endif
60 
61 #define OrthoSaveLines 0xFF
62 #define OrthoHistoryLines 0xFF
63 
64 #define cOrthoCharWidth DIP2PIXEL(8)
65 #define cOrthoLeftMargin DIP2PIXEL(3)
66 #define cOrthoBottomMargin DIP2PIXEL(5)
67 
68 #define CMD_QUEUE_MASK 0x3
69 
70 class COrtho {
71 public:
72   std::vector<Block*> Blocks{};
73   Block *GrabbedBy{}, *ClickedIn{};
74   int X{}, Y{}, Height{}, Width{};
75   int LastX{}, LastY{}, LastModifiers{};
76   int ActiveButton{};
77   int DrawText{};
78   int InputFlag{};                /* whether or not we have active input on the line */
79 
80   OrthoLineType Line[OrthoSaveLines + 1]{};
81   OrthoLineType History[OrthoHistoryLines + 1]{};
82   int HistoryLine{}, HistoryView{};
83   int CurLine{}, CurChar{}, PromptChar{}, CursorChar{};
84   int AutoOverlayStopLine{};
85   char Prompt[255]{};
86   int ShowLines{};
87   char Saved[OrthoLineLength]{};
88   int SavedPC{}, SavedCC{};
89   float TextColor[3]{}, OverlayColor[3]{}, WizardBackColor[3]{}, WizardTextColor[3]{};
90   int DirtyFlag{};
91   double BusyLast{}, BusyLastUpdate{};
92   int BusyStatus[4]{};
93   char BusyMessage[255]{};
94   char *WizardPromptVLA{};
95   int SplashFlag{};
96   int HaveSeqViewer{};
97   BlockRect LoopRect{};
98   int LoopFlag{};
99   int cmdNestLevel{};
100   std::array<std::queue<std::string>, CMD_QUEUE_MASK + 1> cmdQueue;
101   std::queue<std::string> *cmdActiveQueue;
102   int cmdActiveBusy{};
103   std::queue<std::string> feedback;
104   int Pushed{};
105   std::vector<std::unique_ptr<CDeferred>> deferred; //Ortho manages DeferredObjs
106   int RenderMode{};
107   GLint ViewPort[4]{};
108   int WrapXFlag{};
109   GLenum ActiveGLBuffer{};
110   double DrawTime{}, LastDraw{};
111   int WrapClickSide{};            /* ugly kludge for finding click side in geowall stereo mode */
112 
113   /* packing information */
114   int WizardHeight{};
115   int TextBottom{};
116 
117   int IssueViewportWhenReleased{};
118   GLuint bg_texture_id{};
119   short bg_texture_needs_update{};
120   CGO *bgCGO{};
121   int bgWidth = 0, bgHeight = 0;
122   std::shared_ptr<pymol::Image> bgData; // this is the image data set from CMol, takes precedence of bg_gradient or bg_image_filename
123   CGO *orthoCGO{}, *orthoFastCGO{};
124 
125   /**
126    * Finds last block located and coordinate (x, y)
127    * @param x cursor X location
128    * @param y cursor Y location
129    * @return pointer to last block located at (x, y)
130    */
131   Block* findBlock(int x, int y);
132 
133 public:
134   /**
135    * Draws all blocks
136    * @param orthoCGO CGO to append to
137    */
138   void draw(CGO* orthoCGO);
139 
140   /**
141    * Draws all blocks
142    * @param orthoCGO CGO to append to
143    * @return true if anything was drawn to CGO
144    */
145   bool fastDraw(CGO* orthoCGO);
146 };
147 
OrthoBackgroundDataIsSet(const COrtho & ortho)148 bool OrthoBackgroundDataIsSet(const COrtho& ortho)
149 {
150   return (ortho.bgData && (!ortho.bgData->empty()));
151 }
152 
OrthoBackgroundDataGet(const COrtho & ortho)153 std::shared_ptr<pymol::Image> OrthoBackgroundDataGet(const COrtho& ortho)
154 {
155   return ortho.bgData;
156 }
157 
OrthoGetSize(const COrtho & ortho)158 std::pair<int, int> OrthoGetSize(const COrtho& ortho){
159   return std::make_pair(ortho.Width, ortho.Height);
160 }
161 
OrthoGetBackgroundSize(const COrtho & ortho)162 std::pair<int, int> OrthoGetBackgroundSize(const COrtho& ortho){
163   if(ortho.bgData){
164     return ortho.bgData->getSize();
165   } else{
166     return std::make_pair(ortho.bgWidth, ortho.bgHeight);
167   }
168 }
169 
170 static
171 void OrthoParseCurrentLine(PyMOLGlobals * G);
172 
173 #define cBusyWidth 240
174 #define cBusyHeight 60
175 #define cBusyMargin 10
176 #define cBusyBar 10
177 #define cBusySpacing 15
178 
179 #define cBusyUpdate 0.2
180 
181 #define cWizardTopMargin 15
182 #define cWizardLeftMargin 15
183 #define cWizardBorder 7
184 
get_wrap_x(int x,int * last_x,int width,int * click_side)185 static int get_wrap_x(int x, int *last_x, int width, int *click_side)
186 {
187   int width_2 = width / 2;
188   int width_3 = width / 3;
189   if(!last_x) {
190     if(x > width_2) {
191       x -= width_2;
192       if(click_side)
193         *click_side = 1;
194     } else {
195       if(click_side)
196         *click_side = -1;
197     }
198   } else {
199     if((x - (*last_x)) > width_3) {
200       x -= width_2;
201       if(click_side)
202         *click_side = 1;
203     } else if(((*last_x) - x) > width_3) {
204       x += width_2;
205       if(click_side)
206         *click_side = 1;
207     } else {
208       if(click_side)
209         *click_side = -1;
210     }
211   }
212   return x;
213 }
214 
OrthoDrawBuffer(PyMOLGlobals * G,GLenum mode)215 void OrthoDrawBuffer(PyMOLGlobals * G, GLenum mode)
216 {
217   COrtho *I = G->Ortho;
218 
219   if (mode == GL_BACK) {
220     mode = G->DRAW_BUFFER0;
221   }
222 
223   if(!hasFrameBufferBinding() && (mode != I->ActiveGLBuffer) && G->HaveGUI && G->ValidContext) {
224 #ifndef PURE_OPENGL_ES_2
225     glDrawBuffer(mode);
226 #endif
227     I->ActiveGLBuffer = mode;
228   }
229 }
230 
OrthoGetDirty(PyMOLGlobals * G)231 int OrthoGetDirty(PyMOLGlobals * G)
232 {
233   COrtho *I = G->Ortho;
234   return I->DirtyFlag;
235 }
236 
OrthoGetRenderMode(PyMOLGlobals * G)237 int OrthoGetRenderMode(PyMOLGlobals * G)
238 {
239   COrtho *I = G->Ortho;
240   return I->RenderMode;
241 }
242 
OrthoSetLoopRect(PyMOLGlobals * G,int flag,BlockRect * rect)243 void OrthoSetLoopRect(PyMOLGlobals * G, int flag, BlockRect * rect)
244 {
245   COrtho *I = G->Ortho;
246   I->LoopRect = (*rect);
247   I->LoopFlag = flag;
248   OrthoInvalidateDoDraw(G);
249   OrthoDirty(G);
250 }
251 
OrthoDeferredWaiting(PyMOLGlobals * G)252 int OrthoDeferredWaiting(PyMOLGlobals * G)
253 {
254   COrtho *I = G->Ortho;
255   return (!I->deferred.empty());
256 }
257 
OrthoExecDeferred(PyMOLGlobals * G)258 void OrthoExecDeferred(PyMOLGlobals * G)
259 {
260   COrtho *I = G->Ortho;
261   /* execute all deferred actions that happened to require a
262    * valid OpenGL context (such as atom picks, etc.) */
263   for(const auto& d : I->deferred){
264     d->exec();
265   }
266   I->deferred.clear();
267 }
268 
OrthoDefer(PyMOLGlobals * G,std::unique_ptr<CDeferred> && D)269 void OrthoDefer(PyMOLGlobals * G, std::unique_ptr<CDeferred> && D)
270 {
271   COrtho *I = G->Ortho;
272   I->deferred.emplace_back(std::move(D));
273   OrthoDirty(G);
274 }
275 
OrthoGetWidth(PyMOLGlobals * G)276 int OrthoGetWidth(PyMOLGlobals * G)
277 {
278   if(G) {
279     COrtho *I = G->Ortho;
280     return (I->Width);
281   }
282   return 0;
283 }
284 
OrthoGetHeight(PyMOLGlobals * G)285 int OrthoGetHeight(PyMOLGlobals * G)
286 {
287   if(G) {
288     COrtho *I = G->Ortho;
289     return (I->Height);
290   }
291   return 0;
292 }
293 
294 
295 /*========================================================================*/
OrthoFakeDrag(PyMOLGlobals * G)296 void OrthoFakeDrag(PyMOLGlobals * G)
297 {                               /* for timing-based events, such as pop-ups */
298   COrtho *I = G->Ortho;
299   if(I->GrabbedBy)
300     OrthoDrag(G, I->LastX, I->LastY, I->LastModifiers);
301 }
302 
303 
304 /*========================================================================*/
305 
OrthoSetWizardPrompt(PyMOLGlobals * G,char * vla)306 void OrthoSetWizardPrompt(PyMOLGlobals * G, char *vla)
307 {
308   COrtho *I = G->Ortho;
309   VLAFreeP(I->WizardPromptVLA);
310   I->WizardPromptVLA = vla;
311 }
312 
313 
314 /*========================================================================*/
OrthoSpecial(PyMOLGlobals * G,int k,int x,int y,int mod)315 void OrthoSpecial(PyMOLGlobals * G, int k, int x, int y, int mod)
316 {
317   COrtho *I = G->Ortho;
318   int curLine = I->CurLine & OrthoSaveLines;
319   int cursorMoved = false;
320 
321   PRINTFB(G, FB_Ortho, FB_Blather)
322     " OrthoSpecial: %c (%d), x %d y %d, mod %d\n", k, k, x, y, mod ENDFB(G);
323 
324   switch (k) {
325   case P_GLUT_KEY_DOWN:
326     if(I->CurChar && (I->HistoryView == I->HistoryLine)) {
327       strcpy(I->History[I->HistoryLine], I->Line[curLine] + I->PromptChar);
328     }
329     I->HistoryView = (I->HistoryView + 1) & OrthoHistoryLines;
330     strcpy(I->Line[curLine], I->Prompt);
331     I->PromptChar = strlen(I->Prompt);
332     if(I->History[I->HistoryView][0]) {
333       strcat(I->Line[curLine], I->History[I->HistoryView]);
334       I->CurChar = strlen(I->Line[curLine]);
335     } else {
336       I->CurChar = I->PromptChar;
337     }
338     I->InputFlag = 1;
339     I->CursorChar = -1;
340     cursorMoved = true;
341     break;
342   case P_GLUT_KEY_UP:
343     if(I->CurChar && (I->HistoryView == I->HistoryLine)) {
344       strcpy(I->History[I->HistoryLine], I->Line[curLine] + I->PromptChar);
345     }
346     I->HistoryView = (I->HistoryView - 1) & OrthoHistoryLines;
347     strcpy(I->Line[curLine], I->Prompt);
348     I->PromptChar = strlen(I->Prompt);
349     if(I->History[I->HistoryView][0]) {
350       strcat(I->Line[curLine], I->History[I->HistoryView]);
351       I->CurChar = strlen(I->Line[curLine]);
352     } else {
353       I->CurChar = I->PromptChar;
354     }
355     I->CursorChar = -1;
356     I->InputFlag = 1;
357     cursorMoved = true;
358     break;
359   case P_GLUT_KEY_LEFT:
360     if(I->CursorChar >= 0) {
361       I->CursorChar--;
362     } else {
363       I->CursorChar = I->CurChar - 1;
364     }
365     if(I->CursorChar < I->PromptChar)
366       I->CursorChar = I->PromptChar;
367     cursorMoved = true;
368     break;
369   case P_GLUT_KEY_RIGHT:
370     if(I->CursorChar >= 0) {
371       I->CursorChar++;
372     } else {
373       I->CursorChar = I->CurChar - 1;
374     }
375     if((unsigned) I->CursorChar > strlen(I->Line[curLine]))
376       I->CursorChar = strlen(I->Line[curLine]);
377     cursorMoved = true;
378     break;
379   }
380   if (cursorMoved){
381     OrthoInvalidateDoDraw(G);
382   }
383   OrthoDirty(G);
384 }
385 
386 
387 /*========================================================================*/
OrthoTextVisible(PyMOLGlobals * G)388 int OrthoTextVisible(PyMOLGlobals * G)
389 {
390   return (SettingGetGlobal_i(G, cSetting_internal_feedback) ||
391           SettingGetGlobal_b(G, cSetting_text) || SettingGetGlobal_i(G, cSetting_overlay));
392 }
393 
394 
395 /*========================================================================*/
396 
OrthoArrowsGrabbed(PyMOLGlobals * G)397 int OrthoArrowsGrabbed(PyMOLGlobals * G)
398 {
399   COrtho *I = G->Ortho;
400   return ((I->CurChar > I->PromptChar) && OrthoTextVisible(G));
401   /* arrows can't be grabbed if text isn't visible */
402 }
403 
404 /*========================================================================*/
OrthoGetOverlayStatus(PyMOLGlobals * G)405 int OrthoGetOverlayStatus(PyMOLGlobals * G)
406 {
407   COrtho *I = G->Ortho;
408   int overlay = SettingGetGlobal_i(G, cSetting_overlay);
409   if(!overlay) {
410     if(SettingGetGlobal_i(G, cSetting_auto_overlay) > 0) {
411       if(I->CurLine != I->AutoOverlayStopLine) {
412         overlay = -1;           /* signal auto overlay */
413       }
414     }
415   }
416   return overlay;
417 }
418 
419 
420 /*========================================================================*/
OrthoRemoveAutoOverlay(PyMOLGlobals * G)421 void OrthoRemoveAutoOverlay(PyMOLGlobals * G)
422 {
423   COrtho *I = G->Ortho;
424   I->AutoOverlayStopLine = I->CurLine;
425 }
426 
427 
428 /*========================================================================*/
OrthoRemoveSplash(PyMOLGlobals * G)429 void OrthoRemoveSplash(PyMOLGlobals * G)
430 {
431   COrtho *I = G->Ortho;
432   I->SplashFlag = false;
433 }
434 
435 
436 /*========================================================================*/
OrthoCommandNest(PyMOLGlobals * G,int dir)437 void OrthoCommandNest(PyMOLGlobals * G, int dir)
438 {
439   COrtho *I = G->Ortho;
440   I->cmdNestLevel += dir;
441   {
442     int level = I->cmdNestLevel;
443     if(level < 0)
444       level = 0;
445     if(level > CMD_QUEUE_MASK)
446       level = CMD_QUEUE_MASK;
447     I->cmdActiveQueue = &I->cmdQueue[level];
448   }
449 }
450 
451 
452 /*========================================================================*/
OrthoCommandIsEmpty(COrtho & ortho)453 bool OrthoCommandIsEmpty(COrtho& ortho){
454   return ortho.cmdActiveQueue->empty();
455 }
456 
457 /*========================================================================*/
OrthoCommandOut(COrtho & ortho)458 std::string OrthoCommandOut(COrtho& ortho){
459   std::string str;
460   if(ortho.cmdActiveQueue){
461     str = std::move(ortho.cmdActiveQueue->front());
462     ortho.cmdActiveQueue->pop();
463   }
464   return str;
465 }
466 
467 
468 /*========================================================================*/
OrthoCommandWaiting(PyMOLGlobals * G)469 int OrthoCommandWaiting(PyMOLGlobals * G)
470 {
471   COrtho *I = G->Ortho;
472   return (I->cmdActiveBusy || !OrthoCommandIsEmpty(*I));
473 }
474 
475 
476 /*========================================================================*/
OrthoClear(PyMOLGlobals * G)477 void OrthoClear(PyMOLGlobals * G)
478 {
479   int a;
480   COrtho *I = G->Ortho;
481   for(a = 0; a <= OrthoSaveLines; a++)
482     I->Line[a][0] = 0;
483   OrthoNewLine(G, NULL, true);
484   OrthoRestorePrompt(G);
485   OrthoInvalidateDoDraw(G);
486   OrthoDirty(G);
487 }
488 
489 
490 /*========================================================================*/
OrthoFeedbackIn(PyMOLGlobals * G,const char * buffer)491 void OrthoFeedbackIn(PyMOLGlobals * G, const char *buffer)
492 {
493   COrtho *I = G->Ortho;
494   if(G->Option->pmgui) {
495     I->feedback.emplace(buffer);
496   }
497 }
498 
499 
500 /*========================================================================*/
501 // For now keep G here for Settings
OrthoFeedbackOut(PyMOLGlobals * G,COrtho & ortho)502 std::string OrthoFeedbackOut(PyMOLGlobals* G, COrtho& ortho)
503 {
504   std::string buffer;
505   if (ortho.feedback.empty()) {
506     return buffer;
507   }
508   buffer = std::move(ortho.feedback.front());
509   ortho.feedback.pop();
510   if (!SettingGetGlobal_b(G, cSetting_colored_feedback)) {
511     UtilStripANSIEscapes(buffer);
512   }
513 
514   return buffer;
515 }
516 
517 
518 /*========================================================================*/
OrthoDirty(PyMOLGlobals * G)519 void OrthoDirty(PyMOLGlobals * G)
520 {
521   COrtho *I = G->Ortho;
522   PRINTFD(G, FB_Ortho)
523     " OrthoDirty: called.\n" ENDFD;
524   if(!I->DirtyFlag) {
525     I->DirtyFlag = true;
526   }
527   PyMOL_NeedRedisplay(G->PyMOL);
528 }
529 
530 
531 /*========================================================================*/
OrthoBusyMessage(PyMOLGlobals * G,const char * message)532 void OrthoBusyMessage(PyMOLGlobals * G, const char *message)
533 {
534   COrtho *I = G->Ortho;
535   if(strlen(message) < 255)
536     strcpy(I->BusyMessage, message);
537 }
538 
539 
540 /*========================================================================*/
OrthoBusySlow(PyMOLGlobals * G,int progress,int total)541 void OrthoBusySlow(PyMOLGlobals * G, int progress, int total)
542 {
543   COrtho *I = G->Ortho;
544   double time_yet = (-I->BusyLastUpdate) + UtilGetSeconds(G);
545 
546   PRINTFD(G, FB_Ortho)
547     " OrthoBusySlow-DEBUG: progress %d total %d\n", progress, total ENDFD;
548   I->BusyStatus[0] = progress;
549   I->BusyStatus[1] = total;
550   if(SettingGetGlobal_b(G, cSetting_show_progress) && (time_yet > 0.15F)) {
551     if(PyMOL_GetBusy(G->PyMOL, false)) {        /* harmless race condition */
552 #ifndef _PYMOL_NOPY
553       int blocked = PAutoBlock(G);
554       if(PLockStatusAttempt(G)) {
555 #endif
556         PyMOL_SetProgress(G->PyMOL, PYMOL_PROGRESS_SLOW, progress, total);
557         I->BusyLastUpdate = UtilGetSeconds(G);
558 
559 #ifndef _PYMOL_NOPY
560         PUnlockStatus(G);
561       }
562       PAutoUnblock(G, blocked);
563 #endif
564     }
565     OrthoBusyDraw(G, false);
566   }
567 }
568 
569 
570 /*========================================================================*/
OrthoBusyFast(PyMOLGlobals * G,int progress,int total)571 void OrthoBusyFast(PyMOLGlobals * G, int progress, int total)
572 {
573   COrtho *I = G->Ortho;
574   double time_yet = (-I->BusyLastUpdate) + UtilGetSeconds(G);
575   short finished = progress == total;
576   PRINTFD(G, FB_Ortho)
577     " OrthoBusyFast-DEBUG: progress %d total %d\n", progress, total ENDFD;
578   I->BusyStatus[2] = progress;
579   I->BusyStatus[3] = total;
580   if(finished || (SettingGetGlobal_b(G, cSetting_show_progress) && (time_yet > 0.15F))) {
581     if(PyMOL_GetBusy(G->PyMOL, false) || finished) {        /* harmless race condition */
582 #ifndef _PYMOL_NOPY
583       int blocked = PAutoBlock(G);
584       if(PLockStatusAttempt(G)) {
585 #endif
586         PyMOL_SetProgress(G->PyMOL, PYMOL_PROGRESS_FAST, progress, total);
587         I->BusyLastUpdate = UtilGetSeconds(G);
588 #ifndef _PYMOL_NOPY
589         PUnlockStatus(G);
590       }
591       PAutoUnblock(G, blocked);
592 #endif
593     }
594     OrthoBusyDraw(G, false);
595   }
596 }
597 
598 
599 /*========================================================================*/
OrthoBusyPrime(PyMOLGlobals * G)600 void OrthoBusyPrime(PyMOLGlobals * G)
601 {
602   COrtho *I = G->Ortho;
603   int a;
604   for(a = 0; a < 4; a++)
605     I->BusyStatus[a] = 0;
606   I->BusyMessage[0] = 0;
607   I->BusyLast = UtilGetSeconds(G);
608   I->BusyLastUpdate = UtilGetSeconds(G);
609 }
610 
611 
612 /*========================================================================*/
OrthoBusyDraw(PyMOLGlobals * G,int force)613 void OrthoBusyDraw(PyMOLGlobals * G, int force)
614 {
615   COrtho *I = G->Ortho;
616   double now;
617   double busyTime;
618 
619   PRINTFD(G, FB_Ortho)
620     " OrthoBusyDraw: entered.\n" ENDFD;
621   now = UtilGetSeconds(G);
622   busyTime = (-I->BusyLast) + now;
623   if(SettingGetGlobal_b(G, cSetting_show_progress) && (force || (busyTime > cBusyUpdate))) {
624 
625     I->BusyLast = now;
626     if(PIsGlutThread()) {
627 
628       if(G->HaveGUI && G->ValidContext
629           // only draw into GL_FRONT if default draw buffer is GL_BACK
630           // (not the case for QOpenGLWidget)
631           && G->DRAW_BUFFER0 == GL_BACK) {
632         char *c;
633         int x, y;
634         float white[3] = { 1, 1, 1 };
635         int draw_both = SceneMustDrawBoth(G);
636         OrthoPushMatrix(G);
637         {
638           int pass = 0;
639           SceneGLClear(G, GL_DEPTH_BUFFER_BIT);
640           while(1) {
641             if(draw_both) {
642               if(!pass)
643                 OrthoDrawBuffer(G, GL_FRONT_LEFT);
644               else
645                 OrthoDrawBuffer(G, GL_FRONT_RIGHT);
646             } else {
647               OrthoDrawBuffer(G, GL_FRONT);     /* draw into the front buffer */
648             }
649 
650 #ifndef PURE_OPENGL_ES_2
651             glColor3f(0.f, 0.f, 0.f); // black
652             glBegin(GL_TRIANGLE_STRIP);
653             glVertex2i(0, I->Height);
654             glVertex2i(cBusyWidth, I->Height);
655             glVertex2i(0, I->Height - cBusyHeight);
656             glVertex2i(cBusyWidth, I->Height - cBusyHeight);
657             glEnd();
658             glColor3fv(white);
659 #endif
660             y = I->Height - cBusyMargin;
661             c = I->BusyMessage;
662             if(*c) {
663               TextSetColor(G, white);
664               TextSetPos2i(G, cBusyMargin, y - (cBusySpacing / 2));
665               TextDrawStr(G, c, NULL);
666               y -= cBusySpacing;
667             }
668 
669             if(I->BusyStatus[1]) {
670               glBegin(GL_LINE_LOOP);
671               glVertex2i(cBusyMargin, y);
672               glVertex2i(cBusyWidth - cBusyMargin, y);
673               glVertex2i(cBusyWidth - cBusyMargin, y - cBusyBar);
674               glVertex2i(cBusyMargin, y - cBusyBar);
675               glEnd();
676               glColor3fv(white);
677               x =
678                 (I->BusyStatus[0] * (cBusyWidth - 2 * cBusyMargin) / I->BusyStatus[1]) +
679                 cBusyMargin;
680               glBegin(GL_TRIANGLE_STRIP);
681               glVertex2i(cBusyMargin, y);
682               glVertex2i(x,y);
683               glVertex2i(cBusyMargin, y - cBusyBar);
684               glVertex2i(x, y - cBusyBar);
685               glEnd();
686               y -= cBusySpacing;
687             }
688 
689             if(I->BusyStatus[3]) {
690               glColor3fv(white);
691               glBegin(GL_LINE_LOOP);
692               glVertex2i(cBusyMargin, y);
693               glVertex2i(cBusyWidth - cBusyMargin, y);
694               glVertex2i(cBusyWidth - cBusyMargin, y - cBusyBar);
695               glVertex2i(cBusyMargin, y - cBusyBar);
696               glEnd();
697               x =
698                 (I->BusyStatus[2] * (cBusyWidth - 2 * cBusyMargin) / I->BusyStatus[3]) +
699                 cBusyMargin;
700               glColor3fv(white);
701               glBegin(GL_TRIANGLE_STRIP);
702               glVertex2i(cBusyMargin, y);
703               glVertex2i(x, y);
704               glVertex2i(cBusyMargin, y - cBusyBar);
705               glVertex2i(x, y - cBusyBar);
706               glEnd();
707               y -= cBusySpacing;
708             }
709             if(!draw_both)
710               break;
711             if(pass > 1)
712               break;
713             pass++;
714           }
715 
716           glFlush();
717           glFinish();
718 
719           if(draw_both)
720             OrthoDrawBuffer(G, GL_BACK_LEFT);
721           else
722             OrthoDrawBuffer(G, GL_BACK);
723         }
724         OrthoPopMatrix(G);
725         OrthoDirty(G);
726       }
727 
728     }
729   }
730 
731   PRINTFD(G, FB_Ortho)
732     " OrthoBusyDraw: leaving...\n" ENDFD;
733 
734 }
735 
736 
737 /*========================================================================*/
OrthoRestorePrompt(PyMOLGlobals * G)738 void OrthoRestorePrompt(PyMOLGlobals * G)
739 {
740   COrtho *I = G->Ortho;
741   int curLine;
742   if(!I->InputFlag) {
743     if(I->Saved[0]) {
744       if(I->CurChar) {
745         OrthoNewLine(G, NULL, true);
746       }
747       curLine = I->CurLine & OrthoSaveLines;
748       strcpy(I->Line[curLine], I->Saved);
749       I->Saved[0] = 0;
750       I->CurChar = I->SavedCC;
751       I->PromptChar = I->SavedPC;
752     } else {
753       if(I->CurChar)
754         OrthoNewLine(G, I->Prompt, true);
755       else {
756         curLine = I->CurLine & OrthoSaveLines;
757         strcpy(I->Line[curLine], I->Prompt);
758         I->CurChar = (I->PromptChar = strlen(I->Prompt));
759       }
760     }
761     I->InputFlag = 1;
762   }
763 }
764 
765 
766 /*========================================================================*/
767 static
OrthoKeyControl(PyMOLGlobals * G,unsigned char k)768 void OrthoKeyControl(PyMOLGlobals * G, unsigned char k)
769 {
770   char buffer[OrthoLineLength];
771 
772   /* safer... */
773 
774   sprintf(buffer, "cmd._ctrl(chr(%d))", k);
775   /* sprintf(buffer,"_ctrl %c",k); */
776   PLog(G, buffer, cPLog_pym);
777   PParse(G, buffer);
778   PFlush(G);
779 
780 }
781 
782 /*========================================================================*/
783 static
OrthoKeyCmmd(PyMOLGlobals * G,unsigned char k)784 void OrthoKeyCmmd(PyMOLGlobals * G, unsigned char k)
785 {
786   char buffer[OrthoLineLength];
787 
788   /* safer... */
789 
790   sprintf(buffer, "cmd._cmmd(chr(%d))", k);
791   /* sprintf(buffer,"_ctrl %c",k); */
792   PLog(G, buffer, cPLog_pym);
793   PParse(G, buffer);
794   PFlush(G);
795 
796 }
797 
798 /*========================================================================*/
799 static
OrthoKeyCtSh(PyMOLGlobals * G,unsigned char k)800 void OrthoKeyCtSh(PyMOLGlobals * G, unsigned char k)
801 {
802   char buffer[OrthoLineLength];
803 
804   /* safer... */
805 
806   sprintf(buffer, "cmd._ctsh(chr(%d))", k);
807   /* sprintf(buffer,"_ctrl %c",k); */
808   PLog(G, buffer, cPLog_pym);
809   PParse(G, buffer);
810   PFlush(G);
811 
812 }
813 
814 
815 /*========================================================================*/
816 static
OrthoKeyAlt(PyMOLGlobals * G,unsigned char k)817 void OrthoKeyAlt(PyMOLGlobals * G, unsigned char k)
818 {
819   char buffer[OrthoLineLength];
820 
821   /* safer... */
822 
823   if(k == '@') {
824     /* option G produces '@' on some non-US keyboards, so simply
825        ignore the modifier */
826     OrthoKey(G, k, 0, 0, 0);
827   } else {
828     sprintf(buffer, "cmd._alt(chr(%d))", k);
829     /* sprintf(buffer,"_alt %c",k); */
830     PLog(G, buffer, cPLog_pym);
831     PParse(G, buffer);
832     PFlush(G);
833   }
834 
835 }
836 
add_normal_char(COrtho * I,unsigned char k)837 static int add_normal_char(COrtho * I, unsigned char k)
838 {
839   char buffer[OrthoLineLength];
840   int curLine = I->CurLine & OrthoSaveLines;
841   if(I->CursorChar >= 0) {
842     strcpy(buffer, I->Line[curLine] + I->CursorChar);
843     I->Line[curLine][I->CursorChar] = k;
844     I->CursorChar++;
845     I->CurChar++;
846     strcpy(I->Line[curLine] + I->CursorChar, buffer);
847   } else {
848     I->Line[curLine][I->CurChar] = k;
849     I->CurChar++;
850     I->Line[curLine][I->CurChar] = 0;
851   }
852   return curLine;
853 }
854 
855 
856 /*========================================================================*/
OrthoKey(PyMOLGlobals * G,unsigned char k,int x,int y,int mod)857 void OrthoKey(PyMOLGlobals * G, unsigned char k, int x, int y, int mod)
858 {
859   COrtho *I = G->Ortho;
860   char buffer[OrthoLineLength];
861   int curLine;
862 
863   PRINTFB(G, FB_Ortho, FB_Blather)
864     " OrthoKey: %c (%d), x %d y %d, mod %d\n", k, k, x, y, mod ENDFB(G);
865 
866   OrthoRestorePrompt(G);
867 
868   if(mod == 4) {                /* alt */
869     OrthoKeyAlt(G, k);
870   } else if  (mod == 3) {       /* chsh */
871     OrthoKeyCtSh(G,(unsigned int) (k+64));
872   } else if((k > 32) && (k != 127)) {
873     curLine = add_normal_char(I, k);
874   } else
875     switch (k) {
876     case 32:                   /* spacebar */
877       if((!OrthoArrowsGrabbed(G)) &&
878 	 (I->CurChar == I->PromptChar)) { /* no text entered yet... */
879         if(SettingGetGlobal_b(G, cSetting_presentation)) {
880           if(mod & cOrthoSHIFT) {
881             OrthoCommandIn(G,"rewind;mplay");
882           } else {
883             PParse(G, "cmd.scene('','next')");
884           }
885         } else {
886           if(mod & cOrthoSHIFT) {
887             OrthoCommandIn(G,"rewind;mplay");
888           } else {
889             OrthoCommandIn(G,"mtoggle");
890           }
891         }
892       } else {
893         curLine = add_normal_char(I, k);
894       }
895       break;
896     case 127:                  /* delete */
897       if((!I->CurChar) || (I->CurChar == I->PromptChar) || !OrthoTextVisible(G)) {
898         OrthoKeyControl(G, 4 + 64);
899       } else {
900         if(I->CursorChar > -1 && I->CursorChar < I->CurChar) {
901           curLine = I->CurLine & OrthoSaveLines;
902           strcpy(buffer, I->Line[curLine] + I->CursorChar + 1);
903           I->CurChar--;
904           strcpy(I->Line[curLine] + I->CursorChar, buffer);
905         }
906       }
907       break;
908     case 8:                    /* backspace */
909       if(I->CurChar > I->PromptChar) {
910         curLine = I->CurLine & OrthoSaveLines;
911         if(I->CursorChar >= 0) {
912           if(I->CursorChar > I->PromptChar) {
913             strcpy(buffer, I->Line[curLine] + I->CursorChar);
914             I->Line[curLine][I->CursorChar] = k;
915             I->CursorChar--;
916             I->CurChar--;
917             strcpy(I->Line[curLine] + I->CursorChar, buffer);
918           }
919         } else {
920           I->CurChar--;
921           I->Line[curLine][I->CurChar] = 0;
922         }
923       }
924       break;
925     case 5:                    /* CTRL E -- ending */
926       if(OrthoArrowsGrabbed(G)) {
927         I->CursorChar = -1;
928       } else
929         OrthoKeyControl(G, (unsigned char) (k + 64));
930       break;
931     case 1:                    /* CTRL A -- beginning */
932       if(OrthoArrowsGrabbed(G)) {
933         if(I->CurChar)
934           I->CursorChar = I->PromptChar;
935       } else
936         OrthoKeyControl(G, (unsigned char) (k + 64));
937       break;
938     case 4:                    /* CTRL D */
939       if((!I->CurChar) || (I->CurChar == I->PromptChar) || !OrthoTextVisible(G)) {
940         OrthoKeyControl(G, (unsigned char) (4 + 64));
941       } else if((I->CurChar > I->PromptChar) && (I->CursorChar >= 0) && (I->CursorChar < I->CurChar)) { /* deleting */
942         curLine = I->CurLine & OrthoSaveLines;
943         strcpy(buffer, I->Line[curLine] + I->CursorChar + 1);
944         I->CurChar--;
945         strcpy(I->Line[curLine] + I->CursorChar, buffer);
946       } else {                  /* filename completion query */
947         curLine = I->CurLine & OrthoSaveLines;
948         if(I->PromptChar) {
949           strcpy(buffer, I->Line[curLine]);
950           PComplete(G, buffer + I->PromptChar, sizeof(OrthoLineType) - I->PromptChar);      /* just print, don't complete */
951         }
952       }
953       break;
954     case 9:                    /* CTRL I -- tab */
955       if(mod & cOrthoCTRL) {
956         OrthoKeyControl(G, (unsigned char) (k + 64));
957       } else {
958         curLine = I->CurLine & OrthoSaveLines;
959         if(I->PromptChar) {
960           strcpy(buffer, I->Line[curLine]);
961 
962           if(PComplete(G, buffer + I->PromptChar, sizeof(OrthoLineType) - I->PromptChar)) {
963             OrthoRestorePrompt(G);
964             curLine = I->CurLine & OrthoSaveLines;
965             strcpy(I->Line[curLine], buffer);
966             I->CurChar = strlen(I->Line[curLine]);
967             I->CursorChar = -1;
968           }
969         }
970       }
971       break;
972     case 27:                   /* ESCAPE */
973       if(SettingGetGlobal_b(G, cSetting_presentation)
974          && !(mod & (cOrthoCTRL | cOrthoSHIFT))) {
975         PParse(G, "_quit");
976       } else {
977         if(I->SplashFlag) {
978           OrthoRemoveSplash(G);
979         } else {
980           if(mod & cOrthoSHIFT)
981             SettingSetGlobal_i(G, cSetting_overlay, !(SettingGetGlobal_i(G, cSetting_overlay)));
982           else
983             SettingSetGlobal_b(G, cSetting_text,    !(SettingGetGlobal_b(G, cSetting_text   )));
984         }
985       }
986       break;
987     case 13:                   /* CTRL M -- carriage return */
988       if(I->CurChar > I->PromptChar)
989         OrthoParseCurrentLine(G);
990       else if(((SettingGetGlobal_b(G, cSetting_movie_panel) ||
991                 SettingGetGlobal_b(G, cSetting_presentation))
992                && MovieGetLength(G))) {
993         if(mod & cOrthoSHIFT) {
994           if(mod & cOrthoCTRL)
995             OrthoCommandIn(G,"mview toggle_interp,quiet=1,object=same");
996           else
997             OrthoCommandIn(G,"mview toggle_interp,quiet=1");
998         } else if(mod & cOrthoCTRL) {
999           OrthoCommandIn(G,"mview toggle,freeze=1,quiet=1");
1000         } else {
1001           if(SettingGetGlobal_b(G, cSetting_presentation)) {
1002             OrthoCommandIn(G,"mtoggle");
1003           } else {
1004             OrthoCommandIn(G,"mview toggle,quiet=1");
1005           }
1006         }
1007       }
1008       break;
1009     case 11:                   /* CTRL K -- truncate */
1010       if(OrthoArrowsGrabbed(G)) {
1011         if(I->CursorChar >= 0) {
1012           I->Line[I->CurLine & OrthoSaveLines][I->CursorChar] = 0;
1013           I->CurChar = I->CursorChar;
1014           I->CursorChar = -1;
1015         }
1016       } else {
1017         if(mod & cOrthoCTRL) {
1018           OrthoKeyControl(G, (unsigned char) (k + 64));
1019         }
1020       }
1021       break;
1022     case 22:                   /* CTRL V -- paste */
1023 #ifndef _PYMOL_NOPY
1024       if (I->CurChar != I->PromptChar) { /* no text entered yet... */
1025 	PBlockAndUnlockAPI(G);
1026 	PRunStringInstance(G, "cmd.paste()");
1027 	PLockAPIAndUnblock(G);
1028       } else {
1029 	OrthoKeyControl(G, (unsigned char) (k + 64));
1030       }
1031 #endif
1032       break;
1033     default:
1034       OrthoKeyControl(G, (unsigned char) (k + 64));
1035       break;
1036     }
1037   OrthoInvalidateDoDraw(G);
1038 }
1039 
1040 
1041 /*========================================================================*/
OrthoParseCurrentLine(PyMOLGlobals * G)1042 void OrthoParseCurrentLine(PyMOLGlobals * G)
1043 {
1044   COrtho *I = G->Ortho;
1045   char buffer[OrthoLineLength];
1046   int curLine;
1047 
1048   OrthoRemoveAutoOverlay(G);
1049   curLine = I->CurLine & OrthoSaveLines;
1050   I->Line[curLine][I->CurChar] = 0;
1051   strcpy(buffer, I->Line[curLine] + I->PromptChar);
1052 #ifndef _PYMOL_NOPY
1053   if(buffer[0]) {
1054     strcpy(I->History[I->HistoryLine], buffer);
1055     I->HistoryLine = (I->HistoryLine + 1) & OrthoHistoryLines;
1056     I->History[I->HistoryLine][0] = 0;
1057     I->HistoryView = I->HistoryLine;
1058 
1059     OrthoNewLine(G, NULL, true);
1060     if(WordMatch(G, buffer, "quit", true) == 0) /* don't log quit */
1061       PLog(G, buffer, cPLog_pml);
1062     OrthoDirty(G);              /* this will force a redraw, if necessary */
1063     PParse(G, buffer);
1064     OrthoRestorePrompt(G);
1065   }
1066 #endif
1067   I->CursorChar = -1;
1068 }
1069 
1070 
1071 /*========================================================================*/
OrthoAddOutput(PyMOLGlobals * G,const char * str)1072 void OrthoAddOutput(PyMOLGlobals * G, const char *str)
1073 {
1074   COrtho *I = G->Ortho;
1075   int curLine;
1076   const char *p;
1077   char *q;
1078   int cc;
1079   int wrap;
1080   curLine = I->CurLine & OrthoSaveLines;
1081   if(I->InputFlag) {
1082     strcpy(I->Saved, I->Line[curLine]);
1083     I->SavedPC = I->PromptChar;
1084     I->SavedCC = I->CurChar;
1085     I->PromptChar = 0;
1086     I->CurChar = 0;
1087     I->Line[curLine][0] = 0;
1088     I->InputFlag = 0;
1089   }
1090   curLine = I->CurLine & OrthoSaveLines;
1091   p = str;
1092   q = I->Line[curLine] + I->CurChar;
1093   cc = I->CurChar;
1094   while(*p) {
1095     if(*p != '\r' && *p != '\n') {
1096       cc++;
1097       wrap = SettingGetGlobal_b(G, cSetting_wrap_output);
1098 
1099       if(wrap > 0) {
1100         if(cc > wrap) {
1101           *q = 0;
1102           I->CurChar = cc;
1103           OrthoNewLine(G, NULL, true);
1104           cc = 0;
1105           q = I->Line[I->CurLine & OrthoSaveLines];
1106           curLine = I->CurLine & OrthoSaveLines;
1107         }
1108       }
1109       if(cc >= OrthoLineLength - 6) {   /* fail safe */
1110         *q = 0;
1111         I->CurChar = cc;
1112         OrthoNewLine(G, NULL, false);
1113         cc = 0;
1114         q = I->Line[I->CurLine & OrthoSaveLines];
1115         curLine = I->CurLine & OrthoSaveLines;
1116       }
1117       *q++ = *p++;
1118     } else {
1119       *q = 0;
1120       I->CurChar = cc;
1121       OrthoNewLine(G, NULL, true);
1122       q = I->Line[I->CurLine & OrthoSaveLines];
1123       curLine = I->CurLine & OrthoSaveLines;
1124       p++;
1125       cc = 0;
1126     }
1127   }
1128   *q = 0;
1129   I->CurChar = strlen(I->Line[curLine]);
1130   if((SettingGetGlobal_i(G, cSetting_internal_feedback) > 1) ||
1131      SettingGetGlobal_i(G, cSetting_overlay) || SettingGetGlobal_i(G, cSetting_auto_overlay))
1132     OrthoDirty(G);
1133 
1134   if(I->DrawText)
1135     OrthoInvalidateDoDraw(G);
1136 }
1137 
1138 
1139 /*========================================================================*/
OrthoNewLine(PyMOLGlobals * G,const char * prompt,int crlf)1140 void OrthoNewLine(PyMOLGlobals * G, const char *prompt, int crlf)
1141 {
1142   int curLine;
1143   COrtho *I = G->Ortho;
1144 
1145   /*  printf("orthoNewLine: CC: %d CL:%d PC: %d IF:L %d\n",I->CurChar,I->CurLine,
1146      I->PromptChar,I->InputFlag); */
1147   /*  if(I->CurChar)
1148      { */
1149   if(I->CurChar)
1150     OrthoFeedbackIn(G, I->Line[I->CurLine & OrthoSaveLines]);
1151   else
1152     OrthoFeedbackIn(G, " ");
1153 
1154   bool do_print = Feedback(G, FB_Python, FB_Output);
1155   bool do_print_with_escapes = false;
1156 
1157 #if !defined(_WIN32) && !defined(_WEBGL) && !defined(_PYMOL_LIB)
1158   do_print_with_escapes = do_print
1159     && SettingGetGlobal_b(G, cSetting_colored_feedback)
1160     && isatty(STDOUT_FILENO);
1161 #endif
1162 
1163   // print as-is if stdout supports ANSI Escape sequences
1164   if (do_print_with_escapes) {
1165     printf("%s", I->Line[I->CurLine & OrthoSaveLines]);
1166   }
1167 
1168   // strip ANSI Escape sequences (in-place)
1169   UtilStripANSIEscapes(I->Line[I->CurLine & OrthoSaveLines]);
1170 
1171   if (do_print) {
1172     if (!do_print_with_escapes) {
1173       printf("%s", I->Line[I->CurLine & OrthoSaveLines]);
1174     }
1175 
1176     if(crlf) {
1177       putchar('\n');
1178     }
1179     fflush(stdout);
1180   }
1181   /*        } */
1182 
1183   /*  if(I->Line[I->CurLine&OrthoSaveLines][0]) */
1184   I->CurLine++;
1185   curLine = I->CurLine & OrthoSaveLines;
1186 
1187   if(prompt) {
1188     strcpy(I->Line[curLine], prompt);
1189     I->CurChar = (I->PromptChar = strlen(prompt));
1190     I->InputFlag = 1;
1191   } else {
1192     I->CurChar = 0;
1193     I->Line[curLine][0] = 0;
1194     I->PromptChar = 0;
1195     I->InputFlag = 0;
1196   }
1197   /*printf("orthoNewLine: CC: %d CL:%d PC: %d IF:L %d\n",I->CurChar,I->CurLine,
1198      I->PromptChar,I->InputFlag); */
1199 
1200 }
1201 
1202 
1203 /*========================================================================*/
OrthoGrab(PyMOLGlobals * G,Block * block)1204 void OrthoGrab(PyMOLGlobals * G, Block * block)
1205 {
1206   COrtho *I = G->Ortho;
1207   I->GrabbedBy = block;
1208 }
1209 
OrthoGrabbedBy(PyMOLGlobals * G,Block * block)1210 int OrthoGrabbedBy(PyMOLGlobals * G, Block * block)
1211 {
1212   COrtho *I = G->Ortho;
1213   return I->GrabbedBy == block;
1214 }
1215 
OrthoDoViewportWhenReleased(PyMOLGlobals * G)1216 void OrthoDoViewportWhenReleased(PyMOLGlobals *G)
1217 {
1218   COrtho *I = G->Ortho;
1219   if(!(I->GrabbedBy||I->ClickedIn)) { /* no active UI element? */
1220     OrthoCommandIn(G, "viewport"); /* then issue viewport refresh */
1221     OrthoDirty(G);
1222   } else {
1223     I->IssueViewportWhenReleased = true; /* otherwise, defer */
1224   }
1225 }
1226 
1227 /*========================================================================*/
OrthoUngrab(PyMOLGlobals * G)1228 void OrthoUngrab(PyMOLGlobals * G)
1229 {
1230   COrtho *I = G->Ortho;
1231   I->GrabbedBy = NULL;
1232 }
1233 
1234 
1235 /*========================================================================*/
OrthoAttach(PyMOLGlobals * G,Block * block,int type)1236 void OrthoAttach(PyMOLGlobals * G, Block * block, int type)
1237 {
1238   G->Ortho->Blocks.push_back(block);
1239 }
1240 
1241 
1242 /*========================================================================*/
OrthoDetach(PyMOLGlobals * G,Block * block)1243 void OrthoDetach(PyMOLGlobals * G, Block * block)
1244 {
1245   COrtho *I = G->Ortho;
1246   if(I->GrabbedBy == block)
1247     I->GrabbedBy = NULL;
1248   auto iter = std::find(I->Blocks.begin(), I->Blocks.end(), block);
1249   if(iter != I->Blocks.end()){
1250     I->Blocks.erase(iter);
1251   }
1252 }
1253 
OrthoGetOverlayColor(PyMOLGlobals * G)1254 float *OrthoGetOverlayColor(PyMOLGlobals * G)
1255 {
1256   COrtho *I = G->Ortho;
1257   return I->OverlayColor;
1258 }
1259 
1260 
1261 /*========================================================================*/
1262 
1263 /* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
1264 #ifdef PYMOL_EVAL
1265 #include "OrthoEvalMessage.h"
1266 #endif
1267 #ifdef PYMOL_BETA
1268 #include "OrthoBetaMessage.h"
1269 #endif
1270 #ifdef JYMOL_EVAL
1271 #include "OrthoJyMolEvalMessage.h"
1272 #endif
1273 #ifdef PYMOL_EDU
1274 #include "OrthoEduMessage.h"
1275 #endif
1276 #ifdef PYMOL_COLL
1277 #include "OrthoCollMessage.h"
1278 #endif
1279 #ifdef AXPYMOL_EVAL
1280 #include "OrthoAxMessage.h"
1281 #endif
1282 
1283 /* END PROPRIETARY CODE SEGMENT */
1284 
1285 /* draw background gradient from bg_rgb_top
1286  * to bg_rgb_bottom is bg_gradient is set
1287  */
1288 
1289 #define BACKGROUND_TEXTURE_SIZE 256
1290 
OrthoGetBackgroundTextureID(PyMOLGlobals * G)1291 GLuint OrthoGetBackgroundTextureID(PyMOLGlobals * G){
1292   COrtho *I = G->Ortho;
1293   return I->bg_texture_id;
1294 }
1295 
OrthoInvalidateBackgroundTexture(PyMOLGlobals * G)1296 void OrthoInvalidateBackgroundTexture(PyMOLGlobals * G){
1297   COrtho *I = G->Ortho;
1298   if (I->bg_texture_id){
1299     glDeleteTextures(1, &I->bg_texture_id);
1300     I->bg_texture_id = 0;
1301     I->bg_texture_needs_update = 1;
1302   }
1303   if (I->bgCGO){
1304     CGOFree(I->bgCGO);
1305   }
1306 }
1307 
OrthoBackgroundTextureNeedsUpdate(PyMOLGlobals * G)1308 void OrthoBackgroundTextureNeedsUpdate(PyMOLGlobals * G){
1309   COrtho *I = G->Ortho;
1310   I->bg_texture_needs_update = 1;
1311 }
1312 
bg_grad(PyMOLGlobals * G)1313 void bg_grad(PyMOLGlobals * G) {
1314   COrtho *I = G->Ortho;
1315   float top[3];
1316   float bottom[3];
1317   int bg_gradient = SettingGet_b(G, NULL, NULL, cSetting_bg_gradient);
1318   int bg_image_mode = SettingGet_b(G, NULL, NULL, cSetting_bg_image_mode);
1319   const char * bg_image_filename = SettingGetGlobal_s(G, cSetting_bg_image_filename);
1320   short bg_image = bg_image_filename && bg_image_filename[0];
1321   short bg_is_solid = 0;
1322   short is_repeat = bg_gradient ? 0 : 1;
1323   int ok = true;
1324   copy3f(ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_rgb_top)), top);
1325   copy3f(ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_rgb_bottom)), bottom);
1326 
1327   if (!bg_gradient && !bg_image && !I->bgData){
1328     const float *bg_rgb = ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_rgb));
1329     SceneGLClearColor(bg_rgb[0], bg_rgb[1], bg_rgb[2], 1.0);
1330     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
1331       return;
1332   }
1333 
1334   if (!G->ShaderMgr->ShadersPresent()){
1335     float zero[3] = { 0.f, 0.f, 0.f } ;
1336     const float *bg_rgb = ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_rgb));
1337     bg_is_solid = !equal3f(bg_rgb, zero);
1338       SceneGLClearColor(bg_rgb[0], bg_rgb[1], bg_rgb[2], 1.0);
1339       glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
1340     return;
1341     }
1342   if (bg_image || I->bgData){
1343     is_repeat = (bg_image_mode==0 || bg_image_mode==1) ? 0 : 1;
1344   }
1345 
1346   glDisable(GL_DEPTH_TEST);
1347 
1348   {
1349     if (!I->bgCGO) {
1350       CGO *cgo = CGONew(G), *cgo2 = NULL;
1351       ok &= CGOBegin(cgo, GL_TRIANGLE_STRIP);
1352       if (ok)
1353 	ok &= CGOVertex(cgo, -1.f, -1.f, 0.98f);
1354       if (ok)
1355 	ok &= CGOVertex(cgo, 1.f, -1.f, 0.98f);
1356       if (ok)
1357 	ok &= CGOVertex(cgo, -1.f, 1.f, 0.98f);
1358       if (ok)
1359 	ok &= CGOVertex(cgo, 1.f, 1.f, 0.98f);
1360       if (ok)
1361 	ok &= CGOEnd(cgo);
1362       if (ok)
1363 	ok &= CGOStop(cgo);
1364       if (ok)
1365 	cgo2 = CGOCombineBeginEnd(cgo, 0);
1366       CHECKOK(ok, cgo2);
1367       CGOFree(cgo);
1368       if (ok)
1369 	I->bgCGO = CGOOptimizeToVBONotIndexed(cgo2, 0);
1370       if (ok){
1371 	CGOChangeShadersTo(I->bgCGO, GL_DEFAULT_SHADER_WITH_SETTINGS, GL_BACKGROUND_SHADER);
1372 	I->bgCGO->use_shader = true;
1373       } else {
1374 	CGOFree(I->bgCGO);
1375       }
1376       CGOFree(cgo2);
1377     }
1378     if (ok && !bg_is_solid && (I->bgData && (!I->bg_texture_id || I->bg_texture_needs_update))){
1379       short is_new = !I->bg_texture_id;
1380       if (is_new){
1381 	glGenTextures(1, &I->bg_texture_id);
1382       }
1383       glActiveTexture(GL_TEXTURE4);
1384       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1385       glBindTexture(GL_TEXTURE_2D, I->bg_texture_id);
1386       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, is_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
1387       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, is_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
1388       {
1389 	int bg_image_linear = SettingGet_b(G, NULL, NULL, cSetting_bg_image_linear);
1390 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bg_image_linear ? GL_LINEAR : GL_NEAREST);
1391 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bg_image_linear ? GL_LINEAR : GL_NEAREST);
1392       }
1393       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1394 		   I->bgData->getWidth(), I->bgData->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)I->bgData->bits());
1395 
1396       bg_image = false;
1397       bg_gradient = I->bg_texture_needs_update = 0;
1398     }
1399 
1400     if (ok && !bg_is_solid && (bg_image && (!I->bg_texture_id || I->bg_texture_needs_update))){
1401       // checking to see if bg_image_filename can be loaded into texture
1402       auto bgImage = MyPNGRead(bg_image_filename);
1403       if(bgImage) {
1404         I->bgWidth = bgImage->getWidth();
1405         I->bgHeight = bgImage->getHeight();
1406 
1407 	short is_new = !I->bg_texture_id;
1408 	if (is_new){
1409 	  glGenTextures(1, &I->bg_texture_id);
1410 	}
1411 
1412 	glActiveTexture(GL_TEXTURE4);
1413 	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1414 	glBindTexture(GL_TEXTURE_2D, I->bg_texture_id);
1415 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, is_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
1416 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, is_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
1417 	{
1418 	  int bg_image_linear = SettingGet_b(G, NULL, NULL, cSetting_bg_image_linear);
1419 	  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bg_image_linear ? GL_LINEAR : GL_NEAREST);
1420 	  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bg_image_linear ? GL_LINEAR : GL_NEAREST);
1421 	}
1422         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bgImage->getWidth(),
1423             bgImage->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
1424             (GLvoid*) bgImage->bits());
1425         bgImage.reset();
1426       bg_gradient = I->bg_texture_needs_update = 0;
1427       } else {
1428 	PRINTFB(G, FB_Ortho, FB_Errors)
1429 	  "Ortho: bg_grad: bg_image_filename='%s' cannot be loaded, unset\n", bg_image_filename
1430 	  ENDFB(G);
1431 	SettingSetGlobal_s(G, cSetting_bg_image_filename, "");
1432 	G->ShaderMgr->Reload_All_Shaders();
1433       }
1434       bgImage = nullptr;
1435     }
1436 
1437     if (ok && !bg_is_solid && bg_gradient && (!I->bg_texture_id || I->bg_texture_needs_update)){
1438       short is_new = !I->bg_texture_id;
1439       int tex_dim = BACKGROUND_TEXTURE_SIZE;
1440       pymol::Image tmpImg(tex_dim, tex_dim);
1441       I->bg_texture_needs_update = 0;
1442       if (is_new){
1443 	glGenTextures(1, &I->bg_texture_id);
1444       }
1445       glActiveTexture(GL_TEXTURE4);
1446       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1447       glBindTexture(GL_TEXTURE_2D, I->bg_texture_id);
1448       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, is_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
1449       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, is_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
1450       {
1451 	int bg_image_linear = SettingGet_b(G, NULL, NULL, cSetting_bg_image_linear);
1452 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bg_image_linear ? GL_LINEAR : GL_NEAREST);
1453 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bg_image_linear ? GL_LINEAR : GL_NEAREST);
1454       }
1455 
1456       {
1457 	int a, b;
1458 	unsigned char *q, val[4];
1459 	float bot[3] = { bottom[0]*255, bottom[1]*255, bottom[2]*255 };
1460 	float tmpb, diff[3] = { 255.f*(top[0] - bottom[0]),
1461 				255.f*(top[1] - bottom[1]),
1462 				255.f*(top[2] - bottom[2]) };
1463 
1464 	for(b = 0; b < BACKGROUND_TEXTURE_SIZE; b++) {
1465 	  tmpb = b / (BACKGROUND_TEXTURE_SIZE-1.f);
1466 	  val[0] = (unsigned char)pymol_roundf(bot[0] + tmpb*diff[0]) ;
1467 	  val[1] = (unsigned char)pymol_roundf(bot[1] + tmpb*diff[1]) ;
1468 	  val[2] = (unsigned char)pymol_roundf(bot[2] + tmpb*diff[2]) ;
1469 	  for(a = 0; a < BACKGROUND_TEXTURE_SIZE; a++) {
1470 	    q = tmpImg.bits() + (4 * BACKGROUND_TEXTURE_SIZE * b) + 4 * a;
1471 	    *(q++) = val[0];
1472 	    *(q++) = val[1];
1473 	    *(q++) = val[2];
1474 	    *(q++) = 255;
1475 	  }
1476 	}
1477       }
1478       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1479 		   tex_dim, tex_dim, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)tmpImg.bits());
1480     }
1481     if (ok && I->bgCGO) {
1482        	CGORenderGL(I->bgCGO, NULL, NULL, NULL, NULL, NULL);
1483 	glEnable(GL_DEPTH_TEST);
1484     }
1485   }
1486 
1487   glEnable(GL_DEPTH_TEST);
1488 }
1489 
OrthoDoDraw(PyMOLGlobals * G,int render_mode)1490 void OrthoDoDraw(PyMOLGlobals * G, int render_mode)
1491 {
1492   COrtho *I = G->Ortho;
1493   CGO *orthoCGO = NULL;
1494   int x, y;
1495   int l, lcount;
1496   char *str;
1497   int showLines;
1498   int height;
1499   int overlay, text;
1500   int rightSceneMargin;
1501   int internal_feedback;
1502   int times = 1, origtimes = 0;
1503   int double_pump = false;
1504   const float *bg_color;
1505   int skip_prompt = 0;
1506   int render = false;
1507   int internal_gui_mode = SettingGetGlobal_i(G, cSetting_internal_gui_mode);
1508 #ifdef _PYMOL_OPENVR
1509   bool offscreen_vr = false;
1510   int openvr_text = 0;
1511 #endif
1512 
1513   int generate_shader_cgo = 0;
1514 
1515   I->RenderMode = render_mode;
1516   if(SettingGetGlobal_b(G, cSetting_seq_view)) {
1517     SeqUpdate(G);
1518     I->HaveSeqViewer = true;
1519   } else if(I->HaveSeqViewer) {
1520     SeqUpdate(G);
1521     I->HaveSeqViewer = false;
1522   }
1523 
1524   if(SettingGet_i(G, NULL, NULL, cSetting_internal_prompt))
1525     skip_prompt = 0;
1526   else
1527     skip_prompt = 1;
1528 
1529   double_pump = SettingGet_i(G, NULL, NULL, cSetting_stereo_double_pump_mono);
1530   bg_color = ColorGet(G, SettingGet_color(G, NULL, NULL, cSetting_bg_rgb));
1531 
1532   I->OverlayColor[0] = 1.0F - bg_color[0];
1533   I->OverlayColor[1] = 1.0F - bg_color[1];
1534   I->OverlayColor[2] = 1.0F - bg_color[2];
1535   if(diff3f(I->OverlayColor, bg_color) < 0.25)
1536     zero3f(I->OverlayColor);
1537 
1538   PRINTFD(G, FB_Ortho)
1539     " OrthoDoDraw: entered.\n" ENDFD;
1540   if(G->HaveGUI && G->ValidContext) {
1541 
1542 #ifdef GL_FRAMEBUFFER_UNDEFINED
1543     // prevents GL_INVALID_FRAMEBUFFER_OPERATION (0x0506) on macOS
1544     // with external Monitor
1545     if (glCheckFramebufferStatus &&
1546         glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_UNDEFINED)
1547       return;
1548 #endif
1549 
1550     if(Feedback(G, FB_OpenGL, FB_Debugging))
1551       PyMOLCheckOpenGLErr("OrthoDoDraw checkpoint 0");
1552 
1553     if(SettingGetGlobal_b(G, cSetting_internal_gui)) {
1554       switch (SettingGetGlobal_i(G, cSetting_internal_gui_mode)) {
1555       case 0:
1556         rightSceneMargin = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_width));
1557         break;
1558       default:
1559         rightSceneMargin = 0;
1560         break;
1561       }
1562     } else {
1563       rightSceneMargin = 0;
1564     }
1565 
1566     internal_feedback = SettingGetGlobal_i(G, cSetting_internal_feedback);
1567 
1568     overlay = OrthoGetOverlayStatus(G);
1569     switch (overlay) {
1570     case -1:                   /* auto overlay */
1571       overlay = I->CurLine - I->AutoOverlayStopLine;
1572       if(overlay < 0) {
1573         overlay += (OrthoSaveLines + 1);
1574       }
1575       if(internal_feedback > 1) {
1576         overlay -= (internal_feedback - 1);
1577       }
1578       if(overlay < 0)
1579         overlay = 0;
1580       break;
1581     case 1:                    /* default -- user overlay_lines */
1582       overlay = SettingGetGlobal_i(G, cSetting_overlay_lines);
1583       break;
1584     }
1585 
1586     text = SettingGetGlobal_b(G, cSetting_text);
1587     if(text)
1588       overlay = 0;
1589 
1590     if(overlay || (!text) || render_mode < 0)
1591       if(!SceneRenderCached(G))
1592         render = true;
1593 
1594     if(render_mode < 0) {
1595 #ifdef _PYMOL_OPENVR
1596       times = 2;
1597       double_pump = false;
1598       offscreen_vr = true;
1599       OrthoDrawBuffer(G, GL_BACK);
1600       SceneGLClear(G, GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
1601       openvr_text = SettingGetGlobal_i(G, cSetting_openvr_gui_text);
1602 #endif
1603     } else if(render_mode < 2) {
1604       if(SceneMustDrawBoth(G)) {
1605         OrthoDrawBuffer(G, GL_BACK_LEFT);
1606         SceneGLClear(G, GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
1607         OrthoDrawBuffer(G, GL_BACK_RIGHT);
1608         SceneGLClear(G, GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
1609         times = 2;
1610         double_pump = true;
1611       } else {
1612         OrthoDrawBuffer(G, GL_BACK);
1613         SceneGLClear(G, GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
1614         times = 1;
1615         double_pump = false;
1616       }
1617     } else {
1618       times = 1;
1619       double_pump = false;
1620     }
1621 
1622     I->DrawTime = -I->LastDraw;
1623     I->LastDraw = UtilGetSeconds(G);
1624     I->DrawTime += I->LastDraw;
1625     ButModeSetRate(G, (float) I->DrawTime);
1626 
1627     if(render && (render_mode < 2))
1628       SceneRender(G, NULL, 0, 0, NULL, 0, 0, 0,
1629                   SettingGetGlobal_b(G, cSetting_image_copy_always));
1630     else if (text){
1631       bg_grad(G);  // only render the background for text
1632     }
1633     SceneGLClearColor(0.0, 0.0, 0.0, 1.0);
1634 
1635     origtimes = times;
1636     while(times--) {
1637       bool draw_text = text;
1638 
1639       switch (times) {
1640       case 1:
1641 #ifdef _PYMOL_OPENVR
1642         if(offscreen_vr) {
1643           draw_text = text || (openvr_text == 1);
1644           OrthoDrawBuffer(G, GL_NONE);
1645           OpenVRMenuBufferStart(G, I->Width, I->Height);
1646         } else
1647 #endif
1648           OrthoDrawBuffer(G, GL_BACK_LEFT);
1649         break;
1650       case 0:
1651 #ifdef _PYMOL_OPENVR
1652         if(offscreen_vr) {
1653           draw_text = text && (openvr_text != 2);
1654         }
1655 #endif
1656         if(double_pump) {
1657           OrthoDrawBuffer(G, GL_BACK_RIGHT);
1658         } else
1659           OrthoDrawBuffer(G, GL_BACK);
1660         break;
1661       }
1662 
1663       OrthoPushMatrix(G);
1664 
1665       if (G->ShaderMgr->ShadersPresent()){
1666 	if(SettingGetGlobal_b(G, cSetting_internal_gui) &&
1667 	   SettingGetGlobal_b(G, cSetting_use_shaders)){
1668 	  CGO *orthoFastCGO = CGONew(G);
1669           CGOFree(I->orthoFastCGO);
1670 	  if (G->Ortho->fastDraw(orthoFastCGO)){
1671 	    int ok = true;
1672 	    CGO *expandedCGO;
1673 	    CGOStop(orthoFastCGO);
1674 	    expandedCGO = CGOExpandDrawTextures(orthoFastCGO, 0);
1675 	    CHECKOK(ok, expandedCGO);
1676 	    if (ok)
1677 	      I->orthoFastCGO = CGOOptimizeScreenTexturesAndPolygons(expandedCGO, 0);
1678 	    CHECKOK(ok, orthoFastCGO);
1679 	    CGOFree(orthoFastCGO);
1680 	    CGOFree(expandedCGO);
1681 	  } else {
1682 	    CGOFree(orthoFastCGO);
1683 	  }
1684 	  if (!I->orthoCGO){
1685 	    orthoCGO = CGONew(G);
1686 	    generate_shader_cgo = true;
1687 	  } else {
1688 	    OrthoRenderCGO(G);
1689 	    OrthoPopMatrix(G);
1690 #ifdef _PYMOL_OPENVR
1691 	    if (offscreen_vr && times) {
1692 	      OpenVRMenuBufferFinish(G);
1693 	    }
1694 #endif
1695 	    continue;
1696 	  }
1697 	}
1698       }
1699       x = I->X;
1700       y = I->Y;
1701 
1702       if(I->DrawText && internal_feedback) {    /* moved to avoid conflict with menus */
1703         Block *block = SceneGetBlock(G);
1704         height = block->rect.bottom;
1705         switch (internal_gui_mode) {
1706         case 0:
1707 	  if (generate_shader_cgo){
1708 	    CGOColor(orthoCGO, 0.f, 0.f, 0.f);
1709 	    CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
1710 	    CGOVertex(orthoCGO, I->Width - rightSceneMargin, height - 1, 0.f);
1711 	    CGOVertex(orthoCGO, I->Width - rightSceneMargin, 0, 0.f);
1712 	    CGOVertex(orthoCGO, 0.f, height - 1,0.f);
1713 	    CGOVertex(orthoCGO, 0.f, 0.f, 0.f);
1714 	    CGOEnd(orthoCGO);
1715 	  } else {
1716 	    glColor3f(0.0, 0.0, 0.0);
1717 	    glBegin(GL_POLYGON);
1718 	    glVertex2i(I->Width - rightSceneMargin, height - 1);
1719 	    glVertex2i(I->Width - rightSceneMargin, 0);
1720 	    glVertex2i(0, 0);
1721 	    glVertex2i(0, height - 1);
1722 	    glEnd();
1723 	  }
1724           /* deliberate fall-through */
1725         case 1:
1726 	  if (generate_shader_cgo){
1727 	    CGOColor(orthoCGO, 0.3f, 0.3f, 0.3f);
1728 	    CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
1729 	    CGOVertex(orthoCGO, 1 + I->Width - rightSceneMargin, height, 0.f);
1730 	    CGOVertex(orthoCGO, 1 + I->Width - rightSceneMargin, height - 1, 0.f);
1731 	    CGOVertex(orthoCGO, -1, height, 0.f);
1732 	    CGOVertex(orthoCGO, -1, height - 1, 0.f);
1733 	    CGOEnd(orthoCGO);
1734 	  } else {
1735 	    glColor3f(0.3, 0.3, 0.3);
1736 	    glBegin(GL_LINES);
1737 	    glVertex2i(1 + I->Width - rightSceneMargin, height - 1);
1738 	    glVertex2i(-1, height - 1);
1739 	    glEnd();
1740 	  }
1741           break;
1742         }
1743       }
1744 
1745       PRINTFD(G, FB_Ortho)
1746         " OrthoDoDraw: drawing blocks...\n" ENDFD;
1747 
1748       if(SettingGetGlobal_b(G, cSetting_internal_gui)) {
1749         int internal_gui_width = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_width));
1750         if(internal_gui_mode != 2) {
1751 	  if (generate_shader_cgo){
1752 	    CGOColor(orthoCGO, 0.3f, 0.3f, 0.3f);
1753 	    CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
1754 	    CGOVertex(orthoCGO, I->Width - internal_gui_width, 0.f, 0.f);
1755 	    CGOVertex(orthoCGO, I->Width - internal_gui_width + 1.f, 0.f, 0.f);
1756 	    CGOVertex(orthoCGO, I->Width - internal_gui_width, I->Height, 0.f);
1757 	    CGOVertex(orthoCGO, I->Width - internal_gui_width + 1.f, I->Height, 0.f);
1758 	    CGOEnd(orthoCGO);
1759 	  } else {
1760 	    glColor3f(0.3, 0.3, 0.3);
1761 	    glBegin(GL_LINES);
1762 	    glVertex2i(I->Width - internal_gui_width, 0);
1763 	    glVertex2i(I->Width - internal_gui_width, I->Height);
1764 	    glEnd();
1765 	  }
1766         }
1767       }
1768 
1769       OrthoRestorePrompt(G);
1770 
1771       if(I->DrawText) {
1772         int adjust_at = 0;
1773         /* now print the text */
1774 
1775         lcount = 0;
1776         x = cOrthoLeftMargin;
1777         y = cOrthoBottomMargin + MovieGetPanelHeight(G);
1778 
1779         if(draw_text || I->SplashFlag)
1780           showLines = I->ShowLines;
1781         else {
1782           showLines = internal_feedback + overlay;
1783         }
1784         if(internal_feedback)
1785           adjust_at = internal_feedback + 1;
1786 
1787         l = (I->CurLine - (lcount + skip_prompt)) & OrthoSaveLines;
1788 
1789 	if (orthoCGO)
1790 	  CGOColorv(orthoCGO, I->TextColor);
1791 	else
1792 	  glColor3fv(I->TextColor);
1793 
1794         while(l >= 0) {
1795           lcount++;
1796           if(lcount > showLines)
1797             break;
1798           if(lcount == adjust_at)
1799             y += 4;
1800           str = I->Line[l & OrthoSaveLines];
1801           if(internal_gui_mode) {
1802             TextSetColor(G, I->OverlayColor);
1803           } else if(strncmp(str, I->Prompt, 6) == 0) {
1804             if(lcount < adjust_at)
1805               TextSetColor(G, I->TextColor);
1806             else {
1807               if(length3f(I->OverlayColor) < 0.5)
1808                 TextSetColor(G, I->OverlayColor);
1809               else
1810                 TextSetColor(G, I->TextColor);
1811             }
1812           } else
1813             TextSetColor(G, I->OverlayColor);
1814           TextSetPos2i(G, x, y);
1815           if(str) {
1816             TextDrawStr(G, str ORTHOCGOARGVAR);
1817             if((lcount == 1) && (I->InputFlag)) {
1818               if(!skip_prompt) {
1819                 if(I->CursorChar >= 0) {
1820                   TextSetPos2i(G, x + cOrthoCharWidth * I->CursorChar, y);
1821                 }
1822                 TextDrawChar(G, '_' ORTHOCGOARGVAR);
1823               }
1824             }
1825           }
1826           l = (I->CurLine - (lcount + skip_prompt)) & OrthoSaveLines;
1827           y = y + cOrthoLineHeight;
1828         }
1829       }
1830 
1831       OrthoDrawWizardPrompt(G ORTHOCGOARGVAR);
1832 
1833       if(draw_text || I->SplashFlag) {
1834         Block *block;
1835         int active_tmp;
1836         block = SeqGetBlock(G);
1837         active_tmp = block->active;
1838         block->active = false;
1839         G->Ortho->draw(orthoCGO);
1840         block->active = active_tmp;
1841       } else {
1842         G->Ortho->draw(orthoCGO);
1843       }
1844 
1845       PRINTFD(G, FB_Ortho)
1846         " OrthoDoDraw: blocks drawn.\n" ENDFD;
1847 
1848       if(I->LoopFlag) {
1849         const float *vc = ColorGet(G, cColorFront);
1850 	if (generate_shader_cgo){
1851 	  CGOColor(orthoCGO, vc[0], vc[1], vc[2]);
1852 
1853 	  CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
1854 	  CGOVertex(orthoCGO, I->LoopRect.left, I->LoopRect.bottom, 0.f);
1855 	  CGOVertex(orthoCGO, I->LoopRect.left, I->LoopRect.top+1, 0.f);
1856 	  CGOVertex(orthoCGO, I->LoopRect.left+1, I->LoopRect.bottom, 0.f);
1857 	  CGOVertex(orthoCGO, I->LoopRect.left+1, I->LoopRect.top+1, 0.f);
1858 	  CGOEnd(orthoCGO);
1859 	  CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
1860 	  CGOVertex(orthoCGO, I->LoopRect.left, I->LoopRect.top, 0.f);
1861 	  CGOVertex(orthoCGO, I->LoopRect.left, I->LoopRect.top+1, 0.f);
1862 	  CGOVertex(orthoCGO, I->LoopRect.right, I->LoopRect.top, 0.f);
1863 	  CGOVertex(orthoCGO, I->LoopRect.right, I->LoopRect.top+1, 0.f);
1864 	  CGOEnd(orthoCGO);
1865 	  CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
1866 	  CGOVertex(orthoCGO, I->LoopRect.right, I->LoopRect.bottom, 0.f);
1867 	  CGOVertex(orthoCGO, I->LoopRect.right, I->LoopRect.top+1, 0.f);
1868 	  CGOVertex(orthoCGO, I->LoopRect.right+1, I->LoopRect.bottom, 0.f);
1869 	  CGOVertex(orthoCGO, I->LoopRect.right+1, I->LoopRect.top+1, 0.f);
1870 	  CGOEnd(orthoCGO);
1871 	  CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
1872 	  CGOVertex(orthoCGO, I->LoopRect.left, I->LoopRect.bottom, 0.f);
1873 	  CGOVertex(orthoCGO, I->LoopRect.left, I->LoopRect.bottom+1, 0.f);
1874 	  CGOVertex(orthoCGO, I->LoopRect.right, I->LoopRect.bottom, 0.f);
1875 	  CGOVertex(orthoCGO, I->LoopRect.right, I->LoopRect.bottom+1, 0.f);
1876 	  CGOEnd(orthoCGO);
1877 	} else {
1878 	  glColor3f(vc[0], vc[1], vc[2]);
1879 	  glBegin(GL_LINE_LOOP);
1880 	  glVertex2i(I->LoopRect.left, I->LoopRect.top);
1881 	  glVertex2i(I->LoopRect.right, I->LoopRect.top);
1882 	  glVertex2i(I->LoopRect.right, I->LoopRect.bottom);
1883 	  glVertex2i(I->LoopRect.left, I->LoopRect.bottom);
1884 	  glVertex2i(I->LoopRect.left, I->LoopRect.top);
1885 	  glEnd();
1886 	}
1887       }
1888 
1889 
1890       /* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
1891 #ifdef PYMOL_EVAL
1892       OrthoDrawEvalMessage(G ORTHOCGOARGVAR);
1893 #endif
1894 #ifdef PYMOL_BETA
1895       OrthoDrawBetaMessage(G);
1896 #endif
1897 #ifdef JYMOL_EVAL
1898       OrthoDrawEvalMessage(G);
1899 #endif
1900 #ifdef PYMOL_EDU
1901       OrthoDrawEduMessage(G);
1902 #endif
1903 #ifdef PYMOL_COLL
1904       OrthoDrawCollMessage(G);
1905 #endif
1906 #ifdef AXPYMOL_EVAL
1907       OrthoDrawAxMessage(G);
1908 #endif
1909 
1910       /* END PROPRIETARY CODE SEGMENT */
1911 
1912       OrthoPopMatrix(G);
1913 
1914 #ifdef _PYMOL_OPENVR
1915       if (offscreen_vr && times) {
1916         OpenVRMenuBufferFinish(G);
1917       }
1918 #endif
1919 
1920       if(Feedback(G, FB_OpenGL, FB_Debugging))
1921         PyMOLCheckOpenGLErr("OrthoDoDraw final checkpoint");
1922 
1923     }                           /* while */
1924 
1925   }
1926 
1927   if (generate_shader_cgo){
1928     int ok = true;
1929 
1930     {
1931 #ifdef SHOW_FONT_TEXTURE
1932       /*  This shows the font texture in the middle of the screen, we might want to debug it */
1933       CGO *testOrthoCGO =  orthoCGO;
1934       //      CGO *testOrthoCGO =  CGONew(G);
1935       float minx = 100.f, maxx = 612.f, miny = 100.f, maxy = 612.f;
1936       short texcoord = true;
1937       CGOAlpha(testOrthoCGO, .5f);
1938       CGOColor(testOrthoCGO, 0.f, 0.f, 0.f);
1939       CGOBegin(testOrthoCGO, GL_TRIANGLE_STRIP);
1940       if (texcoord)
1941 	CGOTexCoord2f(testOrthoCGO, 1.f, 1.f);
1942       CGOVertex(testOrthoCGO, maxx, maxy, 0.f);
1943       if (texcoord)
1944 	CGOTexCoord2f(testOrthoCGO, 1.f, 0.f);
1945       CGOVertex(testOrthoCGO, maxx, miny, 0.f);
1946       if (texcoord)
1947 	CGOTexCoord2f(testOrthoCGO, 0.f, 1.f);
1948       CGOVertex(testOrthoCGO, minx, maxy, 0.f);
1949       if (texcoord)
1950 	CGOTexCoord2f(testOrthoCGO, 0.f, 0.f);
1951       CGOVertex(testOrthoCGO, minx, miny, 0.f);
1952       CGOEnd(testOrthoCGO);
1953       CGOStop(testOrthoCGO);
1954 #else
1955     CGOStop(orthoCGO);
1956 #endif
1957     }
1958     {
1959       CGO *expandedCGO = CGOExpandDrawTextures(orthoCGO, 0);
1960       CHECKOK(ok, expandedCGO);
1961       if (ok)
1962 	I->orthoCGO = CGOOptimizeScreenTexturesAndPolygons(expandedCGO, 0);
1963       CGOFree(orthoCGO);
1964       CGOFree(expandedCGO);
1965 
1966       while(origtimes--){
1967 	switch (origtimes){
1968 	case 1:
1969 #ifdef _PYMOL_OPENVR
1970 	  if(offscreen_vr) {
1971 	    OrthoDrawBuffer(G, GL_NONE);
1972 	    OpenVRMenuBufferStart(G, I->Width, I->Height);
1973 	  } else
1974 #endif
1975 	    OrthoDrawBuffer(G, GL_BACK_LEFT);
1976 	  break;
1977 	case 0:
1978 	  if(double_pump) {
1979 	    OrthoDrawBuffer(G, GL_BACK_RIGHT);
1980 	  } else
1981 	    OrthoDrawBuffer(G, GL_BACK);
1982 	  break;
1983 	}
1984 	OrthoPushMatrix(G);
1985 	OrthoRenderCGO(G);
1986 	OrthoPopMatrix(G);
1987 #ifdef _PYMOL_OPENVR
1988         if (offscreen_vr && origtimes) {
1989           OpenVRMenuBufferFinish(G);
1990         }
1991 #endif
1992       }
1993     }
1994   }
1995 
1996   I->DirtyFlag = false;
1997   PRINTFD(G, FB_Ortho)
1998     " OrthoDoDraw: leaving...\n" ENDFD;
1999 
2000 }
2001 
OrthoRenderCGO(PyMOLGlobals * G)2002 void OrthoRenderCGO(PyMOLGlobals * G){
2003   COrtho *I = G->Ortho;
2004   if (I->orthoCGO) {
2005     SceneDrawImageOverlay(G, 0, NULL);
2006     glDisable(GL_DEPTH_TEST);
2007     glEnable(GL_BLEND);
2008     if (I->orthoCGO)
2009       CGORenderGL(I->orthoCGO, NULL, NULL, NULL, NULL, NULL);
2010     if (I->orthoFastCGO)
2011       CGORenderGL(I->orthoFastCGO, NULL, NULL, NULL, NULL, NULL);
2012     G->ShaderMgr->Disable_Current_Shader();
2013     glEnable(GL_DEPTH_TEST);
2014   }
2015 }
2016 /*========================================================================*/
2017 
OrthoDrawWizardPrompt(PyMOLGlobals * G ORTHOCGOARG)2018 void OrthoDrawWizardPrompt(PyMOLGlobals * G ORTHOCGOARG)
2019 {
2020   /* assumes PMGUI */
2021 
2022   COrtho *I = G->Ortho;
2023 
2024   char *vla, *p;
2025   int nLine;
2026   int x, y;
2027   int nChar, c, ll;
2028   int maxLen;
2029   BlockRect rect;
2030   int prompt_mode = SettingGetGlobal_i(G, cSetting_wizard_prompt_mode);
2031   int gui_mode = SettingGetGlobal_b(G, cSetting_internal_gui_mode);
2032   float *text_color = I->WizardTextColor;
2033   float black[3] = { 0.0F, 0.0F, 0.0F };
2034 
2035   if(I->WizardPromptVLA && prompt_mode) {
2036     vla = I->WizardPromptVLA;
2037 
2038     if(gui_mode)
2039       text_color = black;
2040     nLine = UtilCountStringVLA(vla);
2041     if(nLine) {
2042       nChar = VLAGetSize(I->WizardPromptVLA);
2043 
2044       /* count max line length; it's strlen - X,
2045        * where X is 4*n, where n is the number
2046        * of colors in the text label */
2047 
2048       maxLen = 0;
2049       p = vla;
2050       ll = 0;
2051       c = nChar;
2052       while(c > 0) {
2053         if(!*p) {
2054           if(maxLen < ll)
2055             maxLen = ll;
2056           ll = 0;
2057           p++;
2058           c--;
2059         } else if(TextStartsWithColorCode(p)) {
2060           p += 4;
2061           c -= 4;
2062         } else {
2063           ll++;
2064           p++;
2065           c--;
2066         }
2067       }
2068 
2069       /* determine the coordinates from which to draw the text;
2070        * need to make adjustments for the sequence viewer */
2071 
2072       rect.top = I->Height;
2073       if(I->HaveSeqViewer)
2074         if(!SettingGetGlobal_b(G, cSetting_seq_view_location)) {
2075           rect.top -= SeqGetHeight(G);
2076         }
2077 
2078       if(prompt_mode != 3) {
2079         rect.top -= cWizardTopMargin;
2080         rect.left = cWizardLeftMargin;
2081       } else {
2082         rect.top -= 1;
2083         rect.left = 1;
2084       }
2085 
2086       rect.bottom = rect.top - (nLine * cOrthoLineHeight + 2 * cWizardBorder) - 2;
2087       rect.right = rect.left + cOrthoCharWidth * maxLen + 2 * cWizardBorder + 1;
2088 
2089       if(prompt_mode == 1) {
2090 	if (orthoCGO){
2091 	  if(SettingGetGlobal_b(G, cSetting_internal_gui_mode)) {
2092 	    CGOColor(orthoCGO, 1.0, 1.0F, 1.0F);
2093 	  } else {
2094 	    CGOColorv(orthoCGO, I->WizardBackColor);
2095 	  }
2096 	  CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
2097 	  CGOVertex(orthoCGO, rect.right, rect.top, 0.f);
2098 	  CGOVertex(orthoCGO, rect.right, rect.bottom, 0.f);
2099 	  CGOVertex(orthoCGO, rect.left, rect.top, 0.f);
2100 	  CGOVertex(orthoCGO, rect.left, rect.bottom, 0.f);
2101 	  CGOEnd(orthoCGO);
2102 	} else {
2103 	  if(SettingGetGlobal_b(G, cSetting_internal_gui_mode)) {
2104 	    glColor3f(1.0, 1.0F, 1.0F);
2105 	  } else {
2106 	    glColor3fv(I->WizardBackColor);
2107 	  }
2108 	  glBegin(GL_POLYGON);
2109 	  glVertex2i(rect.right, rect.top);
2110 	  glVertex2i(rect.right, rect.bottom);
2111 	  glVertex2i(rect.left, rect.bottom);
2112 	  glVertex2i(rect.left, rect.top);
2113 	  glEnd();
2114 	}
2115       }
2116       if (orthoCGO)
2117 	CGOColorv(orthoCGO, text_color);
2118       else
2119 	glColor3fv(text_color);
2120 
2121       x = rect.left + cWizardBorder;
2122       y = rect.top - (cWizardBorder + cOrthoLineHeight);
2123 
2124       vla = I->WizardPromptVLA;
2125 
2126       /* count max line length */
2127 
2128       TextSetColor(G, text_color);
2129       TextSetPos2i(G, x, y);
2130       p = vla;
2131       ll = 0;
2132       c = nChar;
2133       /* set the char color, position the characters and draw the text */
2134       while(c > 0) {
2135         if(TextSetColorFromCode(G, p, text_color)) {
2136           p += 4;
2137           c -= 4;
2138         }
2139         if(c--) {
2140           if(*p) {
2141             TextDrawChar(G, *p ORTHOCGOARGVAR);
2142           }
2143           if(!*(p++)) {
2144             y = y - cOrthoLineHeight;
2145             TextSetPos2i(G, x, y);
2146           }
2147         }
2148       }
2149     }
2150   }
2151 }
2152 
OrthoLayoutPanel(PyMOLGlobals * G,int m_top,int m_left,int m_bottom,int m_right)2153 static void OrthoLayoutPanel(PyMOLGlobals * G,
2154                              int m_top, int m_left, int m_bottom, int m_right)
2155 {
2156   COrtho *I = G->Ortho;
2157   Block *block = NULL;
2158 
2159   int controlHeight = DIP2PIXEL(20);
2160   int butModeHeight = ButModeGetHeight(G);
2161   int wizardHeight = I->WizardHeight;
2162 
2163   int controlBottom = m_bottom;
2164   int butModeBottom = controlBottom + controlHeight;
2165   int wizardBottom = butModeBottom + butModeHeight;
2166   int executiveBottom = wizardBottom + wizardHeight;
2167 
2168   int height = I->Height;
2169 
2170   if(SettingGetGlobal_b(G, cSetting_internal_gui)) {
2171     /* The Executive Block consists of the area in which object entries are rendered,
2172        if the wizard doesn't exist, then this region extends all the way down to the
2173        top of the ButMode block */
2174     block = ExecutiveGetBlock(G);
2175     block->setMargin(m_top, m_left, executiveBottom, m_right);
2176     block->active = true;
2177 
2178     /* The Wizard Block is shown when a wizard is loaded, it is the area between the
2179        Executive Block and the ButMode Block, and is used for Wizard-related info/buttons */
2180     block = WizardGetBlock(G);
2181     block->setMargin(height - executiveBottom + 1, m_left, wizardBottom, m_right);
2182     block->active = false;
2183 
2184     /* The ButMode block shows info about which Mouse Mode, Selecting Mode, State info,
2185        and other info like frame rate. It is located under the Wizard Block, and above
2186        the Control Block */
2187     block = ButModeGetBlock(G);
2188     block->setMargin(height - wizardBottom + 1, m_left, butModeBottom, m_right);
2189     block->active = true;
2190 
2191     /* Controls are the Movie/Scene arrow buttons at the very bottom */
2192     block = ControlGetBlock(G);
2193     block->setMargin(height - butModeBottom + 1, m_left, controlBottom, m_right);
2194     block->active = true;
2195   } else {
2196     /* The Executive Block consists of the area in which object entries are rendered,
2197        if the wizard doesn't exist, then this region extends all the way down to the
2198        top of the ButMode block */
2199     block = ExecutiveGetBlock(G);
2200     block->setMargin(m_right, m_bottom, m_right, m_bottom);
2201     block->active = false;
2202 
2203     /* The Wizard Block is shown when a wizard is loaded, it is the area between the
2204        Executive Block and the ButMode Block, and is used for Wizard-related info/buttons */
2205     block = WizardGetBlock(G);
2206     block->setMargin(m_right, m_bottom, m_right, m_bottom);
2207     block->active = false;
2208 
2209     /* The ButMode block shows info about which Mouse Mode, Selecting Mode, State info,
2210        and other info like frame rate. It is located under the Wizard Block, and above
2211        the Control Block */
2212     block = ButModeGetBlock(G);
2213     block->setMargin(m_right, m_bottom, m_right, m_bottom);
2214     block->active = false;
2215 
2216     /* Controls are the Movie/Scene arrow buttons at the very bottom */
2217     block = ControlGetBlock(G);
2218     block->setMargin(m_right, m_bottom, m_right, m_bottom);
2219     block->active = false;
2220   }
2221 }
2222 
2223 
2224 /*========================================================================*/
OrthoReshape(PyMOLGlobals * G,int width,int height,int force)2225 void OrthoReshape(PyMOLGlobals * G, int width, int height, int force)
2226 {
2227   COrtho *I = G->Ortho;
2228 
2229   if(!G->HaveGUI && width < 0)
2230     return;
2231 
2232   Block *block = NULL;
2233   int sceneBottom, sceneRight = 0;
2234   int textBottom = 0;
2235   int internal_gui_width;
2236   int internal_feedback;
2237   int sceneTop = 0;
2238 
2239   PRINTFD(G, FB_Ortho)
2240     " OrthoReshape-Debug: %d %d\n", width, height ENDFD;
2241 
2242   I->WrapXFlag = false;
2243   if(width > 0) {
2244     int stereo = SettingGetGlobal_i(G, cSetting_stereo);
2245     int stereo_mode = SettingGetGlobal_i(G, cSetting_stereo_mode);
2246     if (stereo){
2247       switch (stereo_mode) {
2248       case cStereo_geowall:
2249       case cStereo_dynamic:
2250 	width = width / 2;
2251 	I->WrapXFlag = true;
2252 	break;
2253       }
2254     }
2255   }
2256 
2257   if((width != I->Width) || (height != I->Height) || force) {
2258     if(width < 0)
2259       width = I->Width;
2260     if(height < 0)
2261       height = I->Height;
2262 
2263     I->Height = height;
2264     I->Width = width;
2265     I->ShowLines = height / cOrthoLineHeight;
2266 
2267     textBottom += MovieGetPanelHeight(G);
2268     I->TextBottom = textBottom;
2269 
2270     internal_feedback = SettingGetGlobal_i(G, cSetting_internal_feedback);
2271     if(internal_feedback)
2272       sceneBottom =
2273         textBottom + (internal_feedback - 1) * cOrthoLineHeight + cOrthoBottomSceneMargin;
2274     else
2275       sceneBottom = textBottom;
2276 
2277     internal_gui_width = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_width));
2278     if(!SettingGetGlobal_b(G, cSetting_internal_gui)) {
2279       internal_gui_width = 0;
2280       sceneRight = 0;
2281     } else {
2282       switch (SettingGetGlobal_i(G, cSetting_internal_gui_mode)) {
2283       case 2:
2284         sceneRight = 0;
2285         sceneBottom = 0;
2286         break;
2287       default:
2288         sceneRight = internal_gui_width;
2289         break;
2290       }
2291     }
2292 
2293     {
2294       int seqHeight;
2295       block = SeqGetBlock(G);
2296       block->active = true;
2297 
2298       /* reloate the sequence viewer as necessary */
2299 
2300       if(SettingGetGlobal_b(G, cSetting_seq_view_location)) {
2301 
2302         block->setMargin(height - sceneBottom - 10, 0, sceneBottom, sceneRight);
2303           block->reshape(width, height);
2304         seqHeight = SeqGetHeight(G);
2305         block->setMargin(height - sceneBottom - seqHeight, 0, sceneBottom,
2306                        sceneRight);
2307         if(!SettingGetGlobal_b(G, cSetting_seq_view_overlay)) {
2308           sceneBottom += seqHeight;
2309         }
2310 
2311       } else {
2312 
2313         block->setMargin(0, 0, height - 10, sceneRight);
2314           block->reshape(width, height);
2315         seqHeight = SeqGetHeight(G);
2316         block->setMargin(0, 0, height - seqHeight, sceneRight);
2317         if(!SettingGetGlobal_b(G, cSetting_seq_view_overlay)) {
2318           sceneTop = seqHeight;
2319         }
2320       }
2321     }
2322 
2323     OrthoLayoutPanel(G, 0, width - internal_gui_width, textBottom, 0);
2324 
2325     block = MovieGetBlock(G);
2326     block->setMargin(height - textBottom, 0, 0, 0);
2327     block->active = textBottom ? true : false;
2328 
2329     block = SceneGetBlock(G);
2330     block->setMargin(sceneTop, 0, sceneBottom, sceneRight);
2331 
2332     block = NULL;
2333     for(auto block : I->Blocks){
2334       block->reshape(width, height);
2335     }
2336 
2337     WizardRefresh(G);           /* safe to call even if no wizard exists */
2338   }
2339   SceneInvalidateStencil(G);
2340   G->ShaderMgr->ResetUniformSet();
2341   OrthoInvalidateDoDraw(G);
2342   OrthoDirty(G);
2343 }
2344 
2345 
2346 /*========================================================================*/
OrthoReshapeWizard(PyMOLGlobals * G,ov_size wizHeight)2347 void OrthoReshapeWizard(PyMOLGlobals * G, ov_size wizHeight)
2348 {
2349   COrtho *I = G->Ortho;
2350   I->WizardHeight = wizHeight;
2351 
2352   if(SettingGetGlobal_b(G, cSetting_internal_gui)) {
2353     Block *block;
2354     int internal_gui_width = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_width));
2355 
2356     OrthoLayoutPanel(G, 0, I->Width - internal_gui_width, I->TextBottom, 0);
2357 
2358     block = ExecutiveGetBlock(G);
2359     block->reshape(I->Width, I->Height);
2360     block = WizardGetBlock(G);
2361     block->reshape(I->Width, I->Height);
2362     block->active = wizHeight ? true : false;
2363   }
2364 }
2365 
2366 /*========================================================================*/
OrthoGetWrapClickSide(PyMOLGlobals * G)2367 int OrthoGetWrapClickSide(PyMOLGlobals * G)
2368 {
2369   return G->Ortho->WrapClickSide;
2370 }
2371 
2372 
2373 /*========================================================================*/
OrthoButton(PyMOLGlobals * G,int button,int state,int x,int y,int mod)2374 int OrthoButton(PyMOLGlobals * G, int button, int state, int x, int y, int mod)
2375 {
2376   COrtho *I = G->Ortho;
2377   Block *block = NULL;
2378   int handled = 0;
2379 
2380   PRINTFB(G, FB_Ortho, FB_Blather)
2381     "OrthoButton: button:%d, state=%d, x=%d, y=%d, mod=%d\n",
2382     button,state,x,y,mod
2383     ENDFB(G);
2384 
2385   switch (button) {
2386   case P_GLUT_BUTTON_SCROLL_FORWARD:
2387   case P_GLUT_BUTTON_SCROLL_BACKWARD:
2388     if((button != I->ActiveButton) && (I->ActiveButton>=0) && (I->ActiveButton<3)) {
2389       /* suppress wheel events when a button is already pushed */
2390       return 1;
2391     }
2392   }
2393 
2394   if(I->WrapXFlag) {
2395     if(state == P_GLUT_DOWN) {
2396       x = get_wrap_x(x, NULL, G->Option->winX, &I->WrapClickSide);
2397     } else {
2398       x = get_wrap_x(x, &I->LastX, G->Option->winX, &I->WrapClickSide);
2399     }
2400   } else {
2401     I->WrapClickSide = 0;
2402   }
2403 
2404   OrthoRemoveSplash(G);
2405   OrthoRemoveAutoOverlay(G);
2406   I->X = x;
2407   I->Y = y;
2408   I->LastX = x;
2409   I->LastY = y;
2410   I->LastModifiers = mod;
2411 
2412   if(state == P_GLUT_DOWN) {
2413     I->ActiveButton = button;
2414     if(I->GrabbedBy) {
2415       block = I->GrabbedBy;
2416     } else if(!block)
2417       block = G->Ortho->findBlock(x, y);
2418     if(block) {
2419       I->ClickedIn = block;
2420       handled = block->click(button, x, y, mod);
2421     }
2422   } else if(state == P_GLUT_UP) {
2423     if(I->IssueViewportWhenReleased) {
2424       OrthoCommandIn(G, "viewport");
2425       I->IssueViewportWhenReleased = false;
2426     }
2427 
2428     if(I->GrabbedBy) {
2429       block = I->GrabbedBy;
2430       handled = block->release(button, x, y, mod);
2431       I->ClickedIn = NULL;
2432     }
2433     if(I->ClickedIn) {
2434       block = I->ClickedIn;
2435       handled = block->release(button, x, y, mod);
2436       I->ClickedIn = NULL;
2437     }
2438     I->ActiveButton = -1;
2439   }
2440   if (handled)
2441     OrthoInvalidateDoDraw(G);
2442   return (handled);
2443 }
2444 
2445 struct COrthoButtonDeferred : public CDeferred {
2446   int button;
2447   int state;
2448   int x;
2449   int y;
2450   int mod;
COrthoButtonDeferredCOrthoButtonDeferred2451   COrthoButtonDeferred(PyMOLGlobals *G) : CDeferred(G) {}
2452 };
2453 
2454 static
OrthoButtonDeferred(COrthoButtonDeferred * d)2455 void OrthoButtonDeferred(COrthoButtonDeferred * d)
2456 {
2457   OrthoButton(d->m_G, d->button, d->state, d->x, d->y, d->mod);
2458 }
2459 
OrthoButtonDefer(PyMOLGlobals * G,int button,int state,int x,int y,int mod)2460 int OrthoButtonDefer(PyMOLGlobals * G, int button, int state, int x, int y, int mod)
2461 {
2462   auto d = pymol::make_unique<COrthoButtonDeferred>(G);
2463   if(d) {
2464     d->fn = (DeferredFn *)OrthoButtonDeferred;
2465     d->button = button;
2466     d->state = state;
2467     d->x = x;
2468     d->y = y;
2469     d->mod = mod;
2470   }
2471   OrthoDefer(G, std::move(d));
2472   return 1;
2473 }
2474 
2475 /*========================================================================*/
OrthoDrag(PyMOLGlobals * G,int x,int y,int mod)2476 int OrthoDrag(PyMOLGlobals * G, int x, int y, int mod)
2477 {
2478   COrtho *I = G->Ortho;
2479 
2480   Block *block = NULL;
2481   int handled = 0;
2482 
2483   if(I->WrapXFlag) {
2484     x = get_wrap_x(x, &I->LastX, G->Option->winX, NULL);
2485   }
2486 
2487   I->LastX = x;
2488   I->LastY = y;
2489   I->LastModifiers = mod;
2490 
2491   I->X = x;
2492   I->Y = y;
2493   if(I->GrabbedBy) {
2494     block = I->GrabbedBy;
2495       handled = block->drag(x, y, mod);
2496   } else if(I->ClickedIn) {
2497     block = I->ClickedIn;
2498     handled = block->drag(x, y, mod);
2499   }
2500   if (handled && block!=SceneGetBlock(G))  // if user is not draging inside scene, then update OrthoCGO
2501     OrthoInvalidateDoDraw(G);
2502   return (handled);
2503 }
2504 
2505 
2506 /*========================================================================*/
OrthoSplash(PyMOLGlobals * G)2507 void OrthoSplash(PyMOLGlobals * G)
2508 {
2509 
2510 /* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
2511 #ifdef _PYMOL_IP_SPLASH
2512 #include"OrthoIPSplash.h"
2513 #else
2514   if(G->Option->incentive_product) {
2515 #ifdef AXPYMOL_EVAL
2516     PRINTF
2517       " AxPyMOL(TM) Evaluation Product - Copyright (c) Schrodinger, LLC.\n \n"
2518       ENDF(G);
2519     PRINTF " This Executable Build integrates and extends Open-Source PyMOL " ENDF(G);
2520     PRINTF _PyMOL_VERSION ENDF(G);
2521     PRINTF ".\n" ENDF(G);
2522 #else
2523     PRINTF " PyMOL(TM) Incentive Product - Copyright (c) Schrodinger, LLC.\n \n"
2524       ENDF(G);
2525     PRINTF " This Executable Build integrates and extends Open-Source PyMOL " ENDF(G);
2526     PRINTF _PyMOL_VERSION ENDF(G);
2527     PRINTF ".\n" ENDF(G);
2528 #endif
2529   } else
2530 
2531 /* END PROPRIETARY CODE SEGMENT */
2532   {
2533     /* Splash message for unrestricted access open-source versions... */
2534     PRINTF " PyMOL(TM) Molecular Graphics System, Version " ENDF(G);
2535     PRINTF _PyMOL_VERSION ENDF(G);
2536     PRINTF ".\n" ENDF(G);
2537     PRINTF " Copyright (c) Schrodinger, LLC.\n All Rights Reserved.\n \n"
2538       ENDF(G);
2539 
2540     PRINTF "    Created by Warren L. DeLano, Ph.D. \n \n" ENDF(G);
2541 
2542     /* PRINTF " Other Major Authors and Contributors:\n\n" ENDF(G);
2543      * PRINTF " Ralf W. Grosse-Kunstleve, Ph.D.\n \n" ENDF(G);
2544      *
2545      * NOTICE: Enduring thanks to Ralf, but in point of fact, his
2546      * sglite module is no longer used by PyMOL, and thus we should
2547      * not mislead everyone by asserting otherwise... */
2548 
2549     PRINTF "    PyMOL is user-supported open-source software.  Although some versions\n"
2550       ENDF(G);
2551     PRINTF "    are freely available, PyMOL is not in the public domain.\n \n" ENDF(G);
2552 
2553     PRINTF "    If PyMOL is helpful in your work or study, then please volunteer \n"
2554       ENDF(G);
2555     PRINTF
2556       "    support for our ongoing efforts to create open and affordable scientific\n"
2557       ENDF(G);
2558     PRINTF
2559       "    software by purchasing a PyMOL Maintenance and/or Support subscription.\n\n"
2560       ENDF(G);
2561 
2562     PRINTF "    More information can be found at \"http://www.pymol.org\".\n \n" ENDF(G);
2563 
2564     PRINTF "    Enter \"help\" for a list of commands.\n" ENDF(G);
2565     PRINTF
2566       "    Enter \"help <command-name>\" for information on a specific command.\n\n"
2567       ENDF(G);
2568 
2569     PRINTF " Hit ESC anytime to toggle between text and graphics.\n\n" ENDF(G);
2570   }
2571 #endif
2572 }
2573 
2574 
2575 /*========================================================================*/
OrthoInit(PyMOLGlobals * G,int showSplash)2576 int OrthoInit(PyMOLGlobals * G, int showSplash)
2577 {
2578   COrtho *I = NULL;
2579 
2580   if((I = (G->Ortho = new COrtho()))) {
2581 
2582     I->ActiveButton = -1;
2583     I->Pushed = 0;
2584     I->cmdActiveQueue = &(*I->cmdQueue.begin());
2585     I->cmdNestLevel = 0;
2586     I->RenderMode = 0;
2587     I->WrapXFlag = false;
2588 
2589     I->WizardBackColor[0] = 0.2F;
2590     I->WizardBackColor[1] = 0.2F;
2591     I->WizardBackColor[2] = 0.2F;
2592     I->WizardTextColor[0] = 0.2F;
2593     I->WizardTextColor[1] = 1.0F;
2594     I->WizardTextColor[2] = 0.2F;
2595 
2596     I->GrabbedBy = NULL;
2597     I->ClickedIn = NULL;
2598     I->DrawText = 1;
2599     I->HaveSeqViewer = false;
2600     I->TextColor[0] = 0.83F;
2601     I->TextColor[1] = 0.83F;
2602     I->TextColor[2] = 1.0;
2603     I->OverlayColor[0] = 1.0;
2604     I->OverlayColor[1] = 1.0;
2605     I->OverlayColor[2] = 1.0;
2606     I->CurLine = 1000;
2607     I->PromptChar = 0;
2608     I->CurChar = 0;
2609     I->CurLine = 0;
2610     I->AutoOverlayStopLine = 0;
2611     I->CursorChar = -1;
2612     I->HistoryLine = 0;
2613     I->HistoryView = 0;
2614     I->Line[I->CurLine & OrthoSaveLines][I->CurChar] = 0;
2615     I->WizardPromptVLA = NULL;
2616     I->SplashFlag = false;
2617     I->ShowLines = 1;
2618     I->Saved[0] = 0;
2619     I->DirtyFlag = true;
2620     I->ActiveGLBuffer = GL_NONE;
2621     I->LastDraw = UtilGetSeconds(G);
2622     I->DrawTime = 0.0;
2623     I->bg_texture_id = 0;
2624     I->bg_texture_needs_update = 0;
2625     I->bgCGO = NULL;
2626     I->bgData = nullptr;
2627     I->orthoCGO = NULL;
2628     I->orthoFastCGO = NULL;
2629 
2630     if(showSplash) {
2631       OrthoSplash(G);
2632       I->SplashFlag = true;
2633     }
2634     /*  OrthoFeedbackIn(G," "); */
2635     I->CurLine++;
2636 
2637 #ifndef _PYMOL_LIB
2638     /* prompt (and typing) should only be shown for PyMOL, not libpymol */
2639     strcpy(I->Prompt, "PyMOL>");
2640 #endif
2641     strcpy(I->Line[I->CurLine], I->Prompt);
2642     I->CurChar = (I->PromptChar = strlen(I->Prompt));
2643     I->InputFlag = 1;
2644 
2645     /*printf("orthoNewLine: CC: %d CL:%d PC: %d IF:L %d\n",I->CurChar,I->CurLine,
2646        I->PromptChar,I->InputFlag); */
2647 
2648     PopInit(G);
2649     {
2650       int a;
2651       for(a = 0; a <= OrthoHistoryLines; a++)
2652         I->History[a][0] = 0;
2653     }
2654 
2655     return 1;
2656   } else {
2657     return 0;
2658   }
2659 }
2660 
2661 
2662 /*========================================================================*/
OrthoFree(PyMOLGlobals * G)2663 void OrthoFree(PyMOLGlobals * G)
2664 {
2665   COrtho *I = G->Ortho;
2666 
2667   VLAFreeP(I->WizardPromptVLA);
2668   PopFree(G);
2669   {
2670     I->cmdActiveQueue = NULL;
2671   }
2672 
2673   I->bgData = nullptr;
2674 
2675     CGOFree(I->bgCGO);
2676   CGOFree(I->orthoCGO);
2677   CGOFree(I->orthoFastCGO);
2678   delete G->Ortho;
2679 }
2680 
2681 
2682 /*========================================================================*/
OrthoPushMatrix(PyMOLGlobals * G)2683 void OrthoPushMatrix(PyMOLGlobals * G)
2684 {
2685   COrtho *I = G->Ortho;
2686 
2687   if(G->HaveGUI && G->ValidContext) {
2688 
2689     if(!I->Pushed) {
2690       glGetIntegerv(GL_VIEWPORT, I->ViewPort);
2691     }
2692     switch (I->RenderMode) {
2693     case 2:
2694       glViewport(I->ViewPort[0] + I->ViewPort[2], I->ViewPort[1],
2695                  I->ViewPort[2], I->ViewPort[3]);
2696       break;
2697     case 1:
2698     default:
2699       glViewport(I->ViewPort[0], I->ViewPort[1], I->ViewPort[2], I->ViewPort[3]);
2700     }
2701 
2702     glMatrixMode(GL_PROJECTION);
2703     glPushMatrix();
2704     glLoadIdentity();
2705     glOrtho(0, I->ViewPort[2], 0, I->ViewPort[3], -100, 100);
2706     glMatrixMode(GL_MODELVIEW);
2707     glPushMatrix();
2708     glLoadIdentity();
2709     glTranslatef(0.33F, 0.33F, 0.0F);   /* this generates better
2710                                            rasterization on macs */
2711 
2712     glDisable(GL_ALPHA_TEST);
2713     glDisable(GL_LIGHTING);
2714     glDisable(GL_FOG);
2715     glDisable(GL_NORMALIZE);
2716     glDisable(GL_COLOR_MATERIAL);
2717     glDisable(GL_LINE_SMOOTH);
2718     glDisable(GL_BLEND);
2719     glDisable(GL_DEPTH_TEST);
2720     glDisable(GL_DITHER);
2721 
2722 #ifndef PURE_OPENGL_ES_2
2723     glShadeModel(SettingGetGlobal_b(G, cSetting_pick_shading) ? GL_FLAT : GL_SMOOTH);
2724 #endif
2725     if(G->Option->multisample)
2726       glDisable(0x809D);        /* GL_MULTISAMPLE_ARB */
2727     I->Pushed++;
2728   }
2729   /*  glDisable(GL_ALPHA_TEST);
2730      glDisable(GL_CULL_FACE);
2731      glDisable(GL_POINT_SMOOTH); */
2732 
2733 }
2734 
2735 
2736 /*========================================================================*/
OrthoPopMatrix(PyMOLGlobals * G)2737 void OrthoPopMatrix(PyMOLGlobals * G)
2738 {
2739   COrtho *I = G->Ortho;
2740   if(G->HaveGUI && G->ValidContext) {
2741 
2742     if(I->Pushed >= 0) {
2743       glViewport(I->ViewPort[0], I->ViewPort[1], I->ViewPort[2], I->ViewPort[3]);
2744       glPopMatrix();
2745       glMatrixMode(GL_PROJECTION);
2746       glPopMatrix();
2747       glMatrixMode(GL_MODELVIEW);
2748       I->Pushed--;
2749     }
2750   }
2751 }
2752 
OrthoGetPushed(PyMOLGlobals * G)2753 int OrthoGetPushed(PyMOLGlobals * G)
2754 {
2755   return G->Ortho->Pushed;
2756 }
2757 
2758 
2759 /*========================================================================*/
OrthoCommandIn(COrtho & ortho,const char * buffer)2760 void OrthoCommandIn(COrtho& ortho, const char* buffer)
2761 {
2762   if (ortho.cmdActiveQueue) {
2763     ortho.cmdActiveQueue->emplace(buffer);
2764   }
2765 }
2766 
OrthoCommandSetBusy(PyMOLGlobals * G,int busy)2767 void OrthoCommandSetBusy(PyMOLGlobals * G, int busy){
2768   COrtho *I = G->Ortho;
2769   I->cmdActiveBusy = busy;
2770 }
2771 
2772 /*========================================================================*/
OrthoPasteIn(PyMOLGlobals * G,const char * buffer)2773 void OrthoPasteIn(PyMOLGlobals * G, const char *buffer)
2774 {
2775   COrtho *I = G->Ortho;
2776   int curLine = I->CurLine & OrthoSaveLines;
2777   int execFlag = false;
2778   OrthoLineType buf2;
2779 
2780   if(I->InputFlag) {
2781     if(I->CursorChar >= 0) {
2782       strcpy(buf2, I->Line[curLine] + I->CursorChar);
2783       strcpy(I->Line[curLine] + I->CursorChar, buffer);
2784       I->CurChar = strlen(I->Line[curLine]);
2785       I->CursorChar = I->CurChar;
2786       while((I->Line[curLine][I->CurChar - 1] == 10)
2787             || (I->Line[curLine][I->CurChar - 1] == 13)) {
2788         execFlag = true;
2789         I->CurChar--;
2790         I->Line[curLine][I->CurChar] = 0;
2791         if(I->CurChar <= I->PromptChar)
2792           break;
2793       }
2794       if(!execFlag) {
2795         strcpy(I->Line[curLine] + I->CursorChar, buf2);
2796         I->CurChar = strlen(I->Line[curLine]);
2797       }
2798     } else {
2799       strcat(I->Line[curLine], buffer);
2800       I->CurChar = strlen(I->Line[curLine]);
2801       while((I->Line[curLine][I->CurChar - 1] == 10)
2802             || (I->Line[curLine][I->CurChar - 1] == 13)) {
2803         execFlag = true;
2804         I->CurChar--;
2805         I->Line[curLine][I->CurChar] = 0;
2806         if(I->CurChar <= I->PromptChar)
2807           break;
2808       }
2809     }
2810   } else {
2811     OrthoRestorePrompt(G);
2812 
2813     while((I->Line[curLine][I->CurChar - 1] == 10)
2814           || (I->Line[curLine][I->CurChar - 1] == 13)) {
2815       execFlag = true;
2816       I->CurChar--;
2817       I->Line[curLine][I->CurChar] = 0;
2818       if(I->CurChar <= I->PromptChar)
2819         break;
2820     }
2821   }
2822   if(execFlag) {
2823     printf("[%s]\n", I->Line[curLine]);
2824     OrthoParseCurrentLine(G);
2825   } else
2826     I->InputFlag = true;
2827 }
2828 
2829 /* TODO: Removed. Check in Mobile PyMOL to see if needed - PYMOL-3148*/
OrthoSetBackgroundImage(PyMOLGlobals * G,const char * image_data,int width,int height)2830 void OrthoSetBackgroundImage(PyMOLGlobals * G, const char *image_data, int width, int height){
2831 #if 0
2832   COrtho *I = G->Ortho;
2833   int buff_total = width * height;
2834   short should_update = 0;
2835   if (I->bgData){
2836     FreeP(I->bgData);
2837     I->bgData = NULL;
2838     I->bgWidth = 0;
2839     I->bgHeight = 0;
2840     should_update = 1;
2841   }
2842   if (buff_total){
2843     I->bgData = pymol::malloc<unsigned char>(buff_total*4);
2844     I->bgWidth = width;
2845     I->bgHeight = height;
2846     memcpy(I->bgData, image_data, buff_total * 4);
2847     should_update = 1;
2848 #ifdef _PYMOL_IOS
2849     {  /* for now, the background is black for background images */
2850       float bg[] = {0.f, 0.f, 0.f };
2851       ColorUpdateFront(G, bg);
2852       ExecutiveInvalidateRep(G, "all", cRepAll, cRepInvColor);
2853     }
2854 #endif
2855   }
2856   if (should_update){
2857     G->ShaderMgr->Reload_All_Shaders();
2858     I->bg_texture_needs_update = 1;
2859   }
2860 #endif
2861 }
2862 
OrthoInvalidateDoDraw(PyMOLGlobals * G)2863 void OrthoInvalidateDoDraw(PyMOLGlobals * G)
2864 {
2865   COrtho *I = G->Ortho;
2866   if (I->orthoCGO){
2867     CGOFree(I->orthoCGO);
2868     PyMOL_NeedRedisplay(G->PyMOL);
2869   }
2870 }
2871 
draw(CGO * orthoCGO)2872 void COrtho::draw(CGO* orthoCGO)
2873 {
2874   for (auto block : Blocks) {
2875     block->recursiveDraw(orthoCGO);
2876   }
2877 }
2878 
fastDraw(CGO * orthoCGO)2879 bool COrtho::fastDraw(CGO* orthoCGO)
2880 {
2881   bool ret{false};
2882   for (auto block : Blocks) {
2883     ret |= block->recursiveFastDraw(orthoCGO);
2884   }
2885   return ret;
2886 }
2887 
findBlock(int x,int y)2888 Block* COrtho::findBlock(int x, int y)
2889 {
2890   for (auto blockIter = Blocks.rbegin(); blockIter != Blocks.rend();
2891        ++blockIter) {
2892     auto blockFound = (*blockIter)->recursiveFind(x, y);
2893     if (blockFound != nullptr) {
2894       return blockFound;
2895     }
2896   }
2897   return nullptr;
2898 }
2899