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_gl.h"
20
21 #include"Base.h"
22 #include"OOMac.h"
23 #include"main.h"
24 #include"View.h"
25 #include"Ray.h"
26 #include"Setting.h"
27 #include"PConv.h"
28 #include"OVLexicon.h"
29 #include"Text.h"
30 #include"Feedback.h"
31 #include"Ortho.h"
32 #include"CGO.h"
33
ViewElemModify(PyMOLGlobals * G,CViewElem ** handle,int action,int index,int count,int target)34 int ViewElemModify(PyMOLGlobals *G, CViewElem **handle, int action, int index, int count, int target)
35 {
36 int ok = true;
37 CViewElem *vla = *handle;
38 if(!vla) {
39 vla = VLACalloc(CViewElem, 0);
40 }
41 if(vla) {
42 int n_frame = VLAGetSize(vla);
43 switch(action) {
44 case cViewElemModifyInsert:
45 VLAInsert(vla,CViewElem,index,count);
46 break;
47 case cViewElemModifyDelete:
48 VLADelete(vla,CViewElem,index,count);
49 break;
50 case cViewElemModifyMove:
51 if((index>=0) && (target>=0) && (index<n_frame) && (target<n_frame)) {
52 if((count>1)||(vla[index].specification_level>1)) {
53
54 int i;
55 for(i=0;i<count;i++) {
56 if( ((i+index)<n_frame) && ((i+target)<n_frame)) {
57 int src,dst;
58 if(index>target) {
59 src = index+i;
60 dst = target+i;
61 } else {
62 src = index+(count-1)-i;
63 dst = target+(count-1)-i;
64 }
65 memcpy(vla + dst, vla + src, sizeof(CViewElem));
66 memset(vla + src, 0, sizeof(CViewElem));
67 }
68 }
69 }
70 }
71 break;
72 case cViewElemModifyCopy:
73 if((index>=0) && (target>=0) && (index<n_frame) && (target<n_frame)) {
74 if((count>1)||(vla[index].specification_level>1)) {
75 int i;
76 for(i=0;i<count;i++) {
77 if( ((i+index)<n_frame) && ((i+target)<n_frame)) {
78 int src,dst;
79 if(index>target) {
80 src = index+i;
81 dst = target+i;
82 } else {
83 src = index+(count-1)-i;
84 dst = target+(count-1)-i;
85 }
86 memcpy(vla + dst, vla + src, sizeof(CViewElem));
87 }
88 }
89 }
90 }
91 break;
92 }
93 }
94 *handle = vla;
95 return ok;
96 }
97
ViewElemXtoFrame(BlockRect * rect,int frames,int x,int nearest)98 int ViewElemXtoFrame(BlockRect *rect, int frames, int x, int nearest)
99 {
100 int offset = 0;
101 float width = (float) (rect->right - rect->left);
102 float extra = (nearest ? 0.4999F : 0.0F);
103 int frame = (int)(extra + (frames * (x - rect->left )) / width + offset);
104 return frame;
105 }
106
ViewElemDrawBox(PyMOLGlobals * G,BlockRect * rect,int first,int last,int frames,float * color4,int fill ORTHOCGOARG)107 void ViewElemDrawBox(PyMOLGlobals *G, BlockRect *rect, int first, int last,
108 int frames, float *color4,int fill ORTHOCGOARG)
109 {
110 if(G->HaveGUI && G->ValidContext && rect) {
111 int nDrawn = frames;
112 int offset = 0;
113 float width = (float) (rect->right - rect->left);
114 float top = rect->top - 1;
115 float bot = rect->bottom + 1;
116 float start = (int)(rect->left + (width * (first - offset)) / nDrawn);
117 float stop = (int)(rect->left + (width * (last - offset)) / nDrawn);
118 if((stop - start) < 1.0F)
119 stop = start+1.0F;
120 if(fill) {
121 glEnable(GL_BLEND);
122 if (orthoCGO){
123 float prevAlpha = orthoCGO->alpha;
124 CGOAlpha(orthoCGO, color4[3]);
125 CGOColorv(orthoCGO, color4);
126 CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
127 CGOVertex(orthoCGO, start, bot, 0.f);
128 CGOVertex(orthoCGO, start, top, 0.f);
129 CGOVertex(orthoCGO, stop, bot, 0.f);
130 CGOVertex(orthoCGO, stop, top, 0.f);
131 CGOEnd(orthoCGO);
132 CGOAlpha(orthoCGO, prevAlpha);
133 } else {
134 glColor4fv(color4);
135 glBegin(GL_POLYGON);
136 glVertex2f(start, bot);
137 glVertex2f(start, top);
138 glVertex2f(stop, top);
139 glVertex2f(stop, bot);
140 glEnd();
141 }
142 glDisable(GL_BLEND);
143 } else {
144 if (orthoCGO){
145 CGOLineAsTriangleStrips(orthoCGO, start, bot, stop, top);
146 } else {
147 glBegin(GL_LINE_LOOP);
148 glVertex2f(start, bot);
149 glVertex2f(start, top);
150 glVertex2f(stop, top);
151 glVertex2f(stop, bot);
152 glEnd();
153 }
154 }
155 }
156 }
157
ViewElemDraw(PyMOLGlobals * G,const CViewElem * view_elem,const BlockRect * rect,int frames,const char * title ORTHOCGOARG)158 void ViewElemDraw(PyMOLGlobals *G,
159 const CViewElem * view_elem,
160 const BlockRect *rect, int frames,
161 const char *title ORTHOCGOARG)
162 {
163 if(G->HaveGUI && G->ValidContext && view_elem) {
164 int size = VLAGetSize(view_elem);
165 float width = (float) (rect->right - rect->left);
166 float start = 0.0F, stop;
167 const int last = size;
168 float top = rect->top - 2;
169 float bot = rect->bottom + 2;
170 float mid_top = (int)((0.499F + 3 * top + 2 * bot) / 5);
171 float mid_bot = (int)((0.499F + 2 * top + 3 * bot) / 5);
172 float top_color[3] = { 0.6, 0.6, 1.0 };
173 float key_color[3] = { 0.4, 0.4, 0.8 };
174 float bar_color[3] = { 0.3, 0.3, 0.6 };
175 float bot_color[3] = { 0.2, 0.2, 0.4 };
176 int cur_level = -1, last_level = -1;
177 int cur;
178 for(cur = 0; cur <= last; cur++) {
179 if(cur < last) {
180 cur_level = view_elem->specification_level;
181 } else {
182 cur_level = -1;
183 }
184 if(cur_level != last_level) {
185 stop = (int)(rect->left + (width * cur) / frames);
186 switch (last_level) {
187 case 0:
188 break;
189 case 1:
190 if (orthoCGO){
191 CGOColorv(orthoCGO, bar_color);
192 CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
193 CGOVertex(orthoCGO, start, mid_bot, 0.f);
194 CGOVertex(orthoCGO, start, mid_top, 0.f);
195 CGOVertex(orthoCGO, stop, mid_bot, 0.f);
196 CGOVertex(orthoCGO, stop, mid_top, 0.f);
197 CGOEnd(orthoCGO);
198 } else {
199 glColor3fv(bar_color);
200 glBegin(GL_POLYGON);
201 glVertex2f(start, mid_bot);
202 glVertex2f(start, mid_top);
203 glVertex2f(stop, mid_top);
204 glVertex2f(stop, mid_bot);
205 glEnd();
206 }
207 if (orthoCGO){
208 CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
209 CGOColorv(orthoCGO, key_color);
210 CGOVertex(orthoCGO, start, mid_top, 0.f);
211 CGOVertex(orthoCGO, start, mid_top+1, 0.f);
212 CGOVertex(orthoCGO, stop, mid_top, 0.f);
213 CGOVertex(orthoCGO, stop, mid_top+1, 0.f);
214 CGOEnd(orthoCGO);
215 CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
216 CGOColorv(orthoCGO, bot_color);
217 CGOVertex(orthoCGO, start, mid_bot-1, 0.f);
218 CGOVertex(orthoCGO, start, mid_bot, 0.f);
219 CGOVertex(orthoCGO, stop, mid_bot-1, 0.f);
220 CGOVertex(orthoCGO, stop, mid_bot, 0.f);
221 CGOEnd(orthoCGO);
222 } else {
223 glColor3fv(key_color);
224 glBegin(GL_LINES);
225 glVertex2f(start,mid_top);
226 glVertex2f(stop,mid_top);
227 glColor3fv(bot_color);
228 glVertex2f(start,mid_bot-1);
229 glVertex2f(stop,mid_bot-1);
230 glEnd();
231 }
232 break;
233 case 2:
234 if((stop - start) < 1.0F)
235 stop = start+1.0F;
236 if (orthoCGO){
237 CGOColorv(orthoCGO, key_color);
238 CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
239 CGOVertex(orthoCGO, start, bot, 0.f);
240 CGOVertex(orthoCGO, start, top, 0.f);
241 CGOVertex(orthoCGO, stop, bot, 0.f);
242 CGOVertex(orthoCGO, stop, top, 0.f);
243 CGOEnd(orthoCGO);
244 } else {
245 glColor3fv(key_color);
246 glBegin(GL_POLYGON);
247 glVertex2f(start, bot);
248 glVertex2f(start, top);
249 glVertex2f(stop, top);
250 glVertex2f(stop, bot);
251 glEnd();
252 }
253
254 if (orthoCGO){
255 CGOColorv(orthoCGO, bot_color);
256 CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
257 CGOVertex(orthoCGO, start,bot-1,0.f);
258 CGOVertex(orthoCGO, start,bot,0.f);
259 CGOVertex(orthoCGO, stop,bot-1,0.f);
260 CGOVertex(orthoCGO, stop,bot,0.f);
261 CGOEnd(orthoCGO);
262 CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
263 CGOVertex(orthoCGO, stop,bot,0.f);
264 CGOVertex(orthoCGO, stop,top,0.f);
265 CGOVertex(orthoCGO, stop+1,bot,0.f);
266 CGOVertex(orthoCGO, stop+1,top,0.f);
267 CGOEnd(orthoCGO);
268
269 CGOColorv(orthoCGO, top_color);
270 CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
271 CGOVertex(orthoCGO, start,top,0.f);
272 CGOVertex(orthoCGO, start,top+1,0.f);
273 CGOVertex(orthoCGO, stop,top,0.f);
274 CGOVertex(orthoCGO, stop,top+1,0.f);
275 CGOEnd(orthoCGO);
276
277 CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
278 CGOVertex(orthoCGO, start,bot,0.f);
279 CGOVertex(orthoCGO, start,top,0.f);
280 CGOVertex(orthoCGO, start+1,bot,0.f);
281 CGOVertex(orthoCGO, start+1,top,0.f);
282 CGOEnd(orthoCGO);
283 } else {
284 glBegin(GL_LINES);
285 glColor3fv(bot_color);
286 glVertex2f(start,bot-1);
287 glVertex2f(stop,bot-1);
288 glVertex2f(stop,bot);
289 glVertex2f(stop,top);
290 glColor3fv(top_color);
291 glVertex2f(start,top);
292 glVertex2f(stop,top);
293 glVertex2f(start,bot);
294 glVertex2f(start,top);
295 glEnd();
296 }
297 break;
298 }
299 start = stop;
300 }
301 last_level = cur_level;
302 view_elem++;
303 }
304
305 if(title)
306 ViewElemDrawLabel(G, title, rect, orthoCGO);
307 }
308 }
309
ViewElemDrawLabel(PyMOLGlobals * G,const char * label,const BlockRect * rect,CGO * orthoCGO)310 void ViewElemDrawLabel(
311 PyMOLGlobals* G, const char* label, const BlockRect* rect, CGO* orthoCGO)
312 {
313 TextDrawStrAt(
314 G, label, rect->right + 1, (rect->bottom + rect->top) / 2 - 3, orthoCGO);
315 }
316
ViewElemCopy(PyMOLGlobals * G,const CViewElem * src,CViewElem * dst)317 void ViewElemCopy(PyMOLGlobals * G, const CViewElem * src, CViewElem * dst)
318 {
319 if(dst->scene_flag && dst->scene_name) {
320 OVLexicon_DecRef(G->Lexicon, dst->scene_name);
321 }
322 *dst = *src;
323 if(dst->scene_flag && dst->scene_name) {
324 OVLexicon_IncRef(G->Lexicon, dst->scene_name);
325 }
326 }
327
ViewElemArrayPurge(PyMOLGlobals * G,CViewElem * view,int nFrame)328 void ViewElemArrayPurge(PyMOLGlobals * G, CViewElem * view, int nFrame)
329 {
330 int a;
331 for(a = 0; a < nFrame; a++) {
332 if(view->scene_flag && view->scene_name) {
333 OVLexicon_DecRef(G->Lexicon, view->scene_name);
334 view->scene_name = 0;
335 view->scene_flag = false;
336 }
337 view++;
338 }
339 }
340
ViewElemAsPyList(PyMOLGlobals * G,const CViewElem * view)341 PyObject *ViewElemAsPyList(PyMOLGlobals * G, const CViewElem * view)
342 {
343 #ifdef _PYMOL_NOPY
344 return NULL;
345 #else
346 PyObject *result = NULL;
347
348 result = PyList_New(21);
349
350 if(result) {
351 PyList_SetItem(result, 0, PyInt_FromLong(view->matrix_flag));
352 if(view->matrix_flag) {
353 PyList_SetItem(result, 1, PConvDoubleArrayToPyList(view->matrix, 16));
354 } else {
355 PyList_SetItem(result, 1, PConvAutoNone(NULL));
356 }
357
358 PyList_SetItem(result, 2, PyInt_FromLong(view->pre_flag));
359 if(view->pre_flag) {
360 PyList_SetItem(result, 3, PConvDoubleArrayToPyList(view->pre, 3));
361 } else {
362 PyList_SetItem(result, 3, PConvAutoNone(NULL));
363 }
364
365 PyList_SetItem(result, 4, PyInt_FromLong(view->post_flag));
366 if(view->post_flag) {
367 PyList_SetItem(result, 5, PConvDoubleArrayToPyList(view->post, 3));
368 } else {
369 PyList_SetItem(result, 5, PConvAutoNone(NULL));
370 }
371
372 PyList_SetItem(result, 6, PyInt_FromLong(view->clip_flag));
373 if(view->post_flag) {
374 PyList_SetItem(result, 7, PyFloat_FromDouble((double) view->front));
375 PyList_SetItem(result, 8, PyFloat_FromDouble((double) view->back));
376 } else {
377 PyList_SetItem(result, 7, PConvAutoNone(NULL));
378 PyList_SetItem(result, 8, PConvAutoNone(NULL));
379 }
380
381 PyList_SetItem(result, 9, PyInt_FromLong(view->ortho_flag));
382 if(view->ortho_flag) {
383 PyList_SetItem(result, 10, PyFloat_FromDouble(view->ortho));
384 } else {
385 PyList_SetItem(result, 10, PConvAutoNone(NULL));
386 }
387
388 PyList_SetItem(result, 11, PyInt_FromLong(view->view_mode));
389
390 PyList_SetItem(result, 12, PyInt_FromLong(view->specification_level));
391
392 PyList_SetItem(result, 13, PyInt_FromLong(view->scene_flag));
393
394 if(view->scene_flag && view->scene_name) {
395 char null_st[1] = "";
396 char *st = null_st;
397
398 st = OVLexicon_FetchCString(G->Lexicon, view->scene_name);
399 PyList_SetItem(result, 14, PyString_FromString(st));
400 } else {
401 PyList_SetItem(result, 14, PyInt_FromLong(0));
402 }
403
404 PyList_SetItem(result, 15, PyInt_FromLong(view->power_flag));
405 if(view->ortho_flag) {
406 PyList_SetItem(result, 16, PyFloat_FromDouble(view->power));
407 } else {
408 PyList_SetItem(result, 16, PConvAutoNone(NULL));
409 }
410
411 PyList_SetItem(result, 17, PyInt_FromLong(view->bias_flag));
412 if(view->bias_flag) {
413 PyList_SetItem(result, 18, PyFloat_FromDouble(view->bias));
414 } else {
415 PyList_SetItem(result, 18, PConvAutoNone(NULL));
416 }
417
418 PyList_SetItem(result, 19, PyInt_FromLong(view->state_flag));
419 if(view->state_flag) {
420 PyList_SetItem(result, 20, PyInt_FromLong(view->state));
421 } else {
422 PyList_SetItem(result, 20, PConvAutoNone(NULL));
423 }
424
425 }
426
427 return PConvAutoNone(result);
428 #endif
429 }
430
ViewElemFromPyList(PyMOLGlobals * G,PyObject * list,CViewElem * view)431 int ViewElemFromPyList(PyMOLGlobals * G, PyObject * list, CViewElem * view)
432 {
433 int ok = true;
434 ov_size ll = 0;
435
436 if(ok)
437 ok = (list != NULL);
438 if(ok)
439 ok = PyList_Check(list);
440 if(ok)
441 ok = ((ll = PyList_Size(list)) > 11);
442
443 if(ok)
444 ok = PConvPyIntToInt(PyList_GetItem(list, 0), &view->matrix_flag);
445 if(ok && view->matrix_flag)
446 ok = PConvPyListToDoubleArrayInPlace(PyList_GetItem(list, 1), view->matrix, 16);
447
448 if(ok)
449 ok = PConvPyIntToInt(PyList_GetItem(list, 2), &view->pre_flag);
450 if(ok && view->pre_flag)
451 ok = PConvPyListToDoubleArrayInPlace(PyList_GetItem(list, 3), view->pre, 3);
452
453 if(ok)
454 ok = PConvPyIntToInt(PyList_GetItem(list, 4), &view->post_flag);
455 if(ok && view->post_flag)
456 ok = PConvPyListToDoubleArrayInPlace(PyList_GetItem(list, 5), view->post, 3);
457
458 if(ok)
459 ok = PConvPyIntToInt(PyList_GetItem(list, 6), &view->clip_flag);
460 if(view->post_flag) {
461 if(ok)
462 ok = PConvPyFloatToFloat(PyList_GetItem(list, 7), &view->front);
463 if(ok)
464 ok = PConvPyFloatToFloat(PyList_GetItem(list, 8), &view->back);
465 }
466
467 if(ok)
468 ok = PConvPyIntToInt(PyList_GetItem(list, 9), &view->ortho_flag);
469 if(ok && view->ortho_flag) {
470 ok = PConvPyFloatToFloat(PyList_GetItem(list, 10), &view->ortho);
471 if(!ok) {
472 int dummy_int;
473 ok = PConvPyIntToInt(PyList_GetItem(list, 10), &dummy_int);
474 view->ortho = dummy_int;
475 }
476 }
477
478 if(ok)
479 ok = PConvPyIntToInt(PyList_GetItem(list, 11), &view->view_mode);
480 if(ok)
481 ok = PConvPyIntToInt(PyList_GetItem(list, 12), &view->specification_level);
482
483 if(ok & (ll > 14)) {
484 if(ok)
485 ok = PConvPyIntToInt(PyList_GetItem(list, 13), &view->scene_flag);
486 if(ok && view->scene_flag) {
487 const char *ptr = NULL;
488 view->scene_flag = false;
489 if(PConvPyStrToStrPtr(PyList_GetItem(list, 14), &ptr)) {
490 OVreturn_word result = OVLexicon_GetFromCString(G->Lexicon, ptr);
491 if(OVreturn_IS_OK(result)) {
492 view->scene_name = result.word;
493 view->scene_flag = true;
494 }
495 }
496 }
497 }
498 if(ok && (ll>16)) {
499 ok = PConvPyIntToInt(PyList_GetItem(list, 15), &view->power_flag);
500 if(ok && view->power_flag) {
501 ok = PConvPyFloatToFloat(PyList_GetItem(list, 16), &view->power);
502 } else {
503 view->power = 0.0F;
504 }
505 }
506 if(ok && (ll>18)) {
507 ok = PConvPyIntToInt(PyList_GetItem(list, 17), &view->bias_flag);
508 if(ok && view->bias_flag) {
509 ok = PConvPyFloatToFloat(PyList_GetItem(list, 18), &view->bias);
510 } else {
511 view->bias = 1.0F;
512 }
513 }
514 if(ok && (ll>20)) {
515 ok = PConvPyIntToInt(PyList_GetItem(list, 19), &view->state_flag);
516 if(ok && view->state_flag) {
517 ok = PConvPyIntToInt(PyList_GetItem(list, 20), &view->state);
518 } else {
519 view->state = 0;
520 }
521 }
522 return ok;
523 }
524
ViewElemVLAFromPyList(PyMOLGlobals * G,PyObject * list,CViewElem ** vla_ptr,int nFrame)525 int ViewElemVLAFromPyList(PyMOLGlobals * G, PyObject * list, CViewElem ** vla_ptr,
526 int nFrame)
527 {
528 int ok = true;
529 CViewElem *vla = NULL;
530 if(ok)
531 ok = (list != NULL);
532 if(ok)
533 ok = PyList_Check(list);
534 if(ok)
535 ok = (PyList_Size(list) == nFrame);
536 if(ok)
537 ok = ((vla = VLACalloc(CViewElem, nFrame)) != NULL);
538 if(ok) {
539 int a;
540 for(a = 0; a < nFrame; a++) {
541 if(ok)
542 ok = ViewElemFromPyList(G, PyList_GetItem(list, a), vla + a);
543 else
544 break;
545 }
546 }
547 if(!ok) {
548 VLAFreeP(vla);
549 } else
550 *vla_ptr = vla;
551 return ok;
552 }
553
ViewElemVLAAsPyList(PyMOLGlobals * G,const CViewElem * vla,int nFrame)554 PyObject *ViewElemVLAAsPyList(PyMOLGlobals * G, const CViewElem * vla, int nFrame)
555 {
556 #ifdef _PYMOL_NOPY
557 return NULL;
558 #else
559
560 PyObject *result = NULL;
561 int a;
562 result = PyList_New(nFrame);
563 for(a = 0; a < nFrame; a++) {
564 PyList_SetItem(result, a, ViewElemAsPyList(G, vla + a));
565 }
566 return (PConvAutoNone(result));
567 #endif
568 }
569
ViewNew(PyMOLGlobals * G)570 CView *ViewNew(PyMOLGlobals * G)
571 {
572 OOAlloc(G, CView);
573 I->G = G;
574 I->View = NULL;
575 return I;
576 }
577
ViewFree(CView * I)578 void ViewFree(CView * I)
579 {
580 if(I)
581 VLAFreeP(I->View);
582 }
583
ViewGetIterator(CView * I)584 CViewIterator ViewGetIterator(CView * I)
585 {
586 return 0;
587 }
588
ViewIterate(CView * I,CViewIterator * iter,CRay * ray,int at_least_once)589 int ViewIterate(CView * I, CViewIterator * iter, CRay * ray, int at_least_once)
590 {
591 int result;
592 CViewElem *elem = NULL;
593
594 if((!I) || (!I->NView)) { /* trusting short-circuit to avoid segfault */
595 if(at_least_once) {
596 if(!*iter) { /* do loop at least once if asked to do so */
597 *iter = 1;
598 result = true;
599 } else
600 result = false;
601 } else {
602 result = false;
603 }
604 } else {
605 if(*iter < I->NView) {
606 elem = I->View + (*iter)++;
607 result = true;
608 } else
609 result = false;
610 }
611 if(elem) { /* are we to apply a transformation? */
612 if(ray) {
613
614 } else if(I->G->HaveGUI && I->G->ValidContext) {
615
616 if(elem->pre_flag) {
617 /* move the camera to the location we are looking at */
618 #ifdef PURE_OPENGL_ES_2
619 /* TODO */
620 #else
621 glTranslated(elem->pre[0], elem->pre[1], elem->pre[2]);
622 #endif
623 }
624
625 if(elem->matrix_flag) {
626 /* rotate about the origin (the the center of rotation) */
627 #ifdef PURE_OPENGL_ES_2
628 /* TODO */
629 #else
630 glMultMatrixd(elem->matrix);
631 #endif
632 }
633
634 if(elem->post_flag) {
635 /* move the origin to the center of rotation */
636 #ifdef PURE_OPENGL_ES_2
637 /* TODO */
638 #else
639 glTranslated(elem->post[0], elem->post[1], elem->post[2]);
640 #endif
641 }
642
643 }
644 }
645 return result;
646 }
647
matrix_interpolate(Matrix53f imat,Matrix53f mat,float * pivot_point,float * bisect_dir,float * rot_axis,float rotate_angle,float * trans_axis,float translate_angle,float fxn,float linearity)648 static void matrix_interpolate(Matrix53f imat, Matrix53f mat,
649 float *pivot_point,
650 float *bisect_dir,
651 float *rot_axis,
652 float rotate_angle,
653 float *trans_axis,
654 float translate_angle, float fxn, float linearity)
655 {
656 int a;
657 float pos[3], adj[3], opp[3], oppdir[3];
658 float p0[3], p1[3], center[3];
659 float hyplen, adjlen, opplen;
660 float tAlpha;
661
662 rotation_to_matrix(imat, rot_axis, fxn * rotate_angle);
663
664 /* ______--------______
665 * /____________ \
666 * / \ opp |adj \
667 * | \ | trans |
668 * (CM)---------------------------------->(CM)
669 * \ \ | /
670 * \ \hyp |-bisect_dir /
671 * \p0 \ | p1/
672 * \ \ | /
673 * \ \ | /
674 * \\v /
675 * <--------O pivot
676 * F-raxis
677 */
678
679 subtract3f(&mat[3][0], pivot_point, p0);
680 subtract3f(&mat[4][0], pivot_point, p1);
681
682 hyplen = (float) length3f(p0);
683
684 average3f(&mat[3][0], &mat[4][0], center);
685
686 cross_product3f(bisect_dir, trans_axis, oppdir);
687 normalize3f(oppdir);
688
689 tAlpha = (float) (fabs(0.5 - fxn) * translate_angle);
690 opplen = (float) fabs(hyplen * sin(tAlpha));
691 adjlen = (float) fabs(hyplen * cos(tAlpha));
692
693 scale3f(oppdir, opplen, opp);
694 scale3f(bisect_dir, -adjlen, adj);
695
696 add3f(pivot_point, adj, pos);
697
698 if(fxn <= 0.5) {
699 add3f(pos, opp, pos);
700 } else {
701 subtract3f(pos, opp, pos);
702 }
703
704 /* straight linear for now... */
705
706 for(a = 0; a < 3; a++) {
707 imat[4][a] = (float) ((((1.0 - fxn) * mat[3][a] + fxn * mat[4][a]) * linearity) +
708 (1.0 - linearity) * pos[a]);
709 }
710 }
711
ViewElemSmooth(CViewElem * first,CViewElem * last,int window,int loop)712 int ViewElemSmooth(CViewElem * first, CViewElem * last, int window, int loop)
713 {
714 ov_diff n = (last - first) + 1;
715 int delta;
716 if(window > n)
717 window = (int) n;
718 delta = (window - 1) / 2;
719 if(n && delta) {
720 CViewElem *cpy = pymol::malloc<CViewElem>((n + 2 * delta));
721 CViewElem *src, *dst;
722 int a, b, c, cnt;
723 memcpy(cpy + delta, first, sizeof(CViewElem) * n);
724 if(loop) {
725 for(a = 0; a < delta; a++) {
726 memcpy(cpy + a, last - delta + a, sizeof(CViewElem));
727 memcpy(cpy + (delta + n) + a, first + a, sizeof(CViewElem));
728 }
729 } else {
730 for(a = 0; a < delta; a++) {
731 memcpy(cpy + a, first, sizeof(CViewElem));
732 memcpy(cpy + (delta + n) + a, last, sizeof(CViewElem));
733 }
734 }
735 for(a = 0; a < n; a++) {
736 int above, below;
737 dst = first + a;
738
739 above = delta;
740 below = delta;
741 if(above > a)
742 above = a;
743 if(below > ((n - 1) - a))
744 below = (int) ((n - 1) - a);
745
746 if(dst->specification_level) { /* has to be specified */
747
748 if(dst->matrix_flag) {
749 cnt = 1;
750 for(b = -below; b <= above; b++) {
751 if(b) {
752 src = cpy + delta + a + b;
753 if(src->matrix_flag) {
754 cnt++;
755 for(c = 0; c < 16; c++) {
756 dst->matrix[c] += src->matrix[c];
757 }
758 }
759 }
760 }
761 for(c = 0; c < 16; c++) {
762 dst->matrix[c] /= cnt;
763 }
764 reorient44d(dst->matrix); /* convert those averages into a valid matrix */
765 }
766
767 if(dst->pre_flag) {
768 cnt = 1;
769 for(b = -below; b <= above; b++) {
770 if(b) {
771 src = cpy + delta + a + b;
772 if(src->pre_flag) {
773 cnt++;
774 for(c = 0; c < 3; c++) {
775 dst->pre[c] += src->pre[c];
776 }
777 }
778 }
779 }
780 for(c = 0; c < 3; c++) {
781 dst->pre[c] /= cnt;
782 }
783 }
784
785 if(dst->post_flag) {
786 cnt = 1;
787 for(b = -below; b <= above; b++) {
788 if(b) {
789 src = cpy + delta + a + b;
790 if(src->post_flag) {
791 cnt++;
792 for(c = 0; c < 3; c++) {
793 dst->post[c] += src->post[c];
794 }
795 }
796 }
797 }
798 for(c = 0; c < 3; c++) {
799 dst->post[c] /= cnt;
800 }
801 }
802
803 if(dst->clip_flag) {
804 cnt = 1;
805 for(b = -below; b <= above; b++) {
806 if(b) {
807 src = cpy + delta + a + b;
808 if(src->clip_flag) {
809 cnt++;
810 dst->front += src->front;
811 dst->back += src->back;
812 }
813 }
814 }
815 dst->front /= cnt;
816 dst->back /= cnt;
817 }
818
819 }
820 }
821 FreeP(cpy);
822 }
823 return 1;
824 }
825
ViewElemInterpolate(PyMOLGlobals * G,CViewElem * first,CViewElem * last,float power,float bias,int simple,float linearity,int hand,float cut)826 int ViewElemInterpolate(PyMOLGlobals * G, CViewElem * first, CViewElem * last,
827 float power, float bias,
828 int simple, float linearity, int hand, float cut)
829 {
830 float first3x3[9];
831 float last3x3[9];
832 float inverse3x3[9];
833 float inter3x3[9];
834 float rot_axis[3], trans_axis[3] = { 0.0F, 0.0F, 0.0F };
835 float angle;
836 CViewElem *current;
837 ov_diff n = (last - first) - 1;
838 Matrix53f rot, imat;
839 int a;
840 float tVector[3], tCenter[3], tDir[3];
841 float tLen = 0.0F;
842 float bisect[3], v2[3];
843 float translate_angle = 0.0F;
844 float pivot[3] = { 0.0F, 0.0F, 0.0F };
845 const float _1 = 1.0F, _p5 = 0.5F;
846 int parabolic = true;
847 int timing_flag;
848 double timing = 0.0F;
849 int state_flag;
850 int state = 0;
851 float pre[3];
852 float firstC44f[16], firstRTTT[16], firstR44f[16];
853 float lastC44f[16], lastRTTT[16], lastR44f[16];
854 int linear = false;
855 int debug = Feedback(G,FB_Movie, FB_Debugging);
856
857 if(hand == 0)
858 hand = 1;
859
860 if(debug) {
861 printf("ViewElemInterpolate: %8.3f %8.3f %d %8.3f %d %8.3f\n",
862 power, bias, simple, linearity, hand, cut);
863 dump44d(first->matrix,"first->matrix");
864 dump44d(last->matrix,"last->matrix");
865 printf("first->pre_flag %d first->post_flag %d\n",first->pre_flag, first->post_flag);
866 dump3d(first->pre,"first->pre");
867 dump3d(first->post,"first->post");
868 printf("last->pre_flag %d last->post_flag %d\n",last->pre_flag, last->post_flag);
869 dump3d(last->pre,"last->pre");
870 dump3d(last->post,"last->post");
871 }
872 if(power == 0.0F) {
873 if(first->power_flag && last->power_flag) {
874 if(((first->power > 0.0F) && (last->power > 0.0F)) ||
875 ((first->power < 0.0F) && (last->power < 0.0F))) {
876 power = (first->power + last->power) / 2.0F;
877 } else if(fabs(first->power) > fabs(last->power)) {
878 power = first->power;
879 } else if(last->power < 0.0F) {
880 power = last->power;
881 } else {
882 power = first->power;
883 }
884 } else if(first->power_flag) {
885 power = first->power;
886 } else if(last->power_flag) {
887 power = last->power;
888 } else {
889 power = 1.4F; /* default */
890 }
891 }
892 if(power < 0.0F) {
893 parabolic = false;
894 power = -power;
895 }
896
897 if(bias < 0.0F) { /* default */
898 if(first->bias_flag && last->bias_flag) {
899 if((first->bias > 0.0F) && (last->bias > 0.0F)) {
900 bias = (first->bias * 1.0F/last->bias);
901 } else if(fabs(first->bias) > 0.0) {
902 bias = first->bias;
903 } else if(last->bias > 0.0F) {
904 bias = 1.0F/last->bias;
905 } else {
906 bias = 1.0F;
907 }
908 } else if(first->bias_flag) {
909 bias = first->bias;
910 } else if(last->bias_flag) {
911 bias = 1.0F/last->bias;
912 } else {
913 bias = 1.0F; /* default */
914 }
915 }
916
917 if(bias <= 0.0F) {
918 bias = 1.0F;
919 }
920
921 /* WARNING: this routine is operating on column-major matrices!!! */
922
923 copy44d33f(first->matrix, first3x3);
924 copy44d33f(last->matrix, last3x3);
925
926 transpose33f33f(first3x3, inverse3x3);
927
928 multiply33f33f(inverse3x3, last3x3, &rot[0][0]); /* [rot] = [first]^-1 [last] */
929 matrix_to_rotation(rot, rot_axis, &angle);
930
931 if(debug)
932 dump3f(rot_axis, "rot_axis");
933
934 if(hand) {
935 if((cPI - fabs(angle)) < 0.01F) { /* this a complete 180 degree motion */
936 if(((rot_axis[0] * 0.7F + rot_axis[1] * 0.8F + rot_axis[2] * 0.9F) * hand * angle) >
937 0.0F) {
938 invert3f(rot_axis);
939 if(angle > 0) {
940 angle = (float) ((2 * cPI) - angle);
941 } else {
942 angle = (float) (-(2 * cPI) - angle);
943 }
944 }
945 }
946 }
947
948 if(!simple) {
949 /* switch back into row major to promote developer sanity */
950
951 copy33f44f(first3x3, firstC44f);
952 copy33f44f(last3x3, lastC44f);
953
954 transpose44f44f(firstC44f, firstRTTT);
955 transpose44f44f(lastC44f, lastRTTT);
956
957 /* form TTTs */
958
959 firstRTTT[12] = (float) -first->pre[0];
960 firstRTTT[13] = (float) -first->pre[1];
961 firstRTTT[14] = (float) -first->pre[2];
962
963 firstRTTT[3] = (float) first->post[0];
964 firstRTTT[7] = (float) first->post[1];
965 firstRTTT[11] = (float) first->post[2];
966
967 lastRTTT[12] = (float) -last->pre[0];
968 lastRTTT[13] = (float) -last->pre[1];
969 lastRTTT[14] = (float) -last->pre[2];
970
971 lastRTTT[3] = (float) last->post[0];
972 lastRTTT[7] = (float) last->post[1];
973 lastRTTT[11] = (float) last->post[2];
974
975 if(debug)
976 dump44f(firstRTTT, "firstRTTT");
977 if(debug)
978 dump44f(lastRTTT, "lastRTTT");
979
980 /* convert to homogenous */
981
982 convertTTTfR44f(firstRTTT, firstR44f);
983 convertTTTfR44f(lastRTTT, lastR44f);
984
985 /* reset both matrices to a common origin */
986
987 {
988 float first_pre[3], last_pre[3];
989 float post[4], *dst;
990
991 copy3d3f(first->pre, first_pre);
992 copy3d3f(last->pre, last_pre);
993 average3f(first_pre, last_pre, pre);
994
995 transform44f3fas33f3f(firstR44f, pre, post);
996 copy44f(firstR44f, firstRTTT);
997 firstRTTT[3] += post[0];
998 firstRTTT[7] += post[1];
999 firstRTTT[11] += post[2];
1000 dst = firstRTTT + 12;
1001 invert3f3f(pre, dst);
1002
1003 transform44f3fas33f3f(lastR44f, pre, post);
1004 copy44f(lastR44f, lastRTTT);
1005 lastRTTT[3] += post[0];
1006 lastRTTT[7] += post[1];
1007 lastRTTT[11] += post[2];
1008 dst = lastRTTT + 12;
1009 invert3f3f(pre, dst);
1010 }
1011
1012 if(debug)
1013 dump44f(firstRTTT, "firstRTTT");
1014 if(debug)
1015 dump44f(lastRTTT, "lastRTTT");
1016
1017 /* convertTTTfR44f(firstRTTT, firstR44f);
1018 convertTTTfR44f(lastRTTT, lastR44f); */
1019
1020 /* now populate the translation fields */
1021
1022 rot[3][0] = firstRTTT[3];
1023 rot[3][1] = firstRTTT[7];
1024 rot[3][2] = firstRTTT[11];
1025
1026 rot[4][0] = lastRTTT[3];
1027 rot[4][1] = lastRTTT[7];
1028 rot[4][2] = lastRTTT[11];
1029
1030 /* now set up the interpolation */
1031
1032 subtract3f(&rot[4][0], &rot[3][0], tVector);
1033 tLen = (float) length3f(tVector);
1034 average3f(&rot[4][0], &rot[3][0], tCenter);
1035
1036 if(tLen < 0.0001F) {
1037 if(debug)
1038 printf("translation too short %8.3f\n", tLen);
1039 simple = true;
1040 }
1041 }
1042
1043 if(!simple) {
1044
1045 normalize23f(tVector, tDir);
1046 if(debug)
1047 dump3f(tDir, "tDir");
1048 cross_product3f(tDir, rot_axis, bisect);
1049 /* bisect is a vector in the translation arc */
1050 if(length3f(bisect) < 0.0001F) {
1051 if(debug)
1052 printf("rotation coincident with translation\n");
1053 linear = true;
1054 }
1055 }
1056
1057 if(!(simple || linear)) {
1058 normalize3f(bisect);
1059
1060 /* this section needs work... */
1061
1062 cross_product3f(bisect, tDir, trans_axis);
1063 normalize3f(trans_axis);
1064
1065 transform33Tf3f(&rot[0][0], bisect, v2); /* column major */
1066
1067 remove_component3f(v2, trans_axis, v2);
1068 normalize3f(v2); /* project vector onto plane _|_ to axis */
1069
1070 if(debug) {
1071 dump3f(rot_axis, "rot_axis");
1072 dump3f(tDir, "tDir");
1073 dump3f(bisect, "bisect");
1074 dump3f(trans_axis, "trans_axis");
1075 dump3f(v2, "v2");
1076 }
1077
1078 {
1079 double dot = dot_product3f(bisect, v2);
1080 if(dot < -1.0F)
1081 dot = -1.0F;
1082 if(dot > 1.0F)
1083 dot = 1.0F;
1084 translate_angle = (float) acos(dot);
1085
1086 /* if translation angle > rotation angle then sets translation angle
1087 * to same as rotation angle, with proper sign of course */
1088
1089 if((fabs(translate_angle) > fabs(angle)) && (fabs(angle) > R_SMALL4)) {
1090 translate_angle = (float) (fabs(angle) * (translate_angle / fabs(angle)));
1091 }
1092
1093 if(fabs(translate_angle) < 0.0001F) {
1094 linear = true;
1095 if(debug)
1096 printf("no significant rotation\n");
1097 }
1098
1099 if((translate_angle * angle) < 0.0F) {
1100 /* if motions are in opposing directions, then flip translation axis and location */
1101 invert3f(bisect);
1102 invert3f(trans_axis);
1103 }
1104
1105 }
1106 }
1107
1108 if(!(simple || linear)) {
1109 float pLen = (float) tan(translate_angle / 2);
1110 if(fabs(pLen) > 0.0000001)
1111 pLen = (tLen / 2) / pLen;
1112 else {
1113 if(debug)
1114 printf("pLen too short %8.3f\n", pLen);
1115 simple = true;
1116 }
1117
1118 if(!simple) {
1119 pivot[0] = tCenter[0] + pLen * bisect[0];
1120 pivot[1] = tCenter[1] + pLen * bisect[1];
1121 pivot[2] = tCenter[2] + pLen * bisect[2];
1122 }
1123
1124 if(debug && !simple) {
1125 dump3f(tCenter, "center");
1126 dump3f(pivot, "pivot");
1127 printf("pLen %8.3f angle %8.3f translate_angle %8.3f\n",
1128 pLen, angle, translate_angle);
1129 }
1130 }
1131
1132 /* now interpolate */
1133
1134 state_flag = first->state_flag && last->state_flag;
1135
1136 timing_flag = first->timing_flag && last->timing_flag;
1137
1138 current = first + 1;
1139
1140 if(debug)
1141 dump44f(firstR44f, "first");
1142
1143 for(a = 0; a < n; a++) {
1144 double fxn = (a + 1.0) / (n + 1.0);
1145 double fxn_1 = 1.0 - fxn;
1146
1147 if(timing_flag) {
1148 timing = (first->timing * fxn_1) + (last->timing * fxn);
1149 }
1150
1151 if(state_flag) { /* states are interpolated linearly by default */
1152 state = (int)(first->state * (1.0F - fxn) + (last->state * fxn) + 0.499F);
1153 }
1154
1155 if(bias != 1.0F) {
1156 fxn = 1 - (float) pow(1 - pow(fxn, bias), _1 / bias);
1157 }
1158
1159 if((power != 1.0F) || (!parabolic)) {
1160 if(fxn < 0.5F) {
1161 if(!parabolic)
1162 fxn = (float) ((_1 - cos(cPI * fxn)) * _p5); /* circular */
1163 fxn = (float) pow(fxn * 2.0F, power) * _p5; /* parabolic */
1164 } else if(fxn > 0.5F) {
1165 fxn = _1 - fxn;
1166 if(!parabolic)
1167 fxn = (float) ((_1 - cos(cPI * fxn)) * _p5);
1168 fxn = (float) pow(fxn * 2.0F, power) * _p5; /* parabolic */
1169 fxn = _1 - fxn;
1170 }
1171 }
1172
1173 fxn_1 = 1.0F - fxn;
1174
1175 ViewElemCopy(G, first, current);
1176
1177 if(simple) {
1178 rotation_matrix3f(fxn * angle, rot_axis[0], rot_axis[1], rot_axis[2], &imat[0][0]);
1179
1180
1181 /* [cur] = [first] [partial-rot], so....
1182 at start: [cur] = [first] [identity] = [first]
1183 at end: [cur] = [first] [first]^-1 [last] = [last]
1184 */
1185 current->matrix_flag = true;
1186 multiply33f33f(first3x3, &imat[0][0], inter3x3);
1187
1188 copy33f44d(inter3x3, current->matrix);
1189
1190 if(first->pre_flag && last->pre_flag) {
1191 mix3d(first->pre, last->pre, (double) fxn, current->pre);
1192 current->pre_flag = true;
1193 } else {
1194 current->pre_flag = false;
1195 }
1196 if(first->post_flag && last->post_flag) {
1197 mix3d(first->post, last->post, (double) fxn, current->post);
1198 current->post_flag = true;
1199 } else {
1200 current->post_flag = false;
1201 }
1202 } else if(linear) {
1203 int b;
1204 rotation_matrix3f(fxn * angle, rot_axis[0], rot_axis[1], rot_axis[2], &imat[0][0]);
1205 current->matrix_flag = true;
1206 multiply33f33f(first3x3, &imat[0][0], inter3x3);
1207
1208 copy33f44d(inter3x3, current->matrix);
1209
1210 current->pre_flag = true;
1211 copy3f3d(pre, current->pre);
1212
1213 current->post_flag = true;
1214 for(b = 0; b < 3; b++) {
1215 imat[4][b] = (float) ((1.0 - fxn) * rot[3][b] + fxn * rot[4][b]);
1216 }
1217 copy3f3d(&imat[4][0], current->post);
1218 } else {
1219 matrix_interpolate(imat, rot,
1220 pivot, bisect,
1221 rot_axis, angle, trans_axis, translate_angle, fxn, linearity);
1222
1223 current->matrix_flag = true;
1224 multiply33f33f(first3x3, &imat[0][0], inter3x3);
1225
1226 copy33f44d(inter3x3, current->matrix);
1227
1228 current->pre_flag = true;
1229 copy3f3d(pre, current->pre);
1230
1231 current->post_flag = true;
1232 copy3f3d(&imat[4][0], current->post);
1233
1234 }
1235 if(debug) {
1236 if((a == 0) || (a == n - 1)) {
1237 float curC44f[16], curRTTT[16], curR44f[16];
1238
1239 copy33f44f(inter3x3, curC44f);
1240
1241 transpose44f44f(curC44f, curRTTT);
1242
1243 /* form TTTs */
1244
1245 curRTTT[12] = (float) -current->pre[0];
1246 curRTTT[13] = (float) -current->pre[1];
1247 curRTTT[14] = (float) -current->pre[2];
1248
1249 curRTTT[3] = (float) current->post[0];
1250 curRTTT[7] = (float) current->post[1];
1251 curRTTT[11] = (float) current->post[2];
1252
1253 convertTTTfR44f(curRTTT, curR44f);
1254 dump44f(curR44f, "cur");
1255 }
1256 }
1257
1258 if(first->clip_flag && last->clip_flag) {
1259 current->front = first->front * fxn_1 + last->front * fxn;
1260 current->back = first->back * fxn_1 + last->back * fxn;
1261 current->clip_flag = true;
1262 } else {
1263 current->clip_flag = false;
1264 }
1265
1266 if(first->ortho_flag && last->ortho_flag) {
1267 float approx_ortho = first->ortho * fxn_1 + last->ortho * fxn;
1268 if(first->pre_flag && last->pre_flag) {
1269 float first_far = first->pre[2] * tan(cPI * fabs(first->ortho) / 360.0);
1270 float last_far = last->pre[2] * tan(cPI * fabs(last->ortho) / 360.0);
1271
1272 float cur_far = first_far * fxn_1 + last_far * fxn;
1273 current->ortho = 360.0 * atan(cur_far / current->pre[2]) / cPI;
1274
1275 if((current->ortho * approx_ortho) < 0) /* fix sign */
1276 current->ortho = -current->ortho;
1277 } else {
1278 current->ortho = approx_ortho;
1279 }
1280 }
1281 current->specification_level = 1;
1282
1283 if(state_flag) {
1284 current->state_flag = true;
1285 current->state = state;
1286 }
1287
1288 if(timing_flag) {
1289 current->timing_flag = true;
1290 current->timing = timing;
1291 }
1292
1293
1294 if(first->scene_flag && last->scene_flag) {
1295 if(current->scene_name) {
1296 OVLexicon_DecRef(G->Lexicon, current->scene_name);
1297 }
1298 current->scene_flag = true;
1299 if(fxn >= cut) {
1300 current->scene_name = last->scene_name;
1301 } else {
1302 current->scene_name = first->scene_name;
1303 }
1304 OVLexicon_IncRef(G->Lexicon, current->scene_name);
1305 }
1306 current++;
1307 }
1308 if(debug)
1309 dump44f(lastR44f, "last");
1310
1311 return 1;
1312 }
1313