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"RepAngle.h"
25 #include"Color.h"
26 #include"Scene.h"
27 #include"main.h"
28 #include"Vector.h"
29 #include"Setting.h"
30 #include"PyMOLObject.h"
31 #include"ShaderMgr.h"
32 #include"CGO.h"
33 #include"CoordSet.h"
34 
35 typedef struct RepAngle {
36   Rep R;
37   float *V;
38   int N;
39   CObject *Obj;
40   DistSet *ds;
41   float linewidth, radius;
42   CGO *shaderCGO;
43 } RepAngle;
44 
45 #include"ObjectDist.h"
46 
47 static
RepAngleFree(RepAngle * I)48 void RepAngleFree(RepAngle * I)
49 {
50   if (I->shaderCGO){
51     CGOFree(I->shaderCGO);
52     I->shaderCGO = 0;
53   }
54   VLAFreeP(I->V);
55   RepPurge(&I->R);
56   OOFreeP(I);
57 }
58 
RepAngleCGOGenerate(RepAngle * I,RenderInfo * info)59 static int RepAngleCGOGenerate(RepAngle * I, RenderInfo * info)
60 {
61   PyMOLGlobals *G = I->R.G;
62   float *v = I->V;
63   int c = I->N;
64   float line_width;
65   int ok = true;
66   CGO *convertcgo = NULL;
67   int dash_as_cylinders = SettingGetGlobal_b(G, cSetting_render_as_cylinders) && SettingGetGlobal_b(G, cSetting_dash_as_cylinders);
68   int color =
69     SettingGet_color(G, NULL, I->ds->Obj->Setting, cSetting_angle_color);
70   I->linewidth = line_width =
71     SettingGet_f(G, NULL, I->ds->Obj->Setting, cSetting_dash_width);
72   I->radius =
73     SettingGet_f(G, NULL, I->ds->Obj->Setting, cSetting_dash_radius);
74   line_width = SceneGetDynamicLineWidth(info, line_width);
75   ok &= CGOSpecial(I->shaderCGO, LINEWIDTH_DYNAMIC_WITH_SCALE_DASH);
76   if (ok)
77     ok &= CGOResetNormal(I->shaderCGO, true);
78   if (ok){
79     if(color >= 0){
80       ok &= CGOColorv(I->shaderCGO, ColorGet(G, color));
81     } else if (I->Obj && I->Obj->Color >= 0){
82       ok &= CGOColorv(I->shaderCGO, ColorGet(G, I->Obj->Color));
83     }
84   }
85   v = I->V;
86   c = I->N;
87   if (dash_as_cylinders){
88     float *origin = NULL, axis[3];
89     while(ok && c > 0) {
90       origin = v;
91       v += 3;
92       axis[0] = v[0] - origin[0];
93       axis[1] = v[1] - origin[1];
94       axis[2] = v[2] - origin[2];
95       v += 3;
96       ok &= (bool)I->shaderCGO->add<cgo::draw::shadercylinder>(origin, axis, 1.f, 15);
97       c -= 2;
98     }
99   } else if (ok) {
100     ok &= CGOBegin(I->shaderCGO, GL_LINES);
101     while(ok && c > 0) {
102       ok &= CGOVertexv(I->shaderCGO, v);
103       v += 3;
104       if (ok)
105 	ok &= CGOVertexv(I->shaderCGO, v);
106       v += 3;
107       c -= 2;
108     }
109     if (ok)
110       ok &= CGOEnd(I->shaderCGO);
111   }
112   if (ok)
113     ok &= CGOStop(I->shaderCGO);
114   if (ok)
115     convertcgo = CGOCombineBeginEnd(I->shaderCGO, 0);
116   CHECKOK(ok, convertcgo);
117   CGOFree(I->shaderCGO);
118   I->shaderCGO = convertcgo;
119   convertcgo = NULL;
120   if (ok){
121     if (dash_as_cylinders){
122       CGO *tmpCGO = CGONew(G);
123       if (ok) ok &= CGOEnable(tmpCGO, GL_CYLINDER_SHADER);
124       if (ok) ok &= CGOSpecial(tmpCGO, CYLINDER_WIDTH_FOR_DISTANCES);
125       convertcgo = CGOConvertShaderCylindersToCylinderShader(I->shaderCGO, tmpCGO);
126       if (ok) ok &= CGOEnable(tmpCGO, GL_DASH_TRANSPARENCY_DEPTH_TEST);
127       if (ok) ok &= CGOAppendNoStop(tmpCGO, convertcgo);
128       if (ok) ok &= CGODisable(tmpCGO, GL_DASH_TRANSPARENCY_DEPTH_TEST);
129       if (ok) ok &= CGODisable(tmpCGO, GL_CYLINDER_SHADER);
130       if (ok) ok &= CGOStop(tmpCGO);
131       CGOFreeWithoutVBOs(convertcgo);
132       convertcgo = tmpCGO;
133     } else {
134       CGO *tmpCGO = CGONew(G);
135       if (ok) ok &= CGOEnable(tmpCGO, GL_DEFAULT_SHADER);
136       if (ok) ok &= CGODisable(tmpCGO, CGO_GL_LIGHTING);
137       convertcgo = CGOOptimizeToVBONotIndexedNoShader(I->shaderCGO, 0);
138       if (ok) ok &= CGOEnable(tmpCGO, GL_DASH_TRANSPARENCY_DEPTH_TEST);
139       if (ok) ok &= CGOAppendNoStop(tmpCGO, convertcgo);
140       if (ok) ok &= CGODisable(tmpCGO, GL_DASH_TRANSPARENCY_DEPTH_TEST);
141       if (ok) ok &= CGODisable(tmpCGO, GL_DEFAULT_SHADER);
142       if (ok) ok &= CGOStop(tmpCGO);
143       CGOFreeWithoutVBOs(convertcgo);
144       convertcgo = tmpCGO;
145     }
146     convertcgo->use_shader = true;
147   }
148   CHECKOK(ok, convertcgo);
149   if (convertcgo){
150     CGOFree(I->shaderCGO);
151     I->shaderCGO = convertcgo;
152     convertcgo = NULL;
153   }
154   return ok;
155 }
156 
RepAngleRenderImmediate(RepAngle * I,RenderInfo * info,int color,short dash_transparency_enabled,float dash_transparency)157 static void RepAngleRenderImmediate(RepAngle * I, RenderInfo * info, int color,
158                                     short dash_transparency_enabled, float dash_transparency)
159 {
160 #ifndef PURE_OPENGL_ES_2
161   PyMOLGlobals *G = I->R.G;
162   float *v = I->V;
163   int c = I->N;
164   float line_width;
165   bool t_mode_3 =
166     SettingGet_i(G, NULL, I->ds->Obj->Setting, cSetting_transparency_mode) == 3;
167   line_width =
168     SettingGet_f(G, NULL, I->ds->Obj->Setting, cSetting_dash_width);
169   line_width = SceneGetDynamicLineWidth(info, line_width);
170 
171   if(info->width_scale_flag) {
172     glLineWidth(line_width * info->width_scale);
173   } else {
174     glLineWidth(line_width);
175   }
176   SceneResetNormal(G, true);
177 
178   if (dash_transparency_enabled){
179     const float *col = ColorGet(G, color);
180     glColor4f(col[0], col[1], col[2], 1.f-dash_transparency);
181   } else {
182     glColor3fv(ColorGet(G, color));
183   }
184   if (dash_transparency_enabled && !t_mode_3)
185     glDisable(GL_DEPTH_TEST);
186   if(!info->line_lighting)
187     glDisable(GL_LIGHTING);
188   glBegin(GL_LINES);
189   while(c > 0) {
190     glVertex3fv(v);
191     v += 3;
192     glVertex3fv(v);
193     v += 3;
194     c -= 2;
195   }
196   glEnd();
197   glEnable(GL_LIGHTING);
198   if (dash_transparency_enabled && !t_mode_3)
199     glEnable(GL_DEPTH_TEST);
200 #endif
201 }
202 
RepAngleRender(RepAngle * I,RenderInfo * info)203 static void RepAngleRender(RepAngle * I, RenderInfo * info)
204 {
205   CRay *ray = info->ray;
206   auto pick = info->pick;
207   PyMOLGlobals *G = I->R.G;
208   float *v = I->V;
209   int c = I->N;
210   const float *vc;
211   int round_ends;
212   float line_width;
213   int ok = true;
214   float dash_transparency;
215   short dash_transparency_enabled;
216   int color =
217     SettingGet_color(G, NULL, I->ds->Obj->Setting, cSetting_angle_color);
218   if(color < 0)
219     color = I->Obj->Color;
220   I->linewidth = line_width =
221     SettingGet_f(G, NULL, I->ds->Obj->Setting, cSetting_dash_width);
222   I->radius =
223     SettingGet_f(G, NULL, I->ds->Obj->Setting, cSetting_dash_radius);
224   round_ends =
225     SettingGet_b(G, NULL, I->ds->Obj->Setting, cSetting_dash_round_ends);
226   line_width = SceneGetDynamicLineWidth(info, line_width);
227   dash_transparency =
228     SettingGet_f(G, NULL, I->ds->Obj->Setting, cSetting_dash_transparency);
229   dash_transparency = (dash_transparency < 0.f ? 0.f : (dash_transparency > 1.f ? 1.f : dash_transparency));
230   dash_transparency_enabled = (dash_transparency > 0.f);
231 
232   if (!(ray || pick) && (!info->pass || (info->pass > 0) == dash_transparency_enabled))
233     return;
234 
235   if(ray) {
236 
237     float radius;
238     if (dash_transparency_enabled){
239       ray->transparentf(dash_transparency);
240     }
241 
242     if(I->radius == 0.0F) {
243       radius = ray->PixelRadius * line_width / 2.0F;
244     } else {
245       radius = I->radius;
246     }
247 
248     vc = ColorGet(G, color);
249     v = I->V;
250     c = I->N;
251 
252     while(ok && c > 0) {
253       /*      printf("%8.3f %8.3f %8.3f   %8.3f %8.3f %8.3f \n",v[3],v[4],v[5],v[6],v[7],v[8]); */
254       if(round_ends) {
255         ok &= ray->sausage3fv(v, v + 3, radius, vc, vc);
256       } else {
257         ok &= ray->customCylinder3fv(v, v + 3, radius, vc, vc, cCylCapFlat, cCylCapFlat);
258       }
259       v += 6;
260       c -= 2;
261     }
262 
263   } else if(G->HaveGUI && G->ValidContext) {
264     if(pick) {
265     } else {
266       short use_shader, generate_shader_cgo = 0;
267 
268       use_shader = SettingGetGlobal_b(G, cSetting_dash_use_shader) &
269 	           SettingGetGlobal_b(G, cSetting_use_shaders);
270 
271       if (!use_shader && I->shaderCGO){
272 	CGOFree(I->shaderCGO);
273 	I->shaderCGO = 0;
274       }
275       if (use_shader){
276 	if (!I->shaderCGO){
277 	  I->shaderCGO = CGONew(G);
278 	  CHECKOK(ok, I->shaderCGO);
279 	  if (ok)
280 	    I->shaderCGO->use_shader = true;
281 	  generate_shader_cgo = 1;
282 	  if (dash_transparency_enabled){
283 	    CGOAlpha(I->shaderCGO, 1.f-dash_transparency);
284           }
285 	  ok &= RepAngleCGOGenerate(I, info);
286    	} else {
287 	  CGORenderGL(I->shaderCGO, NULL, NULL, NULL, info, &I->R);
288 	  return;
289 	}
290       }
291 
292       if (!generate_shader_cgo) {
293 	RepAngleRenderImmediate(I, info, color, dash_transparency_enabled, dash_transparency);
294       } else {
295 	CGORenderGL(I->shaderCGO, NULL, NULL, NULL, info, &I->R);
296       }
297     }
298   }
299   if (!ok){
300     CGOFree(I->shaderCGO);
301     I->ds->Rep[cRepAngle] = NULL;
302     RepAngleFree(I);
303   }
304 }
305 
RepAngleNew(DistSet * ds,int state)306 Rep *RepAngleNew(DistSet * ds, int state)
307 {
308   PyMOLGlobals *G = ds->G;
309   int a;
310   int n = 0;
311   float *v, *v1, *v2, *v3, *v4, d1[3], d2[3], d3[3], n1[3], n3[3], l1, l2, x[3], y[3];
312   float length, radius, angle, pos, phase;
313   float dash_len, dash_gap, dash_sum;
314   int ok = true;
315   float dash_transparency;
316   dash_transparency =
317     SettingGet_f(G, NULL, ds->Obj->Setting, cSetting_dash_transparency);
318   dash_transparency = (dash_transparency < 0.f ? 0.f : (dash_transparency > 1.f ? 1.f : dash_transparency));
319 
320   OOAlloc(G, RepAngle);
321   CHECKOK(ok, I);
322 
323   PRINTFD(G, FB_RepAngle)
324     "RepAngleNew: entered.\n" ENDFD;
325   if(!ok || !ds->NAngleIndex) {
326     OOFreeP(I);
327     return (NULL);
328   }
329 
330   RepInit(G, &I->R);
331 
332   I->R.fRender = (void (*)(struct Rep *, RenderInfo * info)) RepAngleRender;
333   I->R.fFree = (void (*)(struct Rep *)) RepAngleFree;
334   I->R.fRecolor = NULL;
335   I->R.obj = ds->Obj;
336 
337   dash_len = SettingGet_f(G, NULL, ds->Obj->Setting, cSetting_dash_length);
338   dash_gap = SettingGet_f(G, NULL, ds->Obj->Setting, cSetting_dash_gap);
339   dash_sum = dash_len + dash_gap;
340   if(dash_sum < R_SMALL4)
341     dash_sum = 0.1F;
342 
343   I->shaderCGO = 0;
344   I->N = 0;
345   I->V = NULL;
346   I->R.P = NULL;
347   I->Obj = (CObject *) ds->Obj;
348   I->ds = ds;
349 
350   n = 0;
351   if(ds->NAngleIndex) {
352     I->V = VLAlloc(float, ds->NAngleIndex * 10);
353     CHECKOK(ok, I->V);
354     for(a = 0; ok && a < ds->NAngleIndex; a = a + 5) {
355       v1 = ds->AngleCoord + 3 * a;
356       v2 = ds->AngleCoord + 3 * (a + 1);
357       v3 = ds->AngleCoord + 3 * (a + 2);
358       v4 = ds->AngleCoord + 3 * (a + 3);
359       subtract3f(v1, v2, d1);
360       subtract3f(v3, v2, d2);
361 
362       l1 = (float) length3f(d1);
363       l2 = (float) length3f(d2);
364 
365       if(l1 > l2)
366         radius = l2;
367       else
368         radius = l1;
369       radius *= SettingGet_f(G, NULL, ds->Obj->Setting, cSetting_angle_size);
370 
371       angle = get_angle3f(d1, d2);
372 
373       normalize23f(d1, n1);
374 
375       remove_component3f(d2, n1, d3);
376 
377       if(length3f(d3) < R_SMALL8) {
378         d3[0] = 1.0F;
379         d3[1] = 0.0F;
380         d3[2] = 0.0F;
381       } else {
382         normalize23f(d3, n3);
383       }
384 
385       scale3f(n1, radius, x);
386       scale3f(n3, radius, y);
387 
388       if(v4[0] != 0.0F) {       /* line 1 flag */
389         VLACheck(I->V, float, (n * 3) + 5);
390 	CHECKOK(ok, I->V);
391 	if (ok){
392 	  v = I->V + n * 3;
393 	  copy3f(v1, v);
394 	  v += 3;
395 	  copy3f(v2, v);
396 	  n += 2;
397 	}
398       }
399 
400       if(ok && v4[1] != 0.0F) {       /* line 2 flag */
401 	VLACheck(I->V, float, (n * 3) + 5);
402 	CHECKOK(ok, I->V);
403 	if (ok){
404 	  v = I->V + n * 3;
405 	  copy3f(v3, v);
406 	  v += 3;
407 	  copy3f(v2, v);
408 	  n += 2;
409 	}
410       }
411       if (!ok)
412 	break;
413       /* now we have a relevant orthogonal axes */
414 
415       length = (float) (angle * radius * 2);
416 
417       /* figure out dash/gap phasing that will lead to nicely spaced dashes and gaps */
418 
419       phase = dash_sum - (float) fmod(length / 2 + (dash_gap / 2), dash_sum);
420       pos = -phase;
421 
422       if(length > R_SMALL4) {
423 
424         float vx[3], vy[3];
425         float cur_angle;
426         float cons_pos1, cons_pos2;
427 
428         while(ok && pos < length) {
429 
430           VLACheck(I->V, float, (n * 3) + 5);
431 	  CHECKOK(ok, I->V);
432 
433 	  if (!ok)
434 	    break;
435           cons_pos1 = pos;
436           if(cons_pos1 < 0.0F)
437             cons_pos1 = 0.0F;
438           cons_pos2 = pos + dash_len;
439           if(cons_pos2 > length)
440             cons_pos2 = length;
441 
442           if(cons_pos1 < cons_pos2) {
443             cur_angle = angle * cons_pos1 / length;
444 
445             v = I->V + n * 3;
446             scale3f(x, (float) cos(cur_angle), vx);
447             scale3f(y, (float) sin(cur_angle), vy);
448             add3f(vx, vy, v);
449             add3f(v2, v, v);
450 
451             cur_angle = angle * cons_pos2 / length;
452 
453             v += 3;
454             scale3f(x, (float) cos(cur_angle), vx);
455             scale3f(y, (float) sin(cur_angle), vy);
456             add3f(vx, vy, v);
457             add3f(v2, v, v);
458 
459             n += 2;
460           }
461           pos += dash_sum;
462         }
463       }
464     }
465     if (ok)
466       VLASize(I->V, float, n * 3);
467     CHECKOK(ok, I->V);
468     if (ok)
469       I->N = n;
470   }
471   if (!ok){
472     RepAngleFree(I);
473     I = NULL;
474   }
475   return (Rep *) I;
476 }
477