1 
2 
3 /*
4 A* -------------------------------------------------------------------
5 B* This file contains source code for the PyMOL computer program
6 C* Copyright (c) Schrodinger, LLC.
7 D* -------------------------------------------------------------------
8 E* It is unlawful to modify or remove this copyright notice.
9 F* -------------------------------------------------------------------
10 G* Please see the accompanying LICENSE file for further information.
11 H* -------------------------------------------------------------------
12 I* Additional authors of this source file include:
13 -*
14 -*
15 -*
16 Z* -------------------------------------------------------------------
17 */
18 
19 #include"os_predef.h"
20 #include"os_std.h"
21 #include"os_gl.h"
22 
23 #include"Base.h"
24 #include"Sphere.h"
25 #include"Vector.h"
26 #include"Err.h"
27 
28 #include"MemoryDebug.h"
29 
30 #define FAST_SPHERE_INIT
31 
32 #ifndef FAST_SPHERE_INIT
33 /* Twelve vertices of icosahedron on unit sphere */
34 #define tau 0.8506508084F       /* t=(1+sqrt(5))/2, tau=t/sqrt(1+t^2)  */
35 #define one 0.5257311121F       /* one=1/sqrt(1+t^2) , unit sphere     */
36 
37 static const float start_points[13][3] = {
38   {tau, one, 0},
39   {-tau, one, 0},
40   {-tau, -one, 0},
41   {tau, -one, 0},
42   {one, 0, tau},
43   {one, 0, -tau},
44   {-one, 0, -tau},
45   {-one, 0, tau},
46   {0, tau, one},
47   {0, -tau, one},
48   {0, -tau, -one},
49   {0, tau, -one}
50 };
51 
52 static const int icosahedron[21][3] = {
53   {4, 8, 7},
54   {4, 7, 9},
55   {5, 6, 11},
56   {5, 10, 6},
57   {0, 4, 3},
58   {0, 3, 5},
59   {2, 7, 1},
60   {2, 1, 6},
61   {8, 0, 11},
62   {8, 11, 1},
63   {9, 10, 3},
64   {9, 2, 10},
65   {8, 4, 0},
66   {11, 0, 5},
67   {4, 9, 3},
68   {5, 3, 10},
69   {7, 8, 1},
70   {6, 1, 11},
71   {7, 2, 9},
72   {6, 10, 2}
73 };
74 #endif
75 
76 static const int mesh[30][2] = {
77   {0, 3},
78   {0, 4},
79   {0, 5},
80   {0, 8},
81   {0, 11},
82   {1, 2},
83   {1, 6},
84   {1, 7},
85   {1, 8},
86   {1, 11},
87   {2, 6},
88   {2, 7},
89   {2, 9},
90   {2, 10},
91   {3, 4},
92   {3, 5},
93   {3, 9},
94   {3, 10},
95   {4, 7},
96   {4, 8},
97   {4, 9},
98   {5, 6},
99   {5, 10},
100   {5, 11},
101   {6, 10},
102   {6, 11},
103   {7, 8},
104   {7, 9},
105   {8, 11},
106   {9, 10}
107 };
108 
109 #ifdef FAST_SPHERE_INIT
110 #include"SphereData.h"
111 
112 #else
113 
114 static SphereRec *MakeDotSphere(PyMOLGlobals * G, int level);
115 
116 #endif
117 
118 #ifndef FAST_SPHERE_INIT
SphereDumpAll(CSphere * I)119 static void SphereDumpAll(CSphere *I)
120 {
121   FILE *f;
122   int i, dot_total, a, c, strip_total, seq_total, tri_total;
123   SphereRec *sp;
124   f = fopen("SphereData.h", "w");
125 
126   fprintf(f, "static int Sphere_NSpheres = %d;\n", NUMBER_OF_SPHERE_LEVELS);
127 
128   fprintf(f, "static int Sphere_NTri[%d] = {\n", NUMBER_OF_SPHERE_LEVELS);
129   for (i=0; i < NUMBER_OF_SPHERE_LEVELS; i++){
130     fprintf(f, " %d, ", I->Sphere[i]->NTri);
131   }
132   fprintf(f, "\n};\n");
133 
134   fprintf(f, "static int Sphere_NStrip[%d] = {\n", NUMBER_OF_SPHERE_LEVELS);
135   for (i=0; i < NUMBER_OF_SPHERE_LEVELS; i++){
136     fprintf(f, " %d, ", I->Sphere[i]->NStrip);
137   }
138   fprintf(f, "\n};\n");
139 
140   fprintf(f, "static int Sphere_NVertTot[%d] = {\n", NUMBER_OF_SPHERE_LEVELS);
141   for (i=0; i < NUMBER_OF_SPHERE_LEVELS; i++){
142     fprintf(f, " %d, ", I->Sphere[i]->NVertTot);
143   }
144   fprintf(f, "\n};\n");
145 
146   fprintf(f, "static int Sphere_nDot[%d] = {\n", NUMBER_OF_SPHERE_LEVELS);
147   for (i=0; i < NUMBER_OF_SPHERE_LEVELS; i++){
148     fprintf(f, " %d, ", I->Sphere[i]->nDot);
149   }
150   fprintf(f, "\n};\n");
151 
152   fprintf(f, "static int Sphere_dot_start[%d] = {\n", NUMBER_OF_SPHERE_LEVELS);
153   dot_total = 0;
154   for (i=0; i < NUMBER_OF_SPHERE_LEVELS; i++){
155     fprintf(f, " %d, ", dot_total);
156     dot_total += I->Sphere[i]->nDot;
157   }
158   fprintf(f, "\n};\n");
159 
160   fprintf(f, "static float Sphere_dot[][3] = {\n");
161   for (i=0; i < NUMBER_OF_SPHERE_LEVELS; i++){
162     sp = I->Sphere[i];
163     fprintf(f, "/* dots for Sphere #%d */\n", i);
164     for(a = 0; a < sp->nDot; a++) {
165       fprintf(f, "{ %15.12fF, %15.12fF, %15.12fF },\n",
166 	      sp->dot[a][0], sp->dot[a][1], sp->dot[a][2]);
167     }
168   }
169   fprintf(f, "};\n");
170 
171   fprintf(f, "static float Sphere_area[] = {\n");
172   for (i=0; i < NUMBER_OF_SPHERE_LEVELS; i++){
173     sp = I->Sphere[i];
174     fprintf(f, "/* areas for Sphere #%d */\n", i);
175     c = 0;
176     for(a = 0; a < sp->nDot; a++) {
177       fprintf(f, "%15.12fF,", sp->area[a]);
178     c = (c + 1) % 4;
179       if (!c)
180 	fprintf(f, "\n");
181     }
182     if (c)
183       fprintf(f, "\n");
184   }
185   fprintf(f, "};\n");
186 
187 
188   fprintf(f, "static int Sphere_StripLen_start[%d] = {\n", NUMBER_OF_SPHERE_LEVELS);
189   strip_total = 0;
190   for (i=0; i < NUMBER_OF_SPHERE_LEVELS; i++){
191     fprintf(f, " %d, ", strip_total);
192     strip_total += I->Sphere[i]->NStrip;
193   }
194   fprintf(f, "\n};\n");
195 
196   fprintf(f, "static int Sphere_StripLen[] = {\n");
197   for (i=0; i < NUMBER_OF_SPHERE_LEVELS; i++){
198     sp = I->Sphere[i];
199     fprintf(f, "/* StripLen for Sphere #%d */\n", i);
200     c = 0;
201     for(a = 0; a < sp->NStrip; a++) {
202       fprintf(f, "%6d,", sp->StripLen[a]);
203       c = (c + 1) % 10;
204       if(!c)
205 	fprintf(f, "\n");
206     }
207     if (c)
208       fprintf(f, "\n");
209   }
210   fprintf(f, "};\n");
211 
212   fprintf(f, "static int Sphere_Sequence_start[%d] = {\n", NUMBER_OF_SPHERE_LEVELS);
213   seq_total = 0;
214   for (i=0; i < NUMBER_OF_SPHERE_LEVELS; i++){
215     fprintf(f, " %d, ", seq_total);
216     seq_total += I->Sphere[i]->NVertTot;
217   }
218   fprintf(f, "\n};\n");
219 
220   fprintf(f, "static int Sphere_Sequence[] = {\n");
221   for (i=0; i < NUMBER_OF_SPHERE_LEVELS; i++){
222     sp = I->Sphere[i];
223     fprintf(f, "/* Sequence for Sphere #%d */\n", i);
224     c = 0;
225     for(a = 0; a < sp->NVertTot; a++) {
226       fprintf(f, "%6d,", sp->Sequence[a]);
227       c = (c + 1) % 10;
228       if(!c)
229 	fprintf(f, "\n");
230     }
231     if (c)
232       fprintf(f, "\n");
233   }
234   fprintf(f, "};\n");
235 
236   fprintf(f, "static int Sphere_Tri_start[%d] = {\n", NUMBER_OF_SPHERE_LEVELS);
237   tri_total = 0;
238   for (i=0; i < NUMBER_OF_SPHERE_LEVELS; i++){
239     fprintf(f, " %d, ", tri_total);
240     tri_total += 3 * I->Sphere[i]->NTri;
241   }
242   fprintf(f, "\n};\n");
243 
244   fprintf(f, "static int Sphere_Tri[] = {\n");
245   for (i=0; i < NUMBER_OF_SPHERE_LEVELS; i++){
246     sp = I->Sphere[i];
247     fprintf(f, "/* Tri for Sphere #%d */\n", i);
248     c = 0;
249     for(a = 0; a < 3* sp->NTri; a++) {
250       fprintf(f, "%6d,", sp->Tri[a]);
251       c = (c + 1) % 10;
252       if(!c)
253 	fprintf(f, "\n");
254     }
255     if (c)
256       fprintf(f, "\n");
257   }
258   fprintf(f, "};\n");
259 
260   fclose(f);
261 }
262 #endif
263 
SphereInit(PyMOLGlobals * G)264 void SphereInit(PyMOLGlobals * G)
265 {
266   CSphere *I = (G->Sphere = pymol::calloc<CSphere>(1));
267 
268 #ifdef FAST_SPHERE_INIT
269   I->Array = pymol::malloc<SphereRec>(Sphere_NSpheres);
270 
271   {
272     int i;
273     for (i=0; i<Sphere_NSpheres; i++){
274       I->Array[i].area = &Sphere_area[Sphere_dot_start[i]];
275       I->Array[i].dot = &Sphere_dot[Sphere_dot_start[i]];
276       I->Array[i].StripLen = &Sphere_StripLen[Sphere_StripLen_start[i]];
277       I->Array[i].Sequence = &Sphere_Sequence[Sphere_Sequence_start[i]];
278       I->Array[i].NStrip = Sphere_NStrip[i];
279       I->Array[i].NVertTot = Sphere_NVertTot[i];
280       I->Array[i].nDot = Sphere_nDot[i];
281       I->Array[i].Tri = &Sphere_Tri[Sphere_Tri_start[i]];
282       I->Array[i].NTri = Sphere_NTri[i];
283 
284       if (i){
285 	I->Array[i].Mesh = NULL;
286 	I->Array[i].NMesh = 0;
287       } else {
288 	I->Array[i].Mesh = (int *) (void *) mesh;
289 	I->Array[i].NMesh = 30;
290       }
291       I->Sphere[i] = &I->Array[i];
292     }
293   }
294 #else
295   {
296     int i;
297     for (i=0; i<NUMBER_OF_SPHERE_LEVELS; i++){
298       I->Sphere[i] = MakeDotSphere(G, i);
299     }
300     SphereDumpAll(I);
301   }
302 #endif
303 
304 }
305 
306 #ifndef FAST_SPHERE_INIT
SpherePurge(SphereRec * I)307 static void SpherePurge(SphereRec * I)
308 {
309   /* NOTE: S->Mesh is not currently a pointer */
310   mfree(I->dot);
311   mfree(I->area);
312   mfree(I->StripLen);
313   mfree(I->Sequence);
314   mfree(I->Tri);
315   FreeP(I);
316 }
317 #endif
318 
SphereFree(PyMOLGlobals * G)319 void SphereFree(PyMOLGlobals * G)
320 {
321   CSphere *I = G->Sphere;
322 
323 #ifndef FAST_SPHERE_INIT
324   SpherePurge(I->Sphere[0]);
325   SpherePurge(I->Sphere[1]);
326   SpherePurge(I->Sphere[2]);
327   SpherePurge(I->Sphere[3]);
328   SpherePurge(I->Sphere[4]);
329 #else
330   FreeP(I->Array);
331 #endif
332   FreeP(I);
333 }
334 
335 
336 /* private stuff */
337 
338 #ifndef FAST_SPHERE_INIT
339 
340 // MAXDOT : 12, 42, 162, 642, 2562 ... :: 12 + (30 + 120 + 480 + 1920 + ... ) :: 12 + ( 30 + (30*4) + (30*4*4) + (30*4*4*4) + ... )
341 // MAXTRI : 80, 320, 1280, 5120, ... :: 20*1 + 20*4 + 20*4*4 + 20*4*4*4 + 20*4*4*4*4 ::
342 
343 //For NUMBER_OF_SPHERE_LEVELS=6
344 //#define MAXDOT 12900   // 12800
345 //#define MAXTRI 20500   // 20480
346 
347 //For NUMBER_OF_SPHERE_LEVELS=5
348 #define MAXDOT 2600      // 2562
349 #define MAXTRI 5200      // 5120
350 
351 typedef int EdgeCol[MAXDOT];    /* should move these into dynamic storage to save 3MB  mem */
352 typedef EdgeCol EdgeArray[MAXDOT];
353 
354 typedef int Triangle[3];
355 
356 typedef struct {
357 
358   float *Dot;
359   EdgeArray *EdgeRef;
360   Triangle *Tri;
361   int NDot, NTri;
362 
363 } SphereBuilderRec;
364 
MakeVertex(SphereBuilderRec * S,int d1,int d2)365 static void MakeVertex(SphereBuilderRec * S, int d1, int d2)
366 {
367   if((*S->EdgeRef)[d1][d2] < 0) {
368     average3f(S->Dot + (3 * d1), S->Dot + (3 * d2), S->Dot + (3 * S->NDot));
369     (*S->EdgeRef)[d1][d2] = S->NDot;
370     (*S->EdgeRef)[d2][d1] = S->NDot;
371     normalize3f(S->Dot + (3 * S->NDot));
372     S->NDot++;
373   }
374 }
375 
SphericalAngle(SphereBuilderRec * S,int d0,int d1,int d2)376 static float SphericalAngle(SphereBuilderRec * S, int d0, int d1, int d2)
377 {
378   Vector3f v1, v2, s1, s2;
379 
380   /* map vector onto surface of sphere and measure angle */
381   subtract3f(S->Dot + (3 * d1), S->Dot + (3 * d0), v1);
382   subtract3f(S->Dot + (3 * d2), S->Dot + (3 * d0), v2);
383 
384   remove_component3f(v1, S->Dot + (3 * d0), s1);
385   remove_component3f(v2, S->Dot + (3 * d0), s2);
386   return (get_angle3f(s1, s2));
387 
388 }
389 
MakeDotSphere(PyMOLGlobals * G,int level)390 static SphereRec *MakeDotSphere(PyMOLGlobals * G, int level)
391 {
392   SphereRec *result;
393   int *TriFlag;
394   int a, b, c, h, k, l, curTri, n, it;
395   float area, sumArea = 0.0;
396   int nStrip, *q, *s;
397   int nVertTot;
398   int flag;
399   float vt1[3], vt2[3], vt[3];
400   SphereBuilderRec SBuild, *S;
401   S = &SBuild;
402 
403   S->Dot = pymol::malloc<float>(3 * MAXDOT);
404   ErrChkPtr(G, S->Dot);
405   S->EdgeRef = pymol::malloc<EdgeArray>(1);
406   ErrChkPtr(G, S->EdgeRef);
407   S->Tri = pymol::malloc<Triangle>(MAXTRI);
408   ErrChkPtr(G, S->Tri);
409   TriFlag = pymol::malloc<int>(MAXTRI);
410   ErrChkPtr(G, TriFlag);
411 
412   S->NDot = 12;
413   for(a = 0; a < S->NDot; a++) {
414     for(c = 0; c < 3; c++)
415       S->Dot[3 * a + c] = start_points[a][c];
416     normalize3f(S->Dot + (3 * a));
417   }
418 
419   S->NTri = 20;
420   for(a = 0; a < S->NTri; a++)
421     for(c = 0; c < 3; c++)
422       S->Tri[a][c] = icosahedron[a][c];
423 
424   for(a = 0; a < MAXDOT; a++)
425     for(b = 0; b < MAXDOT; b++)
426       (*S->EdgeRef)[a][b] = -1;
427 
428   if(level > (NUMBER_OF_SPHERE_LEVELS-1))
429     level = (NUMBER_OF_SPHERE_LEVELS-1);
430 
431   for(c = 0; c < level; c++) {
432     /* create new vertices */
433     for(a = 0; a < S->NTri; a++) {
434       MakeVertex(S, S->Tri[a][0], S->Tri[a][1]);
435       MakeVertex(S, S->Tri[a][1], S->Tri[a][2]);
436       MakeVertex(S, S->Tri[a][0], S->Tri[a][2]);
437     }
438     /* create new triangles */
439     curTri = S->NTri;
440     for(a = 0; a < curTri; a++) {
441       h = S->Tri[a][0];
442       k = S->Tri[a][1];
443       l = S->Tri[a][2];
444 
445       S->Tri[a][0] = h;
446       S->Tri[a][1] = (*S->EdgeRef)[h][k];
447       S->Tri[a][2] = (*S->EdgeRef)[h][l];
448 
449       S->Tri[S->NTri][0] = k;
450       S->Tri[S->NTri][1] = (*S->EdgeRef)[k][h];
451       S->Tri[S->NTri][2] = (*S->EdgeRef)[k][l];
452       S->NTri++;
453 
454       S->Tri[S->NTri][0] = l;
455       S->Tri[S->NTri][1] = (*S->EdgeRef)[l][h];
456       S->Tri[S->NTri][2] = (*S->EdgeRef)[l][k];
457       S->NTri++;
458 
459       S->Tri[S->NTri][0] = (*S->EdgeRef)[h][k];
460       S->Tri[S->NTri][1] = (*S->EdgeRef)[k][l];
461       S->Tri[S->NTri][2] = (*S->EdgeRef)[l][h];
462       S->NTri++;
463     }
464     //    printf( "MakeDotSphere: Level: %i  S->NTri: %i\n",c, S->NTri);
465   }
466   //  printf(" MakeDotSphere: NDot %i S->NTri %i\n",S->NDot,S->NTri);
467   result = pymol::malloc<SphereRec>(1);
468   ErrChkPtr(G, result);
469   result->dot = pymol::malloc<Vector3f>(S->NDot);
470   ErrChkPtr(G, result->dot);
471   result->area = pymol::malloc<float>(S->NDot);
472   ErrChkPtr(G, result->area);
473   result->StripLen = pymol::malloc<int>(S->NTri * 3);
474   ErrChkPtr(G, result->StripLen);
475   result->Sequence = pymol::malloc<int>(S->NTri * 3);
476   ErrChkPtr(G, result->Sequence);
477 
478   for(a = 0; a < S->NDot; a++) {
479     for(c = 0; c < 3; c++)
480       result->dot[a][c] = *(S->Dot + (3 * a + c));
481     result->area[a] = 0.0;
482   }
483 
484   /* fix normals so that v1-v0 x v2-v0 is the correct normal */
485 
486   for(a = 0; a < S->NTri; a++) {
487     subtract3f(result->dot[S->Tri[a][1]], result->dot[S->Tri[a][0]], vt1);
488     subtract3f(result->dot[S->Tri[a][2]], result->dot[S->Tri[a][0]], vt2);
489     cross_product3f(vt1, vt2, vt);
490     if(dot_product3f(vt, result->dot[S->Tri[a][0]]) < 0.0) {    /* if wrong, then interchange */
491       it = S->Tri[a][2];
492       S->Tri[a][2] = S->Tri[a][1];
493       S->Tri[a][1] = it;
494     }
495   }
496 
497   for(a = 0; a < S->NTri; a++) {
498     area = (float) (SphericalAngle(S, S->Tri[a][0], S->Tri[a][1], S->Tri[a][2]) +
499                     SphericalAngle(S, S->Tri[a][1], S->Tri[a][0], S->Tri[a][2]) +
500                     SphericalAngle(S, S->Tri[a][2], S->Tri[a][0], S->Tri[a][1]) - cPI);
501     /* multiply by r^2 to get area */
502     sumArea += area;
503     area /= 3.0;
504     result->area[S->Tri[a][0]] += area;
505     result->area[S->Tri[a][1]] += area;
506     result->area[S->Tri[a][2]] += area;
507   }
508 
509   if(fabs(sumArea - (4 * cPI)) > 0.001) {
510     printf(" MakeDotSphere: sumArea: %8.6f which is %8.6f Pi\n", sumArea, sumArea / cPI);
511     ErrFatal(G, "MakeDotSphere", "Area of sphere does not sum to 4*pi!\n");
512   }
513 
514   for(a = 0; a < S->NTri; a++)
515     TriFlag[a] = false;
516 
517   nStrip = 0;
518   nVertTot = 0;
519   s = result->StripLen;
520   q = result->Sequence;
521 
522   /* tesselate the sphere in a semi-efficient fashion...this could definitely be improved */
523 
524   flag = true;
525   while(flag) {
526     flag = false;
527     a = 0;
528     while(a < S->NTri) {
529       if(!TriFlag[a]) {
530         flag = true;
531 
532         TriFlag[a] = true;
533         *(q++) = S->Tri[a][0];
534         *(q++) = S->Tri[a][1];
535         *(q++) = S->Tri[a][2];
536         n = 3;
537 
538         b = 0;
539         while(b < S->NTri) {
540           if(!TriFlag[b]) {
541             if(((S->Tri[b][0] == q[-2]) && (S->Tri[b][1] == q[-1])) ||
542                ((S->Tri[b][0] == q[-1]) && (S->Tri[b][1] == q[-2]))) {
543               *(q++) = S->Tri[b][2];
544               TriFlag[b] = true;
545               b = 0;
546               n++;
547             } else if(((S->Tri[b][0] == q[-2]) && (S->Tri[b][2] == q[-1])) ||
548                       ((S->Tri[b][0] == q[-1]) && (S->Tri[b][2] == q[-2]))) {
549               *(q++) = S->Tri[b][1];
550               TriFlag[b] = true;
551               b = 0;
552               n++;
553             } else if(((S->Tri[b][2] == q[-2]) && (S->Tri[b][1] == q[-1])) ||
554                       ((S->Tri[b][2] == q[-1]) && (S->Tri[b][1] == q[-2]))) {
555               *(q++) = S->Tri[b][0];
556               TriFlag[b] = true;
557               b = 0;
558               n++;
559             }
560           }
561           b++;
562         }
563         if(n == 3) {
564           q[-3] = S->Tri[a][1];
565           q[-2] = S->Tri[a][2];
566           q[-1] = S->Tri[a][0];
567 
568           b = 0;
569           while(b < S->NTri) {
570             if(!TriFlag[b]) {
571               if(((S->Tri[b][0] == q[-2]) && (S->Tri[b][1] == q[-1])) ||
572                  ((S->Tri[b][0] == q[-1]) && (S->Tri[b][1] == q[-2]))) {
573                 *(q++) = S->Tri[b][2];
574                 TriFlag[b] = true;
575                 b = 0;
576                 n++;
577               } else if(((S->Tri[b][0] == q[-2]) && (S->Tri[b][2] == q[-1])) ||
578                         ((S->Tri[b][0] == q[-1]) && (S->Tri[b][2] == q[-2]))) {
579                 *(q++) = S->Tri[b][1];
580                 TriFlag[b] = true;
581                 b = 0;
582                 n++;
583               } else if(((S->Tri[b][2] == q[-2]) && (S->Tri[b][1] == q[-1])) ||
584                         ((S->Tri[b][2] == q[-1]) && (S->Tri[b][1] == q[-2]))) {
585                 *(q++) = S->Tri[b][0];
586                 TriFlag[b] = true;
587                 b = 0;
588                 n++;
589               }
590             }
591             b++;
592           }
593         }
594         if(n == 3) {
595           q[-3] = S->Tri[a][2];
596           q[-2] = S->Tri[a][0];
597           q[-1] = S->Tri[a][1];
598           b = 0;
599           while(b < S->NTri) {
600             if(!TriFlag[b]) {
601               if(((S->Tri[b][0] == q[-2]) && (S->Tri[b][1] == q[-1])) ||
602                  ((S->Tri[b][0] == q[-1]) && (S->Tri[b][1] == q[-2]))) {
603                 *(q++) = S->Tri[b][2];
604                 TriFlag[b] = true;
605                 b = 0;
606                 n++;
607               } else if(((S->Tri[b][0] == q[-2]) && (S->Tri[b][2] == q[-1])) ||
608                         ((S->Tri[b][0] == q[-1]) && (S->Tri[b][2] == q[-2]))) {
609                 *(q++) = S->Tri[b][1];
610                 TriFlag[b] = true;
611                 b = 0;
612                 n++;
613               } else if(((S->Tri[b][2] == q[-2]) && (S->Tri[b][1] == q[-1])) ||
614                         ((S->Tri[b][2] == q[-1]) && (S->Tri[b][1] == q[-2]))) {
615                 *(q++) = S->Tri[b][0];
616                 TriFlag[b] = true;
617                 b = 0;
618                 n++;
619               }
620             }
621             b++;
622           }
623         }
624         *(s++) = n;
625         nVertTot += n;
626         nStrip++;
627       }
628       a++;
629     }
630   }
631   mfree(S->Dot);
632   mfree(S->EdgeRef);
633   mfree(TriFlag);
634   result->Tri = (int *) S->Tri;
635   result->Tri = pymol::realloc(result->Tri, S->NTri * 3);
636   result->NTri = S->NTri;
637   result->StripLen = pymol::realloc(result->StripLen, nStrip);
638   result->Sequence = pymol::realloc(result->Sequence, nVertTot);
639   result->dot = pymol::realloc(result->dot, S->NDot);
640   result->area = pymol::realloc(result->area, S->NDot);
641   result->nDot = S->NDot;
642   result->NStrip = nStrip;
643   result->NVertTot = nVertTot;
644   result->Mesh = NULL;
645   result->NMesh = 0;
646   if(!level) {                  /* provide mesh for S->Sphere[0] only...rest, to do. */
647     result->Mesh = (int *) mesh;
648     result->NMesh = 30;
649   }
650   /*
651      q=result->Sequence;
652      for(a=0;a<result->NStrip;a++)
653      {
654      printf("%d:",result->StripLen[a]);
655      for(b=0;b<result->StripLen[a];b++)
656      {
657      printf("%d ",*(q++));
658      }
659      printf("\n");
660      }
661    */
662 
663   return (result);
664 }
665 
666 #endif
667 
SphereRender(PyMOLGlobals * G,int level,const float * centroid,const float * color,float alpha,float radius)668 void SphereRender(PyMOLGlobals * G, int level, const float *centroid, const float *color, float alpha, float radius){
669 #ifndef PURE_OPENGL_ES_2
670   SphereRec *sp = G->Sphere->Sphere[level];
671   int a, cc;
672   int *q = sp->Sequence;
673   float pt[3];
674   if (color)
675     glColor4f(color[0], color[1], color[2], alpha);
676   for(a = 0; a < sp->NStrip; a++) {
677     glBegin(GL_TRIANGLE_STRIP);
678     cc = sp->StripLen[a];
679     while(cc--) {
680       glNormal3fv(sp->dot[*q]);
681       mult3f(sp->dot[*q], radius, pt);
682       add3f(centroid, pt, pt);
683       glVertex3fv(pt);
684       q++;
685     }
686     glEnd();
687   }
688 #endif
689 }
690 
GetSpheroidSphereRec(PyMOLGlobals * G)691 SphereRec* GetSpheroidSphereRec(PyMOLGlobals* G)
692 {
693   return G->Sphere->Sphere[2];
694 }
695