1 
2 #include"Scene.h"
3 #include"SceneRay.h"
4 #include"SceneDef.h"
5 #include"Util.h"
6 #include"ShaderMgr.h"
7 #include"Matrix.h"
8 #include"PyMOL.h"
9 #include"ListMacros.h"
10 #include"Color.h"
11 #include"P.h"
12 
13 static double accumTiming = 0.0;
14 
15 /* EXPERIMENTAL VOLUME RAYTRACING DATA */
16 static std::shared_ptr<pymol::Image> rayVolumeImage;
17 extern float *rayDepthPixels;
18 extern int rayVolume, rayWidth, rayHeight;
19 
20 
SceneRaySetRayView(PyMOLGlobals * G,CScene * I,int stereo_hand,float * rayView,float * angle,float shift)21 static void SceneRaySetRayView(PyMOLGlobals * G, CScene *I, int stereo_hand,
22     float *rayView, float *angle, float shift)
23 {
24   /* start afresh, looking in the negative Z direction (0,0,-1) from (0,0,0) */
25   identity44f(rayView);
26 
27   if(stereo_hand) {
28     /* stereo */
29 
30     float stAng, stShift;
31     stAng = SettingGetGlobal_f(G, cSetting_stereo_angle);
32     stShift = SettingGetGlobal_f(G, cSetting_stereo_shift);
33     /* right hand */
34     stShift = (float) (stShift * fabs(I->m_view.m_pos[2]) / 100.0);
35     stAng = (float) (stAng * atan(stShift / fabs(I->m_view.m_pos[2])) * 90.0 / cPI);
36     if(stereo_hand == 2) {  /* left hand */
37       stAng = -stAng;
38       stShift = -stShift;
39     }
40     *angle = stAng;
41     {
42       float temp[16];
43       identity44f(temp);
44       MatrixRotateC44f(temp, (float) (-PI * stAng / 180), 0.0F, 1.0F, 0.0F);        /* y-axis rotation */
45       MatrixMultiplyC44f(temp, rayView);
46     }
47     /* move the camera to the location we are looking at */
48     MatrixTranslateC44f(rayView, I->m_view.m_pos[0], I->m_view.m_pos[1], I->m_view.m_pos[2]);
49     MatrixTranslateC44f(rayView, stShift, 0.0, 0.0);
50     MatrixMultiplyC44f(I->m_view.m_rotMatrix, rayView);
51   } else {                  /* not stereo mode */
52     /* move the camera to the location we are looking at */
53     MatrixTranslateC44f(rayView, I->m_view.m_pos[0], I->m_view.m_pos[1], I->m_view.m_pos[2]);
54     if(shift) {
55       MatrixTranslateC44f(rayView, shift, 0.0F, 0.0F);
56     }
57     /* move the camera so that we can see the origin
58      * NOTE, vector is given in the coordinates of the world's motion
59      * relative to the camera */
60     /* 4. rotate about the origin (the the center of rotation) */
61     if(*angle) {
62       float temp[16];
63       identity44f(temp);
64       MatrixRotateC44f(temp, (float) (-PI * *angle / 180), 0.0F, 1.0F, 0.0F);
65       MatrixMultiplyC44f(I->m_view.m_rotMatrix, temp);
66       MatrixMultiplyC44f(temp, rayView);
67     } else {
68       MatrixMultiplyC44f(I->m_view.m_rotMatrix, rayView);
69     }
70   }
71   /* 5. move the origin to the center of rotation */
72   MatrixTranslateC44f(rayView, -I->m_view.m_origin[0], -I->m_view.m_origin[1], -I->m_view.m_origin[2]);
73 
74   if(Feedback(G, FB_Scene, FB_Debugging)) {
75     fprintf(stderr, "SceneRay: %8.3f %8.3f %8.3f\n", I->m_view.m_pos[0], I->m_view.m_pos[1], I->m_view.m_pos[2]);
76     fprintf(stderr, "SceneRay: %8.3f %8.3f %8.3f\n",
77 	    I->m_view.m_origin[0], I->m_view.m_origin[1], I->m_view.m_origin[2]);
78     fprintf(stderr, "SceneRay: %8.3f %8.3f %8.3f\n",
79 	    I->m_view.m_rotMatrix[0], I->m_view.m_rotMatrix[1], I->m_view.m_rotMatrix[2]);
80   }
81 }
82 
SceneRay(PyMOLGlobals * G,int ray_width,int ray_height,int mode,char ** headerVLA_ptr,char ** charVLA_ptr,float angle,float shift,int quiet,G3dPrimitive ** g3d,int show_timing,int antialias)83 bool SceneRay(PyMOLGlobals * G,
84               int ray_width, int ray_height, int mode,
85               char **headerVLA_ptr,
86               char **charVLA_ptr, float angle,
87               float shift, int quiet, G3dPrimitive ** g3d, int show_timing, int antialias)
88 {
89 #ifdef _PYMOL_NO_RAY
90   FeedbackAdd(G, "" _PYMOL_NO_RAY);
91   return false;
92 #else
93 
94   CScene *I = G->Scene;
95   CRay *ray = NULL;
96   float height, width;
97   float aspRat;
98   float rayView[16];
99   double timing;
100   char *charVLA = NULL;
101   char *headerVLA = NULL;
102   float fov;
103   int stereo_hand = 0;
104   int grid_mode = SettingGetGlobal_i(G, cSetting_grid_mode);
105   std::shared_ptr<pymol::Image> stereo_image;
106   OrthoLineType prefix = "";
107   int ortho = SettingGetGlobal_i(G, cSetting_ray_orthoscopic);
108   int last_grid_active = I->grid.active;
109   int grid_size = 0;
110 
111   if(SettingGetGlobal_i(G, cSetting_defer_builds_mode) == 5)
112     SceneUpdate(G, true);
113 
114   if(ortho < 0)
115     ortho = SettingGetGlobal_b(G, cSetting_ortho);
116 
117   if(mode != 0)
118     grid_mode = 0;              /* only allow grid mode with PyMOL renderer */
119 
120   SceneUpdateAnimation(G);
121 
122   if(mode == 0)
123     SceneInvalidateCopy(G, true);
124 
125   if(antialias < 0) {
126     antialias = SettingGetGlobal_i(G, cSetting_antialias);
127   }
128   if(ray_width < 0)
129     ray_width = 0;
130   if(ray_height < 0)
131     ray_height = 0;
132   if((!ray_width) || (!ray_height)) {
133     if(ray_width && (!ray_height)) {
134       ray_height = (ray_width * I->Height) / I->Width;
135     } else if(ray_height && (!ray_width)) {
136       ray_width = (ray_height * I->Width) / I->Height;
137     } else {
138       ray_width = I->Width;
139       ray_height = I->Height;
140     }
141   }
142 
143   fov = SettingGetGlobal_f(G, cSetting_field_of_view);
144 
145   timing = UtilGetSeconds(G);   /* start timing the process */
146 
147   SceneUpdate(G, false);
148 
149   switch (I->StereoMode) {
150   case cStereo_quadbuffer:
151   case cStereo_openvr:
152     stereo_hand = 2;
153     break;
154   case cStereo_crosseye:
155   case cStereo_walleye:
156     ray_width = ray_width / 2;
157     stereo_hand = 2;
158     break;
159   case cStereo_geowall:
160   case cStereo_sidebyside:
161     stereo_hand = 2;
162     break;
163   case cStereo_stencil_by_row:
164   case cStereo_stencil_by_column:
165   case cStereo_stencil_checkerboard:
166   case cStereo_stencil_custom:
167   case cStereo_anaglyph:
168     stereo_hand = 2;
169     break;
170   }
171 
172   aspRat = ((float) ray_width) / ((float) ray_height);
173 
174   if(grid_mode) {
175     grid_size = SceneGetGridSize(G, grid_mode);
176     GridUpdate(&I->grid, aspRat, grid_mode, grid_size);
177     if(I->grid.active)
178       aspRat *= I->grid.asp_adjust;
179   }
180   if (last_grid_active != I->grid.active || grid_size != I->last_grid_size){
181     //    ExecutiveInvalidateRep(G, cKeywordAll, cRepLabel, cRepInvAll);
182     G->ShaderMgr->ResetUniformSet();
183   }
184   I->last_grid_size = grid_size;
185   while(1) {
186     int slot;
187     int tot_width = ray_width;
188     int tot_height = ray_height;
189     int ray_x = 0, ray_y = 0;
190 
191     if(I->grid.active)
192       GridGetRayViewport(&I->grid, ray_width, ray_height);
193 
194     for(slot = 0; slot <= I->grid.last_slot; slot++) {
195 
196       if(I->grid.active) {
197         GridSetRayViewport(&I->grid, slot, &ray_x, &ray_y, &ray_width, &ray_height);
198         OrthoBusySlow(G, slot, I->grid.last_slot);
199       }
200 
201       ray = RayNew(G, antialias);
202       if(!ray)
203         break;
204 
205       SceneRaySetRayView(G, I, stereo_hand, rayView, &angle, shift);
206 
207       /* define the viewing volume */
208 
209       height = (float) (fabs(I->m_view.m_pos[2]) * tan((fov / 2.0) * cPI / 180.0));
210       width = height * aspRat;
211       PyMOL_SetBusy(G->PyMOL, true);
212       OrthoBusyFast(G, 0, 20);
213 
214       {
215         float pixel_scale_value = SettingGetGlobal_f(G, cSetting_ray_pixel_scale);
216 
217         if(pixel_scale_value < 0)
218           pixel_scale_value = 1.0F;
219 
220         pixel_scale_value *= ((float) tot_height) / I->Height;
221 
222         if(ortho) {
223           const float _1 = 1.0F;
224           RayPrepare(ray, -width, width, -height, height, I->m_view.m_clipSafe.m_front,
225                      I->m_view.m_clipSafe.m_back, fov,  I->m_view.m_pos, rayView, I->m_view.m_rotMatrix,
226                      aspRat, ray_width, ray_height,
227                      pixel_scale_value, ortho, _1, _1,
228                      ((float) ray_height) / I->Height);
229         } else {
230           float back_ratio;
231           float back_height;
232           float back_width;
233           float pos;
234           pos = I->m_view.m_pos[2];
235 
236           if((-pos) < I->m_view.m_clipSafe.m_front) {
237             pos = -I->m_view.m_clipSafe.m_front;
238           }
239 
240           back_ratio = -I->m_view.m_clipSafe.m_back / pos;
241           back_height = back_ratio * height;
242           back_width = aspRat * back_height;
243           RayPrepare(ray,
244                      -back_width, back_width,
245                      -back_height, back_height,
246                      I->m_view.m_clipSafe.m_front, I->m_view.m_clipSafe.m_back,
247                      fov, I->m_view.m_pos,
248                      rayView, I->m_view.m_rotMatrix, aspRat,
249                      ray_width, ray_height,
250                      pixel_scale_value, ortho,
251                      height / back_height,
252                      I->m_view.m_clipSafe.m_front / I->m_view.m_clipSafe.m_back, ((float) ray_height) / I->Height);
253         }
254       }
255       {
256         int *slot_vla = I->SlotVLA;
257         int state = SceneGetState(G);
258         RenderInfo info;
259         UtilZeroMem(&info, sizeof(RenderInfo));
260         info.ray = ray;
261         info.ortho = ortho;
262         info.vertex_scale = SceneGetScreenVertexScale(G, NULL);
263 	info.use_shaders = SettingGetGlobal_b(G, cSetting_use_shaders);
264 
265         if(SettingGetGlobal_b(G, cSetting_dynamic_width)) {
266           info.dynamic_width = true;
267           info.dynamic_width_factor =
268             SettingGetGlobal_f(G, cSetting_dynamic_width_factor);
269           info.dynamic_width_min = SettingGetGlobal_f(G, cSetting_dynamic_width_min);
270           info.dynamic_width_max = SettingGetGlobal_f(G, cSetting_dynamic_width_max);
271         }
272 
273         for (auto* obj : I->Obj) {
274           // ObjectGroup used to have fRender = NULL
275           if (obj->type != cObjectGroup) {
276             if(SceneGetDrawFlag(&I->grid, slot_vla, obj->grid_slot)) {
277               float color[3];
278               ColorGetEncoded(G, obj->Color, color);
279               RaySetContext(ray, obj->Context);
280               ray->color3fv(color);
281 
282               auto icx = SettingGetWD<int>(
283                   obj->Setting, cSetting_ray_interior_color, cColorDefault);
284 
285               if (icx == cColorDefault) {
286                 ray->interiorColor3fv(color, true);
287               } else if (icx == cColorObject) {
288                 ray->interiorColor3fv(color, false);
289               } else {
290                 float icolor[3];
291                 ColorGetEncoded(G, icx, icolor);
292                 ray->interiorColor3fv(icolor, false);
293               }
294 
295               if((!I->grid.active) || (I->grid.mode < 2)) {
296                 info.state = ObjectGetCurrentState(obj, false);
297                 obj->render(&info);
298               } else if(I->grid.slot) {
299                 if (I->grid.mode == 2) {
300                   if((info.state = state + I->grid.slot - 1) >= 0)
301                     obj->render(&info);
302                 } else if (I->grid.mode == 3) {
303                   info.state = I->grid.slot - obj->grid_slot - 1;
304                   if (info.state >= 0 && info.state < obj->getNFrame())
305                     obj->render(&info);
306                 }
307               }
308             }
309           }
310         }
311       }
312 
313       OrthoBusyFast(G, 1, 20);
314 
315       if(mode != 2) {           /* don't show pixel count for tests */
316         if(!quiet) {
317           PRINTFB(G, FB_Ray, FB_Blather)
318             " Ray: tracing %dx%d = %d rays against %d primitives.\n", ray_width,
319             ray_height, ray_width * ray_height, RayGetNPrimitives(ray)
320             ENDFB(G);
321         }
322       }
323       switch (mode) {
324       case 0:                  /* mode 0 is built-in */
325         {
326           auto image = pymol::make_unique<pymol::Image>(ray_width, ray_height);
327           std::uint32_t background;
328 
329           RayRender(ray, image->pixels(), timing, angle, antialias, &background);
330 
331           /*    RayRenderColorTable(ray,ray_width,ray_height,buffer); */
332           if(!I->grid.active) {
333             I->Image = std::move(image);
334           } else {
335             if(!I->Image) {     /* alloc on first pass */
336               I->Image = pymol::make_unique<pymol::Image>(tot_width, tot_height);
337               if(I->Image) {
338                 unsigned int tot_size = tot_width * tot_height;
339                 {               /* fill with background color */
340                   unsigned int *ptr = I->Image->pixels();
341                   for(size_t i = 0; i < tot_size; ++i) {
342                     *(ptr++) = background;
343                   }
344                 }
345               }
346             }
347             /* merge in the latest rendering */
348             if(I->Image && I->Image->bits()) {
349               int i, j;
350               unsigned int *src = image->pixels();
351               unsigned int *dst = I->Image->pixels();
352 
353               dst += (ray_x + ray_y * tot_width);
354 
355               for(i = 0; i < ray_height; i++) {
356                 for(j = 0; j < ray_width; j++) {
357                   if(*src != background)
358                     *(dst) = *(src);
359                   dst++;
360                   src++;
361                 }
362                 dst += (tot_width - ray_width);
363               }
364             }
365           }
366           I->DirtyFlag = false;
367           I->CopyType = true;
368           I->CopyForced = true;
369 
370           if (SettingGet<bool>(G, cSetting_ray_volume) && !I->Image->empty()) {
371             rayVolumeImage = I->Image;
372           } else {
373             rayVolumeImage = nullptr;
374           }
375         }
376         break;
377 
378       case 1:                  /* mode 1 is povray */
379         charVLA = VLACalloc(char, 100000);
380         headerVLA = VLACalloc(char, 2000);
381         RayRenderPOV(ray, ray_width, ray_height, &headerVLA, &charVLA,
382                      I->m_view.m_clipSafe.m_front, I->m_view.m_clipSafe.m_back, fov, angle, antialias);
383         if(!(charVLA_ptr && headerVLA_ptr)) {   /* immediate mode */
384           strcpy(prefix, SettingGet_s(G, NULL, NULL, cSetting_batch_prefix));
385 #ifndef _PYMOL_NOPY
386           if(PPovrayRender(G, headerVLA, charVLA, prefix, ray_width,
387                            ray_height, antialias)) {
388             strcat(prefix, ".png");
389             SceneLoadPNG(G, prefix, false, 0, false);
390             I->DirtyFlag = false;
391           }
392 #endif
393           VLAFreeP(charVLA);
394           VLAFreeP(headerVLA);
395         } else {                /* get_povray mode */
396           *charVLA_ptr = charVLA;
397           *headerVLA_ptr = headerVLA;
398         }
399         break;
400       case 2:                  /* mode 2 is for testing of geometries */
401         RayRenderTest(ray, ray_width, ray_height, I->m_view.m_clipSafe.m_front, I->m_view.m_clipSafe.m_back, fov);
402         break;
403       case 3:                  /* mode 3 is for Jmol */
404         {
405           G3dPrimitive *jp =
406             RayRenderG3d(ray, ray_width, ray_height, I->m_view.m_clipSafe.m_front, I->m_view.m_clipSafe.m_back, fov,
407                          quiet);
408           if(0) {
409             int cnt = VLAGetSize(jp);
410             int a;
411             for(a = 0; a < cnt; a++) {
412               switch (jp[a].op) {
413               case 1:
414                 printf("g3d.fillSphereCentered(gray,%d,%d,%d,%d);\n", jp[a].r, jp[a].x1,
415                        jp[a].y1, jp[a].z1);
416                 break;
417               case 2:
418                 printf("triangle(%d,%d,%d,%d,%d,%d,%d,%d,%d);\n",
419                        jp[a].x1, jp[a].y1, jp[a].z1,
420                        jp[a].x2, jp[a].y2, jp[a].z2, jp[a].x3, jp[a].y3, jp[a].z3);
421                 break;
422               case 3:
423                 printf("g3d.fillCylinder(gray,gray,(byte)3,%d,%d,%d,%d,%d,%d,%d);\n",
424                        jp[a].r,
425                        jp[a].x1, jp[a].y1, jp[a].z1, jp[a].x2, jp[a].y2, jp[a].z2);
426                 break;
427               }
428             }
429           }
430           if(g3d) {
431             *g3d = jp;
432           } else {
433             VLAFreeP(jp);
434           }
435         }
436         break;
437       case 4:                  /* VRML2 */
438         {
439           char *vla = VLACalloc(char, 100000);
440           RayRenderVRML2(ray, ray_width, ray_height, &vla,
441                          I->m_view.m_clipSafe.m_front, I->m_view.m_clipSafe.m_back, fov, angle, I->m_view.m_pos[2]);
442           *charVLA_ptr = vla;
443         }
444         break;
445       case 5:                  /* mode 5 is OBJ MTL */
446         {
447           char *objVLA = VLACalloc(char, 100000);
448           char *mtlVLA = VLACalloc(char, 1000);
449           RayRenderObjMtl(ray, ray_width, ray_height, &objVLA, &mtlVLA,
450                           I->m_view.m_clipSafe.m_front, I->m_view.m_clipSafe.m_back, fov, angle, I->m_view.m_pos[2]);
451           *headerVLA_ptr = objVLA;
452           *charVLA_ptr = mtlVLA;
453         }
454         break;
455       case 6:                  /* VRML1 -- more compatible with tools like blender */
456         {
457           char *vla = VLACalloc(char, 100000);
458           RayRenderVRML1(ray, ray_width, ray_height, &vla,
459                          I->m_view.m_clipSafe.m_front, I->m_view.m_clipSafe.m_back, fov, angle, I->m_view.m_pos[2]);
460           *charVLA_ptr = vla;
461         }
462         break;
463       case cSceneRay_MODE_IDTF:
464         {
465           *headerVLA_ptr = VLACalloc(char, 10000);
466           *charVLA_ptr = VLACalloc(char, 10000);
467           RayRenderIDTF(ray, headerVLA_ptr, charVLA_ptr);
468         }
469         break;
470       case 8:                   /* mode 8 is COLLADA (.dae) */
471         {
472           *charVLA_ptr = VLACalloc(char, 100000);
473           RayRenderCOLLADA(ray, ray_width, ray_height, charVLA_ptr,
474                             I->m_view.m_clipSafe.m_front, I->m_view.m_clipSafe.m_back, fov);
475         }
476         break;
477 
478       }
479       RayFree(ray);
480     }
481     if(I->grid.active)
482       GridSetRayViewport(&I->grid, -1, &ray_x, &ray_y, &ray_width, &ray_height);
483 
484     if((mode == 0) && I->Image && !I->Image->empty()) {
485       SceneApplyImageGamma(G, I->Image->pixels(), I->Image->getWidth(),
486                            I->Image->getHeight());
487     }
488 
489     stereo_hand--;
490     if((I->StereoMode == 0) || (stereo_hand <= 0))
491       break;
492     else {
493       stereo_image = I->Image;
494     }
495   }
496 
497   if(stereo_image) {
498     if(I->Image) {
499       switch (I->StereoMode) {
500       case cStereo_quadbuffer:
501       case cStereo_geowall:
502       case cStereo_openvr:
503         /* merge the two images into one */
504         I->Image->merge(*stereo_image);
505         break;
506       case cStereo_crosseye:
507       case cStereo_walleye:
508         {
509           /* merge the two images into one */
510           auto merged_image =
511               pymol::Image(I->Image->getWidth() * 2, I->Image->getHeight());
512 
513           unsigned int *q = merged_image.pixels();
514           unsigned int *l;
515           unsigned int *r;
516           int height, width;
517           int a, b;
518 
519           if(I->StereoMode == 2) {
520             l = (unsigned int *) stereo_image->bits();
521             r = (unsigned int *) I->Image->bits();
522           } else {
523             r = (unsigned int *) stereo_image->bits();
524             l = (unsigned int *) I->Image->bits();
525           }
526           height = I->Image->getHeight();
527           width = I->Image->getWidth();
528 
529           for(a = 0; a < height; a++) {
530             for(b = 0; b < width; b++)
531               *(q++) = *(l++);
532             for(b = 0; b < width; b++)
533               *(q++) = *(r++);
534           }
535           *I->Image = std::move(merged_image);
536         }
537         break;
538       case cStereo_anaglyph:
539         {
540           int big_endian;
541           {
542             unsigned int test;
543             unsigned char *testPtr;
544             test = 0xFF000000;
545             testPtr = (unsigned char *) &test;
546             big_endian = (*testPtr) & 0x01;
547           }
548           {
549             extern float anaglyphR_constants[6][9];
550             extern float anaglyphL_constants[6][9];
551             unsigned int *l = stereo_image->pixels();
552             unsigned int *r = I->Image->pixels();
553 	    int anaglyph_mode = SettingGetGlobal_i(G, cSetting_anaglyph_mode);
554 	    /* anaglyph scalars */
555 	    float * a_r = anaglyphR_constants[anaglyph_mode];
556 	    float * a_l = anaglyphL_constants[anaglyph_mode];
557 
558             int height, width;
559             int a, b;
560 	    float _r[3] = {0.F,0.F,0.F}, _l[3] = {0.F,0.F,0.F}, _b[3] = {0.F,0.F,0.F};
561             height = I->Image->getHeight();
562             width = I->Image->getWidth();
563 
564             for(a = 0; a < height; a++) {
565               for(b = 0; b < width; b++) {
566                 if(big_endian) {
567                   /* original : RGBA
568 		   *r = (*l & 0x00FFFFFF) | (*r & 0xFF000000);
569 		   */
570 		  /* UNTESTED */
571 		  _l[0] = (float)((*r & 0xFF000000));
572 		  _l[1] = (float)((*r & 0x00FF0000) >> 16);
573 		  _l[2] = (float)((*r & 0x0000FF00) >> 8);
574 		  _r[0] = (float)((*l & 0xFF000000));
575 		  _r[1] = (float)((*l & 0x00FF0000) >> 16);
576 		  _r[2] = (float)((*l & 0x0000FF00) >> 8);
577 		  _b[0] = (a_l[0] * _l[0] + a_l[3] * _l[1] + a_l[6] * _l[2]); // R
578 		  _b[1] = (a_l[1] * _l[0] + a_l[4] * _l[1] + a_l[7] * _l[2]); // G
579 		  _b[2] = (a_l[2] * _l[0] + a_l[5] * _l[1] + a_l[8] * _l[2]); // B
580 		  *l = (unsigned int) (0x000000FF & *l) |
581 		       (unsigned int) (1.0 * _b[0]) |
582 		      ((unsigned int) (1.0 * _b[1]))<<8 |
583 		      ((unsigned int) (1.0 * _b[2]))<<16;
584 
585 		  _b[0] = (a_r[0] * _r[0] + a_r[3] * _r[1] + a_r[6] * _r[2]); // R
586 		  _b[1] = (a_r[1] * _r[0] + a_r[4] * _r[1] + a_r[7] * _r[2]); // G
587 		  _b[2] = (a_r[2] * _r[0] + a_r[5] * _r[1] + a_r[8] * _r[2]); // B
588 
589 		  *r = (unsigned int) (0x000000FF & *r) |
590 		       (unsigned int) (1.0 * _b[0]) |
591    		      ((unsigned int) (1.0 * _b[1]))<<8 |
592 		      ((unsigned int) (1.0 * _b[2]))<<16;
593 
594 		  *r = (*l | *r);
595                 } else {
596                   /* original : AGBR
597 		   *r = (*l & 0xFFFFFF00) | (*r & 0x000000FF);
598 		   */
599 
600 		  /* Right and Left as unsigned ints */
601 		  /* CORRECT */
602 		  _l[0] = (float)((*r & 0x000000FF));
603 		  _l[1] = (float)((*r & 0x0000FF00) >> 8);
604 		  _l[2] = (float)((*r & 0x00FF0000) >> 16);
605 		  _r[0] = (float)((*l & 0x000000FF));
606 		  _r[1] = (float)((*l & 0x0000FF00) >> 8);
607 		  _r[2] = (float)((*l & 0x00FF0000) >> 16);
608 
609 		  _b[0] = (a_l[0] * _l[0] + a_l[3] * _l[1] + a_l[6] * _l[2]); // R
610 		  _b[1] = (a_l[1] * _l[0] + a_l[4] * _l[1] + a_l[7] * _l[2]); // G
611 		  _b[2] = (a_l[2] * _l[0] + a_l[5] * _l[1] + a_l[8] * _l[2]); // B
612 
613 		  *l = (unsigned int) (0xFF000000 & *l) |
614 		       (unsigned int) (1.0 * _b[0]) |
615 		      ((unsigned int) (1.0 * _b[1]))<<8 |
616 		      ((unsigned int) (1.0 * _b[2]))<<16;
617 
618 		  _b[0] = (a_r[0] * _r[0] + a_r[3] * _r[1] + a_r[6] * _r[2]); // R
619 		  _b[1] = (a_r[1] * _r[0] + a_r[4] * _r[1] + a_r[7] * _r[2]); // G
620 		  _b[2] = (a_r[2] * _r[0] + a_r[5] * _r[1] + a_r[8] * _r[2]); // B
621 
622 		  *r = (unsigned int) (0xFF000000 & *r) |
623 		       (unsigned int) (1.0 * _b[0]) |
624    		      ((unsigned int) (1.0 * _b[1]))<<8 |
625 		      ((unsigned int) (1.0 * _b[2]))<<16;
626 
627 		  *r = (*l | *r);
628                 }
629                 l++;
630                 r++;
631               }
632             }
633           }
634         }
635         break;
636       case cStereo_stencil_by_row:
637       case cStereo_stencil_by_column:
638       case cStereo_stencil_checkerboard:
639         {
640           /* merge the two images into one */
641 
642           int parity = 0;
643 
644           if(I->StereoMode == cStereo_stencil_by_row) {
645             parity = I->StencilParity;
646             if(I->rect.bottom & 0x1)
647               parity = 1 - parity;
648           }
649 
650           unsigned int* l = stereo_image->pixels();
651           unsigned int* r = I->Image->pixels();
652 
653           int height = I->Image->getHeight();
654           int width = I->Image->getWidth();
655 
656           auto merged_image = pymol::Image(width, height);
657           unsigned int *q = merged_image.pixels();
658 
659           for (int a = 0; a < height; ++a) {
660             for (int b = 0; b < width; ++b) {
661               switch (I->StereoMode) {
662               case cStereo_stencil_by_row:
663                 if((a + parity) & 0x1) {
664                   *(q++) = *(l++);
665                   r++;
666                 } else {
667                   *(q++) = *(r++);
668                   l++;
669                 }
670                 break;
671               case cStereo_stencil_by_column:
672                 if(b & 0x1) {
673                   *(q++) = *(l++);
674                   r++;
675                 } else {
676                   *(q++) = *(r++);
677                   l++;
678                 }
679                 break;
680               case cStereo_stencil_checkerboard:
681                 if((a + b) & 0x1) {
682                   *(q++) = *(l++);
683                   r++;
684                 } else {
685                   *(q++) = *(r++);
686                   l++;
687                 }
688                 break;
689               }
690             }
691           }
692           *I->Image = std::move(merged_image);
693         }
694         break;
695       }
696     }
697   }
698   timing = UtilGetSeconds(G) - timing;
699   if(mode != 2) {               /* don't show timings for tests */
700     accumTiming += timing;
701 
702     if(show_timing && !quiet) {
703       if(!G->Interrupt) {
704         PRINTFB(G, FB_Ray, FB_Details)
705           " Ray: render time: %4.2f sec. = %3.1f frames/hour (%4.2f sec. accum.).\n",
706           timing, 3600 / timing, accumTiming ENDFB(G);
707       } else {
708         PRINTFB(G, FB_Ray, FB_Details)
709           " Ray: render aborted.\n" ENDFB(G);
710       }
711     }
712   }
713 
714   if(mode != 3) {
715     OrthoDirty(G);
716   }
717 
718   /* EXPERIMENTAL VOLUME CODE */
719   if (rayVolume) {
720     SceneUpdate(G, true);
721   }
722   OrthoBusyFast(G, 20, 20);
723   PyMOL_SetBusy(G->PyMOL, false);
724 
725   return true;
726 #endif
727 }
728 
SceneDeferredRay(DeferredRay * dr)729 static int SceneDeferredRay(DeferredRay * dr)
730 {
731   PyMOLGlobals *G = dr->m_G;
732   SceneRay(G, dr->ray_width, dr->ray_height, dr->mode,
733            NULL, NULL, dr->angle, dr->shift, dr->quiet,
734            NULL, dr->show_timing, dr->antialias);
735   if((dr->mode == 0) && G->HaveGUI && SettingGetGlobal_b(G, cSetting_auto_copy_images)) {
736 #ifdef _PYMOL_IP_EXTRAS
737     PParse(G, "cmd._copy_image(quiet=0)");
738 #else
739 #ifdef PYMOL_EVAL
740     PRINTFB(G, FB_Scene, FB_Warnings)
741       " Warning: Clipboard image transfers disabled in Evaluation Builds.\n" ENDFB(G);
742 #endif
743 #endif
744   }
745   return 1;
746 }
747 
SceneDeferRay(PyMOLGlobals * G,int ray_width,int ray_height,int mode,float angle,float shift,int quiet,int show_timing,int antialias)748 int SceneDeferRay(PyMOLGlobals * G,
749                   int ray_width,
750                   int ray_height,
751                   int mode,
752                   float angle, float shift, int quiet, int show_timing, int antialias)
753 {
754   auto dr = pymol::make_unique<DeferredRay>(G);
755   if(dr) {
756     dr->ray_width = ray_width;
757     dr->ray_height = ray_height;
758     dr->mode = mode;
759     dr->angle = angle;
760     dr->shift = shift;
761     dr->quiet = quiet;
762     dr->show_timing = show_timing;
763     dr->antialias = antialias;
764     dr->fn = (DeferredFn *) SceneDeferredRay;
765   }
766   OrthoDefer(G, std::move(dr));
767   return 1;
768 }
769 
SceneRenderRayVolume(PyMOLGlobals * G,CScene * I)770 void SceneRenderRayVolume(PyMOLGlobals * G, CScene *I){
771 #ifndef PURE_OPENGL_ES_2
772   glMatrixMode(GL_PROJECTION);
773   glPushMatrix();
774   glLoadIdentity();
775   glOrtho(0, I->Width, 0, I->Height, -100, 100);
776   glMatrixMode(GL_MODELVIEW);
777   glPushMatrix();
778   glLoadIdentity();
779 #endif
780 
781 #ifndef PURE_OPENGL_ES_2
782   glRasterPos3f(0, 0, -1);
783 #endif
784   glDepthMask(GL_FALSE);
785 #ifndef PURE_OPENGL_ES_2
786   if (PIsGlutThread() && rayVolumeImage) {
787     if (rayWidth == I->Width && rayHeight == I->Height){
788       glDrawPixels(rayVolumeImage->getWidth(), rayVolumeImage->getHeight(),
789           GL_RGBA, GL_UNSIGNED_BYTE, rayVolumeImage->bits());
790     } else {
791       SceneDrawImageOverlay(G, 1, NULL);
792     }
793   }
794 #endif
795   glDepthMask(GL_TRUE);
796   glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
797   glDepthFunc(GL_ALWAYS);
798 #ifndef PURE_OPENGL_ES_2
799   if (PIsGlutThread() && rayWidth == I->Width && rayHeight == I->Height)
800     glDrawPixels(I->Width, I->Height, GL_DEPTH_COMPONENT, GL_FLOAT, rayDepthPixels);
801 #endif
802   glDepthFunc(GL_LESS);
803   glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
804 
805 #ifdef PURE_OPENGL_ES_2
806   /* TODO */
807 #else
808   glPopMatrix();
809   glMatrixMode(GL_PROJECTION);
810   glPopMatrix();
811   glMatrixMode(GL_MODELVIEW);
812 #endif
813 }
814