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