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