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