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"Feedback.h"
24 #include"CGO.h"
25 #include"Base.h"
26 #include"OOMac.h"
27 #include"Setting.h"
28 #include"Sphere.h"
29 #include"PConv.h"
30 #include"GadgetSet.h"
31 #include"VFont.h"
32 #include"P.h"
33 #include"PyMOLGlobals.h"
34 #include"Ray.h"
35 #include"Util.h"
36 #include"Scene.h"
37 #include"ScenePicking.h"
38 #include"Matrix.h"
39 #include"ShaderMgr.h"
40 #include"CoordSet.h"
41 #include"Rep.h"
42 #include"Vector.h"
43 #include"ObjectGadgetRamp.h"
44 #include"Triangle.h"
45 #include "Picking.h"
46
47 #include "pymol/algorithm.h"
48
49 #if defined(_PYMOL_IOS) && !defined(_WEBGL)
50 #define ALIGN_VBOS_TO_4_BYTE_ARRAYS
51 #define VAR_FOR_NORMAL plc
52 #define VAR_FOR_NORMAL_CNT_PLUS + (cnt / 3)
53 #define VERTEX_NORMAL_SIZE 4
54 #else
55 #define VAR_FOR_NORMAL pl
56 #define VERTEX_NORMAL_SIZE 3
57 #define VAR_FOR_NORMAL_CNT_PLUS
58 #endif
59
60 #define VALUES_PER_IMPOSTER_SPACE_COORD 1
61
62 #if defined(PURE_OPENGL_ES_2)
63 #define VERTICES_PER_SPHERE 6
64 #else
65 #define VERTICES_PER_SPHERE 4
66 #endif
67
68 #if defined(_PYMOL_IOS) && !defined(_WEBGL)
69 #define NUM_VERTICES_PER_CYLINDER 4
70 #define NUM_TOTAL_VERTICES_PER_CYLINDER 6
71 #else
72 #define NUM_VERTICES_PER_CYLINDER 8
73 #define NUM_TOTAL_VERTICES_PER_CYLINDER 36
74 #endif
75
76 #ifdef PURE_OPENGL_ES_2
77 #define glVertexAttrib4ubv(loc, data) glVertexAttrib4f(loc, \
78 (data)[0] / 255.f, (data)[1] / 255.f, (data)[2] / 255.f, (data)[3] / 255.f);
79 #endif
80
81 #include <cassert>
82 #include <iostream>
83 #include <algorithm>
84
85 using namespace std;
86
87 #define MAX_INDICES_FOR_IOS 65536
88
89 const float g_ones4f[4] = {1.f, 1.f, 1.f, 1.f};
90
91 template <typename T>
CLAMPVALUE(T val,T minimum,T maximum)92 inline T CLAMPVALUE(T val, T minimum, T maximum) {
93 return
94 (val < minimum) ? minimum :
95 (val > maximum) ? maximum : val;
96 }
97
98 #if defined(_PYMOL_IOS) && !defined(_WEBGL)
99 extern "C" void firePyMOLLimitationWarning();
100 #define CHECK_GL_ERROR_OK(printstr) \
101 if ((err = glGetError())!=0 || I->G->Interrupt != 0){ \
102 if (err) \
103 PRINTFB(I->G, FB_CGO, FB_Errors) printstr, err ENDFB(I->G); \
104 }
105 #else
106 #define CHECK_GL_ERROR_OK(printstr) \
107 if ((err = glGetError()) != 0){ \
108 PRINTFB(I->G, FB_CGO, FB_Errors) printstr, err ENDFB(I->G); \
109 }
110 #endif
111
112 #define WARN_UNEXPECTED_OPERATION(G, op) \
113 PRINTFB(G, FB_CGO, FB_Warnings) \
114 " %s-Warning: unexpected op=0x%x (line %d)\n", __func__, op, __LINE__ ENDFB(G)
115
116 // like g_return_val_if_fail from glib
117 #define RETURN_VAL_IF_FAIL(expr, val) \
118 { \
119 if (!(expr)) \
120 return (val); \
121 }
122
123 struct _CCGORenderer {
124 PyMOLGlobals *G;
125 RenderInfo *info;
126 Rep *rep;
127 const float *color;
128 float alpha;
129 short sphere_quality;
130 bool isPicking;
pick_pass_CCGORenderer131 unsigned pick_pass() const { return info->pick->m_pass; }
132 bool use_shader; // OpenGL 1.4+, e.g., glEnableVertexAttribArray() (on) vs. glEnableClientState() (off)
133 bool debug;
134 CSetting *set1, *set2;
135 };
136
137 static
set_current_pick_color(CGO * cgo,unsigned int idx,int bnd)138 void set_current_pick_color(
139 CGO * cgo,
140 unsigned int idx,
141 int bnd)
142 {
143 if (cgo) {
144 cgo->current_pick_color_index = idx;
145 cgo->current_pick_color_bond = bnd;
146 }
147 }
148
149 /**
150 * Assign a new pick color index for {context, index, bond} (only in the
151 * first pass) and convert that to an RGBA color for the current picking pass.
152 *
153 * @param[out] cgo Set the "current pick color" in this CGO
154 * @param[in,out] pickmgr Pick color manager
155 * @param[out] color RGBA pick color to use in this pass
156 * @param[in] context Object state identifier
157 * @param[in] index Primary index
158 * @param[in] bond Secondary index
159 */
AssignNewPickColor(CGO * cgo,PickColorManager * pickmgr,unsigned char * color,const PickContext * context,unsigned int index,int bond)160 void AssignNewPickColor(CGO* cgo, PickColorManager* pickmgr,
161 unsigned char* color, const PickContext* context, unsigned int index,
162 int bond)
163 {
164 set_current_pick_color(cgo, index, bond);
165 pickmgr->colorNext(color, context, index, bond);
166 }
167
168 static
CGOConvertDebugMode(int debug,int modeArg)169 int CGOConvertDebugMode(int debug, int modeArg){
170 int mode = modeArg;
171 if (debug==1){
172 switch (mode){
173 case GL_TRIANGLES:
174 mode = GL_LINES;
175 break;
176 case GL_TRIANGLE_STRIP:
177 mode = GL_LINE_STRIP;
178 break;
179 case GL_TRIANGLE_FAN:
180 mode = GL_LINES;
181 break;
182 }
183 } else {
184 mode = GL_POINTS;
185 }
186 return mode;
187 }
188
189
CGORendererInit(PyMOLGlobals * G)190 int CGORendererInit(PyMOLGlobals * G)
191 {
192 CCGORenderer *I = NULL;
193
194 I = (G->CGORenderer = pymol::calloc<CCGORenderer>(1));
195 if(I) {
196 I->G = G;
197 I->isPicking = false;
198 I->alpha = 1.0F;
199 return 1;
200 } else
201 return 0;
202 }
203
CGORendererFree(PyMOLGlobals * G)204 void CGORendererFree(PyMOLGlobals * G)
205 {
206 FreeP(G->CGORenderer);
207 }
208
209 int CGO_sz[] = {
210 CGO_NULL_SZ,
211 CGO_NULL_SZ,
212 CGO_BEGIN_SZ,
213 CGO_END_SZ,
214
215 CGO_VERTEX_SZ,
216 CGO_NORMAL_SZ,
217 CGO_COLOR_SZ,
218 CGO_SPHERE_SZ,
219
220 CGO_TRIANGLE_SZ,
221 fsizeof<cgo::draw::cylinder>(),
222 CGO_LINEWIDTH_SZ,
223 CGO_WIDTHSCALE_SZ,
224
225 CGO_ENABLE_SZ,
226 CGO_DISABLE_SZ,
227 fsizeof<cgo::draw::sausage>(),
228 fsizeof<cgo::draw::custom_cylinder>(),
229
230 CGO_DOTWIDTH_SZ,
231 CGO_ALPHA_TRIANGLE_SZ,
232 CGO_ELLIPSOID_SZ,
233 CGO_FONT_SZ,
234
235 CGO_FONT_SCALE_SZ,
236 CGO_FONT_VERTEX_SZ,
237 CGO_FONT_AXES_SZ,
238 CGO_CHAR_SZ,
239
240 CGO_INDENT_SZ,
241 CGO_ALPHA_SZ,
242 CGO_QUADRIC_SZ,
243 CGO_CONE_SZ,
244
245 fsizeof<cgo::draw::arrays>(),
246 CGO_NULL_SZ,
247 CGO_RESET_NORMAL_SZ,
248 CGO_PICK_COLOR_SZ,
249
250 CGO_NULL_SZ, // CGO_DRAW_BUFFERS_SZ no longer used
251 fsizeof<cgo::draw::buffers_indexed>(),
252 CGO_BOUNDING_BOX_SZ,
253 fsizeof<cgo::draw::buffers_not_indexed>(),
254 CGO_SPECIAL_SZ,
255 fsizeof<cgo::draw::cylinder_buffers>(),
256 fsizeof<cgo::draw::shadercylinder>(),
257 fsizeof<cgo::draw::shadercylinder2ndcolor>(),
258 fsizeof<cgo::draw::sphere_buffers>(),
259 CGO_ACCESSIBILITY_SZ,
260 CGO_DRAW_TEXTURE_SZ,
261 fsizeof<cgo::draw::textures>(),
262 fsizeof<cgo::draw::screen_textures>(),
263 CGO_TEX_COORD_SZ,
264 fsizeof<cgo::draw::label>(),
265 fsizeof<cgo::draw::labels>(),
266 CGO_DRAW_CONNECTOR_SZ,
267 fsizeof<cgo::draw::connectors>(),
268 CGO_DRAW_TRILINES_SZ, CGO_UNIFORM3F_SZ,
269 CGO_SPECIAL_WITH_ARG_SZ,
270 fsizeof<cgo::draw::line>(),
271 fsizeof<cgo::draw::splitline>(),
272 fsizeof<cgo::draw::custom>(),
273 fsizeof<cgo::draw::vertex_attribute_3f>(),
274 fsizeof<cgo::draw::vertex_attribute_4ub>(),
275 fsizeof<cgo::draw::vertex_attribute_1f>(),
276 fsizeof<cgo::draw::mask_attribute_if_picking>(),
277 fsizeof<cgo::draw::bind_vbo_for_picking>(),
278 CGO_VERTEX_BEGIN_LINE_STRIP_SZ, CGO_INTERPOLATED_SZ, CGO_VERTEX_CROSS_SZ,
279 fsizeof<cgo::draw::vertex_attribute_4ub_if_picking>(),
280 fsizeof<cgo::draw::custom_cylinder_alpha>(),
281 CGO_NULL_SZ
282 };
283
284 /**
285 * Get the number of elements in `CGO_sz`
286 */
CGO_sz_size()287 size_t CGO_sz_size()
288 {
289 return sizeof(CGO_sz) / sizeof(*CGO_sz);
290 }
291
292 // I think CGO rendering functions should not modify CGO's, so the
293 // data pointer should be const. Current exception: `pickcolorsset`
294 #define CGO_OP_DATA_CONST const
295 typedef CGO_OP_DATA_CONST float* const* CGO_op_data;
296 typedef void CGO_op(CCGORenderer * I, CGO_op_data);
297 typedef CGO_op *CGO_op_fn;
298
299 static float *CGO_add(CGO * I, unsigned c);
300 static float *CGO_size(CGO * I, int sz);
301 static int CGOSimpleCylinder(CGO * I, const float *v1, const float *v2, const float tube_size, const float *c1,
302 const float *c2, float a1, const float a2, const bool interp, const int cap1, const int cap2,
303 const Pickable *pickcolor2 = nullptr, const bool stick_round_nub = false);
304 template<typename CylinderT>
305 static int CGOSimpleCylinder(CGO * I, const CylinderT &cyl, const float a1, const float a2, const bool interp, const int cap1,
306 const int cap2, const Pickable *pickcolor2 = nullptr, const bool stick_round_nub = false);
307 static int CGOSimpleEllipsoid(CGO * I, const float *v, float vdw, const float *n0, const float *n1,
308 const float *n2);
309 static int CGOSimpleQuadric(CGO * I, const float *v, float vdw, const float *q);
310 static int CGOSimpleSphere(CGO * I, const float *v, float vdw, short sphere_quality);
311 static int CGOSimpleCone(CGO * I, const float *v1, const float *v2, float r1, float r2, const float *c1,
312 const float *c2, int cap1, int cap2);
313
314
315 /*
316 * Inverse function of CGOArrayFromPyListInPlace
317 *
318 * I: (input) Primitive CGO (may contain CGO_DRAW_ARRAYS)
319 *
320 * Return: All-float Python list primitive CGO
321 */
CGOArrayAsPyList(const CGO * I)322 static PyObject *CGOArrayAsPyList(const CGO * I)
323 {
324 std::vector<float> flat;
325 flat.reserve(I->c);
326
327 for (auto it = I->begin(); !it.is_stop(); ++it) {
328 auto op = it.op_code();
329 auto pc = it.data();
330 auto sz = CGO_sz[op];
331
332 flat.push_back(op);
333
334 switch (op) {
335 case CGO_BEGIN:
336 case CGO_ENABLE:
337 case CGO_DISABLE:
338 case CGO_SPECIAL:
339 // first member int
340 flat.push_back(*reinterpret_cast<const int*>(pc));
341 ++pc;
342 --sz;
343 break;
344 case CGO_DRAW_ARRAYS:
345 {
346 auto sp = reinterpret_cast<const cgo::draw::arrays*>(pc);
347 flat.push_back(sp->mode);
348 flat.push_back(sp->arraybits);
349 flat.push_back(sp->narrays); // (redundant)
350 flat.push_back(sp->nverts);
351 pc = sp->get_data();
352 sz = sp->get_data_length();
353 }
354 }
355
356 // float members
357 for(; sz; --sz) {
358 flat.push_back(*(pc++));
359 }
360 }
361
362 return PConvToPyObject(flat);
363 }
364
CGOAsPyList(CGO * I)365 PyObject *CGOAsPyList(CGO * I)
366 {
367 PyObject *result;
368 result = PyList_New(2);
369 PyObject *list = CGOArrayAsPyList(I);
370 PyList_SetItem(result, 0, PyInt_FromLong(PyList_Size(list)));
371 PyList_SetItem(result, 1, list);
372 return (result);
373 }
374
CPythonVal_PyFloat_AsDouble_From_List(void * G,PyObject * list,size_t i)375 static float CPythonVal_PyFloat_AsDouble_From_List(void * G, PyObject * list, size_t i) {
376 float out;
377 PConvPyFloatToFloat(PyList_GetItem(list, i), &out);
378 return out;
379 }
380
381 /*
382 * Inverse function of CGOArrayAsPyList
383 *
384 * list: (input) All-float Python list primitive CGO (may contain CGO_DRAW_ARRAYS)
385 * I: (output) empty CGO
386 */
CGOArrayFromPyListInPlace(PyObject * list,CGO * I)387 static int CGOArrayFromPyListInPlace(PyObject * list, CGO * I)
388 {
389 // sanity check
390 if (!list || !PyList_Check(list))
391 return false;
392
393 auto G = I->G;
394
395 #define GET_FLOAT(i) ((float) CPythonVal_PyFloat_AsDouble_From_List(I->G, list, i))
396 #define GET_INT(i) ((int) CPythonVal_PyFloat_AsDouble_From_List(I->G, list, i))
397
398 for (int i = 0, l = PyList_Size(list); i < l;) {
399 unsigned op = GET_INT(i++);
400 ok_assert(1, op < CGO_sz_size());
401 int sz = CGO_sz[op];
402 float * fdata = I->add_to_buffer(sz + 1);
403 CGO_write_int(fdata, op);
404
405 switch (op) {
406 case CGO_STOP:
407 // don't increment size for null terminator
408 I->c -= 1;
409 return true;
410 case CGO_BEGIN:
411 I->has_begin_end = true;
412 case CGO_ENABLE:
413 case CGO_DISABLE:
414 case CGO_SPECIAL:
415 // first member int
416 ok_assert(1, i < l);
417 CGO_write_int(fdata, GET_INT(i++));
418 sz--;
419 break;
420 case CGO_DRAW_ARRAYS:
421 {
422 // has abstract superclass, need to be constructed!
423 ok_assert(1, i + 3 < l);
424 auto sp = new (fdata) cgo::draw::arrays(
425 GET_INT(i),
426 GET_INT(i + 1),
427 GET_INT(i + 3));
428
429 // sanity check
430 int narrays_check = GET_INT(i + 2);
431 if (sp->narrays != narrays_check) {
432 PRINTFB(I->G, FB_CGO, FB_Warnings)
433 " CGO-Warning: narrays mismatch: %d != %d\n",
434 sp->narrays, narrays_check ENDFB(I->G);
435 }
436
437 // data
438 sz = sp->get_data_length();
439 sp->floatdata = fdata = I->allocate_in_data_heap(sz);
440
441 i += 4;
442 }
443 break;
444 }
445
446 // float members
447 for(; sz; --sz) {
448 ok_assert(1, i < l);
449 *(fdata++) = GET_FLOAT(i++);
450 }
451 }
452
453 #undef GET_FLOAT
454 #undef GET_INT
455
456 return true;
457
458 ok_except1:
459 PRINTFB(G, FB_CGO, FB_Errors) " %s-Error: Corrupt data\n", __func__ ENDFB(G);
460 return false;
461 }
462
CGONewFromPyList(PyMOLGlobals * G,PyObject * list,int version,bool shouldCombine)463 CGO *CGONewFromPyList(PyMOLGlobals * G, PyObject * list, int version, bool shouldCombine)
464 {
465 int ok = true;
466 auto I = CGONew(G);
467 if(ok)
468 ok = (list != NULL);
469 if(ok)
470 ok = PyList_Check(list);
471 /* TO ENABLE BACKWARDS COMPATIBILITY...
472 Always check ll when adding new PyList_GetItem's */
473 if((version > 0) && (version <= 86)) {
474 if(ok)
475 ok = PConvFromPyListItem(G, list, 0, I->c);
476 if(ok)
477 VLACheck(I->op, float, I->c);
478 if(ok)
479 ok = PConvPyListToFloatArrayInPlace(PyList_GetItem(list, 1), I->op, I->c);
480 } else {
481 if(ok)
482 ok = CGOArrayFromPyListInPlace(PyList_GetItem(list, 1), I);
483 }
484 if(!ok) {
485 CGOFree(I);
486 }
487 {
488 CGO *cgo = NULL;
489 if (shouldCombine && I && I->has_begin_end){
490 cgo = CGOCombineBeginEnd(I, 0);
491 CGOFree(I);
492 } else {
493 cgo = I;
494 }
495 return cgo;
496 }
497 }
498
CGO(PyMOLGlobals * G,int size)499 CGO::CGO(PyMOLGlobals* G, int size)
500 : G(G)
501 {
502 op = VLACalloc(float, size + 32);
503 cgo_shader_ub_color = SettingGet<bool>(G, cSetting_cgo_shader_ub_color);
504 cgo_shader_ub_normal = SettingGet<bool>(G, cSetting_cgo_shader_ub_normal);
505 }
506
CGOSetUseShader(CGO * I,int use_shader)507 void CGOSetUseShader(CGO *I, int use_shader){
508 I->use_shader = use_shader;
509 if (use_shader){
510 I->cgo_shader_ub_color = SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color);
511 I->cgo_shader_ub_normal = SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_normal);
512 } else {
513 I->cgo_shader_ub_color = 0;
514 I->cgo_shader_ub_normal = 0;
515 }
516 }
CGOReset(CGO * I)517 void CGOReset(CGO * I)
518 {
519 I->c = 0;
520 I->z_flag = false;
521 I->alpha = 1.f;
522 I->has_begin_end = false;
523 I->has_draw_buffers = false;
524 I->has_draw_cylinder_buffers = false;
525 I->normal[0] = 0.f; I->normal[1] = 0.f; I->normal[2] = 1.f;
526 I->color[0] = 0.f; I->color[1] = 0.f; I->color[2] = 1.f;
527 I->pickColor[0] = 0; I->pickColor[1] = 0; I->pickColor[2] = 0; I->pickColor[3] = 255;
528 I->current_accessibility = 1.f;
529 }
530
CGOFree(CGO * & I,bool withVBOs)531 void CGOFree(CGO * &I, bool withVBOs)
532 {
533 if(I) {
534 if (!withVBOs) {
535 I->has_draw_buffers = false;
536 }
537 DeleteP(I);
538 }
539 }
540
~CGO()541 CGO::~CGO()
542 {
543 if (has_draw_buffers) {
544 CGOFreeVBOs(this);
545 }
546 FreeP(i_start);
547 VLAFreeP(op);
548 }
549
CGO_add(CGO * I,unsigned c)550 static float *CGO_add(CGO * I, unsigned c)
551 {
552 float *at;
553 VLACheck(I->op, float, I->c + c);
554 if (!I->op){
555 return NULL;
556 }
557 at = I->op + I->c;
558 I->c += c;
559 return (at);
560 }
561
CGO_size(CGO * I,int sz)562 static float *CGO_size(CGO * I, int sz)
563 {
564 float *at;
565 VLASize(I->op, float, sz);
566 if (!I->op){
567 return NULL;
568 }
569 at = I->op + I->c;
570 I->c = sz;
571 return (at);
572 }
573
574
575 /*===== Object Creation Routines =======*/
576
CGOFromFloatArray(CGO * I,const float * src,int len)577 int CGOFromFloatArray(CGO * I, const float *src, int len)
578 {
579 int iarg;
580 int ok;
581 int all_ok = true;
582 int bad_entry = 0;
583 int sz;
584 int a;
585 int cc = 0;
586 float val;
587 float *pc, *save_pc, *tf;
588 VLACheck(I->op, float, I->c + len + 32);
589 save_pc = I->op + I->c;
590 while(len-- > 0) {
591 cc++;
592 const auto op = static_cast<unsigned>(*(src++));
593
594 if (op >= CGO_sz_size()) {
595 bad_entry = cc;
596 break;
597 }
598
599 sz = CGO_sz[op];
600 if(len < sz)
601 break; /* discard short instruction */
602 len -= sz;
603 pc = save_pc;
604 CGO_write_int(pc, op);
605 ok = true;
606 for(a = 0; a < sz; a++) {
607 cc++;
608 val = *(src++);
609 if((FLT_MAX - val) > 0.0F) { /* make sure we have a real float */
610 *(pc++) = val;
611 } else {
612 *(pc++) = 0.0;
613 ok = false;
614 }
615 }
616 if(ok) {
617 switch (op) {
618 case CGO_END:
619 case CGO_VERTEX:
620 case CGO_BEGIN:
621 I->has_begin_end = true;
622 }
623 switch (op) { /* now convert any instructions with int arguments */
624 case CGO_BEGIN:
625 case CGO_ENABLE:
626 case CGO_DISABLE:
627 case CGO_SPECIAL:
628 tf = save_pc + 1;
629 iarg = (int) *(tf);
630 CGO_write_int(tf, iarg);
631 break;
632 }
633 save_pc = pc;
634 I->c += sz + 1;
635 } else { /* discard illegal instructions */
636 if(all_ok)
637 bad_entry = cc;
638 all_ok = false;
639 }
640 }
641 return (bad_entry);
642 }
643
CGOBegin(CGO * I,int mode)644 int CGOBegin(CGO * I, int mode)
645 {
646 float *pc = CGO_add(I, CGO_BEGIN_SZ + 1);
647 if (!pc)
648 return false;
649 CGO_write_int(pc, CGO_BEGIN);
650 CGO_write_int(pc, mode);
651 I->has_begin_end = true;
652 I->texture[0] = 0.f;
653 I->texture[1] = 0.f;
654 return true;
655 }
656
CGOEnd(CGO * I)657 int CGOEnd(CGO * I)
658 {
659 float *pc = CGO_add(I, CGO_END_SZ + 1);
660 if (!pc)
661 return false;
662 CGO_write_int(pc, CGO_END);
663 I->has_begin_end = true;
664 return true;
665 }
666
CGOEnable(CGO * I,int mode)667 int CGOEnable(CGO * I, int mode)
668 {
669 float *pc = CGO_add(I, CGO_ENABLE_SZ + 1);
670 if (!pc)
671 return false;
672 CGO_write_int(pc, CGO_ENABLE);
673 CGO_write_int(pc, mode);
674 return true;
675 }
676
CGODisable(CGO * I,int mode)677 int CGODisable(CGO * I, int mode)
678 {
679 float *pc = CGO_add(I, CGO_DISABLE_SZ + 1);
680 if (!pc)
681 return false;
682 CGO_write_int(pc, CGO_DISABLE);
683 CGO_write_int(pc, mode);
684 return true;
685 }
686
CGOLinewidth(CGO * I,float v)687 int CGOLinewidth(CGO * I, float v)
688 {
689 float *pc = CGO_add(I, CGO_LINEWIDTH_SZ + 1);
690 if (!pc)
691 return false;
692 CGO_write_int(pc, CGO_LINEWIDTH);
693 *(pc++) = v;
694 return true;
695 }
696
697 /*
698 * implements special-case operations inside a CGO
699 *
700 * v: lookup value defined for each special operation (see CGO.h)
701 */
CGOSpecial(CGO * I,int v)702 int CGOSpecial(CGO * I, int v)
703 {
704 float *pc = CGO_add(I, CGO_SPECIAL_SZ + 1);
705 if (!pc)
706 return false;
707 CGO_write_int(pc, CGO_SPECIAL);
708 CGO_write_int(pc, v);
709 return true;
710 }
711
712 /*
713 * implements special-case operations with an argument
714 * inside a CGO
715 *
716 * v: lookup value defined for each special operation (see CGO.h)
717 * argval : argument value
718 */
CGOSpecialWithArg(CGO * I,int v,float argval)719 int CGOSpecialWithArg(CGO * I, int v, float argval)
720 {
721 float *pc = CGO_add(I, CGO_SPECIAL_WITH_ARG_SZ + 1);
722 if (!pc)
723 return false;
724 CGO_write_int(pc, CGO_SPECIAL_WITH_ARG);
725 CGO_write_int(pc, v);
726 *pc = argval;
727 return true;
728 }
729
CGODotwidth(CGO * I,float v)730 int CGODotwidth(CGO * I, float v)
731 {
732 float *pc = CGO_add(I, CGO_DOTWIDTH_SZ + 1);
733 if (!pc)
734 return false;
735 CGO_write_int(pc, CGO_DOTWIDTH);
736 *(pc++) = v;
737 return true;
738 }
739
740 /* CGOUniform3f - specifies a 3f uniform variable and
741 its value. This function returns the offset of where
742 these values are stored inside the CGO float array
743 so that they can be accessed and changed from outside
744 the CGO.
745
746 */
CGOUniform3f(CGO * I,int uniform_id,const float * value)747 int CGOUniform3f(CGO *I, int uniform_id, const float *value){
748 float *pc = CGO_add(I, CGO_UNIFORM3F_SZ + 1);
749 if (!pc)
750 return 0;
751 CGO_write_int(pc, CGO_UNIFORM3F);
752 CGO_write_int(pc, uniform_id);
753 copy3f(value, pc);
754 return pc - I->op;
755 }
756
CGOBoundingBox(CGO * I,const float * min,const float * max)757 int CGOBoundingBox(CGO *I, const float *min, const float *max){
758 float *pc = CGO_add(I, CGO_BOUNDING_BOX_SZ + 1);
759 if (!pc)
760 return false;
761 CGO_write_int(pc, CGO_BOUNDING_BOX);
762 *(pc++) = *(min);
763 *(pc++) = *(min+1);
764 *(pc++) = *(min+2);
765 *(pc++) = *(max);
766 *(pc++) = *(max+1);
767 *(pc++) = *(max+2);
768 return true;
769 }
770
CGOAccessibility(CGO * I,float a)771 int CGOAccessibility(CGO * I, float a)
772 {
773 float *pc = CGO_add(I, CGO_ACCESSIBILITY_SZ + 1);
774 if (!pc)
775 return false;
776 CGO_write_int(pc, CGO_ACCESSIBILITY);
777 *(pc++) = a;
778 return true;
779 }
780
CGODrawTexture(CGO * I,int texture_id,float * worldPos,float * screenMin,float * screenMax,float * textExtent)781 int CGODrawTexture(CGO *I, int texture_id, float *worldPos, float *screenMin, float *screenMax, float *textExtent)
782 {
783 float *pc = CGO_add(I, CGO_DRAW_TEXTURE_SZ + 1);
784 if (!pc)
785 return false;
786 CGO_write_int(pc, CGO_DRAW_TEXTURE);
787 *(pc++) = worldPos[0];
788 *(pc++) = worldPos[1];
789 *(pc++) = worldPos[2];
790 *(pc++) = screenMin[0];
791 *(pc++) = screenMin[1];
792 *(pc++) = screenMin[2];
793 *(pc++) = screenMax[0];
794 *(pc++) = screenMax[1];
795 *(pc++) = screenMax[2];
796 *(pc++) = textExtent[0];
797 *(pc++) = textExtent[1];
798 *(pc++) = textExtent[2];
799 *(pc++) = textExtent[3];
800 return true;
801 }
802
CGODrawConnector(CGO * I,float * targetPt3d,float * labelCenterPt3d,float text_width,float text_height,float * indentFactor,float * screenWorldOffset,float * connectorColor,short relativeMode,int draw_flags,float bkgrd_transp,float * bkgrd_color,float rel_ext_length,float connectorWidth)803 int CGODrawConnector(CGO *I, float *targetPt3d, float *labelCenterPt3d, float text_width, float text_height, float *indentFactor, float *screenWorldOffset, float *connectorColor, short relativeMode, int draw_flags, float bkgrd_transp, float *bkgrd_color, float rel_ext_length, float connectorWidth)
804 {
805 float *pc = CGO_add(I, CGO_DRAW_CONNECTOR_SZ + 1);
806 if (!pc)
807 return false;
808 CGO_write_int(pc, CGO_DRAW_CONNECTOR);
809 *(pc++) = targetPt3d[0];
810 *(pc++) = targetPt3d[1];
811 *(pc++) = targetPt3d[2];
812 *(pc++) = labelCenterPt3d[0];
813 *(pc++) = labelCenterPt3d[1];
814 *(pc++) = labelCenterPt3d[2];
815 *(pc++) = indentFactor[0];
816 *(pc++) = indentFactor[1];
817 *(pc++) = rel_ext_length; /* place for ext_length relative to height (i.e., text_height which is total height */
818 *(pc++) = screenWorldOffset[0];
819 *(pc++) = screenWorldOffset[1];
820 *(pc++) = screenWorldOffset[2];
821 *(pc++) = text_width;
822 *(pc++) = text_height;
823 *(pc++) = connectorColor[0];
824 *(pc++) = connectorColor[1];
825 *(pc++) = connectorColor[2];
826 *(pc++) = (float)relativeMode;
827 *(pc++) = (float)draw_flags;
828 *(pc++) = bkgrd_color[0];
829 *(pc++) = bkgrd_color[1];
830 *(pc++) = bkgrd_color[2];
831 *(pc++) = bkgrd_transp;
832 *(pc++) = connectorWidth; // place for label_connector_width
833 return true;
834 }
835
CGODrawLabel(CGO * I,int texture_id,float * targetPos,float * worldPos,float * screenWorldOffset,float * screenMin,float * screenMax,float * textExtent,short relativeMode)836 int CGODrawLabel(CGO *I, int texture_id, float *targetPos, float *worldPos, float *screenWorldOffset, float *screenMin, float *screenMax, float *textExtent, short relativeMode)
837 {
838 float *pc = CGO_add(I, CGO_DRAW_LABEL_SZ + 1);
839 if (!pc)
840 return false;
841 CGO_write_int(pc, CGO_DRAW_LABEL);
842 *(pc++) = worldPos[0];
843 *(pc++) = worldPos[1];
844 *(pc++) = worldPos[2];
845 *(pc++) = screenWorldOffset[0];
846 *(pc++) = screenWorldOffset[1];
847 *(pc++) = screenWorldOffset[2];
848 *(pc++) = screenMin[0];
849 *(pc++) = screenMin[1];
850 *(pc++) = screenMin[2];
851 *(pc++) = screenMax[0];
852 *(pc++) = screenMax[1];
853 *(pc++) = screenMax[2];
854 *(pc++) = textExtent[0];
855 *(pc++) = textExtent[1];
856 *(pc++) = textExtent[2];
857 *(pc++) = textExtent[3];
858 *(pc++) = (float)relativeMode;
859 *(pc++) = targetPos[0];
860 *(pc++) = targetPos[1];
861 *(pc++) = targetPos[2];
862 return true;
863 }
864
CGOConev(CGO * I,const float * p1,const float * p2,float r1,float r2,const float * c1,const float * c2,float cap1,float cap2)865 int CGOConev(CGO * I,
866 const float *p1,
867 const float *p2, float r1, float r2,
868 const float *c1,
869 const float *c2,
870 float cap1, float cap2)
871 {
872 float *pc = CGO_add(I, CGO_CONE_SZ + 1);
873 if (!pc)
874 return false;
875 CGO_write_int(pc, CGO_CONE);
876 *(pc++) = *(p1++);
877 *(pc++) = *(p1++);
878 *(pc++) = *(p1++);
879 *(pc++) = *(p2++);
880 *(pc++) = *(p2++);
881 *(pc++) = *(p2++);
882 *(pc++) = r1;
883 *(pc++) = r2;
884 *(pc++) = *(c1++);
885 *(pc++) = *(c1++);
886 *(pc++) = *(c1++);
887 *(pc++) = *(c2++);
888 *(pc++) = *(c2++);
889 *(pc++) = *(c2++);
890 *(pc++) = cap1;
891 *(pc++) = cap2;
892 return true;
893 }
894
CGOPickColor(CGO * I,unsigned int index,int bond)895 int CGOPickColor(CGO * I, unsigned int index, int bond)
896 {
897 // check if uchar is -1 since extrude does this for masked atoms
898 if (index == (unsigned int)-1){
899 bond = cPickableNoPick;
900 }
901 if (I->current_pick_color_index==index &&
902 I->current_pick_color_bond==bond)
903 return true;
904 float *pc = CGO_add(I, CGO_PICK_COLOR_SZ + 1);
905 if (!pc)
906 return false;
907 CGO_write_int(pc, CGO_PICK_COLOR);
908 CGO_write_uint(pc, index);
909 CGO_write_int(pc, bond);
910 I->current_pick_color_index = index;
911 I->current_pick_color_bond = bond;
912 return true;
913 }
914
CGOAlpha(CGO * I,float alpha)915 int CGOAlpha(CGO * I, float alpha)
916 {
917 float *pc = CGO_add(I, CGO_ALPHA_SZ + 1);
918 if (!pc)
919 return false;
920 CGO_write_int(pc, CGO_ALPHA);
921 *(pc++) = alpha;
922 I->alpha = alpha;
923 return true;
924 }
925
CGOSphere(CGO * I,const float * v1,float r)926 int CGOSphere(CGO * I, const float *v1, float r)
927 {
928 float *pc = CGO_add(I, CGO_SPHERE_SZ + 1);
929 if (!pc)
930 return false;
931 CGO_write_int(pc, CGO_SPHERE);
932 *(pc++) = *(v1++);
933 *(pc++) = *(v1++);
934 *(pc++) = *(v1++);
935 *(pc++) = r;
936 return true;
937 }
938
CGOEllipsoid(CGO * I,const float * v1,float r,const float * n1,const float * n2,const float * n3)939 int CGOEllipsoid(CGO * I, const float *v1, float r,
940 const float *n1,
941 const float *n2,
942 const float *n3)
943 {
944 float *pc = CGO_add(I, CGO_ELLIPSOID_SZ + 1);
945 if (!pc)
946 return false;
947 CGO_write_int(pc, CGO_ELLIPSOID);
948
949 *(pc++) = *(v1++);
950 *(pc++) = *(v1++);
951 *(pc++) = *(v1++);
952 *(pc++) = r;
953 *(pc++) = *(n1++);
954 *(pc++) = *(n1++);
955 *(pc++) = *(n1++);
956 *(pc++) = *(n2++);
957 *(pc++) = *(n2++);
958 *(pc++) = *(n2++);
959 *(pc++) = *(n3++);
960 *(pc++) = *(n3++);
961 *(pc++) = *(n3++);
962 return true;
963 }
964
CGOQuadric(CGO * I,const float * v,float r,const float * q)965 int CGOQuadric(CGO * I, const float *v, float r, const float *q)
966 {
967 float *pc = CGO_add(I, CGO_QUADRIC_SZ + 1);
968 if (!pc)
969 return false;
970 CGO_write_int(pc, CGO_QUADRIC);
971
972 *(pc++) = *(v++);
973 *(pc++) = *(v++);
974 *(pc++) = *(v++);
975 *(pc++) = r;
976
977 *(pc++) = *(q++);
978 *(pc++) = *(q++);
979 *(pc++) = *(q++);
980 *(pc++) = *(q++);
981 *(pc++) = *(q++);
982
983 *(pc++) = *(q++);
984 *(pc++) = *(q++);
985 *(pc++) = *(q++);
986 *(pc++) = *(q++);
987 *(pc++) = *(q++);
988 return true;
989 }
990
CGOSetZVector(CGO * I,float z0,float z1,float z2)991 void CGOSetZVector(CGO * I, float z0, float z1, float z2)
992 {
993 I->z_flag = true;
994 I->z_vector[0] = z0;
995 I->z_vector[1] = z1;
996 I->z_vector[2] = z2;
997 I->z_min = FLT_MAX;
998 I->z_max = -FLT_MAX;
999 }
1000
1001 const static float one_third = 1.0F / 3.0F;
1002 const static float _0 = 0.0F;
1003
CGOAlphaTriangle(CGO * I,const float * v1,const float * v2,const float * v3,const float * n1,const float * n2,const float * n3,const float * c1,const float * c2,const float * c3,float a1,float a2,float a3,int reverse)1004 int CGOAlphaTriangle(CGO * I,
1005 const float *v1, const float *v2, const float *v3,
1006 const float *n1, const float *n2, const float *n3,
1007 const float *c1, const float *c2, const float *c3,
1008 float a1, float a2, float a3, int reverse)
1009 {
1010 if(v1 && v2 && v3) {
1011 float *pc = CGO_add(I, CGO_ALPHA_TRIANGLE_SZ + 1);
1012 float z = _0;
1013 if (!pc)
1014 return false;
1015 CGO_write_int(pc, CGO_ALPHA_TRIANGLE);
1016 CGO_write_int(pc, 0); // this is the place for the next triangle in the bin
1017 *(pc++) = (v1[0] + v2[0] + v3[0]) * one_third;
1018 *(pc++) = (v1[1] + v2[1] + v3[1]) * one_third;
1019 *(pc++) = (v1[2] + v2[2] + v3[2]) * one_third;
1020 if(I->z_flag) {
1021 float *zv = I->z_vector;
1022 z = pc[-3] * zv[0] + pc[-2] * zv[1] + pc[-1] * zv[2];
1023 if(z > I->z_max)
1024 I->z_max = z;
1025 if(z < I->z_min)
1026 I->z_min = z;
1027 }
1028 *(pc++) = z;
1029
1030 if(reverse) {
1031 *(pc++) = *(v2++); /* vertices @ +5 */
1032 *(pc++) = *(v2++);
1033 *(pc++) = *(v2++);
1034 *(pc++) = *(v1++);
1035 *(pc++) = *(v1++);
1036 *(pc++) = *(v1++);
1037 } else {
1038 *(pc++) = *(v1++); /* vertices @ +5 */
1039 *(pc++) = *(v1++);
1040 *(pc++) = *(v1++);
1041 *(pc++) = *(v2++);
1042 *(pc++) = *(v2++);
1043 *(pc++) = *(v2++);
1044 }
1045
1046 *(pc++) = *(v3++);
1047 *(pc++) = *(v3++);
1048 *(pc++) = *(v3++);
1049
1050 if(reverse) {
1051 *(pc++) = *(n2++); /* normals @ +14 */
1052 *(pc++) = *(n2++);
1053 *(pc++) = *(n2++);
1054 *(pc++) = *(n1++);
1055 *(pc++) = *(n1++);
1056 *(pc++) = *(n1++);
1057 } else {
1058 *(pc++) = *(n1++); /* normals @ +14 */
1059 *(pc++) = *(n1++);
1060 *(pc++) = *(n1++);
1061 *(pc++) = *(n2++);
1062 *(pc++) = *(n2++);
1063 *(pc++) = *(n2++);
1064 }
1065 *(pc++) = *(n3++);
1066 *(pc++) = *(n3++);
1067 *(pc++) = *(n3++);
1068
1069 if(reverse) {
1070 *(pc++) = *(c2++); /* colors @ +23 */
1071 *(pc++) = *(c2++);
1072 *(pc++) = *(c2++);
1073 *(pc++) = a2;
1074 *(pc++) = *(c1++);
1075 *(pc++) = *(c1++);
1076 *(pc++) = *(c1++);
1077 *(pc++) = a1;
1078 } else {
1079 *(pc++) = *(c1++); /* colors @ +23 */
1080 *(pc++) = *(c1++);
1081 *(pc++) = *(c1++);
1082 *(pc++) = a1;
1083 *(pc++) = *(c2++);
1084 *(pc++) = *(c2++);
1085 *(pc++) = *(c2++);
1086 *(pc++) = a2;
1087 }
1088 *(pc++) = *(c3++);
1089 *(pc++) = *(c3++);
1090 *(pc++) = *(c3++);
1091 *(pc++) = a3;
1092 }
1093 return true;
1094 }
1095
CGOVertex(CGO * I,float v1,float v2,float v3)1096 int CGOVertex(CGO * I, float v1, float v2, float v3)
1097 {
1098 float *pc = CGO_add(I, CGO_VERTEX_SZ + 1);
1099 if (!pc)
1100 return false;
1101 CGO_write_int(pc, CGO_VERTEX);
1102 *(pc++) = v1;
1103 *(pc++) = v2;
1104 *(pc++) = v3;
1105 return true;
1106 }
1107
CGOVertexv(CGO * I,const float * v)1108 int CGOVertexv(CGO * I, const float *v)
1109 {
1110 float *pc = CGO_add(I, CGO_VERTEX_SZ + 1);
1111 if (!pc)
1112 return false;
1113 CGO_write_int(pc, CGO_VERTEX);
1114 *(pc++) = *(v++);
1115 *(pc++) = *(v++);
1116 *(pc++) = *(v++);
1117 return true;
1118 }
1119
CGOVertexBeginLineStripv(CGO * I,const float * v)1120 int CGOVertexBeginLineStripv(CGO * I, const float *v)
1121 {
1122 float *pc = CGO_add(I, CGO_VERTEX_BEGIN_LINE_STRIP_SZ + 1);
1123 if (!pc)
1124 return false;
1125 CGO_write_int(pc, CGO_VERTEX_BEGIN_LINE_STRIP);
1126 *(pc++) = *(v++);
1127 *(pc++) = *(v++);
1128 *(pc++) = *(v++);
1129 return true;
1130 }
1131
CGOVertexCrossv(CGO * I,const float * v)1132 int CGOVertexCrossv(CGO * I, const float *v)
1133 {
1134 float *pc = CGO_add(I, CGO_VERTEX_CROSS_SZ + 1);
1135 if (!pc)
1136 return false;
1137 CGO_write_int(pc, CGO_VERTEX_CROSS);
1138 *(pc++) = *(v++);
1139 *(pc++) = *(v++);
1140 *(pc++) = *(v++);
1141 return true;
1142 }
CGOInterpolated(CGO * I,const bool interp)1143 int CGOInterpolated(CGO * I, const bool interp)
1144 {
1145 float *pc = CGO_add(I, CGO_INTERPOLATED_SZ + 1);
1146 if (!pc)
1147 return false;
1148 CGO_write_int(pc, CGO_INTERPOLATED);
1149 *(pc++) = interp ? 1.f : 0.f;
1150 I->interpolated = interp;
1151 return true;
1152 }
1153
CGOColor(CGO * I,float v1,float v2,float v3)1154 int CGOColor(CGO * I, float v1, float v2, float v3)
1155 {
1156 float *pc = CGO_add(I, CGO_COLOR_SZ + 1);
1157 if (!pc)
1158 return false;
1159 CGO_write_int(pc, CGO_COLOR);
1160 *(pc++) = v1;
1161 *(pc++) = v2;
1162 *(pc++) = v3;
1163 I->color[0] = v1;
1164 I->color[1] = v2;
1165 I->color[2] = v3;
1166 return true;
1167 }
1168
CGOColorv(CGO * I,const float * v)1169 int CGOColorv(CGO * I, const float *v)
1170 {
1171 return CGOColor(I, v[0], v[1], v[2]);
1172 }
1173
CGOTexCoord2f(CGO * I,float v1,float v2)1174 int CGOTexCoord2f(CGO * I, float v1, float v2){
1175 float *pc = CGO_add(I, CGO_TEX_COORD_SZ + 1);
1176 if (!pc)
1177 return false;
1178 CGO_write_int(pc, CGO_TEX_COORD);
1179 *(pc++) = v1;
1180 *(pc++) = v2;
1181 I->texture[0] = v1;
1182 I->texture[1] = v2;
1183 return true;
1184 }
1185
CGONormal(CGO * I,float v1,float v2,float v3)1186 int CGONormal(CGO * I, float v1, float v2, float v3)
1187 {
1188 float *pc = CGO_add(I, CGO_NORMAL_SZ + 1);
1189 if (!pc)
1190 return false;
1191 CGO_write_int(pc, CGO_NORMAL);
1192 *(pc++) = v1;
1193 *(pc++) = v2;
1194 *(pc++) = v3;
1195 I->normal[0] = v1;
1196 I->normal[1] = v2;
1197 I->normal[2] = v3;
1198 return true;
1199 }
1200
CGOResetNormal(CGO * I,int mode)1201 int CGOResetNormal(CGO * I, int mode)
1202 {
1203 float *pc = CGO_add(I, CGO_RESET_NORMAL_SZ + 1);
1204 if (!pc)
1205 return false;
1206 CGO_write_int(pc, CGO_RESET_NORMAL);
1207 CGO_write_int(pc, mode);
1208 SceneGetResetNormal(I->G, I->normal, mode);
1209 return true;
1210 }
1211
CGOFontVertexv(CGO * I,const float * v)1212 int CGOFontVertexv(CGO * I, const float *v)
1213 {
1214 float *pc = CGO_add(I, CGO_FONT_VERTEX_SZ + 1);
1215 if (!pc)
1216 return false;
1217 CGO_write_int(pc, CGO_FONT_VERTEX);
1218 *(pc++) = *(v++);
1219 *(pc++) = *(v++);
1220 *(pc++) = *(v++);
1221 return true;
1222 }
1223
CGOFontVertex(CGO * I,float x,float y,float z)1224 int CGOFontVertex(CGO * I, float x, float y, float z)
1225 {
1226 float *pc = CGO_add(I, CGO_FONT_VERTEX_SZ + 1);
1227 if (!pc)
1228 return false;
1229 CGO_write_int(pc, CGO_FONT_VERTEX);
1230 *(pc++) = x;
1231 *(pc++) = y;
1232 *(pc++) = z;
1233 return true;
1234 }
1235
CGOFontScale(CGO * I,float v1,float v2)1236 int CGOFontScale(CGO * I, float v1, float v2)
1237 {
1238 float *pc = CGO_add(I, CGO_FONT_SCALE_SZ + 1);
1239 if (!pc)
1240 return false;
1241 CGO_write_int(pc, CGO_FONT_SCALE);
1242 *(pc++) = v1;
1243 *(pc++) = v2;
1244 return true;
1245 }
1246
CGOChar(CGO * I,char c)1247 int CGOChar(CGO * I, char c)
1248 {
1249 float *pc = CGO_add(I, CGO_CHAR_SZ + 1);
1250 if (!pc)
1251 return false;
1252 CGO_write_int(pc, CGO_CHAR);
1253 *(pc++) = (float) c;
1254 return true;
1255 }
1256
CGOIndent(CGO * I,char c,float dir)1257 int CGOIndent(CGO * I, char c, float dir)
1258 {
1259 float *pc = CGO_add(I, CGO_INDENT_SZ + 1);
1260 if (!pc)
1261 return false;
1262 CGO_write_int(pc, CGO_INDENT);
1263 *(pc++) = (float) c;
1264 *(pc++) = dir;
1265 return true;
1266 }
1267
CGOWrite(CGO * I,const char * str)1268 int CGOWrite(CGO * I, const char *str)
1269 {
1270 float *pc;
1271
1272 while(*str) {
1273 pc = CGO_add(I, CGO_CHAR_SZ + 1);
1274 if (!pc)
1275 return false;
1276 CGO_write_int(pc, CGO_CHAR);
1277 *(pc++) = (float) *(str++);
1278 }
1279 return true;
1280 }
1281
CGOWriteLeft(CGO * I,const char * str)1282 int CGOWriteLeft(CGO * I, const char *str)
1283 {
1284 float *pc;
1285 const char *s = str;
1286 while(*s) {
1287 pc = CGO_add(I, CGO_INDENT_SZ + 1);
1288 if (!pc)
1289 return false;
1290 CGO_write_int(pc, CGO_INDENT);
1291 *(pc++) = (float) *(s++);
1292 *(pc++) = -1.0F;
1293 }
1294 s = str;
1295 while(*s) {
1296 pc = CGO_add(I, CGO_CHAR_SZ + 1);
1297 if (!pc)
1298 return false;
1299 CGO_write_int(pc, CGO_CHAR);
1300 *(pc++) = (float) *(s++);
1301 }
1302 return true;
1303 }
1304
CGOWriteIndent(CGO * I,const char * str,float indent)1305 int CGOWriteIndent(CGO * I, const char *str, float indent)
1306 {
1307 float *pc;
1308 const char *s = str;
1309 while(*s) {
1310 pc = CGO_add(I, CGO_INDENT_SZ + 1);
1311 if (!pc)
1312 return false;
1313 CGO_write_int(pc, CGO_INDENT);
1314 *(pc++) = (float) *(s++);
1315 *(pc++) = indent;
1316 }
1317 s = str;
1318 while(*s) {
1319 pc = CGO_add(I, CGO_CHAR_SZ + 1);
1320 if (!pc)
1321 return false;
1322 CGO_write_int(pc, CGO_CHAR);
1323 *(pc++) = (float) *(s++);
1324 }
1325 return true;
1326 }
1327
CGONormalv(CGO * I,const float * v)1328 int CGONormalv(CGO * I, const float *v)
1329 {
1330 float *pc = CGO_add(I, CGO_NORMAL_SZ + 1);
1331 if (!pc)
1332 return false;
1333 CGO_write_int(pc, CGO_NORMAL);
1334 *(pc++) = *(v++);
1335 *(pc++) = *(v++);
1336 *(pc++) = *(v++);
1337 return true;
1338 }
1339
1340 /*
1341 * Add a null terminator to the CGO buffer, but don't increment
1342 * the size variable (CGO::c).
1343 */
CGOStop(CGO * I)1344 int CGOStop(CGO * I)
1345 {
1346 #define CGO_STOP_ZEROS 1
1347
1348 float *pc = CGO_size(I, I->c + CGO_STOP_ZEROS);
1349 if (!pc)
1350 return false;
1351 UtilZeroMem(pc, sizeof(float) * CGO_STOP_ZEROS);
1352 I->c -= CGO_STOP_ZEROS;
1353 return true;
1354 }
1355
CGOCheckComplex(CGO * I)1356 int CGOCheckComplex(CGO * I)
1357 {
1358 int fc = 0;
1359 const SphereRec* sp = I->G->Sphere->Sphere[1];
1360
1361 /* stick_quality needs to match *every* CGO? */
1362 auto nEdge = SettingGet<int>(I->G, cSetting_stick_quality);
1363
1364 for (auto it = I->begin(); !it.is_stop(); ++it) {
1365 auto pc = it.data();
1366 int op = it.op_code();
1367
1368 switch (op) {
1369 case CGO_CYLINDER:
1370 case CGO_CONE:
1371 case CGO_SAUSAGE:
1372 case CGO_CUSTOM_CYLINDER:
1373 case CGO_CUSTOM_CYLINDER_ALPHA:
1374 fc += 3 * (3 + (nEdge + 1) * 9) + 9;
1375 break;
1376 case CGO_ELLIPSOID:
1377 case CGO_QUADRIC:
1378 case CGO_SPHERE:
1379 fc += (sp->NVertTot * 6) + (sp->NStrip * 3) + 3;
1380 break;
1381 case CGO_DRAW_ARRAYS:
1382 {
1383 cgo::draw::arrays * sp = reinterpret_cast<decltype(sp)>(pc);
1384 fc += sp->nverts;
1385 }
1386 break;
1387 case CGO_DRAW_BUFFERS_INDEXED:
1388 {
1389 cgo::draw::buffers_indexed * sp = reinterpret_cast<decltype(sp)>(pc);
1390 switch(sp->mode){
1391 case GL_TRIANGLES:
1392 fc += sp->nindices / 3;
1393 break;
1394 case GL_LINES:
1395 fc += sp->nindices / 2;
1396 break;
1397 }
1398 }
1399 break;
1400 case CGO_DRAW_BUFFERS_NOT_INDEXED:
1401 {
1402 cgo::draw::buffers_not_indexed * sp = reinterpret_cast<decltype(sp)>(pc);
1403 switch(sp->mode){
1404 case GL_TRIANGLES:
1405 fc += sp->nverts / 3;
1406 break;
1407 case GL_LINES:
1408 fc += sp->nverts / 2;
1409 break;
1410 }
1411 }
1412 break;
1413 case CGO_DRAW_SPHERE_BUFFERS:
1414 {
1415 cgo::draw::sphere_buffers * sp = reinterpret_cast<decltype(sp)>(pc);
1416 fc += sp->num_spheres * VERTICES_PER_SPHERE;
1417 }
1418 break;
1419 case CGO_DRAW_CYLINDER_BUFFERS:
1420 {
1421 cgo::draw::cylinder_buffers * sp = reinterpret_cast<decltype(sp)>(pc);
1422 fc += sp->num_cyl * NUM_VERTICES_PER_CYLINDER;
1423 }
1424 break;
1425 }
1426 }
1427 return (fc);
1428 }
1429
CGOPreloadFonts(CGO * I)1430 int CGOPreloadFonts(CGO * I)
1431 {
1432 int ok = true;
1433 int font_seen = false;
1434 int font_id;
1435
1436 auto blocked = PAutoBlock(I->G);
1437
1438 for (auto it = I->begin(); !it.is_stop(); ++it) {
1439 const auto op = it.op_code();
1440
1441 switch (op) {
1442 case CGO_FONT:
1443 ok = ok && (VFontLoad(I->G, 1.0, 1, 1, true));
1444 font_seen = true;
1445 break;
1446 case CGO_CHAR:
1447 if(!font_seen) {
1448 font_id = VFontLoad(I->G, 1.0, 1, 1, true);
1449 ok = ok && font_id;
1450 font_seen = true;
1451 }
1452 break;
1453 }
1454 }
1455 if(blocked)
1456 PUnblock(I->G);
1457 return (ok);
1458 }
1459
CGOCheckForText(CGO * I)1460 int CGOCheckForText(CGO * I)
1461 {
1462 int fc = 0;
1463
1464 for (auto it = I->begin(); !it.is_stop(); ++it) {
1465 const auto op = it.op_code();
1466
1467 switch (op) {
1468 case CGO_FONT:
1469 case CGO_FONT_AXES:
1470 case CGO_FONT_SCALE:
1471 fc++;
1472 break;
1473 case CGO_INDENT:
1474 case CGO_FONT_VERTEX:
1475 fc++;
1476 break;
1477 case CGO_CHAR:
1478 fc += 3 + 2 * 3 * 10; /* est 10 lines per char */
1479 break;
1480 }
1481 }
1482 PRINTFD(I->G, FB_CGO)
1483 " CGOCheckForText-Debug: %d\n", fc ENDFD;
1484
1485 return (fc);
1486 }
1487
CGODrawText(const CGO * I,int est,float * camera)1488 CGO *CGODrawText(const CGO * I, int est, float *camera)
1489 { /* assumes blocked intepreter */
1490 CGO *cgo;
1491 int font_id = 0;
1492 char text[2] = " ";
1493 float pos[] = { 0.0F, 0.0F, 0.0F };
1494 float axes[] = { 1.0F, 0.0F, 0.0F,
1495 0.0F, 1.0F, 0.0F,
1496 0.0F, 0.0F, 1.0F
1497 };
1498 float scale[2] = { 1.0, 1.0 };
1499
1500 cgo = CGONewSized(I->G, I->c + est);
1501
1502 for (auto it = I->begin(); !it.is_stop(); ++it) {
1503 const auto op = it.op_code();
1504 const auto pc = it.data();
1505
1506 switch (op) {
1507 case CGO_FONT:
1508 break;
1509 case CGO_FONT_AXES:
1510 break;
1511 case CGO_FONT_SCALE:
1512 scale[0] = pc[0];
1513 scale[1] = pc[1];
1514 break;
1515 case CGO_FONT_VERTEX:
1516 copy3f(pc, pos);
1517 break;
1518 case CGO_INDENT:
1519 text[0] = (unsigned char) *pc;
1520 VFontIndent(I->G, font_id, text, pos, scale, axes, pc[1]);
1521 break;
1522 case CGO_CHAR:
1523 if(!font_id) {
1524 font_id = VFontLoad(I->G, 1.0, 1, 1, false);
1525 }
1526 text[0] = (unsigned char) *pc;
1527 VFontWriteToCGO(I->G, font_id, cgo, text, pos, scale, axes, cgo->color);
1528 break;
1529 case CGO_COLOR:
1530 cgo->color[0] = *pc; cgo->color[1] = *(pc + 1); cgo->color[2] = *(pc + 2);
1531 default:
1532 cgo->add_to_cgo(op, pc);
1533 }
1534 }
1535 CGOStop(cgo);
1536 if (cgo && cgo->has_begin_end){
1537 /* this is mainly for VFontWriteToCGO() that still creates CGOBegin/CGOEnd */
1538 if(cgo && cgo->has_begin_end){
1539 CGO *convertcgo = NULL;
1540 convertcgo = CGOCombineBeginEnd(cgo, 0);
1541 CGOFree(cgo);
1542 cgo = convertcgo;
1543 }
1544 }
1545 return (cgo);
1546 }
1547
1548 static
CGOAddVertexToDrawArrays(CGO * cgo,int pl,int plc,int pla,const float * vertex,short notHaveValue,float * vertexVals,float * normalVals,float * colorVals,float * pickColorVals,float * accessibilityVals)1549 void CGOAddVertexToDrawArrays(CGO *cgo, int pl, int plc, int pla, const float *vertex,
1550 short notHaveValue, float *vertexVals, float *normalVals,
1551 float *colorVals, float *pickColorVals, float *accessibilityVals){
1552 float *tmp_ptr;
1553 if (notHaveValue & CGO_NORMAL_ARRAY){
1554 if (pl){
1555 tmp_ptr = &normalVals[pl-3];
1556 copy3f(tmp_ptr, &normalVals[pl]);
1557 } else {
1558 copy3f(cgo->normal, &normalVals[pl]);
1559 }
1560 }
1561 if (notHaveValue & CGO_COLOR_ARRAY){
1562 if (plc){
1563 tmp_ptr = &colorVals[plc-4];
1564 copy4f(tmp_ptr, &colorVals[plc]);
1565 } else {
1566 copy3f(&colorVals[plc], cgo->color);
1567 colorVals[plc+3] = cgo->alpha;
1568 }
1569 }
1570 if (pickColorVals){
1571 CGO_put_uint(pickColorVals + pla * 2, cgo->current_pick_color_index);
1572 CGO_put_int(pickColorVals + pla * 2 + 1, cgo->current_pick_color_bond);
1573 }
1574 if (accessibilityVals){
1575 accessibilityVals[pla] = cgo->current_accessibility;
1576 }
1577 copy3f(vertex, &vertexVals[pl]);
1578 }
1579
CGOCombineBeginEnd(CGO ** I,bool do_not_split_lines)1580 bool CGOCombineBeginEnd(CGO ** I, bool do_not_split_lines) {
1581 CGO *cgo = CGOCombineBeginEnd(*I, 0, do_not_split_lines);
1582 CGOFree(*I);
1583 *I = cgo;
1584 return (cgo != NULL);
1585 }
1586
CGOCombineBeginEnd(const CGO * I,int est,bool do_not_split_lines)1587 CGO *CGOCombineBeginEnd(const CGO * I, int est, bool do_not_split_lines)
1588 {
1589 CGO *cgo;
1590
1591 int ok = true;
1592 if (!I)
1593 return NULL;
1594 cgo = CGONewSized(I->G, 0);
1595 ok &= cgo ? true : false;
1596
1597 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
1598 auto pc = it.data();
1599 int op = it.op_code();
1600
1601 switch (op) {
1602 case CGO_END:
1603 case CGO_VERTEX:
1604 PRINTFB(I->G, FB_CGO, FB_Warnings)
1605 " CGOCombineBeginEnd: op=0x%02x encountered without CGO_BEGIN\n", op
1606 ENDFB(I->G);
1607 break;
1608 case CGO_BEGIN:
1609 {
1610 float firstColor[3], firstAlpha;
1611 char hasFirstColor = 0, hasFirstAlpha = 0;
1612 int nverts = 0, damode = CGO_VERTEX_ARRAY, err = 0;
1613
1614 // read int argument of the BEGIN operation
1615 int mode = CGO_get_int(it.data());
1616 ++it;
1617
1618 // we want to iterate twice over the BEGIN/END block
1619 auto it2 = it;
1620
1621 // first iteration over BEGIN/END block (consumes 'it')
1622 for (; !err && it != CGO_END; ++it) {
1623 auto pc = it.data();
1624 switch (it.op_code()) {
1625 case CGO_DRAW_ARRAYS:
1626 case CGO_STOP:
1627 PRINTFB(I->G, FB_CGO, FB_Errors)
1628 " CGO-Error: CGOCombineBeginEnd: invalid op=0x%02x inside BEGIN/END\n",
1629 it.op_code() ENDFB(I->G);
1630 err = true;
1631 continue;
1632 case CGO_NORMAL:
1633 damode |= CGO_NORMAL_ARRAY;
1634 break;
1635 case CGO_COLOR:
1636 if (!nverts){
1637 hasFirstColor = 1;
1638 copy3f(pc, firstColor);
1639 } else {
1640 hasFirstColor = 0;
1641 damode |= CGO_COLOR_ARRAY;
1642 }
1643 copy3f(pc, cgo->color);
1644 break;
1645 case CGO_PICK_COLOR:
1646 damode |= CGO_PICK_COLOR_ARRAY;
1647 break;
1648 case CGO_ACCESSIBILITY:
1649 damode |= CGO_ACCESSIBILITY_ARRAY;
1650 break;
1651 case CGO_VERTEX:
1652 nverts++;
1653 break;
1654 case CGO_ALPHA:
1655 cgo->alpha = *pc;
1656 if (!nverts){
1657 hasFirstAlpha = 1;
1658 firstAlpha = cgo->alpha;
1659 } else {
1660 hasFirstAlpha = 0;
1661 damode |= CGO_COLOR_ARRAY;
1662 }
1663 break;
1664 case CGO_LINE:
1665 nverts+=2;
1666 break;
1667 case CGO_SPLITLINE:
1668 {
1669 auto splitline = reinterpret_cast<const cgo::draw::splitline *>(pc);
1670 if (do_not_split_lines || (splitline->flags & cgo::draw::splitline::equal_colors)){
1671 nverts+=2;
1672 } else {
1673 nverts+=4;
1674 }
1675 }
1676 break;
1677 }
1678 }
1679 if (nverts>0 && !err){
1680 int pl = 0, plc = 0, pla = 0;
1681 float *vertexVals;
1682 float *normalVals = 0, *colorVals = 0, *nxtVals = 0, *pickColorVals = 0, *accessibilityVals = 0;
1683 short notHaveValue = 0, nxtn = 3;
1684 if (hasFirstAlpha || hasFirstColor){
1685 if (hasFirstAlpha){
1686 CGOAlpha(cgo, firstAlpha);
1687 }
1688 if (hasFirstColor){
1689 CGOColorv(cgo, firstColor);
1690 }
1691 }
1692 nxtVals = vertexVals = cgo->add<cgo::draw::arrays>(mode, damode, nverts);
1693 ok &= vertexVals ? true : false;
1694 if (!ok)
1695 continue;
1696 if (damode & CGO_NORMAL_ARRAY){
1697 nxtVals = normalVals = vertexVals + (nxtn*nverts);
1698 nxtn = 3;
1699 }
1700 if (damode & CGO_COLOR_ARRAY){
1701 nxtVals = colorVals = nxtVals + (nxtn*nverts);
1702 nxtn = 4;
1703 }
1704 if (damode & CGO_PICK_COLOR_ARRAY){
1705 nxtVals = nxtVals + (nxtn*nverts);
1706 pickColorVals = nxtVals + nverts;
1707 nxtn = 3;
1708 }
1709 if (damode & CGO_ACCESSIBILITY_ARRAY){
1710 nxtVals = nxtVals + (nxtn*nverts);
1711 accessibilityVals = nxtVals;
1712 nxtn = 1;
1713 }
1714 notHaveValue = damode;
1715
1716 // second iteration (with copy of iterator, doesn't consume 'it')
1717 for (; ok && it2 != CGO_END; ++it2) {
1718 auto pc = it2.data();
1719 switch (it2.op_code()) {
1720 case CGO_NORMAL:
1721 copy3f(pc, &normalVals[pl]);
1722 notHaveValue &= ~CGO_NORMAL_ARRAY;
1723 break;
1724 case CGO_COLOR:
1725 if (colorVals){
1726 copy3f(pc, &colorVals[plc]);
1727 colorVals[plc+3] = cgo->alpha;
1728 notHaveValue &= ~CGO_COLOR_ARRAY;
1729 }
1730 copy3f(pc, cgo->color);
1731 break;
1732 case CGO_PICK_COLOR:
1733 cgo->current_pick_color_index = CGO_get_uint(pc);
1734 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
1735 notHaveValue &= ~CGO_PICK_COLOR_ARRAY;
1736 break;
1737 case CGO_ACCESSIBILITY:
1738 cgo->current_accessibility = pc[0];
1739 break;
1740 case CGO_SPLITLINE:
1741 {
1742 auto splitline = reinterpret_cast<const cgo::draw::splitline *>(pc);
1743 float color2[] = { CONVERT_COLOR_VALUE(splitline->color2[0]),
1744 CONVERT_COLOR_VALUE(splitline->color2[1]),
1745 CONVERT_COLOR_VALUE(splitline->color2[2]) };
1746 if (do_not_split_lines || (splitline->flags & cgo::draw::splitline::equal_colors)){
1747 CGOAddVertexToDrawArrays(cgo, pl, plc, pla, splitline->vertex1, notHaveValue, vertexVals,
1748 normalVals, colorVals, pickColorVals, accessibilityVals);
1749 pl+=3; plc+=4; pla++;
1750 notHaveValue = damode;
1751
1752 if (!(splitline->flags & cgo::draw::splitline::equal_colors)){
1753 if (colorVals){
1754 copy3f(color2, &colorVals[plc]);
1755 colorVals[plc+3] = cgo->alpha;
1756 notHaveValue = notHaveValue & ~CGO_COLOR_ARRAY;
1757 }
1758 copy3f(color2, cgo->color);
1759 }
1760 if (pickColorVals){
1761 cgo->current_pick_color_index = splitline->index;
1762 cgo->current_pick_color_bond = splitline->bond;
1763 notHaveValue = notHaveValue & ~CGO_PICK_COLOR_ARRAY;
1764 }
1765 CGOAddVertexToDrawArrays(cgo, pl, plc, pla, splitline->vertex2, notHaveValue, vertexVals,
1766 normalVals, colorVals, pickColorVals, accessibilityVals);
1767 pl+=3; plc+=4; pla++;
1768 notHaveValue = damode;
1769 } else {
1770 float mid[3];
1771 add3f(splitline->vertex1, splitline->vertex2, mid);
1772 mult3f(mid, .5f, mid);
1773 CGOAddVertexToDrawArrays(cgo, pl, plc, pla, splitline->vertex1, notHaveValue, vertexVals,
1774 normalVals, colorVals, pickColorVals, accessibilityVals);
1775 notHaveValue = damode;
1776 pl+=3; plc+=4; pla++;
1777 CGOAddVertexToDrawArrays(cgo, pl, plc, pla, mid, notHaveValue, vertexVals,
1778 normalVals, colorVals, pickColorVals, accessibilityVals);
1779 pl+=3; plc+=4; pla++;
1780 if (colorVals){
1781 copy3f(color2, &colorVals[plc]);
1782 colorVals[plc+3] = cgo->alpha;
1783 notHaveValue = notHaveValue & ~CGO_COLOR_ARRAY;
1784 }
1785 copy3f(color2, cgo->color);
1786 if (pickColorVals){
1787 cgo->current_pick_color_index = splitline->index;
1788 cgo->current_pick_color_bond = splitline->bond;
1789 notHaveValue = notHaveValue & ~CGO_PICK_COLOR_ARRAY;
1790 }
1791 CGOAddVertexToDrawArrays(cgo, pl, plc, pla, mid, notHaveValue, vertexVals,
1792 normalVals, colorVals, pickColorVals, accessibilityVals);
1793 notHaveValue = damode;
1794 pl+=3; plc+=4; pla++;
1795 CGOAddVertexToDrawArrays(cgo, pl, plc, pla, splitline->vertex2, notHaveValue, vertexVals,
1796 normalVals, colorVals, pickColorVals, accessibilityVals);
1797 pl+=3; plc+=4; pla++;
1798 notHaveValue = damode;
1799 }
1800 }
1801 break;
1802 case CGO_LINE:
1803 {
1804 auto line = reinterpret_cast<const cgo::draw::line *>(pc);
1805 CGOAddVertexToDrawArrays(cgo, pl, plc, pla, line->vertex1, notHaveValue, vertexVals,
1806 normalVals, colorVals, pickColorVals, accessibilityVals);
1807 pl+=3; plc+=4; pla++;
1808 notHaveValue = damode;
1809 CGOAddVertexToDrawArrays(cgo, pl, plc, pla, line->vertex2, notHaveValue, vertexVals,
1810 normalVals, colorVals, pickColorVals, accessibilityVals);
1811 pl+=3; plc+=4; pla++;
1812 }
1813 break;
1814 case CGO_VERTEX:
1815 CGOAddVertexToDrawArrays(cgo, pl, plc, pla, pc, notHaveValue, vertexVals,
1816 normalVals, colorVals, pickColorVals, accessibilityVals);
1817 pl+=3; plc+=4; pla++;
1818 notHaveValue = damode;
1819 break;
1820 case CGO_ALPHA:
1821 // in case we're before CGO_COLOR
1822 cgo->alpha = *pc;
1823 if (colorVals) {
1824 // in case we're after CGO_COLOR
1825 colorVals[plc + 3] = *pc;
1826 }
1827 break;
1828 }
1829 }
1830 }
1831 }
1832 break;
1833 case CGO_PICK_COLOR:
1834 cgo->current_pick_color_index = CGO_get_uint(pc);
1835 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
1836 cgo->add_to_cgo(op, pc);
1837 break;
1838 case CGO_ALPHA:
1839 cgo->alpha = *pc;
1840 default:
1841 cgo->add_to_cgo(op, pc);
1842 }
1843 }
1844 if (ok){
1845 ok &= CGOStop(cgo);
1846 if (ok){
1847 cgo->use_shader = I->use_shader;
1848 if (cgo->use_shader){
1849 cgo->cgo_shader_ub_color = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_color);
1850 cgo->cgo_shader_ub_normal = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_normal);
1851 }
1852 }
1853 }
1854 if (!ok){
1855 CGOFree(cgo);
1856 }
1857 return (cgo);
1858 }
1859
1860 /**
1861 * Release all shader resources from this CGO
1862 */
CGOFreeVBOs(CGO * I)1863 void CGOFreeVBOs(CGO * I) {
1864 constexpr bool freevbos = true;
1865
1866 for (auto it = I->begin(); !it.is_stop(); ++it) {
1867 const auto op = it.op_code();
1868
1869 switch (op) {
1870 case CGO_DRAW_TRILINES:
1871 {
1872 unsigned buf = it.cast<cgo::draw::trilines>()->buffer;
1873 if (freevbos)
1874 I->G->ShaderMgr->AddVBOToFree(buf);
1875 }
1876 break;
1877 case CGO_DRAW_CUSTOM:
1878 {
1879 auto sp = it.cast<cgo::draw::custom>();
1880 if (freevbos) {
1881 I->G->ShaderMgr->freeGPUBuffer(sp->vboid);
1882 I->G->ShaderMgr->freeGPUBuffer(sp->iboid);
1883 I->G->ShaderMgr->freeGPUBuffer(sp->pickvboid);
1884 }
1885 }
1886 break;
1887 case CGO_DRAW_SPHERE_BUFFERS:
1888 {
1889 auto sp = it.cast<cgo::draw::sphere_buffers>();
1890 if (freevbos) {
1891 I->G->ShaderMgr->freeGPUBuffer(sp->vboid);
1892 I->G->ShaderMgr->freeGPUBuffer(sp->pickvboid);
1893 }
1894 }
1895 break;
1896 case CGO_DRAW_LABELS:
1897 {
1898 auto sp = it.cast<cgo::draw::labels>();
1899 if (freevbos) {
1900 I->G->ShaderMgr->freeGPUBuffer(sp->vboid);
1901 I->G->ShaderMgr->freeGPUBuffer(sp->pickvboid);
1902 }
1903 }
1904 break;
1905 case CGO_DRAW_TEXTURES:
1906 {
1907 auto sp = it.cast<cgo::draw::textures>();
1908 if (freevbos)
1909 I->G->ShaderMgr->freeGPUBuffer(sp->vboid);
1910 }
1911 break;
1912 case CGO_DRAW_SCREEN_TEXTURES_AND_POLYGONS:
1913 {
1914 auto sp = it.cast<cgo::draw::screen_textures>();
1915 if (freevbos)
1916 I->G->ShaderMgr->freeGPUBuffer(sp->vboid);
1917 }
1918 break;
1919 case CGO_DRAW_CYLINDER_BUFFERS:
1920 {
1921 auto sp = it.cast<cgo::draw::cylinder_buffers>();
1922 if (freevbos) {
1923 I->G->ShaderMgr->freeGPUBuffer(sp->vboid);
1924 I->G->ShaderMgr->freeGPUBuffer(sp->iboid);
1925 I->G->ShaderMgr->freeGPUBuffer(sp->pickvboid);
1926 }
1927 }
1928 break;
1929 case CGO_DRAW_BUFFERS_NOT_INDEXED:
1930 {
1931 auto sp = it.cast<cgo::draw::buffers_not_indexed>();
1932 if (freevbos) {
1933 I->G->ShaderMgr->freeGPUBuffer(sp->vboid);
1934 I->G->ShaderMgr->freeGPUBuffer(sp->pickvboid);
1935 }
1936 }
1937 break;
1938 case CGO_DRAW_BUFFERS_INDEXED:
1939 {
1940 auto sp = it.cast<cgo::draw::buffers_indexed>();
1941 if (freevbos) {
1942 I->G->ShaderMgr->freeGPUBuffers({ sp->vboid, sp->iboid, sp->pickvboid });
1943 }
1944 }
1945 break;
1946 case CGO_DRAW_CONNECTORS:
1947 {
1948 auto sp = it.cast<cgo::draw::connectors>();
1949 if (freevbos)
1950 I->G->ShaderMgr->freeGPUBuffer(sp->vboid);
1951 }
1952 break;
1953 }
1954 }
1955 }
1956
1957 #define set_min_max(mn, mx, pt) { \
1958 if (mn[0]>*pt) mn[0] = *pt; \
1959 if (mn[1]>*(pt+1)) mn[1] = *(pt+1); \
1960 if (mn[2]>*(pt+2)) mn[2] = *(pt+2); \
1961 if (mx[0]<*pt) mx[0] = *pt; \
1962 if (mx[1]<*(pt+1)) mx[1] = *(pt+1); \
1963 if (mx[2]<*(pt+2)) mx[2] = *(pt+2);}
1964
1965
1966 static void CGOCountNumVertices(const CGO *I, int *num_total_vertices, int *num_total_indexes,
1967 int *num_total_vertices_lines, int *num_total_indexes_lines,
1968 int *num_total_vertices_points);
1969
CGOCountNumVerticesDEBUG(const CGO * I)1970 void CGOCountNumVerticesDEBUG(const CGO *I){
1971 int num_total_vertices=0, num_total_indexes=0, num_total_vertices_lines=0, num_total_indexes_lines=0, num_total_vertices_points=0;
1972 CGOCountNumVertices(I, &num_total_vertices, &num_total_indexes, &num_total_vertices_lines, &num_total_indexes_lines, &num_total_vertices_points);
1973 printf("CGOCountNumVerticesDEBUG: num_total_vertices=%d num_total_indexes=%d num_total_vertices_lines=%d num_total_indexes_lines=%d num_total_vertices_points=%d\n", num_total_vertices, num_total_indexes, num_total_vertices_lines, num_total_indexes_lines, num_total_vertices_points);
1974
1975 }
CGOCountNumVertices(const CGO * I,int * num_total_vertices,int * num_total_indexes,int * num_total_vertices_lines,int * num_total_indexes_lines,int * num_total_vertices_points)1976 static void CGOCountNumVertices(const CGO *I, int *num_total_vertices, int *num_total_indexes,
1977 int *num_total_vertices_lines, int *num_total_indexes_lines,
1978 int *num_total_vertices_points){
1979 int verts_skipped = 0;
1980 short err = 0;
1981
1982 for (auto it = I->begin(); !it.is_stop(); ++it) {
1983 const auto op = it.op_code();
1984
1985 err = 0;
1986 switch (op) {
1987 case CGO_DRAW_ARRAYS:
1988 {
1989 const auto sp = it.cast<cgo::draw::arrays>();
1990 short shouldCompress = false, shouldCompressLines = false, shouldCompressPoints = false;
1991 switch(sp->mode){
1992 case GL_TRIANGLE_FAN:
1993 case GL_TRIANGLE_STRIP:
1994 case GL_TRIANGLES:
1995 shouldCompress = true;
1996 break;
1997 case GL_LINES:
1998 case GL_LINE_STRIP:
1999 case GL_LINE_LOOP:
2000 shouldCompressLines = true;
2001 break;
2002 case GL_POINTS:
2003 shouldCompressPoints = true;
2004 break;
2005 default:
2006 break;
2007 }
2008 if (!shouldCompress && !shouldCompressLines && !shouldCompressPoints){
2009 verts_skipped += sp->nverts;
2010 } else if (shouldCompressLines) {
2011 *num_total_vertices_lines += sp->nverts;
2012 switch(sp->mode){
2013 case GL_LINE_LOOP:
2014 *num_total_indexes_lines += 2 * sp->nverts;
2015 break;
2016 case GL_LINE_STRIP:
2017 *num_total_indexes_lines += 2 * (sp->nverts - 1);
2018 break;
2019 case GL_LINES:
2020 *num_total_indexes_lines += sp->nverts;
2021 break;
2022 }
2023 } else if (shouldCompress){
2024 *num_total_vertices += sp->nverts;
2025 switch(sp->mode){
2026 case GL_TRIANGLE_FAN:
2027 *num_total_indexes += 3 * (sp->nverts - 2);
2028 break;
2029 case GL_TRIANGLE_STRIP:
2030 *num_total_indexes += 3 * (sp->nverts - 2);
2031 break;
2032 case GL_TRIANGLES:
2033 *num_total_indexes += sp->nverts;
2034 break;
2035 }
2036 } else if (shouldCompressPoints){
2037 *num_total_vertices_points += sp->nverts;
2038 }
2039 }
2040 break;
2041 case CGO_END:
2042 if (!err){
2043 PRINTFB(I->G, FB_CGO, FB_Warnings) " CGOCountNumVertices: CGO_END encountered, should call CGOCombineBeginEnd before CGOCountNumVertices\n" ENDFB(I->G);
2044 err = true;
2045 }
2046 case CGO_VERTEX:
2047 if (!err){
2048 PRINTFB(I->G, FB_CGO, FB_Warnings) " CGOCountNumVertices: CGO_VERTEX encountered, should call CGOCombineBeginEnd before CGOCountNumVertices\n" ENDFB(I->G);
2049 err = true;
2050 }
2051 case CGO_BEGIN:
2052 if (!err){
2053 PRINTFB(I->G, FB_CGO, FB_Warnings) " CGOCountNumVertices: CGO_BEGIN encountered, should call CGOCombineBeginEnd before CGOCountNumVertices\n" ENDFB(I->G);
2054 err = true;
2055 }
2056 default:
2057 break;
2058 }
2059 }
2060 }
2061
2062 /**
2063 * @param I Primitive CGO
2064 * @return number of vertices, or -1 on error
2065 */
CGOCountNumVerticesForScreen(const CGO * I)2066 static int CGOCountNumVerticesForScreen(const CGO* I)
2067 {
2068 auto G = I->G;
2069 constexpr int MODE_INVALID = -1;
2070 int begin_mode = MODE_INVALID;
2071 int num_total_indexes = 0;
2072 int nverts = 0;
2073
2074 for (auto it = I->begin(); !it.is_stop(); ++it) {
2075 const auto op = it.op_code();
2076
2077 // sanity check: non-primitive operations
2078 switch (op) {
2079 case CGO_DRAW_ARRAYS:
2080 WARN_UNEXPECTED_OPERATION(G, op);
2081 return -1;
2082 }
2083
2084 if (begin_mode == MODE_INVALID) {
2085 switch (op) {
2086 case CGO_BEGIN:
2087 begin_mode = it.cast<cgo::draw::begin>()->mode;
2088 break;
2089 case CGO_VERTEX:
2090 case CGO_END:
2091 WARN_UNEXPECTED_OPERATION(G, op);
2092 return -1;
2093 }
2094 } else {
2095 switch (op) {
2096 case CGO_BEGIN:
2097 WARN_UNEXPECTED_OPERATION(G, op);
2098 return -1;
2099 case CGO_VERTEX:
2100 ++nverts;
2101 break;
2102 case CGO_END:
2103 switch (begin_mode) {
2104 case GL_TRIANGLE_FAN:
2105 case GL_TRIANGLE_STRIP:
2106 num_total_indexes += 3 * (nverts - 2);
2107 break;
2108 case GL_TRIANGLES:
2109 num_total_indexes += nverts;
2110 break;
2111 default:
2112 // not implemented
2113 assert(false);
2114 }
2115 begin_mode = MODE_INVALID;
2116 nverts = 0;
2117 break;
2118 }
2119 }
2120 }
2121
2122 return num_total_indexes;
2123 }
2124
2125 static
SetVertexValuesForVBO(PyMOLGlobals * G,CGO * cgo,int pl,int plc,int cnt,int incr,float * vertexValsDA,float * normalValsDA,float * colorValsDA,float * pickColorValsDA,float * vertexVals,uchar * normalValsC,float * normalVals,uchar * colorValsUC,float * colorVals,float * pickColorVals,float * accessibilityVals=NULL,float * accessibilityValsDA=NULL)2126 void SetVertexValuesForVBO(PyMOLGlobals * G, CGO *cgo, int pl, int plc, int cnt, int incr,
2127 float *vertexValsDA, float *normalValsDA,
2128 float *colorValsDA, float *pickColorValsDA,
2129 float *vertexVals, uchar *normalValsC,
2130 float *normalVals, uchar *colorValsUC, float *colorVals,
2131 float *pickColorVals,
2132 float *accessibilityVals=NULL, float *accessibilityValsDA=NULL){
2133 int pl2 = pl + 1, pl3 = pl + 2;
2134 int pln1 = VAR_FOR_NORMAL, pln2 = VAR_FOR_NORMAL + 1, pln3 = VAR_FOR_NORMAL + 2;
2135 int plc2 = plc + 1, plc3 = plc + 2, plc4 = plc + 3;
2136 int c, c2, c3;
2137 int cc, cc2, cc3, cc4;
2138 int pcc = incr * 2, pcco = cnt * 2;
2139 c = cnt * 3; c2 = c + 1; c3 = c + 2;
2140 cc = cnt * 4; cc2 = cc + 1; cc3 = cc + 2; cc4 = cc + 3;
2141 vertexVals[pl] = vertexValsDA[c]; vertexVals[pl2] = vertexValsDA[c2]; vertexVals[pl3] = vertexValsDA[c3];
2142
2143 if (normalValsC){
2144 if (normalValsDA){
2145 normalValsC[pln1] = CLIP_NORMAL_VALUE(normalValsDA[c]); normalValsC[pln2] = CLIP_NORMAL_VALUE(normalValsDA[c2]); normalValsC[pln3] = CLIP_NORMAL_VALUE(normalValsDA[c3]);
2146 } else {
2147 normalValsC[pln1] = CLIP_NORMAL_VALUE(cgo->normal[0]); normalValsC[pln2] = CLIP_NORMAL_VALUE(cgo->normal[1]); normalValsC[pln3] = CLIP_NORMAL_VALUE(cgo->normal[2]);
2148 }
2149
2150 #ifdef ALIGN_VBOS_TO_4_BYTE_ARRAYS
2151 normalValsC[pln3+1] = 127;
2152 #endif
2153 } else {
2154 if (normalValsDA){
2155 normalVals[pln1] = normalValsDA[c]; normalVals[pln2] = normalValsDA[c2]; normalVals[pln3] = normalValsDA[c3];
2156 } else {
2157 normalVals[pln1] = cgo->normal[0]; normalVals[pln2] = cgo->normal[1]; normalVals[pln3] = cgo->normal[2];
2158 }
2159 }
2160
2161 if (colorValsUC){
2162 if (colorValsDA){
2163 colorValsUC[plc] = CLIP_COLOR_VALUE(colorValsDA[cc]); colorValsUC[plc2] = CLIP_COLOR_VALUE(colorValsDA[cc2]);
2164 colorValsUC[plc3] = CLIP_COLOR_VALUE(colorValsDA[cc3]); colorValsUC[plc4] = CLIP_COLOR_VALUE(colorValsDA[cc4]);
2165 } else {
2166 colorValsUC[plc] = CLIP_COLOR_VALUE(cgo->color[0]); colorValsUC[plc2] = CLIP_COLOR_VALUE(cgo->color[1]);
2167 colorValsUC[plc3] = CLIP_COLOR_VALUE(cgo->color[2]); colorValsUC[plc4] = CLIP_COLOR_VALUE(cgo->alpha);
2168 }
2169 } else {
2170 if (colorValsDA){
2171 colorVals[plc] = colorValsDA[cc]; colorVals[plc2] = colorValsDA[cc2];
2172 colorVals[plc3] = colorValsDA[cc3]; colorVals[plc4] = colorValsDA[cc4];
2173 } else {
2174 colorVals[plc] = cgo->color[0]; colorVals[plc2] = cgo->color[1];
2175 colorVals[plc3] = cgo->color[2]; colorVals[plc4] = cgo->alpha;
2176 }
2177 }
2178 if (pickColorValsDA){
2179 cgo->current_pick_color_index = CGO_get_uint(pickColorValsDA + pcco);
2180 cgo->current_pick_color_bond = CGO_get_int(pickColorValsDA + pcco + 1);
2181 }
2182 CGO_put_uint(pickColorVals + pcc, cgo->current_pick_color_index);
2183 CGO_put_int(pickColorVals + pcc + 1, cgo->current_pick_color_bond);
2184 if (accessibilityValsDA){
2185 accessibilityVals[pl/3] = accessibilityValsDA[cnt];
2186 }
2187 }
2188
OptimizePointsToVBO(const CGO * I,CGO * cgo,int num_total_vertices_points,float * min,float * max,short * has_draw_buffer,bool addshaders)2189 static int OptimizePointsToVBO(const CGO *I, CGO *cgo, int num_total_vertices_points, float *min, float *max, short *has_draw_buffer, bool addshaders){
2190 float *vertexVals = 0, *colorVals = 0, *normalVals = 0;
2191 float *pickColorVals;
2192 int pl = 0, plc = 0, idxpl = 0, vpl = 0, tot, nxtn;
2193 uchar *colorValsUC = 0;
2194 uchar *normalValsC = 0;
2195 bool has_normals = false, has_colors = false;
2196 int ok = true;
2197
2198 cgo->alpha = 1.f;
2199 cgo->color[0] = 1.f; cgo->color[1] = 1.f; cgo->color[2] = 1.f;
2200
2201 tot = num_total_vertices_points * (3 * 5) ;
2202 // tot = num_total_indexes * (3 * 3 + 2) ;
2203 /* NOTE/TODO: Not sure why 3*5 needs to be used, but 3*3+2, which is the
2204 correct length, crashes in glBufferData */
2205 vertexVals = pymol::malloc<float>(tot);
2206 CHECKOK(ok, vertexVals);
2207 if (!ok){
2208 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: OptimizePointsToVBO() vertexVals could not be allocated\n" ENDFB(I->G);
2209 return 0;
2210 }
2211 normalVals = vertexVals + 3 * num_total_vertices_points;
2212 nxtn = 3;
2213 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_normal)){
2214 normalValsC = (uchar*) normalVals;
2215 nxtn = 1;
2216 }
2217 colorVals = normalVals + nxtn * num_total_vertices_points;
2218 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color)){
2219 colorValsUC = (uchar*) colorVals;
2220 nxtn = 1;
2221 } else {
2222 nxtn = 4;
2223 }
2224 pickColorVals = (colorVals + nxtn * num_total_vertices_points);
2225
2226 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
2227 const auto op = it.op_code();
2228 const auto pc = it.data();
2229
2230 switch (op) {
2231 case CGO_BOUNDING_BOX:
2232 case CGO_DRAW_SPHERE_BUFFERS:
2233 case CGO_DRAW_LABELS:
2234 case CGO_DRAW_TEXTURES:
2235 case CGO_DRAW_SCREEN_TEXTURES_AND_POLYGONS:
2236 case CGO_DRAW_CYLINDER_BUFFERS:
2237 case CGO_DRAW_BUFFERS_NOT_INDEXED:
2238 case CGO_DRAW_BUFFERS_INDEXED:
2239 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: OptimizePointsToVBO used with unsupported CGO ops" ENDFB(I->G);
2240 return 0;
2241 break;
2242 case CGO_NORMAL:
2243 cgo->normal[0] = *pc; cgo->normal[1] = *(pc + 1); cgo->normal[2] = *(pc + 2);
2244 has_normals = true;
2245 break;
2246 case CGO_COLOR:
2247 cgo->color[0] = *pc; cgo->color[1] = *(pc + 1); cgo->color[2] = *(pc + 2);
2248 has_colors = true;
2249 break;
2250 case CGO_ALPHA:
2251 cgo->alpha = *pc;
2252 break;
2253 case CGO_PICK_COLOR:
2254 cgo->current_pick_color_index = CGO_get_uint(pc);
2255 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
2256 break;
2257 case CGO_DRAW_ARRAYS:
2258 {
2259 const auto sp = it.cast<cgo::draw::arrays>();
2260 short shouldCompress = false;
2261 switch(sp->mode){
2262 case GL_POINTS:
2263 shouldCompress = true;
2264 default:
2265 break;
2266 }
2267 /* TODO : DO WE NEED TO COMPENSATE FOR THIS? if (!has_normals && arrays & CGO_NORMAL_ARRAY){
2268 arrays = arrays ^ CGO_NORMAL_ARRAY;
2269 narrays -= 1;
2270 }*/
2271 if (shouldCompress){
2272 int cnt, nxtn = 3 ,incr=0;
2273 float *vertexValsDA = NULL, *nxtVals = NULL, *colorValsDA = NULL, *normalValsDA = NULL;
2274 float *pickColorValsDA = NULL, *pickColorValsTMP;
2275
2276 nxtVals = vertexValsDA = sp->floatdata;
2277
2278 for (cnt=0; cnt<sp->nverts*3; cnt+=3){
2279 set_min_max(min, max, &vertexValsDA[cnt]);
2280 }
2281 if (sp->arraybits & CGO_NORMAL_ARRAY){
2282 has_normals = true;
2283 nxtVals = normalValsDA = vertexValsDA + (nxtn*sp->nverts);
2284 }
2285 if (sp->arraybits & CGO_COLOR_ARRAY){
2286 has_colors = true;
2287 nxtVals = colorValsDA = nxtVals + (nxtn*sp->nverts);
2288 nxtn = 4;
2289 }
2290 if (sp->arraybits & CGO_PICK_COLOR_ARRAY){
2291 nxtVals = nxtVals + (nxtn*sp->nverts);
2292 pickColorValsDA = nxtVals + sp->nverts;
2293 nxtn = 3;
2294 }
2295 pickColorValsTMP = pickColorVals + (idxpl * 2);
2296 switch (sp->mode){
2297 case GL_POINTS:
2298 for (cnt = 0; cnt < sp->nverts; cnt++){
2299 SetVertexValuesForVBO(I->G, cgo, pl, plc, cnt, incr++,
2300 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
2301 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
2302 pickColorValsTMP);
2303 idxpl++; pl += 3; plc += 4;
2304 }
2305 break;
2306 }
2307 vpl += sp->nverts;
2308 }
2309 }
2310 break;
2311 }
2312 ok &= !I->G->Interrupt;
2313 }
2314 if (ok){
2315 short arrays = CGO_VERTEX_ARRAY | CGO_PICK_COLOR_ARRAY;
2316 short nsz = 12;
2317 GLenum ntp = GL_FLOAT;
2318 bool nnorm = GL_FALSE;
2319 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_normal)){
2320 nsz = 3;
2321 ntp = GL_BYTE;
2322 nnorm = GL_TRUE;
2323 }
2324
2325 short csz = 4;
2326 GLenum ctp = GL_FLOAT;
2327 bool cnorm = GL_FALSE;
2328 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color)){
2329 csz = 1;
2330 ctp = GL_UNSIGNED_BYTE;
2331 cnorm = GL_TRUE;
2332 }
2333
2334 VertexBuffer * vbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>();
2335
2336 BufferDataDesc bufData =
2337 { { "a_Vertex", GL_FLOAT, 3, sizeof(float) * num_total_vertices_points * 3, vertexVals, GL_FALSE } };
2338
2339 if (has_normals){
2340 bufData.push_back( { "a_Normal", ntp, 3, (size_t)(num_total_vertices_points * nsz), normalVals, nnorm } );
2341 }
2342 if (has_colors){
2343 bufData.push_back( { "a_Color", ctp, 4, sizeof(float) * num_total_vertices_points * csz, colorVals, cnorm } );
2344 }
2345 ok = vbo->bufferData(std::move(bufData));
2346
2347 if (ok && has_colors){
2348 arrays |= CGO_COLOR_ARRAY;
2349 }
2350
2351 size_t vboid = vbo->get_hash_id();
2352
2353 if (ok){
2354 float *newPickColorVals ;
2355 if (addshaders)
2356 CGOEnable(cgo, GL_DEFAULT_SHADER);
2357 newPickColorVals = cgo->add<cgo::draw::buffers_not_indexed>(GL_POINTS, arrays, num_total_vertices_points, vboid);
2358 CHECKOK(ok, newPickColorVals);
2359 if (ok && addshaders)
2360 ok &= CGODisable(cgo, GL_DEFAULT_SHADER);
2361 if (!newPickColorVals)
2362 I->G->ShaderMgr->freeGPUBuffer(vboid);
2363 if (ok)
2364 memcpy(newPickColorVals + num_total_vertices_points, pickColorVals, num_total_vertices_points * 2 * sizeof(float));
2365 *has_draw_buffer = true;
2366 } else {
2367 I->G->ShaderMgr->freeGPUBuffer(vboid);
2368 }
2369 }
2370 FreeP(vertexVals);
2371 return ok;
2372 /* END GL_POINTS */
2373 // printf("num_total_vertices_points=%d\n", num_total_vertices_points);
2374 }
2375
2376 static
FixPickColorsForLine(float * pick1,float * pick2)2377 void FixPickColorsForLine(float *pick1, float *pick2){
2378 unsigned int p1 = CGO_get_uint(pick1);
2379 unsigned int p2 = CGO_get_uint(pick2);
2380 int b1 = CGO_get_int(pick1 + 1);
2381 int b2 = CGO_get_int(pick2 + 1);
2382 if (p1 != p2 || b1 != b2){
2383 // if the pick colors are different, then pick the first one
2384 CGO_put_uint(pick1, p2);
2385 CGO_put_int(pick1 + 1, b2);
2386 }
2387 }
2388
2389 static
FixPickColorsForTriangle(float * pick1,float * pick2,float * pick3)2390 void FixPickColorsForTriangle(float *pick1, float *pick2, float *pick3){
2391 unsigned int p1 = CGO_get_uint(pick1);
2392 unsigned int p2 = CGO_get_uint(pick2);
2393 unsigned int p3 = CGO_get_uint(pick3);
2394 int b1 = CGO_get_int(pick1 + 1);
2395 int b2 = CGO_get_int(pick2 + 1);
2396 int b3 = CGO_get_int(pick3 + 1);
2397 if (p1 != p2 || p1 != p3 || p2 != p3 ||
2398 b1 != b2 || b1 != b3 || b2 != b3){
2399 // right now, if the pick colors are different, then pick majority, otherwise, pick first one
2400 if (p1 == p2 && b1 == b2){
2401 CGO_put_uint(pick3, p1);
2402 CGO_put_int(pick3 + 1, b1);
2403 } else if (p1 == p3 && b1 == b3){
2404 CGO_put_uint(pick2, p1);
2405 CGO_put_int(pick2 + 1, b1);
2406 } else if (p2 == p3 && b2 == b3){
2407 CGO_put_uint(pick1, p2);
2408 CGO_put_int(pick1 + 1, b2);
2409 } else {
2410 CGO_put_uint(pick2, p1);
2411 CGO_put_int(pick2 + 1, b1);
2412 CGO_put_uint(pick3, p1);
2413 CGO_put_int(pick3 + 1, b1);
2414 }
2415 }
2416 }
2417
CGOProcessCGOtoArrays(const CGO * I,CGO * cgo,CGO * addtocgo,float * min,float * max,int * ambient_occlusion,float * vertexVals,float * normalVals,uchar * normalValsC,float * colorVals,uchar * colorValsUC,float * pickColorVals,float * accessibilityVals,bool & has_normals,bool & has_colors,bool & has_accessibility)2418 static bool CGOProcessCGOtoArrays(const CGO* I, CGO* cgo, CGO* addtocgo,
2419 float* min, float* max, int* ambient_occlusion, float* vertexVals,
2420 float* normalVals, uchar* normalValsC, float* colorVals, uchar* colorValsUC,
2421 float* pickColorVals, float* accessibilityVals, bool& has_normals,
2422 bool& has_colors, bool& has_accessibility)
2423 {
2424 auto G = I->G;
2425 int idxpl = 0;
2426 int pl = 0, plc = 0, vpl = 0;
2427 int ok = true;
2428
2429 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
2430 const auto op = it.op_code();
2431 const auto pc = it.data();
2432
2433 switch (op) {
2434 case CGO_BOUNDING_BOX:
2435 {
2436 const float *newpc = pc;
2437 if (addtocgo)
2438 addtocgo->add_to_cgo(op, newpc);
2439 }
2440 break;
2441 case CGO_DRAW_SPHERE_BUFFERS:
2442 case CGO_DRAW_LABELS:
2443 case CGO_DRAW_TEXTURES:
2444 case CGO_DRAW_SCREEN_TEXTURES_AND_POLYGONS:
2445 case CGO_DRAW_CYLINDER_BUFFERS:
2446 case CGO_DRAW_BUFFERS_NOT_INDEXED:
2447 case CGO_DRAW_BUFFERS_INDEXED:
2448 {
2449 const float * newpc = pc;
2450 if (addtocgo)
2451 addtocgo->add_to_cgo(op, newpc);
2452 }
2453 break;
2454 case CGO_NORMAL:
2455 cgo->normal[0] = *pc; cgo->normal[1] = *(pc + 1); cgo->normal[2] = *(pc + 2);
2456 has_normals = true;
2457 break;
2458 case CGO_COLOR:
2459 cgo->color[0] = *pc; cgo->color[1] = *(pc + 1); cgo->color[2] = *(pc + 2);
2460 has_colors = true;
2461 break;
2462 case CGO_ALPHA:
2463 cgo->alpha = *pc;
2464 break;
2465 case CGO_ACCESSIBILITY:
2466 cgo->current_accessibility = pc[0];
2467 has_accessibility = true;
2468 break;
2469 case CGO_PICK_COLOR:
2470 cgo->current_pick_color_index = CGO_get_uint(pc);
2471 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
2472 break;
2473 case CGO_DRAW_ARRAYS:
2474 {
2475 const auto sp = it.cast<cgo::draw::arrays>();
2476 short shouldCompress = false;
2477 switch(sp->mode){
2478 case GL_TRIANGLE_FAN:
2479 case GL_TRIANGLE_STRIP:
2480 case GL_TRIANGLES:
2481 shouldCompress = true;
2482 default:
2483 break;
2484 }
2485 if (shouldCompress){
2486 int cnt, nxtn = 3,incr=0;
2487 float *vertexValsDA = NULL, *nxtVals = NULL, *colorValsDA = NULL, *normalValsDA = NULL, *accessibilityValsDA = NULL;
2488 float *pickColorValsDA = NULL, *pickColorValsTMP;
2489 nxtVals = vertexValsDA = sp->floatdata;
2490
2491 for (cnt=0; cnt<sp->nverts*3; cnt+=3){
2492 set_min_max(min, max, &vertexValsDA[cnt]);
2493 }
2494 if (sp->arraybits & CGO_NORMAL_ARRAY){
2495 nxtVals = normalValsDA = vertexValsDA + (nxtn*sp->nverts);
2496 has_normals = true;
2497 }
2498
2499 if (sp->arraybits & CGO_COLOR_ARRAY){
2500 nxtVals = colorValsDA = nxtVals + (nxtn*sp->nverts);
2501 nxtn = 4;
2502 has_colors = true;
2503 }
2504 if (sp->arraybits & CGO_PICK_COLOR_ARRAY){
2505 nxtVals = nxtVals + (nxtn*sp->nverts);
2506 pickColorValsDA = nxtVals + sp->nverts;
2507 nxtn = 3;
2508 }
2509 pickColorValsTMP = pickColorVals + (idxpl * 2);
2510 if (sp->arraybits & CGO_ACCESSIBILITY_ARRAY){
2511 if (!(*ambient_occlusion) && incr){
2512 for (cnt=0; cnt<incr;cnt++){
2513 /* if ambient_occlusion, need to fill in the array */
2514 accessibilityVals[cnt] = 1.f;
2515 }
2516 }
2517 (*ambient_occlusion) = 1;
2518 accessibilityValsDA = nxtVals + nxtn*sp->nverts;
2519 has_accessibility = true;
2520 } else {
2521 if (*ambient_occlusion){
2522 for (cnt=incr; cnt<incr+sp->nverts;cnt++){
2523 /* if ambient_occlusion, need to fill in the array */
2524 accessibilityVals[cnt] = 1.f;
2525 }
2526 }
2527 }
2528 switch (sp->mode){
2529 case GL_TRIANGLES:
2530 for (cnt = 0; ok && cnt < sp->nverts; cnt++){
2531 SetVertexValuesForVBO(G, cgo, pl, plc, cnt, incr++,
2532 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
2533 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
2534 pickColorValsTMP, accessibilityVals, accessibilityValsDA);
2535 if (incr && (incr % 3) == 0){
2536 FixPickColorsForTriangle(pickColorValsTMP + (incr-3) * 2,
2537 pickColorValsTMP + (incr-2) * 2,
2538 pickColorValsTMP + (incr-1) * 2);
2539 }
2540 idxpl++; pl += 3; plc += 4;
2541 ok &= !G->Interrupt;
2542 }
2543 break;
2544 case GL_TRIANGLE_STRIP:
2545 {
2546 short flip = 0;
2547 for (cnt = 2; ok && cnt < sp->nverts; cnt++){
2548 SetVertexValuesForVBO(G, cgo, pl, plc, cnt - (flip ? 0 : 2), incr++,
2549 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
2550 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
2551 pickColorValsTMP, accessibilityVals, accessibilityValsDA);
2552 idxpl++; pl += 3; plc += 4;
2553 SetVertexValuesForVBO(G, cgo, pl, plc, cnt-1, incr++,
2554 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
2555 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
2556 pickColorValsTMP, accessibilityVals, accessibilityValsDA);
2557 idxpl++; pl += 3; plc += 4;
2558 SetVertexValuesForVBO(G, cgo, pl, plc, cnt - (flip ? 2 : 0) , incr++,
2559 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
2560 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
2561 pickColorValsTMP, accessibilityVals, accessibilityValsDA);
2562 FixPickColorsForTriangle(pickColorValsTMP + (incr-3) * 2,
2563 pickColorValsTMP + (incr-2) * 2,
2564 pickColorValsTMP + (incr-1) * 2);
2565 idxpl++; pl += 3; plc += 4;
2566 ok &= !G->Interrupt;
2567 flip = !flip;
2568 }
2569 }
2570 break;
2571 case GL_TRIANGLE_FAN:
2572 for (cnt = 2; ok && cnt < sp->nverts; cnt++){
2573 SetVertexValuesForVBO(G, cgo, pl, plc, 0, incr++,
2574 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
2575 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
2576 pickColorValsTMP, accessibilityVals, accessibilityValsDA);
2577 idxpl++; pl += 3; plc += 4;
2578 SetVertexValuesForVBO(G, cgo, pl, plc, cnt - 1, incr++,
2579 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
2580 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
2581 pickColorValsTMP, accessibilityVals, accessibilityValsDA);
2582 idxpl++; pl += 3; plc += 4;
2583 SetVertexValuesForVBO(G, cgo, pl, plc, cnt, incr++,
2584 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
2585 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
2586 pickColorValsTMP, accessibilityVals, accessibilityValsDA);
2587 FixPickColorsForTriangle(pickColorValsTMP + (incr-3) * 2,
2588 pickColorValsTMP + (incr-2) * 2,
2589 pickColorValsTMP + (incr-1) * 2);
2590 idxpl++; pl += 3; plc += 4;
2591 ok &= !G->Interrupt;
2592 }
2593 break;
2594 }
2595 vpl += sp->nverts;
2596 }
2597 }
2598 break;
2599 }
2600 ok &= !G->Interrupt;
2601 }
2602 ok &= !G->Interrupt;
2603 return ok;
2604 }
2605
CGOProcessScreenCGOtoArrays(PyMOLGlobals * G,CGO * cgo,float * vertexVals,float * texcoordVals,float * colorVals,uchar * colorValsUC)2606 static bool CGOProcessScreenCGOtoArrays(PyMOLGlobals* G, CGO* cgo,
2607 float* vertexVals, float* texcoordVals, float* colorVals,
2608 uchar* colorValsUC)
2609 {
2610 int pl = 0;
2611 cgo->alpha = 1.f;
2612
2613 for (auto it = cgo->begin(); !it.is_stop(); ++it) {
2614 const auto op = it.op_code();
2615 const auto pc = it.data();
2616
2617 switch (op) {
2618 case CGO_BOUNDING_BOX:
2619 case CGO_DRAW_SPHERE_BUFFERS:
2620 case CGO_DRAW_LABELS:
2621 case CGO_DRAW_TEXTURES:
2622 case CGO_DRAW_SCREEN_TEXTURES_AND_POLYGONS:
2623 case CGO_DRAW_CYLINDER_BUFFERS:
2624 case CGO_DRAW_BUFFERS_NOT_INDEXED:
2625 case CGO_DRAW_BUFFERS_INDEXED:
2626 case CGO_DRAW_ARRAYS:
2627 case CGO_ACCESSIBILITY:
2628 WARN_UNEXPECTED_OPERATION(G, op);
2629 return false;
2630 case CGO_NORMAL:
2631 cgo->normal[0] = *pc; cgo->normal[1] = *(pc + 1); cgo->normal[2] = *(pc + 2);
2632 break;
2633 case CGO_TEX_COORD:
2634 cgo->texture[0] = *pc; cgo->texture[1] = *(pc + 1);
2635 break;
2636 case CGO_COLOR:
2637 cgo->color[0] = *pc; cgo->color[1] = *(pc + 1); cgo->color[2] = *(pc + 2);
2638 break;
2639 case CGO_ALPHA:
2640 cgo->alpha = *pc;
2641 break;
2642 case CGO_PICK_COLOR:
2643 cgo->current_pick_color_index = CGO_get_uint(pc);
2644 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
2645 break;
2646 case CGO_BEGIN:
2647 {
2648 int mode = it.cast<cgo::draw::begin>()->mode;
2649 int nverts = 0, ipl = 0;
2650 cgo->texture[0] = cgo->texture[1] = 0.f;
2651
2652 for (++it;; ++it) {
2653 if (it.is_stop()) {
2654 WARN_UNEXPECTED_OPERATION(G, CGO_STOP);
2655 return false;
2656 }
2657
2658 const auto op = it.op_code();
2659 if (op == CGO_END) {
2660 break;
2661 }
2662
2663 const auto pc = it.data();
2664
2665 switch (op) {
2666 case CGO_TEX_COORD:
2667 cgo->texture[0] = *pc; cgo->texture[1] = *(pc + 1);
2668 break;
2669 case CGO_COLOR:
2670 cgo->color[0] = *pc; cgo->color[1] = *(pc + 1); cgo->color[2] = *(pc + 2);
2671 break;
2672 case CGO_ALPHA:
2673 cgo->alpha = *pc;
2674 break;
2675 case CGO_VERTEX:
2676 {
2677 switch (mode){
2678 case GL_TRIANGLES:
2679 {
2680 int vpl = pl * 3, tpl = pl * 2, cpl = pl * 4;
2681 vertexVals[vpl] = *pc;
2682 vertexVals[vpl + 1] = *(pc + 1);
2683 vertexVals[vpl + 2] = *(pc + 2);
2684 texcoordVals[tpl] = cgo->texture[0];
2685 texcoordVals[tpl+1] = cgo->texture[1];
2686 if (colorValsUC){
2687 colorValsUC[cpl] = CLIP_COLOR_VALUE(cgo->color[0]);
2688 colorValsUC[cpl+1] = CLIP_COLOR_VALUE(cgo->color[1]);
2689 colorValsUC[cpl+2] = CLIP_COLOR_VALUE(cgo->color[2]);
2690 colorValsUC[cpl+3] = CLIP_COLOR_VALUE(cgo->alpha);
2691 } else {
2692 colorVals[cpl] = cgo->color[0];
2693 colorVals[cpl+1] = cgo->color[1];
2694 colorVals[cpl+2] = cgo->color[2];
2695 colorVals[cpl+3] = cgo->alpha;
2696 }
2697 pl++;
2698 }
2699 break;
2700 case GL_TRIANGLE_STRIP:
2701 {
2702 int vpl = pl * 3, tpl = pl * 2, cpl = pl * 4;
2703 if (ipl < 3){
2704 vertexVals[vpl] = *pc; vertexVals[vpl + 1] = *(pc + 1); vertexVals[vpl + 2] = *(pc + 2);
2705 texcoordVals[tpl] = cgo->texture[0]; texcoordVals[tpl+1] = cgo->texture[1];
2706 if (colorValsUC){
2707 colorValsUC[cpl] = CLIP_COLOR_VALUE(cgo->color[0]); colorValsUC[cpl+1] = CLIP_COLOR_VALUE(cgo->color[1]);
2708 colorValsUC[cpl+2] = CLIP_COLOR_VALUE(cgo->color[2]); colorValsUC[cpl+3] = CLIP_COLOR_VALUE(cgo->alpha);
2709 } else {
2710 colorVals[cpl] = cgo->color[0]; colorVals[cpl+1] = cgo->color[1];
2711 colorVals[cpl+2] = cgo->color[2]; colorVals[cpl+3] = cgo->alpha;
2712 }
2713 pl++; ipl++;
2714 } else {
2715 vertexVals[vpl] = vertexVals[vpl-6]; vertexVals[vpl + 1] = vertexVals[vpl-5]; vertexVals[vpl + 2] = vertexVals[vpl-4];
2716 texcoordVals[tpl] = texcoordVals[tpl-4]; texcoordVals[tpl+1] = texcoordVals[tpl-3];
2717 if (colorValsUC){
2718 colorValsUC[cpl] = colorValsUC[cpl-8]; colorValsUC[cpl+1] = colorValsUC[cpl-7];
2719 colorValsUC[cpl+2] = colorValsUC[cpl-6]; colorValsUC[cpl+3] = colorValsUC[cpl-5];
2720 } else {
2721 colorVals[cpl] = colorVals[cpl-8]; colorVals[cpl+1] = colorVals[cpl-7];
2722 colorVals[cpl+2] = colorVals[cpl-6]; colorVals[cpl+3] = colorVals[cpl-5];
2723 }
2724 pl++; vpl+=3; tpl+=2; cpl+=4; ipl++;
2725 vertexVals[vpl] = vertexVals[vpl-6]; vertexVals[vpl + 1] = vertexVals[vpl-5]; vertexVals[vpl + 2] = vertexVals[vpl-4];
2726 texcoordVals[tpl] = texcoordVals[tpl-4]; texcoordVals[tpl+1] = texcoordVals[tpl-3];
2727 if (colorValsUC){
2728 colorValsUC[cpl] = colorValsUC[cpl-8]; colorValsUC[cpl+1] = colorValsUC[cpl-7];
2729 colorValsUC[cpl+2] = colorValsUC[cpl-6]; colorValsUC[cpl+3] = colorValsUC[cpl-5];
2730 } else {
2731 colorVals[cpl] = colorVals[cpl-8]; colorVals[cpl+1] = colorVals[cpl-7];
2732 colorVals[cpl+2] = colorVals[cpl-6]; colorVals[cpl+3] = colorVals[cpl-5];
2733 }
2734 pl++; vpl+=3; tpl+=2; cpl+=4; ipl++;
2735 vertexVals[vpl] = *pc; vertexVals[vpl + 1] = *(pc + 1); vertexVals[vpl + 2] = *(pc + 2);
2736 texcoordVals[tpl] = cgo->texture[0]; texcoordVals[tpl+1] = cgo->texture[1];
2737 if (colorValsUC){
2738 colorValsUC[cpl] = CLIP_COLOR_VALUE(cgo->color[0]); colorValsUC[cpl+1] = CLIP_COLOR_VALUE(cgo->color[1]);
2739 colorValsUC[cpl+2] = CLIP_COLOR_VALUE(cgo->color[2]); colorValsUC[cpl+3] = CLIP_COLOR_VALUE(cgo->alpha);
2740 } else {
2741 colorVals[cpl] = cgo->color[0]; colorVals[cpl+1] = cgo->color[1];
2742 colorVals[cpl+2] = cgo->color[2]; colorVals[cpl+3] = cgo->alpha;
2743 }
2744 pl++; ipl++;
2745 }
2746 }
2747 break;
2748 case GL_TRIANGLE_FAN:
2749 default:
2750 printf("CGOProcessScreenCGOtoArrays: WARNING: mode=%d not implemented yet GL_LINES=%d GL_LINE_STRIP=%d GL_LINE_LOOP=%d\n", mode, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP);
2751 break;
2752 }
2753 nverts++;
2754 }
2755 }
2756 }
2757 }
2758 break;
2759 }
2760 }
2761 return true;
2762 }
2763
CGOOptimizeToVBONotIndexed(CGO ** I)2764 bool CGOOptimizeToVBONotIndexed(CGO ** I) {
2765 CGO *cgo = CGOOptimizeToVBONotIndexed(*I, 0, true, NULL);
2766 CGOFree(*I);
2767 *I = cgo;
2768 return (cgo != NULL);
2769 }
2770
CGOOptimizeToVBONotIndexed(const CGO * I,int est,bool addshaders,float ** returnedData)2771 CGO *CGOOptimizeToVBONotIndexed(const CGO * I, int est, bool addshaders, float **returnedData)
2772 {
2773 CGO *cgo;
2774 int num_total_vertices = 0, num_total_indexes = 0, num_total_vertices_lines = 0, num_total_indexes_lines = 0,
2775 num_total_vertices_points = 0;
2776 short has_draw_buffer = false;
2777 float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX }, max[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
2778 int ambient_occlusion = 0;
2779 int ok = true;
2780 cgo = CGONewSized(I->G, 0);
2781
2782 CGOCountNumVertices(I, &num_total_vertices, &num_total_indexes,
2783 &num_total_vertices_lines, &num_total_indexes_lines,
2784 &num_total_vertices_points);
2785 if (num_total_vertices_points>0){
2786 if (!OptimizePointsToVBO(I, cgo, num_total_vertices_points, min, max, &has_draw_buffer, addshaders)){
2787 CGOFree(cgo);
2788 return NULL;
2789 }
2790 }
2791 if (num_total_indexes>0){
2792 float *vertexVals = 0, *colorVals = 0, *normalVals;
2793 float *pickColorVals, *accessibilityVals = 0;
2794 int tot, nxtn;
2795 uchar *colorValsUC = 0;
2796 uchar *normalValsC = 0;
2797
2798 cgo->alpha = 1.f;
2799 cgo->color[0] = 1.f; cgo->color[1] = 1.f; cgo->color[2] = 1.f;
2800
2801 tot = num_total_indexes * (3 * 6) ;
2802 // tot = num_total_indexes * (3 * 3 + 2) ;
2803 /* NOTE/TODO: Not sure why 3*5 needs to be used, but 3*3+2, which is the
2804 correct length, crashes in glBufferData */
2805 /* before allocating anything, we should check to make sure that we have enough memory on IOS,
2806 otherwise we should just fail */
2807 vertexVals = pymol::malloc<float>(tot);
2808 if (!vertexVals){
2809 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeToVBONotIndexed() vertexVals could not be allocated\n" ENDFB(I->G);
2810 CGOFree(cgo);
2811 return (NULL);
2812 }
2813 normalVals = vertexVals + 3 * num_total_indexes;
2814 nxtn = 3;
2815 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_normal)){
2816 normalValsC = (uchar*) normalVals;
2817 nxtn = 1;
2818 }
2819 colorVals = normalVals + nxtn * num_total_indexes;
2820 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color)){
2821 colorValsUC = (uchar*) colorVals;
2822 nxtn = 1;
2823 } else {
2824 nxtn = 4;
2825 }
2826 pickColorVals = (colorVals + nxtn * num_total_indexes);
2827 nxtn = 3;
2828 accessibilityVals = pickColorVals + nxtn * num_total_indexes;
2829
2830 bool has_normals = false, has_colors = false, has_accessibility = false;
2831 ok = CGOProcessCGOtoArrays(I, cgo, cgo, min, max, &ambient_occlusion,
2832 vertexVals, normalVals, normalValsC, colorVals, colorValsUC,
2833 pickColorVals, accessibilityVals, has_normals, has_colors,
2834 has_accessibility);
2835 if (!ok){
2836 if (!I->G->Interrupt)
2837 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOProcessCGOtoArrays() could not allocate enough memory\n" ENDFB(I->G);
2838 FreeP(vertexVals);
2839 CGOFree(cgo);
2840 return (NULL);
2841 }
2842 if (ok){
2843 short nsz = VERTEX_NORMAL_SIZE * 4;
2844 GLenum ntp = GL_FLOAT;
2845 bool nnorm = GL_FALSE;
2846 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_normal)){
2847 nsz = VERTEX_NORMAL_SIZE;
2848 ntp = GL_BYTE;
2849 nnorm = GL_TRUE;
2850 }
2851
2852 short csz = 4;
2853 GLenum ctp = GL_FLOAT;
2854 bool cnorm = GL_FALSE;
2855 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color)){
2856 csz = 1;
2857 ctp = GL_UNSIGNED_BYTE;
2858 cnorm = GL_TRUE;
2859 }
2860
2861 VertexBuffer * vbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>(VertexBuffer::SEQUENTIAL);
2862 BufferDataDesc bufData =
2863 { { "a_Vertex", GL_FLOAT, 3, sizeof(float) * num_total_indexes * 3, vertexVals, GL_FALSE } };
2864 if (has_normals){
2865 bufData.push_back( { "a_Normal", ntp, VERTEX_NORMAL_SIZE, (size_t)(num_total_indexes * nsz), normalVals, nnorm } );
2866 }
2867 if (has_colors){
2868 bufData.push_back( { "a_Color", ctp, 4, sizeof(float) * num_total_indexes * csz, colorVals, cnorm } );
2869 }
2870 if (has_accessibility){
2871 bufData.push_back( { "a_Accessibility", GL_FLOAT, 1, sizeof(float) * num_total_indexes, accessibilityVals, GL_FALSE } );
2872 }
2873 ok = vbo->bufferData(std::move(bufData));
2874
2875 size_t vboid = vbo->get_hash_id();
2876 // picking VBO: generate a buffer twice the size needed, for each picking pass
2877 VertexBuffer * pickvbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>(VertexBuffer::SEQUENTIAL, GL_DYNAMIC_DRAW);
2878 ok = pickvbo->bufferData({
2879 BufferDesc( "a_Color", GL_UNSIGNED_BYTE, 4, sizeof(float) * num_total_indexes, 0, GL_TRUE ),
2880 BufferDesc( "a_Color", GL_UNSIGNED_BYTE, 4, sizeof(float) * num_total_indexes, 0, GL_TRUE )
2881 });
2882 size_t pickvboid = pickvbo->get_hash_id();
2883
2884 if (ok){
2885 float *newPickColorVals ;
2886 int arrays = CGO_VERTEX_ARRAY | CGO_NORMAL_ARRAY | CGO_COLOR_ARRAY | CGO_PICK_COLOR_ARRAY;
2887 if (ambient_occlusion){
2888 arrays |= CGO_ACCESSIBILITY_ARRAY;
2889 }
2890 if (addshaders)
2891 CGOEnable(cgo, GL_DEFAULT_SHADER_WITH_SETTINGS);
2892 newPickColorVals = cgo->add<cgo::draw::buffers_not_indexed>(GL_TRIANGLES, arrays, num_total_indexes, vboid, pickvboid);
2893 if (ok && addshaders)
2894 ok &= CGODisable(cgo, GL_DEFAULT_SHADER);
2895 CHECKOK(ok, newPickColorVals);
2896 if (!newPickColorVals){
2897 I->G->ShaderMgr->freeGPUBuffer(pickvboid);
2898 I->G->ShaderMgr->freeGPUBuffer(vboid);
2899 }
2900 if (!ok){
2901 PRINTFB(I->G, FB_CGO, FB_Errors) "CGOOptimizeToVBONotIndexedWithReturnedData: ERROR: CGODrawBuffersNotIndexed() could not allocate enough memory\n" ENDFB(I->G);
2902 FreeP(vertexVals);
2903 CGOFree(cgo);
2904 return (NULL);
2905 }
2906 memcpy(newPickColorVals + num_total_indexes, pickColorVals, num_total_indexes * 2 * sizeof(float));
2907 has_draw_buffer = true;
2908 } else {
2909 I->G->ShaderMgr->freeGPUBuffer(vboid);
2910 I->G->ShaderMgr->freeGPUBuffer(pickvboid);
2911 }
2912 }
2913 if (ok && returnedData){
2914 returnedData[0] = vertexVals;
2915 } else {
2916 FreeP(vertexVals);
2917 }
2918 }
2919 if (ok && num_total_indexes_lines>0){
2920 bool has_color = false, has_normals = false;
2921 float *vertexVals = 0, *colorVals = 0, *normalVals;
2922 float *pickColorVals;
2923 int pl = 0, plc = 0, idxpl = 0, vpl = 0, tot, nxtn;
2924 uchar *colorValsUC = 0;
2925 uchar *normalValsC = 0;
2926
2927 cgo->alpha = 1.f;
2928 cgo->color[0] = 1.f; cgo->color[1] = 1.f; cgo->color[2] = 1.f;
2929
2930 tot = num_total_indexes_lines * (3 * 5) ;
2931 // tot = num_total_indexes * (3 * 3 + 2) ;
2932 /* NOTE/TODO: Not sure why 3*5 needs to be used, but 3*3+2, which is the
2933 correct length, crashes in glBufferData */
2934 vertexVals = pymol::malloc<float>(tot);
2935 if (!vertexVals){
2936 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeToVBONotIndexed() vertexVals could not be allocated\n" ENDFB(I->G);
2937 CGOFree(cgo);
2938 return (NULL);
2939 }
2940 normalVals = vertexVals + 3 * num_total_indexes_lines;
2941 nxtn = 3;
2942 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_normal)){
2943 normalValsC = (uchar*) normalVals;
2944 nxtn = 1;
2945 }
2946
2947 colorVals = normalVals + nxtn * num_total_indexes_lines;
2948 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color)){
2949 colorValsUC = (uchar*) colorVals;
2950 nxtn = 1;
2951 } else {
2952 nxtn = 4;
2953 }
2954 pickColorVals = (colorVals + nxtn * num_total_indexes_lines);
2955
2956 for (auto it = I->begin(); !it.is_stop(); ++it) {
2957 auto pc = it.data();
2958 const auto op = it.op_code();
2959
2960 switch (op) {
2961 case CGO_SPECIAL:
2962 case CGO_RESET_NORMAL:
2963 {
2964 const float *newpc = pc;
2965 cgo->add_to_cgo(op, newpc);
2966 }
2967 break;
2968 case CGO_NORMAL:
2969 has_normals = true;
2970 cgo->normal[0] = *pc; cgo->normal[1] = *(pc + 1); cgo->normal[2] = *(pc + 2);
2971 break;
2972 case CGO_COLOR:
2973 has_color = true;
2974 cgo->color[0] = *pc; cgo->color[1] = *(pc + 1); cgo->color[2] = *(pc + 2);
2975 break;
2976 case CGO_ACCESSIBILITY:
2977 cgo->current_accessibility = pc[0];
2978 break;
2979 case CGO_ALPHA:
2980 cgo->alpha = *pc;
2981 break;
2982 case CGO_PICK_COLOR:
2983 cgo->current_pick_color_index = CGO_get_uint(pc);
2984 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
2985 break;
2986 case CGO_DRAW_ARRAYS:
2987 {
2988 auto sp = it.cast<cgo::draw::arrays>();
2989 short shouldCompress = false;
2990 switch(sp->mode){
2991 case GL_LINE_LOOP:
2992 case GL_LINE_STRIP:
2993 case GL_LINES:
2994 shouldCompress = true;
2995 default:
2996 break;
2997 }
2998
2999 if (shouldCompress){
3000 int cnt, nxtn = 3, incr = 0;
3001 float *vertexValsDA = NULL, *nxtVals = NULL, *colorValsDA = NULL, *normalValsDA = NULL;
3002 float *pickColorValsDA = NULL, *pickColorValsTMP;
3003
3004 nxtVals = vertexValsDA = sp->floatdata;
3005
3006 for (cnt=0; cnt<sp->nverts*3; cnt+=3){
3007 set_min_max(min, max, &vertexValsDA[cnt]);
3008 }
3009 if (sp->arraybits & CGO_NORMAL_ARRAY){
3010 has_normals = true;
3011 nxtVals = normalValsDA = vertexValsDA + (nxtn*sp->nverts);
3012 }
3013
3014 if (sp->arraybits & CGO_COLOR_ARRAY){
3015 has_color = true;
3016 nxtVals = colorValsDA = nxtVals + (nxtn*sp->nverts);
3017 nxtn = 4;
3018 }
3019 if (sp->arraybits & CGO_PICK_COLOR_ARRAY){
3020 nxtVals = nxtVals + (nxtn*sp->nverts);
3021 pickColorValsDA = nxtVals + sp->nverts;
3022 nxtn = 3;
3023 }
3024 pickColorValsTMP = pickColorVals + (idxpl * 2);
3025 switch (sp->mode){
3026 case GL_LINES:
3027 for (cnt = 0; cnt < sp->nverts; cnt++){
3028 SetVertexValuesForVBO(I->G, cgo, pl, plc, cnt, incr++,
3029 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
3030 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
3031 pickColorValsTMP);
3032 if (incr && (incr % 2) == 0){
3033 FixPickColorsForLine(pickColorValsTMP + (incr-2) * 2,
3034 pickColorValsTMP + (incr-1) * 2);
3035 }
3036 idxpl++; pl += 3; plc += 4;
3037 }
3038 break;
3039 case GL_LINE_STRIP:
3040 for (cnt = 1; cnt < sp->nverts; cnt++){
3041 SetVertexValuesForVBO(I->G, cgo, pl, plc, cnt-1, incr++,
3042 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
3043 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
3044 pickColorValsTMP);
3045 idxpl++; pl += 3; plc += 4;
3046 SetVertexValuesForVBO(I->G, cgo, pl, plc, cnt, incr++,
3047 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
3048 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
3049 pickColorValsTMP);
3050 FixPickColorsForLine(pickColorValsTMP + (incr-2) * 2,
3051 pickColorValsTMP + (incr-1) * 2);
3052 idxpl++; pl += 3; plc += 4;
3053 }
3054 break;
3055 case GL_LINE_LOOP:
3056 for (cnt = 1; cnt < sp->nverts; cnt++){
3057 SetVertexValuesForVBO(I->G, cgo, pl, plc, cnt-1, incr++,
3058 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
3059 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
3060 pickColorValsTMP);
3061 idxpl++; pl += 3; plc += 4;
3062 SetVertexValuesForVBO(I->G, cgo, pl, plc, cnt, incr++,
3063 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
3064 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
3065 pickColorValsTMP);
3066 FixPickColorsForLine(pickColorValsTMP + (incr-2) * 2,
3067 pickColorValsTMP + (incr-1) * 2);
3068 idxpl++; pl += 3; plc += 4;
3069 }
3070 SetVertexValuesForVBO(I->G, cgo, pl, plc, 0, incr++,
3071 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
3072 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
3073 pickColorValsTMP);
3074 idxpl++; pl += 3; plc += 4;
3075 SetVertexValuesForVBO(I->G, cgo, pl, plc, sp->nverts-1, incr++,
3076 vertexValsDA, normalValsDA, colorValsDA, pickColorValsDA,
3077 vertexVals, normalValsC, normalVals, colorValsUC, colorVals,
3078 pickColorValsTMP);
3079 FixPickColorsForLine(pickColorValsTMP + (incr-2) * 2,
3080 pickColorValsTMP + (incr-1) * 2);
3081 idxpl++; pl += 3; plc += 4;
3082 break;
3083 }
3084
3085 // pl += 3 * nverts;
3086 // plc += 4 * nverts;
3087 vpl += sp->nverts;
3088 }
3089 }
3090 break;
3091 }
3092 }
3093 {
3094 short nsz = VERTEX_NORMAL_SIZE * 4;
3095 GLenum ntp = GL_FLOAT;
3096 bool nnorm = GL_FALSE;
3097 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_normal)){
3098 nsz = VERTEX_NORMAL_SIZE;
3099 ntp = GL_BYTE;
3100 nnorm = GL_TRUE;
3101 }
3102
3103 short csz = 4;
3104 GLenum ctp = GL_FLOAT;
3105 bool cnorm = GL_FALSE;
3106 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color)){
3107 csz = 1;
3108 ctp = GL_UNSIGNED_BYTE;
3109 cnorm = GL_TRUE;
3110 }
3111
3112 VertexBuffer * vbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>(VertexBuffer::SEQUENTIAL);
3113 BufferDataDesc bufData =
3114 { { "a_Vertex", GL_FLOAT, 3, sizeof(float) * num_total_indexes_lines * 3, vertexVals, GL_FALSE } };
3115
3116 if (has_normals){
3117 bufData.push_back( { "a_Normal", ntp, VERTEX_NORMAL_SIZE, (size_t)(num_total_indexes_lines * nsz), normalVals, nnorm } );
3118 }
3119 if (has_color){
3120 bufData.push_back( { "a_Color", ctp, 4, sizeof(float) * num_total_indexes_lines * csz, colorVals, cnorm } );
3121 }
3122 ok = vbo->bufferData(std::move(bufData));
3123 size_t vboid = vbo->get_hash_id();
3124
3125 // picking VBO: generate a buffer twice the size needed, for each picking pass
3126 VertexBuffer * pickvbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>(VertexBuffer::SEQUENTIAL, GL_DYNAMIC_DRAW);
3127 ok &= pickvbo->bufferData({
3128 BufferDesc( "a_Color", GL_UNSIGNED_BYTE, 4, sizeof(float) * num_total_indexes_lines, 0, GL_TRUE ),
3129 BufferDesc( "a_Color", GL_UNSIGNED_BYTE, 4, sizeof(float) * num_total_indexes_lines, 0, GL_TRUE )
3130 });
3131 size_t pickvboid = pickvbo->get_hash_id();
3132
3133 if (ok){
3134 float *newPickColorVals ;
3135 if (addshaders)
3136 CGOEnable(cgo, GL_DEFAULT_SHADER_WITH_SETTINGS);
3137 CGODisable(cgo, GL_SHADER_LIGHTING);
3138 newPickColorVals = cgo->add<cgo::draw::buffers_not_indexed>(GL_LINES, CGO_VERTEX_ARRAY | CGO_NORMAL_ARRAY | CGO_COLOR_ARRAY | CGO_PICK_COLOR_ARRAY, num_total_indexes_lines, vboid, pickvboid);
3139 if (ok && addshaders)
3140 ok &= CGODisable(cgo, GL_DEFAULT_SHADER);
3141 CHECKOK(ok, newPickColorVals);
3142 if (!ok){
3143 PRINTFB(I->G, FB_CGO, FB_Errors) "CGOOptimizeToVBONotIndexedWithReturnedData: ERROR: CGODrawBuffersNotIndexed() could not allocate enough memory\n" ENDFB(I->G);
3144 FreeP(vertexVals);
3145 CGOFree(cgo);
3146 if (!newPickColorVals) {
3147 I->G->ShaderMgr->freeGPUBuffer(pickvboid);
3148 I->G->ShaderMgr->freeGPUBuffer(vboid);
3149 }
3150 return (NULL);
3151 }
3152 memcpy(newPickColorVals + num_total_indexes_lines, pickColorVals, num_total_indexes_lines * 2 * sizeof(float));
3153 has_draw_buffer = true;
3154 } else {
3155 I->G->ShaderMgr->freeGPUBuffer(pickvboid);
3156 I->G->ShaderMgr->freeGPUBuffer(vboid);
3157 }
3158 }
3159 if (ok && returnedData){
3160 returnedData[1] = vertexVals;
3161 } else {
3162 FreeP(vertexVals);
3163 }
3164 }
3165
3166 if (ok && (num_total_vertices>0 || num_total_vertices_lines>0 || num_total_vertices_points>0)){
3167 ok &= CGOBoundingBox(cgo, min, max);
3168 }
3169
3170 if (ok)
3171 ok &= CGOStop(cgo);
3172 if (has_draw_buffer){
3173 cgo->has_draw_buffers = true;
3174 }
3175 cgo->use_shader = I->use_shader;
3176 if (cgo->use_shader){
3177 cgo->cgo_shader_ub_color = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_color);
3178 cgo->cgo_shader_ub_normal = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_normal);
3179 }
3180 if (!ok){
3181 CGOFree(cgo);
3182 }
3183 return (cgo);
3184 }
3185
CGOOptimizeToVBOIndexed(CGO * I,int est,const float * color,bool addshaders,bool embedTransparencyInfo)3186 CGO *CGOOptimizeToVBOIndexed(CGO * I, int est,
3187 const float *color, bool addshaders, bool embedTransparencyInfo)
3188 {
3189 CGO *cgo;
3190
3191 int num_total_vertices = 0, num_total_indexes = 0, num_total_vertices_lines = 0, num_total_indexes_lines = 0,
3192 num_total_vertices_points = 0;
3193 short has_draw_buffer = false;
3194 float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX }, max[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
3195 int ok = true;
3196
3197 CGOCountNumVertices(I, &num_total_vertices, &num_total_indexes,
3198 &num_total_vertices_lines, &num_total_indexes_lines,
3199 &num_total_vertices_points);
3200
3201 cgo = CGONewSized(I->G, I->c + est);
3202 CHECKOK(ok, cgo);
3203 if (ok){
3204 if (color){
3205 cgo->color[0] = color[0]; cgo->color[1] = color[1]; cgo->color[2] = color[2];
3206 cgo->alpha = color[3];
3207 } else {
3208 cgo->color[0] = 1.f; cgo->color[1] = 1.f; cgo->color[2] = 1.f;
3209 cgo->alpha = 1.f;
3210 }
3211 }
3212
3213 #if defined(_PYMOL_IOS) && !defined(_WEBGL)
3214 if (num_total_indexes > MAX_INDICES_FOR_IOS || num_total_indexes_lines > MAX_INDICES_FOR_IOS){
3215 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeToVBOIndexed() VBO Memory Limitation: The requested \n operation requires a larger buffer than PyMOL currently allows. \n The operation has not entirely completed successfully.\n" ENDFB(I->G);
3216 firePyMOLLimitationWarning();
3217 CGOFree(cgo);
3218 return NULL;
3219 }
3220 #endif
3221
3222 if (num_total_vertices_points>0){
3223 /* This does not need to be indexed (for now) */
3224 if (!OptimizePointsToVBO(I, cgo, num_total_vertices_points, min, max, &has_draw_buffer, addshaders)){
3225 CGOFree(cgo);
3226 return NULL;
3227 }
3228 }
3229
3230 if (num_total_vertices>0){
3231 float *vertexVals = 0, *colorVals = 0, *normalVals, *accessibilityVals = 0;
3232 float *pickColorVals;
3233 GL_C_INT_TYPE *vertexIndices;
3234 short vertexIndicesAllocated = 0;
3235 int pl = 0, plc = 0, idxpl = 0, vpl = 0, tot, nxtn;
3236 uchar *colorValsUC = 0;
3237 uchar *normalValsC = 0;
3238 short ambient_occlusion = 0;
3239 float *sumarray = NULL;
3240 int n_data = 0;
3241
3242 if (embedTransparencyInfo){
3243 int n_tri = num_total_indexes / 3;
3244 int bytes_to_allocate = 2 * num_total_indexes * sizeof(GL_C_INT_TYPE) + // vertexIndicesOriginal, vertexIndices
3245 3 * num_total_indexes * sizeof(float) + // 3 * for sum
3246 n_tri * sizeof(float) + 2 * n_tri * sizeof(int) + 256 * sizeof(int); // z_value (float * n_tri), ix (n_tri * int), sort_mem ((n_tri + 256) * int)
3247 // round to 4 byte words for the length of the CGO
3248 n_data = bytes_to_allocate / 4 + (((bytes_to_allocate % 4) == 0) ? 0 : 1) ;
3249 }
3250 vertexIndices = pymol::calloc<GL_C_INT_TYPE>(num_total_indexes);
3251 vertexIndicesAllocated = 1;
3252 if (!vertexIndices){
3253 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeToVBOIndexed() vertexIndices could not be allocated\n" ENDFB(I->G);
3254 CGOFree(cgo);
3255 return (NULL);
3256 }
3257 tot = num_total_vertices * (3 * 6) ;
3258 // tot = num_total_vertices * (3 * 3 + 2) ;
3259 /* NOTE/TODO: Not sure why 3*5 needs to be used, but 3*3+2, which is the
3260 correct length, crashes in glBufferData */
3261 vertexVals = pymol::malloc<float>(tot);
3262 if (!vertexVals){
3263 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeToVBOIndexed() vertexVals could not be allocated\n" ENDFB(I->G);
3264 CGOFree(cgo);
3265 return (NULL);
3266 }
3267 normalVals = vertexVals + 3 * num_total_vertices;
3268 nxtn = 3;
3269 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_normal)){
3270 normalValsC = (uchar*) normalVals;
3271 nxtn = 1;
3272 }
3273
3274 colorVals = normalVals + nxtn * num_total_vertices;
3275 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color)){
3276 colorValsUC = (uchar*) colorVals;
3277 nxtn = 1;
3278 } else {
3279 nxtn = 4;
3280 }
3281 pickColorVals = (colorVals + nxtn * num_total_vertices);
3282 accessibilityVals = pickColorVals + 3 * num_total_vertices;
3283
3284 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
3285 const auto pc = it.data();
3286 const auto op = it.op_code();
3287
3288 switch (op) {
3289 case CGO_NORMAL:
3290 cgo->normal[0] = *pc; cgo->normal[1] = *(pc + 1); cgo->normal[2] = *(pc + 2);
3291 break;
3292 case CGO_COLOR:
3293 cgo->color[0] = *pc; cgo->color[1] = *(pc + 1); cgo->color[2] = *(pc + 2);
3294 break;
3295 case CGO_ALPHA:
3296 cgo->alpha = *pc;
3297 break;
3298 case CGO_ACCESSIBILITY:
3299 cgo->current_accessibility = *pc;
3300 break;
3301 case CGO_PICK_COLOR:
3302 cgo->current_pick_color_index = CGO_get_uint(pc);
3303 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
3304 break;
3305 case CGO_DRAW_ARRAYS:
3306 {
3307 auto sp = it.cast<cgo::draw::arrays>();
3308 short shouldCompress = false;
3309 switch(sp->mode){
3310 case GL_TRIANGLE_FAN:
3311 case GL_TRIANGLE_STRIP:
3312 case GL_TRIANGLES:
3313 shouldCompress = true;
3314 default:
3315 break;
3316 }
3317 if (shouldCompress){
3318 int cnt, nxtn = 3;
3319 float *vertexValsDA = 0, *nxtVals = 0, *colorValsDA = 0, *normalValsDA, *accessibilityValsDA;
3320 float *pickColorValsDA, *pickColorValsTMP, *accessibilityValsTMP;
3321
3322 nxtVals = vertexValsDA = sp->floatdata;
3323 for (cnt=0; cnt<sp->nverts*3; cnt+=3){
3324 set_min_max(min, max, &vertexValsDA[cnt]);
3325 }
3326 for (cnt=0; cnt<sp->nverts*3; cnt++){
3327 vertexVals[pl + cnt] = vertexValsDA[cnt];
3328 }
3329 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_normal)){
3330 if (sp->arraybits & CGO_NORMAL_ARRAY){
3331 nxtVals = normalValsDA = vertexValsDA + (nxtn*sp->nverts);
3332 for (cnt=0; cnt<sp->nverts*3; cnt++){
3333 normalValsC[VAR_FOR_NORMAL + cnt VAR_FOR_NORMAL_CNT_PLUS] = CLIP_NORMAL_VALUE(normalValsDA[cnt]);
3334 }
3335 } else {
3336 uchar norm[3] = { CLIP_NORMAL_VALUE(cgo->normal[0]), CLIP_NORMAL_VALUE(cgo->normal[1]), CLIP_NORMAL_VALUE(cgo->normal[2]) };
3337 for (cnt=0; cnt<sp->nverts*3; cnt++){
3338 normalValsC[VAR_FOR_NORMAL + cnt VAR_FOR_NORMAL_CNT_PLUS] = norm[cnt%3];
3339 }
3340 }
3341 } else {
3342 if (sp->arraybits & CGO_NORMAL_ARRAY){
3343 nxtVals = normalValsDA = vertexValsDA + (nxtn*sp->nverts);
3344 for (cnt=0; cnt<sp->nverts*3; cnt++){
3345 normalVals[pl + cnt] = normalValsDA[cnt];
3346 }
3347 } else {
3348 for (cnt=0; cnt<sp->nverts*3; cnt++){
3349 normalVals[pl + cnt] = cgo->normal[cnt%3];
3350 }
3351 }
3352 }
3353 nxtn = 3;
3354 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color)){
3355 if (sp->arraybits & CGO_COLOR_ARRAY){
3356 nxtVals = colorValsDA = nxtVals + (nxtn*sp->nverts);
3357 for (cnt=0; cnt<sp->nverts*4; cnt+=4){
3358 colorValsUC[plc + cnt] = CLIP_COLOR_VALUE(colorValsDA[cnt]);
3359 colorValsUC[plc + cnt + 1] = CLIP_COLOR_VALUE(colorValsDA[cnt+1]);
3360 colorValsUC[plc + cnt + 2] = CLIP_COLOR_VALUE(colorValsDA[cnt+2]);
3361 colorValsUC[plc + cnt + 3] = CLIP_COLOR_VALUE(colorValsDA[cnt+3]);
3362 }
3363 nxtn = 4;
3364 } else {
3365 uchar col[4] = { CLIP_COLOR_VALUE(cgo->color[0]), CLIP_COLOR_VALUE(cgo->color[1]), CLIP_COLOR_VALUE(cgo->color[2]), CLIP_COLOR_VALUE(cgo->alpha) };
3366 for (cnt=0; cnt<sp->nverts*4; cnt++){
3367 colorValsUC[plc + cnt] = col[cnt%4];
3368 }
3369 }
3370 } else {
3371 if (sp->arraybits & CGO_COLOR_ARRAY){
3372 nxtVals = colorValsDA = nxtVals + (nxtn*sp->nverts);
3373 for (cnt=0; cnt<sp->nverts*4; cnt+=4){
3374 colorVals[plc + cnt] = colorValsDA[cnt];
3375 colorVals[plc + cnt + 1] = colorValsDA[cnt+1];
3376 colorVals[plc + cnt + 2] = colorValsDA[cnt+2];
3377 colorVals[plc + cnt + 3] = colorValsDA[cnt+3];
3378 }
3379 nxtn = 4;
3380 } else {
3381 float col[4] = { cgo->color[0], cgo->color[1], cgo->color[2], cgo->alpha };
3382 for (cnt=0; cnt<sp->nverts*4; cnt++){
3383 colorVals[plc + cnt] = col[cnt%4];
3384 }
3385 }
3386 }
3387 if (sp->arraybits & CGO_PICK_COLOR_ARRAY){
3388 nxtVals = nxtVals + (nxtn*sp->nverts);
3389 pickColorValsDA = nxtVals + sp->nverts;
3390 pickColorValsTMP = pickColorVals + (vpl * 2);
3391 for (cnt=0; cnt<sp->nverts; cnt++){
3392 CGO_put_int(pickColorValsTMP++, CGO_get_int(pickColorValsDA++));
3393 CGO_put_int(pickColorValsTMP++, CGO_get_int(pickColorValsDA++));
3394 }
3395 nxtn = 3;
3396 } else {
3397 pickColorValsTMP = pickColorVals + (vpl * 2);
3398 for (cnt=0; cnt<sp->nverts; cnt++){
3399 CGO_put_uint(pickColorValsTMP++, cgo->current_pick_color_index);
3400 CGO_put_int(pickColorValsTMP++, cgo->current_pick_color_bond);
3401 }
3402 }
3403 if (sp->arraybits & CGO_ACCESSIBILITY_ARRAY){
3404 if (!ambient_occlusion){
3405 for (cnt=0; cnt<vpl; cnt++){
3406 accessibilityVals[cnt] = 1.f;
3407 }
3408 }
3409 ambient_occlusion = 1;
3410 nxtVals = nxtVals + (nxtn*sp->nverts);
3411 accessibilityValsDA = nxtVals;
3412 accessibilityValsTMP = accessibilityVals + vpl;
3413 for (cnt=0; cnt<sp->nverts; cnt++){
3414 accessibilityValsTMP[cnt] = accessibilityValsDA[cnt];
3415 }
3416 } else {
3417 if (ambient_occlusion){
3418 accessibilityValsTMP = accessibilityVals + vpl;
3419 for (cnt=0; cnt<sp->nverts; cnt++){
3420 accessibilityValsTMP[cnt] = 1.f;
3421 }
3422 }
3423 }
3424 switch (sp->mode){
3425 case GL_TRIANGLES:
3426 for (cnt = 0; cnt < sp->nverts; cnt++){
3427 vertexIndices[idxpl++] = vpl + cnt;
3428 }
3429 break;
3430 case GL_TRIANGLE_STRIP:
3431 {
3432 short flip = 0;
3433 for (cnt = 2; cnt < sp->nverts; cnt++){
3434 vertexIndices[idxpl++] = vpl + cnt - (flip ? 0 : 2);
3435 vertexIndices[idxpl++] = vpl + cnt - 1;
3436 vertexIndices[idxpl++] = vpl + cnt - (flip ? 2 : 0);
3437 flip = !flip;
3438 }
3439 }
3440 break;
3441 case GL_TRIANGLE_FAN:
3442 for (cnt = 2; cnt < sp->nverts; cnt++){
3443 vertexIndices[idxpl++] = vpl;
3444 vertexIndices[idxpl++] = vpl + cnt - 1;
3445 vertexIndices[idxpl++] = vpl + cnt;
3446 }
3447 break;
3448 }
3449 pl += 3 * sp->nverts;
3450 plc += 4 * sp->nverts;
3451 vpl += sp->nverts;
3452 }
3453 }
3454 break;
3455 default:
3456 break;
3457 }
3458 ok &= !I->G->Interrupt;
3459 }
3460 if (sumarray){
3461 for (idxpl = 0; idxpl < num_total_indexes; idxpl+=3){
3462 add3f(&vertexVals[3 * vertexIndices[idxpl]], &vertexVals[3 * vertexIndices[idxpl+1]], sumarray);
3463 add3f(&vertexVals[3 * vertexIndices[idxpl+2]], sumarray, sumarray);
3464 sumarray += 3;
3465 }
3466 }
3467 if (ok) {
3468 short nsz = VERTEX_NORMAL_SIZE * 4;
3469 GLenum ntp = GL_FLOAT;
3470 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_normal)){
3471 nsz = VERTEX_NORMAL_SIZE;
3472 ntp = GL_BYTE;
3473 }
3474
3475 short csz = 4;
3476 GLenum ctp = GL_FLOAT;
3477 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color)){
3478 csz = 1;
3479 ctp = GL_UNSIGNED_BYTE;
3480 }
3481
3482 VertexBuffer * vbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>();
3483 ok &= vbo->bufferData({
3484 BufferDesc( "a_Vertex", GL_FLOAT, 3, sizeof(float) * num_total_vertices * 3, vertexVals, GL_FALSE ),
3485 BufferDesc( "a_Normal", ntp, VERTEX_NORMAL_SIZE, num_total_vertices * nsz, normalVals, GL_FALSE ),
3486 BufferDesc( "a_Color", ctp, 4, sizeof(float) * num_total_vertices * csz, colorVals, GL_TRUE ),
3487 BufferDesc( "a_Accessibility", GL_FLOAT, 1, sizeof(float) * num_total_vertices, accessibilityVals, GL_FALSE )
3488 });
3489
3490 IndexBuffer * ibo = I->G->ShaderMgr->newGPUBuffer<IndexBuffer>();
3491 ok &= ibo->bufferData({
3492 BufferDesc( GL_UNSIGNED_INT, sizeof(GL_C_INT_TYPE) * num_total_indexes, vertexIndices )
3493 });
3494
3495 size_t vboid = vbo->get_hash_id();
3496 size_t iboid = ibo->get_hash_id();
3497
3498 VertexBuffer * pickvbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>(VertexBuffer::SEQUENTIAL, GL_DYNAMIC_DRAW);
3499 ok &= pickvbo->bufferData({
3500 BufferDesc( "a_Color", GL_UNSIGNED_BYTE, 4, sizeof(float) * num_total_indexes, 0, GL_TRUE ),
3501 BufferDesc( "a_Color", GL_UNSIGNED_BYTE, 4, sizeof(float) * num_total_indexes, 0, GL_TRUE )
3502 });
3503 size_t pickvboid = pickvbo->get_hash_id();
3504
3505 if (ok) {
3506 float *newPickColorVals ;
3507 int arrays = CGO_VERTEX_ARRAY | CGO_NORMAL_ARRAY | CGO_COLOR_ARRAY | CGO_PICK_COLOR_ARRAY;
3508 if (ambient_occlusion){
3509 arrays |= CGO_ACCESSIBILITY_ARRAY;
3510 }
3511 if (addshaders)
3512 CGOEnable(cgo, GL_DEFAULT_SHADER);
3513 newPickColorVals = cgo->add<cgo::draw::buffers_indexed>(GL_TRIANGLES, arrays, num_total_indexes, num_total_vertices, vboid, iboid, n_data, pickvboid);
3514 if (embedTransparencyInfo){
3515 int n_tri = num_total_indexes/3;
3516 float *sumarray;
3517 float *sum = sumarray = newPickColorVals + num_total_vertices*3;
3518 float *z_value = sum + (num_total_indexes*3);
3519 int *ix = (int *)z_value + n_tri;
3520 int *sort_mem = ix + n_tri;
3521 GL_C_INT_TYPE *vertexIndicesOriginalTI = (GL_C_INT_TYPE *)(sort_mem + n_tri + 256);
3522
3523 for (idxpl = 0; idxpl < num_total_indexes; idxpl+=3){
3524 add3f(&vertexVals[3 * vertexIndices[idxpl]], &vertexVals[3 * vertexIndices[idxpl+1]], sumarray);
3525 add3f(&vertexVals[3 * vertexIndices[idxpl+2]], sumarray, sumarray);
3526 sumarray += 3;
3527 }
3528 memcpy(vertexIndicesOriginalTI, vertexIndices, sizeof(GL_C_INT_TYPE) * num_total_indexes);
3529 }
3530
3531 if (addshaders && ok)
3532 ok &= CGODisable(cgo, GL_DEFAULT_SHADER);
3533 CHECKOK(ok, newPickColorVals);
3534 if (!newPickColorVals){
3535 I->G->ShaderMgr->freeGPUBuffer(pickvboid);
3536 I->G->ShaderMgr->freeGPUBuffer(vboid);
3537 I->G->ShaderMgr->freeGPUBuffer(iboid);
3538 }
3539 if (ok)
3540 memcpy(newPickColorVals + num_total_vertices, pickColorVals, num_total_vertices * 2 * sizeof(float));
3541 has_draw_buffer = true;
3542 } else {
3543 I->G->ShaderMgr->freeGPUBuffer(pickvboid);
3544 I->G->ShaderMgr->freeGPUBuffer(vboid);
3545 I->G->ShaderMgr->freeGPUBuffer(iboid);
3546 }
3547 }
3548 if (vertexIndicesAllocated)
3549 FreeP(vertexIndices);
3550 FreeP(vertexVals);
3551 }
3552 if (ok && num_total_vertices_lines>0){
3553 float *vertexVals = 0, *colorVals = 0, *normalVals = NULL, *nxtVals;
3554 float *pickColorVals;
3555 GL_C_INT_TYPE *vertexIndexes;
3556 uchar *colorValsUC = 0;
3557 uchar *normalValsC = 0;
3558 int pl = 0, plc = 0, idxpl = 0, vpl = 0, tot, sz;
3559 bool hasNormals = 0;
3560
3561 hasNormals = !CGOHasAnyLineVerticesWithoutNormals(I);
3562 vertexIndexes = pymol::malloc<GL_C_INT_TYPE>(num_total_indexes_lines);
3563 if (!vertexIndexes){
3564 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeToVBOIndexed() vertexIndexes could not be allocated\n" ENDFB(I->G);
3565 CGOFree(cgo);
3566 return (NULL);
3567 }
3568 tot = num_total_vertices_lines * (3 * 5) ;
3569 // tot = num_total_vertices * (3 * 3 + 2) ;
3570 /* NOTE/TODO: Not sure why 3*5 needs to be used, but 3*3+2, which is the
3571 correct length, crashes in glBufferData */
3572 vertexVals = pymol::malloc<float>(tot);
3573 if (!vertexVals){
3574 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeToVBOIndexed() vertexVals could not be allocated\n" ENDFB(I->G);
3575 CGOFree(cgo);
3576 return (NULL);
3577 }
3578 nxtVals = vertexVals + 3 * num_total_vertices_lines;
3579 sz = 3;
3580 if (hasNormals){
3581 normalVals = nxtVals;
3582 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_normal)){
3583 normalValsC = (uchar*) normalVals;
3584 sz = 1;
3585 }
3586 }
3587 colorVals = nxtVals + sz * num_total_vertices_lines;
3588 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color)){
3589 colorValsUC = (uchar*) colorVals;
3590 sz = 1;
3591 } else {
3592 sz = 4;
3593 }
3594 pickColorVals = (colorVals + sz * num_total_vertices_lines);
3595
3596 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
3597 const auto pc = it.data();
3598 const auto op = it.op_code();
3599
3600 switch (op) {
3601 case CGO_NORMAL:
3602 cgo->normal[0] = *pc; cgo->normal[1] = *(pc + 1); cgo->normal[2] = *(pc + 2);
3603 break;
3604 case CGO_COLOR:
3605 cgo->color[0] = *pc; cgo->color[1] = *(pc + 1); cgo->color[2] = *(pc + 2);
3606 break;
3607 case CGO_ACCESSIBILITY:
3608 cgo->current_accessibility = *pc;
3609 break;
3610 case CGO_ALPHA:
3611 cgo->alpha = *pc;
3612 break;
3613 case CGO_PICK_COLOR:
3614 cgo->current_pick_color_index = CGO_get_uint(pc);
3615 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
3616 break;
3617 case CGO_DRAW_ARRAYS:
3618 {
3619 auto sp = it.cast<cgo::draw::arrays>();
3620 short shouldCompress = false;
3621 switch(sp->mode){
3622 case GL_LINE_LOOP:
3623 case GL_LINE_STRIP:
3624 case GL_LINES:
3625 shouldCompress = true;
3626 default:
3627 break;
3628 }
3629 if (shouldCompress){
3630 int cnt, nxtn = 3;
3631 float *vertexValsDA = 0, *nxtVals2 = 0, *colorValsDA = 0, *normalValsDA = 0;
3632 float *pickColorValsDA = 0, *pickColorValsTMP;
3633
3634 nxtVals2 = vertexValsDA = sp->floatdata;
3635 for (cnt=0; cnt<sp->nverts*3; cnt+=3){
3636 set_min_max(min, max, &vertexValsDA[cnt]);
3637 }
3638 for (cnt=0; cnt<sp->nverts*3; cnt++){
3639 vertexVals[pl + cnt] = vertexValsDA[cnt];
3640 }
3641 if (normalVals){
3642 if (sp->arraybits & CGO_NORMAL_ARRAY){
3643 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_normal)){
3644 nxtVals2 = normalValsDA = nxtVals2 + (nxtn*sp->nverts);
3645 for (cnt=0; cnt<sp->nverts*3; cnt++){
3646 normalValsC[VAR_FOR_NORMAL + cnt VAR_FOR_NORMAL_CNT_PLUS] = CLIP_NORMAL_VALUE(normalValsDA[cnt]);
3647 }
3648 } else {
3649 nxtVals2 = normalValsDA = nxtVals2 + (nxtn*sp->nverts);
3650 for (cnt=0; cnt<sp->nverts*3; cnt++){
3651 normalVals[VAR_FOR_NORMAL + cnt] = normalValsDA[cnt];
3652 }
3653 }
3654 }
3655 }
3656 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color)){
3657 if (sp->arraybits & CGO_COLOR_ARRAY){
3658 nxtVals2 = colorValsDA = nxtVals2 + (nxtn*sp->nverts);
3659 for (cnt=0; cnt<sp->nverts*4; cnt++){
3660 colorValsUC[plc + cnt] = CLIP_COLOR_VALUE(colorValsDA[cnt]);
3661 }
3662 nxtn = 4;
3663 } else {
3664 uchar col[4] = { CLIP_COLOR_VALUE(cgo->color[0]), CLIP_COLOR_VALUE(cgo->color[1]), CLIP_COLOR_VALUE(cgo->color[2]), CLIP_COLOR_VALUE(cgo->alpha) };
3665 for (cnt=0; cnt<sp->nverts*4; cnt++){
3666 colorValsUC[plc + cnt] = col[cnt%4];
3667 }
3668 }
3669 } else {
3670 if (sp->arraybits & CGO_COLOR_ARRAY){
3671 nxtVals2 = colorValsDA = nxtVals2 + (nxtn*sp->nverts);
3672 for (cnt=0; cnt<sp->nverts*4; cnt++){
3673 colorVals[plc + cnt] = colorValsDA[cnt];
3674 }
3675 nxtn = 4;
3676 } else {
3677 float col[4] = { cgo->color[0], cgo->color[1], cgo->color[2], cgo->alpha };
3678 for (cnt=0; cnt<sp->nverts*4; cnt++){
3679 colorVals[plc + cnt] = col[cnt%4];
3680 }
3681 }
3682 }
3683 if (sp->arraybits & CGO_PICK_COLOR_ARRAY){
3684 nxtVals2 = nxtVals2 + (nxtn*sp->nverts);
3685 pickColorValsDA = nxtVals2 + sp->nverts;
3686 pickColorValsTMP = pickColorVals + (vpl * 2);
3687 for (cnt=0; cnt<sp->nverts; cnt++){
3688 CGO_put_int(pickColorValsTMP++, CGO_get_int(pickColorValsDA++));
3689 CGO_put_int(pickColorValsTMP++, CGO_get_int(pickColorValsDA++));
3690 }
3691 nxtn = 3;
3692 } else {
3693 pickColorValsTMP = pickColorVals + (vpl * 2);
3694 for (cnt=0; cnt<sp->nverts; cnt++){
3695 CGO_put_uint(pickColorValsTMP++, cgo->current_pick_color_index);
3696 CGO_put_int(pickColorValsTMP++, cgo->current_pick_color_bond);
3697 }
3698 }
3699 if (idxpl + sp->nverts > num_total_indexes_lines){
3700 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeToVBOIndexed() num_total_indexes_lines=%d mode=%d nverts=%d idxpl=%d\n", num_total_indexes_lines, sp->mode, sp->nverts, idxpl ENDFB(I->G);
3701 }
3702 switch (sp->mode){
3703 case GL_LINES:
3704 for (cnt = 0; cnt < sp->nverts; cnt++){
3705 vertexIndexes[idxpl++] = vpl + cnt;
3706 }
3707 break;
3708 case GL_LINE_STRIP:
3709 for (cnt = 1; cnt < sp->nverts; cnt++){
3710 vertexIndexes[idxpl++] = vpl + cnt - 1;
3711 vertexIndexes[idxpl++] = vpl + cnt;
3712 }
3713 break;
3714 case GL_LINE_LOOP:
3715 for (cnt = 1; cnt < sp->nverts; cnt++){
3716 vertexIndexes[idxpl++] = vpl + cnt - 1;
3717 vertexIndexes[idxpl++] = vpl + cnt;
3718 }
3719 vertexIndexes[idxpl++] = vpl;
3720 vertexIndexes[idxpl++] = vpl + sp->nverts - 1;
3721 break;
3722 }
3723
3724 pl += 3 * sp->nverts;
3725 plc += 4 * sp->nverts;
3726 vpl += sp->nverts;
3727 }
3728 }
3729 break;
3730 case CGO_SPECIAL:
3731 CGOSpecial(cgo, CGO_get_int(pc));
3732 }
3733 ok &= !I->G->Interrupt;
3734 }
3735 if (ok) {
3736 short nsz = VERTEX_NORMAL_SIZE * 4;
3737 GLenum ntp = GL_FLOAT;
3738 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_normal)){
3739 nsz = VERTEX_NORMAL_SIZE;
3740 ntp = GL_BYTE;
3741 }
3742
3743 short csz = 4;
3744 GLenum ctp = GL_FLOAT;
3745 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color)){
3746 csz = 1;
3747 ctp = GL_UNSIGNED_BYTE;
3748 }
3749
3750 VertexBuffer * vbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>();
3751 ok &= vbo->bufferData({
3752 BufferDesc( "a_Vertex", GL_FLOAT, 3, sizeof(float) * num_total_vertices_lines * 3, vertexVals, GL_FALSE ),
3753 BufferDesc( "a_Normal", ntp, VERTEX_NORMAL_SIZE, num_total_vertices_lines * nsz, normalVals, GL_FALSE ),
3754 BufferDesc( "a_Color", ctp, 4, sizeof(float) * num_total_vertices_lines * csz, colorVals, GL_TRUE )
3755 });
3756
3757 IndexBuffer * ibo = I->G->ShaderMgr->newGPUBuffer<IndexBuffer>();
3758 ok &= ibo->bufferData({
3759 BufferDesc( GL_UNSIGNED_INT, sizeof(GL_C_INT_TYPE) * num_total_indexes_lines, vertexIndexes )
3760 });
3761
3762 size_t vboid = vbo->get_hash_id();
3763 size_t iboid = ibo->get_hash_id();
3764
3765 VertexBuffer * pickvbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>(VertexBuffer::SEQUENTIAL, GL_DYNAMIC_DRAW);
3766 ok &= pickvbo->bufferData({
3767 BufferDesc( "a_Color", GL_UNSIGNED_BYTE, 4, sizeof(float) * num_total_indexes, 0, GL_TRUE ),
3768 BufferDesc( "a_Color", GL_UNSIGNED_BYTE, 4, sizeof(float) * num_total_indexes, 0, GL_TRUE )
3769 });
3770 size_t pickvboid = pickvbo->get_hash_id();
3771
3772 if (ok){
3773 float *newPickColorVals ;
3774 if (addshaders){
3775 CGOEnable(cgo, GL_DEFAULT_SHADER);
3776 CGODisable(cgo, GL_SHADER_LIGHTING);
3777 }
3778 newPickColorVals = cgo->add<cgo::draw::buffers_indexed>(GL_LINES,
3779 CGO_VERTEX_ARRAY | CGO_NORMAL_ARRAY |
3780 CGO_COLOR_ARRAY | CGO_PICK_COLOR_ARRAY,
3781 num_total_indexes_lines,
3782 num_total_vertices_lines, vboid, iboid, 0, pickvboid);
3783 CHECKOK(ok, newPickColorVals);
3784 if (addshaders && ok)
3785 ok &= CGODisable(cgo, GL_DEFAULT_SHADER);
3786 if (!newPickColorVals) {
3787 I->G->ShaderMgr->freeGPUBuffer(pickvboid);
3788 I->G->ShaderMgr->freeGPUBuffer(vboid);
3789 I->G->ShaderMgr->freeGPUBuffer(iboid);
3790 }
3791 if (ok)
3792 memcpy(newPickColorVals + num_total_vertices_lines,
3793 pickColorVals, num_total_vertices_lines * 2 * sizeof(float));
3794 has_draw_buffer = true;
3795 } else {
3796 I->G->ShaderMgr->freeGPUBuffer(pickvboid);
3797 I->G->ShaderMgr->freeGPUBuffer(vboid);
3798 I->G->ShaderMgr->freeGPUBuffer(iboid);
3799 }
3800 }
3801 FreeP(vertexIndexes);
3802 FreeP(vertexVals);
3803 }
3804 if (ok && (num_total_vertices>0 || num_total_vertices_lines>0)){
3805 ok &= CGOBoundingBox(cgo, min, max);
3806 }
3807
3808 if (ok)
3809 ok &= CGOStop(cgo);
3810 if (ok){
3811 if (has_draw_buffer){
3812 cgo->has_draw_buffers = true;
3813 }
3814 cgo->use_shader = I->use_shader;
3815 if (cgo->use_shader){
3816 cgo->cgo_shader_ub_color = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_color);
3817 cgo->cgo_shader_ub_normal = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_normal);
3818 }
3819 }
3820 if (!ok){
3821 CGOFree(cgo);
3822 }
3823 return (cgo);
3824 }
3825
CGOOptimizeSpheresToVBONonIndexed(const CGO * I,int est,bool addshaders,CGO * leftOverCGO)3826 CGO *CGOOptimizeSpheresToVBONonIndexed(const CGO * I, int est, bool addshaders, CGO *leftOverCGO)
3827 {
3828 CGO *cgo = NULL;
3829
3830 int rightup_flags[4] = { 0, 1, 3, 2 };
3831 int num_total_spheres = 0;
3832 short has_draw_buffer = false;
3833 float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX }, max[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
3834 int vv, total_vert = 0, total_spheres = 0;
3835 int ok = true;
3836
3837 num_total_spheres = CGOCountNumberOfOperationsOfType(I, CGO_SPHERE);
3838 if (num_total_spheres>0) {
3839 float *vertVals = 0;
3840 GLubyte *rightUpFlagValsUB = 0;
3841 float *rightUpFlagVals = 0;
3842 GLubyte *colorValsUB = 0;
3843 int tot = VERTICES_PER_SPHERE * 4 * num_total_spheres;
3844 float *org_vertVals = NULL;
3845 GLubyte *org_colorValsUB = NULL;
3846 int *org_pickcolorVals = NULL, *pickcolorVals = NULL;
3847 GLubyte *org_rightUpFlagValsUB = NULL;
3848 float *org_rightUpFlagVals = NULL;
3849 float min_alpha;
3850 short cgo_shader_ub_flags;
3851 bool copyNormalToLeftOver, copyColorToLeftOver, copyPickColorToLeftOver, copyAlphaToLeftOver ;
3852 bool has_picking = CGOHasOperationsOfType(I, CGO_PICK_COLOR);
3853
3854 cgo = CGONewSized(I->G, I->c + est);
3855
3856 cgo_shader_ub_flags = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_flags);
3857
3858 org_vertVals = vertVals = pymol::malloc<float>(tot);
3859 if (!org_vertVals){
3860 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeSpheresToVBONonIndexed() org_vertVals could not be allocated\n" ENDFB(I->G);
3861 CGOFree(cgo);
3862 return (NULL);
3863 }
3864
3865 org_colorValsUB = colorValsUB = pymol::malloc<GLubyte>(tot);
3866 if (!org_colorValsUB){
3867 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeSpheresToVBONonIndexed() org_colorValsUB could not be allocated\n" ENDFB(I->G);
3868 FreeP(org_vertVals);
3869 CGOFree(cgo);
3870 return (NULL);
3871 }
3872
3873 if (cgo_shader_ub_flags){
3874 org_rightUpFlagValsUB = rightUpFlagValsUB = pymol::malloc<GLubyte>(VALUES_PER_IMPOSTER_SPACE_COORD * VERTICES_PER_SPHERE * num_total_spheres);
3875 if (!org_rightUpFlagValsUB){
3876 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeSpheresToVBONonIndexed() org_rightUpFlagValsUB could not be allocated\n" ENDFB(I->G);
3877 FreeP(org_colorValsUB); FreeP(org_vertVals);
3878 CGOFree(cgo);
3879 return (NULL);
3880 }
3881 } else {
3882 org_rightUpFlagVals = rightUpFlagVals = pymol::malloc<float>(VALUES_PER_IMPOSTER_SPACE_COORD * VERTICES_PER_SPHERE * num_total_spheres);
3883 if (!org_rightUpFlagVals){
3884 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeSpheresToVBONonIndexed() org_rightUpFlagVals could not be allocated\n" ENDFB(I->G);
3885 FreeP(org_colorValsUB); FreeP(org_vertVals);
3886 CGOFree(cgo);
3887 return (NULL);
3888 }
3889 }
3890 if (has_picking){
3891 // atom/bond info for picking, 2 ints for each sphere
3892 org_pickcolorVals = pickcolorVals = pymol::malloc<int>(num_total_spheres * 2 * 4);
3893 }
3894
3895 cgo->alpha = 1.f;
3896 min_alpha = 1.f;
3897 copyNormalToLeftOver = copyColorToLeftOver = copyPickColorToLeftOver = copyAlphaToLeftOver = 0;
3898
3899 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
3900 const auto op = it.op_code();
3901 const auto pc = it.data();
3902
3903 switch (op) {
3904 case CGO_NORMAL:
3905 cgo->normal[0] = *pc; cgo->normal[1] = *(pc + 1); cgo->normal[2] = *(pc + 2);
3906 copyNormalToLeftOver = true;
3907 break;
3908 case CGO_COLOR:
3909 cgo->color[0] = *pc; cgo->color[1] = *(pc + 1); cgo->color[2] = *(pc + 2);
3910 copyColorToLeftOver = true;
3911 break;
3912 case CGO_ALPHA:
3913 cgo->alpha = *pc;
3914 if (cgo->alpha < min_alpha) min_alpha = cgo->alpha;
3915 copyAlphaToLeftOver = true;
3916 break;
3917 case CGO_PICK_COLOR:
3918 cgo->current_pick_color_index = CGO_get_uint(pc);
3919 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
3920 copyPickColorToLeftOver = true;
3921 break;
3922 case CGO_SPHERE:
3923 for (vv=0; vv<VERTICES_PER_SPHERE; vv++) { // generate eight vertices of a bounding box for each cylinder
3924 vertVals[0] = *(pc);
3925 vertVals[1] = *(pc+1);
3926 vertVals[2] = *(pc+2);
3927 vertVals[3] = *(pc+3);
3928 set_min_max(min, max, vertVals);
3929 if (cgo_shader_ub_flags){
3930 rightUpFlagValsUB[0] = rightup_flags[vv];
3931 rightUpFlagValsUB++;
3932 } else {
3933 rightUpFlagVals[0] = rightup_flags[vv];
3934 rightUpFlagVals++;
3935 }
3936 colorValsUB[0] = CLIP_COLOR_VALUE(cgo->color[0]);
3937 colorValsUB[1] = CLIP_COLOR_VALUE(cgo->color[1]);
3938 colorValsUB[2] = CLIP_COLOR_VALUE(cgo->color[2]);
3939 colorValsUB[3] = CLIP_COLOR_VALUE(cgo->alpha);
3940 colorValsUB += 4;
3941 vertVals += 4;
3942 total_vert++;
3943 }
3944 if (has_picking){
3945 *(pickcolorVals++) = cgo->current_pick_color_index;
3946 *(pickcolorVals++) = cgo->current_pick_color_bond;
3947 }
3948 total_spheres++;
3949 break;
3950 case CGO_DRAW_BUFFERS_INDEXED:
3951 case CGO_DRAW_BUFFERS_NOT_INDEXED:
3952 PRINTFB(I->G, FB_CGO, FB_Warnings) "WARNING: CGOOptimizeSpheresToVBONonIndexed() CGO_DRAW_BUFFERS_INDEXED or CGO_DRAW_BUFFERS_INDEXED encountered op=%d\n", op ENDFB(I->G);
3953 break;
3954 case CGO_DRAW_SCREEN_TEXTURES_AND_POLYGONS:
3955 PRINTFB(I->G, FB_CGO, FB_Warnings) "WARNING: CGOOptimizeCylindersToVBO() CGO_DRAW_SCREEN_TEXTURES_AND_POLYGONS encountered op=0x%X\n", op ENDFB(I->G);
3956 break;
3957 case CGO_DRAW_LABELS:
3958 PRINTFB(I->G, FB_CGO, FB_Warnings) "WARNING: CGOOptimizeCylindersToVBO() CGO_DRAW_LABELS encountered op=0x%X\n", op ENDFB(I->G);
3959 break;
3960 case CGO_DRAW_TEXTURES:
3961 PRINTFB(I->G, FB_CGO, FB_Warnings) "WARNING: CGOOptimizeCylindersToVBO() CGO_DRAW_TEXTURES encountered op=0x%X\n", op ENDFB(I->G);
3962 break;
3963 case CGO_DRAW_ARRAYS:
3964 default:
3965 if (!leftOverCGO)
3966 break;
3967 if (copyAlphaToLeftOver){
3968 copyAlphaToLeftOver = false;
3969 CGOAlpha(leftOverCGO, cgo->alpha);
3970 }
3971 if (copyColorToLeftOver){
3972 copyColorToLeftOver = false;
3973 CGOColor(leftOverCGO, cgo->color[0], cgo->color[1], cgo->color[2] );
3974 }
3975 if (copyNormalToLeftOver){
3976 CGONormalv(leftOverCGO, cgo->normal );
3977 }
3978 if (copyPickColorToLeftOver){
3979 copyPickColorToLeftOver = false;
3980 CGOPickColor(leftOverCGO, cgo->current_pick_color_index, cgo->current_pick_color_bond);
3981 }
3982 leftOverCGO->add_to_cgo(op, pc);
3983 }
3984 #ifndef _WEBGL
3985 ok &= !I->G->Interrupt;
3986 #endif
3987 }
3988 if (ok && total_spheres > 0) {
3989 GLenum rtp = GL_FLOAT;
3990 short rsz = sizeof(float);
3991 void * radiusptr = (void *)org_rightUpFlagVals;
3992 if (cgo_shader_ub_flags) {
3993 rtp = GL_UNSIGNED_BYTE;
3994 rsz = sizeof(GLubyte);
3995 radiusptr = (void *)org_rightUpFlagValsUB;
3996 }
3997
3998 VertexBuffer * vbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>();
3999 ok &= vbo->bufferData({
4000 BufferDesc( "a_vertex_radius", GL_FLOAT, 4, sizeof(float) * total_vert * 4, org_vertVals, GL_FALSE ),
4001 BufferDesc( "a_Color", GL_UNSIGNED_BYTE, 4, sizeof(float) * total_vert, org_colorValsUB, GL_TRUE ),
4002 BufferDesc( "a_rightUpFlags", rtp, VALUES_PER_IMPOSTER_SPACE_COORD, rsz * total_vert * VALUES_PER_IMPOSTER_SPACE_COORD, radiusptr, GL_FALSE )
4003 });
4004 size_t vboid = vbo->get_hash_id();
4005
4006 VertexBuffer * pickvbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>(VertexBuffer::SEQUENTIAL, GL_DYNAMIC_DRAW);
4007 ok &= pickvbo->bufferData({
4008 BufferDesc( "a_Color", GL_UNSIGNED_BYTE, 4, 0, GL_TRUE ),
4009 BufferDesc( "a_Color", GL_UNSIGNED_BYTE, 4, sizeof(float) * total_vert, GL_TRUE )
4010 }, 0, sizeof(float) * total_vert * 2, 0);
4011 size_t pickvboid = pickvbo->get_hash_id();
4012
4013 has_draw_buffer = true;
4014
4015 auto freebuffers = [vboid, pickvboid, I]() {
4016 I->G->ShaderMgr->freeGPUBuffer(vboid);
4017 I->G->ShaderMgr->freeGPUBuffer(pickvboid);
4018 };
4019 if (ok){
4020 int *pickcolor_data;
4021 if (addshaders)
4022 CGOEnable(cgo, GL_SPHERE_SHADER);
4023 pickcolor_data = (int*)cgo->add<cgo::draw::sphere_buffers>(total_spheres, (cgo_shader_ub_flags ? 3 : 1), vboid, pickvboid); // always cgo_shader_ub_color
4024 CHECKOK(ok, pickcolor_data);
4025 if (ok && has_picking){
4026 memcpy(pickcolor_data, org_pickcolorVals, num_total_spheres * 2 * 4);
4027 }
4028 if (ok && addshaders)
4029 ok &= CGODisable(cgo, GL_SPHERE_SHADER);
4030 if (!ok){
4031 freebuffers();
4032 }
4033 } else {
4034 freebuffers();
4035 }
4036 }
4037
4038 FreeP(org_pickcolorVals);
4039 FreeP(org_vertVals);
4040 FreeP(org_colorValsUB);
4041 if (cgo_shader_ub_flags){
4042 FreeP(org_rightUpFlagValsUB);
4043 } else {
4044 FreeP(org_rightUpFlagVals);
4045 }
4046
4047 if (ok && num_total_spheres>0){
4048 ok &= CGOBoundingBox(cgo, min, max);
4049 }
4050
4051 if (ok)
4052 ok &= CGOStop(cgo);
4053
4054 if (ok){
4055 if (has_draw_buffer){
4056 cgo->has_draw_buffers = true;
4057 cgo->has_draw_sphere_buffers = true;
4058 }
4059 cgo->use_shader = I->use_shader;
4060 if (cgo->use_shader){
4061 cgo->cgo_shader_ub_color = true;
4062 cgo->cgo_shader_ub_normal = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_normal);
4063 }
4064 }
4065 }
4066 if (!ok){
4067 CGOFree(cgo);
4068 }
4069 return (cgo);
4070 }
4071
4072 /*
4073 * converts a CGO that has primitives into pure geometry,
4074 * and converts CGO_BEGIN/CGO_END blocks into CGO_DRAW_ARRAYS
4075 * operations, similar to what CGOCombineBeginEnd() does.
4076 *
4077 * I: input CGO
4078 * est: initial size of the newly allocated CGO array
4079 * that is returned by this function
4080 * sphere_quality: the quality of the spheres generated by this function
4081 * (if -1, defaults to cgo_sphere_quality)
4082 * stick_round_nub: if true, a round cap is generated, otherwise, it generates
4083 * the old "pointed" caps
4084 */
CGOSimplify(const CGO * I,int est,short sphere_quality,bool stick_round_nub)4085 CGO *CGOSimplify(const CGO * I, int est, short sphere_quality, bool stick_round_nub)
4086 {
4087 auto G = I->G;
4088 int ok = true;
4089 if (sphere_quality < 0){
4090 sphere_quality = SettingGet_i(I->G, NULL, NULL, cSetting_cgo_sphere_quality);
4091 }
4092
4093 std::unique_ptr<CGO> cgo_managed(CGONew(G, I->c + est));
4094 auto* const cgo = cgo_managed.get();
4095 RETURN_VAL_IF_FAIL(cgo, nullptr);
4096
4097 for (auto it = I->begin(); !it.is_stop(); ++it) {
4098 const auto op = it.op_code();
4099 const auto pc = it.data();
4100
4101 switch (op) {
4102 case CGO_COLOR:
4103 copy3f(pc, cgo->color);
4104 CGOColorv(cgo, pc);
4105 break;
4106 case CGO_PICK_COLOR:
4107 CGOPickColor(cgo, CGO_get_uint(pc), CGO_get_int(pc + 1));
4108 break;
4109 case CGO_SHADER_CYLINDER:
4110 {
4111 float v2[3];
4112 int cap = CGO_get_int(pc + 7);
4113 int fcap = (cap & 1) ? ((cap & cCylShaderCap1RoundBit) ? 2 : 1) : 0;
4114 int bcap = (cap & 2) ? ((cap & cCylShaderCap2RoundBit) ? 2 : 1) : 0;
4115 add3f(pc, pc + 3, v2);
4116 ok &= CGOSimpleCylinder(cgo, pc, v2, *(pc + 6), 0, 0, cgo->alpha, cgo->alpha, (cap & cCylShaderInterpColor),
4117 fcap, bcap, nullptr, stick_round_nub);
4118 }
4119 break;
4120 case CGO_SHADER_CYLINDER_WITH_2ND_COLOR:
4121 {
4122 auto cyl = it.cast<cgo::draw::shadercylinder2ndcolor>();
4123 float v1[3];
4124 int cap = cyl->cap;
4125 int fcap = (cap & 1) ? ((cap & cCylShaderCap1RoundBit) ? 2 : 1) : 0;
4126 int bcap = (cap & 2) ? ((cap & cCylShaderCap2RoundBit) ? 2 : 1) : 0;
4127 Pickable pickcolor2 = { cyl->pick_color_index, cyl->pick_color_bond };
4128 float color1[3] = { cgo->color[0], cgo->color[1], cgo->color[2] };
4129 add3f(pc, pc + 3, v1);
4130 float mid[3];
4131 mult3f(cyl->axis, .5f, mid);
4132 add3f(cyl->origin, mid, mid);
4133 float alpha2 = cyl->alpha >= 0.f ? cyl->alpha : cgo->alpha;
4134 if (cap & cCylShaderInterpColor){
4135 ok &= CGOSimpleCylinder(cgo, cyl->origin, v1, cyl->tube_size, color1, cyl->color2, cgo->alpha, alpha2, true, bcap, fcap, &pickcolor2, stick_round_nub);
4136 } else {
4137 ok &= CGOColorv(cgo, color1);
4138 ok &= CGOSimpleCylinder(cgo, cyl->origin, mid, cyl->tube_size, color1, NULL, cgo->alpha, alpha2, false, fcap, 0, nullptr, stick_round_nub);
4139 ok &= CGOColorv(cgo, cyl->color2);
4140 ok &= CGOPickColor(cgo, pickcolor2.index, pickcolor2.bond);
4141 ok &= CGOSimpleCylinder(cgo, mid, v1, cyl->tube_size, cyl->color2, NULL, cgo->alpha, alpha2, false, 0, bcap, nullptr, stick_round_nub);
4142 }
4143 }
4144 break;
4145 case CGO_CYLINDER:
4146 {
4147 auto cyl = it.cast<cgo::draw::cylinder>();
4148 ok &= CGOSimpleCylinder(cgo, *cyl, cgo->alpha, cgo->alpha, true, 1, 1, nullptr, stick_round_nub);
4149 }
4150 break;
4151 case CGO_CONE:
4152 ok &= CGOSimpleCone(cgo, pc, pc + 3, *(pc + 6), *(pc + 7), pc + 8, pc + 11,
4153 (int) *(pc + 14), (int) *(pc + 15));
4154 break;
4155 case CGO_SAUSAGE:
4156 ok &= CGOSimpleCylinder(cgo, pc, pc + 3, *(pc + 6), pc + 7, pc + 10, cgo->alpha, cgo->alpha, true, 2, 2, nullptr, stick_round_nub);
4157 break;
4158 case CGO_CUSTOM_CYLINDER:
4159 {
4160 auto cyl = it.cast<cgo::draw::custom_cylinder>();
4161 ok &= CGOSimpleCylinder(cgo, *cyl, cgo->alpha, cgo->alpha, true, cyl->cap1, cyl->cap2, nullptr, stick_round_nub);
4162 }
4163 break;
4164 case CGO_CUSTOM_CYLINDER_ALPHA:
4165 {
4166 auto cyl = it.cast<cgo::draw::custom_cylinder_alpha>();
4167 ok &= CGOSimpleCylinder(cgo, *cyl, cyl->color1[3], cyl->color2[3], true, cyl->cap1, cyl->cap2, nullptr, stick_round_nub);
4168 }
4169 break;
4170 case CGO_SPHERE:
4171 ok &= CGOSimpleSphere(cgo, pc, *(pc + 3), sphere_quality);
4172 break;
4173 case CGO_ELLIPSOID:
4174 ok &= CGOSimpleEllipsoid(cgo, pc, *(pc + 3), pc + 4, pc + 7, pc + 10);
4175 break;
4176 case CGO_QUADRIC:
4177 ok &= CGOSimpleQuadric(cgo, pc, *(pc + 3), pc + 4);
4178 break;
4179 case CGO_DRAW_BUFFERS_INDEXED:
4180 case CGO_DRAW_BUFFERS_NOT_INDEXED:
4181 case CGO_DRAW_SPHERE_BUFFERS:
4182 case CGO_DRAW_CYLINDER_BUFFERS:
4183 case CGO_DRAW_LABELS:
4184 case CGO_DRAW_TEXTURES:
4185 case CGO_END:
4186 case CGO_VERTEX:
4187 WARN_UNEXPECTED_OPERATION(G, op);
4188 return nullptr;
4189 case CGO_BEGIN:
4190 {
4191 float firstColor[3], firstAlpha;
4192 char hasFirstColor = 0, hasFirstAlpha = 0;
4193 int nverts = 0, damode = CGO_VERTEX_ARRAY, err = 0;
4194 int mode = it.cast<cgo::draw::begin>()->mode;
4195
4196 // remember for a second iteration
4197 auto it2 = it;
4198
4199 for (++it;; ++it) {
4200 if (it.is_stop()) {
4201 WARN_UNEXPECTED_OPERATION(G, CGO_STOP);
4202 return nullptr;
4203 }
4204
4205 const auto op = it.op_code();
4206 if (op == CGO_END) {
4207 break;
4208 }
4209
4210 const auto pc = it.data();
4211
4212 switch (op) {
4213 case CGO_DRAW_ARRAYS:
4214 WARN_UNEXPECTED_OPERATION(G, op);
4215 return nullptr;
4216 case CGO_NORMAL:
4217 damode |= CGO_NORMAL_ARRAY;
4218 break;
4219 case CGO_COLOR:
4220 if (!nverts){
4221 hasFirstColor = 1;
4222 firstColor[0] = pc[0]; firstColor[1] = pc[1]; firstColor[2] = pc[2];
4223 } else {
4224 hasFirstColor = 0;
4225 damode |= CGO_COLOR_ARRAY;
4226 }
4227 break;
4228 case CGO_PICK_COLOR:
4229 damode |= CGO_PICK_COLOR_ARRAY;
4230 break;
4231 case CGO_ACCESSIBILITY:
4232 damode |= CGO_ACCESSIBILITY_ARRAY;
4233 break;
4234 case CGO_VERTEX:
4235 nverts++;
4236 break;
4237 case CGO_ALPHA:
4238 cgo->alpha = *pc;
4239 if (!nverts){
4240 hasFirstAlpha = 1;
4241 firstAlpha = cgo->alpha;
4242 } else {
4243 hasFirstAlpha = 0;
4244 damode |= CGO_COLOR_ARRAY;
4245 }
4246 }
4247 }
4248
4249 if (nverts>0 && !err){
4250 int pl = 0, plc = 0, pla = 0;
4251 float *vertexVals, *tmp_ptr;
4252 float *normalVals = 0, *colorVals = 0, *nxtVals = 0, *pickColorVals = 0, *accessibilityVals = 0;
4253 short notHaveValue = 0, nxtn = 3;
4254 if (hasFirstAlpha || hasFirstColor){
4255 if (hasFirstAlpha){
4256 CGOAlpha(cgo, firstAlpha);
4257 }
4258 if (hasFirstColor){
4259 CGOColorv(cgo, firstColor);
4260 }
4261 }
4262 nxtVals = vertexVals = cgo->add<cgo::draw::arrays>(mode, damode, nverts);
4263 RETURN_VAL_IF_FAIL(vertexVals, nullptr);
4264 if (damode & CGO_NORMAL_ARRAY){
4265 nxtVals = normalVals = vertexVals + (nxtn*nverts);
4266 }
4267 if (damode & CGO_COLOR_ARRAY){
4268 nxtVals = colorVals = nxtVals + (nxtn*nverts);
4269 nxtn = 4;
4270 }
4271 if (damode & CGO_PICK_COLOR_ARRAY){
4272 nxtVals = nxtVals + (nxtn*nverts);
4273 pickColorVals = nxtVals + nverts;
4274 nxtn = 3;
4275 }
4276 if (damode & CGO_ACCESSIBILITY_ARRAY){
4277 nxtVals = nxtVals + (nxtn*nverts);
4278 accessibilityVals = nxtVals;
4279 nxtn = 1;
4280 }
4281 notHaveValue = damode;
4282 bool skiptoend = false;
4283
4284 // second iteration
4285 for (++it2; !skiptoend; ++it2) {
4286 const auto op = it2.op_code();
4287 if (op == CGO_END) {
4288 break;
4289 }
4290
4291 const auto pc = it2.data();
4292
4293 switch (op) {
4294 case CGO_NORMAL:
4295 normalVals[pl] = pc[0]; normalVals[pl+1] = pc[1]; normalVals[pl+2] = pc[2];
4296 notHaveValue &= ~CGO_NORMAL_ARRAY;
4297 break;
4298 case CGO_COLOR:
4299 if (colorVals){
4300 colorVals[plc] = pc[0]; colorVals[plc+1] = pc[1];
4301 colorVals[plc+2] = pc[2]; colorVals[plc+3] = cgo->alpha;
4302 notHaveValue &= ~CGO_COLOR_ARRAY;
4303 }
4304 break;
4305 case CGO_PICK_COLOR:
4306 CGOPickColor(cgo, CGO_get_uint(pc), CGO_get_int(pc + 1));
4307 notHaveValue &= ~CGO_PICK_COLOR_ARRAY;
4308 break;
4309 case CGO_ACCESSIBILITY:
4310 cgo->current_accessibility = pc[0];
4311 break;
4312 case CGO_VERTEX:
4313 if (notHaveValue & CGO_NORMAL_ARRAY){
4314 if (pl){
4315 tmp_ptr = &normalVals[pl-3];
4316 normalVals[pl] = tmp_ptr[0]; normalVals[pl+1] = tmp_ptr[1]; normalVals[pl+2] = tmp_ptr[2];
4317 } else {
4318 copy3f(cgo->normal, &normalVals[pl]);
4319 }
4320 }
4321 if (notHaveValue & CGO_COLOR_ARRAY){
4322 if (plc){
4323 tmp_ptr = &colorVals[plc-4];
4324 colorVals[plc] = tmp_ptr[0]; colorVals[plc+1] = tmp_ptr[1];
4325 colorVals[plc+2] = tmp_ptr[2]; colorVals[plc+3] = tmp_ptr[3];
4326 } else {
4327 copy3f(cgo->color, &colorVals[plc]);
4328 colorVals[plc+3] = cgo->alpha;
4329 }
4330 }
4331 if (pickColorVals){
4332 CGO_put_uint(pickColorVals + pla * 2, cgo->current_pick_color_index);
4333 CGO_put_int(pickColorVals + pla * 2 + 1, cgo->current_pick_color_bond);
4334 }
4335 if (accessibilityVals){
4336 accessibilityVals[pla] = cgo->current_accessibility;
4337 }
4338 vertexVals[pl++] = pc[0]; vertexVals[pl++] = pc[1]; vertexVals[pl++] = pc[2];
4339 plc += 4;
4340 pla++;
4341 if (pla >= nverts) // anything past the last vertex is ignored
4342 skiptoend = true;
4343 notHaveValue = damode;
4344 break;
4345 case CGO_ALPHA:
4346 // in case we're before CGO_COLOR
4347 cgo->alpha = *pc;
4348 if (colorVals) {
4349 // in case we're after CGO_COLOR
4350 colorVals[plc + 3] = *pc;
4351 }
4352 break;
4353 }
4354 }
4355 }
4356 }
4357 break;
4358 case CGO_ALPHA:
4359 cgo->alpha = *pc;
4360 default:
4361 cgo->add_to_cgo(op, pc);
4362 }
4363
4364 if (G->Interrupt) {
4365 return nullptr;
4366 }
4367
4368 RETURN_VAL_IF_FAIL(ok, nullptr);
4369 }
4370
4371 CGOStop(cgo);
4372 return cgo_managed.release();
4373 }
4374
4375 /*
4376 * converts a CGO that has primitives into pure geomtry, just like CGOSimplify
4377 * but without converting the CGO_BEGIN/CGO_END blocks.
4378 *
4379 */
CGOSimplifyNoCompress(const CGO * I,int est,short sphere_quality,bool stick_round_nub)4380 CGO *CGOSimplifyNoCompress(const CGO * I, int est, short sphere_quality, bool stick_round_nub)
4381 {
4382 CGO *cgo;
4383
4384 int ok = true;
4385 if (sphere_quality < 0){
4386 sphere_quality = SettingGet_i(I->G, NULL, NULL, cSetting_cgo_sphere_quality);
4387 }
4388
4389 cgo = CGONewSized(I->G, I->c + est);
4390 CHECKOK(ok, cgo);
4391
4392 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
4393 const auto op = it.op_code();
4394 const auto pc = it.data();
4395
4396 switch (op) {
4397 case CGO_PICK_COLOR:
4398 CGOPickColor(cgo, CGO_get_uint(pc), CGO_get_int(pc + 1));
4399 break;
4400 case CGO_SHADER_CYLINDER:
4401 {
4402 float v2[3];
4403 int cap = CGO_get_int(pc + 7);
4404 int fcap = (cap & 1) ? ((cap & cCylShaderCap1RoundBit) ? 2 : 1) : 0;
4405 int bcap = (cap & 2) ? ((cap & cCylShaderCap2RoundBit) ? 2 : 1) : 0;
4406 add3f(pc, pc + 3, v2);
4407 ok &= CGOSimpleCylinder(cgo, pc, v2, *(pc + 6), 0, 0, cgo->alpha, cgo->alpha, (cap & cCylShaderInterpColor),
4408 fcap, bcap, nullptr, stick_round_nub);
4409 }
4410 break;
4411 case CGO_SHADER_CYLINDER_WITH_2ND_COLOR:
4412 {
4413 auto cyl = it.cast<cgo::draw::shadercylinder2ndcolor>();
4414 float v1[3];
4415 int cap = cyl->cap;
4416 int fcap = (cap & 1) ? ((cap & cCylShaderCap1RoundBit) ? 2 : 1) : 0;
4417 int bcap = (cap & 2) ? ((cap & cCylShaderCap2RoundBit) ? 2 : 1) : 0;
4418 Pickable pickcolor2 = { cyl->pick_color_index, cyl->pick_color_bond };
4419 float color1[3] = { cgo->color[0], cgo->color[1], cgo->color[2] };
4420 add3f(cyl->origin, cyl->axis, v1);
4421 float mid[3];
4422 mult3f(cyl->axis, .5f, mid);
4423 add3f(cyl->origin, mid, mid);
4424 float alpha2 = cyl->alpha >= 0.f ? cyl->alpha : cgo->alpha;
4425 if (cap & cCylShaderInterpColor){
4426 ok &= CGOSimpleCylinder(cgo, cyl->origin, v1, cyl->tube_size, color1, cyl->color2, cgo->alpha, alpha2, true, bcap, fcap, &pickcolor2, stick_round_nub);
4427 } else {
4428 ok &= CGOColorv(cgo, color1);
4429 ok &= CGOSimpleCylinder(cgo, cyl->origin, mid, cyl->tube_size, color1, NULL, cgo->alpha, alpha2, false, fcap, 0, NULL, stick_round_nub);
4430 ok &= CGOColorv(cgo, cyl->color2);
4431 ok &= CGOPickColor(cgo, pickcolor2.index, pickcolor2.bond);
4432 ok &= CGOSimpleCylinder(cgo, mid, v1, cyl->tube_size, cyl->color2, NULL, cgo->alpha, alpha2, false, 0, bcap, NULL, stick_round_nub);
4433 }
4434 }
4435 break;
4436 case CGO_CYLINDER:
4437 {
4438 auto cyl = it.cast<cgo::draw::cylinder>();
4439 ok &= CGOSimpleCylinder(cgo, *cyl, cgo->alpha, cgo->alpha, true, 1, 1, nullptr, stick_round_nub);
4440 }
4441 break;
4442 case CGO_CONE:
4443 ok &= CGOSimpleCone(cgo, pc, pc + 3, *(pc + 6), *(pc + 7), pc + 8, pc + 11,
4444 (int) *(pc + 14), (int) *(pc + 15));
4445 break;
4446 case CGO_SAUSAGE:
4447 ok &= CGOSimpleCylinder(cgo, pc, pc + 3, *(pc + 6), pc + 7, pc + 10, cgo->alpha, cgo->alpha, true, 2, 2, nullptr, stick_round_nub);
4448 break;
4449 case CGO_CUSTOM_CYLINDER:
4450 {
4451 auto cyl = it.cast<cgo::draw::custom_cylinder>();
4452 ok &= CGOSimpleCylinder(cgo, *cyl, cgo->alpha, cgo->alpha, true, cyl->cap1, cyl->cap2, nullptr, stick_round_nub);
4453 }
4454 break;
4455 case CGO_CUSTOM_CYLINDER_ALPHA:
4456 {
4457 auto cyl = it.cast<cgo::draw::custom_cylinder_alpha>();
4458 ok &= CGOSimpleCylinder(cgo, *cyl, cyl->color1[3], cyl->color2[3], true, cyl->cap1, cyl->cap2, nullptr, stick_round_nub);
4459 }
4460 break;
4461 case CGO_SPHERE:
4462 ok &= CGOSimpleSphere(cgo, pc, *(pc + 3), sphere_quality);
4463 break;
4464 case CGO_ELLIPSOID:
4465 ok &= CGOSimpleEllipsoid(cgo, pc, *(pc + 3), pc + 4, pc + 7, pc + 10);
4466 break;
4467 case CGO_QUADRIC:
4468 ok &= CGOSimpleQuadric(cgo, pc, *(pc + 3), pc + 4);
4469 break;
4470 case CGO_DRAW_BUFFERS_INDEXED:
4471 PRINTFB(I->G, FB_CGO, FB_Errors) "CGOSimplifyNoCompress-Error: CGO_DRAW_BUFFERS_INDEXED encountered\n" ENDFB(I->G);
4472 break;
4473 case CGO_DRAW_BUFFERS_NOT_INDEXED:
4474 PRINTFB(I->G, FB_CGO, FB_Errors) "CGOSimplifyNoCompress-Error: CGO_DRAW_BUFFERS_NOT_INDEXED encountered\n" ENDFB(I->G);
4475 break;
4476 case CGO_DRAW_SPHERE_BUFFERS:
4477 PRINTFB(I->G, FB_CGO, FB_Errors) "CGOSimplifyNoCompress-Error: CGO_DRAW_SPHERE_BUFFERS encountered\n" ENDFB(I->G);
4478 break;
4479 case CGO_DRAW_CYLINDER_BUFFERS:
4480 PRINTFB(I->G, FB_CGO, FB_Errors) "CGOSimplifyNoCompress-Error: CGO_DRAW_CYLINDER_BUFFERS encountered\n" ENDFB(I->G);
4481 break;
4482 case CGO_DRAW_LABELS:
4483 PRINTFB(I->G, FB_CGO, FB_Errors) "CGOSimplifyNoCompress-Error: CGO_DRAW_LABELS encountered\n" ENDFB(I->G);
4484 break;
4485 case CGO_DRAW_TEXTURES:
4486 PRINTFB(I->G, FB_CGO, FB_Errors) "CGOSimplifyNoCompress-Error: CGO_DRAW_TEXTURES encountered\n" ENDFB(I->G);
4487 break;
4488 case CGO_BEGIN:
4489 cgo->has_begin_end = true;
4490 default:
4491 cgo->add_to_cgo(op, pc);
4492 }
4493 ok &= !I->G->Interrupt;
4494 }
4495 if (ok){
4496 ok &= CGOStop(cgo);
4497 }
4498 if (!ok){
4499 CGOFree(cgo);
4500 }
4501 return (cgo);
4502 }
4503
4504
CGOOptimizeTextures(const CGO * I,int est)4505 CGO *CGOOptimizeTextures(const CGO * I, int est)
4506 {
4507 CGO *cgo = NULL;
4508 int num_total_textures;
4509 int ok = true;
4510 num_total_textures = CGOCountNumberOfOperationsOfType(I, CGO_DRAW_TEXTURE);
4511 // printf("CGOOptimizeTextures: num_total_textures=%d\n", num_total_textures);
4512 if (num_total_textures){
4513 float *worldPos, *screenValues, *textExtents, *pickColorVals;
4514 int place3 = 0, place2 = 0;
4515 worldPos = pymol::malloc<float>(num_total_textures * 18);
4516 if (!worldPos){
4517 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeTextures() worldPos could not be allocated\n" ENDFB(I->G);
4518 return NULL;
4519 }
4520 screenValues = pymol::malloc<float>(num_total_textures * 18);
4521 if (!screenValues){
4522 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeTextures() screenValues could not be allocated\n" ENDFB(I->G);
4523 FreeP(worldPos);
4524 return NULL;
4525 }
4526 textExtents = pymol::malloc<float>(num_total_textures * 12);
4527 if (!textExtents){
4528 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeTextures() textExtents could not be allocated\n" ENDFB(I->G);
4529 FreeP(screenValues);
4530 FreeP(worldPos);
4531 return NULL;
4532 }
4533 pickColorVals = pymol::malloc<float>(num_total_textures * 12); /* pick index and bond */
4534 if (!pickColorVals){
4535 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeTextures() pickColorVals could not be allocated\n" ENDFB(I->G);
4536 FreeP(textExtents);
4537 FreeP(screenValues);
4538 FreeP(worldPos);
4539 return NULL;
4540 }
4541
4542 cgo = CGONewSized(I->G, 0);
4543
4544 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
4545 const auto op = it.op_code();
4546 const auto pc = it.data();
4547
4548 switch (op) {
4549 case CGO_PICK_COLOR:
4550 cgo->current_pick_color_index = CGO_get_uint(pc);
4551 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
4552 break;
4553 case CGO_DRAW_BUFFERS_INDEXED:
4554 case CGO_DRAW_BUFFERS_NOT_INDEXED:
4555 PRINTFB(I->G, FB_CGO, FB_Warnings) "WARNING: CGOOptimizeTextures() CGO_DRAW_BUFFERS_INDEXED or CGO_DRAW_BUFFERS_INDEXED encountered op=%d\n", op ENDFB(I->G);
4556 break;
4557 case CGO_DRAW_TEXTURE:
4558 {
4559 float screenMin[3], screenMax[3], textExtent[4];
4560 copy3f(pc, &worldPos[place3]);
4561 copy3f(pc, &worldPos[place3+3]);
4562 copy3f(pc, &worldPos[place3+6]);
4563 copy3f(pc, &worldPos[place3+9]);
4564 copy3f(pc, &worldPos[place3+12]);
4565 copy3f(pc, &worldPos[place3+15]);
4566 copy3f(pc + 3, screenMin);
4567 copy3f(pc + 6, screenMax);
4568 copy4f(pc + 9, textExtent);
4569 copy3f(screenMin, &screenValues[place3]);
4570 copy3f(screenMin, &screenValues[place3+3]);
4571 copy3f(screenMin, &screenValues[place3+6]);
4572 copy3f(screenMin, &screenValues[place3+9]);
4573 copy3f(screenMin, &screenValues[place3+12]);
4574 copy3f(screenMax, &screenValues[place3+15]);
4575 screenValues[place3+4] = screenMax[1];
4576 screenValues[place3+6] = screenMax[0];
4577 screenValues[place3+10] = screenMax[1];
4578 screenValues[place3+12] = screenMax[0];
4579 screenValues[place3+17] = screenMin[2];
4580 place3 += 18;
4581 CGO_put_uint(pickColorVals + place2, cgo->current_pick_color_index);
4582 CGO_put_int(pickColorVals + place2 + 1, cgo->current_pick_color_bond);
4583 textExtents[place2++] = textExtent[0]; textExtents[place2++] = textExtent[1];
4584 CGO_put_uint(pickColorVals + place2, cgo->current_pick_color_index);
4585 CGO_put_int(pickColorVals + place2 + 1, cgo->current_pick_color_bond);
4586 textExtents[place2++] = textExtent[0]; textExtents[place2++] = textExtent[3];
4587 CGO_put_uint(pickColorVals + place2, cgo->current_pick_color_index);
4588 CGO_put_int(pickColorVals + place2 + 1, cgo->current_pick_color_bond);
4589 textExtents[place2++] = textExtent[2]; textExtents[place2++] = textExtent[1];
4590 CGO_put_int(pickColorVals + place2, cgo->current_pick_color_index);
4591 CGO_put_uint(pickColorVals + place2 + 1, cgo->current_pick_color_bond);
4592 textExtents[place2++] = textExtent[0]; textExtents[place2++] = textExtent[3];
4593 CGO_put_uint(pickColorVals + place2, cgo->current_pick_color_index);
4594 CGO_put_int(pickColorVals + place2 + 1, cgo->current_pick_color_bond);
4595 textExtents[place2++] = textExtent[2]; textExtents[place2++] = textExtent[1];
4596 CGO_put_uint(pickColorVals + place2, cgo->current_pick_color_index);
4597 CGO_put_int(pickColorVals + place2 + 1, cgo->current_pick_color_bond);
4598 textExtents[place2++] = textExtent[2]; textExtents[place2++] = textExtent[3];
4599 }
4600 break;
4601 }
4602 ok &= !I->G->Interrupt;
4603 }
4604 if (ok) {
4605 VertexBuffer * vbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>(VertexBuffer::SEQUENTIAL);
4606 ok &= vbo->bufferData({
4607 BufferDesc( "attr_worldpos", GL_FLOAT, 3, sizeof(float) * num_total_textures * 18, worldPos, GL_FALSE ),
4608 BufferDesc( "attr_screenoffset", GL_FLOAT, 3, sizeof(float) * num_total_textures * 18, screenValues, GL_FALSE ),
4609 BufferDesc( "attr_texcoords", GL_FLOAT, 3, sizeof(float) * num_total_textures * 18, textExtents, GL_FALSE )
4610 });
4611 size_t vboid = vbo->get_hash_id();
4612
4613 if (ok) {
4614 float *pickArray = cgo->add<cgo::draw::textures>(num_total_textures, vboid);
4615 CHECKOK(ok, pickArray);
4616 if (!pickArray)
4617 I->G->ShaderMgr->freeGPUBuffer(vboid);
4618 if (ok)
4619 memcpy(pickArray + num_total_textures * 6, pickColorVals, num_total_textures * 12 * sizeof(float));
4620 if (ok)
4621 ok &= CGOStop(cgo);
4622 } else {
4623 I->G->ShaderMgr->freeGPUBuffer(vboid);
4624 }
4625 if (!ok){
4626 CGOFree(cgo);
4627 }
4628 }
4629 FreeP(worldPos);
4630 FreeP(screenValues);
4631 FreeP(textExtents);
4632 FreeP(pickColorVals);
4633 }
4634 return cgo;
4635 }
4636
CGOConvertToLabelShader(const CGO * I,CGO * addTo)4637 CGO *CGOConvertToLabelShader(const CGO *I, CGO * addTo){
4638 /* Lines that pass in two vertices per line */
4639 PyMOLGlobals *G = I->G;
4640
4641 AttribDataOp world_pos_op =
4642 { { CGO_DRAW_LABEL, 1, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::label, world_pos), 0 } };
4643 AttribDataOp screen_offset_op =
4644 { { CGO_DRAW_LABEL, 2, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::label, screen_world_offset), 0 } };
4645 AttribDataOp screen_min_op =
4646 { { CGO_DRAW_LABEL, 3, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::label, screen_min), 0 } };
4647 AttribDataOp screen_max_op =
4648 { { CGO_DRAW_LABEL, 4, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::label, screen_max), 0 } };
4649 AttribDataOp text_extent_op =
4650 { { CGO_DRAW_LABEL, 5, FLOAT2_TO_FLOAT2, offsetof(cgo::draw::label, text_extent), 0 } };
4651 AttribDataOp relative_mode_op =
4652 { { CGO_DRAW_LABEL, 6, FLOAT_TO_FLOAT, offsetof(cgo::draw::label, relative_mode), 0 } };
4653 AttribDataOp target_pos_op =
4654 { { CGO_DRAW_LABEL, 7, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::label, target_pos), 6 } };
4655
4656 AttribDataDesc attrDesc = { { "attr_worldpos", GL_FLOAT, 3, GL_FALSE, world_pos_op },
4657 { "attr_targetpos", GL_FLOAT, 3, GL_FALSE, target_pos_op },
4658 { "attr_screenoffset", GL_FLOAT, 3, GL_FALSE, screen_min_op },
4659 { "attr_texcoords", GL_FLOAT, 2, GL_FALSE, text_extent_op },
4660 { "attr_screenworldoffset", GL_FLOAT, 3, GL_FALSE, screen_offset_op },
4661 { "attr_relative_mode", GL_FLOAT, 1, GL_FALSE, relative_mode_op } };
4662
4663 auto ComputeScreenValues = [](void * varData, const float * pc, void * screenData, int idx) {
4664 auto sp = reinterpret_cast<const cgo::draw::label *>(pc);
4665 const auto& smin = sp->screen_min;
4666 const auto& smax = sp->screen_max;
4667 float * v = reinterpret_cast<float *>(varData);
4668 switch (idx) {
4669 case 0:
4670 v[0] = smin[0]; v[1] = smin[1]; v[2] = smin[2];
4671 break;
4672 case 1:
4673 v[0] = smin[0]; v[1] = smax[1]; v[2] = smin[2];
4674 break;
4675 case 2:
4676 v[0] = smax[0]; v[1] = smin[1]; v[2] = smin[2];
4677 break;
4678 case 3:
4679 v[0] = smin[0]; v[1] = smax[1]; v[2] = smin[2];
4680 break;
4681 case 4:
4682 v[0] = smax[0]; v[1] = smin[1]; v[2] = smin[2];
4683 break;
4684 case 5:
4685 v[0] = smax[0]; v[1] = smax[1]; v[2] = smin[2];
4686 break;
4687 };
4688 };
4689
4690 auto ComputeTexCoords = [](void * varData, const float * pc, void * discard, int idx) {
4691 auto sp = reinterpret_cast<const cgo::draw::label *>(pc);
4692 float * v = reinterpret_cast<float *>(varData);
4693 const auto& te = sp->text_extent;
4694 static struct { int x, y; } const idxs[6] = {
4695 { 0, 1 },
4696 { 0, 3 },
4697 { 2, 1 },
4698 { 0, 3 },
4699 { 2, 1 },
4700 { 2, 3 }
4701 };
4702 v[0] = te[idxs[idx].x];
4703 v[1] = te[idxs[idx].y];
4704 };
4705
4706 attrDesc[1].attrOps[0].funcDataConversions.push_back({ ComputeScreenValues, nullptr, "attr_screenoffset" });
4707 attrDesc[1].attrOps[0].funcDataConversions.push_back({ ComputeTexCoords, nullptr, "attr_texcoords" });
4708
4709 uchar pickdata[4] = { 0, 0, 0, 0 };
4710 addTo->add<cgo::draw::vertex_attribute_4ub>(G->ShaderMgr->GetAttributeUID("attr_pickcolor"), pickdata);
4711
4712 AttribDataOp pickOp = { { CGO_PICK_COLOR, 1, UINT_INT_TO_PICK_DATA, 0, 0 } };
4713 AttribDataDesc pickDesc = { { "attr_pickcolor", GL_UNSIGNED_BYTE, 4, GL_TRUE, pickOp } };
4714 return CGOConvertToShader(I, attrDesc, pickDesc, GL_TRIANGLES, VertexBuffer::INTERLEAVED, true);
4715 }
4716
CGOOptimizeLabels(const CGO * I,int est,bool addshaders)4717 CGO *CGOOptimizeLabels(const CGO * I, int est, bool addshaders)
4718 {
4719 CGO *cgo = NULL;
4720 int num_total_labels;
4721 int ok = true;
4722 num_total_labels = CGOCountNumberOfOperationsOfType(I, CGO_DRAW_LABEL);
4723 if (num_total_labels){
4724 float *targetPos, *worldPos, *screenValues, *screenWorldValues, *textExtents, *pickColorVals;
4725 float *relativeMode;
4726 int place3 = 0, place2 = 0, place = 0;
4727 worldPos = pymol::malloc<float>(num_total_labels * 6 * 17);
4728 if (!worldPos){
4729 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeLabels() worldPos could not be allocated\n" ENDFB(I->G);
4730 return NULL;
4731 }
4732 screenValues = worldPos + (num_total_labels * 18);
4733 targetPos = screenValues + (num_total_labels * 18);
4734 screenWorldValues = targetPos + (num_total_labels * 18);
4735 textExtents = screenWorldValues + (num_total_labels * 18);
4736 pickColorVals = textExtents + (num_total_labels * 12); /* pick index and bond */
4737 relativeMode = (float *)(pickColorVals + (num_total_labels * 12));
4738 cgo = CGONewSized(I->G, 0);
4739
4740 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
4741 const auto op = it.op_code();
4742 const auto pc = it.data();
4743
4744 switch (op) {
4745 case CGO_PICK_COLOR:
4746 cgo->current_pick_color_index = CGO_get_uint(pc);
4747 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
4748 break;
4749 case CGO_DRAW_BUFFERS_INDEXED:
4750 case CGO_DRAW_BUFFERS_NOT_INDEXED:
4751 PRINTFB(I->G, FB_CGO, FB_Warnings) "WARNING: CGOOptimizeLabels() CGO_DRAW_BUFFERS_INDEXED or CGO_DRAW_BUFFERS_INDEXED encountered op=%d\n", op ENDFB(I->G);
4752 break;
4753 case CGO_DRAW_LABEL:
4754 {
4755 float screenWorldOffset[3], screenMin[3], screenMax[3], textExtent[4];
4756 copy3f(pc, &worldPos[place3]);
4757 copy3f(pc, &worldPos[place3+3]);
4758 copy3f(pc, &worldPos[place3+6]);
4759 copy3f(pc, &worldPos[place3+9]);
4760 copy3f(pc, &worldPos[place3+12]);
4761 copy3f(pc, &worldPos[place3+15]);
4762 copy3f(pc + 3, screenWorldOffset);
4763 copy3f(pc + 6, screenMin);
4764 copy3f(pc + 9, screenMax);
4765 copy4f(pc + 12, textExtent);
4766 copy3f(screenWorldOffset, &screenWorldValues[place3]);
4767 copy3f(&screenWorldValues[place3], &screenWorldValues[place3+3]);
4768 copy3f(&screenWorldValues[place3], &screenWorldValues[place3+6]);
4769 copy3f(&screenWorldValues[place3], &screenWorldValues[place3+9]);
4770 copy3f(&screenWorldValues[place3], &screenWorldValues[place3+12]);
4771 copy3f(&screenWorldValues[place3], &screenWorldValues[place3+15]);
4772 copy3f(screenMin, &screenValues[place3]);
4773 copy3f(screenMin, &screenValues[place3+3]);
4774 copy3f(screenMin, &screenValues[place3+6]);
4775 copy3f(screenMin, &screenValues[place3+9]);
4776 copy3f(screenMin, &screenValues[place3+12]);
4777 copy3f(screenMax, &screenValues[place3+15]);
4778 screenValues[place3+4] = screenMax[1];
4779 screenValues[place3+6] = screenMax[0];
4780 screenValues[place3+10] = screenMax[1];
4781 screenValues[place3+12] = screenMax[0];
4782 screenValues[place3+17] = screenMin[2];
4783 copy3f(pc + 17, &targetPos[place3]);
4784 copy3f(pc + 17, &targetPos[place3+3]);
4785 copy3f(pc + 17, &targetPos[place3+6]);
4786 copy3f(pc + 17, &targetPos[place3+9]);
4787 copy3f(pc + 17, &targetPos[place3+12]);
4788 copy3f(pc + 17, &targetPos[place3+15]);
4789 place3 += 18;
4790 CGO_put_uint(pickColorVals + place2, cgo->current_pick_color_index);
4791 CGO_put_int(pickColorVals + place2 + 1, cgo->current_pick_color_bond);
4792 textExtents[place2++] = textExtent[0]; textExtents[place2++] = textExtent[1];
4793 CGO_put_uint(pickColorVals + place2, cgo->current_pick_color_index);
4794 CGO_put_int(pickColorVals + place2 + 1, cgo->current_pick_color_bond);
4795 textExtents[place2++] = textExtent[0]; textExtents[place2++] = textExtent[3];
4796 CGO_put_uint(pickColorVals + place2, cgo->current_pick_color_index);
4797 CGO_put_int(pickColorVals + place2 + 1, cgo->current_pick_color_bond);
4798 textExtents[place2++] = textExtent[2]; textExtents[place2++] = textExtent[1];
4799 CGO_put_uint(pickColorVals + place2, cgo->current_pick_color_index);
4800 CGO_put_int(pickColorVals + place2 + 1, cgo->current_pick_color_bond);
4801 textExtents[place2++] = textExtent[0]; textExtents[place2++] = textExtent[3];
4802 CGO_put_uint(pickColorVals + place2, cgo->current_pick_color_index);
4803 CGO_put_int(pickColorVals + place2 + 1, cgo->current_pick_color_bond);
4804 textExtents[place2++] = textExtent[2]; textExtents[place2++] = textExtent[1];
4805 CGO_put_uint(pickColorVals + place2, cgo->current_pick_color_index);
4806 CGO_put_int(pickColorVals + place2 + 1, cgo->current_pick_color_bond);
4807 textExtents[place2++] = textExtent[2]; textExtents[place2++] = textExtent[3];
4808 {
4809 uchar rM = (uchar)*(pc + 16);
4810 relativeMode[place++] = rM;
4811 relativeMode[place++] = rM;
4812 relativeMode[place++] = rM;
4813 relativeMode[place++] = rM;
4814 relativeMode[place++] = rM;
4815 relativeMode[place++] = rM;
4816 }
4817 }
4818 break;
4819 }
4820 ok &= !I->G->Interrupt;
4821 }
4822 if (ok) {
4823 // Static Vertex Data
4824 VertexBuffer * vbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>(VertexBuffer::SEQUENTIAL);
4825 ok &= vbo->bufferData({
4826 BufferDesc( "attr_worldpos", GL_FLOAT, 3, sizeof(float)*18*num_total_labels, worldPos, GL_FALSE ),
4827 BufferDesc( "attr_targetpos", GL_FLOAT, 3, sizeof(float)*18*num_total_labels, targetPos, GL_FALSE ),
4828 BufferDesc( "attr_screenoffset", GL_FLOAT, 3, sizeof(float)*18*num_total_labels, screenValues, GL_FALSE ),
4829 BufferDesc( "attr_texcoords", GL_FLOAT, 2, sizeof(float)*12*num_total_labels, textExtents, GL_FALSE ),
4830 BufferDesc( "attr_screenworldoffset", GL_FLOAT, 3, sizeof(float)*18*num_total_labels, screenWorldValues, GL_FALSE ),
4831 BufferDesc( "attr_relative_mode", GL_FLOAT, 1, sizeof(float)*6*num_total_labels, relativeMode, GL_FALSE )
4832 });
4833 size_t vboid = vbo->get_hash_id();
4834
4835 VertexBuffer * pickvbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>(VertexBuffer::SEQUENTIAL, GL_DYNAMIC_DRAW);
4836 ok &= pickvbo->bufferData({
4837 BufferDesc( "attr_pickcolor", GL_UNSIGNED_BYTE, VERTEX_COLOR_SIZE, 0, GL_TRUE ),
4838 BufferDesc( "attr_pickcolor", GL_UNSIGNED_BYTE, VERTEX_COLOR_SIZE, sizeof(float) * num_total_labels * 6, GL_TRUE )
4839 }, 0, sizeof(float) * num_total_labels * 12, 0);
4840 size_t pickvboid = pickvbo->get_hash_id();
4841
4842 auto freebuffers = [vboid, pickvboid, I]() {
4843 I->G->ShaderMgr->freeGPUBuffer(vboid);
4844 I->G->ShaderMgr->freeGPUBuffer(pickvboid);
4845 };
4846
4847 if (ok) {
4848 float *pickArray = NULL;
4849 if (addshaders){
4850 CGOEnable(cgo, GL_LABEL_SHADER);
4851 }
4852 pickArray = cgo->add<cgo::draw::labels>(num_total_labels, vboid, pickvboid);
4853 if (addshaders){
4854 CGODisable(cgo, GL_LABEL_SHADER);
4855 }
4856 CHECKOK(ok, pickArray);
4857 if (!pickArray) {
4858 freebuffers();
4859 }
4860 if (ok)
4861 memcpy(pickArray + num_total_labels * 6, pickColorVals, num_total_labels * 12 * sizeof(float));
4862 if (ok)
4863 ok &= CGOStop(cgo);
4864 } else {
4865 freebuffers();
4866 }
4867 if (!ok){
4868 CGOFree(cgo);
4869 }
4870 }
4871 FreeP(worldPos);
4872 }
4873 return cgo;
4874 }
4875
CGOOptimizeConnectors(const CGO * I,int est)4876 CGO *CGOOptimizeConnectors(const CGO * I, int est)
4877 {
4878 CGO *cgo = NULL;
4879 int num_total_connectors;
4880 int ok = true;
4881 int use_geometry_shaders = SettingGetGlobal_b(I->G, cSetting_use_geometry_shaders);
4882 int factor = (use_geometry_shaders ? 1 : 4);
4883 num_total_connectors = CGOCountNumberOfOperationsOfType(I, CGO_DRAW_CONNECTOR);
4884
4885 if (num_total_connectors){
4886 float *targetPt3d, *labelCenterPt3d, *indentFactor, *screenWorldOffset, *connectorColor, *textSize;
4887 float *bkgrdColor, *relExtLength, *connectorWidth;
4888 uchar *relativeMode, *drawBkgrd;
4889 uchar *isCenterPt = NULL;
4890 int place3 = 0, place2 = 0, place = 0;
4891 targetPt3d = pymol::calloc<float>(num_total_connectors * 20 * factor); /* too much, relativeMode only needs 1 byte per vertex, instead of 1 float */
4892 if (!targetPt3d){
4893 PRINTFB(I->G, FB_CGO, FB_Errors) "ERROR: CGOOptimizeConnectors() could not be allocated\n" ENDFB(I->G);
4894 return NULL;
4895 }
4896 labelCenterPt3d = targetPt3d + (num_total_connectors*3 * factor);
4897 indentFactor = labelCenterPt3d + (num_total_connectors*3 * factor);
4898 screenWorldOffset = indentFactor + (num_total_connectors*2 * factor);
4899 connectorColor = screenWorldOffset + (num_total_connectors*3 * factor);
4900 textSize = connectorColor + (num_total_connectors*factor);
4901 relativeMode = (uchar *)(textSize + (num_total_connectors*2*factor));
4902 drawBkgrd = (uchar *)(relativeMode + (num_total_connectors*factor));
4903 bkgrdColor = (float*)(drawBkgrd + (num_total_connectors*factor));
4904 relExtLength = (float*)(bkgrdColor + (num_total_connectors*factor));
4905 connectorWidth = (float*)(relExtLength + (num_total_connectors*factor));
4906 if (!use_geometry_shaders)
4907 isCenterPt = (uchar *)(connectorWidth + (num_total_connectors*factor));
4908 else
4909 isCenterPt = nullptr;
4910 cgo = CGONewSized(I->G, 0);
4911
4912 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
4913 const auto op = it.op_code();
4914 const auto pc = it.data();
4915
4916 switch (op) {
4917 case CGO_PICK_COLOR:
4918 cgo->current_pick_color_index = CGO_get_uint(pc);
4919 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
4920 break;
4921 case CGO_DRAW_BUFFERS_INDEXED:
4922 case CGO_DRAW_BUFFERS_NOT_INDEXED:
4923 PRINTFB(I->G, FB_CGO, FB_Warnings) "WARNING: CGOOptimizeConnectors() CGO_DRAW_BUFFERS_INDEXED or CGO_DRAW_BUFFERS_INDEXED encountered op=%d\n", op ENDFB(I->G);
4924 break;
4925 case CGO_DRAW_CONNECTOR:
4926 {
4927 uchar *uc;
4928 int f;
4929 if (!use_geometry_shaders){
4930 isCenterPt[place] = 0; isCenterPt[place+1] = 2; isCenterPt[place+2] = 2; isCenterPt[place+3] = 1;
4931 }
4932 copy3f(pc, &targetPt3d[place3]);
4933 copy3f(pc + 3, &labelCenterPt3d[place3]);
4934 copy2f(pc + 6, &indentFactor[place2]);
4935 copy3f(pc + 9, &screenWorldOffset[place3]);
4936 copy2f(pc + 12, &textSize[place2]);
4937 relativeMode[place] = (uchar)(int)pc[17];
4938 drawBkgrd[place] = (uchar)(int)pc[18];
4939 uc = (uchar *)&bkgrdColor[place];
4940 uc[0] = CLIP_COLOR_VALUE(*(pc+19));
4941 uc[1] = CLIP_COLOR_VALUE(*(pc+20));
4942 uc[2] = CLIP_COLOR_VALUE(*(pc+21));
4943 uc[3] = CLIP_COLOR_VALUE(*(pc+22));
4944 uc = (uchar *)&connectorColor[place];
4945 uc[0] = CLIP_COLOR_VALUE(*(pc+14));
4946 uc[1] = CLIP_COLOR_VALUE(*(pc+15));
4947 uc[2] = CLIP_COLOR_VALUE(*(pc+16));
4948 uc[3] = 255;
4949 relExtLength[place] = *(pc + 8);
4950 connectorWidth[place] = *(pc + 23);
4951 place3 += 3; place2 += 2; place += 1;
4952 for (f=1;f<factor; f++){
4953 copy3f(pc, &targetPt3d[place3]);
4954 copy3f(pc + 3, &labelCenterPt3d[place3]);
4955 copy2f(pc + 6, &indentFactor[place2]);
4956 copy3f(pc + 9, &screenWorldOffset[place3]);
4957 copy2f(pc + 12, &textSize[place2]);
4958 relativeMode[place] = (uchar)(int)pc[17];
4959 drawBkgrd[place] = (uchar)(int)pc[18];
4960 relExtLength[place] = *(pc + 8);
4961 connectorWidth[place] = *(pc + 23);
4962 uc = (uchar *)&bkgrdColor[place];
4963 uc[0] = uc[-4];
4964 uc[1] = uc[-3];
4965 uc[2] = uc[-2];
4966 uc[3] = uc[-1];
4967 uc = (uchar *)&connectorColor[place];
4968 uc[0] = uc[-4];
4969 uc[1] = uc[-3];
4970 uc[2] = uc[-2];
4971 uc[3] = uc[-1];
4972 place3 += 3; place2 += 2; place += 1;
4973 }
4974 }
4975 break;
4976 }
4977 ok &= !I->G->Interrupt;
4978 }
4979 if (ok) {
4980 const size_t quant = factor * num_total_connectors;
4981 VertexBuffer * vbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>();
4982 ok = vbo->bufferData({
4983 BufferDesc( "a_target_pt3d", GL_FLOAT, 3, sizeof(float) * 3 * quant, targetPt3d, GL_FALSE ),
4984 BufferDesc( "a_center_pt3d", GL_FLOAT, 3, sizeof(float) * 3 * quant, labelCenterPt3d, GL_FALSE ),
4985 BufferDesc( "a_indentFactor", GL_FLOAT, 2, sizeof(float) * 2 * quant, indentFactor, GL_FALSE ),
4986 BufferDesc( "a_screenWorldOffset", GL_FLOAT, 3, sizeof(float) * 3 * quant, screenWorldOffset, GL_FALSE ),
4987 BufferDesc( "a_textSize", GL_FLOAT, 2, sizeof(float) * 2 * quant, textSize, GL_FALSE ),
4988 BufferDesc( "a_Color", GL_UNSIGNED_BYTE, 4, sizeof(float) * quant, connectorColor, GL_TRUE ),
4989 BufferDesc( "a_relative_mode", GL_UNSIGNED_BYTE, 1, sizeof(uchar) * quant, relativeMode, GL_FALSE ),
4990 BufferDesc( "a_draw_flags", GL_UNSIGNED_BYTE, 1, sizeof(uchar) * quant, drawBkgrd, GL_FALSE ),
4991 BufferDesc( "a_bkgrd_color", GL_UNSIGNED_BYTE, 4, sizeof(float) * quant, bkgrdColor, GL_TRUE ),
4992 BufferDesc( "a_rel_ext_length", GL_FLOAT, 1, sizeof(float) * quant, relExtLength, GL_FALSE ),
4993 BufferDesc( "a_con_width", GL_FLOAT, 1, sizeof(float) * quant, connectorWidth, GL_FALSE ),
4994 BufferDesc( "a_isCenterPt", GL_UNSIGNED_BYTE, 1, sizeof(uchar) * quant, isCenterPt, GL_FALSE )
4995 });
4996 size_t vboid = vbo->get_hash_id();
4997 if (ok) {
4998 cgo->add<cgo::draw::connectors>(num_total_connectors, vboid);
4999 if (ok)
5000 ok &= CGOStop(cgo);
5001 }
5002 if (!ok){
5003 I->G->ShaderMgr->freeGPUBuffer(vboid);
5004 CGOFree(cgo);
5005 }
5006 }
5007 FreeP(targetPt3d);
5008 }
5009 {
5010 GLenum err ;
5011 CHECK_GL_ERROR_OK("ERROR: CGOOptimizeConnectors() end returns err=%d\n");
5012 }
5013 return cgo;
5014 }
5015
5016
CGOExpandDrawTextures(const CGO * I,int est)5017 CGO *CGOExpandDrawTextures(const CGO * I, int est)
5018 {
5019 CGO *cgo = CGONew(I->G);
5020 int ok = true;
5021
5022 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
5023 auto pc = it.data();
5024 int op = it.op_code();
5025
5026 switch (op) {
5027 case CGO_PICK_COLOR:
5028 cgo->current_pick_color_index = CGO_get_uint(pc);
5029 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
5030 break;
5031 case CGO_DRAW_BUFFERS_INDEXED:
5032 case CGO_DRAW_BUFFERS_NOT_INDEXED:
5033 PRINTFB(I->G, FB_CGO, FB_Warnings) "WARNING: CGOOptimizeTextures() CGO_DRAW_BUFFERS_INDEXED or CGO_DRAW_BUFFERS_INDEXED encountered op=%d\n", op ENDFB(I->G);
5034 break;
5035 case CGO_DRAW_TEXTURE:
5036 {
5037 float screenMin[3], screenMax[3], textExtent[4];
5038 float alpha = cgo->alpha;
5039 CGOAlpha(cgo, 0.f);
5040 CGOColor(cgo, 0.f,0.f,0.f);
5041 copy3f(pc + 3, screenMin);
5042 copy3f(pc + 6, screenMax);
5043 copy4f(pc + 9, textExtent);
5044 CGOBegin(cgo, GL_TRIANGLES);
5045 CGOTexCoord2f(cgo, textExtent[0], textExtent[1]);
5046 CGOVertexv(cgo, screenMin);
5047 CGOTexCoord2f(cgo, textExtent[0], textExtent[3]);
5048 CGOVertex(cgo, screenMin[0], screenMax[1], screenMin[2]);
5049 CGOTexCoord2f(cgo, textExtent[2], textExtent[1]);
5050 CGOVertex(cgo, screenMax[0], screenMin[1], screenMin[2]);
5051 CGOTexCoord2f(cgo, textExtent[0], textExtent[3]);
5052 CGOVertex(cgo, screenMin[0], screenMax[1], screenMin[2]);
5053 CGOTexCoord2f(cgo, textExtent[2], textExtent[1]);
5054 CGOVertex(cgo, screenMax[0], screenMin[1], screenMin[2]);
5055 CGOTexCoord2f(cgo, textExtent[2], textExtent[3]);
5056 CGOVertex(cgo, screenMax[0], screenMax[1], screenMin[2]);
5057 CGOEnd(cgo);
5058 CGOAlpha(cgo, alpha);
5059 }
5060 break;
5061 default:
5062 cgo->add_to_cgo(op, pc);
5063 }
5064 ok &= !I->G->Interrupt;
5065 }
5066 CGOStop(cgo);
5067 return cgo;
5068 }
5069
5070 /* ======== Raytrace Renderer ======== */
5071
CGOGetExtent(const CGO * I,float * mn,float * mx)5072 int CGOGetExtent(const CGO * I, float *mn, float *mx)
5073 {
5074 int result = false;
5075
5076 #define check_extent(v,r) {\
5077 if(!result) {\
5078 mn[0]=((*(v ))-r); \
5079 mx[0]=((*(v ))+r); \
5080 mn[1]=((*(v+1))-r); \
5081 mx[1]=((*(v+1))+r); \
5082 mn[2]=((*(v+2))-r); \
5083 mx[2]=((*(v+2))+r); \
5084 result=true; \
5085 } else {\
5086 if(mn[0]>((*(v ))-r)) mn[0]=((*(v ))-r); \
5087 if(mx[0]<((*(v ))+r)) mx[0]=((*(v ))+r); \
5088 if(mn[1]>((*((v)+1))-r)) mn[1]=((*((v)+1))-r); \
5089 if(mx[1]<((*((v)+1))+r)) mx[1]=((*((v)+1))+r); \
5090 if(mn[2]>((*((v)+2))-r)) mn[2]=((*((v)+2))-r); \
5091 if(mx[2]<((*((v)+2))+r)) mx[2]=((*((v)+2))+r); }}
5092
5093 #define check_extent4(v,r) {\
5094 if(!result) {\
5095 mn[0]=((*(v ))-r); \
5096 mx[0]=((*(v ))+r); \
5097 mn[1]=((*(v+1))-r); \
5098 mx[1]=((*(v+1))+r); \
5099 mn[2]=((*(v+2))-r); \
5100 mx[2]=((*(v+2))+r); \
5101 mn[3]=((*(v+3))-r); \
5102 mx[3]=((*(v+3))+r); \
5103 result=true; \
5104 } else {\
5105 if(mn[0]>((*(v ))-r)) mn[0]=((*(v ))-r); \
5106 if(mx[0]<((*(v ))+r)) mx[0]=((*(v ))+r); \
5107 if(mn[1]>((*((v)+1))-r)) mn[1]=((*((v)+1))-r); \
5108 if(mx[1]<((*((v)+1))+r)) mx[1]=((*((v)+1))+r); \
5109 if(mn[2]>((*((v)+2))-r)) mn[2]=((*((v)+2))-r); \
5110 if(mx[2]<((*((v)+2))+r)) mx[2]=((*((v)+2))+r); \
5111 if(mn[3]>((*((v)+3))-r)) mn[3]=((*((v)+3))-r); \
5112 if(mx[3]<((*((v)+3))+r)) mx[3]=((*((v)+3))+r); }}
5113
5114 for (auto it = I->begin(); !it.is_stop(); ++it) {
5115 const auto pc = it.data();
5116 const auto op = it.op_code();
5117
5118 switch (op) {
5119 case CGO_VERTEX:
5120 check_extent(pc, 0);
5121 break;
5122 case CGO_SPHERE:
5123 case CGO_ELLIPSOID:
5124 check_extent(pc, *(pc + 3));
5125 break;
5126 case CGO_CYLINDER:
5127 case CGO_CONE:
5128 case CGO_SAUSAGE:
5129 case CGO_CUSTOM_CYLINDER:
5130 case CGO_CUSTOM_CYLINDER_ALPHA:
5131 check_extent(pc, *(pc + 6));
5132 check_extent(pc + 3, *(pc + 6));
5133 break;
5134 case CGO_TRIANGLE:
5135 check_extent(pc, 0);
5136 check_extent(pc + 3, 0);
5137 check_extent(pc + 6, 0);
5138 break;
5139 case CGO_DRAW_ARRAYS:
5140 {
5141 const cgo::draw::arrays * sp = reinterpret_cast<decltype(sp)>(pc);
5142 const float *pct = sp->floatdata;
5143 int pl;
5144
5145 if (sp->arraybits & CGO_VERTEX_ARRAY){
5146 for (pl = 0; pl < sp->nverts; pl++){
5147 check_extent(pct, 0);
5148 pct += 3;
5149 }
5150 }
5151 if (sp->arraybits & CGO_NORMAL_ARRAY){
5152 for (pl = 0; pl < sp->nverts; pl++){
5153 pct += 3;
5154 }
5155 }
5156 if (sp->arraybits & CGO_COLOR_ARRAY){
5157 for (pl = 0; pl < sp->nverts; pl++){
5158 pct += 4;
5159 }
5160 }
5161 if (sp->arraybits & CGO_PICK_COLOR_ARRAY){
5162 for (pl = 0; pl < sp->nverts; pl++){
5163 pct += 3;
5164 }
5165 }
5166 }
5167 break;
5168 case CGO_BOUNDING_BOX:
5169 {
5170 if (!result){
5171 mn[0]=(*pc);
5172 mn[1]=*(pc+1);
5173 mn[2]=*(pc+2);
5174 mx[0]=*(pc+3);
5175 mx[1]=*(pc+4);
5176 mx[2]=*(pc+5);
5177 result = true;
5178 } else {
5179 if(mn[0]>*pc) mn[0]=(*pc);
5180 if(mn[1]>*(pc+1)) mn[1]=*(pc+1);
5181 if(mn[2]>*(pc+2)) mn[2]=*(pc+2);
5182 if(mx[0]<*(pc+3)) mx[0]=*(pc+3);
5183 if(mx[1]<*(pc+4)) mx[1]=*(pc+4);
5184 if(mx[2]<*(pc+5)) mx[2]=*(pc+5);
5185 }
5186 }
5187 }
5188 }
5189 return (result);
5190 }
5191
CGOHasNormals(const CGO * I)5192 int CGOHasNormals(const CGO * I)
5193 {
5194 for (auto it = I->begin(); !it.is_stop(); ++it) {
5195 switch (it.op_code()) {
5196 case CGO_NORMAL:
5197 case CGO_SPHERE:
5198 case CGO_ELLIPSOID:
5199 case CGO_CYLINDER:
5200 case CGO_CONE:
5201 case CGO_SAUSAGE:
5202 case CGO_CUSTOM_CYLINDER:
5203 case CGO_CUSTOM_CYLINDER_ALPHA:
5204 return true;
5205 case CGO_DRAW_ARRAYS:
5206 if (it.cast<cgo::draw::arrays>()->arraybits & CGO_NORMAL_ARRAY) {
5207 return true;
5208 }
5209 break;
5210 }
5211 }
5212 return false;
5213 }
5214
CGOQuadricToEllipsoid(const float * v,float r,const float * q,float * r_el,float * n0,float * n1,float * n2)5215 static int CGOQuadricToEllipsoid(const float *v, float r, const float *q,
5216 float *r_el, float *n0, float *n1, float *n2)
5217 {
5218 int ok = false;
5219 double inp_matrix[16];
5220 double e_val[4];
5221 double e_vec[16];
5222 double inverse[16];
5223
5224 inp_matrix[0] = q[0];
5225 inp_matrix[1] = q[3];
5226 inp_matrix[2] = q[5];
5227 inp_matrix[3] = q[6];
5228 inp_matrix[4] = q[3];
5229 inp_matrix[5] = q[1];
5230 inp_matrix[6] = q[4];
5231 inp_matrix[7] = q[7];
5232 inp_matrix[8] = q[5];
5233 inp_matrix[9] = q[4];
5234 inp_matrix[10] = q[2];
5235 inp_matrix[11] = q[8];
5236 inp_matrix[12] = q[6];
5237 inp_matrix[13] = q[7];
5238 inp_matrix[14] = q[8];
5239 inp_matrix[15] = q[9];
5240
5241 if(xx_matrix_invert(inverse, inp_matrix, 4)) {
5242
5243 /* inverse now contains Uij coefficients */
5244 float pradius = sqrt1f(-1 / inverse[15]);
5245 int n_rot;
5246
5247 if(xx_matrix_jacobi_solve(e_vec, e_val, &n_rot, inverse, 4)) {
5248 float mag[3];
5249 float scale[3];
5250 float mx;
5251 n0[0] = e_vec[0];
5252 n0[1] = e_vec[4];
5253 n0[2] = e_vec[8];
5254 n1[0] = e_vec[1];
5255 n1[1] = e_vec[5];
5256 n1[2] = e_vec[9];
5257 n2[0] = e_vec[2];
5258 n2[1] = e_vec[6];
5259 n2[2] = e_vec[10];
5260
5261 normalize3f(n0);
5262 normalize3f(n1);
5263 normalize3f(n2);
5264 mag[0] = sqrt1f(e_val[0]);
5265 mag[1] = sqrt1f(e_val[1]);
5266 mag[2] = sqrt1f(e_val[2]);
5267
5268 mx = mag[0];
5269 if(mx < mag[1])
5270 mx = mag[1];
5271 if(mx < mag[2])
5272 mx = mag[2];
5273
5274 scale[0] = mag[0] / mx;
5275 scale[1] = mag[1] / mx;
5276 scale[2] = mag[2] / mx;
5277
5278 scale3f(n0, scale[0], n0);
5279 scale3f(n1, scale[1], n1);
5280 scale3f(n2, scale[2], n2);
5281
5282 *r_el = mx * pradius;
5283 ok = true;
5284 }
5285 }
5286 return ok;
5287 }
5288
CGORenderQuadricRay(CRay * ray,float * v,float r,float * q)5289 static int CGORenderQuadricRay(CRay * ray, float *v, float r, float *q)
5290 {
5291 float r_el, n0[3], n1[3], n2[3];
5292 int ok = true;
5293 if(CGOQuadricToEllipsoid(v, r, q, &r_el, n0, n1, n2))
5294 ok &= ray->ellipsoid3fv(v, r_el, n0, n1, n2);
5295 return ok;
5296 }
5297
5298
5299 /* ======== Raytrace Renderer ======== */
5300
CGORenderRay(CGO * I,CRay * ray,RenderInfo * info,const float * color,ObjectGadgetRamp * ramp,CSetting * set1,CSetting * set2)5301 int CGORenderRay(CGO * I, CRay * ray, RenderInfo * info, const float *color, ObjectGadgetRamp *ramp, CSetting * set1, CSetting * set2)
5302 {
5303 #ifdef _PYMOL_NO_RAY
5304 return 0;
5305 #else
5306 int vc = 0;
5307 float linewidth = 1.0F;
5308 float widthscale = 0.15F;
5309 float lineradius, dotradius, dotwidth;
5310 float white[] = { 1.0, 1.0, 1.0 };
5311 float zee[] = { 0.0, 0.0, 1.0 };
5312 int ok = true;
5313 const float *n0 = NULL, *n1 = NULL, *n2 = NULL, *v0 = NULL, *v1 = NULL, *v2 = NULL, *c0 =
5314 NULL, *c1 = NULL, *c2 = NULL;
5315 float rampc0[3], rampc1[3], rampc2[3];
5316 int mode = -1;
5317 /* workaround; multi-state ray-trace bug */
5318 if (!I) {
5319 assert("TODO investigate" && false);
5320 return 0; /* not sure if it should return 0 or 1, 0 - fails, but is it a memory issue? might not be since the arg is NULL */
5321 }
5322
5323 I->G->CGORenderer->alpha =
5324 1.0F - SettingGet_f(I->G, set1, set2, cSetting_cgo_transparency);
5325
5326 widthscale = SettingGet_f(I->G, set1, set2, cSetting_cgo_ray_width_scale);
5327
5328 /* printf("debug %8.9f\n",SceneGetScreenVertexScale(I->G,zee)); */
5329 linewidth = SettingGet_f(I->G, set1, set2, cSetting_cgo_line_width);
5330 if(linewidth < 0.0F)
5331 linewidth = 1.0F;
5332 lineradius = SettingGet_f(I->G, set1, set2, cSetting_cgo_line_radius);
5333 dotwidth = SettingGet_f(I->G, set1, set2, cSetting_cgo_dot_width);
5334 dotradius = SettingGet_f(I->G, set1, set2, cSetting_cgo_dot_radius);
5335 if(lineradius < 0.0F)
5336 lineradius = linewidth * ray->PixelRadius / 2.0F;
5337 if(dotradius < 0.0F)
5338 dotradius = dotwidth * ray->PixelRadius / 2.0F;
5339 if(widthscale < 0.0F)
5340 widthscale = ray->PixelRadius / 2.0F;
5341 if(color)
5342 c0 = color;
5343 else
5344 c0 = white;
5345 ray->transparentf(1.0F - I->G->CGORenderer->alpha);
5346
5347 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
5348 const auto pc = it.data();
5349 const auto op = it.op_code();
5350
5351 switch (op) {
5352 case CGO_BEGIN:
5353 mode = CGO_get_int(pc);
5354 vc = 0;
5355 n0 = zee;
5356 break;
5357 case CGO_END:
5358 switch (mode) {
5359 case GL_LINE_LOOP:
5360 if(vc > 1)
5361 ok &= ray->sausage3fv(v0, v2, lineradius, c0, c2);
5362 break;
5363 }
5364 mode = -1;
5365 break;
5366 case CGO_WIDTHSCALE:
5367 widthscale = *pc;
5368 lineradius = widthscale * linewidth;
5369 dotradius = widthscale * dotwidth;
5370 break;
5371 case CGO_DOTWIDTH:
5372 dotwidth = *pc;
5373 dotradius = widthscale * dotwidth;
5374 break;
5375 case CGO_LINEWIDTH:
5376 linewidth = *pc;
5377 lineradius = widthscale * linewidth;
5378 break;
5379 case CGO_NORMAL:
5380 n0 = pc;
5381 break;
5382 case CGO_SPECIAL_WITH_ARG:
5383 {
5384 float argval = *(pc + 1);
5385 switch (*(int*)pc){
5386 case LINEWIDTH_FOR_LINES:
5387 linewidth = argval;
5388 lineradius = widthscale * linewidth;
5389 }
5390 }
5391 break;
5392 case CGO_SPECIAL:
5393 {
5394 switch ((*(int*)pc)){
5395 case LINEWIDTH_DYNAMIC_WITH_SCALE_RIBBON:
5396 {
5397 float radius = SettingGet_f(I->G, set1, set2, cSetting_ribbon_radius);
5398 if(radius == 0.0F) {
5399 float ribbon_width = SettingGet_f(I->G, set1, set2, cSetting_ribbon_width);
5400 float line_width = SceneGetDynamicLineWidth(info, ribbon_width);
5401 SceneGetDynamicLineWidth(info, line_width);
5402 radius = ray->PixelRadius * line_width / 2.0F;
5403 }
5404 lineradius = radius;
5405 }
5406 break;
5407 case LINEWIDTH_FOR_LINES:
5408 {
5409 float radius = SettingGet_f(I->G, set1, set2, cSetting_line_radius);
5410 if(radius <= 0.0F) {
5411 float line_width = SettingGet_f(I->G, set1, set2, cSetting_line_width);
5412 line_width = SceneGetDynamicLineWidth(info, line_width);
5413 radius = ray->PixelRadius * line_width / 2.0F;
5414 }
5415 lineradius = radius;
5416 }
5417 break;
5418 case CYLINDER_WIDTH_FOR_NONBONDED:
5419 case LINEWIDTH_WITH_SCALE:
5420 {
5421 float line_width = SettingGet_f(I->G, set1, set2, cSetting_line_width);
5422 line_width = SceneGetDynamicLineWidth(info, line_width);
5423 lineradius = widthscale * line_width / 2.f;
5424 }
5425 break;
5426 }
5427 }
5428 break;
5429 case CGO_COLOR:
5430 c0 = pc;
5431 ray->color3fv(c0);
5432 break;
5433 case CGO_ALPHA:
5434 I->G->CGORenderer->alpha = *pc;
5435 ray->transparentf(1.0F - *pc);
5436 break;
5437 case CGO_LINE:
5438 {
5439 auto line = reinterpret_cast<cgo::draw::line *>(pc);
5440 ok &= ray->sausage3fv(line->vertex1, line->vertex2, lineradius, c0, c0);
5441 }
5442 break;
5443 case CGO_SPLITLINE:
5444 {
5445 auto splitline = reinterpret_cast<cgo::draw::splitline *>(pc);
5446 float color2[] = { CONVERT_COLOR_VALUE(splitline->color2[0]),
5447 CONVERT_COLOR_VALUE(splitline->color2[1]),
5448 CONVERT_COLOR_VALUE(splitline->color2[2]) };
5449 if (splitline->flags & cgo::draw::splitline::interpolation){
5450 ok &= ray->sausage3fv(splitline->vertex1, splitline->vertex2, lineradius, c0, color2);
5451 } else {
5452 float mid[3];
5453 add3f(splitline->vertex1, splitline->vertex2, mid);
5454 mult3f(mid, .5f, mid);
5455 ok &= ray->customCylinder3fv(splitline->vertex1, mid,
5456 lineradius, c0, c0, 2, 0);
5457 ok &= ray->customCylinder3fv(mid, splitline->vertex2,
5458 lineradius, color2, color2, 0, 2);
5459 }
5460 }
5461 break;
5462 case CGO_VERTEX_CROSS:
5463 {
5464 float pt1[3], pt2[3];
5465 float nonbonded_size =
5466 SettingGet_f(I->G, set1, set2, cSetting_nonbonded_size);
5467 copy3f(pc, pt1);
5468 copy3f(pc, pt2);
5469 pt1[0] -= nonbonded_size;
5470 pt2[0] += nonbonded_size;
5471 ok &= ray->sausage3fv(pt1, pt2, lineradius, c0, c0);
5472
5473 copy3f(pc, pt1);
5474 copy3f(pc, pt2);
5475 pt1[1] -= nonbonded_size;
5476 pt2[1] += nonbonded_size;
5477 ok &= ray->sausage3fv(pt1, pt2, lineradius, c0, c0);
5478
5479 copy3f(pc, pt1);
5480 copy3f(pc, pt2);
5481 pt1[2] -= nonbonded_size;
5482 pt2[2] += nonbonded_size;
5483 ok &= ray->sausage3fv(pt1, pt2, lineradius, c0, c0);
5484 }
5485 break;
5486 case CGO_VERTEX_BEGIN_LINE_STRIP:
5487 case CGO_VERTEX:
5488 v0 = pc;
5489
5490 if (ramp){
5491 if (!ObjectGadgetRampInterVertex(ramp, v0, rampc0, -1)){
5492 copy3f(white, rampc0);
5493 }
5494 c0 = rampc0;
5495 }
5496 switch (mode) {
5497 case GL_POINTS:
5498 ok &= ray->sphere3fv(v0, dotradius);
5499 break;
5500 case GL_LINES:
5501 if(vc & 0x1)
5502 ok &= ray->sausage3fv(v0, v1, lineradius, c0, c1);
5503 v1 = v0;
5504 if (!ramp){
5505 c1 = c0;
5506 }
5507 break;
5508 case GL_LINE_STRIP:
5509 if(vc){
5510 ok &= ray->sausage3fv(v0, v1, lineradius, c0, c1);
5511 }
5512 v1 = v0;
5513 if (!ramp){
5514 c1 = c0;
5515 }
5516 break;
5517 case GL_LINE_LOOP:
5518 if(vc)
5519 ok &= ray->sausage3fv(v0, v1, lineradius, c0, c1);
5520 else {
5521 v2 = v0;
5522 c2 = c0;
5523 }
5524 v1 = v0;
5525 if (!ramp)
5526 c1 = c0;
5527 break;
5528 case GL_TRIANGLES:
5529 if( ((vc + 1) % 3) == 0)
5530 ok &= ray->triangle3fv(v0, v1, v2, n0, n1, n2, c0, c1, c2);
5531 v2 = v1;
5532 n2 = n1;
5533 v1 = v0;
5534 n1 = n0;
5535 if (!ramp){
5536 c2 = c1;
5537 c1 = c0;
5538 }
5539 break;
5540 case GL_TRIANGLE_STRIP:
5541 if(vc > 1)
5542 ok &= ray->triangle3fv(v0, v1, v2, n0, n1, n2, c0, c1, c2);
5543 v2 = v1;
5544 n2 = n1;
5545 v1 = v0;
5546 n1 = n0;
5547 if (!ramp){
5548 c2 = c1;
5549 c1 = c0;
5550 }
5551 break;
5552 case GL_TRIANGLE_FAN:
5553 if(vc > 1)
5554 ok &= ray->triangle3fv(v0, v1, v2, n0, n1, n2, c0, c1, c2);
5555 else if(!vc) {
5556 n2 = n0;
5557 v2 = v0;
5558 if (!ramp)
5559 c2 = c0;
5560 }
5561 v1 = v0;
5562 n1 = n0;
5563 if (!ramp)
5564 c1 = c0;
5565 break;
5566 }
5567 if (ramp){
5568 switch (mode){
5569 case GL_TRIANGLES:
5570 case GL_TRIANGLE_STRIP:
5571 case GL_TRIANGLE_FAN:
5572 copy3f(rampc1, rampc2);
5573 c2 = rampc2;
5574 case GL_LINES:
5575 case GL_LINE_STRIP:
5576 case GL_LINE_LOOP:
5577 copy3f(rampc0, rampc1);
5578 c1 = rampc1;
5579 break;
5580 }
5581 }
5582 vc++;
5583 break;
5584 case CGO_SPHERE:
5585 ray->color3fv(c0);
5586 ok &= ray->sphere3fv(pc, *(pc + 3));
5587 break;
5588 case CGO_ELLIPSOID:
5589 ray->color3fv(c0);
5590 ok &= ray->ellipsoid3fv(pc, *(pc + 3), pc + 4, pc + 7, pc + 10);
5591 break;
5592 case CGO_QUADRIC:
5593 ray->color3fv(c0);
5594 ok &= CGORenderQuadricRay(ray, pc, *(pc + 3), pc + 4);
5595 break;
5596 case CGO_CONE:
5597 ok &= ray->cone3fv(pc, pc + 3, *(pc + 6), *(pc + 7), pc + 8, pc + 11,
5598 (int) *(pc + 14), (int) *(pc + 15));
5599 break;
5600 case CGO_CUSTOM_CYLINDER:
5601 {
5602 auto cyl = reinterpret_cast<cgo::draw::custom_cylinder*>(pc);
5603 ok &= ray->customCylinder3fv(*cyl);
5604 }
5605 break;
5606 case CGO_CUSTOM_CYLINDER_ALPHA:
5607 {
5608 auto cyl = reinterpret_cast<cgo::draw::custom_cylinder_alpha*>(pc);
5609 ok &= ray->customCylinderAlpha3fv(*cyl);
5610 }
5611 break;
5612 case CGO_SHADER_CYLINDER:
5613 {
5614 float p2[3];
5615 int cap = CGO_get_int(pc + 7);
5616 int cap1 = cap & 1 ? ( (cap & cCylShaderCap1RoundBit) ? 2 : 1 ) : 0;
5617 int cap2 = cap & 2 ? ( (cap & cCylShaderCap2RoundBit) ? 2 : 1 ) : 0;
5618 add3f(pc, pc + 3, p2);
5619 ok &= ray->customCylinder3fv(pc, p2, *(pc + 6), ray->CurColor, ray->CurColor,
5620 cap1, cap2);
5621 }
5622 break;
5623 case CGO_SHADER_CYLINDER_WITH_2ND_COLOR:
5624 {
5625 auto cyl = reinterpret_cast<cgo::draw::shadercylinder2ndcolor*>(pc);
5626 float v1[3];
5627 int cap = cyl->cap;
5628 int fcap = (cap & 1) ? ((cap & cCylShaderCap1RoundBit) ? 2 : 1) : 0;
5629 int bcap = (cap & 2) ? ((cap & cCylShaderCap2RoundBit) ? 2 : 1) : 0;
5630 int colorinterp = cap & cCylShaderInterpColor;
5631 const float *color1 = c0;
5632 const float *color2 = cyl->color2;
5633 add3f(cyl->origin, cyl->axis, v1);
5634 float alpha1 = I->G->CGORenderer->alpha;
5635 float alpha2 = cyl->alpha >= 0.f ? cyl->alpha : alpha1;
5636 if (colorinterp || equal3f(color1, color2)) {
5637 ok &= ray->customCylinder3fv(pc, v1, cyl->tube_size, color1, color2, fcap, bcap, alpha1, alpha2);
5638 } else {
5639 float mid[3];
5640 mult3f(cyl->axis, .5f, mid);
5641 add3f(cyl->origin, mid, mid);
5642
5643 ray->color3fv(c0);
5644 ok &= ray->customCylinder3fv(cyl->origin, mid, cyl->tube_size, color1, color1, fcap, 0, alpha1, alpha2);
5645 ray->color3fv(cyl->color2);
5646 ok &= ray->customCylinder3fv(mid, v1, cyl->tube_size, color2, color2, 0, bcap, alpha1, alpha2);
5647 }
5648 }
5649 break;
5650 case CGO_CYLINDER:
5651 {
5652 auto *cyl = reinterpret_cast<cgo::draw::cylinder*>(pc);
5653 ok &= ray->cylinder3fv(*cyl);
5654 }
5655 break;
5656 case CGO_SAUSAGE:
5657 ok &= ray->sausage3fv(pc, pc + 3, *(pc + 6), pc + 7, pc + 10);
5658 break;
5659 case CGO_TRIANGLE:
5660 ok &= ray->triangle3fv(pc, pc + 3, pc + 6, pc + 9, pc + 12, pc + 15, pc + 18,
5661 pc + 21, pc + 24);
5662 break;
5663 case CGO_DRAW_ARRAYS:
5664 {
5665 cgo::draw::arrays * sp = reinterpret_cast<decltype(sp)>(pc);
5666 int mode = sp->mode, arrays = sp->arraybits, narrays = sp->narrays, nverts = sp->nverts, v, pl, plc;
5667 float *vertexVals = sp->floatdata;
5668 float *normalVals = 0, *colorVals = 0;
5669 int offset = 0;
5670 (void)narrays;
5671 if (arrays & CGO_VERTEX_ARRAY){
5672 vertexVals = sp->floatdata;
5673 offset += nverts * 3;
5674 }
5675 if (arrays & CGO_NORMAL_ARRAY){
5676 normalVals = sp->floatdata + offset;
5677 offset += nverts * 3;
5678 }
5679 if (arrays & CGO_COLOR_ARRAY){
5680 colorVals = sp->floatdata + offset;
5681 offset += nverts * 4;
5682 }
5683 if (arrays & CGO_PICK_COLOR_ARRAY){
5684 offset += nverts * 3;
5685 }
5686 vc = 0;
5687 for (v=0, pl=0, plc=0; ok && v<nverts; v++, pl+=3, plc+=4){
5688 if (normalVals){
5689 n0 = &normalVals[pl];
5690 }
5691 if (colorVals){
5692 c0 = &colorVals[plc];
5693 ray->color3fv(c0);
5694 ray->transparentf(1.0f - c0[3]);
5695 }
5696 if (vertexVals){
5697 v0 = &vertexVals[pl];
5698 }
5699 switch (mode){
5700 case GL_POINTS:
5701 ok &= ray->sphere3fv(v0, dotradius);
5702 break;
5703 case GL_LINES:
5704 if(vc & 0x1)
5705 ok &= ray->sausage3fv(v0, v1, lineradius, c0, c1);
5706 v1 = v0;
5707 c1 = c0;
5708 break;
5709 case GL_LINE_STRIP:
5710 if(vc)
5711 ok &= ray->sausage3fv(v0, v1, lineradius, c0, c1);
5712 v1 = v0;
5713 c1 = c0;
5714 break;
5715 case GL_LINE_LOOP:
5716 if(vc)
5717 ok &= ray->sausage3fv(v0, v1, lineradius, c0, c1);
5718 else {
5719 v2 = v0;
5720 c2 = c0;
5721 }
5722 v1 = v0;
5723 c1 = c0;
5724 break;
5725 case GL_TRIANGLES:
5726 if( ((vc + 1) % 3) == 0)
5727 ok &= ray->triangle3fv(v0, v1, v2, n0, n1, n2, c0, c1, c2);
5728 v2 = v1;
5729 c2 = c1;
5730 n2 = n1;
5731 v1 = v0;
5732 c1 = c0;
5733 n1 = n0;
5734 break;
5735 case GL_TRIANGLE_STRIP:
5736 if(vc > 1)
5737 ok &= ray->triangle3fv(v0, v1, v2, n0, n1, n2, c0, c1, c2);
5738 v2 = v1;
5739 c2 = c1;
5740 n2 = n1;
5741 v1 = v0;
5742 c1 = c0;
5743 n1 = n0;
5744 break;
5745 case GL_TRIANGLE_FAN:
5746 if(vc > 1)
5747 ok &= ray->triangle3fv(v0, v1, v2, n0, n1, n2, c0, c1, c2);
5748 else if(!vc) {
5749 n2 = n0;
5750 v2 = v0;
5751 c2 = c0;
5752 }
5753 v1 = v0;
5754 c1 = c0;
5755 n1 = n0;
5756 break;
5757 }
5758 vc++;
5759 }
5760 }
5761 break;
5762 default:
5763 break;
5764 }
5765 }
5766
5767 if (ok)
5768 ray->transparentf(0.0F);
5769 return ok;
5770 #endif
5771 }
5772
5773
5774 /* ======== GL Rendering ======== */
5775
5776 static int CGO_gl_begin_WARNING_CALLED = false, CGO_gl_end_WARNING_CALLED = false, CGO_gl_vertex_WARNING_CALLED = false;
CGO_gl_begin(CCGORenderer * I,CGO_op_data pc)5777 static void CGO_gl_begin(CCGORenderer * I, CGO_op_data pc){
5778 if (I->use_shader){
5779 if (!CGO_gl_begin_WARNING_CALLED) {
5780 PRINTFB(I->G, FB_CGO, FB_Warnings) " CGO_gl_begin() is called but not implemented in OpenGLES\n" ENDFB(I->G);
5781 CGO_gl_begin_WARNING_CALLED = true;
5782 }
5783 } else {
5784 int mode = CGO_get_int(*pc);
5785 if (I->debug)
5786 mode = CGOConvertDebugMode(I->debug, mode);
5787 glBegin(mode);
5788 }
5789 }
CGO_gl_end(CCGORenderer * I,CGO_op_data)5790 static void CGO_gl_end(CCGORenderer * I, CGO_op_data){
5791 if (I->use_shader){
5792 if (!CGO_gl_end_WARNING_CALLED) {
5793 PRINTFB(I->G, FB_CGO, FB_Warnings) " CGO_gl_end() is called but not implemented in OpenGLES\n" ENDFB(I->G);
5794 CGO_gl_end_WARNING_CALLED = true;
5795 }
5796 } else {
5797 glEnd();
5798 }
5799 }
CGO_gl_vertex(CCGORenderer * I,CGO_op_data v)5800 static void CGO_gl_vertex(CCGORenderer * I, CGO_op_data v){
5801 if (I->use_shader){
5802 if (!CGO_gl_vertex_WARNING_CALLED) {
5803 PRINTFB(I->G, FB_CGO, FB_Warnings) " CGO_gl_vertex() is called but not implemented in OpenGLES\n" ENDFB(I->G);
5804 CGO_gl_vertex_WARNING_CALLED = true;
5805 }
5806 } else {
5807 glVertex3fv(*v);
5808 }
5809 }
5810
CGO_gl_vertex_cross(CCGORenderer * I,CGO_op_data v)5811 static void CGO_gl_vertex_cross(CCGORenderer * I, CGO_op_data v){
5812 #ifndef PURE_OPENGL_ES_2
5813 if (I->use_shader){
5814 #endif
5815 if (!CGO_gl_vertex_WARNING_CALLED) {
5816 PRINTFB(I->G, FB_CGO, FB_Warnings) " CGO_gl_vertex() is called but not implemented in OpenGLES\n" ENDFB(I->G);
5817 CGO_gl_vertex_WARNING_CALLED = true;
5818 }
5819 #ifndef PURE_OPENGL_ES_2
5820 } else {
5821 CSetting * set1 = NULL, * set2 = NULL;
5822 if (I->rep&&I->rep->cs) set1 = I->rep->cs->Setting;
5823 if (I->rep&&I->rep->obj) set2 = I->rep->obj->Setting;
5824 float nonbonded_size =
5825 SettingGet_f(I->G, set1, set2, cSetting_nonbonded_size);
5826 float pt[3];
5827 copy3f(*v, pt);
5828 pt[0] -= nonbonded_size;
5829 glVertex3fv(pt);
5830 pt[0] += 2 * nonbonded_size;
5831 glVertex3fv(pt);
5832 copy3f(*v, pt);
5833 pt[1] -= nonbonded_size;
5834 glVertex3fv(pt);
5835 pt[1] += 2 * nonbonded_size;
5836 glVertex3fv(pt);
5837 copy3f(*v, pt);
5838 pt[2] -= nonbonded_size;
5839 glVertex3fv(pt);
5840 pt[2] += 2 * nonbonded_size;
5841 glVertex3fv(pt);
5842 }
5843 #endif
5844 }
5845
CGO_gl_line(CCGORenderer * I,CGO_op_data v)5846 static void CGO_gl_line(CCGORenderer * I, CGO_op_data v){
5847 #ifndef PURE_OPENGL_ES_2
5848 if (!I->use_shader){
5849 auto line = reinterpret_cast<const cgo::draw::line *>(*v);
5850 glVertex3fv(line->vertex1);
5851 glVertex3fv(line->vertex2);
5852 }
5853 #endif
5854 }
5855
CGO_gl_splitline(CCGORenderer * I,CGO_op_data v)5856 static void CGO_gl_splitline(CCGORenderer * I, CGO_op_data v){
5857 #ifndef PURE_OPENGL_ES_2
5858 if (!I->use_shader){
5859 auto splitline = reinterpret_cast<const cgo::draw::splitline *>(*v);
5860 bool interpolation = splitline->flags & cgo::draw::splitline::interpolation;
5861 bool equal_colors = splitline->flags & cgo::draw::splitline::equal_colors;
5862 bool no_split_for_pick = splitline->flags & cgo::draw::splitline::no_split_for_pick;
5863
5864 if (I->isPicking){
5865 if (no_split_for_pick){
5866 glVertex3fv(splitline->vertex1);
5867 glVertex3fv(splitline->vertex2);
5868 } else {
5869 float h[3];
5870 average3f(splitline->vertex1, splitline->vertex2, h);
5871 glVertex3fv(splitline->vertex1);
5872 glVertex3fv(h);
5873 unsigned char col[4];
5874 AssignNewPickColor(nullptr, I->info->pick, col, &I->rep->context,
5875 splitline->index, splitline->bond);
5876 glColor4ubv(col);
5877 glVertex3fv(h);
5878 glVertex3fv(splitline->vertex2);
5879 }
5880 } else if (interpolation || equal_colors){
5881 glVertex3fv(splitline->vertex1);
5882 if (!equal_colors)
5883 glColor4ub(splitline->color2[0], splitline->color2[1], splitline->color2[2], CLIP_COLOR_VALUE(I->alpha));
5884 glVertex3fv(splitline->vertex2);
5885 } else {
5886 float h[3];
5887 average3f(splitline->vertex1, splitline->vertex2, h);
5888 glVertex3fv(splitline->vertex1);
5889 glVertex3fv(h);
5890 glColor4ub(splitline->color2[0], splitline->color2[1], splitline->color2[2], CLIP_COLOR_VALUE(I->alpha));
5891 glVertex3fv(h);
5892 glVertex3fv(splitline->vertex2);
5893 }
5894 }
5895 #endif
5896 }
5897
5898
CGO_gl_normal(CCGORenderer * I,CGO_op_data varg)5899 static void CGO_gl_normal(CCGORenderer * I, CGO_op_data varg){
5900 const float* v = *varg;
5901 if (I->use_shader){
5902 glVertexAttrib3fv(VERTEX_NORMAL, v);
5903 } else {
5904 glNormal3f(v[0],v[1],v[2]);
5905 }
5906 }
5907
CGO_gl_draw_arrays(CCGORenderer * I,CGO_op_data pc)5908 static void CGO_gl_draw_arrays(CCGORenderer * I, CGO_op_data pc){
5909 auto sp = reinterpret_cast<const cgo::draw::arrays*>(*pc);
5910 int mode = sp->mode, arrays = sp->arraybits, narrays = sp->narrays, nverts = sp->nverts;
5911 const float* data = sp->floatdata;
5912 (void) narrays;
5913 #ifndef PURE_OPENGL_ES_2
5914 if (I->use_shader){
5915 #endif
5916
5917 if (arrays & CGO_VERTEX_ARRAY) glEnableVertexAttribArray(VERTEX_POS);
5918 if (arrays & CGO_NORMAL_ARRAY) glEnableVertexAttribArray(VERTEX_NORMAL);
5919 if (I->isPicking){
5920 if (arrays & CGO_PICK_COLOR_ARRAY){
5921 glEnableVertexAttribArray(VERTEX_COLOR);
5922 }
5923 } else {
5924 if (arrays & CGO_COLOR_ARRAY)
5925 glEnableVertexAttribArray(VERTEX_COLOR);
5926 }
5927
5928 if (arrays & CGO_VERTEX_ARRAY){
5929 #ifdef _WEBGL
5930 #else
5931 glVertexAttribPointer(VERTEX_POS, VERTEX_POS_SIZE, GL_FLOAT, GL_FALSE, 0, data);
5932 #endif
5933 data += nverts*3;
5934 }
5935 if (arrays & CGO_NORMAL_ARRAY){
5936 #ifdef _WEBGL
5937 #else
5938 glVertexAttribPointer(VERTEX_NORMAL, VERTEX_NORMAL_SIZE, GL_FLOAT, GL_FALSE, 0, data);
5939 #endif
5940 data += nverts*3;
5941 }
5942 if (I->isPicking){
5943 if (arrays & CGO_COLOR_ARRAY){
5944 data += nverts*4;
5945 }
5946 if (arrays & CGO_PICK_COLOR_ARRAY){
5947 #ifdef _WEBGL
5948 glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
5949 glBufferData(GL_ARRAY_BUFFER, nverts * 4, data, GL_STATIC_DRAW);
5950 glVertexAttribPointer(VERTEX_COLOR, VERTEX_COLOR_SIZE, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
5951 #else
5952 glVertexAttribPointer(VERTEX_COLOR, VERTEX_COLOR_SIZE, GL_UNSIGNED_BYTE, GL_FALSE, 0, data);
5953 #endif
5954 data += nverts*3;
5955 }
5956 } else {
5957 if (arrays & CGO_COLOR_ARRAY){
5958 #ifdef _WEBGL
5959 #else
5960 glVertexAttribPointer(VERTEX_COLOR, VERTEX_COLOR_SIZE, GL_FLOAT, GL_FALSE, 0, data);
5961 #endif
5962 data += nverts*4;
5963 }
5964 if (arrays & CGO_PICK_COLOR_ARRAY){
5965 data += nverts*3;
5966 }
5967 }
5968 if (I->debug){
5969 mode = CGOConvertDebugMode(I->debug, mode);
5970 }
5971 glDrawArrays(mode, 0, nverts);
5972
5973 if (I->isPicking){
5974 if (arrays & CGO_PICK_COLOR_ARRAY){
5975 glDisableVertexAttribArray(VERTEX_COLOR);
5976 }
5977 } else {
5978 if (arrays & CGO_COLOR_ARRAY)
5979 glDisableVertexAttribArray(VERTEX_COLOR);
5980 }
5981 if (arrays & CGO_VERTEX_ARRAY) glDisableVertexAttribArray(VERTEX_POS);
5982 if (arrays & CGO_NORMAL_ARRAY) glDisableVertexAttribArray(VERTEX_NORMAL);
5983
5984 #ifndef PURE_OPENGL_ES_2
5985 } else {
5986
5987 int pl, pla, plc;
5988 const float *vertexVals = nullptr;
5989 const float *colorVals = 0, *normalVals = 0, *tmp_ptr;
5990 const uchar *pickColorVals = 0, *tmp_pc_ptr;
5991 float alpha = I->alpha;
5992 if (arrays & CGO_VERTEX_ARRAY){
5993 vertexVals = data;
5994 data += nverts*3;
5995 }
5996 if (arrays & CGO_NORMAL_ARRAY){
5997 normalVals = data;
5998 data += nverts*3;
5999 }
6000 if (I->isPicking){
6001 alpha = 1.f;
6002 if (arrays & CGO_COLOR_ARRAY){
6003 data += nverts*4;
6004 }
6005 if (arrays & CGO_PICK_COLOR_ARRAY){
6006 pickColorVals = (uchar*)data;
6007 data += nverts*3;
6008 }
6009 } else {
6010 if (arrays & CGO_COLOR_ARRAY){
6011 colorVals = data;
6012 data += nverts*4;
6013 }
6014 if (arrays & CGO_PICK_COLOR_ARRAY){
6015 data += nverts*3;
6016 }
6017 }
6018 if (arrays & CGO_ACCESSIBILITY_ARRAY) data += nverts;
6019
6020 if (I->debug){
6021 mode = CGOConvertDebugMode(I->debug, mode);
6022 }
6023
6024 glBegin(mode);
6025 for (pl = 0, pla = 0, plc = 0; pl<nverts; pl++, pla+=3, plc+=4){
6026 if (pickColorVals){
6027 tmp_pc_ptr = &pickColorVals[plc]; /* the pick colors are saved with rgba */
6028 glColor4ub(tmp_pc_ptr[0], tmp_pc_ptr[1], tmp_pc_ptr[2], tmp_pc_ptr[3]);
6029 } else {
6030 if (colorVals){
6031 tmp_ptr = &colorVals[plc];
6032 glColor4f(tmp_ptr[0], tmp_ptr[1], tmp_ptr[2], alpha);
6033 }
6034 if (normalVals){
6035 tmp_ptr = &normalVals[pla];
6036 glNormal3fv(&normalVals[pla]);
6037 }
6038 }
6039 if (vertexVals){
6040 tmp_ptr = &vertexVals[pla];
6041 glVertex3fv(&vertexVals[pla]);
6042 }
6043 }
6044 glEnd();
6045 }
6046 #endif
6047 }
6048
6049 static
6050 void TransparentInfoSortIX(PyMOLGlobals * G, float *sum, float *z_value,
6051 int *ix, int n_tri, int *sort_mem, int t_mode);
6052 static
6053 void CGOReorderIndicesWithTransparentInfo(PyMOLGlobals * G, int nindices,
6054 size_t vbuf, int n_tri, int *ix,
6055 GL_C_INT_TYPE *vertexIndicesOriginal,
6056 GL_C_INT_TYPE *vertexIndices);
6057
CGO_gl_draw_buffers_indexed(CCGORenderer * I,CGO_op_data pc)6058 static void CGO_gl_draw_buffers_indexed(CCGORenderer * I, CGO_op_data pc){
6059 auto sp = reinterpret_cast<const cgo::draw::buffers_indexed*>(*pc);
6060 int mode = sp->mode, nindices = sp->nindices,
6061 nverts = sp->nverts, n_data = sp->n_data;
6062 size_t vboid = sp->vboid, iboid = sp->iboid;
6063 VertexBuffer * vbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(vboid);
6064 IndexBuffer * ibo = I->G->ShaderMgr->getGPUBuffer<IndexBuffer>(iboid);
6065 GLenum err ;
6066 CHECK_GL_ERROR_OK("beginning of CGO_gl_draw_buffers_indexed err=%d\n");
6067
6068 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
6069
6070 if (!shaderPrg){
6071 return;
6072 }
6073
6074 if (I->isPicking){
6075 int attr_a_Color = shaderPrg->GetAttribLocation("a_Color");
6076 vbo->maskAttributes({ attr_a_Color });
6077 shaderPrg->Set1i("fog_enabled", 0);
6078 shaderPrg->Set1i("lighting_enabled", 0);
6079 if (I->use_shader){
6080 if (sp->pickvboid){
6081 VertexBuffer * pickvbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->pickvboid);
6082 pickvbo->bind(shaderPrg->id, I->pick_pass());
6083 } else {
6084 glEnableVertexAttribArray(attr_a_Color);
6085 glVertexAttribPointer(attr_a_Color, VERTEX_COLOR_SIZE, GL_UNSIGNED_BYTE, GL_TRUE, 0, sp->floatdata);
6086 }
6087 }
6088 }
6089 if (n_data){
6090 // if transparency data, then sort it
6091 int n_tri = nindices/3;
6092 float *sum = sp->floatdata + nverts*3;
6093 float *z_value = sum + (nindices*3);
6094 int *ix = (int *)(z_value + n_tri);
6095 int *sort_mem = ix + n_tri;
6096 int t_mode;
6097 CSetting * set1 = NULL, * set2 = NULL;
6098 if (I->rep&&I->rep->cs) set1 = I->rep->cs->Setting;
6099 if (I->rep&&I->rep->obj) set2 = I->rep->obj->Setting;
6100 t_mode = SettingGet_i(I->G, set1, set2, cSetting_transparency_mode);
6101 if (t_mode!=3){
6102 GL_C_INT_TYPE *vertexIndicesOriginalTI = (GL_C_INT_TYPE *)(sort_mem + n_tri + 256);
6103 GL_C_INT_TYPE *vertexIndicesTI = vertexIndicesOriginalTI + nindices;
6104 TransparentInfoSortIX(I->G, sum, z_value, ix, n_tri, sort_mem, t_mode);
6105 CGOReorderIndicesWithTransparentInfo(I->G, nindices, iboid, n_tri, ix,
6106 vertexIndicesOriginalTI, vertexIndicesTI);
6107 }
6108 }
6109
6110 if (I->debug){
6111 mode = CGOConvertDebugMode(I->debug, mode);
6112 }
6113 vbo->bind(shaderPrg->id);
6114 ibo->bind();
6115
6116 CHECK_GL_ERROR_OK("CGO_gl_draw_buffers_indexed: before glDrawElements err=%d\n");
6117 glDrawElements(mode, nindices, GL_C_INT_ENUM, 0);
6118 CHECK_GL_ERROR_OK("CGO_gl_draw_buffers_indexed: after glDrawElements err=%d\n");
6119
6120 vbo->unbind();
6121 ibo->unbind();
6122
6123 if (I->isPicking) {
6124 VertexBuffer * pickvbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->pickvboid);
6125 if (pickvbo)
6126 pickvbo->unbind();
6127 }
6128
6129 CHECK_GL_ERROR_OK("CGO_gl_draw_buffers_indexed: end err=%d\n");
6130 }
6131
CGO_gl_draw_buffers_not_indexed(CCGORenderer * I,CGO_op_data pc)6132 static void CGO_gl_draw_buffers_not_indexed(CCGORenderer * I, CGO_op_data pc){
6133 const cgo::draw::buffers_not_indexed * sp = reinterpret_cast<decltype(sp)>(*pc);
6134 int mode = sp->mode;
6135
6136 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
6137 if (!shaderPrg){
6138 return;
6139 }
6140 VertexBuffer * vbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->vboid);
6141 if (!vbo)
6142 return;
6143 if (I->isPicking){
6144 int attr_a_Color = shaderPrg->GetAttribLocation("a_Color");
6145 vbo->maskAttributes({ attr_a_Color });
6146 shaderPrg->Set1i("fog_enabled", 0);
6147 shaderPrg->Set1i("lighting_enabled", 0);
6148 if (I->use_shader){
6149 if (sp->pickvboid){
6150 VertexBuffer * pickvbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->pickvboid);
6151 pickvbo->bind(shaderPrg->id, I->pick_pass());
6152 } else {
6153 glEnableVertexAttribArray(attr_a_Color);
6154 glVertexAttribPointer(attr_a_Color, VERTEX_COLOR_SIZE, GL_UNSIGNED_BYTE, GL_TRUE, 0, sp->floatdata);
6155 }
6156 }
6157 }
6158
6159 if (I->debug){
6160 mode = CGOConvertDebugMode(I->debug, mode);
6161 }
6162
6163 vbo->bind(shaderPrg->id);
6164 glDrawArrays(mode, 0, sp->nverts);
6165 vbo->unbind();
6166
6167 if (I->isPicking) {
6168 VertexBuffer * pickvbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->pickvboid);
6169 if (pickvbo)
6170 pickvbo->unbind();
6171 }
6172 }
6173
CGO_gl_mask_attribute_if_picking(CCGORenderer * I,CGO_op_data pc)6174 static void CGO_gl_mask_attribute_if_picking(CCGORenderer * I, CGO_op_data pc){
6175 if (I->isPicking){
6176 const cgo::draw::mask_attribute_if_picking * sp = reinterpret_cast<decltype(sp)>(*pc);
6177 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
6178 if (!shaderPrg){
6179 return;
6180 }
6181 VertexBuffer * vbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->vboid);
6182 if (!vbo)
6183 return;
6184 int loc = shaderPrg->GetAttribLocation(I->G->ShaderMgr->GetAttributeName(sp->attr_lookup_idx));
6185 vbo->maskAttribute(loc);
6186 }
6187 }
6188
CGO_gl_bind_vbo_for_picking(CCGORenderer * I,CGO_op_data pc)6189 static void CGO_gl_bind_vbo_for_picking(CCGORenderer * I, CGO_op_data pc){
6190 if (I->isPicking){
6191 const cgo::draw::bind_vbo_for_picking * sp = reinterpret_cast<decltype(sp)>(*pc);
6192 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
6193 if (!shaderPrg){
6194 return;
6195 }
6196 VertexBuffer * vbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->vboid);
6197 if (!vbo)
6198 return;
6199 vbo->bind(shaderPrg->id, sp->which_attr_idx + sp->npickattrs * I->pick_pass());
6200 }
6201 }
6202
CGO_gl_draw_custom(CCGORenderer * I,CGO_op_data pc)6203 static void CGO_gl_draw_custom(CCGORenderer * I, CGO_op_data pc){
6204 const cgo::draw::custom * sp = reinterpret_cast<decltype(sp)>(*pc);
6205
6206 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
6207 if (!shaderPrg){
6208 return;
6209 }
6210 VertexBuffer * vbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->vboid);
6211 if (!vbo)
6212 return;
6213 IndexBuffer * ibo = NULL;
6214 if (sp->iboid){
6215 ibo = I->G->ShaderMgr->getGPUBuffer<IndexBuffer>(sp->iboid);
6216 }
6217 vbo->bind(shaderPrg->id);
6218 if (ibo){
6219 ibo->bind();
6220 glDrawElements(sp->mode, sp->nindices, GL_C_INT_ENUM, 0);
6221 } else {
6222 glDrawArrays(sp->mode, 0, sp->nverts);
6223 }
6224 vbo->unbind();
6225 if (sp->pickvboid) {
6226 VertexBuffer * pickvbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->pickvboid);
6227 if (pickvbo)
6228 pickvbo->unbind();
6229 }
6230 if (ibo)
6231 ibo->unbind();
6232
6233 }
6234
CGO_gl_draw_sphere_buffers(CCGORenderer * I,CGO_op_data pc)6235 static void CGO_gl_draw_sphere_buffers(CCGORenderer * I, CGO_op_data pc) {
6236 const cgo::draw::sphere_buffers * sp = reinterpret_cast<decltype(sp)>(*pc);
6237 int num_spheres = sp->num_spheres;
6238 int attr_color;
6239 VertexBuffer * vbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->vboid);
6240 VertexBuffer * pickvbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->pickvboid);
6241 CShaderPrg *shaderPrg;
6242 int pickable = 0;
6243
6244 shaderPrg = I->G->ShaderMgr->Get_DefaultSphereShader(I->info ? I->info->pass : 0);
6245 if (!shaderPrg){
6246 return;
6247 }
6248
6249 attr_color = shaderPrg->GetAttribLocation("a_Color");
6250
6251 if (I->isPicking){
6252 vbo->maskAttributes({ attr_color });
6253 pickable = SettingGet_i(I->G, I->set1, I->set2, cSetting_pickable);
6254 shaderPrg->Set1i("lighting_enabled", 0);
6255 if (pickable){
6256 pickvbo->bind(shaderPrg->id, I->pick_pass());
6257 } else {
6258 assert(I->info->pick);
6259 unsigned char nopick[4] = {};
6260 I->info->pick->colorNoPick(nopick);
6261 glVertexAttrib4ubv(attr_color, nopick);
6262 }
6263 }
6264
6265 vbo->bind(shaderPrg->id);
6266 glDrawArrays(GL_QUADS, 0, num_spheres * 4);
6267
6268 vbo->unbind();
6269 }
6270
CGO_gl_draw_cylinder_buffers(CCGORenderer * I,CGO_op_data pc)6271 static void CGO_gl_draw_cylinder_buffers(CCGORenderer * I, CGO_op_data pc) {
6272 const cgo::draw::cylinder_buffers * sp = reinterpret_cast<decltype(sp)>(*pc);
6273 int num_cyl = sp->num_cyl;
6274 int min_alpha = sp->alpha;
6275 int attr_colors, attr_colors2;
6276 CShaderPrg *shaderPrg;
6277 int pickable = 0;
6278 VertexBuffer * vbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->vboid);
6279 IndexBuffer * ibo = I->G->ShaderMgr->getGPUBuffer<IndexBuffer>(sp->iboid);
6280 VertexBuffer * pickvbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->pickvboid);
6281
6282 shaderPrg = I->G->ShaderMgr->Get_CylinderShader(I->info ? I->info->pass : 0);
6283
6284 if (!shaderPrg){
6285 return;
6286 }
6287 attr_colors = shaderPrg->GetAttribLocation("a_Color");
6288 attr_colors2 = shaderPrg->GetAttribLocation("a_Color2");
6289
6290 if (I->isPicking){
6291 pickable = SettingGet_i(I->G, I->set1, I->set2, cSetting_pickable);
6292 shaderPrg->Set1i("lighting_enabled", 0);
6293 }
6294 if (I->isPicking){
6295 vbo->maskAttributes({ attr_colors, attr_colors2 });
6296 if (pickable){
6297 // in first pass: 1st half of vbo, in second pass: 2nd half of vbo
6298 // first color (offset 0)
6299 pickvbo->bind(shaderPrg->id, I->pick_pass());
6300 // second color (offset 4)
6301 pickvbo->bind(shaderPrg->id, I->pick_pass() + SHADER_PICKING_PASSES_MAX);
6302 } else {
6303 assert(I->info->pick);
6304 unsigned char nopick[4] = {};
6305 I->info->pick->colorNoPick(nopick);
6306 glVertexAttrib4ubv(attr_colors, nopick);
6307 glVertexAttrib4ubv(attr_colors2, nopick);
6308 }
6309 }
6310
6311 vbo->bind(shaderPrg->id);
6312 ibo->bind();
6313
6314 if (min_alpha < 255) {
6315 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
6316 glDrawElements(GL_TRIANGLES, num_cyl * NUM_TOTAL_VERTICES_PER_CYLINDER, GL_C_INT_ENUM, 0);
6317 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6318 glDepthFunc(GL_LEQUAL);
6319 }
6320 glDrawElements(GL_TRIANGLES, num_cyl * NUM_TOTAL_VERTICES_PER_CYLINDER, GL_C_INT_ENUM, 0);
6321
6322 if (min_alpha < 255) {
6323 glDepthFunc(GL_LESS);
6324 }
6325
6326 ibo->unbind();
6327 vbo->unbind();
6328 if (I->isPicking)
6329 pickvbo->unbind();
6330 }
6331 #include "Texture.h"
6332
CGO_gl_draw_labels(CCGORenderer * I,CGO_op_data pc)6333 static void CGO_gl_draw_labels(CCGORenderer * I, CGO_op_data pc) {
6334 const cgo::draw::labels * sp = reinterpret_cast<decltype(sp)>(*pc);
6335
6336 CShaderPrg * shaderPrg;
6337 int t_mode = SettingGetGlobal_i(I->G, cSetting_transparency_mode);
6338
6339 if (t_mode==3 && I->info && !(I->info->pass<0)){
6340 // in transparency_mode=3, labels are drawn in the transparency pass=-1
6341 return;
6342 }
6343 shaderPrg = I->G->ShaderMgr->Get_LabelShader(I->info ? I->info->pass : 0);
6344 if (I->rep){
6345 float label_size;
6346 CSetting * set1 = NULL, * set2 = NULL;
6347 if (I->rep->cs) set1 = I->rep->cs->Setting;
6348 if (I->rep->obj) set2 = I->rep->obj->Setting;
6349 label_size = SettingGet_f(I->G, set1, set2, cSetting_label_size);
6350 shaderPrg->Set1f("scaleByVertexScale", label_size < 0.f ? 1.f : 0.f);
6351 if (label_size<0.f){
6352 shaderPrg->Set1f("labelTextureSize", (float)-2.f* I->info->texture_font_size/label_size);
6353 }
6354 }
6355
6356 if (!shaderPrg){
6357 return;
6358 }
6359
6360 VertexBuffer * vbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->vboid);
6361 VertexBuffer * pickvbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->pickvboid);
6362
6363 if (I->isPicking){
6364 pickvbo->bind(shaderPrg->id, I->pick_pass());
6365 }
6366
6367 if (!vbo)
6368 return;
6369 vbo->bind(shaderPrg->id);
6370
6371 glDrawArrays(GL_TRIANGLES, 0, sp->ntextures*6);
6372
6373 vbo->unbind();
6374 pickvbo->unbind();
6375 }
6376
CGO_gl_draw_connectors(CCGORenderer * I,CGO_op_data pc)6377 static void CGO_gl_draw_connectors(CCGORenderer * I, CGO_op_data pc) {
6378 int use_geometry_shaders = SettingGetGlobal_b(I->G, cSetting_use_geometry_shaders);
6379
6380 const cgo::draw::connectors * sp = reinterpret_cast<decltype(sp)>(*pc);
6381
6382 GLenum mode = GL_LINES;
6383 int factor = 2;
6384 float lineWidth;
6385 if (I->isPicking){
6386 return;
6387 }
6388 {
6389 GLenum err ;
6390 CHECK_GL_ERROR_OK("ERROR: CGO_gl_draw_connectors begin returns err=%d\n");
6391 }
6392
6393 if (use_geometry_shaders){
6394 mode = GL_POINTS;
6395 factor = 1;
6396 } else {
6397 factor = 4;
6398 }
6399 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
6400 if (!shaderPrg){
6401 return;
6402 }
6403 if (I->rep){
6404 float label_size;
6405 CSetting * set1 = NULL, * set2 = NULL;
6406 float v_scale = SceneGetScreenVertexScale(I->G, NULL);
6407 if (I->rep->cs) set1 = I->rep->cs->Setting;
6408 if (I->rep->obj) set2 = I->rep->obj->Setting;
6409 label_size = SettingGet_f(I->G, set1, set2, cSetting_label_size);
6410 shaderPrg->Set1f("scaleByVertexScale", label_size < 0.f ? 1.f : 0.f);
6411 lineWidth = SettingGet_f(I->G, set1, set2, cSetting_label_connector_width);
6412 if (label_size<0.f){
6413 shaderPrg->Set1f("textureToLabelSize", v_scale * (float)I->info->texture_font_size/label_size);
6414 } else {
6415 shaderPrg->Set1f("textureToLabelSize", 1.f);
6416 }
6417 } else {
6418 lineWidth = SettingGetGlobal_f(I->G, cSetting_label_connector_width);
6419 }
6420 #ifndef _WEBGL
6421 if (!use_geometry_shaders)
6422 glLineWidth(lineWidth);
6423 #endif
6424
6425 VertexBuffer * vbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->vboid);
6426 if (!vbo)
6427 return;
6428 vbo->bind(shaderPrg->id);
6429 glDrawArrays(mode, 0, sp->nconnectors*factor);
6430 vbo->unbind();
6431 {
6432 GLenum err ;
6433 CHECK_GL_ERROR_OK("ERROR: CGO_gl_draw_connectors end returns err=%d\n");
6434 }
6435 }
6436
CGO_gl_draw_textures(CCGORenderer * I,CGO_op_data pc)6437 static void CGO_gl_draw_textures(CCGORenderer * I, CGO_op_data pc) {
6438 const cgo::draw::textures * sp = reinterpret_cast<decltype(sp)>(*pc);
6439 int ntextures = sp->ntextures;
6440 VertexBuffer * vbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->vboid);
6441 CShaderPrg * shaderPrg;
6442 int attr_pickcolor = 0;
6443 shaderPrg = I->G->ShaderMgr->Get_LabelShader(I->info ? I->info->pass : 0);
6444 if (!shaderPrg){
6445 return;
6446 }
6447 if (I->isPicking){
6448 attr_pickcolor = shaderPrg->GetAttribLocation("attr_pickcolor");
6449 }
6450 if (attr_pickcolor){
6451 glBindBuffer(GL_ARRAY_BUFFER, 0);
6452 glEnableVertexAttribArray(attr_pickcolor);
6453 glVertexAttribPointer(attr_pickcolor, VERTEX_COLOR_SIZE, GL_UNSIGNED_BYTE, GL_TRUE, 0, sp->floatdata);
6454 }
6455 vbo->bind(shaderPrg->id);
6456 glDrawArrays(GL_TRIANGLES, 0, ntextures*6);
6457 vbo->unbind();
6458 if (attr_pickcolor){
6459 glDisableVertexAttribArray(attr_pickcolor);
6460 }
6461 }
6462
CGO_gl_draw_screen_textures_and_polygons(CCGORenderer * I,CGO_op_data pc)6463 static void CGO_gl_draw_screen_textures_and_polygons(CCGORenderer * I, CGO_op_data pc) {
6464 const cgo::draw::screen_textures * sp = reinterpret_cast<decltype(sp)>(*pc);
6465 int nverts = sp->nverts;
6466 CShaderPrg * shaderPrg;
6467
6468 shaderPrg = I->G->ShaderMgr->Get_ScreenShader();
6469 if (!shaderPrg){
6470 return;
6471 }
6472
6473 VertexBuffer * vb = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(sp->vboid);
6474 if (!vb)
6475 return;
6476 vb->bind(shaderPrg->id);
6477
6478 glDrawArrays(GL_TRIANGLES, 0, nverts);
6479
6480 vb->unbind();
6481 }
6482
CGO_gl_draw_trilines(CCGORenderer * I,CGO_op_data pc)6483 static void CGO_gl_draw_trilines(CCGORenderer * I, CGO_op_data pc) {
6484 int nverts = CGO_get_int(*pc);
6485 int buffer = CGO_get_int(*pc+1);
6486 int a_vertex, a_othervertex, a_uv, a_color, a_color2;
6487 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
6488 if (!shaderPrg){
6489 return;
6490 }
6491 a_vertex = 0; // a_Vertex is bound to 0 (see ShaderMgr) CShaderPrg_GetAttribLocation(shaderPrg, "a_Vertex");
6492 a_othervertex = shaderPrg->GetAttribLocation("a_OtherVertex");
6493 a_uv = shaderPrg->GetAttribLocation("a_UV");
6494 a_color = shaderPrg->GetAttribLocation("a_Color");
6495 a_color2 = shaderPrg->GetAttribLocation("a_Color2");
6496
6497 glEnableVertexAttribArray(a_vertex);
6498 glEnableVertexAttribArray(a_othervertex);
6499 glEnableVertexAttribArray(a_uv);
6500 glEnableVertexAttribArray(a_color);
6501 glEnableVertexAttribArray(a_color2);
6502
6503 glBindBuffer(GL_ARRAY_BUFFER, buffer);
6504
6505 glVertexAttribPointer(a_vertex, 3, GL_FLOAT, GL_FALSE, 32, (const void *)0);
6506 glVertexAttribPointer(a_othervertex, 3, GL_FLOAT, GL_FALSE, 32, (const void *)12);
6507 glVertexAttribPointer(a_uv, 1, GL_FLOAT, GL_FALSE, 32, (const void *)24);
6508 glVertexAttribPointer(a_color, 4, GL_UNSIGNED_BYTE, GL_TRUE, 32, (const void *)28);
6509 glVertexAttribPointer(a_color2, 4, GL_UNSIGNED_BYTE, GL_TRUE, 32, (const void *)28);
6510 glDrawArrays(GL_TRIANGLES, 0, nverts);
6511
6512 glDisableVertexAttribArray(a_vertex);
6513 glDisableVertexAttribArray(a_othervertex);
6514 glDisableVertexAttribArray(a_uv);
6515 glDisableVertexAttribArray(a_color);
6516 glDisableVertexAttribArray(a_color2);
6517 }
6518
6519 /* CGO_gl_uniform3f - this is the implementation for the
6520 * CGOUniform3f/CGO_UNIFORM3F operation. From the uniform_id
6521 * it looks up the uniform location from the current shader,
6522 * and sets it to the values in this op.
6523 *
6524 */
CGO_gl_uniform3f(CCGORenderer * I,CGO_op_data pc)6525 static void CGO_gl_uniform3f(CCGORenderer * I, CGO_op_data pc) {
6526 int uniform_id = CGO_get_int(*pc);
6527 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
6528 if (!shaderPrg){
6529 return;
6530 }
6531 int loc = shaderPrg->GetUniformLocation(
6532 shaderPrg->uniformLocations[uniform_id].c_str());
6533 const float *pcp = *pc + 1;
6534 glUniform3f(loc, pcp[0], pcp[1], pcp[2]);
6535 }
6536
CGO_gl_linewidth(CCGORenderer * I,CGO_op_data pc)6537 static void CGO_gl_linewidth(CCGORenderer * I, CGO_op_data pc)
6538 {
6539 #ifndef _WEBGL
6540 glLineWidth(**pc);
6541 #endif
6542 }
6543
6544 /*
6545 * call glLineWidth and set the "line_width" uniform
6546 */
glLineWidthAndUniform(float line_width,CShaderPrg * shaderPrg=NULL)6547 static void glLineWidthAndUniform(float line_width,
6548 CShaderPrg * shaderPrg=NULL) {
6549 #ifndef _WEBGL
6550 glLineWidth(line_width);
6551 #endif
6552
6553 if (shaderPrg && shaderPrg->name == "trilines")
6554 shaderPrg->Set1f("line_width", line_width);
6555 }
6556
6557 /* CGO_gl_special - this is the implementation function for
6558 CGOSpecial/CGO_SPECIAL. Each op has its own implementation.
6559 */
CGO_gl_special(CCGORenderer * I,CGO_op_data pc)6560 static void CGO_gl_special(CCGORenderer * I, CGO_op_data pc)
6561 {
6562 int mode = CGO_get_int(*pc);
6563 bool openVR = SceneGetStereo(I->G) == cStereo_openvr;
6564 char varwidth = 0;
6565 float vScale = (I->info ? I->info->vertex_scale : SceneGetScreenVertexScale(I->G, NULL));
6566
6567 CSetting *csSetting = NULL, *objSetting = NULL;
6568 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
6569 if (I->rep && I->rep->cs){
6570 csSetting = I->rep->cs->Setting;
6571 }
6572 if (I->rep && I->rep->obj){
6573 objSetting = I->rep->obj->Setting;
6574 }
6575 switch (mode){
6576 case LINEWIDTH_DYNAMIC_WITH_SCALE_RIBBON:
6577 {
6578 float line_width = SettingGet_f(I->G, NULL, NULL, cSetting_ribbon_width);
6579 if (!openVR) line_width = SceneGetDynamicLineWidth(I->info, line_width);
6580 if (I->info && I->info->width_scale_flag){
6581 line_width *= I->info->width_scale;
6582 }
6583 glLineWidthAndUniform(line_width, shaderPrg);
6584 }
6585 break;
6586 case LINEWIDTH_DYNAMIC_WITH_SCALE_DASH:
6587 {
6588 float line_width = SettingGet_f(I->G, NULL, NULL, cSetting_dash_width);
6589 if (!openVR) line_width = SceneGetDynamicLineWidth(I->info, line_width);
6590 if (I->info && I->info->width_scale_flag){
6591 line_width *= I->info->width_scale;
6592 }
6593 glLineWidthAndUniform(line_width, shaderPrg);
6594 }
6595 break;
6596 case LINEWIDTH_DYNAMIC_WITH_SCALE:
6597 {
6598 float line_width = SettingGet_f(I->G, NULL, NULL, cSetting_line_width);
6599 if (!openVR) line_width = SceneGetDynamicLineWidth(I->info, line_width);
6600 if (I->info && I->info->width_scale_flag){
6601 line_width *= I->info->width_scale;
6602 }
6603 glLineWidthAndUniform(line_width, shaderPrg);
6604 }
6605 break;
6606 case LINEWIDTH_WITH_SCALE:
6607 {
6608 float line_width = SettingGet_f(I->G, NULL, NULL, cSetting_line_width);
6609 if (I->info && I->info->width_scale_flag){
6610 line_width *= I->info->width_scale;
6611 }
6612 glLineWidthAndUniform(line_width, shaderPrg);
6613 }
6614 break;
6615 case LINEWIDTH_DYNAMIC_MESH:
6616 {
6617 float line_width;
6618 if (I->rep){
6619 line_width = SettingGet_f(I->G, I->rep->cs->Setting, I->rep->obj->Setting, cSetting_mesh_width);
6620 } else {
6621 line_width = SettingGet_f(I->G, NULL, NULL, cSetting_mesh_width);
6622 }
6623 if (!openVR) line_width = SceneGetDynamicLineWidth(I->info, line_width);
6624 glLineWidthAndUniform(line_width, shaderPrg);
6625 }
6626 break;
6627 case POINTSIZE_DYNAMIC_DOT_WIDTH:
6628 {
6629 float ps;
6630 if(I->info && I->info->width_scale_flag){
6631 ps = SettingGet_f
6632 (I->G, csSetting, objSetting,
6633 cSetting_dot_width) * I->info->width_scale;
6634 }
6635 else {
6636 ps = SettingGet_f
6637 (I->G, csSetting, objSetting, cSetting_dot_width);
6638 }
6639 glPointSize(ps);
6640 break;
6641 }
6642 case CYLINDERWIDTH_DYNAMIC_MESH:
6643 {
6644 CSetting *setting = NULL;
6645 float mesh_width;
6646 if (I && I->rep && I->rep->obj){
6647 setting = I->rep->obj->Setting;
6648 }
6649 mesh_width = SettingGet_f(I->G, setting, NULL, cSetting_mesh_width);
6650 if (shaderPrg) {
6651 const float * color = I->color ? I->color : g_ones4f;
6652 shaderPrg->Set1f("uni_radius", SceneGetLineWidthForCylinders(I->G, I->info, mesh_width));
6653 shaderPrg->SetAttrib4fLocation("a_Color", color[0], color[1], color[2], I->alpha);
6654 shaderPrg->SetAttrib4fLocation("a_Color2", color[0], color[1], color[2], I->alpha);
6655 }
6656 }
6657 break;
6658 case DOTSIZE_WITH_SPHERESCALE:
6659 {
6660 float radius = SettingGet_f(I->G, csSetting, objSetting, cSetting_dot_width);
6661 radius *= vScale;
6662 if (shaderPrg)
6663 shaderPrg->Set1f("sphere_size_scale", fabs(radius));
6664 }
6665 break;
6666 case MESH_WIDTH_FOR_SURFACES:
6667 {
6668 float mesh_width = SettingGet_f(I->G, csSetting, objSetting, cSetting_mesh_width);
6669 if (shaderPrg)
6670 shaderPrg->Set1f("uni_radius", SceneGetLineWidthForCylinders(I->G, I->info, mesh_width));
6671 }
6672 break;
6673 case CYLINDER_WIDTH_FOR_DISTANCES:
6674 {
6675 float line_width, radius;
6676 int round_ends;
6677 round_ends =
6678 SettingGet_b(I->G, csSetting, objSetting, cSetting_dash_round_ends);
6679 line_width =
6680 SettingGet_f(I->G, csSetting, objSetting, cSetting_dash_width);
6681 radius =
6682 SettingGet_f(I->G, csSetting, objSetting, cSetting_dash_radius);
6683
6684 line_width = SceneGetDynamicLineWidth(I->info, line_width);
6685
6686 if (shaderPrg) {
6687 if(radius == 0.0F) {
6688 float dash_size = SettingGet_f(I->G, csSetting, objSetting, cSetting_dash_width);
6689 shaderPrg->Set1f("uni_radius", SceneGetLineWidthForCylindersStatic(I->G, I->info, line_width, dash_size));
6690 } else {
6691 shaderPrg->Set1f("uni_radius", radius);
6692 }
6693 if (!round_ends){
6694 shaderPrg->Set1i("no_flat_caps", 0);
6695 }
6696 }
6697 }
6698 break;
6699 case CYLINDER_WIDTH_FOR_RIBBONS:
6700 {
6701 float pixel_scale_value = SettingGetGlobal_f(I->G, cSetting_ray_pixel_scale);
6702 float line_width, radius;
6703 line_width =
6704 SettingGet_f(I->G, csSetting, objSetting, cSetting_ribbon_width);
6705 radius =
6706 SettingGet_f(I->G, csSetting, objSetting, cSetting_ribbon_radius);
6707
6708 line_width = SceneGetDynamicLineWidth(I->info, line_width);
6709 if(pixel_scale_value < 0)
6710 pixel_scale_value = 1.0F;
6711 if (shaderPrg) {
6712 if(radius == 0.0F) {
6713 shaderPrg->Set1f("uni_radius", vScale * pixel_scale_value * line_width/ 2.f);
6714 } else {
6715 shaderPrg->Set1f("uni_radius", radius);
6716 }
6717 }
6718 }
6719 break;
6720 case DOT_WIDTH_FOR_DOTS:
6721 {
6722 float dot_width = SettingGet_f(I->G, csSetting, objSetting, cSetting_dot_width);
6723 float radius;
6724 if(I->info && I->info->width_scale_flag)
6725 radius = (dot_width * I->info->width_scale);
6726 else
6727 radius= dot_width;
6728 if (shaderPrg)
6729 shaderPrg->Set1f("g_PointSize", radius);
6730 #ifndef _PYMOL_IOS
6731 glPointSize(radius);
6732 #endif
6733 }
6734 break;
6735 case DOT_WIDTH_FOR_DOT_SPHERES:
6736 {
6737 float dotSize = SettingGet_f(I->G, csSetting, objSetting, cSetting_dot_radius);
6738 float dot_width = SettingGet_f(I->G, csSetting, objSetting, cSetting_dot_width);
6739 float radius;
6740 if(I->info && dotSize <= 0.0F) {
6741 if(I->info->width_scale_flag)
6742 radius = dot_width * I->info->width_scale * I->info->vertex_scale / 1.4142F;
6743 else
6744 radius = dot_width * I->info->vertex_scale;
6745 } else {
6746 radius = dotSize;
6747 }
6748 if (shaderPrg)
6749 shaderPrg->Set1f("sphere_size_scale", fabs(radius));
6750 }
6751 break;
6752 case CYLINDER_WIDTH_FOR_NONBONDED:
6753 {
6754 if (shaderPrg){
6755 float line_width = SettingGet_f(I->G, csSetting, objSetting, cSetting_line_width);
6756 shaderPrg->Set1f("uni_radius", SceneGetLineWidthForCylindersStatic(I->G, I->info, line_width, line_width));
6757 }
6758 }
6759 break;
6760 case CYLINDER_WIDTH_FOR_REPWIRE_VARWIDTH:
6761 varwidth = 1;
6762 case CYLINDER_WIDTH_FOR_REPWIRE:
6763 {
6764 float radius = SettingGet_f(I->G, csSetting, objSetting, cSetting_line_radius);
6765 if (radius < R_SMALL8) {
6766 float line_width = SettingGet_f(I->G, csSetting, objSetting, cSetting_line_width);
6767 float pixel_scale_value = SettingGetGlobal_f(I->G, cSetting_ray_pixel_scale);
6768 float vertex_scale = vScale;
6769 float scale_bound = SettingGetGlobal_f(I->G, cSetting_field_of_view) * cPI / 180.0f * 0.018f;
6770 if (!varwidth){
6771 line_width = SceneGetDynamicLineWidth(I->info, line_width);
6772 }
6773 if (vertex_scale < scale_bound) {
6774 vertex_scale = scale_bound;
6775 }
6776 if(pixel_scale_value < 0)
6777 pixel_scale_value = 1.0F;
6778 radius = vertex_scale * pixel_scale_value * line_width / 2.f;
6779 }
6780 if (shaderPrg){
6781 shaderPrg->Set1f("uni_radius", radius);
6782 }
6783 }
6784 break;
6785 case ENABLE_BACK_FACES_IF_NOT_TWO_SIDED:
6786 {
6787 int two_sided_lighting = SettingGet_i(I->G, csSetting, objSetting, cSetting_two_sided_lighting) > 0;
6788 if (!two_sided_lighting){
6789 glCullFace(GL_BACK);
6790 glEnable(GL_CULL_FACE);
6791 }
6792 }
6793 break;
6794 case DISABLE_BACK_FACES_IF_NOT_TWO_SIDED:
6795 {
6796 int two_sided_lighting = SettingGet_i(I->G, csSetting, objSetting, cSetting_two_sided_lighting) > 0;
6797 if (!two_sided_lighting){
6798 glDisable(GL_CULL_FACE);
6799 }
6800 }
6801 break;
6802 case SET_SURFACE_UNIFORMS:
6803 {
6804 float ambient_occlusion_scale = 0.f;
6805 int ambient_occlusion_mode = SettingGet_i(I->G, csSetting, objSetting, cSetting_ambient_occlusion_mode);
6806
6807 if (ambient_occlusion_mode){
6808 ambient_occlusion_scale = SettingGet_f(I->G, csSetting, objSetting, cSetting_ambient_occlusion_scale);
6809 }
6810 if (shaderPrg)
6811 shaderPrg->Set1f("ambient_occlusion_scale", ambient_occlusion_scale);
6812 }
6813 break;
6814 case SET_ALIGNMENT_UNIFORMS_ATTRIBS:
6815 {
6816 float linewidth = SettingGet_f(I->G, csSetting, objSetting, cSetting_cgo_line_width);
6817 float lineradius = SettingGet_f(I->G, csSetting, objSetting, cSetting_cgo_line_radius);
6818 float pixel_scale_value = SettingGetGlobal_f(I->G, cSetting_ray_pixel_scale);
6819 if (linewidth < 0.f){
6820 linewidth = 1.f;
6821 }
6822 if(pixel_scale_value < 0)
6823 pixel_scale_value = 1.0F;
6824 if (lineradius < 0.f){
6825 lineradius = linewidth * vScale * pixel_scale_value / 2.f;
6826 }
6827 shaderPrg->Set1f("uni_radius", lineradius);
6828 if (I->color){
6829 shaderPrg->SetAttrib4fLocation("a_Color", I->color[0], I->color[1], I->color[2], 1.f);
6830 shaderPrg->SetAttrib4fLocation("a_Color2", I->color[0], I->color[1], I->color[2], 1.f);
6831 }
6832 glLineWidthAndUniform(lineradius*2.f / vScale, shaderPrg);
6833 }
6834 break;
6835 case LINEWIDTH_FOR_LINES:
6836 {
6837 float line_width = SceneGetDynamicLineWidth(I->info,
6838 SettingGet_f(I->G, NULL, NULL, cSetting_line_width));
6839 if (I->info && I->info->width_scale_flag){
6840 line_width *= I->info->width_scale;
6841 }
6842 glLineWidthAndUniform(line_width, shaderPrg);
6843 }
6844 break;
6845 case SET_LABEL_SCALE_UNIFORMS:
6846 {
6847 if (I->rep){
6848 float label_size;
6849 CSetting * set1 = NULL, * set2 = NULL;
6850 if (I->rep->cs) set1 = I->rep->cs->Setting;
6851 if (I->rep->obj) set2 = I->rep->obj->Setting;
6852 label_size = SettingGet_f(I->G, set1, set2, cSetting_label_size);
6853 shaderPrg->Set1f("scaleByVertexScale", label_size < 0.f ? 1.f : 0.f);
6854 if (label_size<0.f){
6855 shaderPrg->Set1f("labelTextureSize", (float)-2.f* I->info->texture_font_size/label_size);
6856 }
6857 }
6858
6859
6860 }
6861 break;
6862 default:
6863 PRINTFB(I->G, FB_CGO, FB_Warnings) " CGO_gl_special(): bad mode=%d\n", mode ENDFB(I->G);
6864 }
6865 }
6866
6867 /* CGO_gl_special_with_arg - this is the implementation function for
6868 CGOSpecialWithArg/CGO_SPECIAL_WITH_ARG. Each op has its own implementation.
6869 */
CGO_gl_special_with_arg(CCGORenderer * I,CGO_op_data pc)6870 static void CGO_gl_special_with_arg(CCGORenderer * I, CGO_op_data pc)
6871 {
6872 #ifndef PURE_OPENGL_ES_2
6873 int mode = CGO_get_int(*pc);
6874 float argval = *((*pc) + 1);
6875 bool use_shaders = SettingGetGlobal_b(I->G, cSetting_use_shaders);
6876 bool sphere_use_shaders = use_shaders && SettingGetGlobal_b(I->G, cSetting_use_shaders);
6877 switch(mode){
6878 case LINEWIDTH_FOR_LINES:
6879 {
6880 if (!use_shaders){
6881 glEnd();
6882 glLineWidth(argval);
6883 glBegin(GL_LINES);
6884 }
6885 }
6886 break;
6887 case LINE_LIGHTING:
6888 if (!I->isPicking && !SettingGetGlobal_b(I->G, cSetting_use_shaders)) {
6889 if (!I->info->line_lighting){
6890 bool enableLighting = (int)argval;
6891 if (enableLighting)
6892 glEnable(GL_LIGHTING);
6893 else
6894 glDisable(GL_LIGHTING);
6895 }
6896 }
6897 break;
6898 case SPHERE_MODE_OPS:
6899 {
6900 float pixel_scale = 1.0F / I->info->vertex_scale;
6901 int sphere_mode = (int)fabs(argval);
6902 bool enable = argval > 0.f;
6903 if (enable){
6904 float pointSize;
6905 if((sphere_mode == 1) || (sphere_mode == 6)) {
6906 pointSize = SettingGet_f(I->G, I->set1, I->set2, cSetting_sphere_point_size);
6907 glDisable(GL_POINT_SMOOTH);
6908 glDisable(GL_ALPHA_TEST);
6909 if (!I->isPicking && !sphere_use_shaders){
6910 glEnable(GL_LIGHTING);
6911 glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
6912 }
6913 } else {
6914 float sphere_scale = SettingGet_f(I->G, I->set1, I->set2, cSetting_sphere_scale);
6915 if((sphere_mode == 3) || (sphere_mode == 8)) {
6916 glEnable(GL_POINT_SMOOTH);
6917 glAlphaFunc(GL_GREATER, 0.5F);
6918 glEnable(GL_ALPHA_TEST);
6919 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
6920 pointSize = sphere_scale * pixel_scale * 2.0F;
6921 } else {
6922 glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
6923 glDisable(GL_POINT_SMOOTH);
6924 glDisable(GL_ALPHA_TEST);
6925 pointSize = sphere_scale * pixel_scale * 1.4F;
6926 }
6927 }
6928 if(!I->isPicking && ((sphere_mode == 7) || (sphere_mode == 8)))
6929 glEnable(GL_LIGHTING);
6930 glPointSize(pointSize);
6931 } else {
6932 if(sphere_mode == 3) {
6933 glDisable(GL_POINT_SMOOTH);
6934 glAlphaFunc(GL_GREATER, 0.05F);
6935 } else {
6936 glEnable(GL_ALPHA_TEST);
6937 }
6938 }
6939 }
6940 }
6941 #endif
6942 }
6943
CGO_gl_dotwidth(CCGORenderer * I,CGO_op_data pc)6944 static void CGO_gl_dotwidth(CCGORenderer * I, CGO_op_data pc)
6945 {
6946 glPointSize(**pc);
6947 }
6948
CGO_gl_enable(CCGORenderer * I,CGO_op_data pc)6949 static void CGO_gl_enable(CCGORenderer * I, CGO_op_data pc)
6950 {
6951 GLenum mode = CGO_get_int(*pc);
6952 CShaderMgr *shaderMgr = I->G->ShaderMgr;
6953 CShaderPrg *shaderPrg = shaderMgr->Get_Current_Shader();
6954 if (I->use_shader){
6955 if (true){
6956 switch(mode){
6957 case CGO_GL_LIGHTING:
6958 {
6959 if (shaderPrg){
6960 shaderPrg->SetLightingEnabled(1);
6961 }
6962 }
6963 break;
6964 case GL_SHADER_LIGHTING:
6965 if (!I->isPicking){
6966 if (shaderPrg){
6967 shaderPrg->SetLightingEnabled(1);
6968 }
6969 }
6970 break;
6971 case GL_TWO_SIDED_LIGHTING:
6972 {
6973 if (shaderPrg){
6974 shaderPrg->Set1i("two_sided_lighting_enabled", 1);
6975 }
6976 }
6977 break;
6978 case GL_MESH_LIGHTING:
6979 {
6980 int lighting =
6981 SettingGet_i(I->G, I->set1, I->set2, cSetting_mesh_lighting);
6982 if (shaderPrg){
6983 shaderPrg->SetLightingEnabled(lighting);
6984 }
6985 }
6986 break;
6987 case GL_DOT_LIGHTING:
6988 {
6989 int lighting =
6990 SettingGet_i(I->G, I->set1, I->set2, cSetting_dot_lighting);
6991 if (shaderPrg && !I->isPicking){
6992 shaderPrg->SetLightingEnabled(lighting);
6993 shaderPrg->Set1i("two_sided_lighting_enabled", 0);
6994 }
6995 }
6996 break;
6997 case GL_LABEL_FLOAT_TEXT:
6998 {
6999 int float_text =
7000 SettingGet_i(I->G, I->set1, I->set2, cSetting_float_labels);
7001 if (float_text){
7002 glDisable(GL_DEPTH_TEST);
7003 }
7004 }
7005 break;
7006 case GL_DASH_TRANSPARENCY_DEPTH_TEST:
7007 {
7008 float dash_transparency =
7009 SettingGet_f(I->G, I->set1, I->set2, cSetting_dash_transparency);
7010 short dash_transparency_enabled;
7011 bool t_mode_3 =
7012 SettingGet_i(I->G, I->set1, I->set2, cSetting_transparency_mode) == 3;
7013 dash_transparency = (dash_transparency < 0.f ? 0.f : (dash_transparency > 1.f ? 1.f : dash_transparency));
7014 dash_transparency_enabled = (dash_transparency > 0.f);
7015 if (dash_transparency_enabled && !t_mode_3 && !I->isPicking){
7016 glDisable(GL_DEPTH_TEST);
7017 }
7018 }
7019 break;
7020 case GL_DEFAULT_SHADER:
7021 shaderMgr->Enable_DefaultShader(I->info ? I->info->pass : 0);
7022 break;
7023 case GL_LINE_SHADER:
7024 shaderMgr->Enable_LineShader(I->info ? I->info->pass : 0);
7025 break;
7026 case GL_SURFACE_SHADER:
7027 shaderMgr->Enable_SurfaceShader(I->info ? I->info->pass : 0);
7028 break;
7029 case GL_CYLINDER_SHADER:
7030 shaderMgr->Enable_CylinderShader(I->info ? I->info->pass : 0);
7031 break;
7032 case GL_SPHERE_SHADER:
7033 shaderMgr->Enable_DefaultSphereShader(I->info ? I->info->pass : 0);
7034 break;
7035 case GL_RAMP_SHADER:
7036 shaderMgr->Enable_RampShader();
7037 break;
7038 case GL_DEFAULT_SHADER_WITH_SETTINGS:
7039 shaderMgr->Enable_DefaultShaderWithSettings(I->set1, I->set2, I->info ? I->info->pass : 0);
7040 break;
7041 case GL_BACKGROUND_SHADER:
7042 shaderMgr->Enable_BackgroundShader();
7043 break;
7044 case GL_LABEL_SHADER:
7045 shaderMgr->Enable_LabelShader(I->info ? I->info->pass : 0);
7046 break;
7047 case GL_CONNECTOR_SHADER:
7048 shaderMgr->Enable_ConnectorShader(I->info ? I->info->pass : 0);
7049 break;
7050 case GL_SCREEN_SHADER:
7051 shaderMgr->Enable_ScreenShader();
7052 break;
7053 case GL_TRILINES_SHADER:
7054 shaderMgr->Enable_TriLinesShader();
7055 break;
7056 #ifndef _PYMOL_NO_AA_SHADERS
7057 #endif
7058 case GL_OIT_SHADER:
7059 shaderMgr->Enable_OITShader();
7060 break;
7061 case GL_OIT_COPY_SHADER:
7062 shaderMgr->Enable_OITCopyShader();
7063 break;
7064 case GL_BACK_FACE_CULLING:
7065 glCullFace(GL_BACK);
7066 glEnable(GL_CULL_FACE);
7067 break;
7068 case GL_DEPTH_TEST:
7069 glEnable(mode);
7070 break;
7071 case GL_DEPTH_TEST_IF_FLOATING:
7072 {
7073 int float_text = SettingGet_i(I->G, I->set1, I->set2, cSetting_float_labels);
7074 if(float_text)
7075 glEnable(GL_DEPTH_TEST);
7076 }
7077 break;
7078 }
7079 }
7080 } else {
7081 if (!I->isPicking){
7082 if (mode==CGO_GL_LIGHTING){
7083 glEnable(GL_LIGHTING);
7084 }
7085 }
7086 }
7087 }
7088
CGO_gl_disable(CCGORenderer * I,CGO_op_data pc)7089 static void CGO_gl_disable(CCGORenderer * I, CGO_op_data pc)
7090 {
7091 GLenum mode = CGO_get_int(*pc);
7092 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
7093 if (I->use_shader){
7094 switch(mode){
7095 case GL_SHADER_LIGHTING:
7096 {
7097 if (shaderPrg){
7098 shaderPrg->SetLightingEnabled(0);
7099 }
7100 }
7101 break;
7102 case GL_CYLINDER_SHADER:
7103 glDisable(GL_CULL_FACE);
7104 case GL_RAMP_SHADER:
7105 case GL_SCREEN_SHADER:
7106 case GL_LABEL_SHADER:
7107 case GL_CONNECTOR_SHADER:
7108 case GL_DEFAULT_SHADER:
7109 case GL_SURFACE_SHADER:
7110 case GL_SPHERE_SHADER:
7111 case GL_TRILINES_SHADER:
7112 case GL_OIT_COPY_SHADER:
7113 case GL_LINE_SHADER:
7114 I->G->ShaderMgr->Disable_Current_Shader();
7115 break;
7116 case GL_LABEL_FLOAT_TEXT:
7117 {
7118 int float_text =
7119 SettingGet_i(I->G, I->set1, I->set2, cSetting_float_labels);
7120 if (float_text){
7121 glEnable(GL_DEPTH_TEST);
7122 }
7123 }
7124 break;
7125 case GL_DASH_TRANSPARENCY_DEPTH_TEST:
7126 {
7127 float dash_transparency =
7128 SettingGet_f(I->G, I->set1, I->set2, cSetting_dash_transparency);
7129 short dash_transparency_enabled;
7130 bool t_mode_3 =
7131 SettingGet_i(I->G, I->set1, I->set2, cSetting_transparency_mode) == 3;
7132 dash_transparency = (dash_transparency < 0.f ? 0.f : (dash_transparency > 1.f ? 1.f : dash_transparency));
7133 dash_transparency_enabled = (dash_transparency > 0.f);
7134 if (dash_transparency_enabled && !t_mode_3 && !I->isPicking){
7135 glEnable(GL_DEPTH_TEST);
7136 }
7137 }
7138 break;
7139 case CGO_GL_LIGHTING:
7140 {
7141 if (shaderPrg){
7142 shaderPrg->SetLightingEnabled(0);
7143 }
7144 }
7145 break;
7146 case GL_TWO_SIDED_LIGHTING:
7147 {
7148 if (shaderPrg){
7149 shaderPrg->Set1i("two_sided_lighting_enabled", 0);
7150 }
7151 }
7152 break;
7153 #if !defined(PURE_OPENGL_ES_2) || defined(_WEBGL)
7154 case GL_OIT_SHADER:
7155 case GL_SMAA1_SHADER:
7156 case GL_SMAA2_SHADER:
7157 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, I->G->ShaderMgr->default_framebuffer_id);
7158 break;
7159 #endif
7160 case GL_BACK_FACE_CULLING:
7161 glDisable(GL_CULL_FACE);
7162 break;
7163 case GL_DEPTH_TEST:
7164 glDisable(mode);
7165 break;
7166 case GL_DEPTH_TEST_IF_FLOATING:
7167 {
7168 int float_text = SettingGet_i(I->G, I->set1, I->set2, cSetting_float_labels);
7169 if(float_text)
7170 glDisable(GL_DEPTH_TEST);
7171 }
7172 break;
7173 }
7174 } else {
7175 if (mode!=CGO_GL_LIGHTING || !I->isPicking){
7176 if (mode==CGO_GL_LIGHTING)
7177 mode = GL_LIGHTING;
7178 glDisable(mode);
7179 }
7180 }
7181 }
7182
CGO_gl_alpha(CCGORenderer * I,CGO_op_data pc)7183 static void CGO_gl_alpha(CCGORenderer * I, CGO_op_data pc)
7184 {
7185 I->alpha = **pc;
7186 }
7187
CGO_gl_reset_normal(CCGORenderer * I,CGO_op_data pc)7188 static void CGO_gl_reset_normal(CCGORenderer * I, CGO_op_data pc)
7189 {
7190 SceneResetNormalUseShader(I->G, CGO_get_int(*pc), I->use_shader);
7191 }
7192
CGO_gl_null(CCGORenderer * I,CGO_op_data pc)7193 static void CGO_gl_null(CCGORenderer * I, CGO_op_data pc)
7194 {
7195 }
7196
CGO_gl_error(CCGORenderer * I,CGO_op_data pc)7197 static void CGO_gl_error(CCGORenderer * I, CGO_op_data pc)
7198 {
7199 PRINTFB(I->G, FB_CGO, FB_Warnings)
7200 " CGO_gl_error() is not suppose to be called op=%d\n",
7201 CGO_get_int((*pc) - 1) ENDFB(I->G);
7202 }
7203
CGO_gl_color(CCGORenderer * I,CGO_op_data varg)7204 static void CGO_gl_color(CCGORenderer* I, CGO_op_data varg)
7205 {
7206 auto* v = *varg;
7207 if (I->use_shader){
7208 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
7209 if (shaderPrg){
7210 int attr_a_Color = shaderPrg->GetAttribLocation("a_Color");
7211 glVertexAttrib4f(attr_a_Color, v[0], v[1], v[2], I->alpha);
7212 }
7213 } else {
7214 glColor4f(v[0], v[1], v[2], I->alpha);
7215 }
7216 }
7217
CGO_gl_sphere(CCGORenderer * I,CGO_op_data varg)7218 static void CGO_gl_sphere(CCGORenderer * I, CGO_op_data varg)
7219 {
7220 auto *v = *varg;
7221 if (I->isPicking){
7222 SphereRender(I->G, 0, v, I->color, I->alpha, v[3]);
7223 } else {
7224 SphereRender(I->G, I->sphere_quality, v, NULL, I->alpha, v[3]);
7225 }
7226 }
7227
CGO_gl_vertex_attribute_3f(CCGORenderer * I,CGO_op_data varg)7228 static void CGO_gl_vertex_attribute_3f(CCGORenderer * I, CGO_op_data varg)
7229 {
7230 auto vertex_attr = reinterpret_cast<const cgo::draw::vertex_attribute_3f *>(*varg);
7231 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
7232 int loc = shaderPrg->GetAttribLocation(I->G->ShaderMgr->GetAttributeName(vertex_attr->attr_lookup_idx));
7233 if (loc >= 0)
7234 glVertexAttrib3fv(loc, vertex_attr->values);
7235 }
7236
CGO_gl_vertex_attribute_4ub(CCGORenderer * I,CGO_op_data varg)7237 static void CGO_gl_vertex_attribute_4ub(CCGORenderer * I, CGO_op_data varg)
7238 {
7239 auto vertex_attr = reinterpret_cast<const cgo::draw::vertex_attribute_4ub *>(*varg);
7240 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
7241 int loc = shaderPrg->GetAttribLocation(I->G->ShaderMgr->GetAttributeName(vertex_attr->attr_lookup_idx));
7242 if (loc >= 0)
7243 glVertexAttrib4ubv(loc, vertex_attr->ubdata);
7244 }
7245
CGO_gl_vertex_attribute_4ub_if_picking(CCGORenderer * I,CGO_op_data varg)7246 static void CGO_gl_vertex_attribute_4ub_if_picking(CCGORenderer * I, CGO_op_data varg)
7247 {
7248 if (I->isPicking){
7249 auto vertex_attr = reinterpret_cast<const cgo::draw::vertex_attribute_4ub_if_picking *>(*varg);
7250 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
7251 int loc = shaderPrg->GetAttribLocation(I->G->ShaderMgr->GetAttributeName(vertex_attr->attr_lookup_idx));
7252 if (loc >= 0)
7253 glVertexAttrib4ubv(loc, vertex_attr->ubdata);
7254 }
7255 }
7256
CGO_gl_vertex_attribute_1f(CCGORenderer * I,CGO_op_data varg)7257 static void CGO_gl_vertex_attribute_1f(CCGORenderer * I, CGO_op_data varg)
7258 {
7259 auto vertex_attr = reinterpret_cast<const cgo::draw::vertex_attribute_1f *>(*varg);
7260 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
7261 const char *name = I->G->ShaderMgr->GetAttributeName(vertex_attr->attr_lookup_idx);
7262 int loc = shaderPrg->GetAttribLocation(name);
7263 if (loc >= 0)
7264 glVertexAttrib1f(loc, vertex_attr->value);
7265 }
7266
7267 /* dispatch table for OpenGL */
7268
7269 CGO_op_fn CGO_gl[] = {
7270 CGO_gl_null, /* 0x00 */
7271 CGO_gl_null, /* 0x01 */
7272 CGO_gl_begin, /* 0x02 */
7273 CGO_gl_end, /* 0x03 */
7274 CGO_gl_vertex, /* 0x04 */
7275 CGO_gl_normal, /* 0x05 */
7276 CGO_gl_color, /* 0x06 */
7277 CGO_gl_sphere, /* 0x07 */
7278 CGO_gl_null, /* 0x08 */
7279 CGO_gl_null, /* 0x09 */
7280
7281 CGO_gl_linewidth, /* 0x0A */
7282 CGO_gl_null, /* 0x0B */
7283 CGO_gl_enable, /* 0x0C */
7284 CGO_gl_disable, /* 0x0D */
7285 CGO_gl_null, /* 0x0E */
7286 CGO_gl_null, /* 0x0F */
7287
7288 CGO_gl_dotwidth, /* 0X10 */
7289 CGO_gl_null, /* 0x11 */
7290 CGO_gl_null, /* 0x12 */
7291 CGO_gl_null, /* 0X13 */
7292
7293 CGO_gl_null, /* 0X14 */
7294 CGO_gl_null, /* 0x15 */
7295 CGO_gl_null, /* 0x16 */
7296 CGO_gl_null, /* 0X17 */
7297
7298 CGO_gl_null, /* 0X18 */
7299 CGO_gl_alpha, /* 0x19 */
7300 CGO_gl_null, /* 0x1A */
7301 CGO_gl_null, /* 0X1B */
7302 CGO_gl_draw_arrays, /* 0x1C DrawArrays() */
7303 CGO_gl_null, /* 0x1D */
7304 CGO_gl_reset_normal, /* 0x1E */
7305 CGO_gl_null, /* pick color 0X1F */
7306 CGO_gl_null, /* 0x20 draw buffers REMOVED */
7307 CGO_gl_draw_buffers_indexed, /* 0x21 draw buffers indexed */
7308 CGO_gl_null, /* 0x22 bounding box */
7309 CGO_gl_draw_buffers_not_indexed, /* 0x23 draw buffers not indexed */
7310 CGO_gl_special, /* 0x24 special */
7311 CGO_gl_draw_cylinder_buffers, /* 0x25 draw GLSL cylinders */
7312 CGO_gl_null, /* 0x26 shader cylinder */
7313 CGO_gl_null, /* 0x27 shader cylinder with 2nd color */
7314 CGO_gl_draw_sphere_buffers, /* 0x28 draw sphere buffers */
7315 CGO_gl_null, /* 0x29 accessibility used for ambient occlusion */
7316 CGO_gl_error, /* 0x2A draw texture */
7317 CGO_gl_draw_textures, /* 0x2B draw textures */
7318 CGO_gl_draw_screen_textures_and_polygons, /* 0x2C draw screen textures and polygons */
7319 CGO_gl_error,
7320 CGO_gl_error, CGO_gl_draw_labels,
7321 CGO_gl_error, CGO_gl_draw_connectors, CGO_gl_draw_trilines, CGO_gl_uniform3f, CGO_gl_special_with_arg,
7322 CGO_gl_line, CGO_gl_splitline, CGO_gl_draw_custom,
7323 CGO_gl_vertex_attribute_3f, CGO_gl_vertex_attribute_4ub,
7324 CGO_gl_vertex_attribute_1f,
7325 CGO_gl_mask_attribute_if_picking, CGO_gl_bind_vbo_for_picking,
7326 CGO_gl_vertex,
7327 CGO_gl_null, // interpolated
7328 CGO_gl_vertex_cross, // CGO_VERTEX_CROSS
7329 CGO_gl_vertex_attribute_4ub_if_picking,
7330 CGO_gl_error
7331 };
7332
7333 #if 0
7334 static
7335 void SetUCColorToPrev(uchar *color){
7336 color[0] = color[-4];
7337 color[1] = color[-3];
7338 color[2] = color[-2];
7339 color[3] = color[-1];
7340 }
7341
7342 static
7343 void SetUCColorToPrev8(uchar *color){
7344 color[0] = color[-8];
7345 color[1] = color[-7];
7346 color[2] = color[-6];
7347 color[3] = color[-5];
7348 }
7349 #endif
7350
7351 static
SetUCColorToPrevN(int n,uchar * color)7352 void SetUCColorToPrevN(int n, uchar *color){
7353 color[0] = color[-n*4];
7354 color[1] = color[-n*4+1];
7355 color[2] = color[-n*4+2];
7356 color[3] = color[-n*4+3];
7357 }
7358
7359 static
get_pickcolorsset_ptr(int op,float * pc)7360 int * get_pickcolorsset_ptr(int op, float * pc) {
7361 #define RETURN_PICKCOLORSETPTR_CASE(cls) \
7362 case cgo::draw::cls::op_code: \
7363 return &(reinterpret_cast<cgo::draw::cls*>(pc)->pickcolorsset)
7364 switch (op) {
7365 RETURN_PICKCOLORSETPTR_CASE(buffers_indexed);
7366 RETURN_PICKCOLORSETPTR_CASE(buffers_not_indexed);
7367 RETURN_PICKCOLORSETPTR_CASE(labels);
7368 RETURN_PICKCOLORSETPTR_CASE(sphere_buffers);
7369 RETURN_PICKCOLORSETPTR_CASE(cylinder_buffers);
7370 RETURN_PICKCOLORSETPTR_CASE(custom);
7371 }
7372 return NULL;
7373 }
7374
CGORenderGLPicking(CGO * I,RenderInfo * info,PickContext * context,CSetting * set1,CSetting * set2,Rep * rep)7375 void CGORenderGLPicking(CGO * I, RenderInfo *info, PickContext * context, CSetting * set1,
7376 CSetting * set2, Rep *rep)
7377 {
7378 PyMOLGlobals *G = I->G;
7379
7380 if (!G->ValidContext)
7381 return;
7382
7383 if (!I->c)
7384 return;
7385
7386 CCGORenderer *R = G->CGORenderer;
7387 bool pickable = (!I->no_pick) &&
7388 SettingGet_b(G, set1, set2, cSetting_pickable);
7389 auto pick = info->pick;
7390 bool reset_colors = !pick->pickColorsValid();
7391
7392 R->use_shader = I->use_shader;
7393 R->isPicking = true;
7394 R->set1 = set1;
7395 R->set2 = set2;
7396 R->info = info;
7397 R->rep = rep;
7398
7399 #ifndef _WEBGL
7400 glLineWidth(SettingGet_f(G, set1, set2, cSetting_cgo_line_width));
7401 #endif
7402
7403 for (auto it = I->begin(); !it.is_stop(); ++it) {
7404 const auto op = it.op_code();
7405 CGO_OP_DATA_CONST float* pc = it.data();
7406
7407 switch (op) {
7408 case CGO_COLOR:
7409 continue;
7410
7411 case CGO_PICK_COLOR:
7412
7413 if (reset_colors){ // only if picking info is invalid
7414 unsigned char col[4];
7415 AssignNewPickColor(I, pick, col, context, CGO_get_uint(pc),
7416 pickable ? CGO_get_int(pc + 1) : cPickableNoPick);
7417 #ifndef PURE_OPENGL_ES_2
7418 if (!I->use_shader){
7419 glColor4ubv(col);
7420 }
7421 #endif
7422 } else {
7423 PRINTFB(G, FB_CGO, FB_Warnings)
7424 " %s: unexpected CGO_PICK_COLOR with !reset_colors\n",
7425 __func__ ENDFB(G);
7426 }
7427 continue;
7428
7429 case CGO_DRAW_ARRAYS:
7430 {
7431 const cgo::draw::arrays * sp = reinterpret_cast<decltype(sp)>(pc);
7432 int arrays = sp->arraybits;
7433 if (reset_colors && arrays & CGO_PICK_COLOR_ARRAY){ // only if picking info is invalid
7434 int nverts = sp->nverts, v, idx = -1, bnd = -1;
7435 float *pca = sp->floatdata;
7436
7437 if (arrays & CGO_VERTEX_ARRAY){ pca += nverts * 3; }
7438 if (arrays & CGO_NORMAL_ARRAY){ pca += nverts * 3; }
7439 if (arrays & CGO_COLOR_ARRAY){ pca += nverts * 4; }
7440
7441 auto pickColorValsUC = (uchar*)pca;
7442 auto pickColorVals = (int*)(pca + nverts);
7443
7444 for (v=0;v<nverts; v++) {
7445 bnd = pickable ? pickColorVals[v * 2 + 1] : cPickableNoPick;
7446 idx = pickColorVals[v * 2];
7447 AssignNewPickColor(
7448 I, pick, pickColorValsUC + (v * 4), context, idx, bnd);
7449 }
7450 }
7451 }
7452 break;
7453
7454 case CGO_DRAW_BUFFERS_INDEXED:
7455 case CGO_DRAW_BUFFERS_NOT_INDEXED:
7456 case CGO_DRAW_TEXTURES:
7457 case CGO_DRAW_LABELS:
7458 case CGO_DRAW_SPHERE_BUFFERS:
7459 case CGO_DRAW_CYLINDER_BUFFERS:
7460 case CGO_DRAW_CUSTOM:
7461 {
7462 int pickcolors_are_set = true;
7463 int* pickcolors_are_set_ptr = get_pickcolorsset_ptr(op, const_cast<float*>(pc));
7464 if (!pickcolors_are_set_ptr)
7465 pickcolors_are_set_ptr = &pickcolors_are_set;
7466
7467 // TODO remove `pickcolorsset` fields from CGOs
7468 // This assert can fail during "Roving Detail" demo. However, I still
7469 // question the need of the `pickcolorsset` fields.
7470 // assert(reset_colors || *pickcolors_are_set_ptr);
7471
7472 if (reset_colors || !*pickcolors_are_set_ptr){ // only if picking info is invalid
7473 int nverts = 0;
7474 int nvertsperfrag = 1;
7475 int v, pl;
7476 int bnd = cPickableNoPick;
7477 unsigned int idx = 0;
7478 int srcp;
7479 float *pca = nullptr;
7480 int *pickDataSrc ;
7481 uchar *pickColorDestUC = NULL;
7482 bool free_pick_color_dest = false;
7483 int destOffset = 0, bufsizemult = 1;
7484 size_t pickvbo = 0;
7485 switch (op){
7486 case CGO_DRAW_CUSTOM:
7487 {
7488 const cgo::draw::custom * sp = reinterpret_cast<decltype(sp)>(pc);
7489 nverts = sp->nverts;
7490 pickvbo = sp->pickvboid;
7491 if (!pickvbo)
7492 continue;
7493 pca = sp->floatdata;
7494 nvertsperfrag = sp->vertsperpickinfo;
7495 bufsizemult = sp->npickbufs;
7496
7497 pickColorDestUC = new uchar[bufsizemult * nverts * 4];
7498 }
7499 break;
7500 case CGO_DRAW_BUFFERS_INDEXED:
7501 {
7502 const cgo::draw::buffers_indexed * sp = reinterpret_cast<decltype(sp)>(pc);
7503 nverts = sp->nverts;
7504 pickvbo = sp->pickvboid;
7505 pca = sp->floatdata;
7506 }
7507 break;
7508 case CGO_DRAW_BUFFERS_NOT_INDEXED:
7509 {
7510 const cgo::draw::buffers_not_indexed * sp = reinterpret_cast<decltype(sp)>(pc);
7511 nverts = sp->nverts;
7512 pickvbo = sp->pickvboid;
7513 pca = sp->floatdata;
7514 }
7515 break;
7516 case CGO_DRAW_SPHERE_BUFFERS:
7517 {
7518 const cgo::draw::sphere_buffers * sp = reinterpret_cast<decltype(sp)>(pc);
7519 nverts = sp->num_spheres * VERTICES_PER_SPHERE;
7520 nvertsperfrag = VERTICES_PER_SPHERE;
7521 pickvbo = sp->pickvboid;
7522 pca = sp->floatdata;
7523
7524 pickColorDestUC = new uchar[nverts * 4];
7525 }
7526 break;
7527 case CGO_DRAW_CYLINDER_BUFFERS:
7528 {
7529 const cgo::draw::cylinder_buffers * sp = reinterpret_cast<decltype(sp)>(pc);
7530 nverts = sp->num_cyl * NUM_VERTICES_PER_CYLINDER;
7531 nvertsperfrag = NUM_VERTICES_PER_CYLINDER;
7532 pickvbo = sp->pickvboid;
7533 pca = sp->floatdata;
7534 bufsizemult = 2;
7535
7536 pickColorDestUC = new uchar[bufsizemult * nverts * 4];
7537 }
7538 break;
7539 case CGO_DRAW_TEXTURES:
7540 {
7541 const cgo::draw::textures * sp = reinterpret_cast<decltype(sp)>(pc);
7542 nverts = sp->ntextures * 6;
7543 pca = sp->floatdata;
7544 }
7545 break;
7546 case CGO_DRAW_LABELS:
7547 {
7548 const cgo::draw::labels * sp;
7549 sp = reinterpret_cast<decltype(sp)>(pc);
7550 nverts = sp->ntextures * 6;
7551 pca = sp->floatdata;
7552 pickvbo = sp->pickvboid;
7553 }
7554 break;
7555 }
7556
7557 if (pickColorDestUC) {
7558 free_pick_color_dest = true;
7559 pickDataSrc = (int*)(pca);
7560 } else {
7561 pickColorDestUC = (uchar*)pca;
7562 pickDataSrc = (int*)(pca + nverts);
7563 }
7564
7565 destOffset = R->pick_pass() * sizeof(float) * nverts * bufsizemult;
7566
7567 if (!pickable){
7568 for (int i = 0; i < nverts * bufsizemult; ++i) {
7569 pick->colorNoPick(pickColorDestUC + 4 * i);
7570 }
7571 } else {
7572 int npickbufs = bufsizemult;
7573 int ploffsetforbuf = 0;
7574 if (op == CGO_DRAW_CYLINDER_BUFFERS){
7575 // disabled 2016-07-19 TH: code looks almost identical to
7576 // else branch and CGO_DRAW_CYLINDER_BUFFERS seem to be
7577 // not used anymore.
7578 PRINTFB(I->G, FB_CGO, FB_Errors)
7579 " FIXME: SUPPOSEDLY UNUSED CODE EXECUTED in CGORenderGLPicking!\n"
7580 ENDFB(I->G);
7581 } else {
7582 if (op == CGO_DRAW_CUSTOM){
7583 ploffsetforbuf = sizeof(float) * nverts; // for multiple picking attributes
7584 }
7585 for (v=0, pl = 0;v<nverts; v++, pl += 4){
7586 if (v % nvertsperfrag){
7587 // if same fragment, same color
7588 for (int pi = 0; pi < npickbufs; ++pi){
7589 int ploffset = ploffsetforbuf * pi;
7590 SetUCColorToPrevN(1, &pickColorDestUC[pl+ploffset]);
7591 }
7592 continue;
7593 }
7594
7595 int frag = (int)(v / nvertsperfrag);
7596 for (int pi = 0; pi < npickbufs; ++pi){
7597 int ploffset = ploffsetforbuf * pi;
7598 srcp = 2* ((npickbufs * frag) + pi);
7599 idx = pickDataSrc[srcp];
7600 bnd = pickDataSrc[srcp + 1];
7601
7602 AssignNewPickColor(I, pick, &pickColorDestUC[pl + ploffset],
7603 context, idx, bnd);
7604 }
7605 }
7606 }
7607 }
7608
7609 if (pickvbo) {
7610 // reload entire vbo
7611 VertexBuffer * vbo = I->G->ShaderMgr->getGPUBuffer<VertexBuffer>(pickvbo);
7612 vbo->bufferReplaceData(destOffset, sizeof(float) * nverts * bufsizemult, pickColorDestUC);
7613 (*pickcolors_are_set_ptr) = true;
7614 }
7615
7616 if (free_pick_color_dest){
7617 delete[] pickColorDestUC;
7618 pickColorDestUC = NULL;
7619 free_pick_color_dest = false;
7620 }
7621 }
7622 }
7623 break;
7624 }
7625
7626 CGO_gl[op] (R, &pc);
7627 }
7628
7629 R->isPicking = false;
7630 }
7631
CGORenderGL(CGO * I,const float * color,CSetting * set1,CSetting * set2,RenderInfo * info,Rep * rep)7632 void CGORenderGL(CGO * I, const float *color, CSetting * set1, CSetting * set2,
7633 RenderInfo * info, Rep *rep)
7634 /* this should be as fast as you can make it...
7635
7636 * the ASM loop is about 2X long as raw looped GL calls,
7637
7638 * but hopefully superscaler processors won't care */
7639 {
7640 PyMOLGlobals *G = I->G;
7641
7642 const float zee[] = {0.f, 0.f, 1.f};
7643 const float color_tmp[] = {1.f, 1.f, 1.f};
7644
7645 if (I->render_alpha){
7646 // for now, the render_alpha_only flag calls CGOSetZVector/CGORenderGLAlpha
7647 float *ModMatrix = SceneGetModMatrix(G);
7648 CGOSetZVector(I, ModMatrix[2], ModMatrix[6], ModMatrix[10]);
7649 CGORenderGLAlpha(I, info, 1);
7650 if (I->render_alpha == 1) // right now, render_alpha 1: renders alpha only, 2: renders both alpha and rest
7651 return;
7652 }
7653
7654 if (!G->ValidContext) {
7655 return;
7656 }
7657
7658 if (!I->c) {
7659 return;
7660 }
7661
7662 {
7663 CCGORenderer *R = G->CGORenderer;
7664 R->info = info;
7665 R->use_shader = I->use_shader;
7666 R->debug = I->debug;
7667 R->sphere_quality = I->sphere_quality;
7668 R->rep = rep;
7669 R->color = color;
7670 R->alpha = 1.0F - SettingGet_f(G, set1, set2, cSetting_cgo_transparency);
7671 R->set1 = set1;
7672 R->set2 = set2;
7673 // normals should be initialized to the view vector
7674 // (changed BB 9/14 from SceneResetNormalUseShader(), to CScene->LinesNormal, which was arbitrary, I believe)
7675 SceneResetNormalToViewVector(I->G, I->use_shader);
7676
7677 if (!color) {
7678 color = color_tmp;
7679 }
7680
7681 {
7682 auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
7683 if (shaderPrg && I->use_shader) {
7684 shaderPrg->SetAttrib4fLocation("a_Color", color[0], color[1], color[2], R->alpha);
7685 }
7686 else {
7687 glColor4f(color[0], color[1], color[2], R->alpha);
7688 }
7689 }
7690
7691 #ifndef PURE_OPENGL_ES_2
7692 const float width_scale = (info && info->width_scale_flag) ? info->width_scale : 1.f;
7693 glLineWidth(SettingGet_f(G, set1, set2, cSetting_cgo_line_width) * width_scale);
7694 glPointSize(SettingGet_f(G, set1, set2, cSetting_cgo_dot_width) * width_scale);
7695 #endif
7696
7697 if (!(info && info->alpha_cgo)) {
7698 // Regular CGO dispatch table rendering
7699 for (auto it = I->begin(); !it.is_stop(); ++it) {
7700 const auto op = it.op_code();
7701 assert(op < CGO_sz_size());
7702 CGO_OP_DATA_CONST float* const pc = it.data();
7703
7704 CGO_gl[op](R, &pc);
7705 }
7706 return;
7707 }
7708
7709 /* we're sorting transparent triangles globally */
7710 {
7711 {
7712 int mode = -1;
7713 int vc = 0;
7714 // triangle normals
7715 const float *n0 = NULL, *n1 = NULL, *n2 = NULL;
7716 // triangle vertices
7717 const float *v0 = NULL, *v1 = NULL, *v2 = NULL;
7718 // triangle colors
7719 const float *c0 = color, *c1 = NULL, *c2 = NULL;
7720
7721 for (auto it = I->begin(); !it.is_stop(); ++it) {
7722 const auto op = it.op_code();
7723 assert(op < CGO_sz_size());
7724 CGO_OP_DATA_CONST float* const pc = it.data();
7725
7726 if((R->alpha != 1.f)) {
7727 switch (op) { /* transparency */
7728 case CGO_BEGIN:
7729 mode = CGO_get_int(pc);
7730 CGO_gl_begin(R, &pc);
7731 vc = 0;
7732 n0 = zee;
7733 break;
7734 case CGO_END:
7735 CGO_gl_end(R, &pc);
7736 mode = -1;
7737 break;
7738 case CGO_NORMAL:
7739 switch (mode) {
7740 case GL_TRIANGLES:
7741 case GL_TRIANGLE_STRIP:
7742 case GL_TRIANGLE_FAN:
7743 n0 = pc;
7744 break;
7745 default:
7746 CGO_gl_normal(R, &pc);
7747 }
7748 break;
7749 case CGO_COLOR:
7750 c0 = pc;
7751 CGO_gl_color(R, &pc);
7752 break;
7753 case CGO_TRIANGLE:
7754 CGOAlphaTriangle(info->alpha_cgo,
7755 pc, pc + 3, pc + 6, pc + 9, pc + 12, pc + 15, pc + 18,
7756 pc + 21, pc + 24, R->alpha, R->alpha, R->alpha, false);
7757 break;
7758 case CGO_DRAW_ARRAYS:
7759 {
7760 const cgo::draw::arrays * sp = reinterpret_cast<decltype(sp)>(pc);
7761 int mode = sp->mode, arrays = sp->arraybits, nverts = sp->nverts;
7762 float *vertexVals = 0, *nxtVals = 0, *colorVals = 0, *normalVals;
7763 float *vertexVals_tmp = 0, *colorVals_tmp = 0, *normalVals_tmp = 0;
7764 int step;
7765 short nxtn = 3;
7766 nxtVals = vertexVals = vertexVals_tmp = sp->floatdata;
7767 if (arrays & CGO_NORMAL_ARRAY){
7768 nxtVals = normalVals = normalVals_tmp = vertexVals + (nxtn*nverts);
7769 }
7770 if (arrays & CGO_COLOR_ARRAY){
7771 nxtVals = colorVals = colorVals_tmp = nxtVals + (nxtn*nverts);
7772 nxtn = 4;
7773 }
7774 switch (mode){
7775 case GL_TRIANGLES:
7776 {
7777 for (step = 0; step < nverts; step += 3){
7778 if (colorVals_tmp){
7779 c0 = colorVals_tmp; c1 = colorVals_tmp+4; c2 = colorVals_tmp+8;
7780 } else {
7781 c1 = c2 = c0;
7782 }
7783 if (normalVals_tmp){
7784 n0 = normalVals_tmp; n1 = normalVals_tmp+3; n2 = normalVals_tmp+6;
7785 } else {
7786 n1 = n2 = n0;
7787 }
7788 CGOAlphaTriangle(info->alpha_cgo,
7789 vertexVals_tmp, vertexVals_tmp+3, vertexVals_tmp+6,
7790 n0, n1, n2,
7791 c0, c1, c2,
7792 R->alpha, R->alpha, R->alpha, false);
7793 vertexVals_tmp += 9;
7794 if (normalVals_tmp){
7795 normalVals_tmp += 9;
7796 }
7797 if (colorVals_tmp){
7798 colorVals_tmp += 12;
7799 }
7800 }
7801 }
7802 break;
7803 case GL_TRIANGLE_STRIP:
7804 {
7805 if (colorVals_tmp){
7806 c1 = colorVals_tmp; c2 = colorVals_tmp+4;
7807 colorVals_tmp += 8;
7808 } else {
7809 c1 = c2 = c0;
7810 }
7811 if (normalVals_tmp){
7812 n1 = normalVals_tmp; n2 = normalVals_tmp+3;
7813 normalVals_tmp+= 6;
7814 } else {
7815 n1 = n2 = n0;
7816 }
7817 vertexVals_tmp += 6;
7818 for (step = 2; step < nverts; step++){
7819 if (colorVals_tmp){
7820 c0 = c1; c1 = c2; c2 = colorVals_tmp;
7821 }
7822 if (normalVals_tmp){
7823 n0 = n1; n1 = n2; n2 = normalVals_tmp;
7824 }
7825 CGOAlphaTriangle(info->alpha_cgo,
7826 vertexVals_tmp-6, vertexVals_tmp-3, vertexVals_tmp,
7827 n0, n1, n2,
7828 c0, c1, c2,
7829 R->alpha, R->alpha, R->alpha, false);
7830 vertexVals_tmp += 3;
7831 if (normalVals_tmp){
7832 normalVals_tmp += 3;
7833 }
7834 if (colorVals_tmp){
7835 colorVals_tmp += 4;
7836 }
7837 }
7838 }
7839 break;
7840 case GL_TRIANGLE_FAN:
7841 {
7842 float *firstVertex = vertexVals_tmp;
7843 if (colorVals_tmp){
7844 c0 = colorVals_tmp;
7845 c2 = colorVals_tmp + 4;
7846 colorVals_tmp += 8;
7847 } else {
7848 c1 = c2 = c0;
7849 }
7850 if (normalVals_tmp){
7851 n0 = normalVals_tmp;
7852 n2 = normalVals_tmp + 3;
7853 normalVals_tmp += 6;
7854 }
7855 vertexVals_tmp += 6;
7856 for (step = 2; step < nverts; step++){
7857 if (colorVals_tmp){
7858 c1 = c2; c2 = colorVals_tmp;
7859 }
7860 if (normalVals_tmp){
7861 n1 = n2; n2 = normalVals_tmp;
7862 }
7863 CGOAlphaTriangle(info->alpha_cgo,
7864 firstVertex, vertexVals_tmp-3, vertexVals_tmp,
7865 n0, n1, n2,
7866 c0, c1, c2,
7867 R->alpha, R->alpha, R->alpha, false);
7868 vertexVals_tmp += 3;
7869 if (normalVals_tmp){
7870 normalVals_tmp += 3;
7871 }
7872 if (colorVals_tmp){
7873 colorVals_tmp += 4;
7874 }
7875 }
7876 }
7877 break;
7878 }
7879 }
7880 break;
7881 case CGO_VERTEX:
7882 v0 = pc;
7883 switch (mode) {
7884 case GL_TRIANGLES:
7885 if(3 * ((vc + 1) / 3) == vc + 1) {
7886 CGOAlphaTriangle(info->alpha_cgo,
7887 v0, v1, v2, n0, n1, n2, c0, c1, c2,
7888 R->alpha, R->alpha, R->alpha, true);
7889 }
7890 v2 = v1;
7891 c2 = c1;
7892 n2 = n1;
7893 v1 = v0;
7894 c1 = c0;
7895 n1 = n0;
7896 vc++;
7897 break;
7898 case GL_TRIANGLE_STRIP:
7899 if(vc > 1) {
7900 CGOAlphaTriangle(info->alpha_cgo,
7901 v0, v1, v2, n0, n1, n2, c0, c1, c2,
7902 R->alpha, R->alpha, R->alpha, !(vc & 0x1));
7903 }
7904 v2 = v1;
7905 c2 = c1;
7906 n2 = n1;
7907 v1 = v0;
7908 c1 = c0;
7909 n1 = n0;
7910 vc++;
7911 break;
7912 case GL_TRIANGLE_FAN:
7913 if(vc > 1) {
7914 CGOAlphaTriangle(info->alpha_cgo,
7915 v0, v1, v2, n0, n1, n2, c0, c1, c2,
7916 R->alpha, R->alpha, R->alpha, false);
7917 } else if(!vc) {
7918 n2 = n0;
7919 v2 = v0;
7920 c2 = c0;
7921 }
7922 v1 = v0;
7923 c1 = c0;
7924 n1 = n0;
7925 vc++;
7926 break;
7927 default:
7928 CGO_gl_vertex(R, &pc);
7929 break;
7930 }
7931 break;
7932 default:
7933 CGO_gl[op] (R, &pc);
7934 break;
7935 }
7936 } else { /* opaque */
7937 switch(op){
7938 case CGO_COLOR:
7939 /* Since CGO operations are done in sequence, alpha could happen
7940 after color is set. In this case, we still need to keep track of the color
7941 in case there is a transparent object */
7942 c0 = pc;
7943 break;
7944 default:
7945 break;
7946 }
7947 CGO_gl[op] (R, &pc);
7948 }
7949 }
7950 }
7951 }
7952 }
7953 }
7954
CGORenderGLAlpha(CGO * I,RenderInfo * info,bool calcDepth)7955 void CGORenderGLAlpha(CGO * I, RenderInfo * info, bool calcDepth)
7956 {
7957 PyMOLGlobals *G = I->G;
7958 if(G->ValidContext && I->c) {
7959 int mode = GL_TRIANGLES;
7960 if (I->debug){
7961 mode = CGOConvertDebugMode(I->debug, GL_TRIANGLES);
7962 }
7963 #ifndef PURE_OPENGL_ES_2
7964 // not sure why shader is set, but disable it for now,
7965 // since we are doing immediate mode rendering for global transparency
7966 G->ShaderMgr->Disable_Current_Shader();
7967 #endif
7968 /* 1. transform and measure range (if not already known)
7969 2. bin into linked lists based on Z-centers
7970 3. render by layer */
7971
7972 if(I->z_flag) {
7973 if(!I->i_start) {
7974 I->i_size = 256;
7975 I->i_start = pymol::calloc<int>(I->i_size);
7976 } else {
7977 UtilZeroMem(I->i_start, sizeof(int) * I->i_size);
7978 }
7979 {
7980 const int i_size = I->i_size;
7981 const float* base = I->op;
7982 int *start = I->i_start;
7983 int delta = 1, ntris = 0;
7984 /* bin the triangles */
7985 if (calcDepth){
7986 for (auto it = I->begin(); !it.is_stop(); ++it) {
7987 if (it.op_code() == CGO_ALPHA_TRIANGLE) {
7988 float* const pc = it.data();
7989 const float z = dot_product3f(pc + 1, I->z_vector);
7990 if(z > I->z_max)
7991 I->z_max = z;
7992 if(z < I->z_min)
7993 I->z_min = z;
7994 pc[4] = z;
7995 ntris++;
7996 }
7997 }
7998 }
7999
8000 const float range_factor = (0.9999F * i_size) / (I->z_max - I->z_min);
8001
8002 for (auto it = I->begin(); !it.is_stop(); ++it) {
8003 if (it.op_code() == CGO_ALPHA_TRIANGLE) {
8004 float* const pc = it.data();
8005 assert(base < pc && pc < I->op + I->c);
8006 auto i = pymol::clamp<int>((pc[4] - I->z_min) * range_factor, 0, i_size);
8007 CGO_put_int(pc, start[i]);
8008 start[i] = (pc - base); /* NOTE: will always be > 0 since we have CGO_read_int'd */
8009 }
8010 }
8011
8012 // for single-layer transparency, render front-to-back
8013 if(SettingGetGlobal_i(G, cSetting_transparency_mode) == 2) {
8014 delta = -1;
8015 start += (i_size - 1);
8016 }
8017
8018 /* now render by bin */
8019 #ifndef PURE_OPENGL_ES_2
8020 glBegin(mode);
8021 for (int i = 0; i < i_size; i++) {
8022 int ii = *start;
8023 start += delta;
8024 while(ii) {
8025 const float* pc = base + ii;
8026 glColor4fv(pc + 23);
8027 glNormal3fv(pc + 14);
8028 glVertex3fv(pc + 5);
8029 glColor4fv(pc + 27);
8030 glNormal3fv(pc + 17);
8031 glVertex3fv(pc + 8);
8032 glColor4fv(pc + 31);
8033 glNormal3fv(pc + 20);
8034 glVertex3fv(pc + 11);
8035
8036 ii = CGO_get_int(pc);
8037 }
8038 }
8039 glEnd();
8040 #endif
8041 }
8042 } else {
8043 #ifndef PURE_OPENGL_ES_2
8044 glBegin(mode);
8045 for (auto it = I->begin(); !it.is_stop(); ++it) {
8046 if (it.op_code() == CGO_ALPHA_TRIANGLE) {
8047 float* const pc = it.data();
8048 glColor4fv(pc + 23);
8049 glNormal3fv(pc + 14);
8050 glVertex3fv(pc + 5);
8051 glColor4fv(pc + 27);
8052 glNormal3fv(pc + 17);
8053 glVertex3fv(pc + 8);
8054 glColor4fv(pc + 31);
8055 glNormal3fv(pc + 20);
8056 glVertex3fv(pc + 11);
8057 }
8058 }
8059 glEnd();
8060 #endif
8061 }
8062 }
8063 }
8064
8065
8066 /* translation function which turns cylinders and spheres into triangles */
8067
CGOSimpleSphere(CGO * I,const float * v,float vdw,short sphere_quality)8068 static int CGOSimpleSphere(CGO * I, const float *v, float vdw, short sphere_quality)
8069 {
8070 SphereRec *sp;
8071 int *q, *s;
8072 int b, c;
8073 int ok = true;
8074 /* cgo_sphere_quality is between 0 and (NUMBER_OF_SPHERE_LEVELS-1) */
8075
8076 sp = I->G->Sphere->Sphere[CLAMPVALUE<short>(sphere_quality, 0, (NUMBER_OF_SPHERE_LEVELS-1)) ];
8077
8078 q = sp->Sequence;
8079 s = sp->StripLen;
8080
8081 for(b = 0; b < sp->NStrip; b++) {
8082 if (ok)
8083 ok &= CGOBegin(I, GL_TRIANGLE_STRIP);
8084 for(c = 0; ok && c < (*s); c++) {
8085 ok &= CGONormalv(I, sp->dot[*q]);
8086 if (ok)
8087 ok &= CGOVertex(I, v[0] + vdw * sp->dot[*q][0],
8088 v[1] + vdw * sp->dot[*q][1], v[2] + vdw * sp->dot[*q][2]);
8089 q++;
8090 }
8091 if (ok)
8092 ok &= CGOEnd(I);
8093 s++;
8094 }
8095 return ok;
8096 }
8097
CGOSimpleQuadric(CGO * I,const float * v,float r,const float * q)8098 static int CGOSimpleQuadric(CGO * I, const float *v, float r, const float *q)
8099 {
8100 float r_el, n0[3], n1[3], n2[3];
8101 int ok = true;
8102 if(CGOQuadricToEllipsoid(v, r, q, &r_el, n0, n1, n2))
8103 ok &= CGOSimpleEllipsoid(I, v, r_el, n0, n1, n2);
8104 return ok;
8105 }
8106
CGOSimpleEllipsoid(CGO * I,const float * v,float vdw,const float * n0,const float * n1,const float * n2)8107 static int CGOSimpleEllipsoid(CGO* I, const float* v, float vdw,
8108 const float* n0, const float* n1, const float* n2)
8109 {
8110 SphereRec *sp;
8111 int *q, *s;
8112 int b, c;
8113 int ds;
8114 float nn0[3], nn1[3], nn2[3];
8115 float scale[3], scale_sq[3];
8116 int ok = true;
8117
8118 normalize23f(n0, nn0);
8119 normalize23f(n1, nn1);
8120 normalize23f(n2, nn2);
8121
8122 scale[0] = (float) length3f(n0);
8123 scale[1] = (float) length3f(n1);
8124 scale[2] = (float) length3f(n2);
8125
8126 scale_sq[0] = scale[0] * scale[0];
8127 scale_sq[1] = scale[1] * scale[1];
8128 scale_sq[2] = scale[2] * scale[2];
8129
8130 ds = SettingGet_i(I->G, NULL, NULL, cSetting_cgo_ellipsoid_quality);
8131 if(ds < 0)
8132 ds = SettingGet_i(I->G, NULL, NULL, cSetting_ellipsoid_quality);
8133 if(ds < 0)
8134 ds = 0;
8135 if(ds > 3)
8136 ds = 3;
8137 sp = I->G->Sphere->Sphere[ds];
8138
8139 q = sp->Sequence;
8140 s = sp->StripLen;
8141
8142 for(b = 0; b < sp->NStrip; b++) {
8143 ok &= CGOBegin(I, GL_TRIANGLE_STRIP);
8144 for(c = 0; ok && c < (*s); c++) {
8145 float *sp_dot_q = sp->dot[*q];
8146 float s0 = vdw * sp_dot_q[0];
8147 float s1 = vdw * sp_dot_q[1];
8148 float s2 = vdw * sp_dot_q[2];
8149 float d0[3], d1[3], d2[3], vv[3], direction[3];
8150 float dd0, dd1, dd2, ss0, ss1, ss2;
8151 float comp0[3], comp1[3], comp2[3];
8152 float surfnormal[3];
8153 int i;
8154
8155 scale3f(n0, s0, d0);
8156 scale3f(n1, s1, d1);
8157 scale3f(n2, s2, d2);
8158
8159 for(i = 0; i < 3; i++) {
8160 vv[i] = d0[i] + d1[i] + d2[i];
8161 }
8162 normalize23f(vv, direction);
8163 add3f(v, vv, vv);
8164
8165 dd0 = dot_product3f(direction, nn0);
8166 dd1 = dot_product3f(direction, nn1);
8167 dd2 = dot_product3f(direction, nn2);
8168
8169 if(scale[0] > R_SMALL8) {
8170 ss0 = dd0 / scale_sq[0];
8171 } else {
8172 ss0 = 0.0F;
8173 }
8174 if(scale[1] > R_SMALL8) {
8175 ss1 = dd1 / scale_sq[1];
8176 } else {
8177 ss1 = 0.0F;
8178 }
8179
8180 if(scale[2] > R_SMALL8) {
8181 ss2 = dd2 / scale_sq[2];
8182 } else {
8183 ss2 = 0.0F;
8184 }
8185
8186 scale3f(nn0, ss0, comp0);
8187 scale3f(nn1, ss1, comp1);
8188 scale3f(nn2, ss2, comp2);
8189
8190 for(i = 0; i < 3; i++) {
8191 surfnormal[i] = comp0[i] + comp1[i] + comp2[i];
8192 }
8193 normalize3f(surfnormal);
8194
8195 ok &= CGONormalv(I, surfnormal);
8196 if (ok)
8197 ok &= CGOVertexv(I, vv);
8198 q++;
8199 }
8200 if (ok)
8201 ok &= CGOEnd(I);
8202 s++;
8203 }
8204 return ok;
8205 }
8206
8207 /*
8208 * Triangulated round cap (half-globe)
8209 */
CGORoundNub(CGO * I,const float * v1,const float * p0,const float * p1,const float * p2,int direction,int nEdge,float size)8210 void CGORoundNub(CGO * I,
8211 const float *v1, // cap center
8212 const float *p0, // normal along axis
8213 const float *p1, // x coord in cap space
8214 const float *p2, // y coord in cap space
8215 int direction, // 1 or -1
8216 int nEdge, // "quality"
8217 float size)
8218 {
8219 const int cmax = (nEdge + 3) / 2;
8220 const float PI_over_cmax = PI / ((cmax - 1) * 2);
8221 const float PI_over_nEdge = (PI * 2) / nEdge;
8222 float z2 = 1.f;
8223
8224 // z coord in cap space
8225 float p3[3];
8226 scale3f(p0, direction, p3);
8227
8228 CGOBegin(I, GL_TRIANGLE_STRIP);
8229
8230 // from equator to pole (latitudinal)
8231 for (int c = 1; c < cmax; c += 1){
8232 float z1 = z2;
8233 z2 = cos(c * PI_over_cmax);
8234
8235 // around cylinder axis (longitudinal)
8236 for (int d = (nEdge + 1) * (-direction); d; d += direction){
8237 float z3 = z1;
8238
8239 // 2 vertices
8240 for (int e = -1; e < 1; ++e) {
8241 float x = cos(d * PI_over_nEdge) * sin((c + e) * PI_over_cmax);
8242 float y = sin(d * PI_over_nEdge) * sin((c + e) * PI_over_cmax);
8243 float normal[3], vertex[3];
8244
8245 normal[0] = p1[0] * x + p2[0] * y + p3[0] * z3;
8246 normal[1] = p1[1] * x + p2[1] * y + p3[1] * z3;
8247 normal[2] = p1[2] * x + p2[2] * y + p3[2] * z3;
8248
8249 vertex[0] = v1[0] + normal[0] * size;
8250 vertex[1] = v1[1] + normal[1] * size;
8251 vertex[2] = v1[2] + normal[2] * size;
8252
8253 normalize3f(normal);
8254 CGONormalv(I, normal);
8255 CGOVertexv(I, vertex);
8256
8257 z3 = z2;
8258 }
8259 }
8260 }
8261
8262 CGOEnd(I);
8263 }
8264
CGOSimpleCylinder(CGO * I,const float * v1,const float * v2,const float tube_size,const float * c1,const float * c2,const float alpha1,const float alpha2,const bool interp,const int cap1,const int cap2,const Pickable * pickcolor2,const bool stick_round_nub)8265 static int CGOSimpleCylinder(CGO * I, const float *v1, const float *v2, const float tube_size,
8266 const float *c1, const float *c2, const float alpha1,
8267 const float alpha2, const bool interp, const int cap1, const int cap2,
8268 const Pickable *pickcolor2, const bool stick_round_nub)
8269 {
8270 #define MAX_EDGE 50
8271
8272 float d[3], t[3], p0[3], p1[3], p2[3], vv1[3], vv2[3], v_buf[9], *v;
8273 float x[MAX_EDGE + 1], y[MAX_EDGE + 1];
8274 float overlap;
8275 float nub;
8276 bool colorFlag, interpColorFlag;
8277 int nEdge;
8278 int c;
8279 int ok = true;
8280 float midcolor[3];
8281 float midalpha{alpha1};
8282 Pickable pickcolor[2];
8283 pickcolor[0].index = I->current_pick_color_index;
8284 pickcolor[0].bond = I->current_pick_color_bond;
8285 if (pickcolor2){
8286 pickcolor[1].index = pickcolor2->index;
8287 pickcolor[1].bond = pickcolor2->bond;
8288 } else {
8289 pickcolor[1].index = pickcolor[0].index;
8290 pickcolor[1].bond = pickcolor[0].bond;
8291 }
8292 v = v_buf;
8293 nEdge = SettingGetGlobal_i(I->G, cSetting_stick_quality);
8294 overlap = tube_size * SettingGetGlobal_f(I->G, cSetting_stick_overlap);
8295 nub = tube_size * SettingGetGlobal_f(I->G, cSetting_stick_nub);
8296
8297 if(nEdge > MAX_EDGE)
8298 nEdge = MAX_EDGE;
8299 subdivide(nEdge, x, y);
8300
8301 colorFlag = (c1 != c2) && c2;
8302 colorFlag |= alpha1 != alpha2;
8303
8304 interpColorFlag = c2 && interp && pickcolor2;
8305 if (interpColorFlag){
8306 average3f(c1, c2, midcolor);
8307 midalpha = (alpha1 + alpha2) / 2.0f;
8308 }
8309 /* direction vector */
8310
8311 p0[0] = (v2[0] - v1[0]);
8312 p0[1] = (v2[1] - v1[1]);
8313 p0[2] = (v2[2] - v1[2]);
8314
8315 normalize3f(p0);
8316
8317 if(cap1 == cCylCapRound && !stick_round_nub) {
8318 vv1[0] = v1[0] - p0[0] * overlap;
8319 vv1[1] = v1[1] - p0[1] * overlap;
8320 vv1[2] = v1[2] - p0[2] * overlap;
8321 } else {
8322 vv1[0] = v1[0];
8323 vv1[1] = v1[1];
8324 vv1[2] = v1[2];
8325 }
8326 if(cap2 == cCylCapRound && !stick_round_nub) {
8327 vv2[0] = v2[0] + p0[0] * overlap;
8328 vv2[1] = v2[1] + p0[1] * overlap;
8329 vv2[2] = v2[2] + p0[2] * overlap;
8330 } else {
8331 vv2[0] = v2[0];
8332 vv2[1] = v2[1];
8333 vv2[2] = v2[2];
8334 }
8335
8336 d[0] = (vv2[0] - vv1[0]);
8337 d[1] = (vv2[1] - vv1[1]);
8338 d[2] = (vv2[2] - vv1[2]);
8339 if (pickcolor2){
8340 mult3f(d, .5f, d);
8341 }
8342 get_divergent3f(d, t);
8343 cross_product3f(d, t, p1);
8344 normalize3f(p1);
8345
8346 cross_product3f(d, p1, p2);
8347
8348 normalize3f(p2);
8349
8350 /* now we have a coordinate system */
8351
8352 if (ok)
8353 ok &= CGOBegin(I, GL_TRIANGLE_STRIP);
8354 for(c = nEdge; ok && c >= 0; c--) {
8355 v[0] = p1[0] * x[c] + p2[0] * y[c];
8356 v[1] = p1[1] * x[c] + p2[1] * y[c];
8357 v[2] = p1[2] * x[c] + p2[2] * y[c];
8358
8359 v[3] = vv1[0] + v[0] * tube_size;
8360 v[4] = vv1[1] + v[1] * tube_size;
8361 v[5] = vv1[2] + v[2] * tube_size;
8362
8363 v[6] = v[3] + d[0];
8364 v[7] = v[4] + d[1];
8365 v[8] = v[5] + d[2];
8366
8367 ok &= CGONormalv(I, v);
8368 if(ok && (colorFlag || interpColorFlag) ){
8369 ok &= CGOColorv(I, c1);
8370 ok &= CGOAlpha(I, alpha1);
8371 }
8372 if (ok)
8373 ok &= CGOVertexv(I, v + 3);
8374 if (ok && interpColorFlag){
8375 ok &= CGOColorv(I, midcolor);
8376 ok &= CGOAlpha(I, midalpha);
8377 } else if(ok && colorFlag && !pickcolor2){
8378 ok &= CGOColorv(I, c2);
8379 ok &= CGOAlpha(I, alpha2);
8380 }
8381 if (ok)
8382 ok &= CGOVertexv(I, v + 6);
8383 }
8384 if (ok)
8385 ok &= CGOEnd(I);
8386 if (pickcolor2){
8387 ok &= CGOColorv(I, c2);
8388 ok &= CGOAlpha(I, alpha2);
8389 CGOPickColor(I, pickcolor2->index, pickcolor2->bond);
8390 if (ok)
8391 ok &= CGOBegin(I, GL_TRIANGLE_STRIP);
8392 for(c = nEdge; ok && c >= 0; c--) {
8393 v[0] = p1[0] * x[c] + p2[0] * y[c];
8394 v[1] = p1[1] * x[c] + p2[1] * y[c];
8395 v[2] = p1[2] * x[c] + p2[2] * y[c];
8396
8397 v[3] = vv1[0] + v[0] * tube_size + d[0];
8398 v[4] = vv1[1] + v[1] * tube_size + d[1];
8399 v[5] = vv1[2] + v[2] * tube_size + d[2];
8400
8401 v[6] = v[3] + d[0];
8402 v[7] = v[4] + d[1];
8403 v[8] = v[5] + d[2];
8404
8405 ok &= CGONormalv(I, v);
8406 if (ok && interpColorFlag){
8407 ok &= CGOColorv(I, midcolor);
8408 ok &= CGOAlpha(I, midalpha);
8409 }
8410 if (ok)
8411 ok &= CGOVertexv(I, v + 3);
8412 if (ok && interpColorFlag){
8413 ok &= CGOColorv(I, c2);
8414 ok &= CGOAlpha(I, alpha2);
8415 }
8416 if (ok)
8417 ok &= CGOVertexv(I, v + 6);
8418 }
8419 if (ok)
8420 ok &= CGOEnd(I);
8421 }
8422
8423 if(ok && cap1) {
8424 if(ok && colorFlag && c1){
8425 ok &= CGOColorv(I, c1);
8426 ok &= CGOAlpha(I, alpha1);
8427 }
8428 if (pickcolor2)
8429 CGOPickColor(I, pickcolor[0].index, pickcolor[0].bond);
8430
8431 if(stick_round_nub && cap1 == cCylCapRound) {
8432 CGORoundNub(I, v1, p0, p1, p2, -1, nEdge, tube_size);
8433 } else {
8434 v[0] = -p0[0];
8435 v[1] = -p0[1];
8436 v[2] = -p0[2];
8437
8438 if(cap1 == cCylCapRound) {
8439 v[3] = vv1[0] - p0[0] * nub;
8440 v[4] = vv1[1] - p0[1] * nub;
8441 v[5] = vv1[2] - p0[2] * nub;
8442 } else {
8443 v[3] = vv1[0];
8444 v[4] = vv1[1];
8445 v[5] = vv1[2];
8446 }
8447
8448 if (ok) ok &= CGOBegin(I, GL_TRIANGLE_FAN);
8449 if (ok) ok &= CGONormalv(I, v);
8450 if (ok) ok &= CGOVertexv(I, v + 3);
8451
8452 for(c = nEdge; ok && c >= 0; c--) {
8453 v[0] = p1[0] * x[c] + p2[0] * y[c];
8454 v[1] = p1[1] * x[c] + p2[1] * y[c];
8455 v[2] = p1[2] * x[c] + p2[2] * y[c];
8456
8457 v[3] = vv1[0] + v[0] * tube_size;
8458 v[4] = vv1[1] + v[1] * tube_size;
8459 v[5] = vv1[2] + v[2] * tube_size;
8460
8461 if(cap1 == cCylCapRound)
8462 ok &= CGONormalv(I, v);
8463 if (ok)
8464 ok &= CGOVertexv(I, v + 3);
8465 }
8466 if (ok)
8467 ok &= CGOEnd(I);
8468 }
8469 }
8470
8471 if(ok && cap2) {
8472 if(ok && colorFlag && c2){
8473 ok &= CGOColorv(I, c2);
8474 ok &= CGOAlpha(I, alpha2);
8475 }
8476 if (pickcolor2)
8477 CGOPickColor(I, pickcolor2->index, pickcolor2->bond);
8478
8479 if(stick_round_nub && cap2 == cCylCapRound) {
8480 CGORoundNub(I, v2, p0, p1, p2, 1, nEdge, tube_size);
8481 } else {
8482 v[0] = p0[0];
8483 v[1] = p0[1];
8484 v[2] = p0[2];
8485
8486 if(cap2 == cCylCapRound) {
8487 v[3] = vv2[0] + p0[0] * nub;
8488 v[4] = vv2[1] + p0[1] * nub;
8489 v[5] = vv2[2] + p0[2] * nub;
8490 } else {
8491 v[3] = vv2[0];
8492 v[4] = vv2[1];
8493 v[5] = vv2[2];
8494 }
8495
8496 if (ok) ok &= CGOBegin(I, GL_TRIANGLE_FAN);
8497 if (ok) ok &= CGONormalv(I, v);
8498 if (ok) ok &= CGOVertexv(I, v + 3);
8499
8500 for(c = 0; ok && c <= nEdge; c++) {
8501 v[0] = p1[0] * x[c] + p2[0] * y[c];
8502 v[1] = p1[1] * x[c] + p2[1] * y[c];
8503 v[2] = p1[2] * x[c] + p2[2] * y[c];
8504
8505 v[3] = vv2[0] + v[0] * tube_size;
8506 v[4] = vv2[1] + v[1] * tube_size;
8507 v[5] = vv2[2] + v[2] * tube_size;
8508
8509 if(cap2 == cCylCapRound)
8510 ok &= CGONormalv(I, v);
8511 if (ok)
8512 ok &= CGOVertexv(I, v + 3);
8513 }
8514 if (ok) ok &= CGOEnd(I);
8515 }
8516 }
8517 return ok;
8518 }
8519
8520 template <typename CylinderT>
CGOSimpleCylinder(CGO * I,const CylinderT & cyl,const float a1,const float a2,const bool interp,const int cap1,const int cap2,const Pickable * pickcolor2,const bool stick_round_nub)8521 static int CGOSimpleCylinder(CGO* I, const CylinderT& cyl, const float a1,
8522 const float a2, const bool interp, const int cap1, const int cap2,
8523 const Pickable* pickcolor2, const bool stick_round_nub)
8524 {
8525 return CGOSimpleCylinder(I, cyl.vertex1, cyl.vertex2, cyl.radius, cyl.color1,
8526 cyl.color2, a1, a2, interp, cap1, cap2, pickcolor2, stick_round_nub);
8527 }
8528
CGOSimpleCone(CGO * I,const float * v1,const float * v2,float r1,float r2,const float * c1,const float * c2,int cap1,int cap2)8529 static int CGOSimpleCone(CGO* I, const float* v1, const float* v2, float r1,
8530 float r2, const float* c1, const float* c2, int cap1, int cap2)
8531 {
8532 #define MAX_EDGE 50
8533
8534 float d[3], t[3], p0[3], p1[3], p2[3], vv1[3], vv2[3], v_buf[9], *v;
8535 float x[MAX_EDGE + 1], y[MAX_EDGE + 1], edge_normal[3 * (MAX_EDGE + 1)];
8536 int colorFlag;
8537 int nEdge;
8538 int c;
8539 int ok = true;
8540
8541 v = v_buf;
8542 nEdge = SettingGetGlobal_i(I->G, cSetting_cone_quality);
8543
8544 if(nEdge > MAX_EDGE)
8545 nEdge = MAX_EDGE;
8546 subdivide(nEdge, x, y);
8547
8548 colorFlag = (c1 != c2) && c2;
8549
8550 ok &= CGOColorv(I, c1);
8551
8552 /* direction vector */
8553
8554 p0[0] = (v2[0] - v1[0]);
8555 p0[1] = (v2[1] - v1[1]);
8556 p0[2] = (v2[2] - v1[2]);
8557
8558 normalize3f(p0);
8559
8560 {
8561 vv1[0] = v1[0];
8562 vv1[1] = v1[1];
8563 vv1[2] = v1[2];
8564 }
8565
8566 {
8567 vv2[0] = v2[0];
8568 vv2[1] = v2[1];
8569 vv2[2] = v2[2];
8570 }
8571
8572 d[0] = (vv2[0] - vv1[0]);
8573 d[1] = (vv2[1] - vv1[1]);
8574 d[2] = (vv2[2] - vv1[2]);
8575
8576 get_divergent3f(d, t);
8577
8578 cross_product3f(d, t, p1);
8579
8580 normalize3f(p1);
8581
8582 cross_product3f(d, p1, p2);
8583
8584 normalize3f(p2);
8585
8586 /* now we have a coordinate system */
8587
8588 {
8589 float len = diff3f(v1, v2);
8590 float vt[3], nt[3];
8591 float slope = 0.0F;
8592
8593 if(len) {
8594 slope = (r1 - r2) / len;
8595 }
8596 for(c = nEdge; c >= 0; c--) {
8597 vt[0] = p1[0] * x[c] + p2[0] * y[c];
8598 vt[1] = p1[1] * x[c] + p2[1] * y[c];
8599 vt[2] = p1[2] * x[c] + p2[2] * y[c];
8600
8601 scale3f(p0, slope, nt);
8602 add3f(nt, vt, vt);
8603 normalize3f(vt);
8604 copy3f(vt, edge_normal + 3 * c);
8605 }
8606 }
8607
8608 /* now we have normals */
8609 if (ok)
8610 ok &= CGOBegin(I, GL_TRIANGLE_STRIP);
8611 for(c = nEdge; ok && c >= 0; c--) {
8612 v[0] = p1[0] * x[c] + p2[0] * y[c];
8613 v[1] = p1[1] * x[c] + p2[1] * y[c];
8614 v[2] = p1[2] * x[c] + p2[2] * y[c];
8615
8616 v[3] = vv1[0] + v[0] * r1;
8617 v[4] = vv1[1] + v[1] * r1;
8618 v[5] = vv1[2] + v[2] * r1;
8619
8620 v[6] = vv1[0] + v[0] * r2 + d[0];
8621 v[7] = vv1[1] + v[1] * r2 + d[1];
8622 v[8] = vv1[2] + v[2] * r2 + d[2];
8623
8624 ok &= CGONormalv(I, edge_normal + 3 * c);
8625 if(ok && colorFlag)
8626 CGOColorv(I, c1);
8627 if (ok)
8628 CGOVertexv(I, v + 3);
8629 if(ok && colorFlag)
8630 CGOColorv(I, c2);
8631 if (ok)
8632 CGOVertexv(I, v + 6);
8633 }
8634 if (ok)
8635 ok &= CGOEnd(I);
8636
8637 if(ok && cap1) {
8638 v[0] = -p0[0];
8639 v[1] = -p0[1];
8640 v[2] = -p0[2];
8641
8642 {
8643 v[3] = vv1[0];
8644 v[4] = vv1[1];
8645 v[5] = vv1[2];
8646 }
8647
8648 if(colorFlag)
8649 ok &= CGOColorv(I, c1);
8650 if (ok)
8651 ok &= CGOBegin(I, GL_TRIANGLE_FAN);
8652 if (ok)
8653 ok &= CGONormalv(I, v);
8654 if (ok)
8655 ok &= CGOVertexv(I, v + 3);
8656
8657 for(c = nEdge; ok && c >= 0; c--) {
8658 v[0] = p1[0] * x[c] + p2[0] * y[c];
8659 v[1] = p1[1] * x[c] + p2[1] * y[c];
8660 v[2] = p1[2] * x[c] + p2[2] * y[c];
8661
8662 v[3] = vv1[0] + v[0] * r1;
8663 v[4] = vv1[1] + v[1] * r1;
8664 v[5] = vv1[2] + v[2] * r1;
8665
8666 if(cap1 == cCylCapRound)
8667 ok &= CGONormalv(I, v);
8668 if (ok)
8669 ok &= CGOVertexv(I, v + 3);
8670 }
8671 if (ok)
8672 ok &= CGOEnd(I);
8673 }
8674
8675 if(ok && cap2) {
8676
8677 v[0] = p0[0];
8678 v[1] = p0[1];
8679 v[2] = p0[2];
8680
8681 {
8682 v[3] = vv2[0];
8683 v[4] = vv2[1];
8684 v[5] = vv2[2];
8685 }
8686
8687 if(colorFlag)
8688 ok &= CGOColorv(I, c2);
8689 if (ok)
8690 ok &= CGOBegin(I, GL_TRIANGLE_FAN);
8691 if (ok)
8692 ok &= CGONormalv(I, v);
8693 if (ok)
8694 ok &= CGOVertexv(I, v + 3);
8695
8696 for(c = 0; ok && c <= nEdge; c++) {
8697 v[0] = p1[0] * x[c] + p2[0] * y[c];
8698 v[1] = p1[1] * x[c] + p2[1] * y[c];
8699 v[2] = p1[2] * x[c] + p2[2] * y[c];
8700
8701 v[3] = vv2[0] + v[0] * r2;
8702 v[4] = vv2[1] + v[1] * r2;
8703 v[5] = vv2[2] + v[2] * r2;
8704
8705 if(cap2 == cCylCapRound)
8706 ok &= CGONormalv(I, v);
8707 if (ok)
8708 ok &= CGOVertexv(I, v + 3);
8709 }
8710 if (ok)
8711 ok &= CGOEnd(I);
8712 }
8713 return ok;
8714 }
8715
8716 /* CGOGetNextDrawBufferedIndex: This is used by RepSurface to */
8717 /* get the data from the CGO_DRAW_BUFFERS_INDEXED operation so */
8718 /* that it can update the indices for semi-transparent surfaces. */
CGOGetNextDrawBufferedNotIndex(const CGO * cgo)8719 const cgo::draw::buffers_not_indexed* CGOGetNextDrawBufferedNotIndex(
8720 const CGO* cgo)
8721 {
8722 for (auto it = cgo->begin(); !it.is_stop(); ++it) {
8723 if (it.op_code() == CGO_DRAW_BUFFERS_NOT_INDEXED) {
8724 return it.cast<cgo::draw::buffers_not_indexed>();
8725 }
8726 }
8727 return nullptr;
8728 }
8729
append(const CGO * source,bool stopAtEnd)8730 int CGO::append(const CGO * source, bool stopAtEnd) {
8731 int ok = 1;
8732
8733 for (auto it = source->begin(); !it.is_stop(); ++it) {
8734 add_to_cgo(it.op_code(), it.data());
8735 }
8736
8737 if (stopAtEnd)
8738 ok &= CGOStop(this);
8739 has_draw_buffers |= source->has_draw_buffers;
8740 has_draw_cylinder_buffers |= source->has_draw_cylinder_buffers;
8741 return ok;
8742 }
8743
8744 /*
8745 * Appends `src` to the end of this CGO. Takes ownership of data
8746 * (incl. VBOs) and leaves `src` as a valid but empty CGO.
8747 */
move_append(CGO * src)8748 void CGO::move_append(CGO * src) {
8749 if (!src->c)
8750 return;
8751
8752 // copy buffer
8753 VLACheck(op, float, c + src->c);
8754 memcpy(op + c, src->op, src->c * sizeof(float));
8755
8756 // update sizes
8757 c += src->c;
8758 src->c = 0;
8759
8760 // null terminators (CGO_STOP)
8761 *(op + c) = 0;
8762 *(src->op) = 0;
8763
8764 // move heap data
8765 for (auto& ref : src->_data_heap) {
8766 _data_heap.emplace_back(std::move(ref));
8767 }
8768 src->_data_heap.clear();
8769
8770 // copy boolean flags
8771 has_draw_buffers |= src->has_draw_buffers;
8772 has_draw_cylinder_buffers |= src->has_draw_cylinder_buffers;
8773 has_draw_sphere_buffers |= src->has_draw_sphere_buffers;
8774 has_begin_end |= src->has_begin_end;
8775 use_shader |= src->use_shader;
8776 render_alpha |= src->render_alpha;
8777 }
8778
8779 /*
8780 * Appends `src` to the end of this CGO and then free's `src`
8781 * and sets the pointer to NULL.
8782 */
free_append(CGO * & src)8783 void CGO::free_append(CGO * &src) {
8784 move_append(src);
8785 CGOFreeWithoutVBOs(src);
8786 }
8787
CGOAppend(CGO * dest,const CGO * source,bool stopAtEnd)8788 int CGOAppend(CGO *dest, const CGO *source, bool stopAtEnd){
8789 int ok = dest->append(source, stopAtEnd);
8790 return ok;
8791 }
8792
CGOCountNumberOfOperationsOfType(const CGO * I,int optype)8793 int CGOCountNumberOfOperationsOfType(const CGO *I, int optype){
8794 std::set<int> ops = { optype };
8795 return CGOCountNumberOfOperationsOfTypeN(I, ops);
8796 }
8797
CGOCountNumberOfOperationsOfTypeN(const CGO * I,const std::set<int> & optype)8798 int CGOCountNumberOfOperationsOfTypeN(const CGO* I, const std::set<int>& optype)
8799 {
8800 int numops = 0;
8801 for (auto cgoit = I->begin(); !cgoit.is_stop(); ++cgoit) {
8802 if (optype.count(cgoit.op_code()))
8803 numops++;
8804 }
8805 return (numops);
8806 }
8807
CGOCountNumberOfOperationsOfTypeN(const CGO * I,const std::map<int,int> & optype)8808 int CGOCountNumberOfOperationsOfTypeN(const CGO *I, const std::map<int, int> &optype){
8809 int numops = 0;
8810 for (auto cgoit = I->begin(); !cgoit.is_stop(); ++cgoit) {
8811 auto it = optype.find(cgoit.op_code());
8812 if (it != optype.end())
8813 numops += it->second;
8814 }
8815 return (numops);
8816 }
8817
CGOHasOperationsOfType(const CGO * I,int optype)8818 bool CGOHasOperationsOfType(const CGO *I, int optype){
8819 std::set<int> ops = { optype };
8820 return CGOHasOperationsOfTypeN(I, ops);
8821 }
8822
CGOHasOperations(const CGO * I)8823 bool CGOHasOperations(const CGO *I) {
8824 return !I->begin().is_stop();
8825 }
8826
CGOHasOperationsOfTypeN(const CGO * I,const std::set<int> & optype)8827 bool CGOHasOperationsOfTypeN(const CGO *I, const std::set<int> &optype){
8828 if (!I->op)
8829 return false;
8830
8831 for (auto it = I->begin(); !it.is_stop(); ++it) {
8832 if (optype.count(it.op_code()))
8833 return 1;
8834 }
8835 return (0);
8836 }
8837
8838 static
CGOFilterOutOperationsOfTypeN(const CGO * I,CGO * cgo,const std::set<int> & optype)8839 bool CGOFilterOutOperationsOfTypeN(const CGO *I, CGO *cgo, const std::set<int> &optype){
8840 if (!I->op)
8841 return false;
8842
8843 bool ret = false;
8844 for (auto it = I->begin(); !it.is_stop(); ++it) {
8845 auto op = it.op_code();
8846 if (optype.find(op) == optype.end()){
8847 auto pc = it.data();
8848 cgo->add_to_cgo(op, pc);
8849 } else {
8850 ret = true; // returns if filtered anything
8851 }
8852 }
8853 return ret;
8854 }
8855
CGOFilterOutCylinderOperationsInto(const CGO * I,CGO * cgo)8856 bool CGOFilterOutCylinderOperationsInto(const CGO *I, CGO *cgo){
8857 static std::set<int> optypes = { CGO_SHADER_CYLINDER,
8858 CGO_SHADER_CYLINDER_WITH_2ND_COLOR,
8859 CGO_SAUSAGE,
8860 CGO_CYLINDER,
8861 CGO_CUSTOM_CYLINDER,
8862 CGO_CUSTOM_CYLINDER_ALPHA };
8863 return CGOFilterOutOperationsOfTypeN(I, cgo, optypes);
8864 }
8865
CGOHasCylinderOperations(const CGO * I)8866 bool CGOHasCylinderOperations(const CGO *I){
8867 static std::set<int> optypes = { CGO_SHADER_CYLINDER,
8868 CGO_SHADER_CYLINDER_WITH_2ND_COLOR,
8869 CGO_SAUSAGE,
8870 CGO_CYLINDER,
8871 CGO_CUSTOM_CYLINDER,
8872 CGO_CUSTOM_CYLINDER_ALPHA };
8873 return CGOHasOperationsOfTypeN(I, optypes);
8874 }
8875
CGOHasSphereOperations(const CGO * I)8876 bool CGOHasSphereOperations(const CGO *I){
8877 static std::set<int> optypes = { CGO_SPHERE };
8878 return CGOHasOperationsOfTypeN(I, optypes);
8879 }
8880
CGOCheckWhetherToFree(PyMOLGlobals * G,CGO * I)8881 bool CGOCheckWhetherToFree(PyMOLGlobals * G, CGO *I){
8882 if (I->use_shader){
8883 if (I->cgo_shader_ub_color != SettingGetGlobal_i(G, cSetting_cgo_shader_ub_color) ||
8884 I->cgo_shader_ub_normal != SettingGetGlobal_i(G, cSetting_cgo_shader_ub_normal)){
8885 return true;
8886 }
8887 }
8888 return false;
8889 }
8890
CGOConvertLinesToShaderCylinders(const CGO * I,int est)8891 CGO *CGOConvertLinesToShaderCylinders(const CGO * I, int est){
8892
8893 int tot_nverts = 0, tot_ncyls = 0;
8894
8895 CGO *cgo = CGONewSized(I->G, I->c + est);
8896
8897 for (auto it = I->begin(); !it.is_stop(); ++it) {
8898 auto pc = it.data();
8899 int op = it.op_code();
8900
8901 switch (op) {
8902 case CGO_DRAW_ARRAYS:
8903 {
8904 const cgo::draw::arrays * sp = reinterpret_cast<decltype(sp)>(pc);
8905 float *vals = cgo->add<cgo::draw::arrays>(sp->mode, sp->arraybits, sp->nverts);
8906 int nvals = sp->narrays*sp->nverts;
8907 memcpy(vals, sp->floatdata, nvals);
8908 }
8909 break;
8910 case CGO_END:
8911 PRINTFB(I->G, FB_CGO, FB_Warnings) " CGOConvertLinesToShaderCylinders: CGO_END encountered without CGO_BEGIN but skipped for OpenGLES\n" ENDFB(I->G);
8912 break;
8913 case CGO_VERTEX:
8914 PRINTFB(I->G, FB_CGO, FB_Warnings) " CGOConvertLinesToShaderCylinders: CGO_VERTEX encountered without CGO_BEGIN but skipped for OpenGLES\n" ENDFB(I->G);
8915 break;
8916 case CGO_BEGIN:
8917 {
8918 const float *last_vertex = NULL, *last_color = NULL, *current_color = NULL, *color = NULL ;
8919 unsigned int last_pick_color_idx = 0;
8920 int last_pick_color_bnd = cPickableNoPick ;
8921 int nverts = 0, err = 0;
8922 int mode = CGO_get_int(pc);
8923
8924 for (++it; !err && it != CGO_END; ++it) {
8925 auto pc = it.data();
8926 int op = it.op_code();
8927
8928 switch (op) {
8929 case CGO_VERTEX:
8930 if (last_vertex){
8931 switch (mode){
8932 case GL_LINES:
8933 case GL_LINE_STRIP:
8934 {
8935 float axis[3];
8936 bool pick_color_diff = false;
8937 axis[0] = pc[0] - last_vertex[0];
8938 axis[1] = pc[1] - last_vertex[1];
8939 axis[2] = pc[2] - last_vertex[2];
8940 pick_color_diff = (cgo->current_pick_color_index != last_pick_color_idx ||
8941 cgo->current_pick_color_bond != last_pick_color_bnd);
8942 if (last_color && current_color &&
8943 (!equal3f(last_color, current_color) || pick_color_diff)){
8944 CGOColorv(cgo, last_color);
8945 if (pick_color_diff){
8946 Pickable pickcolor2 = { cgo->current_pick_color_index, cgo->current_pick_color_bond };
8947 CGOPickColor(cgo, last_pick_color_idx, last_pick_color_bnd);
8948 cgo->add<cgo::draw::shadercylinder2ndcolor>(cgo, last_vertex, axis, 1.f, cCylShaderBothCapsRound, current_color, &pickcolor2);
8949 CGOPickColor(cgo, pickcolor2.index, pickcolor2.bond);
8950 } else {
8951 cgo->add<cgo::draw::shadercylinder2ndcolor>(cgo, last_vertex, axis, 1.f, cCylShaderBothCapsRound, current_color);
8952 }
8953 CGOColorv(cgo, current_color);
8954 } else {
8955 cgo->add<cgo::draw::shadercylinder>(last_vertex, axis, 1.f, cCylShaderBothCapsRound);
8956 }
8957 last_vertex = pc;
8958 last_pick_color_idx = cgo->current_pick_color_index;
8959 last_pick_color_bnd = cgo->current_pick_color_bond;
8960 tot_ncyls++;
8961 }
8962 if (mode==GL_LINES){
8963 last_vertex = NULL;
8964 last_color = NULL;
8965 }
8966 }
8967 } else {
8968 last_vertex = pc;
8969 current_color = color;
8970 last_pick_color_idx = cgo->current_pick_color_index;
8971 last_pick_color_bnd = cgo->current_pick_color_bond;
8972 }
8973 nverts++;
8974 break;
8975 case CGO_LINE:
8976 {
8977 float axis[3];
8978 auto line = reinterpret_cast<const cgo::draw::line *>(pc);
8979 subtract3f(line->vertex2, line->vertex1, axis);
8980 cgo->add<cgo::draw::shadercylinder>(line->vertex1, axis, 1.f, cCylShaderBothCapsRound);
8981 tot_ncyls++;
8982 }
8983 break;
8984 case CGO_SPLITLINE:
8985 {
8986 float axis[3];
8987 auto splitline = reinterpret_cast<const cgo::draw::splitline *>(pc);
8988 Pickable pickcolor2 = { splitline->index, splitline->bond };
8989 float color2[] = { CONVERT_COLOR_VALUE(splitline->color2[0]),
8990 CONVERT_COLOR_VALUE(splitline->color2[1]),
8991 CONVERT_COLOR_VALUE(splitline->color2[2]) };
8992 unsigned char flags = splitline->flags;
8993 subtract3f(splitline->vertex2, splitline->vertex1, axis);
8994 if ((flags & cgo::draw::splitline::equal_colors) &&
8995 (flags & cgo::draw::splitline::no_split_for_pick)){
8996 cgo->add<cgo::draw::shadercylinder>(splitline->vertex1, axis, 1., cCylShaderBothCapsRound);
8997 } else {
8998 int cap = cCylShaderBothCapsRound;
8999 if (flags & splitline->flags & cgo::draw::splitline::interpolation){
9000 cap |= cCylShaderInterpColor;
9001 }
9002 cgo->add<cgo::draw::shadercylinder2ndcolor>(cgo, splitline->vertex1, axis, 1., cap, color2, &pickcolor2);
9003 last_pick_color_idx = splitline->index;
9004 last_pick_color_bnd = splitline->bond;
9005 }
9006 tot_ncyls++;
9007 }
9008 break;
9009 case CGO_COLOR:
9010 if (op == CGO_COLOR){
9011 last_color = current_color;
9012 current_color = pc;
9013 color = pc;
9014 }
9015 case CGO_PICK_COLOR:
9016 if (op == CGO_PICK_COLOR){
9017 cgo->current_pick_color_index = CGO_get_uint(pc);
9018 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
9019 }
9020 default:
9021 cgo->add_to_cgo(op, pc);
9022 }
9023 }
9024
9025 tot_nverts += nverts;
9026 }
9027 break;
9028 default:
9029 cgo->add_to_cgo(op, pc);
9030 }
9031 }
9032 CGOStop(cgo);
9033 cgo->use_shader = I->use_shader;
9034 if (cgo->use_shader){
9035 cgo->cgo_shader_ub_color = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_color);
9036 cgo->cgo_shader_ub_normal = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_normal);
9037 }
9038 if (tot_ncyls){
9039 return (cgo);
9040 } else {
9041 CGOFree(cgo);
9042 return NULL;
9043 }
9044 }
9045 /* CGOSplitUpLinesForPicking: This operation goes through */
9046 /* a CGO and returns a new CGO that has the same lines but */
9047 /* a line that has two different pick colors will get split */
9048 /* at its midpoint into two separate lines so that it can */
9049 /* be used for picking */
CGOSplitUpLinesForPicking(const CGO * I)9050 CGO *CGOSplitUpLinesForPicking(const CGO * I){
9051 auto G = I->G;
9052
9053 std::unique_ptr<CGO> cgo_managed(new CGO(G));
9054 CGO* cgo = cgo_managed.get();
9055 int tot_nverts = 0;
9056
9057 CGOBegin(cgo, GL_LINES);
9058
9059 for (auto it = I->begin(); !it.is_stop(); ++it) {
9060 const auto op = it.op_code();
9061 const auto pc = it.data();
9062
9063 switch (op) {
9064 case CGO_PICK_COLOR:
9065 {
9066 cgo->current_pick_color_index = CGO_get_uint(pc);
9067 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
9068 }
9069 break;
9070 case CGO_END:
9071 case CGO_VERTEX:
9072 WARN_UNEXPECTED_OPERATION(G, op);
9073 return nullptr;
9074 case CGO_BEGIN:
9075 {
9076 const float *last_vertex = nullptr, *last_color = nullptr,
9077 *current_color = nullptr, *color = nullptr;
9078 unsigned int last_pick_color_idx = 0;
9079 int last_pick_color_bnd = cPickableNoPick ;
9080 int nverts = 0;
9081 const int mode = it.cast<cgo::draw::begin>()->mode;
9082
9083 for (++it;; ++it) {
9084 if (it.is_stop()) {
9085 WARN_UNEXPECTED_OPERATION(G, CGO_STOP);
9086 return nullptr;
9087 }
9088
9089 const auto op = it.op_code();
9090 if (op == CGO_END) {
9091 break;
9092 }
9093
9094 const auto pc = it.data();
9095
9096 switch (op) {
9097 case CGO_VERTEX:
9098 if (last_vertex){
9099 switch (mode){
9100 case GL_LINES:
9101 case GL_LINE_STRIP:
9102 {
9103 bool pick_color_diff = false;
9104 pick_color_diff = (cgo->current_pick_color_index != last_pick_color_idx ||
9105 cgo->current_pick_color_bond != last_pick_color_bnd);
9106 if (pick_color_diff ||
9107 (last_color && current_color &&
9108 (!equal3f(last_color, current_color)))){
9109 if (pick_color_diff){
9110 float haxis[3];
9111 float mid[3];
9112 uint curp_idx = cgo->current_pick_color_index;
9113 int curp_bnd = cgo->current_pick_color_bond;
9114 haxis[0] = .5f * (pc[0] - last_vertex[0]);
9115 haxis[1] = .5f * (pc[1] - last_vertex[1]);
9116 haxis[2] = .5f * (pc[2] - last_vertex[2]);
9117 add3f(last_vertex, haxis, mid);
9118 CGOPickColor(cgo, last_pick_color_idx, last_pick_color_bnd);
9119 CGOVertexv(cgo, last_vertex);
9120 CGOVertexv(cgo, mid);
9121 CGOPickColor(cgo, curp_idx, curp_bnd);
9122 CGOVertexv(cgo, mid);
9123 CGOVertexv(cgo, pc);
9124 } else {
9125 CGOVertexv(cgo, last_vertex);
9126 CGOVertexv(cgo, pc);
9127 }
9128 } else {
9129 CGOVertexv(cgo, last_vertex);
9130 CGOVertexv(cgo, pc);
9131 }
9132 last_vertex = pc;
9133 last_pick_color_idx = cgo->current_pick_color_index;
9134 last_pick_color_bnd = cgo->current_pick_color_bond;
9135 }
9136 if (mode==GL_LINES){
9137 last_vertex = NULL;
9138 last_color = NULL;
9139 }
9140 }
9141 } else {
9142 last_vertex = pc;
9143 current_color = color;
9144 last_pick_color_idx = cgo->current_pick_color_index;
9145 last_pick_color_bnd = cgo->current_pick_color_bond;
9146 }
9147 nverts++;
9148 break;
9149 case CGO_COLOR:
9150 {
9151 last_color = current_color;
9152 current_color = pc;
9153 color = pc;
9154 }
9155 break;
9156 case CGO_PICK_COLOR:
9157 {
9158 cgo->current_pick_color_index = CGO_get_uint(pc);
9159 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
9160 }
9161 break;
9162 }
9163 }
9164 tot_nverts += nverts;
9165 }
9166 break;
9167 }
9168 }
9169
9170 if (!tot_nverts) {
9171 return nullptr;
9172 }
9173
9174 CGOEnd(cgo);
9175 CGOStop(cgo);
9176 cgo->use_shader = I->use_shader;
9177 if (cgo->use_shader){
9178 cgo->cgo_shader_ub_color = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_color);
9179 cgo->cgo_shader_ub_normal = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_normal);
9180 }
9181
9182 return cgo_managed.release();
9183 }
9184
trilinesBufferAddVertex(float * & buffer,const float * v1,const float * v2,const float * color,float alpha,signed char uv)9185 static void trilinesBufferAddVertex(float * &buffer,
9186 const float * v1, // vertex
9187 const float * v2, // vertex other end of line
9188 const float * color, // RGB color
9189 float alpha, // alpha
9190 signed char uv) // uv
9191 {
9192 // vertex
9193 (*buffer++) = v1[0];
9194 (*buffer++) = v1[1];
9195 (*buffer++) = v1[2];
9196
9197 // othervertex
9198 (*buffer++) = v2[0];
9199 (*buffer++) = v2[1];
9200 (*buffer++) = v2[2];
9201
9202 (*buffer++) = (float) uv;
9203
9204 // RGBA
9205 unsigned char *byte_view = (unsigned char *)(buffer++);
9206 (*byte_view++) = CLIP_COLOR_VALUE(color[0]);
9207 (*byte_view++) = CLIP_COLOR_VALUE(color[1]);
9208 (*byte_view++) = CLIP_COLOR_VALUE(color[2]);
9209 (*byte_view++) = CLIP_COLOR_VALUE(alpha);
9210 }
9211
trilinesBufferAddVertices(float * & buffer,const float * v1,const float * v2,const float * color,float alpha)9212 static void trilinesBufferAddVertices(float * &buffer,
9213 const float * v1, // vertex
9214 const float * v2, // vertex other end of line
9215 const float * color, // RGB color
9216 float alpha) // alpha
9217 {
9218 // Vertex 1
9219 trilinesBufferAddVertex(buffer, v1, v2, color, alpha, 1); //-1, 1);
9220 // Vertex 3
9221 trilinesBufferAddVertex(buffer, v1, v2, color, alpha, 3); //1, 1);
9222 // Vertex 2
9223 trilinesBufferAddVertex(buffer, v1, v2, color, alpha, 0); //-1, -1);
9224 // Vertex 4
9225 trilinesBufferAddVertex(buffer, v1, v2, color, alpha, 3); //1, 1);
9226 // Vertex 3
9227 trilinesBufferAddVertex(buffer, v1, v2, color, alpha, 2); //1, -1);
9228 // Vertex 1
9229 trilinesBufferAddVertex(buffer, v1, v2, color, alpha, 1); //-1, 1);
9230 }
9231
9232 static
CGOTrilines_GetCurrentColor(const float * & current_color,const float * colorv,const float * last_color,const float * cc)9233 void CGOTrilines_GetCurrentColor(const float*& current_color,
9234 const float* colorv, const float* last_color, const float* cc)
9235 {
9236 if (!current_color) {
9237 if (colorv) {
9238 current_color = colorv;
9239 } else if (last_color) {
9240 current_color = last_color;
9241 } else {
9242 current_color = cc;
9243 }
9244 }
9245 }
9246
9247 /**
9248 * Changes
9249 * CGO_ENABLE <frommode>
9250 * to
9251 * CGO_ENABLE <tomode>
9252 * in place.
9253 */
CGOChangeShadersTo(CGO * I,int frommode,int tomode)9254 void CGOChangeShadersTo(CGO *I, int frommode, int tomode){
9255 for (auto it = I->begin(); !it.is_stop(); ++it) {
9256 if (it.op_code() == CGO_ENABLE) {
9257 auto eo = it.cast<cgo::draw::enable>();
9258 if (eo->mode == frommode) {
9259 eo->mode = tomode;
9260 }
9261 }
9262 }
9263 }
9264
CGOOptimizeScreenTexturesAndPolygons(CGO * I,int est)9265 CGO *CGOOptimizeScreenTexturesAndPolygons(CGO * I, int est)
9266 {
9267 auto G = I->G;
9268 int ok = true;
9269
9270 int num_total_indices = CGOCountNumVerticesForScreen(I);
9271 if (num_total_indices <= 0)
9272 return nullptr;
9273
9274 std::unique_ptr<CGO> cgo_managed(new CGO(G));
9275 auto* const cgo = cgo_managed.get();
9276
9277 {
9278 float *colorVals = 0, *texcoordVals;
9279 int tot, nxtn;
9280 uchar *colorValsUC = 0;
9281 CGOAlpha(cgo, 1.f);
9282 cgo->alpha = 1.f;
9283 cgo->color[0] = 1.f; cgo->color[1] = 1.f; cgo->color[2] = 1.f;
9284
9285 {
9286 int mul = 6; // 3 - screenoffset/vertex, 2 - texture coordinates, 1 - color
9287 /*
9288 if (SettingGetGlobal_i(I->G, cSetting_cgo_shader_ub_color)){
9289 mul++;
9290 } else {
9291 mul += 4;
9292 }*/
9293 tot = num_total_indices * mul ;
9294 }
9295
9296 auto vertexVals_managed = std::vector<float>(tot);
9297 float* vertexVals = vertexVals_managed.data();
9298 texcoordVals = vertexVals + 3 * num_total_indices;
9299 nxtn = 2;
9300 colorVals = texcoordVals + nxtn * num_total_indices;
9301 colorValsUC = (uchar*) colorVals;
9302 nxtn = 1;
9303 ok = CGOProcessScreenCGOtoArrays(G, I, vertexVals, texcoordVals, colorVals, colorValsUC);
9304 RETURN_VAL_IF_FAIL(ok && !G->Interrupt, nullptr);
9305 if (ok){
9306 VertexBuffer * vbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>();
9307 ok = vbo->bufferData({
9308 BufferDesc( "attr_screenoffset", GL_FLOAT, 3, sizeof(float) * num_total_indices * 3, vertexVals, GL_FALSE ),
9309 BufferDesc( "attr_texcoords", GL_FLOAT, 2, sizeof(float) * num_total_indices * 2, texcoordVals, GL_FALSE ),
9310 BufferDesc( "attr_backgroundcolor", GL_UNSIGNED_BYTE, 4, sizeof(uchar) * num_total_indices * 4, colorValsUC, GL_TRUE )
9311 });
9312 size_t vboid = vbo->get_hash_id();
9313 if (ok){
9314 CGOEnable(cgo, GL_SCREEN_SHADER);
9315 cgo->add<cgo::draw::screen_textures>(num_total_indices, vboid);
9316 if (ok)
9317 ok &= CGODisable(cgo, GL_SCREEN_SHADER);
9318 RETURN_VAL_IF_FAIL(ok, nullptr);
9319 } else {
9320 I->G->ShaderMgr->freeGPUBuffer(vboid);
9321 }
9322 }
9323 cgo->use_shader = true;
9324 }
9325
9326 return cgo_managed.release();
9327 }
9328
CGOColorByRamp(PyMOLGlobals * G,const CGO * I,ObjectGadgetRamp * ramp,int state,CSetting * set1)9329 CGO* CGOColorByRamp(PyMOLGlobals* G, const CGO* I, ObjectGadgetRamp* ramp,
9330 int state, CSetting* set1)
9331 {
9332 if (!I) {
9333 return nullptr;
9334 }
9335
9336 auto cgo = CGONewSized(G, 0);
9337 if (!cgo) {
9338 return nullptr;
9339 }
9340
9341 int ok = true;
9342 float white[3] = { 1.f, 1.f, 1.f};
9343 float probe_radius = SettingGet_f(G, set1, NULL, cSetting_solvent_radius);
9344 float v_above[3], n0[3] = { 0.f, 0.f, 0.f };
9345 int ramp_above = SettingGet_i(G, set1, NULL, cSetting_surface_ramp_above_mode) == 1;
9346
9347 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
9348 const auto op = it.op_code();
9349 const auto pc = it.data();
9350
9351 bool skipCopy = false;
9352 switch (op) {
9353 case CGO_DRAW_ARRAYS:
9354 {
9355 const cgo::draw::arrays * sp = reinterpret_cast<decltype(sp)>(pc);
9356 float *vals = cgo->add<cgo::draw::arrays>(sp->mode, sp->arraybits, sp->nverts);
9357 int nvals = sp->narrays*sp->nverts;
9358 ok &= vals ? true : false;
9359 if (ok)
9360 memcpy(vals, sp->floatdata, nvals);
9361 skipCopy = true;
9362 }
9363 break;
9364 case CGO_NORMAL:
9365 copy3f(pc, n0);
9366 break;
9367 case CGO_VERTEX:
9368 {
9369 float color[3];
9370 copy3f(white, color);
9371 if (ramp_above){
9372 copy3f(n0, v_above);
9373 scale3f(v_above, probe_radius, v_above);
9374 add3f(pc, v_above, v_above);
9375 } else {
9376 copy3f(pc, v_above);
9377 }
9378 if (ObjectGadgetRampInterVertex(ramp, v_above, color, state)){
9379 CGOColorv(cgo, color);
9380 } else {
9381 CGOColorv(cgo, white);
9382 }
9383 }
9384 break;
9385 }
9386 if (!skipCopy){
9387 cgo->add_to_cgo(op, pc);
9388 }
9389 }
9390 if (ok){
9391 ok &= CGOStop(cgo);
9392 if (ok){
9393 cgo->use_shader = I->use_shader;
9394 if (cgo->use_shader){
9395 cgo->cgo_shader_ub_color = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_color);
9396 cgo->cgo_shader_ub_normal = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_normal);
9397 }
9398 }
9399 }
9400 if (!ok){
9401 CGOFree(cgo);
9402 }
9403 return (cgo);
9404 }
9405
9406 /**
9407 * FIXME: This function always returns true for `checkOpaque=ture`
9408 */
CGOHasTransparency(const CGO * I,bool checkTransp,bool checkOpaque)9409 int CGOHasTransparency(const CGO *I, bool checkTransp, bool checkOpaque){
9410 for (auto it = I->begin(); !it.is_stop(); ++it) {
9411 if (it.op_code() == CGO_ALPHA) {
9412 const auto pc = it.data();
9413 if (checkTransp && *pc < 1.f)
9414 return 1;
9415 if (checkOpaque && *pc == 1.f)
9416 return 1;
9417 }
9418 }
9419
9420 return checkOpaque;
9421 }
9422
9423 /* TransparentInfoSortIX - This function sorts all n_tri triangle
9424 * centroids in the array sum by:
9425 * 1) computing z-value in array z_value
9426 * 2) bin sorting z_values and placing indices in ix array (using Util.cpp)
9427 *
9428 * - uses sort_mem as pre-allocated memory to sort
9429 * - t_mode - either forward (1) or backwards (0) sort
9430 */
TransparentInfoSortIX(PyMOLGlobals * G,float * sum,float * z_value,int * ix,int n_tri,int * sort_mem,int t_mode)9431 void TransparentInfoSortIX(PyMOLGlobals * G,
9432 float *sum, float *z_value, int *ix,
9433 int n_tri, int *sort_mem, int t_mode){
9434 float *zv;
9435 float *sv;
9436 float matrix[16];
9437 int idx;
9438
9439 #ifdef PURE_OPENGL_ES_2
9440 copy44f(SceneGetModelViewMatrix(G), matrix);
9441 #else
9442 glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
9443 #endif
9444 zv = z_value;
9445 sv = sum;
9446
9447 /* for each triangle, computes the z */
9448 for (idx = 0; idx<n_tri; ++idx){
9449 *(zv++) = matrix[2] * sv[0] + matrix[6] * sv[1] + matrix[10] * sv[2];
9450 sv += 3;
9451 }
9452
9453 UtilZeroMem(sort_mem, sizeof(int) * (n_tri + 256));
9454
9455 switch (t_mode) {
9456 case 1:
9457 UtilSemiSortFloatIndexWithNBinsImpl(sort_mem, n_tri, 256, z_value, ix, true); // front to back
9458 /* UtilSortIndex(n_tri,z_value,ix,(UtilOrderFn*)ZOrderFn); */
9459 break;
9460 default:
9461 UtilSemiSortFloatIndexWithNBinsImpl(sort_mem, n_tri, 256, z_value, ix, false); // back to front
9462 /* UtilSortIndex(n_tri,z_value,ix,(UtilOrderFn*)ZRevOrderFn); */
9463 break;
9464 }
9465 }
9466
CGOConvertTrianglesToAlpha(const CGO * I)9467 CGO *CGOConvertTrianglesToAlpha(const CGO * I){
9468 int tot_nverts = 0;
9469
9470 CGO *cgo = CGONewSized(I->G, I->c);
9471
9472 for (auto it = I->begin(); !it.is_stop(); ++it) {
9473 auto pc = it.data();
9474 int op = it.op_code();
9475
9476 switch (op) {
9477 case CGO_DRAW_ARRAYS:
9478 {
9479 const cgo::draw::arrays * sp = reinterpret_cast<decltype(sp)>(pc);
9480 int mode = sp->mode, arrays = sp->arraybits, nverts = sp->nverts;
9481 int nxtn = 3;
9482 float *vertexValsDA = 0, *nxtVals = 0, *colorValsDA = 0, *normalValsDA = 0;
9483 float *vertexVals0, *normalVals0, *colorVals0;
9484
9485 nxtVals = vertexValsDA = sp->floatdata;
9486 if (arrays & CGO_NORMAL_ARRAY){
9487 nxtVals = normalValsDA = vertexValsDA + (nxtn*nverts);
9488 }
9489 if (arrays & CGO_COLOR_ARRAY){
9490 nxtVals = colorValsDA = nxtVals + (nxtn*nverts);
9491 nxtn = 4;
9492 }
9493 if (arrays & CGO_PICK_COLOR_ARRAY){
9494 nxtVals = nxtVals + (nxtn*nverts);
9495 nxtn = 3;
9496 }
9497 vertexVals0 = vertexValsDA;
9498 normalVals0 = normalValsDA;
9499 colorVals0 = colorValsDA;
9500 switch (mode){
9501 case GL_TRIANGLES:
9502 {
9503 for (int cnt = 0; cnt < nverts; cnt+=3){
9504 if (colorVals0){
9505 CGOAlphaTriangle(cgo, vertexValsDA, vertexValsDA+3, vertexValsDA+6,
9506 normalValsDA, normalValsDA+3, normalValsDA+6,
9507 colorValsDA, colorValsDA+4, colorValsDA+8,
9508 *(colorValsDA + 3), *(colorValsDA + 7), *(colorValsDA + 11), 0);
9509 } else {
9510 CGOAlphaTriangle(cgo, vertexValsDA, vertexValsDA+3, vertexValsDA+6,
9511 normalValsDA, normalValsDA+3, normalValsDA+6,
9512 cgo->color, cgo->color, cgo->color,
9513 cgo->alpha, cgo->alpha, cgo->alpha, 0);
9514 }
9515 vertexValsDA += 9;
9516 normalValsDA += 9;
9517 if (colorVals0)
9518 colorValsDA += 12;
9519 }
9520 }
9521 tot_nverts += nverts;
9522 break;
9523 case GL_TRIANGLE_STRIP:
9524 {
9525 short flip = 0;
9526 vertexValsDA += 6;
9527 normalValsDA += 6;
9528 if (colorVals0)
9529 colorValsDA += 8;
9530
9531 for (int cnt = 2; cnt < nverts; cnt++){
9532 if (colorVals0){
9533 CGOAlphaTriangle(cgo, vertexValsDA-6, vertexValsDA-3, vertexValsDA,
9534 normalValsDA-6, normalValsDA-3, normalValsDA,
9535 colorValsDA-8, colorValsDA-4, colorValsDA,
9536 *(colorValsDA - 5), *(colorValsDA - 1), *(colorValsDA + 3), flip);
9537 } else {
9538 CGOAlphaTriangle(cgo, vertexValsDA-6, vertexValsDA-3, vertexValsDA,
9539 normalValsDA-6, normalValsDA-3, normalValsDA,
9540 cgo->color, cgo->color, cgo->color,
9541 cgo->alpha, cgo->alpha, cgo->alpha, flip);
9542 }
9543 vertexValsDA += 3;
9544 normalValsDA += 3;
9545 if (colorVals0)
9546 colorValsDA += 4;
9547 flip = !flip;
9548 }
9549 }
9550 tot_nverts += nverts;
9551 break;
9552 case GL_TRIANGLE_FAN:
9553 {
9554 vertexValsDA += 6;
9555 normalValsDA += 6;
9556 if (colorVals0)
9557 colorValsDA += 8;
9558 for (int cnt = 2; cnt < nverts; cnt++){
9559 if (colorVals0){
9560 CGOAlphaTriangle(cgo, vertexVals0, vertexValsDA-3, vertexValsDA,
9561 normalVals0, normalValsDA-3, normalValsDA,
9562 colorVals0, colorValsDA-4, colorValsDA,
9563 *(colorVals0 + 3), *(colorValsDA - 1), *(colorValsDA + 3), 0);
9564 } else {
9565 CGOAlphaTriangle(cgo, vertexVals0, vertexValsDA-3, vertexValsDA,
9566 normalVals0, normalValsDA-3, normalValsDA,
9567 cgo->color, cgo->color, cgo->color,
9568 cgo->alpha, cgo->alpha, cgo->alpha, 0);
9569 }
9570 vertexValsDA += 3;
9571 normalValsDA += 3;
9572 if (colorVals0)
9573 colorValsDA += 4;
9574 }
9575 }
9576 tot_nverts += nverts;
9577 break;
9578 }
9579 }
9580 break;
9581 case CGO_END:
9582 PRINTFB(I->G, FB_CGO, FB_Warnings) " CGOConvertTrianglesToAlpha: CGO_END encountered without CGO_BEGIN but skipped for OpenGLES\n" ENDFB(I->G);
9583 break;
9584 case CGO_VERTEX:
9585 PRINTFB(I->G, FB_CGO, FB_Warnings) " CGOConvertTrianglesToAlpha: CGO_VERTEX encountered without CGO_BEGIN but skipped for OpenGLES\n" ENDFB(I->G);
9586 break;
9587 case CGO_BEGIN:
9588 {
9589 float vertices[3][3], colors[4][3], normals[4][3], alpha[4] ;
9590 short verticespl = 2, colorspl = 2, normalspl = 2, alphapl = 2;
9591 short hasShifted = 0;
9592 int nverts = 0, err = 0;
9593 int mode = CGO_get_int(pc);
9594 short mode_is_triangles = 0, flip = 0, mode_is_fan = 0;
9595 copy3f(cgo->color, colors[3]);
9596 copy3f(cgo->normal, normals[3]);
9597 alpha[3] = cgo->alpha;
9598 switch (mode){
9599 case GL_TRIANGLE_FAN:
9600 mode_is_fan = 1;
9601 case GL_TRIANGLES:
9602 case GL_TRIANGLE_STRIP:
9603 mode_is_triangles = 1;
9604 }
9605 if (!mode_is_triangles){
9606 CGOBegin(cgo, mode);
9607 }
9608
9609 for (++it; !err && it != CGO_END; ++it) {
9610 auto pc = it.data();
9611 int op = it.op_code();
9612 short add_to_cgo = 1;
9613 switch (op) {
9614 case CGO_VERTEX:
9615 if (mode_is_triangles){
9616 if (!(hasShifted & 1)){ // colors
9617 if (colorspl>=0){
9618 copy3f(colors[colorspl+1], colors[colorspl]);
9619 colorspl--;
9620 } else {
9621 if (!mode_is_fan)
9622 copy3f(colors[1], colors[2]);
9623 copy3f(colors[0], colors[1]);
9624 }
9625 }
9626 if (!(hasShifted & 2)){ // normals
9627 if (normalspl>=0){
9628 copy3f(normals[normalspl+1], normals[normalspl]);
9629 normalspl--;
9630 } else {
9631 if (!mode_is_fan)
9632 copy3f(normals[1], normals[2]);
9633 copy3f(normals[0], normals[1]);
9634 }
9635 }
9636 if (!(hasShifted & 4)){ // alphas
9637 if (alphapl>=0){
9638 alpha[alphapl] = alpha[alphapl+1];
9639 alphapl--;
9640 } else {
9641 if (!mode_is_fan)
9642 alpha[2] = alpha[1];
9643 alpha[1] = alpha[0];
9644 }
9645 }
9646 if (verticespl>=0){
9647 copy3f(pc, vertices[verticespl]) ;
9648 verticespl--;
9649 } else {
9650 if (!mode_is_fan)
9651 copy3f(vertices[1], vertices[2]);
9652 copy3f(vertices[0], vertices[1]);
9653 copy3f(pc, vertices[0]);
9654 }
9655
9656 nverts++;
9657 switch (mode){
9658 case GL_TRIANGLES:
9659 if (!(nverts % 3)){
9660 CGOAlphaTriangle(cgo, vertices[2], vertices[1], vertices[0],
9661 normals[2], normals[1], normals[0],
9662 colors[2], colors[1], colors[0],
9663 alpha[2], alpha[1], alpha[0], 0);
9664 }
9665 break;
9666 case GL_TRIANGLE_STRIP:
9667 if (verticespl<0){
9668 int off0, off2;
9669 if (flip){ off0 = 0; off2 = 2; } else { off0 = 2; off2 = 0; }
9670 flip = !flip;
9671 CGOAlphaTriangle(cgo, vertices[off0], vertices[1], vertices[off2],
9672 normals[off0], normals[1], normals[off2],
9673 colors[off0], colors[1], colors[off2],
9674 alpha[off0], alpha[1], alpha[off2], 0);
9675 }
9676 break;
9677 case GL_TRIANGLE_FAN:
9678 if (verticespl<0){
9679 CGOAlphaTriangle(cgo, vertices[2], vertices[1], vertices[0],
9680 normals[2], normals[1], normals[0],
9681 colors[2], colors[1], colors[0],
9682 alpha[2], alpha[1], alpha[0], 0);
9683 }
9684 }
9685 add_to_cgo = !mode_is_triangles;
9686 hasShifted = 0;
9687 } else {
9688 add_to_cgo = 1;
9689 }
9690 case CGO_COLOR:
9691 if (op == CGO_COLOR){
9692 add_to_cgo = !mode_is_triangles;
9693 if (mode_is_triangles){
9694 if (colorspl>=0){
9695 copy3f(pc, colors[colorspl]);
9696 colorspl--;
9697 } else {
9698 if (!mode_is_fan)
9699 copy3f(colors[1], colors[2]);
9700 copy3f(colors[0], colors[1]);
9701 copy3f(pc, colors[0]);
9702
9703 }
9704 hasShifted |= 1;
9705 }
9706 }
9707 case CGO_NORMAL:
9708 if (op == CGO_NORMAL){
9709 add_to_cgo = !mode_is_triangles;
9710 if (mode_is_triangles){
9711 if (normalspl>=0){
9712 copy3f(pc, normals[normalspl]);
9713 normalspl--;
9714 } else {
9715 if (!mode_is_fan)
9716 copy3f(normals[1], normals[2]);
9717 copy3f(normals[0], normals[1]);
9718 copy3f(pc, normals[0]);
9719 }
9720 hasShifted |= 2;
9721 }
9722 }
9723 case CGO_ALPHA:
9724 if (op == CGO_ALPHA){
9725 add_to_cgo = !mode_is_triangles;
9726 if (mode_is_triangles){
9727 if (alphapl>=0)
9728 alpha[alphapl--] = *pc;
9729 else {
9730 if (!mode_is_fan)
9731 alpha[2] = alpha[1];
9732 alpha[1] = alpha[0];
9733 alpha[0] = *pc;
9734 }
9735 hasShifted |= 4;
9736 }
9737 }
9738 default:
9739 if (add_to_cgo){
9740 cgo->add_to_cgo(op, pc);
9741 }
9742 }
9743 }
9744
9745 if (!mode_is_triangles) {
9746 CGOEnd(cgo);
9747 }
9748
9749 tot_nverts += nverts;
9750 }
9751 break;
9752 case CGO_COLOR:
9753 if (op==CGO_COLOR){
9754 copy3f(pc, cgo->color);
9755 }
9756 case CGO_NORMAL:
9757 if (op==CGO_NORMAL){
9758 copy3f(pc, cgo->normal);
9759 }
9760 case CGO_ALPHA:
9761 if (op==CGO_ALPHA){
9762 cgo->alpha = *pc;
9763 }
9764 default:
9765 cgo->add_to_cgo(op, pc);
9766 }
9767 }
9768 CGOStop(cgo);
9769 cgo->use_shader = I->use_shader;
9770 if (cgo->use_shader){
9771 cgo->cgo_shader_ub_color = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_color);
9772 cgo->cgo_shader_ub_normal = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_normal);
9773 }
9774 if (tot_nverts){
9775 return (cgo);
9776 } else {
9777 CGOFree(cgo);
9778 return NULL;
9779 }
9780 }
9781
9782 /*
9783 * Converts TRIANGLE(_STRIP|_FAN) to TRIANGLES and generates
9784 * normals for all triangles. Discards any existing normals for
9785 * triangles.
9786 *
9787 * I: primitive CGO
9788 * return: new primitive CGO with normals on triangles
9789 */
CGOGenerateNormalsForTriangles(const CGO * I)9790 CGO *CGOGenerateNormalsForTriangles(const CGO * I){
9791 auto G = I->G;
9792 auto cgo = CGONewSized(G, I->c);
9793
9794 float vertices[3][3];
9795 float current_color[3] = {0.f, 0.f, 0.f}, colors[3][3];
9796 float current_normal[3];
9797 float current_alpha = 0, alphas[3];
9798
9799 bool has_alpha = false;
9800 bool has_color = false;
9801
9802 int mode = 0;
9803 bool inside_begin_triangles = false;
9804 int current_i = 0;
9805 int vertex_count = 0;
9806 bool flip = false;
9807 bool emit;
9808
9809 const int indices_regular[] = {0, 1, 2};
9810 const int indices_flipped[] = {0, 2, 1};
9811
9812 for (auto it = I->begin(); !it.is_stop(); ++it) {
9813 auto pc = it.data();
9814 auto op = it.op_code();
9815
9816 if (op == CGO_BEGIN) {
9817 mode = *reinterpret_cast<const int*>(pc);
9818
9819 switch (mode) {
9820 case GL_TRIANGLE_STRIP:
9821 case GL_TRIANGLE_FAN:
9822 case GL_TRIANGLES:
9823 current_i = 0;
9824 vertex_count = 0;
9825 flip = false;
9826 inside_begin_triangles = true;
9827
9828 CGOBegin(cgo, GL_TRIANGLES);
9829 continue; // for-loop, no add_to_cgo
9830 }
9831
9832 inside_begin_triangles = false;
9833 } else if (op == CGO_END) {
9834 inside_begin_triangles = false;
9835 }
9836
9837 if (!inside_begin_triangles) {
9838 cgo->add_to_cgo(op, pc);
9839 continue;
9840 }
9841
9842 // handle operations inside BEGIN/END TRIANGLE(S|_STRIP|_FAN)
9843 switch (op) {
9844 case CGO_VERTEX:
9845 copy3(reinterpret_cast<const float*>(pc), vertices[current_i]);
9846 copy3(current_color, colors[current_i]);
9847 alphas[current_i] = current_alpha;
9848
9849 ++vertex_count;
9850
9851 switch (mode) {
9852 case GL_TRIANGLE_STRIP:
9853 current_i = vertex_count % 3;
9854 emit = (vertex_count > 2);
9855 break;
9856 case GL_TRIANGLE_FAN:
9857 current_i = ((vertex_count + 1) % 2) + 1;
9858 emit = (vertex_count > 2);
9859 break;
9860 default:
9861 current_i = vertex_count % 3;
9862 emit = (current_i == 0);
9863 }
9864
9865 if (emit) {
9866 auto * indices = flip ? indices_flipped : indices_regular;
9867
9868 if (mode != GL_TRIANGLES) {
9869 flip = !flip;
9870 }
9871
9872 CalculateTriangleNormal(vertices[0],
9873 vertices[indices[1]],
9874 vertices[indices[2]], current_normal);
9875
9876 CGONormalv(cgo, current_normal);
9877
9878 for (int j = 0; j < 3; ++j) {
9879 int k = indices[j];
9880 if (has_color) CGOColorv(cgo, colors[k]);
9881 if (has_alpha) CGOAlpha(cgo, alphas[k]);
9882 CGOVertexv(cgo, vertices[k]);
9883 }
9884 }
9885
9886 break;
9887 case CGO_COLOR:
9888 copy3(reinterpret_cast<const float*>(pc), current_color);
9889 has_color = true;
9890 break;
9891 case CGO_ALPHA:
9892 current_alpha = *reinterpret_cast<const float*>(pc);
9893 has_alpha = true;
9894 break;
9895 case CGO_NORMAL:
9896 // discard, we will generate new normals
9897 break;
9898 default:
9899 PRINTFB(G, FB_CGO, FB_Warnings)
9900 " CGO-Warning: CGOGenerateNormalsForTriangles: unhandled op=0x%02x inside BEGIN/END\n",
9901 op ENDFB(G);
9902 cgo->add_to_cgo(op, pc);
9903 }
9904 }
9905
9906 CGOStop(cgo);
9907 cgo->use_shader = I->use_shader;
9908 if (cgo->use_shader){
9909 cgo->cgo_shader_ub_color = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_color);
9910 cgo->cgo_shader_ub_normal = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_normal);
9911 }
9912 return (cgo);
9913 }
9914
CGOTurnLightingOnLinesOff(const CGO * I,bool use_shader)9915 CGO* CGOTurnLightingOnLinesOff(const CGO* I, bool use_shader)
9916 {
9917 bool cur_mode_is_lines = false;
9918 auto cgo = CGONewSized(I->G, I->c);
9919
9920 for (auto it = I->begin(); !it.is_stop(); ++it) {
9921 const auto op = it.op_code();
9922 const auto pc = it.data();
9923
9924 switch (op) {
9925 case CGO_DRAW_ARRAYS:
9926 {
9927 const cgo::draw::arrays * sp = reinterpret_cast<decltype(sp)>(pc);
9928 float *vals;
9929 int nvals = sp->narrays*sp->nverts;
9930 switch (sp->mode){
9931 case GL_LINES:
9932 case GL_LINE_STRIP:
9933 CGODisable(cgo, CGO_GL_LIGHTING);
9934 cur_mode_is_lines = true;
9935 }
9936 vals = cgo->add<cgo::draw::arrays>(sp->mode, sp->arraybits, sp->nverts);
9937 memcpy(vals, sp->floatdata, nvals);
9938 if (cur_mode_is_lines){
9939 CGOEnable(cgo, CGO_GL_LIGHTING);
9940 cur_mode_is_lines = false;
9941 }
9942 }
9943 break;
9944 case CGO_DRAW_BUFFERS_INDEXED:
9945 {
9946 const cgo::draw::buffers_indexed * sp = reinterpret_cast<decltype(sp)>(pc);
9947 int mode = sp->mode, mode_is_lines = 0;
9948 switch (mode){
9949 case GL_LINES:
9950 case GL_LINE_STRIP:
9951 mode_is_lines = true;
9952 }
9953 if (mode_is_lines){
9954 CGODisable(cgo, CGO_GL_LIGHTING);
9955 }
9956 cgo->copy_op_from<cgo::draw::buffers_indexed>(pc);
9957 if (mode_is_lines){
9958 CGOEnable(cgo, CGO_GL_LIGHTING);
9959 }
9960 }
9961 break;
9962 case CGO_DRAW_BUFFERS_NOT_INDEXED:
9963 {
9964 const cgo::draw::buffers_not_indexed * sp = reinterpret_cast<decltype(sp)>(pc);
9965 int mode = sp->mode, mode_is_lines = 0;
9966 switch (mode){
9967 case GL_LINES:
9968 case GL_LINE_STRIP:
9969 mode_is_lines = true;
9970 }
9971 if (mode_is_lines){
9972 CGODisable(cgo, CGO_GL_LIGHTING);
9973 }
9974 cgo->copy_op_from<cgo::draw::buffers_not_indexed>(pc);
9975 if (mode_is_lines){
9976 CGOEnable(cgo, CGO_GL_LIGHTING);
9977 }
9978 }
9979 case CGO_END:
9980 {
9981 CGOEnd(cgo);
9982 if (cur_mode_is_lines){
9983 CGOEnable(cgo, CGO_GL_LIGHTING);
9984 cur_mode_is_lines = 0;
9985 }
9986 }
9987 break;
9988 case CGO_BEGIN:
9989 {
9990 int mode = CGO_get_int(pc);
9991 switch (mode){
9992 case GL_LINES:
9993 case GL_LINE_STRIP:
9994 CGODisable(cgo, CGO_GL_LIGHTING);
9995 cur_mode_is_lines = true;
9996 break;
9997 default:
9998 if (!use_shader) { // no shaders, not lines, turn lighting on
9999 CGOEnable(cgo, CGO_GL_LIGHTING);
10000 }
10001 }
10002 CGOBegin(cgo, mode);
10003 }
10004 break;
10005 default:
10006 cgo->add_to_cgo(op, pc);
10007 }
10008 }
10009 cgo->use_shader = use_shader;
10010 if (cgo->use_shader){
10011 cgo->cgo_shader_ub_color = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_color);
10012 cgo->cgo_shader_ub_normal = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_normal);
10013 }
10014 return (cgo);
10015 }
10016
CGOHasAnyTriangleVerticesWithoutNormals(const CGO * I,bool checkTriangles)10017 bool CGOHasAnyTriangleVerticesWithoutNormals(const CGO *I, bool checkTriangles){
10018 bool inside = false;
10019 bool hasNormal = false;
10020
10021 for (auto it = I->begin(); !it.is_stop(); ++it) {
10022 const auto op = it.op_code();
10023 const auto pc = it.data();
10024
10025 switch (op) {
10026 case CGO_BEGIN:
10027 switch (CGO_get_int(pc)){
10028 case GL_TRIANGLE_FAN:
10029 case GL_TRIANGLES:
10030 case GL_TRIANGLE_STRIP:
10031 if (checkTriangles)
10032 inside = 1;
10033 break;
10034 case GL_LINE_STRIP:
10035 case GL_LINES:
10036 if (!checkTriangles)
10037 inside = 1;
10038 break;
10039 }
10040 break;
10041 case CGO_END:
10042 inside = 0;
10043 break;
10044 case CGO_NORMAL:
10045 hasNormal = 1;
10046 break;
10047 case CGO_VERTEX:
10048 if (inside && !hasNormal)
10049 return 1;
10050 break;
10051 case CGO_DRAW_ARRAYS:
10052 {
10053 const auto sp = it.cast<cgo::draw::arrays>();
10054 switch (sp->mode){
10055 case GL_TRIANGLE_FAN:
10056 case GL_TRIANGLES:
10057 case GL_TRIANGLE_STRIP:
10058 if (checkTriangles){
10059 if (!(sp->arraybits & CGO_NORMAL_ARRAY)){
10060 return 1;
10061 }
10062 }
10063 break;
10064 case GL_LINE_STRIP:
10065 case GL_LINES:
10066 if (!checkTriangles){
10067 if (!(sp->arraybits & CGO_NORMAL_ARRAY)){
10068 return 1;
10069 }
10070 }
10071 break;
10072 }
10073 }
10074 break;
10075 }
10076 }
10077 return 0;
10078 }
10079
10080 /*
10081 * CGOReorderIndicesWithTransparentInfo : This function
10082 * takes the triangle index array ix (result from TransparentInfoSortIX)
10083 * and sets the vertices (vertexIndices) for each triangle from the original
10084 * indices (vertexIndicesOriginal), then uses glBufferData to set the
10085 * GL_ELEMENT_ARRAY_BUFFER to these indices.
10086 *
10087 */
CGOReorderIndicesWithTransparentInfo(PyMOLGlobals * G,int nindices,size_t vbuf,int n_tri,int * ix,GL_C_INT_TYPE * vertexIndicesOriginal,GL_C_INT_TYPE * vertexIndices)10088 void CGOReorderIndicesWithTransparentInfo(PyMOLGlobals * G,
10089 int nindices, size_t vbuf,
10090 int n_tri, int *ix,
10091 GL_C_INT_TYPE *vertexIndicesOriginal,
10092 GL_C_INT_TYPE *vertexIndices){
10093 int c, pl, idx;
10094 IndexBuffer * ibo = G->ShaderMgr->getGPUBuffer<IndexBuffer>( vbuf );
10095 if (!vertexIndices){
10096 PRINTFB(G, FB_RepSurface, FB_Errors) "ERROR: RepSurfaceRender() vertexIndices is not set, nindices=%d\n", nindices ENDFB(G);
10097 }
10098 /* updates the vertexIndices from the ix array */
10099 for(c = 0, pl=0; c < n_tri; c++) {
10100 idx = ix[c] * 3;
10101 vertexIndices[pl++] = vertexIndicesOriginal[idx];
10102 vertexIndices[pl++] = vertexIndicesOriginal[idx + 1];
10103 vertexIndices[pl++] = vertexIndicesOriginal[idx + 2];
10104 }
10105 ibo->bufferSubData(0, sizeof(GL_C_INT_TYPE) * nindices, vertexIndices);
10106 }
10107
add_to_cgo(int op,const float * pc)10108 void CGO::add_to_cgo(int op, const float * pc) {
10109 switch (op) {
10110 case CGO_STOP:
10111 // only append to buffer, don't increment size
10112 CGOStop(this);
10113 break;
10114 case CGO_DRAW_ARRAYS:
10115 copy_op_from<cgo::draw::arrays>(pc);
10116 break;
10117 case CGO_DRAW_BUFFERS_INDEXED:
10118 copy_op_from<cgo::draw::buffers_indexed>(pc);
10119 break;
10120 case CGO_DRAW_TEXTURES:
10121 copy_op_from<cgo::draw::textures>(pc);
10122 break;
10123 case CGO_DRAW_SCREEN_TEXTURES_AND_POLYGONS:
10124 copy_op_from<cgo::draw::screen_textures>(pc);
10125 break;
10126 case CGO_DRAW_LABELS:
10127 copy_op_from<cgo::draw::labels>(pc);
10128 break;
10129 case CGO_DRAW_CONNECTORS:
10130 copy_op_from<cgo::draw::connectors>(pc);
10131 break;
10132 case CGO_DRAW_BUFFERS_NOT_INDEXED:
10133 copy_op_from<cgo::draw::buffers_not_indexed>(pc);
10134 break;
10135 case CGO_DRAW_SPHERE_BUFFERS:
10136 copy_op_from<cgo::draw::sphere_buffers>(pc);
10137 break;
10138 case CGO_DRAW_CYLINDER_BUFFERS:
10139 copy_op_from<cgo::draw::cylinder_buffers>(pc);
10140 break;
10141 case CGO_DRAW_CUSTOM:
10142 copy_op_from<cgo::draw::custom>(pc);
10143 break;
10144 default:
10145 int sz = CGO_sz[op];
10146 std::copy_n(pc - 1, sz + 1, add_to_buffer(sz + 1));
10147 };
10148 }
10149
print_table() const10150 void CGO::print_table() const {
10151 }
10152
CGOConvertSpheresToPoints(const CGO * I)10153 CGO* CGOConvertSpheresToPoints(const CGO* I)
10154 {
10155 CGO *cgo;
10156
10157 int ok = true;
10158 cgo = CGONew(I->G);
10159 CHECKOK(ok, cgo);
10160 CGOBegin(cgo, GL_POINTS);
10161
10162 for (auto it = I->begin(); ok && !it.is_stop(); ++it) {
10163 const auto pc = it.data();
10164 const auto op = it.op_code();
10165
10166 switch (op) {
10167 case CGO_PICK_COLOR:
10168 cgo->current_pick_color_index = CGO_get_uint(pc);
10169 cgo->current_pick_color_bond = CGO_get_int(pc + 1);
10170 CGOPickColor(cgo, cgo->current_pick_color_index, cgo->current_pick_color_bond);
10171 break;
10172 case CGO_SHADER_CYLINDER:
10173 case CGO_SHADER_CYLINDER_WITH_2ND_COLOR:
10174 case CGO_CYLINDER:
10175 case CGO_CONE:
10176 case CGO_SAUSAGE:
10177 case CGO_CUSTOM_CYLINDER:
10178 case CGO_CUSTOM_CYLINDER_ALPHA:
10179 case CGO_END:
10180 case CGO_VERTEX:
10181 case CGO_BEGIN:
10182 case CGO_ELLIPSOID:
10183 case CGO_QUADRIC:
10184 case CGO_DRAW_BUFFERS_INDEXED:
10185 case CGO_DRAW_BUFFERS_NOT_INDEXED:
10186 case CGO_DRAW_SPHERE_BUFFERS:
10187 case CGO_DRAW_CYLINDER_BUFFERS:
10188 case CGO_DRAW_LABELS:
10189 break;
10190 case CGO_SPHERE:
10191 CGOVertexv(cgo, pc);
10192 break;
10193 case CGO_ALPHA:
10194 cgo->alpha = *pc;
10195 default:
10196 cgo->add_to_cgo(op, pc);
10197 }
10198 ok &= !I->G->Interrupt;
10199 }
10200 CGOEnd(cgo);
10201 if (ok){
10202 ok &= CGOStop(cgo);
10203 }
10204 if (!ok){
10205 CGOFree(cgo);
10206 }
10207 return (cgo);
10208 }
10209
10210 #ifdef _PYMOL_ARB_SHADERS
CGORenderSpheresARB(RenderInfo * info,const CGO * I,const float * fog_info)10211 void CGORenderSpheresARB(RenderInfo* info, const CGO* I, const float* fog_info)
10212 {
10213 static const float _00[2] = { 0.0F, 0.0F };
10214 static const float _01[2] = { 0.0F, 1.0F };
10215 static const float _11[2] = { 1.0F, 1.0F };
10216 static const float _10[2] = { 1.0F, 0.0F };
10217 if(I->c) {
10218 float last_radius;
10219 last_radius = -1.f;
10220 glNormal3fv(info->view_normal);
10221 glBegin(GL_QUADS);
10222
10223 for (auto it = I->begin(); !it.is_stop(); ++it) {
10224 const auto pc = it.data();
10225 const auto op = it.op_code();
10226
10227 switch (op) {
10228 case CGO_SPHERE:
10229 {
10230 float sphereCenter[] = { *(pc), *(pc+1), *(pc+2) };
10231 float sphereRadius = *(pc+3);
10232 if(last_radius != sphereRadius) {
10233 glEnd();
10234 glProgramEnvParameter4fARB(GL_VERTEX_PROGRAM_ARB,
10235 0, 0.0F, 0.0F, sphereRadius, 0.0F);
10236 glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB,
10237 0, fog_info[0], fog_info[1], 0.0F, 0.0F);
10238 glBegin(GL_QUADS);
10239 last_radius = sphereRadius;
10240 }
10241 glTexCoord2fv(_00);
10242 glVertex3fv(sphereCenter);
10243 glTexCoord2fv(_10);
10244 glVertex3fv(sphereCenter);
10245 glTexCoord2fv(_11);
10246 glVertex3fv(sphereCenter);
10247 glTexCoord2fv(_01);
10248 glVertex3fv(sphereCenter);
10249 }
10250 break;
10251 case CGO_COLOR:
10252 glColor3f(*pc, *(pc + 1), *(pc + 2));
10253 break;
10254 }
10255 }
10256 glEnd();
10257 }
10258 }
10259 #endif
10260
10261 // Will create an interleaved VBO with { vertex, otherVertex, uv, and texcoord info }
10262 // Currently, this function does not support/parse lines inside CGODrawArrays, i.e.,
10263 // a CGO that CGOCombineBeginEnd was used on
CGOConvertLinesToTrilines(const CGO * I,bool addshaders)10264 CGO *CGOConvertLinesToTrilines(const CGO * I, bool addshaders){
10265 static std::set<int> lineops = { CGO_VERTEX, CGO_LINE, CGO_SPLITLINE };
10266 auto G = I->G;
10267 const int nLines = CGOCountNumberOfOperationsOfTypeN(I, lineops ) + 1;
10268
10269 if (nLines == 0) {
10270 return nullptr;
10271 }
10272
10273 int line_counter = 0;
10274 GLuint glbuff = 0;
10275 const float *colorv = NULL;
10276 unsigned int buff_size = nLines * 6 * (8 * sizeof(float));
10277
10278 // VBO memory -- number of lines x 4 vertices per line x (vertex + otherVertex + normal + texCoord + color)
10279 std::vector<float> buffer_start(buff_size);
10280 float *buffer = buffer_start.data();
10281
10282 std::unique_ptr<CGO> cgo(new CGO(G));
10283
10284 for (auto it = I->begin(); !it.is_stop(); ++it) {
10285 const auto op = it.op_code();
10286 const auto pc = it.data();
10287
10288 switch (op) {
10289 case CGO_DRAW_ARRAYS:
10290 {
10291 auto sp = it.cast<cgo::draw::arrays>();
10292 float *vals = cgo->add<cgo::draw::arrays>(sp->mode, sp->arraybits, sp->nverts);
10293 int nvals = sp->narrays*sp->nverts;
10294 memcpy(vals, sp->floatdata, nvals);
10295 }
10296 break;
10297 case CGO_END:
10298 WARN_UNEXPECTED_OPERATION(G, op);
10299 return nullptr;
10300 case CGO_BEGIN:
10301 {
10302 const float *last_vertex = nullptr, *last_color = nullptr,
10303 *current_color = nullptr, *color = nullptr;
10304 const int mode = it.cast<cgo::draw::begin>()->mode;
10305
10306 for (++it;; ++it) {
10307 if (it.is_stop()) {
10308 WARN_UNEXPECTED_OPERATION(G, CGO_STOP);
10309 return nullptr;
10310 }
10311
10312 const auto op = it.op_code();
10313 if (op == CGO_END) {
10314 break;
10315 }
10316
10317 const auto pc = it.data();
10318
10319 switch (op) {
10320 case CGO_VERTEX:
10321 if (last_vertex){
10322 switch (mode){
10323 case GL_LINES:
10324 case GL_LINE_STRIP:
10325 {
10326 float cc[3] = { 1, 1, 1 };
10327 float alpha = cgo->alpha;
10328 CGOTrilines_GetCurrentColor(current_color, colorv, last_color, cc);
10329 trilinesBufferAddVertices(buffer, pc, last_vertex, current_color, alpha);
10330 line_counter++;
10331 last_vertex = pc;
10332 }
10333 if (mode==GL_LINES){
10334 last_vertex = NULL;
10335 last_color = NULL;
10336 }
10337 }
10338 } else {
10339 last_vertex = pc;
10340 current_color = color;
10341 }
10342 break;
10343 case CGO_LINE:
10344 {
10345 auto line = it.cast<cgo::draw::line>();
10346 float cc[3] = { 1, 1, 1 };
10347 float alpha = cgo->alpha;
10348 CGOTrilines_GetCurrentColor(current_color, colorv, last_color, cc);
10349 trilinesBufferAddVertices(buffer, line->vertex1, line->vertex2, current_color, alpha);
10350 line_counter++;
10351 }
10352 break;
10353 case CGO_SPLITLINE:
10354 {
10355 auto splitline = it.cast<cgo::draw::splitline>();
10356 float cc[3] = { 1, 1, 1 };
10357 float alpha = cgo->alpha;
10358 float mid[3];
10359 float color2[] = { CONVERT_COLOR_VALUE(splitline->color2[0]),
10360 CONVERT_COLOR_VALUE(splitline->color2[1]),
10361 CONVERT_COLOR_VALUE(splitline->color2[2]) };
10362 add3f(splitline->vertex1, splitline->vertex2, mid);
10363 mult3f(mid, .5f, mid);
10364 CGOTrilines_GetCurrentColor(current_color, colorv, last_color, cc);
10365 trilinesBufferAddVertices(buffer, splitline->vertex1, mid, current_color, alpha);
10366 trilinesBufferAddVertices(buffer, mid, splitline->vertex2, color2, alpha);
10367 line_counter+=2;
10368 }
10369 break;
10370 case CGO_COLOR:
10371 last_color = current_color;
10372 current_color = pc;
10373 color = pc;
10374 break;
10375 }
10376 }
10377 }
10378 break;
10379 case CGO_ALPHA:
10380 cgo->alpha = *pc;
10381 break;
10382 case CGO_COLOR:
10383 colorv = pc;
10384 break;
10385 }
10386 }
10387
10388 cgo->use_shader = I->use_shader;
10389 if (cgo->use_shader){
10390 cgo->cgo_shader_ub_color = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_color);
10391 cgo->cgo_shader_ub_normal = SettingGetGlobal_i(cgo->G, cSetting_cgo_shader_ub_normal);
10392 }
10393
10394 {
10395 int err = 0;
10396 glGenBuffers(1, &glbuff);
10397 glBindBuffer(GL_ARRAY_BUFFER, glbuff);
10398 glBufferData(GL_ARRAY_BUFFER, line_counter * 6 * 8 * sizeof(float), buffer_start.data(), GL_STATIC_DRAW);
10399 CHECK_GL_ERROR_OK("ERROR: CGOConvertLinesToTriangleStrips() glBindBuffer returns err=%d\n");
10400 if (addshaders)
10401 cgo->add<cgo::draw::enable>(GL_TRILINES_SHADER);
10402 cgo->add<cgo::draw::trilines>(line_counter * 6, glbuff);
10403 cgo->has_draw_buffers = true;
10404 if (addshaders)
10405 cgo->add<cgo::draw::disable>(GL_TRILINES_SHADER);
10406 CGOStop(cgo.get());
10407 }
10408
10409 return cgo.release();
10410 }
10411
10412 /*
10413 * copies data for a particular attribute operation into the array used to load the VBO.
10414 * this takes into account whether it is interleaved or not.
10415 *
10416 * isInterleaved : whether the VBO is interleaved
10417 * nvert : which vertex in the VBO
10418 * attribOp : the attribute op
10419 * vertexDataSize : total vertex data size in VBO (for interleaved)
10420 * dataPtrs : all data pointers for attributes (for interleaved, they are all the pointer to the one array)
10421 * attrOffset : offsets of the attributes (for interleaved)
10422 * pcarg : pc pointer to CGO operation data
10423 * pick_data : pointer to pick data for current vertex (writes to if pick data)
10424 * has_pick_colorBS : keeps track of which pick attributes have been set
10425 *
10426 */
10427 static
copyAttributeForOp(bool isInterleaved,int & nvert,AttribOp * attribOp,int vertexDataSize,vector<void * > & dataPtrs,vector<int> & attrOffset,const float * pcarg,float * pick_data,int & has_pick_colorBS,int pstride)10428 void copyAttributeForOp(bool isInterleaved, int &nvert, AttribOp *attribOp, int vertexDataSize, vector<void*> &dataPtrs,
10429 vector<int> &attrOffset, const float *pcarg, float *pick_data, int &has_pick_colorBS, int pstride){
10430 auto attrDesc = attribOp->desc;
10431 int ord = attrDesc->order;
10432 int copyord = -1;
10433 void *dataPtr = dataPtrs[ord];
10434 unsigned char *pc = ((unsigned char *)pcarg) + attribOp->offset;
10435 if (isInterleaved){
10436 dataPtr = (unsigned char*) dataPtr + nvert * vertexDataSize + attrOffset[ord];
10437 if (attribOp->copyAttribDesc){
10438 copyord = attribOp->copyAttribDesc->order;
10439 pc = ((unsigned char*) dataPtrs[ord]) + nvert * vertexDataSize + attrOffset[copyord];
10440 }
10441 } else {
10442 int sz = gl_sizeof(attrDesc->type_size) * attrDesc->type_dim;
10443 dataPtr = (unsigned char*) dataPtr + nvert * sz;
10444 if (attribOp->copyAttribDesc){
10445 copyord = attribOp->copyAttribDesc->order;
10446 int copysz = gl_sizeof(attribOp->copyAttribDesc->type_size) * attribOp->copyAttribDesc->type_dim;
10447 pc = (unsigned char*) dataPtr + nvert * copysz;
10448 }
10449 }
10450 switch (attribOp->conv_type){
10451 case NO_COPY:
10452 break;
10453 case FLOAT_TO_FLOAT:
10454 *((float *) dataPtr) = *((float *)pc);
10455 break;
10456 case FLOAT2_TO_FLOAT2:
10457 *((float *) dataPtr) = *((float *)pc);
10458 *((float *) dataPtr + 1) = *((float *)pc + 1);
10459 break;
10460 case FLOAT3_TO_FLOAT3:
10461 copy3f((float*)pc, (float*)dataPtr);
10462 break;
10463 case FLOAT4_TO_FLOAT4:
10464 *((float *) dataPtr) = *((float *)pc);
10465 *((float *) dataPtr + 1) = *((float *)pc + 1);
10466 *((float *) dataPtr + 2) = *((float *)pc + 2);
10467 *((float *) dataPtr + 3) = *((float *)pc + 3);
10468 break;
10469 case FLOAT3_TO_UB3:
10470 {
10471 auto dataPtrUB = (unsigned char *)dataPtr;
10472 float *pcf = (float*)pc;
10473 dataPtrUB[0] = CLIP_COLOR_VALUE(pcf[0]);
10474 dataPtrUB[1] = CLIP_COLOR_VALUE(pcf[1]);
10475 dataPtrUB[2] = CLIP_COLOR_VALUE(pcf[2]);
10476 }
10477 break;
10478 case FLOAT1_TO_UB_4TH:
10479 {
10480 auto dataPtrUB = (unsigned char *)dataPtr;
10481 float *pcf = (float*)pc;
10482 dataPtrUB[3] = CLIP_COLOR_VALUE(pcf[0]);
10483 }
10484 break;
10485 case UB3_TO_UB3:
10486 {
10487 auto dataPtrUB = (unsigned char *)dataPtr;
10488 auto pcUB = (unsigned char *)pc;
10489 dataPtrUB[0] = pcUB[0];
10490 dataPtrUB[1] = pcUB[1];
10491 dataPtrUB[2] = pcUB[2];
10492 break;
10493 }
10494 case UINT_INT_TO_PICK_DATA:
10495 {
10496 float *pcf = (float*)pc;
10497 unsigned int index = CGO_get_uint(pcf);
10498 int bond = CGO_get_int(pcf+1);
10499 CGO_put_uint(ord * 2 + pick_data, index);
10500 CGO_put_int(ord * 2 + pick_data + 1, bond);
10501 has_pick_colorBS |= (1 << ord) ;
10502 }
10503 break;
10504 case FLOAT4_TO_UB4:
10505 {
10506 auto dataPtrUB = (unsigned char *)dataPtr;
10507 float *pcf = (float*)pc;
10508 dataPtrUB[0] = CLIP_COLOR_VALUE(pcf[0]);
10509 dataPtrUB[1] = CLIP_COLOR_VALUE(pcf[1]);
10510 dataPtrUB[2] = CLIP_COLOR_VALUE(pcf[2]);
10511 dataPtrUB[3] = CLIP_COLOR_VALUE(pcf[3]);
10512 }
10513 break;
10514 case CYL_CAP_TO_CAP:
10515 {
10516 unsigned char *dataPtrUB = (unsigned char *)dataPtr;
10517 dataPtrUB[0] = *pc;
10518 }
10519 break;
10520 case CYL_CAPS_ARE_ROUND:
10521 {
10522 unsigned char *dataPtrUB = (unsigned char *)dataPtr;
10523 dataPtrUB[0] = cCylShaderBothCapsRound | cCylShaderInterpColor;
10524 }
10525 break;
10526 case CYL_CAPS_ARE_FLAT:
10527 {
10528 unsigned char *dataPtrUB = (unsigned char *)dataPtr;
10529 dataPtrUB[0] = cCylShaderBothCapsFlat | cCylShaderInterpColor;
10530 }
10531 break;
10532 case CYL_CAPS_ARE_CUSTOM:
10533 {
10534 unsigned char *dataPtrUB = (unsigned char *)dataPtr;
10535 float *pcf = (float*)pc;
10536 int pci[] = { (int)pcf[0], (int)pcf[1] };
10537 dataPtrUB[0] = (((pci[0]) == 1) ? cCylShaderCap1Flat : (((pci[0]) == 2) ? cCylShaderCap1Round : cCylCapNone)) |
10538 (((pci[1]) == 1) ? cCylShaderCap2Flat : (((pci[1]) == 2) ? cCylShaderCap2Round : cCylCapNone)) |
10539 cCylShaderInterpColor;
10540 }
10541 break;
10542 case UB1_TO_INTERP:
10543 {
10544 bool interp = (pc[0] & cgo::draw::splitline::interpolation);
10545 unsigned char *dataPtrUB = (unsigned char *)dataPtr;
10546 dataPtrUB[0] = interp ? 1 : 0;
10547 }
10548 break;
10549 case UB1_INTERP_TO_CAP:
10550 {
10551 bool interp = (pc[0] & cgo::draw::splitline::interpolation);
10552 unsigned char *dataPtrUB = (unsigned char *)dataPtr;
10553 dataPtrUB[0] = (cCylShaderBothCapsRound | (interp ? cCylShaderInterpColor : 0));
10554 }
10555 break;
10556 case FLOAT1_TO_INTERP:
10557 {
10558 float interp = *((float*)pc);
10559 unsigned char *dataPtrUB = (unsigned char *)dataPtr;
10560 dataPtrUB[0] = (interp > .5f) ? 1 : 0;
10561 }
10562 break;
10563 case FLOAT1_INTERP_TO_CAP:
10564 {
10565 float interp = *((float*)pc);
10566 unsigned char *dataPtrUB = (unsigned char *)dataPtr;
10567 dataPtrUB[0] = (cCylShaderBothCapsRound | ((interp > .5f) ? cCylShaderInterpColor : 0));
10568 }
10569 break;
10570 case UB4_TO_UB4:
10571 {
10572 auto dataPtrUB = (unsigned char *)dataPtr;
10573 auto pcUB = (unsigned char *)pc;
10574 dataPtrUB[0] = pcUB[0];
10575 dataPtrUB[1] = pcUB[1];
10576 dataPtrUB[2] = pcUB[2];
10577 dataPtrUB[3] = pcUB[3];
10578 break;
10579 }
10580 case PICK_DATA_TO_PICK_DATA:
10581 {
10582 float *pcf;
10583 if (copyord < 0){
10584 pcf = (float*)pc;
10585 } else {
10586 pcf = (copyord * 2 + pick_data);
10587 if (nvert){
10588 pcf -= pstride;
10589 }
10590 }
10591 unsigned int index = CGO_get_uint(pcf);
10592 int bond = CGO_get_int(pcf+1);
10593 CGO_put_uint(ord * 2 + pick_data, index);
10594 CGO_put_int(ord * 2 + pick_data + 1, bond);
10595 has_pick_colorBS |= (1 << ord) ;
10596 break;
10597 }
10598 }
10599 }
10600
10601 /*
10602 * copies data for a particular attribute into the array used to load the VBO.
10603 * this takes into account whether it is interleaved or not, and if an attribute
10604 * has repeat values
10605 *
10606 * isInterleaved : whether the VBO is interleaved
10607 * nvert : which vertex in the VBO
10608 * attribDesc : the attribute description
10609 * vertexDataSize : total vertex data size in VBO (for interleaved)
10610 * dataPtrs : all data pointers for attributes (for interleaved, they are all the pointer to the one array)
10611 * attrOffset : offsets of the attributes (for interleaved)
10612 *
10613 */
10614 static
copyAttributeForVertex(bool isInterleaved,int & nvert,AttribDesc & attribDesc,const int vertexDataSize,vector<void * > & dataPtrs,vector<int> & attrOffset)10615 void copyAttributeForVertex(bool isInterleaved, int &nvert, AttribDesc &attribDesc,
10616 const int vertexDataSize, vector<void*> &dataPtrs, vector<int> &attrOffset){
10617 int ord = attribDesc.order;
10618 void *dataPtr = dataPtrs[ord];
10619 unsigned char *pc = NULL;
10620 int attrSize = gl_sizeof(attribDesc.type_size) * attribDesc.type_dim;
10621 if (isInterleaved){
10622 dataPtr = (unsigned char*) dataPtr + nvert * vertexDataSize + attrOffset[ord];
10623 pc = (unsigned char*) dataPtr - vertexDataSize;
10624 } else {
10625 dataPtr = (unsigned char*) dataPtr + nvert * attrSize;
10626 pc = (unsigned char*) dataPtr - attrSize;
10627 }
10628 if (attribDesc.repeat_value && attribDesc.repeat_value_length){
10629 int pos = (nvert % attribDesc.repeat_value_length);
10630 pc = attribDesc.repeat_value + pos * attrSize;
10631 memcpy(dataPtr, pc, attrSize);
10632 } else {
10633 memcpy(dataPtr, pc, attrSize);
10634 }
10635 }
10636 /*
10637 * check all attributes (pick and non-pick) to see if they are specified in the CGO (I)
10638 * also checks to see if any picking is specified and sets has_picking argument
10639 * if any of the attributes are not specified and if a default_value is set (in the
10640 * AttribDesc) then the associated vertex_attribute CGO operation is inserted into the
10641 * cgo that is passed in.
10642 *
10643 * I: primitive CGO that is processed
10644 * attrData: definition of attributes
10645 * pickData: definition of pick attributes
10646 * cgo: new cgo that could have vertex_attribute CGO operations added
10647 * has_picking: if there are any operations in the CGO (I) that specifies different values for picking.
10648 * if has_picking is set, then a VBO for picking is generated in CGOConvertToShader()
10649 *
10650 */
10651 static
CheckAttributesForUsage(const CGO * I,AttribDataDesc & attrData,AttribDataDesc & pickData,CGO * cgo,bool & has_picking)10652 void CheckAttributesForUsage(const CGO *I, AttribDataDesc &attrData, AttribDataDesc &pickData, CGO *cgo, bool &has_picking)
10653 {
10654 size_t attrIdx = 0;
10655
10656 // need to check attributes:
10657 // - remove any that are not needed
10658 // - add glVertexAttrib for those that are removed
10659 std::map<int, int> opToAttrUsed; // bitmask for each op to which attributes are set
10660 for (auto &attrDesc : attrData){
10661 auto attrOps = &attrDesc.attrOps;
10662 attrDesc.order = attrIdx++;
10663 for (auto attrOpIt = attrOps->begin(); attrOpIt!=attrOps->end(); ++attrOpIt){
10664 auto attrOp = &(*attrOpIt);
10665 if (opToAttrUsed.find(attrOp->op) == opToAttrUsed.end())
10666 opToAttrUsed[attrOp->op] = 1 << attrDesc.order;
10667 else
10668 opToAttrUsed[attrOp->op] |= 1 << attrDesc.order;
10669 }
10670 }
10671 // add picking ops (1 << attrIdx) i.e., any pick op is the last bit
10672 int pidx = 0;
10673 for (auto pickDataIt = pickData.begin(); pickDataIt!=pickData.end(); ++pickDataIt){
10674 auto pickDesc = &(*pickDataIt);
10675 auto pickOps = &pickDesc->attrOps;
10676 pickDesc->order = pidx++;
10677 for (auto pickOpIt = pickOps->begin(); pickOpIt!=pickOps->end(); ++pickOpIt){
10678 auto pickOp = &(*pickOpIt);
10679 pickOp->desc = pickDesc;
10680 if (opToAttrUsed.find(pickOp->op) == opToAttrUsed.end())
10681 opToAttrUsed[pickOp->op] = 1 << attrIdx;
10682 else
10683 opToAttrUsed[pickOp->op] |= 1 << attrIdx;
10684 }
10685 }
10686 size_t totAttrIdx = (1 << (attrIdx+1)) - 1;
10687 size_t allAttrIdxUsed = 0;
10688 for (auto it = I->begin(); !it.is_stop(); ++it) {
10689 auto pc = it.data();
10690 int op = it.op_code();
10691 if (opToAttrUsed.find(op) != opToAttrUsed.end()){
10692 int attrUsed = opToAttrUsed[op];
10693 if (attrUsed & (1 << attrIdx)){ // if picking, need to check values, and take them out if cPickableNoPick
10694 switch (op){
10695 case cgo::draw::shadercylinder2ndcolor::op_code:
10696 if (reinterpret_cast<const cgo::draw::shadercylinder2ndcolor *>(pc)->pick_color_bond == cPickableNoPick)
10697 attrUsed ^= (1 << attrIdx);
10698 break;
10699 case cgo::draw::splitline::op_code:
10700 if (reinterpret_cast<const cgo::draw::splitline *>(pc)->bond == cPickableNoPick)
10701 attrUsed ^= (1 << attrIdx);
10702 }
10703 }
10704 allAttrIdxUsed |= attrUsed;
10705 if (allAttrIdxUsed == totAttrIdx)
10706 break;
10707 }
10708 }
10709 has_picking = allAttrIdxUsed & (1 << attrIdx); // has_picking if the last bit is set
10710
10711 if (allAttrIdxUsed != totAttrIdx){
10712 // go through any attributes that aren't used:
10713 // - add associated vertex_attribute type (if default_value is set)
10714 // - remove attribute from attrData description so that it isn't included in VBO
10715 AttribDataDesc attrDataNew;
10716 for (auto idx = 0; idx < attrIdx; ++idx){
10717 if (!attrData[idx].repeat_value && !(allAttrIdxUsed & (1 << idx))) {
10718 // attribute not used, need to create glVertexAttrib
10719 if (attrData[idx].default_value){
10720 // need to add glVertexAttrib CGO OP
10721 int attr_lookup_idx = I->G->ShaderMgr->GetAttributeUID(attrData[idx].attr_name);
10722 switch (attrData[idx].type_size){
10723 case GL_FLOAT:
10724 switch (attrData[idx].type_dim){
10725 case 1:
10726 cgo->add<cgo::draw::vertex_attribute_1f>(attr_lookup_idx, *(float*)attrData[idx].default_value);
10727 break;
10728 case 3:
10729 cgo->add<cgo::draw::vertex_attribute_3f>(attr_lookup_idx, attrData[idx].default_value);
10730 break;
10731 default:
10732 std::cerr << "\tNOT IMPLEMENTED: attrData[idx].type_size=" << attrData[idx].type_size << " attrData[idx].type_dim=" << attrData[idx].type_dim << endl;
10733 }
10734 break;
10735 case GL_UNSIGNED_BYTE:
10736 switch (attrData[idx].type_dim){
10737 case 1:
10738 {
10739 float val;
10740 unsigned char valuc = *attrData[idx].default_value;
10741 if (attrData[idx].data_norm){
10742 val = CLAMPVALUE(valuc / 255.f, 0.f, 1.f);
10743 } else {
10744 val = (float)valuc;
10745 }
10746 cgo->add<cgo::draw::vertex_attribute_1f>(attr_lookup_idx, val);
10747 }
10748 break;
10749 case 4:
10750 cgo->add<cgo::draw::vertex_attribute_4ub>(attr_lookup_idx, attrData[idx].default_value);
10751 break;
10752 default:
10753 std::cerr << "\tNOT IMPLEMENTED: attrData[idx].type_size=" << attrData[idx].type_size << " attrData[idx].type_dim=" << attrData[idx].type_dim << endl;
10754 }
10755 }
10756 }
10757 } else {
10758 attrDataNew.push_back(attrData[idx]);
10759 }
10760 }
10761 attrData.swap(attrDataNew); // only keep attributes that are used
10762 }
10763 }
10764
10765 /*
10766 * Populates two structures and sets vertsperpickinfo
10767 * opToCntPer : CGO op to how many vertices are generated for each op.
10768 * opToOrderedAttribOps : CGO op to an ordered map of AttribOps that define how we operate on
10769 * the attribute arrays for each CGO op.
10770 * attrData : definition of attributes
10771 * pickData : definition of pick attributes
10772 * vertsperpickinfo : number of vertices per pick (only used when
10773 *
10774 */
10775 static
PopulateOpsIntoStructuresForConversion(std::map<int,int> & opToCntPer,std::map<int,std::map<int,AttribOp * >> & opToOrderedAttribOps,AttribDataDesc & attrData,AttribDataDesc & pickData,int & vertsperpickinfo,const bool has_picking)10776 void PopulateOpsIntoStructuresForConversion(std::map<int,int> &opToCntPer,
10777 std::map< int, std::map<int, AttribOp*> > &opToOrderedAttribOps,
10778 AttribDataDesc &attrData, AttribDataDesc &pickData,
10779 int &vertsperpickinfo, const bool has_picking){
10780 size_t attrIdx = 0;
10781 for (auto &attrDesc : attrData){
10782 auto attrOps = &attrDesc.attrOps;
10783 attrDesc.order = attrIdx++;
10784 for (auto attrOpIt = attrOps->begin(); attrOpIt!=attrOps->end(); ++attrOpIt){
10785 auto attrOp = &(*attrOpIt);
10786 attrOp->desc = &attrDesc;
10787 if (attrOp->copyFromAttr >= 0){
10788 attrOp->copyAttribDesc = &attrData[attrOp->copyFromAttr];
10789 }
10790 if (attrOp->incr_vertices > 0){
10791 if (!vertsperpickinfo){
10792 vertsperpickinfo = attrOp->incr_vertices;
10793 } else {
10794 if (attrOp->incr_vertices != vertsperpickinfo){
10795 std::cerr << "WARNING: attrOp->incr_vertices set to multiple values, vertsperpickinfo=" << vertsperpickinfo << " attrOp->incr_vertices=" << attrOp->incr_vertices << " : picking might get confused" << std::endl;
10796 }
10797 }
10798 if (opToCntPer.find(attrOp->op) == opToCntPer.end())
10799 opToCntPer[attrOp->op] = attrOp->incr_vertices;
10800 else
10801 opToCntPer[attrOp->op] += attrOp->incr_vertices;
10802 }
10803 if (opToOrderedAttribOps.find(attrOp->op) == opToOrderedAttribOps.end())
10804 opToOrderedAttribOps[attrOp->op] = std::map<int, AttribOp*>({});
10805 opToOrderedAttribOps[attrOp->op][attrOp->order] = attrOp;
10806 }
10807 }
10808 if (has_picking){
10809 for (auto pickDataIt = pickData.begin(); pickDataIt!=pickData.end(); ++pickDataIt){
10810 auto pickDesc = &(*pickDataIt);
10811 auto pickOps = &pickDesc->attrOps;
10812 for (auto pickOpIt = pickOps->begin(); pickOpIt!=pickOps->end(); ++pickOpIt){
10813 auto pickOp = &(*pickOpIt);
10814 if (pickOp->copyFromAttr >= 0){
10815 pickOp->copyAttribDesc = &pickData[pickOp->copyFromAttr];
10816 }
10817 if (opToOrderedAttribOps.find(pickOp->op) == opToOrderedAttribOps.end())
10818 opToOrderedAttribOps[pickOp->op] = std::map<int, AttribOp*>({});
10819 opToOrderedAttribOps[pickOp->op][pickOp->order] = pickOp;
10820 }
10821 }
10822 }
10823 }
10824
10825 /*
10826 * converts a "primitive" CGO into a CGO that renders a custom operation
10827 *
10828 * I: primitive CGO that is processed
10829 * attrData: definition of attributes that are accumulated and put into the VBO
10830 * pickData: definition of pick attributes that accumulate pick data and put into the interleaved picking VBO
10831 * mode: which openGL mode to use for rendering (e.g., GL_POINTS, GL_TRIANGLES, GL_LINE_STRIPS, etc.)
10832 * layout: SEPARATE, SEQUENTIAL, or INTERLEAVED : how the VBO is layed out in memory (default: INTERLEAVED)
10833 * check_attr_for_data: if true, this function checks whether all attributes are used, and if any are not specified,
10834 * and default values are defined in AttribDesc, then glVertexAttrib CGO ops are created on the
10835 * returned CGO (default: true)
10836 * idx_array: if specified, this array is used to specify indices for each fragment in an Indexed Buffer
10837 * and glDrawElements is used to render (instead of glDrawArrays)
10838 * nvertsperfrag: in conjunction with idx_array, how many vertices for each set of indices (default: 0)
10839 * both idx_array and nvertsperfrag are used to specify vertices and geometry for each fragment,
10840 * such as the box for cylinders
10841 * nfragspergroup: Currently, this represents the number of fragments that are inside of a group. For example,
10842 * crosses as cylinders (CGOConvertCrossesToCylinderShader) have 36 indices per fragment (nvertsperfrag=36)
10843 * and 3 fragments per group (nfragspergroup=3) (i.e., one for each line).
10844 * note: idx_array, nvertsperfrag and nfragspergroup should probably be moved to AttrOp in
10845 * the future to support different types of fragments.
10846 *
10847 * returns a CGO that consists of vertex_attrib_* (e.g., glVertexAttrib) and a custom CGO operation that calls
10848 * either glDrawArrays or glDrawElements. It also supports picking if specified in the pickData.
10849 *
10850 */
CGOConvertToShader(const CGO * I,AttribDataDesc & attrData,AttribDataDesc & pickData,int mode,const VertexBuffer::buffer_layout layout,bool check_attr_for_data,int * idx_array,int nvertsperfrag,int nfragspergroup)10851 CGO *CGOConvertToShader(const CGO *I, AttribDataDesc &attrData, AttribDataDesc &pickData, int mode,
10852 const VertexBuffer::buffer_layout layout, bool check_attr_for_data,
10853 int *idx_array, int nvertsperfrag, int nfragspergroup){
10854 CGO *cgo;
10855 int ok = true;
10856 bool isInterleaved = (layout == VertexBuffer::INTERLEAVED);
10857 bool has_picking = true;
10858 std::map<string, AttribDesc*> attrToDesc;
10859
10860 cgo = CGONew(I->G);
10861 cgo->use_shader = true;
10862
10863 if (check_attr_for_data){
10864 CheckAttributesForUsage(I, attrData, pickData, cgo, has_picking);
10865 } else {
10866 // if attributes aren't checked, still need to set pick order and desc pointer
10867 int pidx = 0;
10868 for (auto &pickDesc : pickData){
10869 pickDesc.order = pidx++;
10870 for (auto &pickOp : pickDesc.attrOps){
10871 pickOp.desc = &pickDesc;
10872 }
10873 }
10874 }
10875 std::map<int,int> opToCntPer;
10876 std::map< int, std::map<int, AttribOp*> > opToOrderedAttribOps ;
10877
10878 int vertsperpickinfo = 0;
10879 PopulateOpsIntoStructuresForConversion(opToCntPer, opToOrderedAttribOps, attrData,
10880 pickData, vertsperpickinfo, has_picking);
10881
10882
10883 // Populate these variables used for accumulating and setting VBO data arrays
10884 int vertexDataSize = 0;
10885 vector<int> attrSizes;
10886 vector<int> attrOffset; // for interleaved
10887 int curoffset = 0; // for interleaved
10888 size_t attrIdx = 0;
10889 for (auto &attrDesc : attrData){
10890 attrDesc.order = attrIdx++;
10891 int attrSize = gl_sizeof(attrDesc.type_size) * attrDesc.type_dim;
10892 attrSizes.push_back(attrSize);
10893 vertexDataSize += attrSize;
10894
10895 if (isInterleaved){
10896 attrOffset.push_back(curoffset);
10897 curoffset += attrSize;
10898 } else {
10899 attrOffset.push_back(0); // no offset when not interleaved
10900 }
10901 attrToDesc[attrDesc.attr_name] = &attrDesc;
10902 }
10903
10904 // populate funcData.attrib
10905 for (auto &attrDesc : attrData)
10906 for (auto &attrop : attrDesc.attrOps)
10907 for (auto &funcData : attrop.funcDataConversions){
10908 if (attrToDesc.find(funcData.attribName) != attrToDesc.end()){
10909 funcData.attrib = attrToDesc[funcData.attribName];
10910 }
10911 }
10912
10913 // Since some cards require word-aligned strides (e.g., ATI)
10914 // we need to make sure it is word-aligned. If it isn't, and you
10915 // want to save memory, maybe SEQUENTIAL is a better option
10916 if (vertexDataSize % 4){
10917 vertexDataSize += 4 - (vertexDataSize % 4);
10918 }
10919
10920 int ntotalverts = CGOCountNumberOfOperationsOfTypeN(I, opToCntPer);
10921
10922 // PYMOL-2668
10923 if (ntotalverts == 0) {
10924 CGOStop(cgo);
10925 return cgo;
10926 }
10927
10928 size_t pickvbohash = 0;
10929 int pickDataSize = pickData.size();
10930 int pstride = 2 * pickDataSize;
10931 // Generate VBOs: both for vertex data (vbo) and picking color data (pickvbo) if necessary
10932 // - pickvbo is interleaved so that for multiple channels, pick data for each vertex
10933 // is contiguous
10934 VertexBuffer *vbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>(layout);
10935 VertexBuffer *pickvbo = NULL;
10936 if (pickDataSize){
10937 pickvbo = I->G->ShaderMgr->newGPUBuffer<VertexBuffer>(VertexBuffer::SEQUENTIAL, GL_DYNAMIC_DRAW);
10938 pickvbohash = pickvbo->get_hash_id();
10939 }
10940
10941 // adding SPECIAL OPERATIONS (for now) before adding custom OP
10942 // - for now, this is the only operation that needs to be passed to the new CGO
10943 for (auto it = I->begin(); !it.is_stop(); ++it) {
10944 auto pc = it.data();
10945 int op = it.op_code();
10946 switch (op){
10947 case CGO_SPECIAL:
10948 cgo->add_to_cgo(op, pc);
10949 break;
10950 }
10951 }
10952
10953 // defines how many passes we have
10954 // We *could* set npickcolattr=1 if we had access to PickColorConverter here and getTotalBits() == 32
10955 const int npickcolattr = SHADER_PICKING_PASSES_MAX;
10956 /* for picking, we need to mask the attributes and bind the buffer in the the picking VBO */
10957 int pl = 0;
10958 int npickattr = pickData.size();
10959 for (auto &pickDesc : pickData){
10960 cgo->add<cgo::draw::mask_attribute_if_picking>(I->G->ShaderMgr->GetAttributeUID(pickDesc.attr_name), vbo->get_hash_id());
10961 if (has_picking){
10962 cgo->add<cgo::draw::bind_vbo_for_picking>(pickvbohash, pl++, npickattr);
10963 } else {
10964 /* if no picking, should render black */
10965 static unsigned char zerocolor[] { 0,0,0,0 };
10966 cgo->add<cgo::draw::vertex_attribute_4ub_if_picking>(I->G->ShaderMgr->GetAttributeUID(pickDesc.attr_name), zerocolor);
10967 }
10968 }
10969 size_t iboid = 0;
10970 int num_total_indexes = 0;
10971 if (nvertsperfrag){
10972 GL_C_INT_TYPE *vertexIndices;
10973 int nfrags = nfragspergroup * ntotalverts/vertsperpickinfo;
10974 int nvertsperindivfrag = vertsperpickinfo/nfragspergroup;
10975 num_total_indexes = nfrags * nvertsperfrag;
10976 vertexIndices = pymol::calloc<GL_C_INT_TYPE>(num_total_indexes);
10977 int idxpl=0;
10978 // using vertsperpickinfo as verts per frag
10979 for (int cnt = 0, vpl = 0; cnt < nfrags; ++cnt){
10980 for (int idx_array_pl = 0; idx_array_pl < nvertsperfrag; ++idx_array_pl){
10981 vertexIndices[idxpl] = idx_array[idx_array_pl] + vpl;
10982 idxpl++;
10983 }
10984 vpl+=nvertsperindivfrag;
10985 }
10986 IndexBuffer * ibo = I->G->ShaderMgr->newGPUBuffer<IndexBuffer>();
10987 ok &= ibo->bufferData({
10988 BufferDesc( GL_C_INT_ENUM, sizeof(GL_C_INT_TYPE) * num_total_indexes, vertexIndices )
10989 });
10990 FreeP(vertexIndices);
10991 iboid = ibo->get_hash_id();
10992 }
10993
10994 // pick_data is interleaved if more than one attribute
10995 float * pick_data = cgo->add<cgo::draw::custom>(mode, ntotalverts, vbo->get_hash_id(), pickvbohash, vertsperpickinfo, pickDataSize, iboid, num_total_indexes);
10996 void *allData = malloc(ntotalverts * vertexDataSize);
10997 vector<void*> dataPtrs;
10998 vector<int> repeat_attr_idx;
10999 int allAttrBS = 0;
11000
11001 // Initialize first entry in array(s) with default values and populate dataPtrs
11002 if (isInterleaved){
11003 int pl = 0;
11004 auto attrDataIt = attrData.begin();
11005 auto attrOffsetIt = attrOffset.begin();
11006 for (; attrDataIt!=attrData.end() && attrOffsetIt!=attrOffset.end(); ++attrDataIt, ++attrOffsetIt){
11007 auto attrDesc = &(*attrDataIt);
11008 if (attrDesc->repeat_value){
11009 repeat_attr_idx.push_back(pl);
11010 } else {
11011 allAttrBS |= (1 << attrDesc->order);
11012 }
11013 auto attrOffset = *attrOffsetIt;
11014 unsigned char *first_value = NULL;
11015 first_value = (attrDesc->default_value ? attrDesc->default_value :
11016 (attrDesc->repeat_value ? attrDesc->repeat_value : NULL));
11017 if (first_value){
11018 int attrSize = gl_sizeof(attrDesc->type_size) * attrDesc->type_dim;
11019 memcpy(((unsigned char*)allData)+attrOffset, first_value, attrSize);
11020 }
11021 dataPtrs.push_back((void*)allData);
11022 ++pl;
11023 }
11024 } else {
11025 void *curAllDataPtr = (void*)allData;
11026 int pl = 0;
11027 for (auto &attrDesc : attrData){
11028 if (attrDesc.repeat_value){
11029 repeat_attr_idx.push_back(pl);
11030 } else {
11031 allAttrBS |= (1 << attrDesc.order);
11032 }
11033 dataPtrs.push_back(curAllDataPtr);
11034 unsigned char *first_value = NULL;
11035 first_value = (attrDesc.default_value ? attrDesc.default_value :
11036 (attrDesc.repeat_value ? attrDesc.repeat_value : NULL));
11037 if (first_value){
11038 memcpy((unsigned char*)curAllDataPtr, first_value, attrSizes[pl]);
11039 }
11040 curAllDataPtr = ((unsigned char*)curAllDataPtr) + ntotalverts * attrSizes[pl];
11041 ++pl;
11042 }
11043 }
11044
11045 int nvert = 0;
11046 int attrBS = 0;
11047 int allPickAttrBS = (1 << pickData.size()) - 1;
11048 int has_pick_colorBS = allPickAttrBS;
11049 for (int pi = 0; pi<pickDataSize; ++pi){
11050 CGO_put_uint(2*pi + pick_data, 0);
11051 CGO_put_int(2*pi + pick_data+1, cPickableNoPick);
11052 }
11053 bool cont = true; // need to break while statement as well if past all vertices
11054
11055 // This is the loop that goes through the CGO and accumulates all of the data
11056 // for both the rendering and picking VBOs.
11057 // - For each OP, go through the list of Attribute OPs
11058 // - Each Attribute OP:
11059 // - copies attribute data from the OP
11060 // - can generate vertices (incr_vertices)
11061 // - Attributes are kept track of (attrBS) and when vertices are generated,
11062 // the attributes that have not been newly written for the current vertex
11063 // are copied from the previous one.
11064 for (auto it = I->begin(); cont && !it.is_stop(); ++it) {
11065 auto pc = it.data();
11066 int op = it.op_code();
11067 if (opToOrderedAttribOps.find(op) != opToOrderedAttribOps.end()){
11068 std::map<int, AttribOp*> *attribOpsInOrder = &opToOrderedAttribOps[op];
11069 for (auto attribOpIt : *attribOpsInOrder){
11070 AttribOp *attribOp = attribOpIt.second;
11071 int ord = attribOp->desc->order;
11072 cont = nvert < ntotalverts;
11073 if (!cont)
11074 break;
11075 copyAttributeForOp(isInterleaved, nvert, attribOp, vertexDataSize, dataPtrs, attrOffset, pc, pick_data, has_pick_colorBS, pstride);
11076 if (ord >= 0) // picking is negative, has_pick_colorBS is used instead
11077 attrBS |= (1 << ord);
11078 else
11079 cout << " ord=%d\n" << ord << endl;
11080 if (attribOp->incr_vertices){
11081 if (has_pick_colorBS!=allPickAttrBS){
11082 // copy pick colors that haven't been set from previous vertex
11083 for (int pi = 0; pi<pickDataSize; ++pi){
11084 if (has_pick_colorBS ^ (1 << pi)){
11085 CGO_put_uint(pick_data, CGO_get_uint(pick_data-pstride));
11086 CGO_put_int(pick_data + 1, CGO_get_int(pick_data-pstride+1));
11087 }
11088 pick_data += 2;
11089 }
11090 } else {
11091 pick_data += pstride;
11092 }
11093 has_pick_colorBS = 0;
11094 if (!nvert && attrBS!=allAttrBS){
11095 // for the first vertex, all attributes should be set
11096 for (auto idx = 0; idx < attrData.size(); ++idx){
11097 if (!(attrBS & (1 << idx))) {
11098 if (!attrData[idx].default_value){
11099 std::cerr << "WARNING: attribute #" << idx <<
11100 " (" << attrData[idx].attr_name << ") not set for first"
11101 " vertex and does not have default value" << std::endl;
11102 }
11103 }
11104 }
11105 }
11106 if (nvert && attrBS!=allAttrBS){
11107 // for each vertex that hasn't been written for the current vertex, copy it from the previous vertex
11108 for (auto idx = 0; idx < attrData.size(); ++idx){
11109 if (!(attrBS & (1 << idx))) {
11110 copyAttributeForVertex(isInterleaved, nvert, attrData[idx], vertexDataSize, dataPtrs, attrOffset);
11111 }
11112 }
11113 }
11114 attrBS = 0;
11115
11116 // creating new vertices, all attribute data should be copied into new vertex.
11117 for (int nxt = 0; nxt < attribOp->incr_vertices; ++nxt){
11118 /* for now, always copy values from previous */
11119 ++nvert;
11120 if (nvert < ntotalverts){
11121 {
11122 // last should not need to copy into next, since we call copyAttributeForVertex (above)
11123 // for all attributes that haven't been set
11124 // - note: it might be faster (especially for interleaved) to copy into the next
11125 // vertex, then the above copyAttributeForVertex() would not be needed
11126 if (isInterleaved){
11127 void *dest = ((unsigned char*)allData)+vertexDataSize*nvert;
11128 memcpy(dest, ((unsigned char*)dest) - vertexDataSize, vertexDataSize);
11129 } else {
11130 auto dataPtrIt = dataPtrs.begin();
11131 auto attrDataIt = attrData.begin();
11132 for (; attrDataIt!=attrData.end() && dataPtrIt!=dataPtrs.end(); ++attrDataIt, ++dataPtrIt){
11133 auto attrDesc = &(*attrDataIt);
11134 auto dataPtr = *dataPtrIt;
11135 int attrSize = gl_sizeof(attrDesc->type_size) * attrDesc->type_dim;
11136 void *dest = ((unsigned char*)dataPtr)+attrSize*nvert;
11137 memcpy((unsigned char*)dest, ((unsigned char*)dest) - attrSize, attrSize);
11138 }
11139 }
11140 }
11141 // always copy repeat attributes
11142 if (!repeat_attr_idx.empty()){
11143 for (auto ridx = repeat_attr_idx.begin(); ridx != repeat_attr_idx.end(); ++ridx){
11144 copyAttributeForVertex(isInterleaved, nvert, attrData[*ridx], vertexDataSize, dataPtrs, attrOffset);
11145 }
11146 }
11147 }
11148 if (!attribOp->funcDataConversions.empty()){
11149 // for all attributes, call the funcDataConversion() if defined
11150 int nvert_m_1 = nvert - 1;
11151 for (auto funcData : attribOp->funcDataConversions){
11152 auto funcAttrib = funcData.attrib;
11153 auto order = funcAttrib->order;
11154 if (isInterleaved){
11155 unsigned char *dest = ((unsigned char*)allData)+vertexDataSize*nvert_m_1 + attrOffset[order];
11156 funcData.funcDataConversion(dest, pc, funcData.funcDataGlobalArg, nxt);
11157 } else {
11158 auto dataPtr = dataPtrs[order];
11159 void *dest = ((unsigned char*)dataPtr)+attrSizes[order]*nvert_m_1;
11160 funcData.funcDataConversion(dest, pc, funcData.funcDataGlobalArg, nxt);
11161 }
11162 }
11163 }
11164
11165 }
11166 }
11167 }
11168 }
11169 }
11170
11171 /* Generate Pick Buffers with all pick attributes (if necessary) */
11172 if (pickvbo){
11173 BufferDataDesc pickBufferData;
11174 for (int i=0; i < npickcolattr; i++){
11175 for (auto &pickDesc : pickData){
11176 int pickSize = gl_sizeof(pickDesc.type_size) * pickDesc.type_dim;
11177 pickBufferData.push_back(BufferDesc(pickDesc.attr_name, pickDesc.type_size,
11178 pickDesc.type_dim, pickSize * nvert, NULL, pickDesc.data_norm));
11179 }
11180 }
11181 pickvbo->bufferData(std::move(pickBufferData));
11182 }
11183
11184 /* Generate VBO Buffers with all pick attributes based on the VertexBuffer type SEPARATE/SEQUENTIAL/INTERLEAVED*/
11185 BufferDataDesc bufferData;
11186 switch (layout){
11187 case VertexBuffer::SEPARATE:
11188 case VertexBuffer::SEQUENTIAL:
11189 {
11190 auto attrDataIt = attrData.begin();
11191 auto dataPtrIt = dataPtrs.begin();
11192 auto attrSizeIt = attrSizes.begin();
11193 for (; attrDataIt!=attrData.end() &&
11194 dataPtrIt!=dataPtrs.end() &&
11195 attrSizeIt!=attrSizes.end(); ++attrDataIt, ++dataPtrIt, ++attrSizeIt){
11196 auto attrDesc = &(*attrDataIt);
11197 auto dataPtr = *dataPtrIt;
11198 auto attrSize = *attrSizeIt;
11199 bufferData.push_back(BufferDesc(attrDesc->attr_name, attrDesc->type_size,
11200 attrDesc->type_dim, nvert * attrSize, dataPtr, attrDesc->data_norm));
11201 }
11202 vbo->bufferData(std::move(bufferData));
11203 break;
11204 }
11205 break;
11206 case VertexBuffer::INTERLEAVED:
11207 {
11208 auto attrDataIt = attrData.begin();
11209 auto attrOffsetIt = attrOffset.begin();
11210 for (; attrDataIt!=attrData.end() && attrOffsetIt!=attrOffset.end(); ++attrDataIt, ++attrOffsetIt){
11211 auto attrDesc = &(*attrDataIt);
11212 auto offset = *attrOffsetIt;
11213 bufferData.push_back(BufferDesc(attrDesc->attr_name, attrDesc->type_size,
11214 attrDesc->type_dim, offset, attrDesc->data_norm));
11215 }
11216 vbo->bufferData(std::move(bufferData), (const void *)allData,
11217 (size_t)(nvert*vertexDataSize), (size_t)vertexDataSize);
11218 break;
11219 }
11220 }
11221 free(allData);
11222
11223 CGOStop(cgo);
11224 return cgo;
11225 }
11226
11227 // CGOCheckSplitLineInterpolationIsSame:
11228 // - returns true if always the same
11229 // - returns false if not always the same
CGOCheckSplitLineInterpolationIsSame(const CGO * I,bool & interp_value)11230 bool CGOCheckSplitLineInterpolationIsSame(const CGO *I, bool &interp_value){
11231 bool interp_value_first = false;
11232 bool interp_value_is_set = false;
11233
11234 for (auto it = I->begin(); !it.is_stop(); ++it) {
11235 switch (it.op_code()) {
11236 case cgo::draw::splitline::op_code:
11237 interp_value = (it.cast<cgo::draw::splitline>()->flags & cgo::draw::splitline::interpolation);
11238 break;
11239 case CGO_INTERPOLATED:
11240 interp_value = it.cast<float>()[0] > 0.5f;
11241 break;
11242 default:
11243 continue;
11244 }
11245 if (!interp_value_is_set){
11246 interp_value_first = interp_value;
11247 interp_value_is_set = true;
11248 } else if (interp_value != interp_value_first){
11249 return false;
11250 }
11251 }
11252 return true;
11253 }
11254
11255 // CGOCheckShaderCylinderCapInfoIsSame:
11256 // - returns true if always the same
11257 // - returns false if not always the same
11258 static
CGOCheckShaderCylinderCapInfoIsSame(const CGO * I,unsigned char & cap_value)11259 bool CGOCheckShaderCylinderCapInfoIsSame(const CGO *I, unsigned char &cap_value){
11260 unsigned char cap_value_first = 0;
11261 bool cap_value_first_is_set = false;
11262
11263 for (auto it = I->begin(); !it.is_stop(); ++it) {
11264 switch (it.op_code()) {
11265 case cgo::draw::shadercylinder::op_code:
11266 cap_value = it.cast<cgo::draw::shadercylinder>()->cap;
11267 break;
11268 case cgo::draw::shadercylinder2ndcolor::op_code:
11269 cap_value = it.cast<cgo::draw::shadercylinder2ndcolor>()->cap;
11270 break;
11271 case cgo::draw::sausage::op_code:
11272 cap_value = cCylShaderBothCapsRound | cCylShaderInterpColor;
11273 break;
11274 case cgo::draw::cylinder::op_code:
11275 cap_value = cCylShaderBothCapsFlat | cCylShaderInterpColor;
11276 break;
11277 case cgo::draw::custom_cylinder::op_code:
11278 {
11279 auto cc = it.cast<cgo::draw::custom_cylinder>();
11280 int cap1 = (int) cc->cap1;
11281 int cap2 = (int) cc->cap2;
11282 cap_value = ((cap1 == 1) ? cCylShaderCap1Flat : (cap1 == 2) ? cCylShaderCap1Round : cCylCapNone) |
11283 ((cap2 == 1) ? cCylShaderCap2Flat : (cap2 == 2) ? cCylShaderCap2Round : cCylCapNone) |
11284 cCylShaderInterpColor;
11285 }
11286 break;
11287 case cgo::draw::custom_cylinder_alpha::op_code:
11288 {
11289 auto cc = it.cast<cgo::draw::custom_cylinder_alpha>();
11290 int cap1 = (int) cc->cap1;
11291 int cap2 = (int) cc->cap2;
11292 cap_value = ((cap1 == 1) ? cCylShaderCap1Flat : (cap1 == 2) ? cCylShaderCap1Round : cCylCapNone) |
11293 ((cap2 == 1) ? cCylShaderCap2Flat : (cap2 == 2) ? cCylShaderCap2Round : cCylCapNone) |
11294 cCylShaderInterpColor;
11295 }
11296 break;
11297 default:
11298 continue;
11299 }
11300
11301 if (!cap_value_first_is_set) {
11302 cap_value_first = cap_value;
11303 cap_value_first_is_set = true;
11304 } else if (cap_value != cap_value_first) {
11305 return false;
11306 }
11307 }
11308
11309 return true;
11310 }
11311
CGOConvertToTrilinesShader(const CGO * I,CGO * addTo,bool add_color)11312 CGO *CGOConvertToTrilinesShader(const CGO *I, CGO *addTo, bool add_color){
11313 PyMOLGlobals *G = I->G;
11314
11315 AttribDataOp vertexOps =
11316 { { CGO_LINE, 1, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::line, vertex1), 0 },
11317 { CGO_SPLITLINE, 2, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::splitline, vertex1), 0 } };
11318 AttribDataOp vertexOtherOps =
11319 { { CGO_LINE, 2, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::line, vertex2), 6 },
11320 { CGO_SPLITLINE, 5, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::splitline, vertex2), 6 } };
11321 AttribDataOp colorOps =
11322 { { CGO_COLOR, 0, FLOAT3_TO_UB3, 0 },
11323 { CGO_ALPHA, 0, FLOAT1_TO_UB_4TH, 0 },
11324 { CGO_SPLITLINE, 6, UB3_TO_UB3, offsetof(cgo::draw::splitline, color2) } };
11325 AttribDataOp color2Ops =
11326 { { CGO_COLOR, 1, FLOAT3_TO_UB3, 0 },
11327 { CGO_ALPHA, 1, FLOAT1_TO_UB_4TH, 0 },
11328 { CGO_SPLITLINE, 3, UB3_TO_UB3, offsetof(cgo::draw::splitline, color2) } };
11329 AttribDataOp extraPickColorOps =
11330 { { CGO_PICK_COLOR, 1, UINT_INT_TO_PICK_DATA, 0, 0 },
11331 { CGO_SPLITLINE, 7, UINT_INT_TO_PICK_DATA, offsetof(cgo::draw::splitline, index), 0 } };
11332 AttribDataOp extraPickColor2Ops =
11333 { { CGO_PICK_COLOR, 2, UINT_INT_TO_PICK_DATA, 0, 0 },
11334 { CGO_SPLITLINE, 4, UINT_INT_TO_PICK_DATA, offsetof(cgo::draw::splitline, index), 0 } };
11335 AttribDataDesc pickDesc =
11336 { { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, extraPickColorOps },
11337 { "a_Color2", GL_UNSIGNED_BYTE, 4, GL_TRUE, extraPickColor2Ops }};
11338 AttribDataDesc attrDesc =
11339 { { "a_Vertex", GL_FLOAT, 3, GL_FALSE, vertexOps },
11340 { "a_OtherVertex", GL_FLOAT, 3, GL_FALSE, vertexOtherOps },
11341 { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, colorOps },
11342 { "a_Color2", GL_UNSIGNED_BYTE, 4, GL_TRUE, color2Ops },
11343 { "a_UV", GL_UNSIGNED_BYTE, 1, GL_FALSE } };
11344
11345 if (add_color){
11346 static unsigned char default_color[] = { 255, 255, 255, 255 }; // to write in alpha if CGO doesn't have it
11347 attrDesc[2].default_value = default_color;
11348 attrDesc[3].default_value = default_color;
11349 }
11350 AttribDesc *uvdesc = &attrDesc[attrDesc.size()-1];
11351 uvdesc->repeat_value_length = 6;
11352 static unsigned char uv_bits[] = { 1, 3, 0, 3, 2, 1 };
11353 uvdesc->repeat_value = uv_bits;
11354
11355 bool interp_same, interp_value;
11356 if ((interp_same = CGOCheckSplitLineInterpolationIsSame(I, interp_value))){
11357 addTo->add<cgo::draw::vertex_attribute_1f>(G->ShaderMgr->GetAttributeUID("a_interpolate"), interp_value ? 1.f : 0.f);
11358 } else {
11359 AttribDataOp interpOps =
11360 { { CGO_SPLITLINE, 1, UB1_TO_INTERP, offsetof(cgo::draw::splitline, flags), 0 } };
11361 // need to add a_interpolate attribute
11362 attrDesc.push_back({ "a_interpolate", GL_UNSIGNED_BYTE, 1, GL_FALSE, interpOps } );
11363 }
11364 if (!add_color){
11365 attrDesc.erase(attrDesc.begin()+2); // a_Color
11366 attrDesc.erase(attrDesc.begin()+2); // a_Color2
11367 }
11368
11369 return CGOConvertToShader(I, attrDesc, pickDesc, GL_TRIANGLES, VertexBuffer::INTERLEAVED);
11370 }
11371
CGOConvertToLinesShader(const CGO * I,CGO * addTo,bool add_color)11372 CGO *CGOConvertToLinesShader(const CGO *I, CGO *addTo, bool add_color){
11373 /* Lines that pass in two vertices per line */
11374 PyMOLGlobals *G = I->G;
11375 AttribDataOp vertexOps =
11376 { { CGO_LINE, 1, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::line, vertex1), 1 },
11377 { CGO_SPLITLINE, 2, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::splitline, vertex1), 1 },
11378 { CGO_LINE, 2, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::line, vertex2), 1 },
11379 { CGO_SPLITLINE, 5, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::splitline, vertex2), 1 } };
11380 AttribDataOp colorOps =
11381 { { CGO_COLOR, 0, FLOAT3_TO_UB3, 0 },
11382 { CGO_ALPHA, 0, FLOAT1_TO_UB_4TH, 0 },
11383 { CGO_SPLITLINE, 3, UB3_TO_UB3, offsetof(cgo::draw::splitline, color2) } };
11384 AttribDataOp extraPickColorOps =
11385 { { CGO_PICK_COLOR, 1, UINT_INT_TO_PICK_DATA, 0, 0 },
11386 { CGO_SPLITLINE, 4, UINT_INT_TO_PICK_DATA, offsetof(cgo::draw::splitline, index), 0 } };
11387
11388 AttribDataDesc pickDesc =
11389 { { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, extraPickColorOps } };
11390 AttribDataDesc attrDesc =
11391 { { "a_Vertex", GL_FLOAT, 3, GL_FALSE, vertexOps },
11392 { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, colorOps } };
11393 if (add_color){
11394 static unsigned char default_color[] = { 255, 255, 255, 255 }; // to write in alpha if CGO doesn't have it
11395 attrDesc[1].default_value = default_color;
11396 }
11397 bool interp_same, interp_value;
11398 if ((interp_same = CGOCheckSplitLineInterpolationIsSame(I, interp_value))){
11399 addTo->add<cgo::draw::vertex_attribute_1f>(G->ShaderMgr->GetAttributeUID("a_interpolate"), interp_value ? 1.f : 0.f);
11400 } else {
11401 AttribDataOp interpOps =
11402 { { CGO_SPLITLINE, 1, UB1_TO_INTERP, offsetof(cgo::draw::splitline, flags), 0 } };
11403 // need to add a_interpolate attribute
11404 attrDesc.push_back({ "a_interpolate", GL_UNSIGNED_BYTE, 1, GL_FALSE, interpOps } );
11405 }
11406 #ifndef PURE_OPENGL_ES_2
11407 {
11408 attrDesc.push_back({ "a_line_position", GL_UNSIGNED_BYTE, 1, GL_FALSE } );
11409 AttribDesc *lpdesc = &attrDesc[attrDesc.size()-1];
11410 lpdesc->repeat_value_length = 2;
11411 static unsigned char flip_bits[] = { 0, 1 };
11412 lpdesc->repeat_value = flip_bits;
11413 }
11414 #endif
11415 if (!add_color){
11416 attrDesc.erase(attrDesc.begin()+1); // a_Color
11417 }
11418
11419 return CGOConvertToShader(I, attrDesc, pickDesc, GL_LINES, VertexBuffer::INTERLEAVED);
11420 }
11421
CGOConvertLinesToCylinderShader(const CGO * I,CGO * addTo,bool add_color)11422 CGO *CGOConvertLinesToCylinderShader(const CGO *I, CGO *addTo, bool add_color){
11423 /* Lines that pass in two vertices per line */
11424 PyMOLGlobals *G = I->G;
11425
11426 AttribDataOp vertex1Ops =
11427 { { CGO_LINE, 1, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::line, vertex1), 0 },
11428 { CGO_SPLITLINE, 2, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::splitline, vertex1), 0 } };
11429 AttribDataOp vertex2Ops =
11430 { { CGO_LINE, 2, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::line, vertex2), 8 },
11431 { CGO_SPLITLINE, 5, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::splitline, vertex2), 8 } };
11432 static AttribDataOp colorOps =
11433 { { CGO_COLOR, 0, FLOAT3_TO_UB3, 0 },
11434 { CGO_ALPHA, 0, FLOAT1_TO_UB_4TH, 0 },
11435 { CGO_SPLITLINE, 6, UB3_TO_UB3, offsetof(cgo::draw::splitline, color2) } };
11436 static AttribDataOp color2Ops =
11437 { { CGO_COLOR, 1, FLOAT3_TO_UB3, 0 },
11438 { CGO_ALPHA, 1, FLOAT1_TO_UB_4TH, 0 },
11439 { CGO_SPLITLINE, 3, UB3_TO_UB3, offsetof(cgo::draw::splitline, color2) } };
11440
11441 AttribDataDesc attrDesc = { { "attr_vertex1", GL_FLOAT, 3, GL_FALSE, vertex1Ops },
11442 { "attr_vertex2", GL_FLOAT, 3, GL_FALSE, vertex2Ops },
11443 { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, colorOps },
11444 { "a_Color2", GL_UNSIGNED_BYTE, 4, GL_TRUE, color2Ops },
11445 { "attr_radius", GL_FLOAT, 1, GL_FALSE } };
11446 AttribDesc *fdesc;
11447 static unsigned char cyl_flags[] = { 0, 4, 6, 2, 1, 5, 7, 3 }; // right(4)/up(2)/out(1)
11448
11449 attrDesc.push_back( { "attr_flags", GL_UNSIGNED_BYTE, 1, GL_FALSE } ) ;
11450 fdesc = &attrDesc[attrDesc.size()-1];
11451 fdesc->repeat_value = cyl_flags;
11452 fdesc->repeat_value_length = 8;
11453
11454 if (add_color){
11455 static unsigned char default_color[] = { 255, 255, 255, 255 }; // to write in alpha if CGO doesn't have it
11456 fdesc = &attrDesc[2];
11457 fdesc->default_value = default_color;
11458 fdesc = &attrDesc[3];
11459 fdesc->default_value = default_color;
11460 }
11461
11462 float default_radius = 1.f;
11463 attrDesc[4].default_value = (unsigned char*)&default_radius;
11464
11465 int box_indices[36] = { // box indices
11466 0, 2, 1, 2, 0, 3, 1, 6, 5, 6, 1, 2, 0, 1, 5, 5, 4, 0,
11467 0, 7, 3, 7, 0, 4, 3, 6, 2, 6, 3, 7, 4, 5, 6, 6, 7, 4 };
11468 int *box_indices_ptr = NULL;
11469 box_indices_ptr = box_indices;
11470
11471 bool interp_same, interp_value = false;
11472 if ((interp_same = CGOCheckSplitLineInterpolationIsSame(I, interp_value))){
11473 addTo->add<cgo::draw::vertex_attribute_1f>(G->ShaderMgr->GetAttributeUID("a_cap"), (cCylShaderBothCapsRound | (interp_value ? cCylShaderInterpColor : 0)));
11474 } else {
11475 AttribDataOp interpOps =
11476 { { CGO_SPLITLINE, 1, UB1_INTERP_TO_CAP, offsetof(cgo::draw::splitline, flags), 0 } };
11477 // need to add a_cap attribute
11478 attrDesc.push_back({ "a_cap", GL_UNSIGNED_BYTE, 1, GL_FALSE, interpOps } );
11479 }
11480
11481 if (!add_color){
11482 attrDesc.erase(attrDesc.begin()+2); // attr_colors
11483 attrDesc.erase(attrDesc.begin()+2); // attr_colors2
11484 }
11485
11486 AttribDataOp extraPickColorOps = { { CGO_PICK_COLOR, 1, UINT_INT_TO_PICK_DATA, 0, 0 },
11487 { CGO_SPLITLINE, 7, UINT_INT_TO_PICK_DATA, offsetof(cgo::draw::splitline, index), 0 } };
11488 AttribDataOp extraPickColor2Ops = { { CGO_PICK_COLOR, 2, UINT_INT_TO_PICK_DATA, 0, 0 },
11489 { CGO_SPLITLINE, 4, UINT_INT_TO_PICK_DATA, offsetof(cgo::draw::splitline, index), 0 } };
11490 AttribDataDesc pickDesc = { { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, extraPickColorOps },
11491 { "a_Color2", GL_UNSIGNED_BYTE, 4, GL_TRUE, extraPickColor2Ops }};
11492 return CGOConvertToShader(I, attrDesc, pickDesc, GL_TRIANGLES, VertexBuffer::INTERLEAVED, true, box_indices_ptr, 36);
11493 }
11494
11495 struct CrossSizeData {
11496 float cross_size;
11497 bool forward;
CrossSizeDataCrossSizeData11498 CrossSizeData(float _cross_size, bool _forward) : cross_size(_cross_size), forward(_forward){ }
11499 };
11500
CrossVertexConversion(void * varData,const float * pc,void * crossData,int idx)11501 static void CrossVertexConversion(void *varData, const float * pc, void *crossData, int idx){
11502 CrossSizeData *csd = (CrossSizeData*)crossData;
11503 int idxpl = idx / 8; // X Y or Z
11504 float *varDataF = ((float*)varData);
11505 varDataF[idxpl] += (csd->forward ? csd->cross_size : -csd->cross_size);
11506 }
11507
CGOConvertCrossesToCylinderShader(const CGO * I,CGO * addTo,float cross_size_arg)11508 CGO *CGOConvertCrossesToCylinderShader(const CGO *I, CGO *addTo, float cross_size_arg){
11509 /* Lines that pass in two vertices per line */
11510 PyMOLGlobals *G = I->G;
11511 AttribDataOp vertex1Ops =
11512 { { CGO_VERTEX_CROSS, 1, FLOAT3_TO_FLOAT3, 0, 0 } };
11513 AttribDataOp vertex2Ops =
11514 { { CGO_VERTEX_CROSS, 2, FLOAT3_TO_FLOAT3, 0, 3 * 8, 0 } };
11515
11516 static AttribDataOp colorOps =
11517 { { CGO_COLOR, 0, FLOAT3_TO_UB3, 0 },
11518 { CGO_ALPHA, 0, FLOAT1_TO_UB_4TH, 0 } };
11519 static AttribDataOp color2Ops =
11520 { { CGO_COLOR, 1, FLOAT3_TO_UB3, 0 },
11521 { CGO_ALPHA, 1, FLOAT1_TO_UB_4TH, 0 } };
11522
11523 CrossSizeData crossData[] = { { cross_size_arg, false }, { cross_size_arg, true } };
11524 AttribDataDesc attrDesc = { { "attr_vertex1", GL_FLOAT, 3, GL_FALSE, vertex1Ops },
11525 { "attr_vertex2", GL_FLOAT, 3, GL_FALSE, vertex2Ops },
11526 { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, colorOps },
11527 { "a_Color2", GL_UNSIGNED_BYTE, 4, GL_TRUE, color2Ops },
11528 { "attr_radius", GL_FLOAT, 1, GL_FALSE } };
11529 attrDesc.reserve(10);
11530 attrDesc[1].attrOps[0].funcDataConversions.push_back( { CrossVertexConversion, &crossData[0], "attr_vertex1" } );
11531 attrDesc[1].attrOps[0].funcDataConversions.push_back( { CrossVertexConversion, &crossData[1], "attr_vertex2" } );
11532
11533 AttribDesc *fdesc;
11534 static unsigned char cyl_flags[] = { 0, 4, 6, 2, 1, 5, 7, 3 }; // right(4)/up(2)/out(1)
11535
11536 attrDesc.push_back( { "attr_flags", GL_UNSIGNED_BYTE, 1, GL_FALSE } ) ;
11537 fdesc = &attrDesc[attrDesc.size()-1];
11538 fdesc->repeat_value = cyl_flags;
11539 fdesc->repeat_value_length = 8;
11540
11541 unsigned char default_color[] = { 255, 255, 255, 255 }; // to write in alpha if CGO doesn't have it
11542 fdesc = &attrDesc[2];
11543 fdesc->default_value = default_color;
11544 fdesc = &attrDesc[3];
11545 fdesc->default_value = default_color;
11546 float default_radius = 1.f;
11547 attrDesc[4].default_value = (unsigned char*)&default_radius;
11548
11549 int box_indices[36] = { // box indices
11550 0, 2, 1, 2, 0, 3, 1, 6, 5, 6, 1, 2, 0, 1, 5, 5, 4, 0,
11551 0, 7, 3, 7, 0, 4, 3, 6, 2, 6, 3, 7, 4, 5, 6, 6, 7, 4 };
11552 int *box_indices_ptr = NULL;
11553 box_indices_ptr = box_indices;
11554
11555 addTo->add<cgo::draw::vertex_attribute_1f>(G->ShaderMgr->GetAttributeUID("a_cap"), cCylShaderBothCapsRound);
11556
11557 AttribDataOp extraPickColorOps = { { CGO_PICK_COLOR, 1, UINT_INT_TO_PICK_DATA, 0, 0 } };
11558 AttribDataOp extraPickColor2Ops = { { CGO_PICK_COLOR, 2, UINT_INT_TO_PICK_DATA, 0, 0 } };
11559 AttribDataDesc pickDesc = { { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, extraPickColorOps },
11560 { "a_Color2", GL_UNSIGNED_BYTE, 4, GL_TRUE, extraPickColor2Ops }};
11561 return CGOConvertToShader(I, attrDesc, pickDesc, GL_TRIANGLES, VertexBuffer::INTERLEAVED, true, box_indices_ptr, 36, 3);
11562 }
11563
11564 struct CrossSizeDataLines {
11565 float cross_size;
CrossSizeDataLinesCrossSizeDataLines11566 CrossSizeDataLines(float _cross_size) : cross_size(_cross_size){ }
11567 };
11568
CrossVertexConversionLines(void * varData,const float * pc,void * crossData,int idx)11569 static void CrossVertexConversionLines(void *varData, const float * pc, void *crossData, int idx){
11570 CrossSizeDataLines *csd = (CrossSizeDataLines*)crossData;
11571 int idxpl = idx / 2; // X Y or Z
11572 bool forward = idx % 2;
11573 float *varDataF = ((float*)varData);
11574 varDataF[idxpl] += (forward ? csd->cross_size : -csd->cross_size);
11575 }
11576
CGOConvertCrossesToLinesShader(const CGO * I,CGO * addTo,float cross_size_arg)11577 CGO *CGOConvertCrossesToLinesShader(const CGO *I, CGO *addTo, float cross_size_arg){
11578 /* Lines that pass in two vertices per line */
11579 PyMOLGlobals *G = I->G;
11580 AttribDataOp vertexOps =
11581 { { CGO_VERTEX_CROSS, 1, FLOAT3_TO_FLOAT3, 0, 6 } }; // 6 vertices for a cross
11582 AttribDataOp colorOps =
11583 { { CGO_COLOR, 0, FLOAT3_TO_UB3, 0 },
11584 { CGO_ALPHA, 0, FLOAT1_TO_UB_4TH, 0 } };
11585 AttribDataOp extraPickColorOps =
11586 { { CGO_PICK_COLOR, 1, UINT_INT_TO_PICK_DATA, 0, 0 } };
11587
11588 AttribDataDesc pickDesc =
11589 { { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, extraPickColorOps } };
11590 AttribDataDesc attrDesc =
11591 { { "a_Vertex", GL_FLOAT, 3, GL_FALSE, vertexOps },
11592 { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, colorOps } };
11593 unsigned char default_color[] = { 255, 255, 255, 255 }; // to write in alpha if CGO doesn't have it
11594 attrDesc[1].default_value = default_color;
11595
11596 CrossSizeDataLines crossData = { cross_size_arg };
11597 attrDesc[0].attrOps[0].funcDataConversions.push_back( { CrossVertexConversionLines, &crossData, "a_Vertex" } );
11598
11599 bool interp_same, interp_value = false;
11600 if ((interp_same = CGOCheckSplitLineInterpolationIsSame(I, interp_value))){
11601 addTo->add<cgo::draw::vertex_attribute_1f>(G->ShaderMgr->GetAttributeUID("a_interpolate"), interp_value ? 1.f : 0.f);
11602 } else {
11603 AttribDataOp interpOps =
11604 { { CGO_SPLITLINE, 1, UB1_TO_INTERP, offsetof(cgo::draw::splitline, flags), 0 } };
11605 // need to add a_interpolate attribute
11606 attrDesc.push_back({ "a_interpolate", GL_UNSIGNED_BYTE, 1, GL_FALSE, interpOps } );
11607 }
11608 #ifndef PURE_OPENGL_ES_2
11609 {
11610 attrDesc.push_back({ "a_line_position", GL_UNSIGNED_BYTE, 1, GL_FALSE } );
11611 AttribDesc *lpdesc = &attrDesc[attrDesc.size()-1];
11612 lpdesc->repeat_value_length = 2;
11613 static unsigned char flip_bits[] = { 0, 1 };
11614 lpdesc->repeat_value = flip_bits;
11615 }
11616 #endif
11617 return CGOConvertToShader(I, attrDesc, pickDesc, GL_LINES, VertexBuffer::INTERLEAVED);
11618 }
11619
CrossVertexConversionTrilines(void * varData,const float * pc,void * crossData,int idx)11620 static void CrossVertexConversionTrilines(void *varData, const float * pc, void *crossData, int idx){
11621 CrossSizeData *csd = (CrossSizeData*)crossData;
11622 int idxpl = idx / 6; // X Y or Z
11623 float *varDataF = ((float*)varData);
11624 varDataF[idxpl] += (csd->forward ? csd->cross_size : -csd->cross_size);
11625 }
11626
CGOConvertCrossesToTrilinesShader(const CGO * I,CGO * addTo,float cross_size_arg)11627 CGO *CGOConvertCrossesToTrilinesShader(const CGO *I, CGO *addTo, float cross_size_arg){
11628 PyMOLGlobals *G = I->G;
11629
11630 AttribDataOp vertexOps =
11631 { { CGO_VERTEX_CROSS, 1, FLOAT3_TO_FLOAT3, 0, 0 } };
11632 AttribDataOp vertexOtherOps =
11633 { { CGO_VERTEX_CROSS, 2, FLOAT3_TO_FLOAT3, 0, 6 * 3 } };
11634 AttribDataOp colorOps =
11635 { { CGO_COLOR, 0, FLOAT3_TO_UB3, 0 },
11636 { CGO_ALPHA, 0, FLOAT1_TO_UB_4TH, 0 } };
11637 AttribDataOp color2Ops =
11638 { { CGO_COLOR, 1, FLOAT3_TO_UB3, 0 },
11639 { CGO_ALPHA, 1, FLOAT1_TO_UB_4TH, 0 } };
11640 AttribDataOp extraPickColorOps =
11641 { { CGO_PICK_COLOR, 1, UINT_INT_TO_PICK_DATA, 0, 0 } };
11642 AttribDataOp extraPickColor2Ops =
11643 { { CGO_PICK_COLOR, 2, UINT_INT_TO_PICK_DATA, 0, 0 } };
11644 AttribDataDesc pickDesc =
11645 { { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, extraPickColorOps },
11646 { "a_Color2", GL_UNSIGNED_BYTE, 4, GL_TRUE, extraPickColor2Ops } };
11647 AttribDataDesc attrDesc =
11648 { { "a_Vertex", GL_FLOAT, 3, GL_FALSE, vertexOps },
11649 { "a_OtherVertex", GL_FLOAT, 3, GL_FALSE, vertexOtherOps },
11650 { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, colorOps },
11651 { "a_Color2", GL_UNSIGNED_BYTE, 4, GL_TRUE, color2Ops },
11652 { "a_UV", GL_UNSIGNED_BYTE, 1, GL_FALSE } };
11653
11654 CrossSizeData crossData[] = { { cross_size_arg, false }, { cross_size_arg, true } };
11655
11656 attrDesc[1].attrOps[0].funcDataConversions.push_back( { CrossVertexConversionTrilines, &crossData[0], "a_Vertex" } );
11657 attrDesc[1].attrOps[0].funcDataConversions.push_back( { CrossVertexConversionTrilines, &crossData[1], "a_OtherVertex" } );
11658
11659 unsigned char default_color[] = { 255, 255, 255, 255 }; // to write in alpha if CGO doesn't have it
11660 attrDesc[2].default_value = default_color;
11661 attrDesc[3].default_value = default_color;
11662
11663 AttribDesc *uvdesc = &attrDesc[attrDesc.size()-1];
11664 uvdesc->repeat_value_length = 6;
11665 static unsigned char uv_bits[] = { 1, 3, 0, 3, 2, 1 };
11666 uvdesc->repeat_value = uv_bits;
11667
11668 addTo->add<cgo::draw::vertex_attribute_1f>(G->ShaderMgr->GetAttributeUID("a_interpolate"), 0.f);
11669
11670 return CGOConvertToShader(I, attrDesc, pickDesc, GL_TRIANGLES, VertexBuffer::INTERLEAVED);
11671 }
11672
shadercylinder2ndcolor(CGO * I,const float * _origin,const float * _axis,const float _tube_size,int _cap,const float * _color2,Pickable * pickcolor2,const float _alpha)11673 cgo::draw::shadercylinder2ndcolor::shadercylinder2ndcolor(CGO *I, const float *_origin,
11674 const float *_axis, const float _tube_size,
11675 int _cap, const float *_color2, Pickable *pickcolor2,
11676 const float _alpha) :
11677 tube_size(_tube_size), alpha(_alpha) {
11678 copy3f(_origin, origin);
11679 copy3f(_axis, axis);
11680 cap = _cap;
11681 copy3f(_color2, color2);
11682 if (pickcolor2){
11683 I->current_pick_color_index = pick_color_index = pickcolor2->index;
11684 I->current_pick_color_bond = pick_color_bond = pickcolor2->bond;
11685 } else {
11686 pick_color_index = I->current_pick_color_index;
11687 pick_color_bond = I->current_pick_color_bond;
11688 }
11689 };
11690
SetVertexFromOriginAxisForCylinder(void * varData,const float * pc,void * np,int idx)11691 static void SetVertexFromOriginAxisForCylinder(void *varData, const float * pc, void *np, int idx){
11692 float *varDataF = ((float*)varData);
11693 add3f(pc, pc + 3, varDataF); // adding origin and axis for both shadercylinder and shadercylinder2ndcolor
11694 }
11695
11696 /*
11697 * converts all cylinders in the input CGO to a CGO custom operation, which includes picking information (if it exists)
11698 *
11699 * I - input CGO (includes cylinders)
11700 * addTo - CGO that vertex_attribute operations are added to (if needed), in this case for caps if values for all
11701 * cylinders are the same
11702 *
11703 */
CGOConvertShaderCylindersToCylinderShader(const CGO * I,CGO * addTo)11704 CGO *CGOConvertShaderCylindersToCylinderShader(const CGO *I, CGO *addTo){
11705 /* Lines that pass in two vertices per line */
11706 PyMOLGlobals *G = I->G;
11707
11708 // TODO: NEED TO ADD: CGO_CUSTOM_CYLINDER and CGO_CYLINDER
11709 AttribDataOp vertex1Ops =
11710 { { CGO_SHADER_CYLINDER, 1, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::shadercylinder, origin), 0 },
11711 { CGO_SHADER_CYLINDER_WITH_2ND_COLOR, 1, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::shadercylinder2ndcolor, origin), 0 },
11712 { CGO_SAUSAGE, 1, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::sausage, vertex1), 0 },
11713 { CGO_CYLINDER, 1, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::cylinder, vertex1), 0 },
11714 { CGO_CUSTOM_CYLINDER, 1, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::custom_cylinder, vertex1), 0 },
11715 { CGO_CUSTOM_CYLINDER_ALPHA, 1, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::custom_cylinder_alpha, vertex1), 0 } };
11716 AttribDataOp vertex2Ops =
11717 { { CGO_SHADER_CYLINDER, 5, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::shadercylinder, axis), 8 },
11718 { CGO_SHADER_CYLINDER_WITH_2ND_COLOR, 6, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::shadercylinder2ndcolor, axis), 8 },
11719 { CGO_SAUSAGE, 6, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::sausage, vertex2), 8 },
11720 { CGO_CYLINDER, 6, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::cylinder, vertex2), 8 },
11721 { CGO_CUSTOM_CYLINDER, 6, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::custom_cylinder, vertex2), 8 },
11722 { CGO_CUSTOM_CYLINDER_ALPHA, 6, FLOAT3_TO_FLOAT3, offsetof(cgo::draw::custom_cylinder_alpha, vertex2), 8 } };
11723 static AttribDataOp colorOps =
11724 { { CGO_COLOR, 0, FLOAT3_TO_UB3, 0 },
11725 { CGO_ALPHA, 0, FLOAT1_TO_UB_4TH, 0 },
11726 { CGO_SAUSAGE, 4, FLOAT3_TO_UB3, offsetof(cgo::draw::sausage, color1) },
11727 { CGO_CYLINDER, 4, FLOAT3_TO_UB3, offsetof(cgo::draw::cylinder, color1) },
11728 { CGO_CUSTOM_CYLINDER, 4, FLOAT3_TO_UB3, offsetof(cgo::draw::custom_cylinder, color1) },
11729 { CGO_CUSTOM_CYLINDER_ALPHA, 4, FLOAT4_TO_UB4, offsetof(cgo::draw::custom_cylinder_alpha, color1) } };
11730 static AttribDataOp color2Ops =
11731 { { CGO_COLOR, 1, FLOAT3_TO_UB3, 0 },
11732 { CGO_ALPHA, 1, FLOAT1_TO_UB_4TH, 0 },
11733 { CGO_SHADER_CYLINDER_WITH_2ND_COLOR, 2, FLOAT3_TO_UB3, offsetof(cgo::draw::shadercylinder2ndcolor, color2) },
11734 { CGO_SAUSAGE, 5, FLOAT3_TO_UB3, offsetof(cgo::draw::sausage, color2) },
11735 { CGO_CYLINDER, 5, FLOAT3_TO_UB3, offsetof(cgo::draw::cylinder, color2) },
11736 { CGO_CUSTOM_CYLINDER, 5, FLOAT3_TO_UB3, offsetof(cgo::draw::custom_cylinder, color2) },
11737 { CGO_CUSTOM_CYLINDER_ALPHA, 5, FLOAT4_TO_UB4, offsetof(cgo::draw::custom_cylinder_alpha, color2) } };
11738 AttribDataOp radiusOps =
11739 { { CGO_SHADER_CYLINDER, 2, FLOAT_TO_FLOAT, offsetof(cgo::draw::shadercylinder, tube_size), 0 },
11740 { CGO_SHADER_CYLINDER_WITH_2ND_COLOR, 3, FLOAT_TO_FLOAT, offsetof(cgo::draw::shadercylinder2ndcolor, tube_size), 0 },
11741 { CGO_SAUSAGE, 3, FLOAT_TO_FLOAT, offsetof(cgo::draw::sausage, radius), 0 },
11742 { CGO_CYLINDER, 3, FLOAT_TO_FLOAT, offsetof(cgo::draw::cylinder, radius), 0 },
11743 { CGO_CUSTOM_CYLINDER, 3, FLOAT_TO_FLOAT, offsetof(cgo::draw::custom_cylinder, radius), 0 },
11744 { CGO_CUSTOM_CYLINDER_ALPHA, 3, FLOAT_TO_FLOAT, offsetof(cgo::draw::custom_cylinder_alpha, radius), 0 } };
11745
11746 AttribDataDesc attrDesc = { { "attr_vertex1", GL_FLOAT, 3, GL_FALSE, vertex1Ops },
11747 { "attr_vertex2", GL_FLOAT, 3, GL_FALSE, vertex2Ops },
11748 { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, colorOps },
11749 { "a_Color2", GL_UNSIGNED_BYTE, 4, GL_TRUE, color2Ops },
11750 { "attr_radius", GL_FLOAT, 1, GL_FALSE, radiusOps } };
11751 AttribDesc *fdesc;
11752 static unsigned char cyl_flags[] = { 0, 4, 6, 2, 1, 5, 7, 3 }; // right(4)/up(2)/out(1)
11753
11754 attrDesc[1].attrOps[0].funcDataConversions.push_back( { SetVertexFromOriginAxisForCylinder, NULL, "attr_vertex2" } );
11755 attrDesc[1].attrOps[1].funcDataConversions.push_back( { SetVertexFromOriginAxisForCylinder, NULL, "attr_vertex2" } );
11756
11757 attrDesc.push_back( { "attr_flags", GL_UNSIGNED_BYTE, 1, GL_FALSE } ) ;
11758 fdesc = &attrDesc[attrDesc.size()-1];
11759 fdesc->repeat_value = cyl_flags;
11760 fdesc->repeat_value_length = 8;
11761
11762 unsigned char default_color[] = { 255, 255, 255, 255 }; // to write in alpha if CGO doesn't have it
11763 fdesc = &attrDesc[2];
11764 fdesc->default_value = default_color;
11765 fdesc = &attrDesc[3];
11766 fdesc->default_value = default_color;
11767 float default_radius = 1.f;
11768 attrDesc[4].default_value = (unsigned char*)&default_radius;
11769
11770 int box_indices[36] = { // box indices
11771 0, 2, 1, 2, 0, 3, 1, 6, 5, 6, 1, 2, 0, 1, 5, 5, 4, 0,
11772 0, 7, 3, 7, 0, 4, 3, 6, 2, 6, 3, 7, 4, 5, 6, 6, 7, 4 };
11773 int *box_indices_ptr = NULL;
11774 box_indices_ptr = box_indices;
11775
11776 bool interp_same;
11777 unsigned char cap_value = 0;
11778 if ((interp_same = CGOCheckShaderCylinderCapInfoIsSame(I, cap_value))){
11779 addTo->add<cgo::draw::vertex_attribute_1f>(G->ShaderMgr->GetAttributeUID("a_cap"), cap_value );
11780 } else {
11781 AttribDataOp interpOps =
11782 { { CGO_SHADER_CYLINDER, 3, CYL_CAP_TO_CAP, offsetof(cgo::draw::shadercylinder, cap), 0 },
11783 { CGO_SHADER_CYLINDER_WITH_2ND_COLOR, 4, CYL_CAP_TO_CAP, offsetof(cgo::draw::shadercylinder2ndcolor, cap), 0 },
11784 { CGO_SAUSAGE, 2, CYL_CAPS_ARE_ROUND, 0, 0 },
11785 { CGO_CYLINDER, 2, CYL_CAPS_ARE_FLAT, 0, 0 },
11786 { CGO_CUSTOM_CYLINDER, 2, CYL_CAPS_ARE_CUSTOM, offsetof(cgo::draw::custom_cylinder, cap1), 0 },
11787 { CGO_CUSTOM_CYLINDER_ALPHA, 2, CYL_CAPS_ARE_CUSTOM, offsetof(cgo::draw::custom_cylinder_alpha, cap1), 0 },
11788 };
11789 attrDesc.push_back({ "a_cap", GL_UNSIGNED_BYTE, 1, GL_FALSE, interpOps } );
11790 }
11791
11792 AttribDataOp extraPickColorOps = { { CGO_PICK_COLOR, 1, UINT_INT_TO_PICK_DATA, 0, 0 },
11793 { CGO_SHADER_CYLINDER_WITH_2ND_COLOR, 8, UINT_INT_TO_PICK_DATA, offsetof(cgo::draw::shadercylinder2ndcolor, pick_color_index), 0 } };
11794 AttribDataOp extraPickColor2Ops = { { CGO_PICK_COLOR, 2, UINT_INT_TO_PICK_DATA, 0, 0 },
11795 { CGO_SHADER_CYLINDER_WITH_2ND_COLOR, 5, UINT_INT_TO_PICK_DATA, offsetof(cgo::draw::shadercylinder2ndcolor, pick_color_index), 0 } };
11796 AttribDataDesc pickDesc = { { "a_Color", GL_UNSIGNED_BYTE, 4, GL_TRUE, extraPickColorOps },
11797 { "a_Color2", GL_UNSIGNED_BYTE, 4, GL_TRUE, extraPickColor2Ops }};
11798 return CGOConvertToShader(I, attrDesc, pickDesc, GL_TRIANGLES, VertexBuffer::INTERLEAVED, true, box_indices_ptr, 36);
11799 }
11800
11801 /**
11802 * CGO iterator increment
11803 */
operator ++()11804 CGO::const_iterator& CGO::const_iterator::operator++()
11805 {
11806 const unsigned op = op_code();
11807
11808 // Corrupted OP codes should never make it into a CGO, so we don't want to
11809 // handle this gracefully. Only import of CGOs (from PSEs, from Python, etc.)
11810 // should handle invalid codes gracefully.
11811 assert(op < CGO_sz_size());
11812
11813 m_pc += CGO_sz[op] + 1;
11814 return *this;
11815 }
11816