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 #include"os_python.h"
18
19 #include"os_predef.h"
20 #include"os_gl.h"
21 #include"os_std.h"
22
23 #include"main.h"
24 #include"PyMOLObject.h"
25 #include"Color.h"
26 #include"Ortho.h"
27 #include"Scene.h"
28 #include"Util.h"
29 #include"Ray.h"
30 #include"PConv.h"
31 #include"Matrix.h"
32 #include"MemoryDebug.h"
33 #include"Movie.h"
34 #include"View.h"
35 #include"Err.h"
36
37 #include"Executive.h"
38 #include"CGO.h"
39 #include"Selector.h"
40 #include"vla.h"
41
ObjectPurgeSettings(CObject * I)42 void ObjectPurgeSettings(CObject * I)
43 {
44 SettingFreeP(I->Setting);
45 I->Setting = NULL;
46 }
47
ObjectMotionTrim(CObject * I,int n_frame)48 void ObjectMotionTrim(CObject *I, int n_frame)
49 {
50 if(I->ViewElem) {
51 VLASize(I->ViewElem,CViewElem,n_frame);
52 }
53 }
54
ObjectMotionGetLength(CObject * I)55 int ObjectMotionGetLength(CObject *I)
56 {
57 if(I->ViewElem) {
58 return VLAGetSize(I->ViewElem);
59 }
60 return 0;
61 }
62
ObjectMotionReinterpolate(CObject * I)63 void ObjectMotionReinterpolate(CObject *I)
64 {
65 float power = SettingGet_f(I->G, NULL, I->Setting, cSetting_motion_power);
66 float bias = SettingGet_f(I->G, NULL, I->Setting, cSetting_motion_bias);
67 int simple = SettingGet_i(I->G, NULL, I->Setting, cSetting_motion_simple);
68 float linear = SettingGet_f(I->G, NULL, I->Setting, cSetting_motion_linear);
69 int hand = SettingGet_i(I->G, NULL, I->Setting, cSetting_motion_hand);
70
71 /*
72 int ObjectMotion(CObject * I, int action, int first,
73 int last, float power, float bias,
74 int simple, float linear, int wrap,
75 int hand, int window, int cycles, int state, int quiet);
76 */
77 ObjectMotion(I, 3, -1, -1, power, bias, simple, linear,
78 SettingGetGlobal_b(I->G,cSetting_movie_loop) ? 1 : 0,
79 hand, 5, 1, -1, 1);
80 }
81
ObjectMotionModify(CObject * I,int action,int index,int count,int target,int freeze,int localize)82 int ObjectMotionModify(CObject *I,int action, int index, int count,int target,int freeze,int localize)
83 {
84 int ok;
85
86 if(I->type == cObjectGroup) { /* propagate */
87 ok = ExecutiveGroupMotionModify(I->G,I,action,index,count,target,freeze);
88 } else {
89 ok = ViewElemModify(I->G, &I->ViewElem,action,index,count,target);
90 if(ok && I->ViewElem) {
91 int size = VLAGetSize(I->ViewElem);
92 int n_frame = MovieGetLength(I->G);
93 if(n_frame != size) {
94 /* extend entire movie */
95 if(!localize)
96 ExecutiveMotionExtend(I->G,true);
97 if((!freeze) && SettingGetGlobal_i(I->G,cSetting_movie_auto_interpolate)) {
98 ExecutiveMotionReinterpolate(I->G);
99 }
100 } else if((!freeze) && SettingGetGlobal_i(I->G,cSetting_movie_auto_interpolate)) {
101 ObjectMotionReinterpolate(I);
102 }
103 }
104 }
105 return ok;
106 }
107
TTTToViewElem(float * TTT,CViewElem * elem)108 static void TTTToViewElem(float *TTT, CViewElem * elem)
109 {
110 float *fp = TTT;
111 double *dp;
112
113 /* convert row-major TTT to column-major ViewElem */
114
115 elem->matrix_flag = true;
116 dp = elem->matrix;
117
118 dp[0] = (double) fp[0];
119 dp[1] = (double) fp[4];
120 dp[2] = (double) fp[8];
121 dp[3] = 0.0;
122
123 dp[4] = (double) fp[1];
124 dp[5] = (double) fp[5];
125 dp[6] = (double) fp[9];
126 dp[7] = 0.0;
127
128 dp[8] = (double) fp[2];
129 dp[9] = (double) fp[6];
130 dp[10] = (double) fp[10];
131 dp[11] = 0.0;
132
133 dp[12] = 0.0;
134 dp[13] = 0.0;
135 dp[14] = 0.0;
136 dp[15] = 1.0;
137
138 /* copy inverse pre */
139
140 elem->pre_flag = true;
141 dp = elem->pre;
142 *(dp++) = (double) -TTT[12];
143 *(dp++) = (double) -TTT[13];
144 *(dp++) = (double) -TTT[14];
145
146 /* copy post */
147
148 elem->post_flag = true;
149 dp = elem->post;
150 *(dp++) = (double) TTT[3];
151 *(dp++) = (double) TTT[7];
152 *(dp++) = (double) TTT[11];
153
154 }
155
TTTFromViewElem(float * TTT,CViewElem * elem)156 static void TTTFromViewElem(float *TTT, CViewElem * elem)
157 {
158 float *fp = TTT;
159 double *dp;
160
161 if(elem->matrix_flag) {
162 dp = elem->matrix;
163
164 fp[0] = (float) dp[0];
165 fp[1] = (float) dp[4];
166 fp[2] = (float) dp[8];
167 fp[3] = 0.0;
168
169 fp[4] = (float) dp[1];
170 fp[5] = (float) dp[5];
171 fp[6] = (float) dp[9];
172 fp[7] = 0.0;
173
174 fp[8] = (float) dp[2];
175 fp[9] = (float) dp[6];
176 fp[10] = (float) dp[10];
177 fp[11] = 0.0;
178
179 fp[12] = 0.0;
180 fp[13] = 0.0;
181 fp[14] = 0.0;
182 fp[15] = 1.0;
183 }
184
185 if(elem->pre_flag) {
186 dp = elem->pre;
187 fp[12] = (float) (-*(dp++));
188 fp[13] = (float) (-*(dp++));
189 fp[14] = (float) (-*(dp++));
190 }
191
192 if(elem->post_flag) {
193 dp = elem->post;
194 fp[3] = (float) *(dp++);
195 fp[7] = (float) *(dp++);
196 fp[11] = (float) *(dp++);
197 }
198 fp[15] = 1.0F;
199 }
200
ObjectGetSpecLevel(CObject * I,int frame)201 int ObjectGetSpecLevel(CObject * I, int frame)
202 {
203 if(I->ViewElem) {
204 int size = VLAGetSize(I->ViewElem);
205 if(frame<0) {
206 int max_level = 0;
207 int i;
208 for(i=0;i<size;i++) {
209 if(max_level < I->ViewElem[i].specification_level)
210 max_level = I->ViewElem[i].specification_level;
211 }
212 return max_level;
213 }
214 if((frame>=0) && (frame<size))
215 return I->ViewElem[frame].specification_level;
216 return 0;
217 }
218 return -1;
219 }
220
ObjectDrawViewElem(CObject * I,BlockRect * rect,int frames ORTHOCGOARG)221 void ObjectDrawViewElem(CObject *I, BlockRect *rect,int frames ORTHOCGOARG)
222 {
223 if(I->ViewElem) {
224 ViewElemDraw(I->G,I->ViewElem,rect,frames,I->Name ORTHOCGOARGVAR);
225 }
226 }
227
ObjectMotion(CObject * I,int action,int first,int last,float power,float bias,int simple,float linear,int wrap,int hand,int window,int cycles,int state,int quiet)228 int ObjectMotion(CObject * I, int action, int first,
229 int last, float power, float bias,
230 int simple, float linear, int wrap,
231 int hand, int window, int cycles, int state, int quiet)
232 {
233 PyMOLGlobals *G = I->G;
234 if(I->type == cObjectGroup) { /* propagate */
235 return ExecutiveGroupMotion(G,I,action,first,last, power,bias,simple,linear,
236 wrap,hand,window,cycles,state,quiet);
237 } else {
238
239 int frame;
240 int nFrame = MovieGetLength(I->G);
241
242 if(wrap<0) {
243 wrap = SettingGet_b(I->G,NULL, I->Setting, cSetting_movie_loop);
244 }
245
246 if(nFrame < 0)
247 nFrame = -nFrame;
248
249 if(!I->ViewElem) {
250 I->ViewElem = pymol::vla<CViewElem>(0);
251 }
252
253 if((action == 7) || (action == 8)) { /* toggle */
254 frame = first;
255 if(first < 0)
256 frame = SceneGetFrame(G);
257 VLACheck(I->ViewElem, CViewElem, frame);
258 if(action == 7) {
259 if(I->ViewElem[frame].specification_level>1) {
260 action = 1;
261 } else {
262 action = 0;
263 }
264 } else if(action == 8) {
265 if(I->ViewElem[frame].specification_level>1) {
266 int frame;
267 action = 3;
268 for(frame=0;frame<nFrame;frame++) {
269 if(I->ViewElem[frame].specification_level==1) {
270 action = 6;
271 break;
272 }
273 }
274 }
275 else if(I->ViewElem[frame].specification_level>0) {
276 action = 6;
277 } else {
278 action = 3;
279 }
280 }
281 }
282
283 if(action == 4) { /* smooth */
284 int save_last = last;
285 if(first < 0)
286 first = 0;
287
288 if(last < 0) {
289 last = nFrame;
290 }
291 if(last >= nFrame) {
292 last = nFrame - 1;
293 }
294 if(first <= last) {
295 int a;
296 VLACheck(I->ViewElem, CViewElem, last);
297 for(a = 0; a < cycles; a++) {
298 ViewElemSmooth(I->ViewElem + first, I->ViewElem + last, window, wrap);
299 }
300 }
301 if(SettingGet_b(I->G, NULL, I->Setting, cSetting_movie_auto_interpolate)){
302 action = 3; /* reinterpolate */
303 last = save_last;
304 }
305 }
306 switch (action) {
307 case 0: /* store */
308 if(!I->TTTFlag) {
309 float mn[3], mx[3], orig[3];
310 if(ExecutiveGetExtent(G, I->Name, mn, mx, true, -1, true)) {
311 average3f(mn, mx, orig);
312 ObjectSetTTTOrigin(I, orig);
313 } else {
314 initializeTTT44f(I->TTT);
315 I->TTTFlag = true;
316 }
317 }
318 if(I->ViewElem && I->TTTFlag) {
319 if(first < 0)
320 first = SceneGetFrame(G);
321 if(last < 0)
322 last = first;
323 {
324 int state_tmp=0, state_flag = false;
325 if(state>=0) {
326 state_tmp = state;
327 state_flag = true;
328 } else if(SettingGetIfDefined_i(G, I->Setting, cSetting_state, &state_tmp)) {
329 state_flag = true;
330 state_tmp--;
331 }
332
333 for(frame = first; frame <= last; frame++) {
334 if((frame >= 0) && (frame < nFrame)) {
335 VLACheck(I->ViewElem, CViewElem, frame);
336 if(!quiet) {
337 PRINTFB(G, FB_Object, FB_Details)
338 " ObjectMotion: Setting frame %d.\n", frame + 1 ENDFB(G);
339 }
340 TTTToViewElem(I->TTT, I->ViewElem + frame);
341
342 if(state_flag) {
343 I->ViewElem[frame].state_flag = state_flag;
344 I->ViewElem[frame].state = state_tmp;
345 }
346
347 if(power!=0.0F) {
348 I->ViewElem[frame].power_flag = true;
349 I->ViewElem[frame].power = power;
350 }
351
352 if(bias > 0.0F) {
353 I->ViewElem[frame].bias_flag = true;
354 I->ViewElem[frame].bias = bias;
355 }
356
357 I->ViewElem[frame].specification_level = 2;
358 }
359
360 }
361 }
362 }
363 break;
364 case 1: /* clear */
365 if(I->ViewElem) {
366 if(first < 0)
367 first = SceneGetFrame(G);
368 if(last < 0)
369 last = first;
370 for(frame = first; frame <= last; frame++) {
371 if((frame >= 0) && (frame < nFrame)) {
372 VLACheck(I->ViewElem, CViewElem, frame);
373 ViewElemArrayPurge(G, I->ViewElem + frame, 1);
374 UtilZeroMem((void *) (I->ViewElem + frame), sizeof(CViewElem));
375 }
376 }
377 }
378 break;
379 case 2: /* interpolate & reinterpolate */
380 case 3:
381 {
382 CViewElem *first_view = NULL, *last_view = NULL;
383 int view_found = false;
384
385 if(first < 0)
386 first = 0;
387 if(first > nFrame) {
388 first = nFrame - 1;
389 }
390
391 if(last < 0) {
392 last = nFrame;
393 if(last) {
394 if(!wrap)
395 last--;
396 else {
397 int frame = 0;
398 VLACheck(I->ViewElem, CViewElem, last);
399 for(frame = 0; frame < last; frame++) {
400 if(I->ViewElem[frame].specification_level > 1) {
401 last += frame;
402 break;
403 }
404 }
405 }
406 }
407 } else {
408 if(last >= nFrame) {
409 last = nFrame;
410 if(last && !wrap)
411 last--;
412 }
413 }
414
415 VLACheck(I->ViewElem, CViewElem, last);
416
417 if(wrap && (last >= nFrame)) {
418 /* if we're interpolating beyond the last frame, then wrap by
419 copying early frames to last frames */
420 int a;
421 for(a = nFrame; a <= last; a++) {
422 ViewElemCopy(G, I->ViewElem + a - nFrame, I->ViewElem + a);
423 }
424 } else if(!wrap) {
425 /* if we're not wrapping, then make sure we nuke any stray / old
426 interpolated frames */
427 frame = nFrame - 1;
428 while(frame>=0) {
429 if(I->ViewElem[frame].specification_level > 1)
430 break;
431 else
432 UtilZeroMem((void *) (I->ViewElem + frame), sizeof(CViewElem));
433 frame--;
434 }
435 }
436 VLACheck(I->ViewElem, CViewElem, last);
437 if(!quiet) {
438 if(action == 2) {
439 if(last == nFrame) {
440 PRINTFB(G, FB_Object, FB_Details)
441 " ObjectMotion: interpolating unspecified frames %d to %d (wrapping).\n",
442 first + 1, last ENDFB(G);
443 } else {
444 PRINTFB(G, FB_Object, FB_Details)
445 " ObjectMotion: interpolating unspecified frames %d to %d.\n", first + 1,
446 last + 1 ENDFB(G);
447 }
448 } else {
449 if(last == nFrame) {
450 PRINTFB(G, FB_Object, FB_Details)
451 " ObjectMotion: reinterpolating all frames %d to %d (wrapping).\n", first + 1,
452 last ENDFB(G);
453 } else {
454 PRINTFB(G, FB_Object, FB_Details)
455 " ObjectMotion: reinterpolating all frames %d to %d.\n", first + 1, last + 1
456 ENDFB(G);
457 }
458 }
459 }
460 for(frame = first; frame <= last; frame++) {
461 if(!first_view) {
462 if(I->ViewElem[frame].specification_level == 2) { /* specified */
463 first_view = I->ViewElem + frame;
464 view_found = true;
465 }
466 } else {
467 CViewElem *view;
468 int interpolate_flag = false;
469 if(I->ViewElem[frame].specification_level == 2) { /* specified */
470 last_view = I->ViewElem + frame;
471 if(action == 2) { /* interpolate */
472 for(view = first_view + 1; view < last_view; view++) {
473 if(!view->specification_level)
474 interpolate_flag = true;
475 }
476 } else {
477 interpolate_flag = true;
478 }
479 if(interpolate_flag) {
480 ViewElemInterpolate(G, first_view, last_view,
481 power, bias, simple, linear, hand, 0.0F);
482 }
483 first_view = last_view;
484 last_view = NULL;
485 }
486 }
487 }
488
489 if(first_view) {
490 if(wrap && (last >= nFrame)) {
491 /* if we're interpolating beyond the last frame, then wrap by
492 copying the last frames back over the early frames */
493 int a;
494 for(a = nFrame; a <= last; a++) {
495 ViewElemCopy(G, I->ViewElem + a, I->ViewElem + a - nFrame);
496 }
497 }
498 }
499
500 if((!view_found) && (last>=first) && (first>=0) && (last<=nFrame)) {
501 UtilZeroMem(I->ViewElem + first, sizeof(CViewElem) * (1 + (last-first)));
502 }
503
504 if(last >= nFrame) { /* now erase temporary views */
505 ViewElemArrayPurge(G, I->ViewElem + nFrame, (1 + last - nFrame));
506 UtilZeroMem((void *) (I->ViewElem + nFrame),
507 sizeof(CViewElem) * (1 + last - nFrame));
508 }
509 }
510 break;
511 case 5: /* reset */
512 if(I->ViewElem) {
513 VLAFreeP(I->ViewElem);
514 }
515 I->ViewElem = pymol::vla<CViewElem>(0);
516 break;
517 case 6: /* uninterpolate */
518 if(I->ViewElem) {
519 if(first < 0)
520 first = 0;
521 if(last < 0) {
522 last = nFrame - 1;
523 }
524 for(frame = first; frame <= last; frame++) {
525 if((frame >= 0) && (frame <= last)) {
526 VLACheck(I->ViewElem, CViewElem, frame);
527 if(I->ViewElem[frame].specification_level < 2) {
528 ViewElemArrayPurge(G, I->ViewElem + frame, 1);
529 UtilZeroMem((void *) (I->ViewElem + frame), sizeof(CViewElem));
530 }
531 }
532 }
533 }
534 break;
535 case 9:
536 if(I->ViewElem) {
537 VLAFreeP(I->ViewElem);
538 }
539 break;
540 }
541 if(I->ViewElem) {
542 VLASize(I->ViewElem,CViewElem,nFrame);
543 }
544 }
545 return 1;
546 }
547
ObjectAdjustStateRebuildRange(CObject * I,int * start,int * stop)548 void ObjectAdjustStateRebuildRange(CObject * I, int *start, int *stop)
549 {
550 /* on entry, start and stop should hold the valid range for the object */
551 int defer_builds_mode =
552 SettingGet_i(I->G, NULL, I->Setting, cSetting_defer_builds_mode);
553 int async_builds = SettingGet_b(I->G, NULL, I->Setting, cSetting_async_builds);
554 int max_threads = SettingGet_i(I->G, NULL, I->Setting, cSetting_max_threads);
555 int all_states = SettingGet_i(I->G, NULL, I->Setting, cSetting_all_states);
556 int dummy;
557 if (all_states)
558 return;
559 if(defer_builds_mode >= 3) {
560 if(SceneObjectIsActive(I->G, I))
561 defer_builds_mode = 2;
562 }
563 switch (defer_builds_mode) {
564 case 1: /* defer geometry builds until needed */
565 case 2: /* defer and destroy continuously for increase memory conservation */
566 if(SettingGetIfDefined_i(I->G, I->Setting, cSetting_state, &dummy)) {
567 /* decoupled...so always build all states. Otherwise, geometry
568 may not be there when we need it... unfortunately, this defeats
569 the purpose of defer_builds_mode! */
570 } else {
571 int min = *start;
572 int max = *stop;
573 int global_state = SceneGetState(I->G);
574 int obj_state = ObjectGetCurrentState(I, false);
575
576 *start = obj_state;
577 if((obj_state != global_state) || (!async_builds) || (max_threads < 1)) {
578 *stop = *start + 1;
579 if(*stop > max )
580 *stop = max;
581 } else {
582 int base = (*start / max_threads);
583 *start = (base) * max_threads;
584 *stop = (base + 1) * max_threads;
585 if(*start < min)
586 *start = min;
587 if(*start > max)
588 *start = max;
589 if(*stop < min)
590 *stop = min;
591 if(*stop > max)
592 *stop = max;
593 }
594 if(*start > obj_state)
595 *start = obj_state;
596 if(*stop <= obj_state)
597 *stop = obj_state + 1;
598 if(*start < 0)
599 *start = 0;
600 }
601 break;
602 case 3: /* object not active, so do not rebuild anything */
603 *stop = *start;
604 break;
605 }
606 }
607
608 /**
609 * Replaces invalid characters in the given object name with an underscore,
610 * or strips them if they are terminal or sequential.
611 * @param[in,out] name Object name to validate
612 * @return true if name was modified, false otherwise
613 */
ObjectMakeValidName(char * name)614 bool ObjectMakeValidName(char *name)
615 {
616 bool modified = false;
617 char *p = name, *q;
618 if(p) {
619 /* currently legal are A to Z, a to z, 0 to 9, -, _, + */
620 while(*p) {
621 switch (*p) {
622 case '+':
623 case '-':
624 case '.':
625 case '^':
626 case '_':
627 break;
628 default:
629 if (('A' <= *p && *p <= 'Z') ||
630 ('a' <= *p && *p <= 'z') ||
631 ('0' <= *p && *p <= '9'))
632 break;
633 /* must be an ASCII-visible character */
634 *p = 1; /* placeholder for non-printable */
635 modified = true;
636 }
637 p++;
638 }
639 /* eliminate sequential and terminal nonprintables */
640 p = name;
641 q = name;
642 while(*p) {
643 if(q == name)
644 while(*p == 1)
645 p++;
646 while((*p == 1) && (p[1] == 1))
647 p++;
648 *q++ = *p++;
649 if(!p[-1])
650 break;
651 }
652 *q = 0;
653 while(q > name) {
654 if(q[-1] == 1) {
655 q[-1] = 0;
656 q--;
657 } else
658 break;
659 }
660 /* convert invalides to underscore */
661 p = name;
662 while(*p) {
663 if(*p == 1)
664 *p = '_';
665 p++;
666 }
667 }
668 return modified;
669 }
670
671 /**
672 * Replaces invalid characters in `name` with an underscore,
673 * or strips them if they are terminal or sequential - if `name` equals a reserved
674 * selection keyword, then also append an underscore.
675 *
676 * @param[in,out] name Object name to validate
677 * @param quiet If false, print warnings if the name gets modified.
678 */
ObjectMakeValidName(PyMOLGlobals * G,char * name,bool quiet)679 void ObjectMakeValidName(PyMOLGlobals * G, char *name, bool quiet)
680 {
681 if (ObjectMakeValidName(name) && !quiet) {
682 PRINTFB(G, FB_Executive, FB_Warnings)
683 " Warning: Invalid characters in '%s' have been replaced or stripped\n",
684 name ENDFB(G);
685 }
686
687 if (SelectorNameIsKeyword(G, name)) {
688 if (!quiet) {
689 PRINTFB(G, FB_Executive, FB_Warnings)
690 " Warning: '%s' is a reserved keyword, appending underscore\n", name
691 ENDFB(G);
692 }
693 strcat(name, "_");
694 return;
695 }
696
697 static bool once_protein = false;
698 static bool once_nucleic = false;
699
700 if (!once_protein && strcmp(name, "protein") == 0) {
701 once_protein = true;
702 } else if (!once_nucleic && strcmp(name, "nucleic") == 0) {
703 once_nucleic = true;
704 } else {
705 return;
706 }
707
708 {
709 // Warn the user if "protein" or "nucleic" are used as names, but
710 // don't modify the name (yet).
711 PRINTFB(G, FB_Executive, FB_Warnings)
712 " Warning: '%s' may become a reserved selection keyword in the future\n", name
713 ENDFB(G);
714 }
715 }
716
717 /**
718 * Get a pointer to an object state.
719 * @param state State (0-indexed) or -2/-3 for current state
720 * @return NULL if state is out of bounds or empty
721 */
getObjectState(int state)722 CObjectState* CObject::getObjectState(int state)
723 {
724 if (state == -2 /* cSelectorUpdateTableCurrentState */ ||
725 state == -3 /* cSelectorUpdateTableEffectiveStates */) {
726 state = getCurrentState();
727 }
728 if (state < 0 || state >= getNFrame()) {
729 return nullptr;
730 }
731 return _getObjectState(state);
732 }
733
734 /**
735 * Get the effective state (0-indexed) of an object, based on the `state` and
736 * `static_singletons` settings. Will not validate the value of the `state`
737 * setting, it could be `<0` or `>=getNFrame()`.
738 */
getCurrentState() const739 int CObject::getCurrentState() const
740 {
741 if (getNFrame() == 1 &&
742 SettingGet<bool>(G, Setting, nullptr, cSetting_static_singletons))
743 return 0;
744 return SettingGet<int>(G, Setting, nullptr, cSetting_state) - 1;
745 }
746
747 /**
748 * Like CObject::getCurrentState() but will return `-1` if the `all_states`
749 * setting is set.
750 *
751 * Note: Clamps negative values at `-1` (all states). The usefulness of this
752 * should be questioned, in particular with `ignore_all_states=true` a caller
753 * is likely to discard all negative values, including -1.
754 *
755 * @param ignore_all_states Boolean flag, should be false. You most likely
756 * should use CObject::getCurrentState() instead of setting `ignore_all_states`
757 * to true.
758 */
ObjectGetCurrentState(CObject * I,int ignore_all_states)759 int ObjectGetCurrentState(CObject * I, int ignore_all_states)
760 {
761 assert("use CObject::getCurrentState()" && !ignore_all_states);
762
763 // the previous implementation (up to PyMOL 1.7.6) ignored
764 // object-level state=0 (all states)
765
766 if (!ignore_all_states &&
767 SettingGet_b(I->G, I->Setting, NULL, cSetting_all_states))
768 return -1;
769
770 return std::max(-1, I->getCurrentState());
771 }
772
ObjectAsPyList(CObject * I)773 PyObject *ObjectAsPyList(CObject * I)
774 {
775 PyObject *result = NULL;
776 result = PyList_New(14);
777 PyList_SetItem(result, 0, PyInt_FromLong(I->type));
778 PyList_SetItem(result, 1, PyString_FromString(I->Name));
779 PyList_SetItem(result, 2, PyInt_FromLong(I->Color));
780 PyList_SetItem(result, 3, PyInt_FromLong(I->visRep));
781 PyList_SetItem(result, 4, PConvFloatArrayToPyList(I->ExtentMin, 3));
782 PyList_SetItem(result, 5, PConvFloatArrayToPyList(I->ExtentMax, 3));
783 PyList_SetItem(result, 6, PyInt_FromLong(I->ExtentFlag));
784 PyList_SetItem(result, 7, PyInt_FromLong(I->TTTFlag));
785 PyList_SetItem(result, 8, SettingAsPyList(I->Setting));
786
787 PyList_SetItem(result, 9, PyInt_FromLong(I->Enabled));
788 PyList_SetItem(result, 10, PyInt_FromLong(I->Context));
789 PyList_SetItem(result, 11, PConvFloatArrayToPyList(I->TTT, 16));
790 if(I->ViewElem) {
791 int nFrame = VLAGetSize(I->ViewElem);
792 PyList_SetItem(result, 12, PyInt_FromLong(nFrame));
793 PyList_SetItem(result, 13, ViewElemVLAAsPyList(I->G, I->ViewElem, nFrame));
794 } else {
795 PyList_SetItem(result, 12, PyInt_FromLong(0));
796 PyList_SetItem(result, 13, PConvAutoNone(NULL));
797 }
798 return (PConvAutoNone(result));
799 }
800
ObjectFromPyList(PyMOLGlobals * G,PyObject * list,CObject * I)801 int ObjectFromPyList(PyMOLGlobals * G, PyObject * list, CObject * I)
802 {
803 int ok = true;
804 int ll = 0;
805 I->G = G;
806 if(ok)
807 ok = (list != NULL);
808 if(ok)
809 ok = PyList_Check(list);
810 if(ok)
811 ll = PyList_Size(list);
812 if(ok)
813 ok = CPythonVal_PConvPyIntToInt_From_List(G, list, 0, reinterpret_cast<int*>(&I->type));
814 if(ok)
815 ok = PConvPyStrToStr(PyList_GetItem(list, 1), I->Name, WordLength);
816 if(ok)
817 ok = PConvPyIntToInt(PyList_GetItem(list, 2), &I->Color);
818 if(ok)
819 I->Color = ColorConvertOldSessionIndex(G, I->Color);
820 if(ok) {
821 PyObject *val = PyList_GetItem(list, 3);
822 if(PyList_Check(val)) {
823 ok = PConvPyListToBitmask(val, &I->visRep, cRepCnt);
824 } else {
825 ok = PConvPyIntToInt(val, &I->visRep);
826 }
827 CPythonVal_Free(val);
828 }
829 if(ok)
830 ok = PConvPyListToFloatArrayInPlaceAutoZero(PyList_GetItem(list, 4), I->ExtentMin, 3);
831 if(ok)
832 ok = PConvPyListToFloatArrayInPlaceAutoZero(PyList_GetItem(list, 5), I->ExtentMax, 3);
833 if(ok)
834 ok = PConvPyIntToInt(PyList_GetItem(list, 6), &I->ExtentFlag);
835 if(ok)
836 ok = PConvPyIntToInt(PyList_GetItem(list, 7), &I->TTTFlag);
837 if(ok)
838 I->Setting = SettingNewFromPyList(G, PyList_GetItem(list, 8));
839 if(ok && (ll > 9))
840 ok = PConvPyIntToInt(PyList_GetItem(list, 9), &I->Enabled);
841 if(ok && (ll > 10))
842 ok = PConvPyIntToInt(PyList_GetItem(list, 10), &I->Context);
843 if(ok && (ll > 11))
844 ok = PConvPyListToFloatArrayInPlaceAutoZero(PyList_GetItem(list, 11), I->TTT, 16);
845 if(ok && (ll > 13)) {
846 PyObject *tmp;
847 int nFrame;
848 VLAFreeP(I->ViewElem);
849 I->ViewElem = NULL;
850 if(ok)
851 ok = PConvPyIntToInt(PyList_GetItem(list, 12), &nFrame);
852 if(ok && nFrame) {
853 tmp = PyList_GetItem(list, 13);
854 if(tmp && !(tmp == Py_None))
855 ok = ViewElemVLAFromPyList(G, tmp, &I->ViewElem, nFrame);
856 }
857 }
858 /* TO SUPPORT BACKWARDS COMPATIBILITY...
859 Always check ll when adding new PyList_GetItem's */
860
861 return (ok);
862 }
863
ObjectCopyHeader(CObject * I,const CObject * src)864 int ObjectCopyHeader(CObject * I, const CObject * src)
865 {
866 int ok = true;
867
868 I->G = src->G;
869 I->type = src->type;
870 UtilNCopy(I->Name, src->Name, WordLength);
871 I->Color = src->Color;
872 I->visRep = src->visRep;
873 copy3f(src->ExtentMin, I->ExtentMin);
874 copy3f(src->ExtentMax, I->ExtentMax);
875
876 I->ExtentFlag = src->ExtentFlag;
877 I->TTTFlag = src->TTTFlag;
878 I->Setting = NULL; /* to do */
879 I->Enabled = src->Enabled;
880 I->Context = src->Context;
881 {
882 int a;
883 for(a = 0; a < 16; a++)
884 I->TTT[a] = src->TTT[a];
885 }
886 I->ViewElem = NULL; /* to do */
887
888 return (ok);
889 }
890
891
892 /*========================================================================*/
ObjectCombineTTT(CObject * I,const float * ttt,int reverse_order,int store)893 void ObjectCombineTTT(CObject * I, const float *ttt, int reverse_order, int store)
894 {
895 if(I->type == cObjectGroup) {
896 ExecutiveGroupCombineTTT(I->G, I, ttt, reverse_order,store);
897 } else {
898 float cpy[16];
899 if(!I->TTTFlag) {
900 I->TTTFlag = true;
901 initializeTTT44f(cpy);
902 } else {
903 UtilCopyMem(cpy, I->TTT, sizeof(float) * 16);
904 }
905 if(reverse_order) {
906 combineTTT44f44f(cpy, ttt, I->TTT);
907 } else {
908 combineTTT44f44f(ttt, cpy, I->TTT);
909 }
910 if(store<0)
911 store = SettingGet_i(I->G, I->Setting, NULL, cSetting_movie_auto_store);
912 if(store && MovieDefined(I->G)) {
913 if(!I->ViewElem)
914 I->ViewElem = pymol::vla<CViewElem>(0);
915 if(I->ViewElem) { /* update motion path waypoint, if active */
916 int frame = SceneGetFrame(I->G);
917 if(frame >= 0) {
918 VLACheck(I->ViewElem, CViewElem, frame);
919 TTTToViewElem(I->TTT, I->ViewElem + frame);
920 I->ViewElem[frame].specification_level = 2;
921 }
922 }
923 }
924 }
925 }
926 /*========================================================================*/
ObjectTranslateTTT(CObject * I,const float * v,int store)927 void ObjectTranslateTTT(CObject * I, const float *v, int store)
928 {
929 if(I->type == cObjectGroup) {
930 ExecutiveGroupTranslateTTT(I->G, I, v, store);
931 } else {
932 if(!I->TTTFlag) {
933 I->TTTFlag = true;
934 initializeTTT44f(I->TTT);
935 }
936 if(v) {
937 I->TTT[3] += v[0];
938 I->TTT[7] += v[1];
939 I->TTT[11] += v[2];
940 }
941 if(store<0)
942 store = SettingGet_i(I->G, I->Setting, NULL, cSetting_movie_auto_store);
943 if(store && MovieDefined(I->G)) {
944 if(!I->ViewElem)
945 I->ViewElem = pymol::vla<CViewElem>(0);
946 if(I->ViewElem) { /* update motion path waypoint, if active */
947 int frame = SceneGetFrame(I->G);
948 if(frame >= 0) {
949 VLACheck(I->ViewElem, CViewElem, frame);
950 TTTToViewElem(I->TTT, I->ViewElem + frame);
951 I->ViewElem[frame].specification_level = 2;
952 }
953 }
954 }
955 }
956 }
957
958
959 /*========================================================================*/
ObjectSetTTT(CObject * I,const float * ttt,int state,int store)960 void ObjectSetTTT(CObject * I, const float *ttt, int state, int store)
961 {
962 if(state < 0) {
963 if(ttt) {
964 UtilCopyMem(I->TTT, ttt, sizeof(float) * 16);
965 I->TTTFlag = true;
966 } else {
967 I->TTTFlag = false;
968 return;
969 }
970 if(store<0)
971 store = SettingGet_i(I->G, I->Setting, NULL, cSetting_movie_auto_store);
972 if(store && MovieDefined(I->G)) {
973 if(!I->ViewElem)
974 I->ViewElem = pymol::vla<CViewElem>(0);
975 if(I->ViewElem) { /* update motion path waypoint, if active */
976 int frame = SceneGetFrame(I->G);
977 if(frame >= 0) {
978 VLACheck(I->ViewElem, CViewElem, frame);
979 TTTToViewElem(I->TTT, I->ViewElem + frame);
980 I->ViewElem[frame].specification_level = 2;
981 }
982 }
983 }
984 } else {
985 /* to do */
986 }
987 }
988
989 /*========================================================================*/
ObjectGetTTT(CObject * I,const float ** ttt,int state)990 int ObjectGetTTT(CObject * I, const float **ttt, int state)
991 {
992 if(state < 0) {
993 if(I->TTTFlag) {
994 *ttt = I->TTT;
995 return 1;
996 } else {
997 *ttt = NULL;
998 }
999
1000 } else {
1001 }
1002 return 0;
1003 }
1004
1005
1006 /*========================================================================*/
ObjectResetTTT(CObject * I,int store)1007 void ObjectResetTTT(CObject * I,int store)
1008 {
1009
1010 I->TTTFlag = false;
1011 if(store<0)
1012 store = SettingGet_i(I->G, I->Setting, NULL, cSetting_movie_auto_store);
1013 if(store && MovieDefined(I->G)) {
1014 if(!I->ViewElem)
1015 I->ViewElem = pymol::vla<CViewElem>(0);
1016 if(I->ViewElem) { /* update motion path waypoint, if active */
1017 int frame = SceneGetFrame(I->G);
1018 if(frame >= 0) {
1019 identity44f(I->TTT);
1020 VLACheck(I->ViewElem, CViewElem, frame);
1021 TTTToViewElem(I->TTT, I->ViewElem + frame);
1022 I->ViewElem[frame].specification_level = 2;
1023 }
1024 }
1025 }
1026 }
1027
1028
1029 /*========================================================================*/
1030 /**
1031 * Get the combined transformation of TTT and state matrix. State matrix is
1032 * only included if `history=true` or `matrix_mode > 0`.
1033 *
1034 * @param state See CObject::getObjectState
1035 * @param history Boolean flag
1036 * @param[out] matrix Homogeneous 4x4 matrix
1037 * @return True if `matrix` was populated
1038 */
ObjectGetTotalMatrix(CObject * I,int state,int history,double * matrix)1039 int ObjectGetTotalMatrix(CObject * I, int state, int history, double *matrix)
1040 {
1041 int result = false;
1042 if(I->TTTFlag) {
1043 convertTTTfR44d(I->TTT, matrix);
1044 result = true;
1045 }
1046
1047 if (!history) {
1048 history =
1049 SettingGet<int>(I->G, I->Setting, nullptr, cSetting_matrix_mode) > 0;
1050 }
1051
1052 if (history) {
1053 {
1054 CObjectState* obj_state = I->getObjectState(state);
1055 if (obj_state) {
1056 if(!obj_state->Matrix.empty()) {
1057 const double *state_matrix = obj_state->Matrix.data();
1058 if(result) {
1059 right_multiply44d44d(matrix, state_matrix);
1060 } else {
1061 copy44d(state_matrix, matrix);
1062 }
1063 result = true;
1064 }
1065 }
1066 }
1067 }
1068 return result;
1069 }
1070
1071
1072 /*========================================================================*/
ObjectPrepareContext(CObject * I,RenderInfo * info)1073 void ObjectPrepareContext(CObject * I, RenderInfo * info)
1074 {
1075 CRay * ray = info ? info->ray : NULL;
1076
1077 if(I->ViewElem) {
1078 int frame = SceneGetFrame(I->G);
1079 if(frame >= 0) {
1080 VLACheck(I->ViewElem, CViewElem, frame);
1081
1082 if(I->Grabbed) {
1083 TTTToViewElem(I->TTT, I->ViewElem + frame);
1084 I->ViewElem[frame].specification_level = 2;
1085 } else {
1086 if(I->ViewElem[frame].specification_level) {
1087 TTTFromViewElem(I->TTT, I->ViewElem + frame);
1088 I->TTTFlag = true;
1089 }
1090 if(I->ViewElem[frame].state_flag) {
1091 SettingCheckHandle(I->G,&I->Setting);
1092 if(I->Setting) {
1093 /* note: this assumes that the state has already been
1094 calculated and can thus be displayed. How can we
1095 guarantee this to be true? */
1096 SettingSet_i(I->Setting,cSetting_state,I->ViewElem[frame].state + 1);
1097 }
1098 }
1099 }
1100 }
1101 }
1102 if(ray) {
1103 RaySetTTT(ray, I->TTTFlag, I->TTT);
1104 } else {
1105 PyMOLGlobals *G = I->G;
1106 if(G->HaveGUI && G->ValidContext) {
1107 if(I->TTTFlag) {
1108 /* convert the row-major TTT matrix to a column-major OpenGL matrix */
1109 float gl[16], *ttt;
1110
1111 ttt = I->TTT;
1112 gl[0] = ttt[0];
1113 gl[4] = ttt[1];
1114 gl[8] = ttt[2];
1115 gl[12] = ttt[3];
1116 gl[1] = ttt[4];
1117 gl[5] = ttt[5];
1118 gl[9] = ttt[6];
1119 gl[13] = ttt[7];
1120 gl[2] = ttt[8];
1121 gl[6] = ttt[9];
1122 gl[10] = ttt[10];
1123 gl[14] = ttt[11];
1124 gl[3] = 0.0;
1125 gl[7] = 0.0;
1126 gl[11] = 0.0;
1127 gl[15] = 1.0;
1128
1129 auto mvm = SceneGetModelViewMatrix(G);
1130 MatrixMultiplyC44f(gl, mvm);
1131 MatrixTranslateC44f(mvm, ttt[12], ttt[13], ttt[14]);
1132
1133 #ifndef PURE_OPENGL_ES_2
1134 if (ALWAYS_IMMEDIATE_OR(!info->use_shaders)) {
1135 glLoadMatrixf(mvm);
1136 }
1137 #endif
1138 }
1139 }
1140 }
1141 }
1142
1143
1144 /*========================================================================*/
ObjectSetTTTOrigin(CObject * I,float * origin)1145 void ObjectSetTTTOrigin(CObject * I, float *origin)
1146 {
1147 float homo[16];
1148 float *dst;
1149 float post[3];
1150
1151 if(!I->TTTFlag) {
1152 I->TTTFlag = true;
1153 initializeTTT44f(I->TTT);
1154 }
1155
1156 /* convert the existing TTT into a homogenous transformation matrix */
1157
1158 convertTTTfR44f(I->TTT, homo);
1159
1160 /* now reset to the passed-in origin */
1161
1162 transform44f3fas33f3f(homo, origin, post);
1163
1164 homo[3] += post[0];
1165 homo[7] += post[1];
1166 homo[11] += post[2];
1167
1168 dst = homo + 12;
1169
1170 invert3f3f(origin, dst);
1171
1172 copy44f(homo, I->TTT);
1173 }
1174
1175
1176 /*========================================================================*/
getSettingHandle(int state)1177 CSetting **CObject::getSettingHandle(int state)
1178 {
1179 return &Setting;
1180 }
1181
1182
1183 /*========================================================================*/
describeElement(int index,char * buffer) const1184 void CObject::describeElement(int index, char* buffer) const
1185 {
1186 buffer[0] = 0;
1187 }
1188
1189
1190 /*========================================================================*/
ObjectToggleRepVis(CObject * I,int rep)1191 void ObjectToggleRepVis(CObject * I, int rep)
1192 {
1193 if((rep >= 0) && (rep < cRepCnt))
1194 I->visRep ^= (1 << rep);
1195 }
1196
1197
1198 /*========================================================================*/
ObjectSetRepVisMask(CObject * I,int repmask,int value)1199 void ObjectSetRepVisMask(CObject * I, int repmask, int value)
1200 {
1201 switch (value) {
1202 case cVis_HIDE:
1203 I->visRep &= ~repmask;
1204 break;
1205 case cVis_SHOW:
1206 I->visRep |= repmask;
1207 break;
1208 case cVis_AS:
1209 I->visRep = repmask;
1210 break;
1211 case cVis_TOGGLE:
1212 I->visRep ^= repmask;
1213 break;
1214 default:
1215 printf("error: invalid value: %d\n", value);
1216 }
1217 }
1218
1219
1220 /*========================================================================*/
ObjectSetName(CObject * I,const char * name)1221 void ObjectSetName(CObject * I, const char *name)
1222 {
1223 UtilNCopy(I->Name, name, WordLength);
1224 if(SettingGetGlobal_b(I->G, cSetting_validate_object_names))
1225 ObjectMakeValidName(I->G, I->Name);
1226 }
1227
1228
1229 /*========================================================================*/
~CObject()1230 CObject::~CObject()
1231 {
1232 SceneObjectDel(this->G, this, false);
1233 SettingFreeP(this->Setting);
1234 }
1235
1236
1237 /*========================================================================*/
ObjectUseColor(CObject * I)1238 void ObjectUseColor(CObject * I)
1239 {
1240 PyMOLGlobals *G = I->G;
1241 if(G->HaveGUI && G->ValidContext) {
1242 glColor3fv(ColorGet(I->G, I->Color));
1243 }
1244 }
1245
ObjectUseColorCGO(CGO * cgo,CObject * I)1246 void ObjectUseColorCGO(CGO *cgo, CObject * I)
1247 {
1248 PyMOLGlobals *G = I->G;
1249 if(G->HaveGUI && G->ValidContext) {
1250 CGOColorv(cgo, ColorGet(I->G, I->Color));
1251 }
1252 }
1253
1254 /*========================================================================*/
1255 /**
1256 * Render a unit box (dummy representation)
1257 */
render(RenderInfo * info)1258 void CObject::render(RenderInfo * info)
1259 {
1260 if(G->HaveGUI && G->ValidContext) {
1261 #ifdef PURE_OPENGL_ES_2
1262 /* TODO */
1263 #else
1264 glBegin(GL_LINE_LOOP);
1265 glVertex3i(-1, -1, -1);
1266 glVertex3i(-1, -1, 1);
1267 glVertex3i(-1, 1, 1);
1268 glVertex3i(-1, 1, -1);
1269
1270 glVertex3i(1, 1, -1);
1271 glVertex3i(1, 1, 1);
1272 glVertex3i(1, -1, 1);
1273 glVertex3i(1, -1, -1);
1274 glEnd();
1275
1276 glBegin(GL_LINES);
1277 glVertex3i(0, 0, 0);
1278 glVertex3i(1, 0, 0);
1279
1280 glVertex3i(0, 0, 0);
1281 glVertex3i(0, 3, 0);
1282
1283 glVertex3i(0, 0, 0);
1284 glVertex3i(0, 0, 9);
1285
1286 glEnd();
1287 #endif
1288 }
1289 }
1290
1291
1292 /*========================================================================*/
CObject(PyMOLGlobals * G)1293 CObject::CObject(PyMOLGlobals * G) : G(G)
1294 {
1295 OrthoRemoveSplash(G); /* HMM... this seems like an inappropriate sideeffect */
1296 visRep = cRepBitmask & ~(cRepCellBit | cRepExtentBit);
1297 }
1298
1299 /*========================================================================*/
1300
ObjectStateInit(PyMOLGlobals * G,CObjectState * I)1301 void ObjectStateInit(PyMOLGlobals * G, CObjectState * I)
1302 {
1303 I->G = G;
1304 }
1305
ObjectStatePurge(CObjectState * I)1306 void ObjectStatePurge(CObjectState * I)
1307 {
1308 }
1309
ObjectStateSetMatrix(CObjectState * I,double * matrix)1310 int ObjectStateSetMatrix(CObjectState * I, double *matrix)
1311 {
1312 int ok = true;
1313 if(matrix) {
1314 I->Matrix.resize(16);
1315 copy44d(matrix, I->Matrix.data());
1316 } else {
1317 I->Matrix.clear();
1318 }
1319 I->InvMatrix.clear();
1320 return ok;
1321 }
1322
ObjectStateRightCombineMatrixR44d(CObjectState * I,double * matrix)1323 void ObjectStateRightCombineMatrixR44d(CObjectState * I, double *matrix)
1324 {
1325 if(matrix) {
1326 if(I->Matrix.empty()) {
1327 I->Matrix = std::vector<double>(16);
1328 copy44d(matrix, I->Matrix.data());
1329 } else {
1330 right_multiply44d44d(I->Matrix.data(), matrix);
1331 }
1332 }
1333 I->InvMatrix.clear();
1334 }
1335
ObjectStateLeftCombineMatrixR44d(CObjectState * I,double * matrix)1336 void ObjectStateLeftCombineMatrixR44d(CObjectState * I, double *matrix)
1337 {
1338 if(matrix) {
1339 if(I->Matrix.empty()) {
1340 I->Matrix = std::vector<double>(16);
1341 copy44d(matrix, I->Matrix.data());
1342 } else {
1343 left_multiply44d44d(matrix, I->Matrix.data());
1344 }
1345 }
1346 I->InvMatrix.clear();
1347 }
1348
ObjectStateCombineMatrixTTT(CObjectState * I,float * matrix)1349 void ObjectStateCombineMatrixTTT(CObjectState * I, float *matrix)
1350 {
1351
1352 if(matrix) {
1353 if(I->Matrix.empty()) {
1354 I->Matrix = std::vector<double>(16);
1355 convertTTTfR44d(matrix, I->Matrix.data());
1356 } else {
1357 double tmp[16];
1358 convertTTTfR44d(matrix, tmp);
1359 right_multiply44d44d(I->Matrix.data(), tmp);
1360 }
1361 }
1362 I->InvMatrix.clear();
1363 }
1364
ObjectStateGetMatrix(CObjectState * I)1365 double *ObjectStateGetMatrix(CObjectState * I)
1366 {
1367 if(!I->Matrix.empty()) {
1368 return I->Matrix.data();
1369 }
1370 return nullptr;
1371 }
1372
1373 /*
1374 * Get the Matrix inverse
1375 */
ObjectStateGetInvMatrix(CObjectState * I)1376 double *ObjectStateGetInvMatrix(CObjectState * I)
1377 {
1378 if(!I->Matrix.empty() && I->InvMatrix.empty()) {
1379 I->InvMatrix = std::vector<double>(16);
1380 xx_matrix_invert(I->InvMatrix.data(), I->Matrix.data(), 4);
1381 }
1382 return I->InvMatrix.data();
1383 }
1384
ObjectStateTransformMatrix(CObjectState * I,double * matrix)1385 void ObjectStateTransformMatrix(CObjectState * I, double *matrix)
1386 {
1387 if(I->Matrix.empty()) {
1388 I->Matrix = std::vector<double>(16);
1389 if(!I->Matrix.empty()) {
1390 copy44d(matrix, I->Matrix.data());
1391 }
1392 } else {
1393 right_multiply44d44d(I->Matrix.data(), matrix);
1394 }
1395 I->InvMatrix.clear();
1396 }
1397
ObjectStatePushAndApplyMatrix(CObjectState * I,RenderInfo * info)1398 int ObjectStatePushAndApplyMatrix(CObjectState * I, RenderInfo * info)
1399 {
1400 PyMOLGlobals *G = I->G;
1401 float matrix[16];
1402 const double *i_matrix = nullptr;
1403 if(!I->Matrix.empty()) {
1404 i_matrix = I->Matrix.data();
1405 }
1406 int result = false;
1407 if(i_matrix) {
1408 if(info->ray) {
1409 float ttt[16], matrix[16], i_matrixf[16];
1410 RayPushTTT(info->ray);
1411 RayGetTTT(info->ray, ttt);
1412 convertTTTfR44f(ttt, matrix);
1413 copy44d44f(i_matrix, i_matrixf);
1414 right_multiply44f44f(matrix, i_matrixf);
1415 RaySetTTT(info->ray, true, matrix);
1416 result = true;
1417 } else if(G->HaveGUI && G->ValidContext) {
1418 matrix[0] = i_matrix[0];
1419 matrix[1] = i_matrix[4];
1420 matrix[2] = i_matrix[8];
1421 matrix[3] = i_matrix[12];
1422 matrix[4] = i_matrix[1];
1423 matrix[5] = i_matrix[5];
1424 matrix[6] = i_matrix[9];
1425 matrix[7] = i_matrix[13];
1426 matrix[8] = i_matrix[2];
1427 matrix[9] = i_matrix[6];
1428 matrix[10] = i_matrix[10];
1429 matrix[11] = i_matrix[14];
1430 matrix[12] = i_matrix[3];
1431 matrix[13] = i_matrix[7];
1432 matrix[14] = i_matrix[11];
1433 matrix[15] = i_matrix[15];
1434
1435 ScenePushModelViewMatrix(G);
1436 auto mvm = SceneGetModelViewMatrix(G);
1437 MatrixMultiplyC44f(matrix, mvm);
1438
1439 #ifndef PURE_OPENGL_ES_2
1440 if (ALWAYS_IMMEDIATE_OR(!info->use_shaders)) {
1441 glLoadMatrixf(mvm);
1442 }
1443 #endif
1444
1445 result = true;
1446 }
1447 }
1448 return result;
1449 }
1450
ObjectStatePopMatrix(CObjectState * I,RenderInfo * info)1451 void ObjectStatePopMatrix(CObjectState * I, RenderInfo * info)
1452 {
1453 PyMOLGlobals *G = I->G;
1454 if(info->ray) {
1455 RayPopTTT(info->ray);
1456 } else if(G->HaveGUI && G->ValidContext) {
1457 ScenePopModelViewMatrix(G, !info->use_shaders);
1458 }
1459 }
1460
ObjectStateResetMatrix(CObjectState * I)1461 void ObjectStateResetMatrix(CObjectState* I)
1462 {
1463 I->Matrix.clear();
1464 I->InvMatrix.clear();
1465 }
1466
ObjectStateAsPyList(CObjectState * I)1467 PyObject *ObjectStateAsPyList(CObjectState * I)
1468 {
1469 PyObject *result = NULL;
1470
1471 if(I) {
1472 result = PyList_New(1);
1473
1474 if(!I->Matrix.empty()) {
1475 PyList_SetItem(result, 0, PConvDoubleArrayToPyList(I->Matrix.data(), 16));
1476 } else {
1477 PyList_SetItem(result, 0, PConvAutoNone(Py_None));
1478 }
1479 }
1480 return (PConvAutoNone(result));
1481 }
1482
ObjectStateFromPyList(PyMOLGlobals * G,PyObject * list,CObjectState * I)1483 int ObjectStateFromPyList(PyMOLGlobals * G, PyObject * list, CObjectState * I)
1484 {
1485 PyObject *tmp;
1486 int ok = true;
1487
1488 ObjectStateInit(G, I);
1489
1490 if(list && (list != Py_None)) { /* allow None */
1491 if(ok)
1492 ok = (list != NULL);
1493 if(ok)
1494 ok = PyList_Check(list);
1495 /* TO SUPPORT BACKWARDS COMPATIBILITY...
1496 Always check ll when adding new PyList_GetItem's */
1497 if(ok) {
1498 tmp = PyList_GetItem(list, 0);
1499 if(tmp != Py_None)
1500 ok = PConvFromPyObject(G, tmp, I->Matrix);
1501 }
1502 }
1503 return (ok);
1504 }
1505