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_std.h"
21 #include"os_gl.h"
22 
23 #include"OOMac.h"
24 #include"ObjectSurface.h"
25 #include"Base.h"
26 #include"MemoryDebug.h"
27 #include"Map.h"
28 #include"Parse.h"
29 #include"Tetsurf.h"
30 #include"Vector.h"
31 #include"Color.h"
32 #include"main.h"
33 #include"Scene.h"
34 #include"Setting.h"
35 #include"Executive.h"
36 #include"PConv.h"
37 #include"P.h"
38 #include"Util.h"
39 #include"PyMOLGlobals.h"
40 #include"Matrix.h"
41 #include"ShaderMgr.h"
42 #include"CGO.h"
43 
44 static void ObjectSurfaceRecomputeExtent(ObjectSurface * I);
45 
ObjectSurfaceStateAsPyList(ObjectSurfaceState * I)46 static PyObject *ObjectSurfaceStateAsPyList(ObjectSurfaceState * I)
47 {
48   PyObject *result = NULL;
49 
50   result = PyList_New(17);
51 
52   PyList_SetItem(result, 0, PyInt_FromLong(I->Active));
53   PyList_SetItem(result, 1, PyString_FromString(I->MapName));
54   PyList_SetItem(result, 2, PyInt_FromLong(I->MapState));
55   PyList_SetItem(result, 3, CrystalAsPyList(&I->Crystal));
56   PyList_SetItem(result, 4, PyInt_FromLong(I->ExtentFlag));
57   PyList_SetItem(result, 5, PConvFloatArrayToPyList(I->ExtentMin, 3));
58   PyList_SetItem(result, 6, PConvFloatArrayToPyList(I->ExtentMax, 3));
59   PyList_SetItem(result, 7, PConvIntArrayToPyList(I->Range, 6));
60   PyList_SetItem(result, 8, PyFloat_FromDouble(I->Level));
61   PyList_SetItem(result, 9, PyFloat_FromDouble(I->Radius));
62   PyList_SetItem(result, 10, PyInt_FromLong(I->CarveFlag));
63   PyList_SetItem(result, 11, PyFloat_FromDouble(I->CarveBuffer));
64   if(I->CarveFlag && I->AtomVertex) {
65     PyList_SetItem(result, 12, PConvFloatVLAToPyList(I->AtomVertex));
66   } else {
67     PyList_SetItem(result, 12, PConvAutoNone(NULL));
68   }
69   PyList_SetItem(result, 13, PyInt_FromLong(I->DotFlag));
70   PyList_SetItem(result, 14, PyInt_FromLong(I->Mode));
71   PyList_SetItem(result, 15, PyInt_FromLong(I->Side));
72   PyList_SetItem(result, 16, PyInt_FromLong(I->quiet));
73 
74   return (PConvAutoNone(result));
75 }
76 
ObjectSurfaceAllStatesAsPyList(ObjectSurface * I)77 static PyObject *ObjectSurfaceAllStatesAsPyList(ObjectSurface * I)
78 {
79 
80   auto result = PyList_New(I->State.size());
81   for(int a = 0; a < I->State.size(); a++) {
82     if(I->State[a].Active) {
83       PyList_SetItem(result, a, ObjectSurfaceStateAsPyList(&I->State[a]));
84     } else {
85       PyList_SetItem(result, a, PConvAutoNone(NULL));
86     }
87   }
88   return (PConvAutoNone(result));
89 
90 }
91 
ObjectSurfaceStateFromPyList(PyMOLGlobals * G,ObjectSurfaceState * I,PyObject * list)92 static int ObjectSurfaceStateFromPyList(PyMOLGlobals * G, ObjectSurfaceState * I,
93                                         PyObject * list)
94 {
95   int ok = true;
96   int ll = 0;
97   PyObject *tmp;
98   if(ok)
99     ok = (list != NULL);
100   if(ok) {
101     if(!PyList_Check(list))
102       I->Active = false;
103     else {
104       *I = ObjectSurfaceState(G);
105       if(ok)
106         ok = PyList_Check(list);
107       if(ok)
108         ll = PyList_Size(list);
109       if(ok)
110         ok = PConvPyIntToInt(PyList_GetItem(list, 0), &I->Active);
111       if(ok)
112         ok = PConvPyStrToStr(PyList_GetItem(list, 1), I->MapName, WordLength);
113       if(ok)
114         ok = PConvPyIntToInt(PyList_GetItem(list, 2), &I->MapState);
115       if(ok)
116         ok = CrystalFromPyList(&I->Crystal, PyList_GetItem(list, 3));
117       if(ok)
118         ok = PConvPyIntToInt(PyList_GetItem(list, 4), &I->ExtentFlag);
119       if(ok)
120         ok = PConvPyListToFloatArrayInPlace(PyList_GetItem(list, 5), I->ExtentMin, 3);
121       if(ok)
122         ok = PConvPyListToFloatArrayInPlace(PyList_GetItem(list, 6), I->ExtentMax, 3);
123       if(ok)
124         ok = PConvPyListToIntArrayInPlace(PyList_GetItem(list, 7), I->Range, 6);
125       if(ok)
126         ok = PConvPyFloatToFloat(PyList_GetItem(list, 8), &I->Level);
127       if(ok)
128         ok = PConvPyFloatToFloat(PyList_GetItem(list, 9), &I->Radius);
129       if(ok)
130         ok = PConvPyIntToInt(PyList_GetItem(list, 10), &I->CarveFlag);
131       if(ok)
132         ok = PConvPyFloatToFloat(PyList_GetItem(list, 11), &I->CarveBuffer);
133       if(ok) {
134         tmp = PyList_GetItem(list, 12);
135         if(tmp == Py_None)
136           I->AtomVertex = NULL;
137         else
138           ok = PConvPyListToFloatVLA(tmp, &I->AtomVertex);
139       }
140       if(ok)
141         ok = PConvPyIntToInt(PyList_GetItem(list, 13), &I->DotFlag);
142       if(ok)
143         ok = PConvPyIntToInt(PyList_GetItem(list, 14), &I->Mode);
144 
145       if(ok && (ll > 15))
146         PConvPyIntToInt(PyList_GetItem(list, 15), &I->Side);
147       if(ok && (ll > 16))
148         PConvPyIntToInt(PyList_GetItem(list, 16), &I->quiet);
149 
150       if(ok) {
151         I->RefreshFlag = true;
152         I->ResurfaceFlag = true;
153       }
154     }
155   }
156   return (ok);
157 }
158 
ObjectSurfaceAllStatesFromPyList(ObjectSurface * I,PyObject * list,int size)159 static int ObjectSurfaceAllStatesFromPyList(ObjectSurface * I, PyObject * list, int size)
160 {
161   int ok = true;
162   I->State.reserve(size);
163   if(ok)
164     ok = PyList_Check(list);
165   if(ok) {
166     for(int a = 0; a < size; a++) {
167       CPythonVal *val = CPythonVal_PyList_GetItem(I->G, list, a);
168       I->State.emplace_back(I->G);
169       ok = ObjectSurfaceStateFromPyList(I->G, &I->State.back(), val);
170       CPythonVal_Free(val);
171       if(!ok)
172         break;
173     }
174   }
175   return (ok);
176 }
177 
ObjectSurfaceNewFromPyList(PyMOLGlobals * G,PyObject * list,ObjectSurface ** result)178 int ObjectSurfaceNewFromPyList(PyMOLGlobals * G, PyObject * list, ObjectSurface ** result)
179 {
180   int ok = true;
181   ObjectSurface *I = NULL;
182   (*result) = NULL;
183 
184   if(ok)
185     ok = (list != NULL);
186   if(ok)
187     ok = PyList_Check(list);
188 
189   I = new ObjectSurface(G);
190   if(ok)
191     ok = (I != NULL);
192 
193   if(ok){
194     auto *val = PyList_GetItem(list, 0);
195     ok = ObjectFromPyList(G, val, I);
196   }
197   int size = 0;
198   if(ok)
199     ok = CPythonVal_PConvPyIntToInt_From_List(G, list, 1, &size);
200   if(ok){
201     CPythonVal *val = CPythonVal_PyList_GetItem(G, list, 2);
202     ok = ObjectSurfaceAllStatesFromPyList(I, val, size);
203     CPythonVal_Free(val);
204   }
205   if(ok) {
206     (*result) = I;
207     ObjectSurfaceRecomputeExtent(I);
208   } else {
209     /* cleanup? */
210   }
211   return (ok);
212 }
213 
ObjectSurfaceAsPyList(ObjectSurface * I)214 PyObject *ObjectSurfaceAsPyList(ObjectSurface * I)
215 {
216   PyObject *result = NULL;
217 
218   result = PyList_New(3);
219   PyList_SetItem(result, 0, ObjectAsPyList(I));
220   PyList_SetItem(result, 1, PyInt_FromLong(I->State.size()));
221   PyList_SetItem(result, 2, ObjectSurfaceAllStatesAsPyList(I));
222 
223   return (PConvAutoNone(result));
224 }
225 
ObjectSurfaceDump(ObjectSurface * I,const char * fname,int state,int quiet)226 void ObjectSurfaceDump(ObjectSurface * I, const char *fname, int state, int quiet)
227 {
228   FILE* f = fopen(fname, "wb");
229   if(!f)
230     ErrMessage(I->G, "ObjectSurfaceDump", "can't open file for writing");
231   else {
232     if(state < I->State.size()) {
233       auto n = I->State[state].N.data();
234       auto v = I->State[state].V.data();
235       if(n && v)
236         while(*n) {
237           v += 12;
238           int c = *(n++);
239           c -= 4;
240           bool backface = true;
241           const float *v1, *v2;
242           while(c > 0) {
243             if ((backface = !backface)) {
244               v1 = v - 6;
245               v2 = v - 12;
246             } else {
247               v1 = v - 12;
248               v2 = v - 6;
249             }
250             fprintf(f,
251                     "%10.4f%10.4f%10.4f%10.4f%10.4f%10.4f\n%10.4f%10.4f%10.4f%10.4f%10.4f%10.4f\n%10.4f%10.4f%10.4f%10.4f%10.4f%10.4f\n",
252                     *(v1 + 3), *(v1 + 4), *(v1 + 5), *(v1), *(v1 + 1), *(v1 + 2),
253                     *(v2 + 3), *(v2 + 4), *(v2 + 5), *(v2), *(v2 + 1), *(v2 + 2),
254                     *(v + 3), *(v + 4), *(v + 5), *(v), *(v + 1), *(v + 2));
255 
256             v += 6;
257             c -= 2;
258           }
259         }
260     }
261     fclose(f);
262     if (!quiet) {
263       PRINTFB(I->G, FB_ObjectSurface, FB_Actions)
264         " ObjectSurfaceDump: %s written to %s\n", I->Name, fname ENDFB(I->G);
265     }
266   }
267 }
268 
invalidate(int rep,int level,int state)269 void ObjectSurface::invalidate(int rep, int level, int state)
270 {
271   auto I = this;
272   int once_flag = true;
273   if(level >= cRepInvExtents) {
274     I->ExtentFlag = false;
275   }
276   if((rep == cRepSurface) || (rep == cRepMesh) || (rep == cRepAll)) {
277     for(int a = 0; a < I->State.size(); a++) {
278       if(state < 0)
279         once_flag = false;
280       if(!once_flag)
281         state = a;
282       I->State[state].RefreshFlag = true;
283       if(level >= cRepInvRep) {
284         I->State[state].ResurfaceFlag = true;
285 	if(I->State[state].shaderCGO){
286 	  I->State[state].shaderCGO.reset();
287 	}
288         SceneChanged(I->G);
289       } else if(level >= cRepInvColor) {
290         I->State[state].RecolorFlag = true;
291 	if(I->State[state].shaderCGO){
292 	  I->State[state].shaderCGO.reset();
293 	}
294         SceneChanged(I->G);
295       } else {
296         SceneInvalidate(I->G);
297       }
298       if(once_flag)
299         break;
300     }
301   }
302 }
303 
ObjectSurfaceInvalidateMapName(ObjectSurface * I,const char * name,const char * new_name)304 int ObjectSurfaceInvalidateMapName(ObjectSurface * I, const char *name, const char * new_name)
305 {
306   int result = false;
307   for(int a = 0; a < I->State.size(); a++) {
308     auto ms = &I->State[a];
309     if(ms->Active) {
310       if(strcmp(ms->MapName, name) == 0) {
311         if (new_name)
312           strcpy(ms->MapName, new_name);
313         I->invalidate(cRepAll, cRepInvAll, a);
314         result = true;
315       }
316     }
317   }
318   return result;
319 }
320 
ObjectSurfaceStateUpdateColors(ObjectSurface * I,ObjectSurfaceState * ms)321 static void ObjectSurfaceStateUpdateColors(ObjectSurface * I, ObjectSurfaceState * ms)
322 {
323   int one_color_flag = true;
324   int cur_color =
325     SettingGet_color(I->G, I->Setting, NULL, cSetting_surface_color);
326 
327   if(cur_color == -1)
328     cur_color = I->Color;
329 
330   if(ColorCheckRamped(I->G, cur_color))
331     one_color_flag = false;
332 
333   ms->OneColor = cur_color;
334   if(ms->V) {
335     int ramped_flag = false;
336     float *v = ms->V.data();
337     float *vc;
338     int *rc;
339     int a;
340     int state = std::distance(I->State.data(), ms);
341     int base_n_vert = ms->base_n_V;
342     switch (ms->Mode) {
343     case 3:
344     case 2:
345       {
346         int n_vert = VLAGetSize(ms->V) / 6;
347         base_n_vert /= 6;
348 
349         if(!ms->VC.empty() && (ms->VCsize() < n_vert)) {
350           ms->VC.clear();
351           ms->RC.clear();
352         }
353 
354         if(ms->VC.empty()) {
355           ms->VC.resize(n_vert * 3);
356         }
357         if(ms->RC.empty()) {
358           ms->RC.resize(n_vert);
359         }
360         rc = ms->RC.data();
361         vc = ms->VC.data();
362         v += 3;
363         if(vc) {
364           for(a = 0; a < n_vert; a++) {
365             if(a == base_n_vert) {
366               int new_color = SettingGet_color(I->G, I->Setting,
367                                                NULL, cSetting_surface_negative_color);
368               if(new_color == -1)
369                 new_color = cur_color;
370               if(new_color != cur_color) {
371                 one_color_flag = false;
372                 cur_color = new_color;
373               }
374             }
375             if(ColorCheckRamped(I->G, cur_color)) {
376               ColorGetRamped(I->G, cur_color, v, vc, state);
377               *rc = cur_color;
378               ramped_flag = true;
379             } else {
380               const float *col = ColorGet(I->G, cur_color);
381               copy3f(col, vc);
382             }
383             rc++;
384             vc += 3;
385             v += 6;             /* alternates with normals */
386           }
387         }
388       }
389       break;
390     case 1:
391     case 0:
392     default:
393       {
394         int n_vert = VLAGetSize(ms->V) / 3;
395         base_n_vert /= 3;
396         if(!ms->VC.empty() && (ms->VCsize() < n_vert)) {
397           ms->VC.clear();
398           ms->RC.clear();
399         }
400 
401         if(ms->VC.empty()) {
402           ms->VC.resize(n_vert * 3);
403         }
404         if(ms->RC.empty()) {
405           ms->RC.resize(n_vert);
406         }
407         rc = ms->RC.data();
408         vc = ms->VC.data();
409         if(vc) {
410           for(a = 0; a < n_vert; a++) {
411             if(a == base_n_vert) {
412               int new_color = SettingGet_color(I->G, I->Setting,
413                                                NULL, cSetting_surface_negative_color);
414               if(new_color == -1)
415                 new_color = cur_color;
416               if(new_color != cur_color)
417                 one_color_flag = false;
418               cur_color = new_color;
419             }
420 
421             if(ColorCheckRamped(I->G, cur_color)) {
422               ColorGetRamped(I->G, cur_color, v, vc, state);
423               *rc = cur_color;
424               ramped_flag = true;
425             } else {
426               const float *col = ColorGet(I->G, cur_color);
427               copy3f(col, vc);
428             }
429             rc++;
430             vc += 3;
431             v += 3;
432           }
433         }
434       }
435       break;
436     }
437 
438     if(one_color_flag && (!ramped_flag)) {
439       ms->VC.clear();
440       ms->RC.clear();
441     } else if((!ramped_flag)
442               ||
443               (!SettingGet_b(I->G, NULL, I->Setting, cSetting_ray_color_ramps))) {
444       ms->RC.clear();
445     }
446   }
447 }
448 
update()449 void ObjectSurface::update()
450 {
451   auto I = this;
452   float carve_buffer;
453   for(auto& msref : I->State) {
454     ObjectSurfaceState *ms = &msref;
455     ObjectMapState *oms = NULL;
456     ObjectMap *map = NULL;
457     MapType *voxelmap = NULL;     /* this has nothing to do with isosurfaces... */
458 
459     if(ms->Active) {
460       map = ExecutiveFindObjectMapByName(I->G, ms->MapName);
461       if(!map) {
462         PRINTFB(I->G, FB_ObjectSurface, FB_Errors)
463           "ObjectSurfaceUpdate-Error: map '%s' has been deleted.\n", ms->MapName
464           ENDFB(I->G);
465         ms->ResurfaceFlag = false;
466       }
467       if(map) {
468         oms = ObjectMapGetState(map, ms->MapState);
469       }
470       if(oms) {
471         if(!oms->Matrix.empty()) {
472           ObjectStateSetMatrix(ms, oms->Matrix.data());
473         } else if(!ms->Matrix.empty()) {
474           ObjectStateResetMatrix(ms);
475         }
476 
477         if(I->visRep & cRepCellBit){
478           if (!ms->UnitCellCGO || ms->RefreshFlag || ms->ResurfaceFlag) {
479             ms->Crystal = oms->Symmetry->Crystal;
480             if((I->visRep & cRepCellBit)) {
481               ms->UnitCellCGO.reset(CrystalGetUnitCellCGO(&ms->Crystal));
482             }
483           }
484           ms->RefreshFlag = false;
485         }
486       }
487       if(map && ms && oms && ms->N && ms->V && (I->visRep & cRepSurfaceBit)) {
488         if(ms->ResurfaceFlag) {
489           ms->ResurfaceFlag = false;
490           ms->RecolorFlag = true;
491           if(!ms->quiet) {
492             PRINTFB(I->G, FB_ObjectSurface, FB_Details)
493               " ObjectSurface: updating \"%s\".\n", I->Name ENDFB(I->G);
494           }
495 
496           ms->shaderCGO.reset();
497 
498           if(oms->Field) {
499 
500             {
501               float *min_ext, *max_ext;
502               float tmp_min[3], tmp_max[3];
503               if(MatrixInvTransformExtentsR44d3f(ms->Matrix.data(),
504                                                  ms->ExtentMin, ms->ExtentMax,
505                                                  tmp_min, tmp_max)) {
506                 min_ext = tmp_min;
507                 max_ext = tmp_max;
508               } else {
509                 min_ext = ms->ExtentMin;
510                 max_ext = ms->ExtentMax;
511               }
512 
513               TetsurfGetRange(I->G, oms->Field.get(), &oms->Symmetry->Crystal,
514                               min_ext, max_ext, ms->Range);
515             }
516 
517             if(ms->CarveFlag && ms->AtomVertex) {
518               carve_buffer = ms->CarveBuffer;
519               if(carve_buffer < 0.0F) {
520                 carve_buffer = -carve_buffer;
521               }
522 
523               voxelmap = MapNew(I->G, -carve_buffer, ms->AtomVertex,
524                                 VLAGetSize(ms->AtomVertex) / 3, NULL);
525               if(voxelmap)
526                 MapSetupExpress(voxelmap);
527             }
528 
529             ms->nT = TetsurfVolume(I->G, oms->Field.get(),
530                                    ms->Level,
531                                    &ms->N, &ms->V,
532                                    ms->Range,
533                                    ms->Mode,
534                                    voxelmap, ms->AtomVertex, ms->CarveBuffer, ms->Side);
535 
536             if(!SettingGet_b
537                (I->G, I->Setting, NULL, cSetting_surface_negative_visible)) {
538               ms->base_n_V = VLAGetSize(ms->V);
539             } else {
540               /* do we want the negative surface too? */
541 
542               int nT2;
543               int *N2 = VLAlloc(int, 10000);
544               float *V2 = VLAlloc(float, 10000);
545 
546               nT2 = TetsurfVolume(I->G, oms->Field.get(),
547                                   -ms->Level,
548                                   &N2, &V2,
549                                   ms->Range,
550                                   ms->Mode,
551                                   voxelmap, ms->AtomVertex.data(), ms->CarveBuffer, ms->Side);
552               if(N2 && V2) {
553 
554                 int base_n_N = VLAGetSize(ms->N);
555                 int base_n_V = VLAGetSize(ms->V);
556                 int addl_n_N = VLAGetSize(N2);
557                 int addl_n_V = VLAGetSize(V2);
558 
559                 ms->base_n_V = base_n_V;
560 
561                 /* make room */
562 
563                 VLASize(ms->N, int, base_n_N + addl_n_N);
564                 VLASize(ms->V, float, base_n_V + addl_n_V);
565 
566                 /* copy vertex data */
567 
568                 memcpy(((char *) ms->V.data()) + (sizeof(float) * base_n_V),
569                        V2, sizeof(float) * addl_n_V);
570 
571                 /* copy strip counts */
572 
573                 memcpy(((char *) ms->N.data()) + (sizeof(int) * (base_n_N - 1)),
574                        N2, sizeof(int) * addl_n_N);
575                 ms->N[base_n_N + addl_n_N - 1] = 0;
576 
577                 ms->nT += nT2;
578                 VLAFreeP(N2);
579                 VLAFreeP(V2);
580               }
581             }
582 
583             if(voxelmap)
584               MapFree(voxelmap);
585 
586             if(!ms->Matrix.empty()) {      /* in we're in a different reference frame... */
587               double *matrix = ms->Matrix.data();
588               auto v = ms->V.data();
589               auto n = ms->N.data();
590 
591               if(n && v) {
592 
593                 while(*n) {
594                   int c = *(n++);
595                   switch (ms->Mode) {
596                   case 3:
597                   case 2:
598                     transform44d3fas33d3f(matrix, v, v);
599                     transform44d3f(matrix, v + 3, v + 3);
600                     transform44d3fas33d3f(matrix, v + 6, v + 6);
601                     transform44d3f(matrix, v + 9, v + 9);
602                     v += 12;
603                     c -= 4;
604                     while(c > 0) {
605                       transform44d3fas33d3f(matrix, v, v);
606                       transform44d3f(matrix, v + 3, v + 3);
607                       v += 6;
608                       c -= 2;
609                     }
610                     break;
611                   case 1:
612                     transform44d3f(matrix, v, v);
613                     c--;
614                     v += 3;
615                     while(c > 0) {
616                       transform44d3f(matrix, v, v);
617                       v += 3;
618                       c--;
619                     }
620                     break;
621                   case 0:
622                   default:
623                     while(c > 0) {
624                       transform44d3f(matrix, v, v);
625                       v += 3;
626                       c--;
627                     }
628                     break;
629                   }
630                 }
631               }
632             }
633           }
634         }
635         if(ms->RecolorFlag) {
636           ObjectSurfaceStateUpdateColors(I, ms);
637           ms->RecolorFlag = false;
638         }
639       }
640     }
641   }
642   if(!I->ExtentFlag) {
643     ObjectSurfaceRecomputeExtent(I);
644   }
645   SceneInvalidate(I->G);
646 }
647 
ObjectSurfaceRenderGlobalTransparency(PyMOLGlobals * G,RenderInfo * info,ObjectSurfaceState * ms,const float * col,float alpha)648 static void ObjectSurfaceRenderGlobalTransparency(PyMOLGlobals * G,
649     RenderInfo * info, ObjectSurfaceState *ms, const float *col, float alpha)
650 {
651   auto v = ms->V.data();
652   auto vc = ms->VC.data();
653   auto n = ms->N.data();
654 
655   while(*n) {
656     int parity = 1;
657     int c = *(n++);
658 
659     v += 6;
660     if(vc)
661       vc += 3;
662     c -= 2;
663 
664     v += 6;
665     if(vc)
666       vc += 3;
667     c -= 2;
668 
669     while(c > 0) {
670       if(vc) {
671         CGOAlphaTriangle(info->alpha_cgo,
672                          v + (3 - 6), v + (3 - 12), v + 3,
673                          v - 6, v - 12, v,
674                          vc - 3, vc - 6, vc,
675                          alpha, alpha, alpha, parity);
676       } else {
677         CGOAlphaTriangle(info->alpha_cgo,
678                          v + (3 - 6), v + (3 - 12), v + 3,
679                          v - 6, v - 12, v,
680                          col, col, col,
681                          alpha, alpha, alpha, parity);
682       }
683       v += 6;
684       if(vc)
685         vc += 3;
686       c -= 2;
687       parity = !parity;
688     }
689   }
690 }
691 
ObjectSurfaceRenderUnOptimizedTransparency(ObjectSurfaceState * ms,float alpha)692 static void ObjectSurfaceRenderUnOptimizedTransparency(ObjectSurfaceState *ms, float alpha){
693   auto v = ms->V.data();
694   auto vc = ms->VC.data();
695   auto n = ms->N.data();
696 
697   while(*n) {
698     int c = *(n++);
699     CGOBegin(ms->shaderCGO.get(), GL_TRIANGLE_STRIP);
700     while(c > 0) {
701       CGONormalv(ms->shaderCGO.get(), v);
702       v += 3;
703       if(vc) {
704         CGOColorv(ms->shaderCGO.get(), vc);
705         vc += 3;
706       }
707       CGOVertexv(ms->shaderCGO.get(), v);
708       v += 3;
709       c -= 2;
710     }
711     CGOEnd(ms->shaderCGO.get());
712   }
713 }
714 
ObjectSurfaceRenderOpaque(PyMOLGlobals * G,ObjectSurface * I,ObjectSurfaceState * ms)715 static void ObjectSurfaceRenderOpaque(PyMOLGlobals * G, ObjectSurface * I, ObjectSurfaceState *ms){
716   auto v = ms->V.data();
717   auto n = ms->N.data();
718   CGOSpecial(ms->shaderCGO.get(), LINEWIDTH_DYNAMIC_MESH);
719   auto vc = ms->VC.data();
720 
721   while(*n) {
722     int c = *(n++);
723     switch (ms->Mode) {
724     case 3:
725     case 2:
726       CGOBegin(ms->shaderCGO.get(), GL_TRIANGLE_STRIP);
727       while(c > 0) {
728         CGONormalv(ms->shaderCGO.get(), v);
729         v += 3;
730         if(vc) {
731           CGOColorv(ms->shaderCGO.get(), vc);
732           vc += 3;
733         }
734         CGOVertexv(ms->shaderCGO.get(), v);
735         v += 3;
736         c -= 2;
737       }
738       CGOEnd(ms->shaderCGO.get());
739       break;
740     case 1:
741       CGOBegin(ms->shaderCGO.get(), GL_LINES);
742       while(c > 0) {
743         if(vc) {
744           CGOColorv(ms->shaderCGO.get(), vc);
745           vc += 3;
746         }
747         CGOVertexv(ms->shaderCGO.get(), v);
748         v += 3;
749         c--;
750       }
751       CGOEnd(ms->shaderCGO.get());
752       break;
753     case 0:
754     default:
755       CGOBegin(ms->shaderCGO.get(), GL_POINTS);
756       while(c > 0) {
757         if(vc) {
758           CGOColorv(ms->shaderCGO.get(), vc);
759           vc += 3;
760         }
761         CGOVertexv(ms->shaderCGO.get(), v);
762         v += 3;
763         c--;
764       }
765       CGOEnd(ms->shaderCGO.get());
766     }
767   }
768 }
769 
ObjectSurfaceRenderRay(PyMOLGlobals * G,ObjectSurface * I,RenderInfo * info,ObjectSurfaceState * ms)770 static void ObjectSurfaceRenderRay(PyMOLGlobals * G, ObjectSurface *I,
771     RenderInfo * info, ObjectSurfaceState *ms)
772 {
773   float *v = ms->V.data();
774   float *vc = ms->VC.data();
775   int *rc;
776   int c;
777   int* n = ms->N.data();
778   float alpha = 1.0F - SettingGet_f(G, NULL, I->Setting, cSetting_transparency);
779   if(fabs(alpha - 1.0) < R_SMALL4)
780     alpha = 1.0F;
781 
782 
783   CRay *ray = info->ray;
784   if(ms->UnitCellCGO && (I->visRep & cRepCellBit)){
785     int rayok = CGORenderRay(ms->UnitCellCGO.get(), ray, info, ColorGet(G, I->Color),
786                              NULL, I->Setting, NULL);
787     if (!rayok){
788       ms->UnitCellCGO.reset();
789     }
790   }
791 
792   ray->transparentf(1.0F - alpha);
793   ms->Radius = SettingGet_f(G, I->Setting, NULL, cSetting_mesh_radius);
794   if(ms->Radius == 0.0F) {
795     ms->Radius = ray->PixelRadius *
796       SettingGet_f(I->G, I->Setting, NULL, cSetting_mesh_width) / 2.0F;
797   }
798 
799   if(n && v && (I->visRep & cRepSurfaceBit)) {
800     float cc[3];
801     float colA[3], colB[3], colC[3];
802     ColorGetEncoded(G, ms->OneColor, cc);
803     vc = ms->VC.data();
804 
805     rc = ms->RC.data();
806     while(*n) {
807       c = *(n++);
808       switch (ms->Mode) {
809       case 3:
810       case 2:
811         v += 12;
812         if(vc)
813           vc += 6;
814         c -= 4;
815         while(c > 0) {
816           if(vc) {
817             float *cA = vc - 6, *cB = vc - 3, *cC = vc;
818             if(rc) {
819               if(rc[0] < -1)
820                 ColorGetEncoded(G, rc[0], (cA = colA));
821               if(rc[1] < -1)
822                 ColorGetEncoded(G, rc[1], (cB = colB));
823               if(rc[2] < -1)
824                 ColorGetEncoded(G, rc[2], (cC = colC));
825               rc++;
826             }
827             ray->triangle3fv(v - 9, v - 3, v + 3,
828                              v - 12, v - 6, v, cA, cB, cC);
829             vc += 3;
830           } else {
831             ray->triangle3fv(v - 9, v - 3, v + 3,
832                              v - 12, v - 6, v, cc, cc, cc);
833           }
834           v += 6;
835           c -= 2;
836         }
837         break;
838       case 1:
839         c--;
840         v += 3;
841         if(vc)
842           vc += 3;
843         while(c > 0) {
844           if(vc) {
845             float *cA = vc - 3, *cB = vc;
846             if(rc) {
847               if(rc[0] < -1)
848                 ColorGetEncoded(G, rc[0], (cA = colA));
849               if(rc[1] < -1)
850                 ColorGetEncoded(G, rc[1], (cB = colB));
851               rc++;
852             }
853             ray->sausage3fv(v - 3, v, ms->Radius, cA, cB);
854             vc += 3;
855           } else
856             ray->sausage3fv(v - 3, v, ms->Radius, cc, cc);
857           v += 3;
858           c--;
859         }
860         break;
861       case 0:
862       default:
863         while(c > 0) {
864           if(vc) {
865             ray->color3fv(vc);
866             vc += 3;
867           }
868           ray->sphere3fv(v, ms->Radius);
869           v += 3;
870           c--;
871         }
872         break;
873       }
874     }
875   }
876   ray->transparentf(0.0);
877 }
878 
ObjectSurfaceRenderCell(PyMOLGlobals * G,ObjectSurface * I,RenderInfo * info,ObjectSurfaceState * ms,short use_shader)879 static void ObjectSurfaceRenderCell(PyMOLGlobals *G, ObjectSurface * I,
880     RenderInfo * info, ObjectSurfaceState *ms, short use_shader)
881 {
882   const float *color = ColorGet(G, I->Color);
883   if (use_shader != ms->UnitCellCGO->has_draw_buffers){
884     if (use_shader){
885       CGO *convertcgo = CGOOptimizeToVBONotIndexed(ms->UnitCellCGO.get(), 0);
886       ms->UnitCellCGO.reset(convertcgo);
887       ms->UnitCellCGO->use_shader = true;
888     } else {
889       ms->UnitCellCGO.reset(CrystalGetUnitCellCGO(&ms->Crystal));
890     }
891   }
892   CGORenderGL(ms->UnitCellCGO.get(), color,
893               I->Setting, NULL, info, NULL);
894 }
895 
render(RenderInfo * info)896 void ObjectSurface::render(RenderInfo * info)
897 {
898   auto I = this;
899   int state = info->state;
900   CRay *ray = info->ray;
901   auto pick = info->pick;
902   int pass = info->pass;
903   const float *col;
904   ObjectSurfaceState *ms = NULL;
905   float alpha;
906   ObjectPrepareContext(I, info);
907 
908   alpha = 1.0F - SettingGet_f(G, NULL, I->Setting, cSetting_transparency);
909   if(fabs(alpha - 1.0) < R_SMALL4)
910     alpha = 1.0F;
911 
912   StateIterator iter(G, I->Setting, state, I->State.size());
913   while(iter.next()) {
914     ms = &I->State[iter.state];
915     if(ms && ms->Active && ms->V && ms->N) {
916       if(ray) {
917         ObjectSurfaceRenderRay(G, I, info, ms);
918       } else if(G->HaveGUI && G->ValidContext) {
919         if(!pick) {  // no picking for ObjectSurfaces
920           int render_now = false;
921           short use_shader;
922           use_shader = SettingGetGlobal_b(G, cSetting_surface_use_shader) &
923             SettingGetGlobal_b(G, cSetting_use_shaders);
924 
925           if(info && info->alpha_cgo) {
926             render_now = (pass == 1);
927             use_shader = false;
928           } else if(alpha < 1.0F) {
929             render_now = (pass == -1);
930           } else {
931             render_now = (pass == 1);
932           }
933 
934           if((I->visRep & cRepCellBit) && ms->UnitCellCGO && (pass == 1)){
935             ObjectSurfaceRenderCell(G, I, info, ms, use_shader);
936           }
937 
938           if(render_now) {
939             if (ms->shaderCGO && use_shader != ms->shaderCGO->has_draw_buffers){
940               ms->shaderCGO.reset();
941             }
942 
943             if (ms->shaderCGO){
944               CGORenderGL(ms->shaderCGO.get(), NULL, NULL, NULL, info, NULL);
945               continue;
946             }
947 
948             // Generating CGO
949             ms->shaderCGO.reset(CGONew(G));
950             ms->shaderCGO->use_shader = true;
951 
952             CGOResetNormal(ms->shaderCGO.get(), false);
953 
954             col = ColorGet(G, ms->OneColor);
955             if((alpha != 1.0)) {
956               CGOAlpha(ms->shaderCGO.get(), alpha);
957             }
958             CGOColorv(ms->shaderCGO.get(), col);
959 
960             if(I->visRep & cRepSurfaceBit) {
961               if((ms->Mode > 1) && (alpha != 1.0)) {        /* transparent */
962                 if(info->alpha_cgo) {     /* global transparency */
963                   ObjectSurfaceRenderGlobalTransparency(G, info, ms, col, alpha);
964                 } else {  /* cgo transparency with sorting if needed */
965                   ObjectSurfaceRenderUnOptimizedTransparency(ms, alpha);
966                 }
967               } else {      /* opaque, triangles */
968                 ObjectSurfaceRenderOpaque(G, I, ms);
969               }
970             }
971             CGOStop(ms->shaderCGO.get());
972 
973             if (use_shader){
974               auto convertcgo = CGOCombineBeginEnd(ms->shaderCGO.get(), 0);
975               ms->shaderCGO.reset(convertcgo);
976               convertcgo = CGOOptimizeToVBOIndexed(ms->shaderCGO.get(), 0, NULL, true, (alpha != 1.0) /* embedTransparency */);
977               if (convertcgo){
978                 ms->shaderCGO.reset(convertcgo);
979               }
980               ms->shaderCGO->use_shader = true;
981               CGORenderGL(ms->shaderCGO.get(), NULL, NULL, NULL, info, NULL);
982             } else {
983               if (alpha != 1.0){
984                 // use_shader = 0
985                 CGO *convertcgo = CGOConvertTrianglesToAlpha(ms->shaderCGO.get());
986                 ms->shaderCGO.reset(convertcgo);
987                 ms->shaderCGO->render_alpha = 1;
988               }
989               ms->shaderCGO->use_shader = false;
990               CGORenderGL(ms->shaderCGO.get(), NULL, NULL, NULL, info, NULL);
991             }
992           }
993         }
994       }
995     }
996   }
997 }
998 
999 
1000 /*========================================================================*/
1001 
getNFrame() const1002 int ObjectSurface::getNFrame() const
1003 {
1004   return State.size();
1005 }
1006 
1007 
1008 /*========================================================================*/
ObjectSurface(PyMOLGlobals * G)1009 ObjectSurface::ObjectSurface(PyMOLGlobals* G)
1010     : CObject(G)
1011 {
1012   type = cObjectSurface;
1013 }
1014 
1015 /*========================================================================*/
ObjectSurfaceState(PyMOLGlobals * G)1016 ObjectSurfaceState::ObjectSurfaceState(PyMOLGlobals* G)
1017     : CObjectState(G)
1018     , Crystal(G)
1019     , Active(true)
1020 {
1021   V = pymol::vla<float>(10000);
1022   N = pymol::vla<int>(10000);
1023 }
1024 
1025 /*========================================================================*/
ObjectSurfaceFromBox(PyMOLGlobals * G,ObjectSurface * obj,ObjectMap * map,int map_state,int state,float * mn,float * mx,float level,int mode,float carve,float * vert_vla,int side,int quiet)1026 ObjectSurface *ObjectSurfaceFromBox(PyMOLGlobals * G, ObjectSurface * obj,
1027                                     ObjectMap * map, int map_state, int state, float *mn,
1028                                     float *mx, float level, int mode, float carve,
1029                                     float *vert_vla, int side, int quiet)
1030 {
1031   ObjectSurface *I;
1032   ObjectSurfaceState *ms;
1033   ObjectMapState *oms;
1034 
1035   if(!obj) {
1036     I = new ObjectSurface(G);
1037   } else {
1038     I = obj;
1039   }
1040 
1041   if(state < 0)
1042     state = I->State.size();
1043   if(I->State.size() <= state) {
1044     VecCheckEmplace(I->State, state, G);
1045   }
1046 
1047   ms = &I->State[state];
1048   *ms = ObjectSurfaceState(G);
1049 
1050   strcpy(ms->MapName, map->Name);
1051   ms->MapState = map_state;
1052   oms = ObjectMapGetState(map, map_state);
1053 
1054   ms->Level = level;
1055   ms->Mode = mode;
1056   ms->Side = side;
1057   ms->quiet = quiet;
1058   if(oms) {
1059 
1060     if(!oms->Matrix.empty()) {
1061       ObjectStateSetMatrix(ms, oms->Matrix.data());
1062     } else if(!ms->Matrix.empty()) {
1063       ObjectStateResetMatrix(ms);
1064     }
1065 
1066     copy3f(mn, ms->ExtentMin);  /* this is not exactly correct...should actually take vertex points from range */
1067     copy3f(mx, ms->ExtentMax);
1068 
1069     {
1070       float *min_ext, *max_ext;
1071       float tmp_min[3], tmp_max[3];
1072       if(MatrixInvTransformExtentsR44d3f(ms->Matrix.data(),
1073                                          ms->ExtentMin, ms->ExtentMax,
1074                                          tmp_min, tmp_max)) {
1075         min_ext = tmp_min;
1076         max_ext = tmp_max;
1077       } else {
1078         min_ext = ms->ExtentMin;
1079         max_ext = ms->ExtentMax;
1080       }
1081 
1082       TetsurfGetRange(G, oms->Field.get(), &oms->Symmetry->Crystal, min_ext, max_ext, ms->Range);
1083     }
1084     ms->ExtentFlag = true;
1085   }
1086   if(carve != 0.0) {
1087     ms->CarveFlag = true;
1088     ms->CarveBuffer = carve;
1089     ms->AtomVertex = pymol::vla_take_ownership(vert_vla);
1090 
1091     double *matrix = ObjectStateGetInvMatrix(ms);
1092 
1093     if(matrix) {
1094       int n = VLAGetSize(ms->AtomVertex) / 3;
1095       float *v = ms->AtomVertex.data();
1096       while(n--) {
1097         /* convert back into original map coordinates
1098            for surface carving operation */
1099         transform44d3f(matrix, v, v);
1100         v += 3;
1101       }
1102     }
1103 
1104   }
1105   if(I) {
1106     ObjectSurfaceRecomputeExtent(I);
1107   }
1108   I->ExtentFlag = true;
1109   /*  printf("Brick %d %d %d %d %d %d\n",I->Range[0],I->Range[1],I->Range[2],I->Range[3],I->Range[4],I->Range[5]); */
1110   SceneChanged(G);
1111   SceneCountFrames(G);
1112   return (I);
1113 }
1114 
ObjectSurfaceGetLevel(ObjectSurface * I,int state)1115 pymol::Result<float> ObjectSurfaceGetLevel(ObjectSurface * I, int state)
1116 {
1117   if(state >= I->State.size()) {
1118     return pymol::make_error("Invalid surface state");
1119   } else {
1120     if(state < 0) {
1121       state = 0;
1122     }
1123     auto ms = &I->State[state];
1124     if(ms->Active) {
1125       return ms->Level;
1126     } else {
1127       return pymol::make_error("Invalid Surface state");
1128     }
1129   }
1130 }
1131 
ObjectSurfaceSetLevel(ObjectSurface * I,float level,int state,int quiet)1132 int ObjectSurfaceSetLevel(ObjectSurface * I, float level, int state, int quiet)
1133 {
1134   int ok = true;
1135   int once_flag = true;
1136   if(state >= I->State.size()) {
1137     ok = false;
1138   } else {
1139     for(int a = 0; a < I->State.size(); a++) {
1140       if(state < 0) {
1141         once_flag = false;
1142       }
1143       if(!once_flag) {
1144         state = a;
1145       }
1146       auto ms = &I->State[state];
1147       if(ms->Active) {
1148         ms->ResurfaceFlag = true;
1149         ms->RefreshFlag = true;
1150         ms->Level = level;
1151         ms->quiet = quiet;
1152       }
1153       if(once_flag) {
1154         break;
1155       }
1156     }
1157   }
1158   return (ok);
1159 }
1160 
1161 
1162 /*========================================================================*/
1163 
ObjectSurfaceRecomputeExtent(ObjectSurface * I)1164 void ObjectSurfaceRecomputeExtent(ObjectSurface * I)
1165 {
1166   int extent_flag = false;
1167 
1168   for(auto& msr : I->State) {
1169     auto ms = &msr;
1170     if(ms->Active) {
1171       if(ms->ExtentFlag) {
1172         if(!extent_flag) {
1173           extent_flag = true;
1174           copy3f(ms->ExtentMax, I->ExtentMax);
1175           copy3f(ms->ExtentMin, I->ExtentMin);
1176         } else {
1177           max3f(ms->ExtentMax, I->ExtentMax, I->ExtentMax);
1178           min3f(ms->ExtentMin, I->ExtentMin, I->ExtentMin);
1179         }
1180       }
1181     }
1182   }
1183   I->ExtentFlag = extent_flag;
1184 
1185   if(I->TTTFlag && I->ExtentFlag) {
1186     const float *ttt;
1187     double tttd[16];
1188     if(ObjectGetTTT(I, &ttt, -1)) {
1189       convertTTTfR44d(ttt, tttd);
1190       MatrixTransformExtentsR44d3f(tttd,
1191                                    I->ExtentMin, I->ExtentMax,
1192                                    I->ExtentMin, I->ExtentMax);
1193     }
1194   }
1195 }
1196 
1197 /*========================================================================*/
1198 
clone() const1199 CObject* ObjectSurface::clone() const
1200 {
1201   return new ObjectSurface(*this);
1202 }
1203 
1204