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 -*   Larry Coopet (various optimizations)
13 -*   Chris Want (RayRenderVRML2, via the public domain )
14 -*
15 Z* -------------------------------------------------------------------
16 */
17 #include"os_python.h"
18 
19 #include"os_predef.h"
20 #include"os_std.h"
21 
22 #include"Base.h"
23 #include"MemoryDebug.h"
24 #include"Err.h"
25 #include"Vector.h"
26 #include"OOMac.h"
27 #include"Setting.h"
28 #include"Ortho.h"
29 #include"Util.h"
30 #include"Ray.h"
31 #include"Triangle.h"
32 #include"Color.h"
33 #include"Matrix.h"
34 #include"P.h"
35 #include"MemoryCache.h"
36 #include"Character.h"
37 #include"Text.h"
38 #include"PyMOL.h"
39 #include"Scene.h"
40 #include"PConv.h"
41 #include"MyPNG.h"
42 #include"CGO.h"
43 
44 #define SettingGetfv SettingGetGlobal_3fv
45 
46 #include"Basis.h"
47 
48 #ifndef RAY_SMALL
49 #define RAY_SMALL 0.00001
50 #endif
51 
52 /* BASES
53    0 contains untransformed vertices (vector size = 3)
54 	1 contains transformed vertices (vector size = 3)
55 	2 contains transformed vertices for shadowing
56 */
57 
58 
59 /* note: the following value must be at least one greater than the max
60    number of lights */
61 #define MAX_BASIS 12
62 
63 typedef float float3[3];
64 typedef float float4[4];
65 
66 struct _CRayThreadInfo {
67   CRay *ray;
68   int width, height;
69   unsigned int *image;
70   float front, back;
71   unsigned int fore_mask;
72   float *bkrd_top, *bkrd_bottom;
73   short bkrd_is_gradient; /* if not gradient, use bkrd_top as bkrd */
74   float ambient;
75   unsigned int background;
76   int border;
77   int phase, n_thread;
78   int x_start, x_stop;
79   int y_start, y_stop;
80   unsigned int *edging;
81   unsigned int edging_cutoff;
82   int perspective;
83   float fov, pos[3];
84   float *depth;
85 
86   int bgWidth, bgHeight;
87   void *bkrd_data; /* used for image-based background */
88 };
89 
90 struct _CRayHashThreadInfo {
91   CBasis *basis;
92   int *vert2prim;
93   CPrimitive *prim;
94   int n_prim;
95   float *clipBox;
96   unsigned int *image;
97   unsigned int background;
98   size_t bytes;
99   int perspective;
100   float front;
101   int phase;
102   float size_hint;
103   CRay *ray;
104   float *bkrd_top, *bkrd_bottom;
105   short bkrd_is_gradient; /* if not gradient, use bkrd_top as bkrd */
106   int width, height;
107   int opaque_back;
108 };
109 
110 struct _CRayAntiThreadInfo {
111   unsigned int *image;
112   unsigned int *image_copy;
113   unsigned int width, height;
114   int mag;
115   int phase, n_thread;
116   CRay *ray;
117 };
118 
119 static
120 void RayRelease(CRay * I);
121 
122 static void RayApplyMatrix33(unsigned int n, float3 * q, const float m[16], float3 * p);
123 static void RayApplyMatrixInverse33(unsigned int n, float3 * q, const float m[16], float3 * p);
124 static void RayTransformNormals33(unsigned int n, float3 * q, const float m[16], float3 * p);
125 static void RayTransformInverseNormals33(unsigned int n, float3 * q, const float m[16],
126                                   float3 * p);
127 static
128 void RayProjectTriangle(CRay * I, RayInfo * r, float *light, float *v0, float *n0,
129                         float scale);
RaySetContext(CRay * I,int context)130 void RaySetContext(CRay * I, int context)
131 {
132   if(context >= 0)
133     I->Context = context;
134   else
135     I->Context = 0;
136 }
137 
RayGetScreenVertexScale(CRay * I,float * v1)138 float RayGetScreenVertexScale(CRay * I, float *v1)
139 {
140   /* what size should a screen pixel be at the coordinate provided? */
141 
142   float vt[3];
143   float ratio;
144   RayApplyMatrix33(1, (float3 *) vt, I->ModelView, (float3 *) v1);
145 
146   if(I->Ortho) {
147     ratio =
148       2 * (float) (fabs(I->Pos[2]) * tan((I->Fov / 2.0) * cPI / 180.0)) / (I->Height);
149   } else {
150     float front_size =
151       2 * I->Volume[4] * ((float) tan((I->Fov / 2.0F) * PI / 180.0F)) / (I->Height);
152     ratio = fabs(front_size * (-vt[2] / I->Volume[4]));
153   }
154   return ratio;
155 }
156 
RayApplyContextToVertex(CRay * I,float * v)157 static void RayApplyContextToVertex(CRay * I, float *v)
158 {
159   switch (I->Context) {
160   case 1:
161     {
162       float tw;
163       float th;
164 
165       if(I->AspRatio > 1.0F) {
166         tw = I->AspRatio;
167         th = 1.0F;
168       } else {
169         th = 1.0F / I->AspRatio;
170         tw = 1.0F;
171       }
172 
173       if(!SettingGetGlobal_b(I->G, cSetting_ortho)) {
174         float scale = v[2] + 0.5F;
175         scale = I->FrontBackRatio * scale + 1.0F - scale;
176 
177         /* z-coodinate is easy... */
178 
179         v[2] = v[2] * I->Range[2] - (I->Volume[4] + I->Volume[5]) / 2.0F;
180         v[0] -= 0.5F;
181         v[1] -= 0.5F;
182         v[0] = scale * v[0] * I->Range[0] / tw + (I->Volume[0] + I->Volume[1]) / 2.0F;
183         v[1] = scale * v[1] * I->Range[1] / th + (I->Volume[2] + I->Volume[3]) / 2.0F;
184 
185         RayApplyMatrixInverse33(1, (float3 *) v, I->ModelView, (float3 *) v);
186       } else {
187         v[0] += (tw - 1.0F) / 2;
188         v[1] += (th - 1.0F) / 2;
189         v[0] = v[0] * (I->Range[0] / tw) + I->Volume[0];
190         v[1] = v[1] * (I->Range[1] / th) + I->Volume[2];
191         v[2] = v[2] * I->Range[2] - (I->Volume[4] + I->Volume[5]) / 2.0F;
192         RayApplyMatrixInverse33(1, (float3 *) v, I->ModelView, (float3 *) v);
193       }
194 
195     }
196     break;
197   }
198 }
199 
RayApplyContextToNormal(CRay * I,float * v)200 static void RayApplyContextToNormal(CRay * I, float *v)
201 {
202   switch (I->Context) {
203   case 1:
204     RayTransformInverseNormals33(1, (float3 *) v, I->ModelView, (float3 *) v);
205     break;
206   }
207 }
208 
RayGetNPrimitives(CRay * I)209 int RayGetNPrimitives(CRay * I)
210 {
211   return (I->NPrimitive);
212 }
213 
214 
215 /*========================================================================*/
216 
RayGetSphereNormal(CRay * I,RayInfo * r)217 static void RayGetSphereNormal(CRay * I, RayInfo * r)
218 {
219 
220   r->impact[0] = r->base[0];
221   r->impact[1] = r->base[1];
222   r->impact[2] = r->base[2] - r->dist;
223 
224   r->surfnormal[0] = r->impact[0] - r->sphere[0];
225   r->surfnormal[1] = r->impact[1] - r->sphere[1];
226   r->surfnormal[2] = r->impact[2] - r->sphere[2];
227 
228   normalize3f(r->surfnormal);
229 }
230 
RayGetSphereNormalPerspective(CRay * I,RayInfo * r)231 static void RayGetSphereNormalPerspective(CRay * I, RayInfo * r)
232 {
233 
234   r->impact[0] = r->base[0] + r->dist * r->dir[0];
235   r->impact[1] = r->base[1] + r->dist * r->dir[1];
236   r->impact[2] = r->base[2] + r->dist * r->dir[2];
237 
238   r->surfnormal[0] = r->impact[0] - r->sphere[0];
239   r->surfnormal[1] = r->impact[1] - r->sphere[1];
240   r->surfnormal[2] = r->impact[2] - r->sphere[2];
241 
242   normalize3f(r->surfnormal);
243 }
244 
fill(unsigned int * buffer,unsigned int value,size_t cnt)245 static void fill(unsigned int *buffer, unsigned int value, size_t cnt)
246 {
247   // std::fill_n(buffer, cnt, value);
248   for (auto it_end = buffer + cnt; buffer != it_end;) {
249     *(buffer++) = value;
250   }
251 }
252 #define MIN(x,y) ((x < y) ? x : y)
253 #define MAX(x,y) ((x > y) ? x : y)
254 
add4ucf(unsigned char * ucval,float * fval,float mulv)255 static void add4ucf(unsigned char *ucval, float *fval, float mulv){
256   fval[0] += ucval[0] * mulv;
257   fval[1] += ucval[1] * mulv;
258   fval[2] += ucval[2] * mulv;
259   fval[3] += ucval[3] * mulv;
260 }
261 
copy4fuc(float * fval,unsigned char * ucval)262 static void copy4fuc(float *fval, unsigned char *ucval){
263   ucval[0] = (0xFF & (int)pymol_roundf(fval[0]));
264   ucval[1] = (0xFF & (int)pymol_roundf(fval[1]));
265   ucval[2] = (0xFF & (int)pymol_roundf(fval[2]));
266   ucval[3] = (0xFF & (int)pymol_roundf(fval[3]));
267 }
268 
fmodpos(float a,float b)269 static float fmodpos(float a, float b){
270   float ret = fmod(a, b);
271   if (ret < 0.f){
272     ret = fmod(-ret, b);
273     ret = fmod( b - ret, b);
274   }
275   return ret;
276 }
277 
compute_background_for_pixel(unsigned char * bkrd,short isOutsideInY,int bg_image_mode,const float * bg_image_tilesize,const float * bg_rgb,int bg_image_linear,unsigned char * bkgrd_data,int bkgrd_width,int bkgrd_height,float w,float wr,float hl,float hpixelx,short blend_bg)278 static void compute_background_for_pixel(unsigned char *bkrd, short isOutsideInY,
279     int bg_image_mode, const float *bg_image_tilesize, const float *bg_rgb, int bg_image_linear,
280     unsigned char *bkgrd_data, int bkgrd_width, int bkgrd_height, float w, float wr,
281     float hl, float hpixelx, short blend_bg)
282 {
283   short isBackground = isOutsideInY;
284   float wl;
285   switch (bg_image_mode){
286   case 1: // isCentered
287     {
288       float tmpx = floor(w - hpixelx);
289       isBackground |= (tmpx < 0.f || tmpx > (float)bkgrd_width);
290       wl = fmodpos(tmpx, (float)bkgrd_width);
291     }
292     break;
293   case 2: // isTiled
294     wl = bkgrd_width * (fmodpos((float)w, bg_image_tilesize[0])/bg_image_tilesize[0]);
295     break;
296   case 3: // isCenteredRepeated
297     wl = fmodpos(floor(w - hpixelx), (float)bkgrd_width) ;
298     break;
299   default:
300     wl = w * wr;
301   }
302   if (isBackground){
303     copy3f(bg_rgb, bkrd);
304     bkrd[3] = 1.f;
305   } else if (bg_image_linear){
306     int wlf = floor(wl), hlf = floor(hl);
307     float xp = (wl - wlf) - .5f, yp = (hl - hlf) - .5f;
308     float xpa = fabs(xp), ypa = fabs(yp);
309     float xpam = 1.f - xpa, ypam = 1.f - ypa;
310     float valx[4] = { 0.f, 0.f, 0.f, 0.f }, valy[4] = { 0.f, 0.f, 0.f, 0.f }, val[4] = { 0.f, 0.f, 0.f, 0.f };
311     int xd = (xp > 0.f) ? 1 : -1, yd = (yp > 0.f) ? 1 : -1;
312     int wlfn = (wlf + xd + bkgrd_width) % bkgrd_width, hlfn = (hlf + yd + bkgrd_height) % bkgrd_height;
313 
314     add4ucf(&bkgrd_data[(bkgrd_width*hlf + wlf)*4], valx, xpam);
315     add4ucf(&bkgrd_data[(bkgrd_width*hlf + wlfn)*4], valx, xpa);
316 
317     add4ucf(&bkgrd_data[(bkgrd_width*hlfn + wlf)*4], valy, xpam);
318     add4ucf(&bkgrd_data[(bkgrd_width*hlfn + wlfn)*4], valy, xpa);
319 
320     mult4f(valx, ypam, val);
321     mult4f(valy, ypa, valy);
322     add4f(valy, val, val);
323     copy4fuc(val, bkrd);
324   } else {
325     copy4f(&bkgrd_data[(bkgrd_width*(int)floor(hl) + (int)floor(wl))*4], bkrd);
326   }
327   // alpha blending with bg_rgb if needed
328   if (blend_bg && bkrd[3] < 255){
329     float alpha = (255.f - bkrd[3]) / 255.f;
330     float tmpadd1[3], tmpadd2[3];
331     tmpadd1[0] = bkrd[0]; tmpadd1[1] = bkrd[1]; tmpadd1[2] = bkrd[2];
332     mult3f(tmpadd1, 1.f - alpha, tmpadd1);
333     mult3f(bg_rgb, alpha, tmpadd2);
334     add3f(tmpadd1, tmpadd2, tmpadd2);
335     bkrd[0] = 0xFF & (int)pymol_roundf(tmpadd2[0]);
336     bkrd[1] = 0xFF & (int)pymol_roundf(tmpadd2[1]);
337     bkrd[2] = 0xFF & (int)pymol_roundf(tmpadd2[2]);
338     bkrd[3] = 255;
339   }
340 }
341 
fill_background_image(CRay * I,unsigned int * buffer,int width,int height,unsigned int cnt)342 static void fill_background_image(CRay * I, unsigned int *buffer, int width, int height, unsigned int cnt){
343   int bkgrd_width = I->bkgrd_data->getWidth(), bkgrd_height = I->bkgrd_data->getHeight();
344   unsigned char *bkgrd_data = I->bkgrd_data->bits();
345   int bg_image_mode = SettingGetGlobal_i(I->G, cSetting_bg_image_mode);
346   int bg_image_linear = SettingGetGlobal_b(I->G, cSetting_bg_image_linear);
347   float bg_rgb[3];
348   const float *tmpf;
349   int w, h;
350   unsigned int value;
351   float wr = bkgrd_width/(float)width, hr = bkgrd_height/(float)height;
352   float hl;
353   unsigned int back_mask;
354   unsigned char bkrd[4];
355   float hpixelx = floor(width/2.f)  - floor(bkgrd_width / 2.f),
356     hpixely = floor(height/2.f) - floor(bkgrd_height / 2.f);
357   auto bg_image_tilesize = SettingGet<const float*>(I->G, cSetting_bg_image_tilesize);
358   short isOutsideInY = 0;
359   int opaque_back ;
360   opaque_back = SettingGetGlobal_i(I->G, cSetting_ray_opaque_background);
361   if(opaque_back < 0)
362     opaque_back = SettingGetGlobal_i(I->G, cSetting_opaque_background);
363 
364   tmpf = ColorGet(I->G, SettingGet_color(I->G, NULL, NULL, cSetting_bg_rgb));
365   mult3f(tmpf, 255.f, bg_rgb);
366 
367   if(opaque_back) {
368     if(I->BigEndian)
369       back_mask = 0x000000FF;
370     else
371       back_mask = 0xFF000000;
372   } else {
373     back_mask = 0x00000000;
374   }
375   // tiled or stretched
376   for (h=0; h<height; h++){
377     switch (bg_image_mode){
378     case 1: // isCentered
379       {
380 	float tmpy = floor(h - hpixely);
381 	isOutsideInY = (tmpy < 0.f || tmpy > (float)bkgrd_height);
382 	hl = fmodpos(tmpy, (float)bkgrd_height);
383       }
384       break;
385     case 2: // isTiled
386       hl = bkgrd_height * (fmodpos((float)h, bg_image_tilesize[1])/bg_image_tilesize[1]);
387       break;
388     case 3: // isCenteredRepeated
389       hl = fmodpos(floor(h - hpixely), (float)bkgrd_height);
390       break;
391     default:
392       hl = h * hr;
393       break;
394     }
395     for (w=0; w<width; w++){
396       compute_background_for_pixel(bkrd, isOutsideInY, bg_image_mode, bg_image_tilesize, bg_rgb, bg_image_linear, bkgrd_data, bkgrd_width, bkgrd_height, w, wr, hl, hpixelx, opaque_back );
397       if(I->BigEndian){
398 	value =
399 	  ((0xFF & bkrd[0]) << 24) |
400 	  ((0xFF & bkrd[1]) << 16) |
401 	  ((0xFF & bkrd[2]) << 8) |
402 	  (0xFF & bkrd[3]);
403       } else {
404 	value =
405 	  ((0xFF & bkrd[3]) << 24) |
406 	  ((0xFF & bkrd[2]) << 16) |
407 	  ((0xFF & bkrd[1]) << 8) |
408 	  (0xFF & bkrd[0]);
409       }
410       if(opaque_back) {
411 	value = back_mask | value;
412       }
413       *(buffer++) = value;
414     }
415   }
416 }
417 
fill_gradient(CRay * I,int opaque_back,unsigned int * buffer,float * bkrd_bottom,float * bkrd_top,int width,int height,unsigned int cnt)418 static void fill_gradient(CRay * I, int opaque_back, unsigned int *buffer, float *bkrd_bottom, float *bkrd_top, int width, int height, unsigned int cnt)
419 {
420   const float _p499 = 0.499F;
421   int w, h;
422   unsigned int value;
423   float bkrd[3], perc;
424   unsigned int back_mask;
425 
426   if(opaque_back) {
427     if(I->BigEndian)
428       back_mask = 0x000000FF;
429     else
430       back_mask = 0xFF000000;
431   } else {
432     back_mask = 0x00000000;
433   }
434   for (h=0; h<height; h++){
435     /* for fill_gradient, y is from top to bottom */
436     perc = h/(float)height;
437     bkrd[0] = bkrd_top[0] + perc * (bkrd_bottom[0] - bkrd_top[0]);
438     bkrd[1] = bkrd_top[1] + perc * (bkrd_bottom[1] - bkrd_top[1]);
439     bkrd[2] = bkrd_top[2] + perc * (bkrd_bottom[2] - bkrd_top[2]);
440     if(I->BigEndian){
441       value = back_mask | ((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))) << 24) |
442 	((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 16) |
443 	((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 8);
444     } else {
445       value = back_mask | ((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 16) |
446 	((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 8) |
447 	((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))));
448     }
449     for (w=0; w<width; w++){
450       *(buffer++) = value;
451     }
452   }
453 }
454 
455 /*========================================================================*/
RayReflectAndTexture(CRay * I,RayInfo * r,int perspective)456 static void RayReflectAndTexture(CRay * I, RayInfo * r, int perspective)
457 {
458   if(r->prim->wobble)
459     switch (r->prim->wobble) {
460     case 1:
461       scatter3f(r->surfnormal, I->WobbleParam[0]);
462       break;
463     case 2:
464       wiggle3f(r->surfnormal, r->impact, I->WobbleParam);
465       break;
466     case 3:
467       {
468         float3 v;
469         float3 n;
470         copy3f(r->impact, v);
471         RayApplyMatrixInverse33(1, &v, I->ModelView, &v);
472         n[0] = (float) cos((v[0] + v[1] + v[2]) * I->WobbleParam[1]);
473         n[1] = (float) cos((v[0] - v[1] + v[2]) * I->WobbleParam[1]);
474         n[2] = (float) cos((v[0] + v[1] - v[2]) * I->WobbleParam[1]);
475         RayTransformNormals33(1, &n, I->ModelView, &n);
476         scale3f(n, I->WobbleParam[0], n);
477         add3f(n, r->surfnormal, r->surfnormal);
478         normalize3f(r->surfnormal);
479       }
480     case 4:
481       {
482         float3 v;
483         float3 n;
484         float *tp = I->WobbleParam;
485         copy3f(r->impact, v);
486         RayApplyMatrixInverse33(1, &v, I->ModelView, &v);
487         n[0] = I->Random[0xFF & (int) ((cos((v[0]) * tp[1]) * 256 * tp[2]))];
488         n[1] = I->Random[0xFF & (int) ((cos((v[1]) * tp[1]) * 256 * tp[2] + 96))];
489         n[2] = I->Random[0xFF & (int) ((cos((v[2]) * tp[1]) * 256 * tp[2] + 148))];
490         RayTransformNormals33(1, &n, I->ModelView, &n);
491         scale3f(n, tp[0], n);
492         add3f(n, r->surfnormal, r->surfnormal);
493         normalize3f(r->surfnormal);
494       }
495       break;
496     case 5:
497       {
498         float3 v;
499         float3 n;
500         float *tp = I->WobbleParam;
501         copy3f(r->impact, v);
502         RayApplyMatrixInverse33(1, &v, I->ModelView, &v);
503         n[0] = I->Random[0xFF & (int) ((v[0] * tp[1]) + 0)] +
504           I->Random[0xFF & (int) ((v[1] * tp[1]) + 20)] +
505           I->Random[0xFF & (int) ((v[2] * tp[1]) + 40)];
506         n[1] = I->Random[0xFF & (int) ((-v[0] * tp[1]) + 90)] +
507           I->Random[0xFF & (int) ((v[1] * tp[1]) + 100)] +
508           I->Random[0xFF & (int) ((-v[2] * tp[1]) + 120)];
509         n[2] = I->Random[0xFF & (int) ((v[0] * tp[1]) + 200)] +
510           I->Random[0xFF & (int) ((-v[1] * tp[1]) + 70)] +
511           I->Random[0xFF & (int) ((v[2] * tp[1]) + 30)];
512 
513         n[0] +=
514           I->Random[0xFF & ((int) ((v[0] - v[1]) * tp[1]) + 0)] +
515           I->Random[0xFF & ((int) ((v[1] - v[2]) * tp[1]) + 20)] +
516           I->Random[0xFF & ((int) ((v[2] - v[0]) * tp[1]) + 40)];
517         n[1] +=
518           I->Random[0xFF & ((int) ((v[0] + v[1]) * tp[1]) + 10)] +
519           I->Random[0xFF & ((int) ((v[1] + v[2]) * tp[1]) + 90)] +
520           I->Random[0xFF & ((int) ((v[2] + v[0]) * tp[1]) + 30)];
521         n[2] +=
522           I->Random[0xFF & ((int) ((-v[0] + v[1]) * tp[1]) + 220)] +
523           I->Random[0xFF & ((int) ((-v[1] + v[2]) * tp[1]) + 20)] +
524           I->Random[0xFF & ((int) ((-v[2] + v[0]) * tp[1]) + 50)];
525 
526         n[0] +=
527           I->Random[0xFF & ((int) ((v[0] + v[1] + v[2]) * tp[1]) + 5)] +
528           I->Random[0xFF & ((int) ((v[0] + v[1] + v[2]) * tp[1]) + 25)] +
529           I->Random[0xFF & ((int) ((v[0] + v[1] + v[2]) * tp[1]) + 46)];
530         n[1] +=
531           I->Random[0xFF & ((int) ((-v[0] - v[1] + v[2]) * tp[1]) + 90)] +
532           I->Random[0xFF & ((int) ((-v[0] - v[1] + v[2]) * tp[1]) + 45)] +
533           I->Random[0xFF & ((int) ((-v[0] - v[1] + v[2]) * tp[1]) + 176)];
534         n[2] +=
535           I->Random[0xFF & ((int) ((v[0] + v[1] - v[2]) * tp[1]) + 192)] +
536           I->Random[0xFF & ((int) ((v[0] + v[1] - v[2]) * tp[1]) + 223)] +
537           I->Random[0xFF & ((int) ((v[0] + v[1] - v[2]) * tp[1]) + 250)];
538 
539         RayTransformNormals33(1, &n, I->ModelView, &n);
540         scale3f(n, tp[0], n);
541         add3f(n, r->surfnormal, r->surfnormal);
542         normalize3f(r->surfnormal);
543       }
544       break;
545     }
546   if(perspective) {
547     r->dotgle = dot_product3f(r->dir, r->surfnormal);
548     r->flat_dotgle = -r->dotgle;
549 
550     r->reflect[0] = r->dir[0] - (2 * r->dotgle * r->surfnormal[0]);
551     r->reflect[1] = r->dir[1] - (2 * r->dotgle * r->surfnormal[1]);
552     r->reflect[2] = r->dir[2] - (2 * r->dotgle * r->surfnormal[2]);
553   } else {
554     r->dotgle = -r->surfnormal[2];
555     r->flat_dotgle = r->surfnormal[2];
556 
557     r->reflect[0] = -(2 * r->dotgle * r->surfnormal[0]);
558     r->reflect[1] = -(2 * r->dotgle * r->surfnormal[1]);
559     r->reflect[2] = -1.0F - (2 * r->dotgle * r->surfnormal[2]);
560   }
561 }
562 
563 
564 /*========================================================================*/
RayExpandPrimitives(CRay * I)565 int RayExpandPrimitives(CRay * I)
566 {
567   int a;
568   float *v0, *v1, *n0, *n1;
569   CBasis *basis;
570   int nVert, nNorm;
571   float voxel_floor;
572   int ok = true;
573 
574   nVert = 0;
575   nNorm = 0;
576   for(a = 0; a < I->NPrimitive; a++) {
577     switch (I->Primitive[a].type) {
578     case cPrimSphere:
579       nVert++;
580       break;
581     case cPrimEllipsoid:
582       nVert++;
583       nNorm += 3;
584       break;
585     case cPrimCone:
586     case cPrimCylinder:
587     case cPrimSausage:
588       nVert++;
589       nNorm++;
590       break;
591     case cPrimTriangle:
592     case cPrimCharacter:
593       nVert += 3;
594       nNorm += 4;
595       break;
596     }
597   }
598 
599   basis = I->Basis;
600 
601   VLACacheSize(I->G, basis->Vertex, float, 3 * nVert, 0, cCache_basis_vertex);
602   VLACacheSize(I->G, basis->Radius, float, nVert, 0, cCache_basis_radius);
603   VLACacheSize(I->G, basis->Radius2, float, nVert, 0, cCache_basis_radius2);
604   VLACacheSize(I->G, basis->Vert2Normal, int, nVert, 0, cCache_basis_vert2normal);
605   VLACacheSize(I->G, basis->Normal, float, 3 * nNorm, 0, cCache_basis_normal);
606 
607   VLACacheSize(I->G, I->Vert2Prim, int, nVert, 0, cCache_ray_vert2prim);
608 
609   voxel_floor = I->PixelRadius / 2.0F;
610 
611   basis->MaxRadius = 0.0F;
612   basis->MinVoxel = 0.0F;
613   basis->NVertex = nVert;
614   basis->NNormal = nNorm;
615 
616   nVert = 0;
617   nNorm = 0;
618   v0 = basis->Vertex;
619   n0 = basis->Normal;
620   ok &= !I->G->Interrupt;
621   for(a = 0; ok && a < I->NPrimitive; a++) {
622     switch (I->Primitive[a].type) {
623     case cPrimTriangle:
624     case cPrimCharacter:
625 
626       I->Primitive[a].vert = nVert;
627       I->Vert2Prim[nVert] = a;
628       I->Vert2Prim[nVert + 1] = a;
629       I->Vert2Prim[nVert + 2] = a;
630       basis->Radius[nVert] = I->Primitive[a].r1;
631       basis->Radius2[nVert] = I->Primitive[a].r1 * I->Primitive[a].r1;  /*necessary?? */
632       /*              if(basis->Radius[nVert]>basis->MinVoxel)
633          basis->MinVoxel=basis->Radius[nVert]; */
634       if(basis->MinVoxel < voxel_floor)
635         basis->MinVoxel = voxel_floor;
636       basis->Vert2Normal[nVert] = nNorm;
637       basis->Vert2Normal[nVert + 1] = nNorm;
638       basis->Vert2Normal[nVert + 2] = nNorm;
639       n1 = I->Primitive[a].n0;
640       (*n0++) = (*n1++);
641       (*n0++) = (*n1++);
642       (*n0++) = (*n1++);
643       n1 = I->Primitive[a].n1;
644       (*n0++) = (*n1++);
645       (*n0++) = (*n1++);
646       (*n0++) = (*n1++);
647       n1 = I->Primitive[a].n2;
648       (*n0++) = (*n1++);
649       (*n0++) = (*n1++);
650       (*n0++) = (*n1++);
651       n1 = I->Primitive[a].n3;
652       (*n0++) = (*n1++);
653       (*n0++) = (*n1++);
654       (*n0++) = (*n1++);
655       nNorm += 4;
656       v1 = I->Primitive[a].v1;
657       (*v0++) = (*v1++);
658       (*v0++) = (*v1++);
659       (*v0++) = (*v1++);
660       v1 = I->Primitive[a].v2;
661       (*v0++) = (*v1++);
662       (*v0++) = (*v1++);
663       (*v0++) = (*v1++);
664       v1 = I->Primitive[a].v3;
665       (*v0++) = (*v1++);
666       (*v0++) = (*v1++);
667       (*v0++) = (*v1++);
668       nVert += 3;
669       break;
670     case cPrimSphere:
671       I->Primitive[a].vert = nVert;
672       I->Vert2Prim[nVert] = a;
673       v1 = I->Primitive[a].v1;
674       basis->Radius[nVert] = I->Primitive[a].r1;
675       basis->Radius2[nVert] = I->Primitive[a].r1 * I->Primitive[a].r1;  /*precompute */
676       if(basis->Radius[nVert] > basis->MaxRadius)
677         basis->MaxRadius = basis->Radius[nVert];
678       (*v0++) = (*v1++);
679       (*v0++) = (*v1++);
680       (*v0++) = (*v1++);
681       nVert++;
682       break;
683     case cPrimEllipsoid:
684       I->Primitive[a].vert = nVert;
685       I->Vert2Prim[nVert] = a;
686       v1 = I->Primitive[a].v1;
687       basis->Radius[nVert] = I->Primitive[a].r1;
688       basis->Radius2[nVert] = I->Primitive[a].r1 * I->Primitive[a].r1;  /*precompute */
689       if(basis->Radius[nVert] > basis->MaxRadius)
690         basis->MaxRadius = basis->Radius[nVert];
691       basis->Vert2Normal[nVert] = nNorm;
692       (*v0++) = (*v1++);
693       (*v0++) = (*v1++);
694       (*v0++) = (*v1++);
695       nVert++;
696       n1 = I->Primitive[a].n1;
697       (*n0++) = (*n1++);
698       (*n0++) = (*n1++);
699       (*n0++) = (*n1++);
700       n1 = I->Primitive[a].n2;
701       (*n0++) = (*n1++);
702       (*n0++) = (*n1++);
703       (*n0++) = (*n1++);
704       n1 = I->Primitive[a].n3;
705       (*n0++) = (*n1++);
706       (*n0++) = (*n1++);
707       (*n0++) = (*n1++);
708       nNorm += 3;
709       break;
710     case cPrimCone:
711     case cPrimCylinder:
712     case cPrimSausage:
713       I->Primitive[a].vert = nVert;
714       I->Vert2Prim[nVert] = a;
715       basis->Radius[nVert] = I->Primitive[a].r1;
716       basis->Radius2[nVert] = I->Primitive[a].r1 * I->Primitive[a].r1;  /*precompute */
717       if(basis->MinVoxel < voxel_floor)
718         basis->MinVoxel = voxel_floor;
719       subtract3f(I->Primitive[a].v2, I->Primitive[a].v1, n0);
720       I->Primitive[a].l1 = (float) length3f(n0);
721       normalize3f(n0);
722       n0 += 3;
723       basis->Vert2Normal[nVert] = nNorm;
724       nNorm++;
725       v1 = I->Primitive[a].v1;
726       (*v0++) = (*v1++);
727       (*v0++) = (*v1++);
728       (*v0++) = (*v1++);
729       nVert++;
730       break;
731     }
732     ok &= !I->G->Interrupt;
733   }
734   if(nVert > basis->NVertex) {
735     fprintf(stderr, "Error: basis->NVertex exceeded\n");
736   }
737   PRINTFB(I->G, FB_Ray, FB_Blather)
738     " Ray: minvoxel  %8.3f\n Ray: NPrimit  %d nvert %d\n", basis->MinVoxel, I->NPrimitive,
739     nVert ENDFB(I->G);
740   return ok;
741 }
742 
743 
744 /*========================================================================*/
RayComputeBox(CRay * I)745 void RayComputeBox(CRay * I)
746 {
747 
748 #define minmax(v,r) { \
749   xp = v[0] + r;\
750   xm = v[0] - r;\
751   yp = v[1] + r;\
752   ym = v[1] - r;\
753   zp = v[2] + r;\
754   zm = v[2] - r;\
755   if(xmin>xm) xmin = xm;\
756   if(xmax<xp) xmax = xp;\
757   if(ymin>ym) ymin = ym;\
758   if(ymax<yp) ymax = yp;\
759   if(zmin>zm) zmin = zm;\
760   if(zmax<zp) zmax = zp;\
761 }
762 
763   CPrimitive *prm;
764   CBasis *basis1;
765 
766   float xmin = 0.0F, ymin = 0.0F, xmax = 0.0F, ymax = 0.0F, zmin = 0.0F, zmax = 0.0F;
767   float xp, xm, yp, ym, zp, zm;
768 
769   float *v, r;
770   float vt[3];
771   const float _0 = 0.0F;
772   int a;
773 
774   basis1 = I->Basis + 1;
775   if(basis1->NVertex) {
776     xmin = xmax = basis1->Vertex[0];
777     ymin = ymax = basis1->Vertex[1];
778     zmin = zmax = basis1->Vertex[2];
779 
780     for(a = 0; a < I->NPrimitive; a++) {
781       prm = I->Primitive + a;
782 
783       switch (prm->type) {
784       case cPrimTriangle:
785       case cPrimCharacter:
786 
787         r = _0;
788         v = basis1->Vertex + prm->vert * 3;
789         minmax(v, r);
790         v = basis1->Vertex + prm->vert * 3 + 3;
791         minmax(v, r);
792         v = basis1->Vertex + prm->vert * 3 + 6;
793         minmax(v, r);
794         break;
795       case cPrimSphere:
796       case cPrimEllipsoid:
797         r = prm->r1;
798         v = basis1->Vertex + prm->vert * 3;
799         minmax(v, r);
800         break;
801       case cPrimCone:
802       case cPrimCylinder:
803       case cPrimSausage:
804         r = prm->r1;
805         v = basis1->Vertex + prm->vert * 3;
806         minmax(v, r);
807         v = basis1->Normal + basis1->Vert2Normal[prm->vert] * 3;
808         scale3f(v, prm->l1, vt);
809         v = basis1->Vertex + prm->vert * 3;
810         add3f(v, vt, vt);
811         minmax(vt, r);
812         break;
813       }                         /* end of switch */
814     }
815   }
816   // without the R_SMALL4 padding, this caused ray tracing failure
817   // on OS X (X11) with a flat ObjectCGO (zmin == zmax).
818   I->min_box[0] = xmin - R_SMALL4;
819   I->min_box[1] = ymin - R_SMALL4;
820   I->min_box[2] = zmin - R_SMALL4;
821   I->max_box[0] = xmax + R_SMALL4;
822   I->max_box[1] = ymax + R_SMALL4;
823   I->max_box[2] = zmax + R_SMALL4;
824 }
825 
RayTransformFirst(CRay * I,int perspective,int identity)826 int RayTransformFirst(CRay * I, int perspective, int identity)
827 {
828   CBasis *basis0, *basis1;
829   CPrimitive *prm;
830   int a;
831   float *v0;
832   int backface_cull;
833   int ok = true;
834   int two_sided_lighting = SettingGetGlobal_b(I->G, cSetting_two_sided_lighting);
835 
836   if(two_sided_lighting<0) {
837     if(SettingGetGlobal_i(I->G, cSetting_surface_cavity_mode))
838       two_sided_lighting = true;
839     else
840       two_sided_lighting = false;
841   }
842 
843   backface_cull = SettingGetGlobal_b(I->G, cSetting_backface_cull);
844 
845   if(two_sided_lighting ||
846      (SettingGetGlobal_i(I->G, cSetting_transparency_mode) == 1) ||
847      (SettingGetGlobal_i(I->G, cSetting_ray_interior_color) != -1) || I->CheckInterior)
848     backface_cull = 0;
849 
850 
851   basis0 = I->Basis;
852   basis1 = I->Basis + 1;
853 
854   if (ok){
855     VLACacheSize(I->G, basis1->Vertex, float, 3 * basis0->NVertex, 1, cCache_basis_vertex);
856     CHECKOK(ok, basis1->Vertex);
857   }
858   if (ok){
859     VLACacheSize(I->G, basis1->Normal, float, 3 * basis0->NNormal, 1, cCache_basis_normal);
860     CHECKOK(ok, basis1->Normal);
861   }
862   if (ok){
863     VLACacheSize(I->G, basis1->Precomp, float, 3 * basis0->NNormal, 1,
864 		 cCache_basis_precomp);
865     CHECKOK(ok, basis1->Precomp);
866   }
867   if (ok){
868     VLACacheSize(I->G, basis1->Vert2Normal, int, basis0->NVertex, 1,
869 		 cCache_basis_vert2normal);
870     CHECKOK(ok, basis1->Vert2Normal);
871   }
872   if (ok){
873     VLACacheSize(I->G, basis1->Radius, float, basis0->NVertex, 1, cCache_basis_radius);
874     CHECKOK(ok, basis1->Radius);
875   }
876   if (ok){
877     VLACacheSize(I->G, basis1->Radius2, float, basis0->NVertex, 1, cCache_basis_radius2);
878     CHECKOK(ok, basis1->Radius2);
879   }
880   ok &= !I->G->Interrupt;
881   if (ok){
882     if(identity) {
883       UtilCopyMem(basis1->Vertex, basis0->Vertex, basis0->NVertex * sizeof(float) * 3);
884     } else {
885       RayApplyMatrix33(basis0->NVertex, (float3 *) basis1->Vertex,
886 		       I->ModelView, (float3 *) basis0->Vertex);
887     }
888   }
889   ok &= !I->G->Interrupt;
890 
891   if (ok){
892     memcpy(basis1->Radius, basis0->Radius, basis0->NVertex * sizeof(float));
893     memcpy(basis1->Radius2, basis0->Radius2, basis0->NVertex * sizeof(float));
894     memcpy(basis1->Vert2Normal, basis0->Vert2Normal, basis0->NVertex * sizeof(int));
895   }
896   ok &= !I->G->Interrupt;
897   if (ok){
898     basis1->MaxRadius = basis0->MaxRadius;
899     basis1->MinVoxel = basis0->MinVoxel;
900     basis1->NVertex = basis0->NVertex;
901   }
902   ok &= !I->G->Interrupt;
903   if (ok){
904     if(identity) {
905       UtilCopyMem(basis1->Normal, basis0->Normal, basis0->NNormal * sizeof(float) * 3);
906     } else {
907       RayTransformNormals33(basis0->NNormal, (float3 *) basis1->Normal,
908 			    I->ModelView, (float3 *) basis0->Normal);
909     }
910     basis1->NNormal = basis0->NNormal;
911   }
912   ok &= !I->G->Interrupt;
913   if(perspective) {
914     for(a = 0; ok && a < I->NPrimitive; a++) {
915       prm = I->Primitive + a;
916 
917       prm = I->Primitive + a;
918       switch (prm->type) {
919       case cPrimTriangle:
920       case cPrimCharacter:
921         BasisTrianglePrecomputePerspective(basis1->Vertex + prm->vert * 3,
922                                            basis1->Vertex + prm->vert * 3 + 3,
923                                            basis1->Vertex + prm->vert * 3 + 6,
924                                            basis1->Precomp +
925                                            basis1->Vert2Normal[prm->vert] * 3);
926         break;
927       }
928       ok &= !I->G->Interrupt;
929     }
930   } else {
931     for(a = 0; ok && a < I->NPrimitive; a++) {
932       prm = I->Primitive + a;
933       switch (prm->type) {
934       case cPrimTriangle:
935       case cPrimCharacter:
936         BasisTrianglePrecompute(basis1->Vertex + prm->vert * 3,
937                                 basis1->Vertex + prm->vert * 3 + 3,
938                                 basis1->Vertex + prm->vert * 3 + 6,
939                                 basis1->Precomp + basis1->Vert2Normal[prm->vert] * 3);
940         v0 = basis1->Normal + (basis1->Vert2Normal[prm->vert] * 3 + 3);
941         prm->cull = (!identity) && backface_cull && ((v0[2] < 0.0F) && (v0[5] < 0.0F)
942                                                      && (v0[8] < 0.0F));
943         break;
944       case cPrimCone:
945       case cPrimSausage:
946       case cPrimCylinder:
947         BasisCylinderSausagePrecompute(basis1->Normal +
948                                        basis1->Vert2Normal[prm->vert] * 3,
949                                        basis1->Precomp +
950                                        basis1->Vert2Normal[prm->vert] * 3);
951         break;
952 
953       }
954       ok &= !I->G->Interrupt;
955     }
956   }
957   return ok;
958 }
959 
960 
961 /*========================================================================*/
RayTransformBasis(CRay * I,CBasis * basis1,int group_id)962 static int RayTransformBasis(CRay * I, CBasis * basis1, int group_id)
963 {
964   CBasis *basis0;
965   int a;
966   float *v0, *v1;
967   CPrimitive *prm;
968   int ok = true;
969 
970   basis0 = I->Basis + 1;
971 
972   VLACacheSize(I->G, basis1->Vertex, float, 3 * basis0->NVertex, group_id,
973                cCache_basis_vertex);
974   CHECKOK(ok, basis1->Vertex);
975   if (ok)
976     VLACacheSize(I->G, basis1->Normal, float, 3 * basis0->NNormal, group_id,
977 		 cCache_basis_normal);
978   CHECKOK(ok, basis1->Normal);
979   if (ok)
980     VLACacheSize(I->G, basis1->Precomp, float, 3 * basis0->NNormal, group_id,
981 		 cCache_basis_precomp);
982   CHECKOK(ok, basis1->Precomp);
983   if (ok)
984     VLACacheSize(I->G, basis1->Vert2Normal, int, basis0->NVertex, group_id,
985 		 cCache_basis_vert2normal);
986   CHECKOK(ok, basis1->Vert2Normal);
987   if (ok)
988     VLACacheSize(I->G, basis1->Radius, float, basis0->NVertex, group_id,
989 		 cCache_basis_radius);
990   CHECKOK(ok, basis1->Radius);
991   if (ok)
992     VLACacheSize(I->G, basis1->Radius2, float, basis0->NVertex, group_id,
993 		 cCache_basis_radius2);
994   CHECKOK(ok, basis1->Radius2);
995   v0 = basis0->Vertex;
996   v1 = basis1->Vertex;
997   for(a = 0; ok && a < basis0->NVertex; a++) {
998     matrix_transform33f3f(basis1->Matrix, v0, v1);
999     v0 += 3;
1000     v1 += 3;
1001     basis1->Radius[a] = basis0->Radius[a];
1002     basis1->Radius2[a] = basis0->Radius2[a];
1003     basis1->Vert2Normal[a] = basis0->Vert2Normal[a];
1004   }
1005   if (ok){
1006     v0 = basis0->Normal;
1007     v1 = basis1->Normal;
1008   }
1009   for(a = 0; ok && a < basis0->NNormal; a++) {
1010     matrix_transform33f3f(basis1->Matrix, v0, v1);
1011     v0 += 3;
1012     v1 += 3;
1013   }
1014   if (ok){
1015     basis1->MaxRadius = basis0->MaxRadius;
1016     basis1->MinVoxel = basis0->MinVoxel;
1017     basis1->NVertex = basis0->NVertex;
1018     basis1->NNormal = basis0->NNormal;
1019   }
1020   for(a = 0; ok && a < I->NPrimitive; a++) {
1021     prm = I->Primitive + a;
1022     switch (prm->type) {
1023     case cPrimTriangle:
1024     case cPrimCharacter:
1025 
1026       BasisTrianglePrecompute(basis1->Vertex + prm->vert * 3,
1027                               basis1->Vertex + prm->vert * 3 + 3,
1028                               basis1->Vertex + prm->vert * 3 + 6,
1029                               basis1->Precomp + basis1->Vert2Normal[prm->vert] * 3);
1030       break;
1031     case cPrimCone:
1032     case cPrimSausage:
1033     case cPrimCylinder:
1034       BasisCylinderSausagePrecompute(basis1->Normal + basis1->Vert2Normal[prm->vert] * 3,
1035                                      basis1->Precomp +
1036                                      basis1->Vert2Normal[prm->vert] * 3);
1037       break;
1038 
1039     }
1040   }
1041   return ok;
1042 }
1043 
1044 
1045 /*========================================================================*/
RayRenderTest(CRay * I,int width,int height,float front,float back,float fov)1046 void RayRenderTest(CRay * I, int width, int height, float front, float back, float fov)
1047 {
1048 
1049   PRINTFB(I->G, FB_Ray, FB_Details)
1050     " RayRenderTest: obtained %i graphics primitives.\n", I->NPrimitive ENDFB(I->G);
1051 }
1052 
1053 
1054 /*========================================================================*/
1055 
RayRenderG3d(CRay * I,int width,int height,float front,float back,float fov,int quiet)1056 G3dPrimitive *RayRenderG3d(CRay * I, int width, int height,
1057                            float front, float back, float fov, int quiet)
1058 {
1059   /* generate a rendering stream for Miguel's G3d java rendering engine */
1060 
1061   float scale_x, scale_y;
1062   int shift_x, shift_y;
1063   float *d;
1064   CBasis *base;
1065   CPrimitive *prim;
1066   float *vert;
1067   float vert2[3];
1068   int a;
1069   G3dPrimitive *jprim = VLAlloc(G3dPrimitive, 10000), *jp;
1070   int n_jp = 0;
1071 
1072 #define convert_r(r) 2*(int)(r*scale_x);
1073 #define convert_x(x) shift_x + (int)(x*scale_x);
1074 #define convert_y(y) height - (shift_y + (int)(y*scale_y));
1075 #define convert_z(z) -(int)((z+front)*scale_x);
1076 #define convert_col(c) (0xFF000000 | (((int)(c[0]*255.0))<<16) | (((int)(c[1]*255.0))<<8) | (((int)(c[2]*255.0))))
1077 
1078   RayExpandPrimitives(I);
1079   RayTransformFirst(I, 0, false);
1080 
1081   if(!quiet) {
1082     PRINTFB(I->G, FB_Ray, FB_Details)
1083       " RayRenderG3d: processed %i graphics primitives.\n", I->NPrimitive ENDFB(I->G);
1084   }
1085   base = I->Basis + 1;
1086 
1087   /* always orthoscopic */
1088 
1089   /* front should give a zero Z,
1090      -I->Range[0] should be off the right hand size
1091      I->Range[1] should be off the top */
1092   scale_x = width / I->Range[0];
1093   scale_y = height / I->Range[1];
1094   shift_x = width / 2;
1095   shift_y = height / 2;
1096 
1097   for(a = 0; a < I->NPrimitive; a++) {
1098     prim = I->Primitive + a;
1099     vert = base->Vertex + 3 * (prim->vert);
1100     switch (prim->type) {
1101     case cPrimSphere:
1102       VLACheck(jprim, G3dPrimitive, n_jp);
1103       jp = jprim + n_jp;
1104       jp->op = 1;
1105       jp->r = convert_r(prim->r1);
1106       jp->x1 = convert_x(vert[0]);
1107       jp->y1 = convert_y(vert[1]);
1108       jp->z1 = convert_z(vert[2]);
1109       jp->c = convert_col(prim->c1);
1110       n_jp++;
1111       break;
1112     case cPrimSausage:
1113       VLACheck(jprim, G3dPrimitive, n_jp);
1114       d = base->Normal + 3 * base->Vert2Normal[prim->vert];
1115       scale3f(d, prim->l1, vert2);
1116       add3f(vert, vert2, vert2);
1117 
1118       jp = jprim + n_jp;
1119       jp->op = 3;
1120       jp->r = convert_r(prim->r1);
1121       jp->x1 = convert_x(vert[0]);
1122       jp->y1 = convert_y(vert[1]);
1123       jp->z1 = convert_z(vert[2]);
1124       jp->x2 = convert_x(vert2[0]);
1125       jp->y2 = convert_y(vert2[1]);
1126       jp->z2 = convert_z(vert2[2]);
1127       jp->c = convert_col(prim->c1);
1128       n_jp++;
1129       break;
1130     case cPrimTriangle:
1131       VLACheck(jprim, G3dPrimitive, n_jp);
1132       jp = jprim + n_jp;
1133       jp->op = 2;
1134       jp->x1 = convert_x(vert[0]);
1135       jp->y1 = convert_y(vert[1]);
1136       jp->z1 = convert_z(vert[2]);
1137       jp->x2 = convert_x(vert[3]);
1138       jp->y2 = convert_y(vert[4]);
1139       jp->z2 = convert_z(vert[5]);
1140       jp->x3 = convert_x(vert[6]);
1141       jp->y3 = convert_y(vert[7]);
1142       jp->z3 = convert_z(vert[8]);
1143       jp->c = convert_col(prim->c1);
1144       n_jp++;
1145       break;
1146     }
1147   }
1148   VLASize(jprim, G3dPrimitive, n_jp);
1149   return jprim;
1150 }
1151 
RayRenderVRML1(CRay * I,int width,int height,char ** vla_ptr,float front,float back,float fov,float angle,float z_corr)1152 void RayRenderVRML1(CRay * I, int width, int height,
1153                     char **vla_ptr, float front, float back,
1154                     float fov, float angle, float z_corr)
1155 {
1156   char *vla = *vla_ptr;
1157   ov_size cc = 0;               /* character count */
1158   OrthoLineType buffer;
1159 
1160   RayExpandPrimitives(I);
1161   RayTransformFirst(I, 0, false);
1162 
1163   strcpy(buffer, "#VRML V1.0 ascii\n\n");
1164   UtilConcatVLA(&vla, &cc, buffer);
1165 
1166   UtilConcatVLA(&vla, &cc, "MaterialBinding { value OVERALL }\n");
1167 
1168   sprintf(buffer,
1169           "Material {\n ambientColor 0 0 0\n diffuseColor 1 1 1\n specularColor 1 1 1\nshininess 0.2\n}\n");
1170   UtilConcatVLA(&vla, &cc, buffer);
1171 
1172   {
1173     int a;
1174     CPrimitive *prim;
1175     float *vert;
1176     CBasis *base = I->Basis + 1;
1177 
1178     UtilConcatVLA(&vla, &cc, "Separator {\n");
1179 
1180     UtilConcatVLA(&vla, &cc, "MatrixTransform {\n");
1181     UtilConcatVLA(&vla, &cc, "matrix 1.0 0.0 0.0 0.0\n");
1182     UtilConcatVLA(&vla, &cc, "       0.0 1.0 0.0 0.0\n");
1183     UtilConcatVLA(&vla, &cc, "       0.0 0.0 1.0 0.0\n");
1184     sprintf(buffer, "    %8.6f %8.6f %8.6f 1.0\n",
1185             (I->Volume[0] + I->Volume[1]) / 2, (I->Volume[2] + I->Volume[3]) / 2, 0.0F);
1186     UtilConcatVLA(&vla, &cc, buffer);
1187     UtilConcatVLA(&vla, &cc, "}\n");
1188 
1189     for(a = 0; a < I->NPrimitive; a++) {
1190       prim = I->Primitive + a;
1191       vert = base->Vertex + 3 * (prim->vert);
1192       switch (prim->type) {
1193       case cPrimSphere:
1194         sprintf(buffer,
1195                 "Material {\ndiffuseColor %6.4f %6.4f %6.4f\n}\n\n",
1196                 prim->c1[0], prim->c1[1], prim->c1[2]);
1197         UtilConcatVLA(&vla, &cc, buffer);
1198         UtilConcatVLA(&vla, &cc, "Separator {\n");
1199         sprintf(buffer,
1200                 "Transform {\ntranslation %8.6f %8.6f %8.6f\nscaleFactor %8.6f %8.6f %8.6f\n}\n",
1201                 vert[0], vert[1], vert[2] - z_corr, prim->r1, prim->r1, prim->r1);
1202         UtilConcatVLA(&vla, &cc, buffer);
1203         sprintf(buffer, "Sphere {}\n");
1204         UtilConcatVLA(&vla, &cc, buffer);
1205         UtilConcatVLA(&vla, &cc, "}\n\n");
1206         break;
1207       case cPrimCylinder:
1208       case cPrimSausage:
1209       case cPrimCone:
1210         break;
1211       case cPrimTriangle:
1212         break;
1213       }
1214     }
1215 
1216     UtilConcatVLA(&vla, &cc, "}\n");
1217   }
1218 
1219   *vla_ptr = vla;
1220 }
1221 
TriangleReverse(CPrimitive * p)1222 int TriangleReverse(CPrimitive * p)
1223 {
1224   float s1[3], s2[3], n0[3];
1225 
1226   subtract3f(p->v1, p->v2, s1);
1227   subtract3f(p->v3, p->v2, s2);
1228   cross_product3f(s1, s2, n0);
1229 
1230   if(dot_product3f(p->n0, n0) < 0.0F)
1231     return 0;
1232   else
1233     return 1;
1234 }
1235 
RayRenderVRML2(CRay * I,int width,int height,char ** vla_ptr,float front,float back,float fov,float angle,float z_corr)1236 void RayRenderVRML2(CRay * I, int width, int height,
1237                     char **vla_ptr, float front, float back,
1238                     float fov, float angle, float z_corr)
1239 {
1240 
1241   /*
1242 
1243      From: pymol-users-admin@lists.sourceforge.net on behalf of Chris Want
1244      Sent: Tuesday, February 07, 2006 1:47 PM
1245      To: pymol-users@lists.sourceforge.net
1246      Subject: [PyMOL] VRML patch
1247 
1248      Hi Warren,
1249 
1250      I took your advice and modified the RayRenderVRML2() function to
1251      support triangles. I also threw out the sphere code that was already
1252      there and rewrote it (the code there was for VRML1, not
1253      VRML2). While I was at it, I also implemented export for cylinders
1254      and sausages.
1255 
1256      The code in the attached patch (diff-ed against cvs, and tested with
1257      two VRML2 readers) can be regarded as being in the public domain.
1258 
1259      Regards,
1260      Chris
1261 
1262      cwant_at_ualberta.ca
1263 
1264    */
1265 
1266   char *vla = *vla_ptr;
1267   ov_size cc = 0;               /* character count */
1268   OrthoLineType buffer;
1269   float mid[3];                 /*, wid[3]; */
1270   float h_fov = cPI * (fov * width) / (180 * height);
1271   int identity = (SettingGetGlobal_i(I->G, cSetting_geometry_export_mode) == 1);
1272 
1273   RayExpandPrimitives(I);
1274   RayTransformFirst(I, 0, identity);
1275   RayComputeBox(I);
1276   /*
1277      mid[0] = (I->max_box[0] + I->min_box[0]) / 2.0;
1278      mid[1] = (I->max_box[1] + I->min_box[1]) / 2.0;
1279      mid[2] = (I->max_box[2] + I->min_box[2]) / 2.0;
1280      wid[0]  = (I->max_box[0] - I->min_box[0]);
1281      wid[1]  = (I->max_box[1] - I->min_box[1]);
1282      wid[2]  = (I->max_box[2] - I->min_box[2]);
1283    */
1284 
1285   copy3f(I->Pos, mid);
1286   UtilConcatVLA(&vla, &cc, "#VRML V2.0 utf8\n"  /* WLD: most VRML2 readers req. utf8 */
1287                 "\n");
1288   if(!identity) {
1289     sprintf(buffer, "Viewpoint {\n" " position 0 0 %6.8f\n" " orientation 1 0 0 0\n" " description \"Z view\"\n" " fieldOfView %8.6f\n" /* WLD: use correct FOV */
1290             "}\n"
1291             /* WLD: only write the viewpoint which matches PyMOL
1292                "Viewpoint {\n"
1293                " position %6.8f 0 0\n"
1294                " orientation 0 1 0 1.570796\n"
1295                " description \"X view\"\n"
1296                "}\n"
1297                "Viewpoint {\n"
1298                " position 0 %6.8f 0\n"
1299                " orientation 0 -0.707106 -0.7071061 3.141592\n"
1300                " description \"Y view\"\n"
1301                "}\n" */ ,
1302             -z_corr,            /* *0.96646  for some reason, PyMOL and C4D cameras differ by about 3.5% ... */
1303             h_fov
1304             /*(wid[2] + wid[1]),
1305                (wid[0] + wid[1]),
1306                (wid[1] + wid[2]) */
1307       );
1308     UtilConcatVLA(&vla, &cc, buffer);
1309   }
1310   if(!identity) {
1311     float light[3];
1312     auto lightv = SettingGet<const float*>(I->G, cSetting_light);
1313     copy3f(lightv, light);
1314     normalize3f(light);
1315     sprintf(buffer,
1316             "DirectionalLight {\n"
1317             " direction %8.6f %8.6f %8.3f\n" "}\n", light[0], light[1], light[2]);
1318     UtilConcatVLA(&vla, &cc, buffer);
1319   }
1320   UtilConcatVLA(&vla, &cc,
1321                 "NavigationInfo {\n" " headlight TRUE\n" " type \"EXAMINE\"\n" "}\n");
1322   {
1323     int a, b;
1324     CPrimitive *prim;
1325     float *vert;
1326     int mesh_obj = false, mesh_start = 0;
1327 
1328     CBasis *base = I->Basis + 1;
1329 
1330     for(a = 0; a < I->NPrimitive; a++) {
1331       prim = I->Primitive + a;
1332       vert = base->Vertex + 3 * (prim->vert);
1333 
1334       if(prim->type == cPrimTriangle) {
1335         if(!mesh_obj) {
1336           /* start mesh */
1337           mesh_start = a;
1338           UtilConcatVLA(&vla, &cc,
1339                         "Shape {\n"
1340                         " appearance Appearance {\n"
1341                         "  material Material { diffuseColor 1.0 1.0 1.0 }\n"
1342                         " }\n"
1343                         " geometry IndexedFaceSet {\n"
1344                         "  coord Coordinate {\n" "   point [\n");
1345           mesh_obj = true;
1346         }
1347       } else if(mesh_obj) {
1348         CPrimitive *cprim;
1349         int tri = 0;
1350         /* output connectivity */
1351         UtilConcatVLA(&vla, &cc, "   ]\n" "  }\n" "  coordIndex [\n");
1352         for(b = mesh_start; b < a; b++) {
1353           cprim = I->Primitive + b;
1354           if(TriangleReverse(cprim))
1355             sprintf(buffer, "%d %d %d -1,\n", tri, tri + 2, tri + 1);
1356           else
1357             sprintf(buffer, "%d %d %d -1,\n", tri, tri + 1, tri + 2);
1358           UtilConcatVLA(&vla, &cc, buffer);
1359           tri += 3;
1360         }
1361 
1362         /* output vertex colors */
1363         UtilConcatVLA(&vla, &cc,
1364                       "  ]\n"
1365                       "  colorPerVertex TRUE\n" "  color Color {\n" "   color [\n");
1366         for(b = mesh_start; b < a; b++) {
1367           cprim = I->Primitive + b;
1368           sprintf(buffer,
1369                   "%6.4f %6.4f %6.4f,\n"
1370                   "%6.4f %6.4f %6.4f,\n"
1371                   "%6.4f %6.4f %6.4f,\n",
1372                   cprim->c1[0], cprim->c1[1], cprim->c1[2],
1373                   cprim->c2[0], cprim->c2[1], cprim->c2[2],
1374                   cprim->c3[0], cprim->c3[1], cprim->c3[2]);
1375           UtilConcatVLA(&vla, &cc, buffer);
1376         }
1377 
1378         /* output vertex normals */
1379         UtilConcatVLA(&vla, &cc,
1380                       "  ] } \n"
1381                       "  normalPerVertex TRUE\n" "  normal Normal {\n" "   vector [\n");
1382         for(b = mesh_start; b < a; b++) {
1383           cprim = I->Primitive + b;
1384           {
1385             float *norm = base->Normal + 3 * base->Vert2Normal[cprim->vert];
1386             sprintf(buffer, "%6.4f %6.4f %6.4f,\n" "%6.4f %6.4f %6.4f,\n" "%6.4f %6.4f %6.4f,\n", norm[3], norm[4], norm[5],    /* transformed cprim->n1 */
1387                     norm[6], norm[7], norm[8],  /* transformed cprim->n2 */
1388                     norm[9], norm[10], norm[11]);       /* transformed cprim->n3 */
1389             UtilConcatVLA(&vla, &cc, buffer);
1390           }
1391         }
1392         UtilConcatVLA(&vla, &cc, "  ] }\n" "  normalIndex [ \n");
1393         tri = 0;
1394         for(b = mesh_start; b < a; b++) {
1395           cprim = I->Primitive + b;
1396           if(TriangleReverse(cprim))
1397             sprintf(buffer, "%d %d %d -1,\n", tri, tri + 2, tri + 1);
1398           else
1399             sprintf(buffer, "%d %d %d -1,\n", tri, tri + 1, tri + 2);
1400           UtilConcatVLA(&vla, &cc, buffer);
1401           tri += 3;
1402         }
1403 
1404         /* close mesh */
1405         UtilConcatVLA(&vla, &cc, " ] \n" " }\n" "}\n");
1406         mesh_obj = false;
1407       }
1408 
1409       switch (prim->type) {
1410       case cPrimSphere:
1411         sprintf(buffer,
1412                 "Transform {\n"
1413                 " translation %8.6f %8.6f %8.6f\n"
1414                 " children Shape {\n"
1415                 "  geometry Sphere { radius %8.6f }\n"
1416                 "  appearance Appearance {\n"
1417                 "   material Material { diffuseColor %6.4f %6.4f %6.4f \n"
1418                 "                       specularColor 0.8 0.8 0.8 \n"
1419                 "                       shininess 0.8 }\n"
1420                 "  }\n"
1421                 " }\n"
1422                 "}\n",
1423                 vert[0] - mid[0],
1424                 vert[1] - mid[1],
1425                 vert[2] - mid[2], prim->r1, prim->c1[0], prim->c1[1], prim->c1[2]);
1426         UtilConcatVLA(&vla, &cc, buffer);
1427         break;
1428       case cPrimCone:
1429         /* TO DO */
1430         break;
1431       case cPrimCylinder:
1432       case cPrimSausage:
1433         {
1434           float *d, vert2[3], axis[3], angle;
1435           OrthoLineType geometry;
1436           /* find the axis and angle that will rotate the y axis onto
1437            * the direction of the length of the cylinder
1438            */
1439           d = base->Normal + 3 * base->Vert2Normal[prim->vert];
1440           if((d[0] * d[0] + d[2] * d[2]) < 0.000001) {
1441             /* parallel with y */
1442             axis[0] = 1.0;
1443             axis[1] = 0.0;
1444             axis[2] = 0.0;
1445             if(d[1] > 0) {
1446               angle = 0.0;
1447             } else {
1448               angle = cPI;
1449             }
1450           } else {
1451             axis[0] = d[2];
1452             axis[1] = 0.0;
1453             axis[2] = -d[0];
1454             normalize3f(axis);
1455             angle = d[1];
1456             if(angle > 1.0)
1457               angle = 1.0;
1458             else if(angle < -1.0)
1459               angle = -1.0;
1460             angle = acos(angle);
1461           }
1462           /* vrml cylinders have origin in middle, not tip, that is why we
1463            * use prim->l1/2
1464            */
1465           scale3f(d, prim->l1 / 2, vert2);
1466           add3f(vert, vert2, vert2);
1467           if(prim->type == cPrimSausage) {
1468             OrthoLineType geom_add;
1469             sprintf(geometry,
1470                     "  Shape {\n"
1471                     "   geometry Cylinder {\n"
1472                     "    radius %8.6f\n"
1473                     "    height %8.6f\n"
1474                     "    bottom FALSE\n"
1475                     "    top    FALSE\n"
1476                     "   }\n"
1477                     "   appearance Appearance {\n"
1478                     "   material Material { diffuseColor %6.4f %6.4f %6.4f \n"
1479                     "                       specularColor 0.8 0.8 0.8 \n"
1480                     "                       shininess 0.8 }\n"
1481                     "   }\n",
1482                     prim->r1, prim->l1,
1483                     (prim->c1[0] + prim->c2[0]) / 2,
1484                     (prim->c1[1] + prim->c2[1]) / 2, (prim->c1[2] + prim->c2[2]) / 2);
1485             /* WLD: format string split to comply with ISO C89 standards */
1486             sprintf(geom_add,
1487                     "  }\n"
1488                     "  Transform {\n"
1489                     "   translation 0.0 %8.6f 0.0\n"
1490                     "   children Shape {\n"
1491                     "    geometry Sphere { radius %8.6f }\n"
1492                     "    appearance Appearance {\n"
1493                     "   material Material { diffuseColor %6.4f %6.4f %6.4f \n"
1494                     "                       specularColor 0.8 0.8 0.8 \n"
1495                     "                       shininess 0.8 }\n"
1496                     "    }\n"
1497                     "   }\n"
1498                     "  }\n", prim->l1 / 2, prim->r1, prim->c1[0], prim->c1[1], prim->c1[2]
1499               );
1500             strcat(geometry, geom_add);
1501             /* WLD: format string split to comply with ISO C89 standards */
1502             sprintf(geom_add,
1503                     "  Transform {\n"
1504                     "   translation 0.0 %8.6f 0.0\n"
1505                     "   children Shape {\n"
1506                     "    geometry Sphere { radius %8.6f }\n"
1507                     "    appearance Appearance {\n"
1508                     "   material Material { diffuseColor %6.4f %6.4f %6.4f \n"
1509                     "                       specularColor 0.8 0.8 0.8 \n"
1510                     "                       shininess 0.8 }\n"
1511                     "    }\n"
1512                     "   }\n"
1513                     "  }\n",
1514                     -prim->l1 / 2, prim->r1, prim->c2[0], prim->c2[1], prim->c2[2]);
1515             strcat(geometry, geom_add);
1516           } else {
1517             sprintf(geometry,
1518                     "  Shape {\n"
1519                     "   geometry Cylinder {\n"
1520                     "    radius %8.6f\n"
1521                     "    height %8.6f\n"
1522                     "   }\n"
1523                     "   appearance Appearance {\n"
1524                     "   material Material { diffuseColor %6.4f %6.4f %6.4f \n"
1525                     "                       specularColor 0.8 0.8 0.8 \n"
1526                     "                       shininess 0.8 }\n"
1527                     "   }\n"
1528                     "  }\n",
1529                     prim->r1, prim->l1,
1530                     (prim->c1[0] + prim->c2[0]) / 2,
1531                     (prim->c1[1] + prim->c2[1]) / 2, (prim->c1[2] + prim->c2[2]) / 2);
1532           }
1533           sprintf(buffer,
1534                   "Transform {\n"
1535                   " translation %8.6f %8.6f %8.6f\n"
1536                   " rotation %8.6f %8.6f %8.6f %8.6f\n"
1537                   " children [\n"
1538                   "%s"
1539                   " ]\n"
1540                   "}\n",
1541                   vert2[0] - mid[0],
1542                   vert2[1] - mid[1],
1543                   vert2[2] - mid[2], axis[0], axis[1], axis[2], angle, geometry);
1544           UtilConcatVLA(&vla, &cc, buffer);
1545         }
1546         break;
1547       case cPrimTriangle:
1548         /* output coords. connectivity and vertex colors handled above/below */
1549         sprintf(buffer,
1550                 "%8.6f %8.6f %8.6f,\n"
1551                 "%8.6f %8.6f %8.6f,\n"
1552                 "%8.6f %8.6f %8.6f,\n",
1553                 vert[0] - mid[0], vert[1] - mid[1], vert[2] - mid[2],
1554                 vert[3] - mid[0], vert[4] - mid[1], vert[5] - mid[2],
1555                 vert[6] - mid[0], vert[7] - mid[1], vert[8] - mid[2]);
1556         UtilConcatVLA(&vla, &cc, buffer);
1557         break;
1558       }
1559     }
1560 
1561     if(mesh_obj) {
1562       CBasis *base = I->Basis + 1;
1563       CPrimitive *cprim;
1564       int tri = 0;
1565       /* output connectivity */
1566       UtilConcatVLA(&vla, &cc, "   ]\n" "  }\n" "  coordIndex [\n");
1567       for(b = mesh_start; b < a; b++) {
1568         cprim = I->Primitive + b;
1569         if(TriangleReverse(cprim))
1570           sprintf(buffer, "%d %d %d -1,\n", tri, tri + 2, tri + 1);
1571         else
1572           sprintf(buffer, "%d %d %d -1,\n", tri, tri + 1, tri + 2);
1573         UtilConcatVLA(&vla, &cc, buffer);
1574         tri += 3;
1575       }
1576 
1577       /* output vertex colors */
1578       UtilConcatVLA(&vla, &cc,
1579                     "  ]\n" "  colorPerVertex TRUE\n" "  color Color {\n" "   color [\n");
1580       for(b = mesh_start; b < a; b++) {
1581         cprim = I->Primitive + b;
1582         sprintf(buffer,
1583                 "%6.4f %6.4f %6.4f,\n"
1584                 "%6.4f %6.4f %6.4f,\n"
1585                 "%6.4f %6.4f %6.4f,\n",
1586                 cprim->c1[0], cprim->c1[1], cprim->c1[2],
1587                 cprim->c2[0], cprim->c2[1], cprim->c2[2],
1588                 cprim->c3[0], cprim->c3[1], cprim->c3[2]);
1589         UtilConcatVLA(&vla, &cc, buffer);
1590       }
1591 
1592       /* output vertex normals */
1593       UtilConcatVLA(&vla, &cc,
1594                     "  ] } \n"
1595                     "  normalPerVertex TRUE\n" "  normal Normal {\n" "   vector [\n");
1596       for(b = mesh_start; b < a; b++) {
1597         cprim = I->Primitive + b;
1598         {
1599           float *norm = base->Normal + 3 * base->Vert2Normal[cprim->vert];
1600           sprintf(buffer, "%6.4f %6.4f %6.4f,\n" "%6.4f %6.4f %6.4f,\n" "%6.4f %6.4f %6.4f,\n", norm[3], norm[4], norm[5],      /* transformed cprim->n1 */
1601                   norm[6], norm[7], norm[8],    /* transformed cprim->n2 */
1602                   norm[9], norm[10], norm[11]); /* transformed cprim->n3 */
1603           UtilConcatVLA(&vla, &cc, buffer);
1604         }
1605       }
1606       UtilConcatVLA(&vla, &cc, "  ] }\n" "  normalIndex [ \n");
1607       tri = 0;
1608       for(b = mesh_start; b < a; b++) {
1609         cprim = I->Primitive + b;
1610         if(TriangleReverse(cprim))
1611           sprintf(buffer, "%d %d %d -1,\n", tri, tri + 2, tri + 1);
1612         else
1613           sprintf(buffer, "%d %d %d -1,\n", tri, tri + 1, tri + 2);
1614         UtilConcatVLA(&vla, &cc, buffer);
1615         tri += 3;
1616       }
1617 
1618       /* close mesh */
1619       UtilConcatVLA(&vla, &cc, " ] \n" " }\n" "}\n");
1620       mesh_obj = false;
1621     }
1622   }
1623 
1624   *vla_ptr = vla;
1625 }
1626 
1627 
1628 /* simple write-once/read-many hash for float-3/4 vectors  */
1629 
1630 #define VECTOR_HASH_MASK 0xFFFF
1631 
1632 typedef struct {
1633   float key[4];
1634   int value;
1635   int next;                     /* 1-based offsets, 0 = terminal */
1636 } VectorHashElem;
1637 
1638 typedef struct {
1639   int first[VECTOR_HASH_MASK + 1];
1640   VectorHashElem *elem;
1641   int size;
1642 } VectorHash;
1643 
VectorHash_Free(VectorHash * I)1644 static void VectorHash_Free(VectorHash * I)
1645 {
1646   if(I) {
1647     VLAFreeP(I->elem);
1648   }
1649   FreeP(I);
1650 }
1651 
VectorHash_New(void)1652 static VectorHash *VectorHash_New(void)
1653 {
1654   VectorHash *I = pymol::calloc<VectorHash>(1);
1655   if(I) {
1656     I->elem = VLACalloc(VectorHashElem, 100);
1657     if(!I->elem) {
1658       VectorHash_Free(I);
1659       I = NULL;
1660     }
1661   }
1662   return I;
1663 }
1664 
VectorHash_GetOrSetKeyValue(VectorHash * I,float * key,float * alpha,int * value)1665 static int VectorHash_GetOrSetKeyValue(VectorHash * I, float *key, float *alpha,
1666                                        int *value)
1667 {
1668   unsigned int hash;
1669   /* returns non-zero if the entry is new */
1670   {
1671     unsigned int a, b, c;
1672 
1673     a = ((unsigned int *) key)[0];
1674     b = ((unsigned int *) key)[1];
1675     c = ((unsigned int *) key)[2];
1676 
1677     /* Robert Jenkin's 96 to 32 bit hash (public domain)
1678        this is probably way overkill */
1679 
1680     a = a - b;
1681     a = a - c;
1682     a = a ^ (c >> 13);
1683     b = b - c;
1684     b = b - a;
1685     b = b ^ (a << 8);
1686     c = c - a;
1687     c = c - b;
1688     c = c ^ (b >> 13);
1689     a = a - b;
1690     a = a - c;
1691     a = a ^ (c >> 12);
1692     b = b - c;
1693     b = b - a;
1694     b = b ^ (a << 16);
1695     c = c - a;
1696     c = c - b;
1697     c = c ^ (b >> 5);
1698     a = a - b;
1699     a = a - c;
1700     a = a ^ (c >> 3);
1701     b = b - c;
1702     b = b - a;
1703     b = b ^ (a << 10);
1704     c = c - a;
1705     c = c - b;
1706     c = c ^ (b >> 15);
1707 
1708     /* mix in the fourth key (if present) */
1709 
1710     if(alpha) {
1711       unsigned int d = *((unsigned int *) alpha);
1712       c = c + d;
1713     }
1714 
1715     /* fold those 32 bits to 16 */
1716 
1717     c ^= (c >> 16);
1718 
1719     /* apply mask */
1720 
1721     hash = c & VECTOR_HASH_MASK;
1722   }
1723   {
1724     int offset = I->first[hash];
1725     while(offset) {
1726       VectorHashElem *elem = I->elem + offset;
1727       float *v = elem->key;
1728       if((v[0] == key[0]) && (v[1] == key[1]) && (v[2] == key[2])) {
1729         if((!alpha) || (*alpha == v[3])) {
1730           *value = elem->value; /* matched, so return value */
1731           return 0;             /* key/value exists */
1732         }
1733       }
1734       offset = elem->next;
1735     }
1736     /* not matched -- add new key/value  */
1737     if(VLACheck(I->elem, VectorHashElem, ++(I->size))) {
1738       VectorHashElem *elem = I->elem + I->size;
1739       elem->next = I->first[hash];
1740       I->first[hash] = I->size;
1741       copy3f(key, elem->key);
1742       if(alpha)
1743         elem->key[3] = *alpha;
1744       elem->value = *value;
1745       return 1;                 /* inform caller */
1746     } else {
1747       I->size--;
1748       return -1;
1749     }
1750   }
1751 }
1752 
unique_vector_add(VectorHash * vh,float * vector,float * vector_array,int * vector_count,int * index_array,int * index_count)1753 static void unique_vector_add(VectorHash * vh, float *vector,
1754                               float *vector_array, int *vector_count,
1755                               int *index_array, int *index_count)
1756 {
1757   int index = *vector_count;
1758   switch (VectorHash_GetOrSetKeyValue(vh, vector, NULL, &index)) {
1759   case 1:
1760     {
1761       float *vector_slot = vector_array + 3 * (*vector_count);
1762       copy3f(vector, vector_slot);
1763       (*vector_count)++;
1764     }
1765     /* INTENTIONAL omission of break */
1766   case 0:
1767     index_array[(*index_count)++] = index;
1768     break;
1769   }
1770 }
1771 
unique_color_add(VectorHash * vh,float * vector,float * vector_array,int * vector_count,int * index_array,int * index_count,float alpha)1772 static void unique_color_add(VectorHash * vh, float *vector,
1773                              float *vector_array, int *vector_count,
1774                              int *index_array, int *index_count, float alpha)
1775 {
1776   int index = *vector_count;
1777 
1778   switch (VectorHash_GetOrSetKeyValue(vh, vector, &alpha, &index)) {
1779   case 1:
1780     {
1781       float *vector_slot = vector_array + 4 * (*vector_count);  /* NOTE 4x spacing */
1782       copy3f(vector, vector_slot);
1783       vector_slot[3] = alpha;
1784       (*vector_count)++;
1785     }
1786     /* INTENTIONAL omission of break */
1787   case 0:
1788     index_array[(*index_count)++] = index;
1789     break;
1790   }
1791 }
1792 
1793 #define noIDTF_COLOR
1794 
1795 typedef struct {
1796   int face_count;
1797   int position_count;
1798   int normal_count;
1799   int *face_position_list;
1800   int *face_normal_list;
1801   int *face_shading_list;
1802   float *model_position_list;
1803   float *model_normal_list;
1804   VectorHash *position_hash;
1805   VectorHash *normal_hash;
1806   int color_count;
1807   int *face_color_list;
1808   float *model_diffuse_color_list;
1809   VectorHash *color_hash;
1810 } IdtfResourceMesh;
1811 
1812 typedef struct {
1813   float *color_list;
1814   int color_count;
1815   VectorHash *color_hash;
1816 } IdtfMaterial;
1817 
idtf_dump_file_header(char ** vla,ov_size cnt)1818 static ov_size idtf_dump_file_header(char **vla, ov_size cnt)
1819 {
1820   UtilConcatVLA(vla, &cnt, "FILE_FORMAT \"IDTF\"\nFORMAT_VERSION 100\n\n");
1821 
1822   UtilConcatVLA(vla, &cnt, "NODE \"VIEW\" {\n");
1823   UtilConcatVLA(vla, &cnt, "\tNODE_NAME \"DefaultView\"\n");
1824   UtilConcatVLA(vla, &cnt, "\tPARENT_LIST {\n");
1825   UtilConcatVLA(vla, &cnt, "\t\tPARENT_COUNT 1\n");
1826   UtilConcatVLA(vla, &cnt, "\t\tPARENT 0 {\n\t\t\tPARENT_NAME \"<NULL>\"\n");
1827   UtilConcatVLA(vla, &cnt, "\t\t\tPARENT_TM {\n");
1828   UtilConcatVLA(vla, &cnt, "\t\t\t\t1.000000 0.000000 0.000000 0.0\n");
1829   UtilConcatVLA(vla, &cnt, "\t\t\t\t0.000000 1.000000 0.000000 0.0\n");
1830   UtilConcatVLA(vla, &cnt, "\t\t\t\t0.000000 0.000000 1.000000 0.0\n");
1831   UtilConcatVLA(vla, &cnt, "\t\t\t\t0.000000 0.000000 0.000000 1.0\n");
1832   UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
1833   UtilConcatVLA(vla, &cnt, "\t\t}\n");
1834   UtilConcatVLA(vla, &cnt, "\t}\n");
1835   UtilConcatVLA(vla, &cnt, "\tRESOURCE_NAME \"SceneViewResource\"\n");
1836   UtilConcatVLA(vla, &cnt, "\tVIEW_DATA {\n");
1837   UtilConcatVLA(vla, &cnt, "\t\tVIEW_TYPE \"PERSPECTIVE\"\n");
1838   UtilConcatVLA(vla, &cnt, "\t\tVIEW_PROJECTION 34.515877\n");
1839   UtilConcatVLA(vla, &cnt, "\t}\n");
1840   UtilConcatVLA(vla, &cnt, "}\n\n");
1841 
1842   UtilConcatVLA(vla, &cnt, "NODE \"LIGHT\"\n");
1843   UtilConcatVLA(vla, &cnt, "{\n");
1844   UtilConcatVLA(vla, &cnt, "\tNODE_NAME \"Omni01\"\n");
1845   UtilConcatVLA(vla, &cnt, "\tPARENT_LIST {\n");
1846   UtilConcatVLA(vla, &cnt, "\t\tPARENT_COUNT 1\n");
1847   UtilConcatVLA(vla, &cnt, "\t\tPARENT 0 {\n");
1848   UtilConcatVLA(vla, &cnt, "\t\t\tPARENT_NAME \"<NULL>\"\n");
1849   UtilConcatVLA(vla, &cnt, "\t\t\tPARENT_TM {\n");
1850   UtilConcatVLA(vla, &cnt, "\t\t\t\t1.000000 0.000000 0.000000 0.000000\n");
1851   UtilConcatVLA(vla, &cnt, "\t\t\t\t0.000000 1.000000 0.000000 0.000000\n");
1852   UtilConcatVLA(vla, &cnt, "\t\t\t\t0.000000 0.000000 1.000000 0.000000\n");
1853   UtilConcatVLA(vla, &cnt, "\t\t\t\t50.000000 -50.00000 50.000000 1.000000\n");
1854   UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
1855   UtilConcatVLA(vla, &cnt, "\t\t}\n");
1856   UtilConcatVLA(vla, &cnt, "\t}\n");
1857   UtilConcatVLA(vla, &cnt, "\tRESOURCE_NAME \"DefaultPointLight\"\n");
1858   UtilConcatVLA(vla, &cnt, "}\n\n");
1859   return cnt;
1860 }
1861 
idtf_dump_model_nodes(char ** vla,ov_size cnt,IdtfResourceMesh * mesh_vla,int n_mesh)1862 static ov_size idtf_dump_model_nodes(char **vla, ov_size cnt,
1863                                      IdtfResourceMesh * mesh_vla, int n_mesh)
1864 {
1865   int a;
1866   IdtfResourceMesh *mesh = mesh_vla;
1867   for(a = 0; a < n_mesh; a++) {
1868     OrthoLineType buffer;
1869 
1870     UtilConcatVLA(vla, &cnt, "NODE \"MODEL\" {\n");
1871 
1872     sprintf(buffer, "\tNODE_NAME \"Mesh%d\"\n", a);
1873     UtilConcatVLA(vla, &cnt, buffer);
1874 
1875     UtilConcatVLA(vla, &cnt, "\tPARENT_LIST {\n");
1876     UtilConcatVLA(vla, &cnt, "\t\tPARENT_COUNT 1\n");
1877     UtilConcatVLA(vla, &cnt, "\t\tPARENT 0 {\n");
1878     UtilConcatVLA(vla, &cnt, "\t\t\tPARENT_NAME \"<NULL>\"\n");
1879     UtilConcatVLA(vla, &cnt, "\t\t\tPARENT_TM {\n");
1880     UtilConcatVLA(vla, &cnt, "\t\t\t1.000000 0.000000 0.000000 0.0\n");
1881     UtilConcatVLA(vla, &cnt, "\t\t\t0.000000 1.000000 0.000000 0.0\n");
1882     UtilConcatVLA(vla, &cnt, "\t\t\t0.000000 0.000000 1.000000 0.0\n");
1883     UtilConcatVLA(vla, &cnt, "\t\t\t0.000000 0.000000 0.000000 1.0\n");
1884     UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
1885     UtilConcatVLA(vla, &cnt, "\t\t}\n");
1886     UtilConcatVLA(vla, &cnt, "\t}\n");
1887 
1888     sprintf(buffer, "\tRESOURCE_NAME \"Mesh%d\"\n", a);
1889     UtilConcatVLA(vla, &cnt, buffer);
1890 
1891     UtilConcatVLA(vla, &cnt, "}\n\n");
1892 
1893     mesh++;
1894   }
1895   return cnt;
1896 }
1897 
idtf_dump_resource_header(char ** vla,ov_size cnt)1898 static ov_size idtf_dump_resource_header(char **vla, ov_size cnt)
1899 {
1900 
1901   UtilConcatVLA(vla, &cnt, "RESOURCE_LIST \"VIEW\" {\n");
1902   UtilConcatVLA(vla, &cnt, "\tRESOURCE_COUNT 1\n");
1903   UtilConcatVLA(vla, &cnt, "\tRESOURCE 0 {\n");
1904   UtilConcatVLA(vla, &cnt, "\t\tRESOURCE_NAME \"SceneViewResource\"\n");
1905   UtilConcatVLA(vla, &cnt, "\t\tVIEW_PASS_COUNT 1\n");
1906   UtilConcatVLA(vla, &cnt, "\t\tVIEW_ROOT_NODE_LIST {\n");
1907   UtilConcatVLA(vla, &cnt, "\t\t\tROOT_NODE 0 {\n");
1908   UtilConcatVLA(vla, &cnt, "\t\t\t\tROOT_NODE_NAME \"<NULL>\"\n");
1909   UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
1910   UtilConcatVLA(vla, &cnt, "\t\t}\n");
1911   UtilConcatVLA(vla, &cnt, "\t}\n");
1912   UtilConcatVLA(vla, &cnt, "}\n\n");
1913 
1914   UtilConcatVLA(vla, &cnt, "RESOURCE_LIST \"LIGHT\" {\n");
1915   UtilConcatVLA(vla, &cnt, "\tRESOURCE_COUNT 1\n");
1916   UtilConcatVLA(vla, &cnt, "\tRESOURCE 0 {\n");
1917   UtilConcatVLA(vla, &cnt, "\t\tRESOURCE_NAME \"DefaultPointLight\"\n");
1918   UtilConcatVLA(vla, &cnt, "\t\tLIGHT_TYPE \"POINT\"\n");
1919   UtilConcatVLA(vla, &cnt, "\t\tLIGHT_COLOR 1.000000 1.000000 1.000000\n");
1920   UtilConcatVLA(vla, &cnt, "\t\tLIGHT_ATTENUATION 1.000000 0.000000 0.000000\n");
1921   UtilConcatVLA(vla, &cnt, "\t\tLIGHT_INTENSITY 1.000000\n");
1922   UtilConcatVLA(vla, &cnt, "\t}\n");
1923   UtilConcatVLA(vla, &cnt, "}\n\n");
1924 
1925   return cnt;
1926 }
1927 
idtf_dump_resources(char ** vla,ov_size cnt,IdtfResourceMesh * mesh_vla,int n_mesh,IdtfMaterial * material)1928 static ov_size idtf_dump_resources(char **vla, ov_size cnt,
1929                                    IdtfResourceMesh * mesh_vla, int n_mesh,
1930                                    IdtfMaterial * material)
1931 {
1932   {
1933     OrthoLineType buffer;
1934     int n_color = material->color_count;
1935 
1936     UtilConcatVLA(vla, &cnt, "RESOURCE_LIST \"SHADER\" {\n");
1937 
1938     sprintf(buffer, "\tRESOURCE_COUNT %d\n", n_color);
1939     UtilConcatVLA(vla, &cnt, buffer);
1940 
1941     {
1942       int c;
1943       for(c = 0; c < n_color; c++) {
1944 
1945         sprintf(buffer, "\tRESOURCE %d {\n", c);
1946         UtilConcatVLA(vla, &cnt, buffer);
1947 
1948         sprintf(buffer, "\t\tRESOURCE_NAME \"Shader%06d\"\n", c);
1949         UtilConcatVLA(vla, &cnt, buffer);
1950 
1951         sprintf(buffer, "\t\tSHADER_MATERIAL_NAME \"Material%06d\"\n", c);
1952         UtilConcatVLA(vla, &cnt, buffer);
1953 
1954         UtilConcatVLA(vla, &cnt, "\t\tSHADER_ACTIVE_TEXTURE_COUNT 0\n");
1955         UtilConcatVLA(vla, &cnt, "\t}\n");
1956       }
1957     }
1958     UtilConcatVLA(vla, &cnt, "}\n\n");
1959   }
1960 
1961   {
1962     OrthoLineType buffer;
1963     int n_color = material->color_count;
1964 
1965     UtilConcatVLA(vla, &cnt, "RESOURCE_LIST \"MATERIAL\" {\n");
1966 
1967     sprintf(buffer, "\tRESOURCE_COUNT %d\n", n_color);
1968     UtilConcatVLA(vla, &cnt, buffer);
1969 
1970     {
1971       int c;
1972       float *fp = material->color_list;
1973 
1974       for(c = 0; c < n_color; c++) {
1975         sprintf(buffer, "\tRESOURCE %d {\n", c);
1976         UtilConcatVLA(vla, &cnt, buffer);
1977         sprintf(buffer, "\t\tRESOURCE_NAME \"Material%06d\"\n", c);
1978         UtilConcatVLA(vla, &cnt, buffer);
1979 
1980         sprintf(buffer, "\t\tMATERIAL_AMBIENT %0.6f %0.6f %0.6f\n",
1981                 fp[0] * 0, fp[1] * 0, fp[2] * 0);
1982         UtilConcatVLA(vla, &cnt, buffer);
1983 
1984         sprintf(buffer, "\t\tMATERIAL_DIFFUSE %0.6f %0.6f %0.6f\n", fp[0], fp[1], fp[2]);
1985         UtilConcatVLA(vla, &cnt, buffer);
1986 
1987         UtilConcatVLA(vla, &cnt, "\t\tMATERIAL_SPECULAR 0.750000 0.750000 0.750000\n");
1988 
1989         sprintf(buffer, "\t\tMATERIAL_EMISSIVE %0.6f %0.6f %0.6f\n",
1990                 fp[0] * 0.13, fp[1] * 0.13, fp[2] * 0.13);
1991         UtilConcatVLA(vla, &cnt, buffer);
1992         UtilConcatVLA(vla, &cnt, "\t\tMATERIAL_REFLECTIVITY 0.40000\n");
1993 
1994         sprintf(buffer, "\t\tMATERIAL_OPACITY %0.6f\n", fp[3]);
1995         UtilConcatVLA(vla, &cnt, buffer);
1996 
1997         UtilConcatVLA(vla, &cnt, "\t}\n");
1998 
1999         fp += 4;
2000       }
2001     }
2002     UtilConcatVLA(vla, &cnt, "}\n\n");
2003   }
2004 
2005   {
2006 
2007     OrthoLineType buffer;
2008     UtilConcatVLA(vla, &cnt, "RESOURCE_LIST \"MODEL\" {\n");
2009 
2010     sprintf(buffer, "\tRESOURCE_COUNT %d\n", n_mesh);
2011     UtilConcatVLA(vla, &cnt, buffer);
2012 
2013     {
2014       int a;
2015       IdtfResourceMesh *mesh = mesh_vla;
2016       for(a = 0; a < n_mesh; a++) {
2017 
2018         sprintf(buffer, "\tRESOURCE %d {\n", a);
2019         UtilConcatVLA(vla, &cnt, buffer);
2020 
2021         sprintf(buffer, "\t\tRESOURCE_NAME \"Mesh%d\"\n", a);
2022         UtilConcatVLA(vla, &cnt, buffer);
2023 
2024         UtilConcatVLA(vla, &cnt, "\t\tMODEL_TYPE \"MESH\"\n");
2025         UtilConcatVLA(vla, &cnt, "\t\tMESH {\n");
2026 
2027         sprintf(buffer, "\t\t\tFACE_COUNT %d\n", mesh->face_count);
2028         UtilConcatVLA(vla, &cnt, buffer);
2029 
2030         sprintf(buffer, "\t\t\tMODEL_POSITION_COUNT %d\n", mesh->position_count);
2031         UtilConcatVLA(vla, &cnt, buffer);
2032 
2033         sprintf(buffer, "\t\t\tMODEL_NORMAL_COUNT %d\n", mesh->normal_count);
2034         UtilConcatVLA(vla, &cnt, buffer);
2035 #ifdef IDTF_COLOR
2036         sprintf(buffer, "\t\t\tMODEL_DIFFUSE_COLOR_COUNT %d\n", mesh->color_count);
2037         UtilConcatVLA(vla, &cnt, buffer);
2038 
2039         sprintf(buffer, "\t\t\tMODEL_SPECULAR_COLOR_COUNT %d\n", mesh->color_count);
2040         UtilConcatVLA(vla, &cnt, buffer);
2041 #else
2042         UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_DIFFUSE_COLOR_COUNT 0\n");
2043         UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_SPECULAR_COLOR_COUNT 0\n");
2044 #endif
2045         UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_TEXTURE_COORD_COUNT 0\n");
2046         UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_BONE_COUNT 0\n");
2047 
2048         {
2049           int n_color = material->color_count;
2050 
2051           sprintf(buffer, "\t\t\tMODEL_SHADING_COUNT %d\n", n_color);
2052           UtilConcatVLA(vla, &cnt, buffer);
2053 
2054           UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_SHADING_DESCRIPTION_LIST {\n");
2055 
2056           {
2057             int c;
2058             for(c = 0; c < n_color; c++) {
2059 
2060               sprintf(buffer, "\t\t\t\tSHADING_DESCRIPTION %d {\n", c);
2061               UtilConcatVLA(vla, &cnt, buffer);
2062 
2063               UtilConcatVLA(vla, &cnt, "\t\t\t\tTEXTURE_LAYER_COUNT 0\n");
2064 
2065               sprintf(buffer, "\t\t\t\tSHADER_ID %d\n", c + 1);
2066               UtilConcatVLA(vla, &cnt, buffer);
2067 
2068               UtilConcatVLA(vla, &cnt, "\t\t\t\t}\n");
2069             }
2070           }
2071           UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
2072         }
2073 
2074         {
2075           int b;
2076           int *ip = mesh->face_position_list;
2077           UtilConcatVLA(vla, &cnt, "\t\t\tMESH_FACE_POSITION_LIST {\n");
2078 
2079           for(b = 0; b < mesh->face_count; b++) {
2080             sprintf(buffer, "\t\t\t%d %d %d\n", ip[0], ip[1], ip[2]);
2081             UtilConcatVLA(vla, &cnt, buffer);
2082             ip += 3;
2083           }
2084           UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
2085         }
2086 
2087         {
2088           int b;
2089           int *ip = mesh->face_normal_list;
2090           UtilConcatVLA(vla, &cnt, "\t\t\tMESH_FACE_NORMAL_LIST {\n");
2091 
2092           for(b = 0; b < mesh->face_count; b++) {
2093             sprintf(buffer, "\t\t\t%d %d %d\n", ip[0], ip[1], ip[2]);
2094             UtilConcatVLA(vla, &cnt, buffer);
2095             ip += 3;
2096           }
2097           UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
2098         }
2099 
2100         {
2101           int b;
2102           int *ip = mesh->face_shading_list;
2103           UtilConcatVLA(vla, &cnt, "\t\t\tMESH_FACE_SHADING_LIST {\n");
2104 
2105           for(b = 0; b < mesh->face_count; b++) {
2106             sprintf(buffer, "\t\t\t%d\n", ip[0]);
2107             UtilConcatVLA(vla, &cnt, buffer);
2108             ip++;
2109           }
2110           UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
2111         }
2112 
2113 #ifdef IDTF_COLOR
2114         {
2115           int b;
2116           int *ip = mesh->face_color_list;
2117           UtilConcatVLA(vla, &cnt, "\t\t\tMESH_FACE_DIFFUSE_COLOR_LIST {\n");
2118 
2119           for(b = 0; b < mesh->face_count; b++) {
2120             sprintf(buffer, "\t\t\t%d %d %d\n", ip[0], ip[1], ip[2]);
2121             UtilConcatVLA(vla, &cnt, buffer);
2122             ip += 3;
2123           }
2124           UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
2125         }
2126         {
2127           int b;
2128           int *ip = mesh->face_color_list;
2129           UtilConcatVLA(vla, &cnt, "\t\t\tMESH_FACE_SPECULAR_COLOR_LIST {\n");
2130 
2131           for(b = 0; b < mesh->face_count; b++) {
2132             sprintf(buffer, "\t\t\t%d %d %d\n", ip[0], ip[1], ip[2]);
2133             UtilConcatVLA(vla, &cnt, buffer);
2134             ip += 3;
2135           }
2136           UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
2137         }
2138 #endif
2139 
2140         {
2141           int b;
2142           float *fp = mesh->model_position_list;
2143           UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_POSITION_LIST {\n");
2144 
2145           for(b = 0; b < mesh->position_count; b++) {
2146             sprintf(buffer, "\t\t\t\t%1.6f %1.6f %1.6f\n", fp[0], fp[1], fp[2]);
2147             UtilConcatVLA(vla, &cnt, buffer);
2148             fp += 3;
2149           }
2150 
2151           UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
2152         }
2153 
2154         {
2155           int b;
2156           float *fp = mesh->model_normal_list;
2157           UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_NORMAL_LIST {\n");
2158 
2159           for(b = 0; b < mesh->normal_count; b++) {
2160             sprintf(buffer, "\t\t\t\t%1.6f %1.6f %1.6f\n", fp[0], fp[1], fp[2]);
2161             UtilConcatVLA(vla, &cnt, buffer);
2162             fp += 3;
2163           }
2164 
2165           UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
2166         }
2167 #ifdef IDTF_COLOR
2168         {
2169           int b;
2170           float *fp = mesh->model_diffuse_color_list;
2171           UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_DIFFUSE_COLOR_LIST {\n");
2172 
2173           for(b = 0; b < mesh->color_count; b++) {
2174             sprintf(buffer, "\t\t\t\t%1.6f %1.6f %1.6f %1.6f\n", fp[0], fp[1], fp[2],
2175                     fp[3]);
2176             UtilConcatVLA(vla, &cnt, buffer);
2177             fp += 4;
2178           }
2179 
2180           UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
2181         }
2182         {
2183           int b;
2184           float *fp = mesh->model_diffuse_color_list;
2185           UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_SPECULAR_COLOR_LIST {\n");
2186 
2187           for(b = 0; b < mesh->color_count; b++) {
2188             sprintf(buffer, "\t\t\t\t%1.6f %1.6f %1.6f %1.6f\n", fp[0], fp[1], fp[2],
2189                     fp[3]);
2190             UtilConcatVLA(vla, &cnt, buffer);
2191             fp += 4;
2192           }
2193 
2194           UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
2195         }
2196 #endif
2197 
2198         UtilConcatVLA(vla, &cnt, "\t\t}\n");
2199         UtilConcatVLA(vla, &cnt, "\t}\n");
2200 
2201         mesh++;
2202       }
2203     }
2204     UtilConcatVLA(vla, &cnt, "}\n\n");
2205   }
2206   return cnt;
2207 }
2208 
2209 
2210 /*========================================================================*/
RayRenderIDTF(CRay * I,char ** node_vla,char ** rsrc_vla)2211 void RayRenderIDTF(CRay * I, char **node_vla, char **rsrc_vla)
2212 {
2213   int identity = (SettingGetGlobal_i(I->G, cSetting_geometry_export_mode) == 1);
2214 
2215   RayExpandPrimitives(I);
2216   RayTransformFirst(I, 0, identity);
2217 
2218   {
2219     CBasis *base = I->Basis + 1;
2220     CPrimitive *prim = I->Primitive;
2221     int mesh_cnt = 0;
2222     IdtfResourceMesh *mesh_vla = VLACalloc(IdtfResourceMesh, 1);
2223     if(mesh_vla) {
2224       IdtfResourceMesh *mesh = NULL;
2225       int a;
2226 
2227       for(a = 0; a < I->NPrimitive; a++) {
2228 
2229         switch (prim->type) {
2230         case cPrimTriangle:
2231         case cPrimSphere:
2232           if(!mesh) {
2233             /* create a new triangle mesh */
2234             if(VLACheck(mesh_vla, IdtfResourceMesh, mesh_cnt)) {
2235               mesh = mesh_vla + mesh_cnt;
2236               if((mesh->face_position_list = VLACalloc(int, 3)) && (mesh->face_normal_list = VLACalloc(int, 3)) && (mesh->face_shading_list = VLACalloc(int, 1)) &&     /* defaults to zero */
2237 
2238                  (mesh->model_position_list = VLAlloc(float, 3)) &&
2239                  (mesh->face_color_list = VLACalloc(int, 3)) &&
2240                  (mesh->model_diffuse_color_list = VLAlloc(float, 4)) &&
2241                  ((mesh->color_hash = VectorHash_New())) &&
2242                  (mesh->model_normal_list = VLAlloc(float, 3)) &&
2243                  ((mesh->position_hash = VectorHash_New())) &&
2244                  ((mesh->normal_hash = VectorHash_New()))
2245                 ) {
2246                 mesh_cnt++;
2247               } else {
2248                 mesh = NULL;
2249               }
2250             }
2251           }
2252           break;
2253         default:               /* close/terminate mesh */
2254           if(mesh) {
2255             mesh = NULL;
2256           }
2257           break;
2258         }
2259 
2260         switch (prim->type) {
2261         case cPrimTriangle:
2262           if(mesh) {
2263             if(VLACheck(mesh->face_position_list, int, mesh->face_count * 3 + 2) &&
2264                VLACheck(mesh->face_normal_list, int, mesh->face_count * 3 + 2) &&
2265                VLACheck(mesh->face_shading_list, int, mesh->face_count) &&
2266                VLACheck(mesh->model_position_list, float, (mesh->position_count + 3) * 3)
2267                && VLACheck(mesh->face_color_list, int, mesh->face_count * 3 + 2)
2268                && VLACheck(mesh->model_diffuse_color_list, float,
2269                            (mesh->color_count + 3) * 4)
2270                && VLACheck(mesh->model_normal_list, float, (mesh->normal_count + 3) * 3)
2271               ) {
2272 
2273               float *vert = base->Vertex + 3 * (prim->vert);
2274               float *norm = base->Normal + 3 * base->Vert2Normal[prim->vert] + 3;
2275               int reverse = TriangleReverse(prim);
2276               int face_position_count = mesh->face_count * 3;
2277               int face_normal_count = face_position_count;
2278               int face_color_count = face_position_count;
2279 
2280               unique_vector_add(mesh->position_hash, vert,
2281                                 mesh->model_position_list, &mesh->position_count,
2282                                 mesh->face_position_list, &face_position_count);
2283               unique_vector_add(mesh->normal_hash, norm,
2284                                 mesh->model_normal_list, &mesh->normal_count,
2285                                 mesh->face_normal_list, &face_normal_count);
2286               unique_color_add(mesh->normal_hash, prim->c1,
2287                                mesh->model_diffuse_color_list, &mesh->color_count,
2288                                mesh->face_color_list, &face_color_count,
2289                                1.0F - prim->trans);
2290               if(reverse) {
2291                 vert += 6;
2292                 norm += 6;
2293                 unique_vector_add(mesh->position_hash, vert,
2294                                   mesh->model_position_list, &mesh->position_count,
2295                                   mesh->face_position_list, &face_position_count);
2296                 unique_vector_add(mesh->normal_hash, norm,
2297                                   mesh->model_normal_list, &mesh->normal_count,
2298                                   mesh->face_normal_list, &face_normal_count);
2299                 unique_color_add(mesh->normal_hash, prim->c3,
2300                                  mesh->model_diffuse_color_list, &mesh->color_count,
2301                                  mesh->face_color_list, &face_color_count,
2302                                  1.0F - prim->trans);
2303                 vert -= 3;
2304                 norm -= 3;
2305                 unique_vector_add(mesh->position_hash, vert,
2306                                   mesh->model_position_list, &mesh->position_count,
2307                                   mesh->face_position_list, &face_position_count);
2308                 unique_vector_add(mesh->normal_hash, norm,
2309                                   mesh->model_normal_list, &mesh->normal_count,
2310                                   mesh->face_normal_list, &face_normal_count);
2311                 unique_color_add(mesh->normal_hash, prim->c2,
2312                                  mesh->model_diffuse_color_list, &mesh->color_count,
2313                                  mesh->face_color_list, &face_color_count,
2314                                  1.0F - prim->trans);
2315               } else {
2316                 vert += 3;
2317                 norm += 3;
2318                 unique_vector_add(mesh->position_hash, vert,
2319                                   mesh->model_position_list, &mesh->position_count,
2320                                   mesh->face_position_list, &face_position_count);
2321                 unique_vector_add(mesh->normal_hash, norm,
2322                                   mesh->model_normal_list, &mesh->normal_count,
2323                                   mesh->face_normal_list, &face_normal_count);
2324                 unique_color_add(mesh->normal_hash, prim->c2,
2325                                  mesh->model_diffuse_color_list, &mesh->color_count,
2326                                  mesh->face_color_list, &face_color_count,
2327                                  1.0F - prim->trans);
2328                 vert += 3;
2329                 norm += 3;
2330                 unique_vector_add(mesh->position_hash, vert,
2331                                   mesh->model_position_list, &mesh->position_count,
2332                                   mesh->face_position_list, &face_position_count);
2333                 unique_vector_add(mesh->normal_hash, norm,
2334                                   mesh->model_normal_list, &mesh->normal_count,
2335                                   mesh->face_normal_list, &face_normal_count);
2336                 unique_color_add(mesh->normal_hash, prim->c3,
2337                                  mesh->model_diffuse_color_list, &mesh->color_count,
2338                                  mesh->face_color_list, &face_color_count,
2339                                  1.0F - prim->trans);
2340               }
2341               mesh->face_count++;
2342             }
2343           }
2344           break;
2345         case cPrimSphere:
2346 
2347           break;
2348         case cPrimCone:
2349           break;
2350         case cPrimCylinder:
2351         case cPrimSausage:
2352           break;
2353         }
2354 
2355         /* looping through each primitive */
2356         prim++;
2357       }
2358 
2359       /* now we need to consolidate materials for each color
2360          combination (creating averages as necessary) and update
2361          mesh->face_shading_list appropriately for each face */
2362 
2363       {
2364         IdtfMaterial *material = pymol::calloc<IdtfMaterial>(1);
2365         if(material &&
2366            (material->color_list = VLAlloc(float, 4)) &&
2367            (material->color_hash = VectorHash_New())) {
2368 
2369           const float one_third = (1 / 3.0F);
2370           int a;
2371           IdtfResourceMesh *mesh = mesh_vla;
2372 
2373           for(a = 0; a < mesh_cnt; a++) {
2374             int *ip = mesh->face_color_list;
2375             int shading_count = 0;
2376             int b;
2377             for(b = 0; b < mesh->face_count; b++) {
2378               float *fp0 = mesh->model_diffuse_color_list + 4 * ip[0];
2379               float *fp1 = mesh->model_diffuse_color_list + 4 * ip[1];
2380               float *fp2 = mesh->model_diffuse_color_list + 4 * ip[2];
2381               float avg_rgba[4];
2382 
2383               avg_rgba[0] = (fp0[0] + fp1[0] + fp2[0]) * one_third;
2384               avg_rgba[1] = (fp0[1] + fp1[1] + fp2[1]) * one_third;
2385               avg_rgba[2] = (fp0[2] + fp1[2] + fp2[2]) * one_third;
2386               avg_rgba[3] = (fp0[3] + fp1[3] + fp2[3]) * one_third;
2387 
2388               if(VLACheck(material->color_list, float, material->color_count * 4 + 3)) {
2389                 unique_color_add(material->color_hash, avg_rgba,
2390                                  material->color_list, &material->color_count,
2391                                  mesh->face_shading_list, &shading_count, avg_rgba[3]);
2392               }
2393               ip += 3;
2394             }
2395             mesh++;
2396           }
2397 
2398           {
2399             int cnt = 0;
2400             cnt = idtf_dump_file_header(node_vla, cnt);
2401             cnt = idtf_dump_model_nodes(node_vla, cnt, mesh_vla, mesh_cnt);
2402             VLASize((*node_vla), char, cnt + 1);
2403           }
2404           {
2405             int cnt = 0;
2406             cnt = idtf_dump_resource_header(rsrc_vla, cnt);
2407             cnt = idtf_dump_resources(rsrc_vla, cnt, mesh_vla, mesh_cnt, material);
2408             VLASize((*rsrc_vla), char, cnt + 1);
2409           }
2410 
2411           VLAFreeP(material->color_list);
2412           VectorHash_Free(material->color_hash);
2413         }
2414         FreeP(material);
2415       }
2416 
2417       {
2418         /* refactor into a delete method */
2419         IdtfResourceMesh *mesh = mesh_vla;
2420         int i;
2421         for(i = 0; i < mesh_cnt; i++) {
2422           VLAFreeP(mesh->face_position_list);
2423           VLAFreeP(mesh->face_normal_list);
2424           VLAFreeP(mesh->face_shading_list);
2425           VLAFreeP(mesh->face_color_list);
2426           VLAFreeP(mesh->model_position_list);
2427           VLAFreeP(mesh->model_normal_list);
2428           VLAFreeP(mesh->model_diffuse_color_list);
2429           VectorHash_Free(mesh->color_hash);
2430           VectorHash_Free(mesh->position_hash);
2431           VectorHash_Free(mesh->normal_hash);
2432           mesh++;
2433         }
2434         VLAFreeP(mesh_vla);
2435       }
2436     }
2437   }
2438 }
2439 
2440 
2441 /*========================================================================*/
RayRenderObjMtl(CRay * I,int width,int height,char ** objVLA_ptr,char ** mtlVLA_ptr,float front,float back,float fov,float angle,float z_corr)2442 void RayRenderObjMtl(CRay * I, int width, int height, char **objVLA_ptr,
2443                      char **mtlVLA_ptr, float front, float back, float fov,
2444                      float angle, float z_corr)
2445 {
2446   char *objVLA = *objVLA_ptr;
2447   char *mtlVLA = *mtlVLA_ptr;
2448   int identity = (SettingGetGlobal_i(I->G, cSetting_geometry_export_mode) == 1);
2449 
2450   ov_size oc = 0;               /* obj character count */
2451   /*  int mc = 0; *//* mtl character count */
2452 
2453   OrthoLineType buffer;
2454 
2455   RayExpandPrimitives(I);
2456   RayTransformFirst(I, 0, identity);
2457 
2458   {
2459     int a;
2460     CPrimitive *prim;
2461     float *vert, *norm;
2462     int vc = 0;
2463     int nc = 0;
2464     CBasis *base = I->Basis + 1;
2465 
2466     for(a = 0; a < I->NPrimitive; a++) {
2467       prim = I->Primitive + a;
2468       vert = base->Vertex + 3 * (prim->vert);
2469       norm = base->Normal + 3 * base->Vert2Normal[prim->vert] + 3;
2470       switch (prim->type) {
2471       case cPrimTriangle:
2472         sprintf(buffer, "v %8.6f %8.6f %8.6f\n", vert[0], vert[1], vert[2] - z_corr);
2473         UtilConcatVLA(&objVLA, &oc, buffer);
2474         sprintf(buffer, "v %8.6f %8.6f %8.6f\n", vert[3], vert[4], vert[5] - z_corr);
2475         UtilConcatVLA(&objVLA, &oc, buffer);
2476         sprintf(buffer, "v %8.6f %8.6f %8.6f\n", vert[6], vert[7], vert[8] - z_corr);
2477         UtilConcatVLA(&objVLA, &oc, buffer);
2478         sprintf(buffer, "vn %8.6f %8.6f %8.6f\n", norm[0], norm[1], norm[2]);
2479         UtilConcatVLA(&objVLA, &oc, buffer);
2480         sprintf(buffer, "vn %8.6f %8.6f %8.6f\n", norm[3], norm[4], norm[5]);
2481         UtilConcatVLA(&objVLA, &oc, buffer);
2482         sprintf(buffer, "vn %8.6f %8.6f %8.6f\n", norm[6], norm[7], norm[8]);
2483         UtilConcatVLA(&objVLA, &oc, buffer);
2484         if(TriangleReverse(prim)) {
2485           sprintf(buffer, "f %d//%d %d//%d %d//%d\n",
2486                   vc + 1, nc + 1, vc + 3, nc + 3, vc + 2, nc + 2);
2487         } else {
2488           sprintf(buffer, "f %d//%d %d//%d %d//%d\n",
2489                   vc + 1, nc + 1, vc + 2, nc + 2, vc + 3, nc + 3);
2490         }
2491         UtilConcatVLA(&objVLA, &oc, buffer);
2492         nc += 3;
2493         vc += 3;
2494 
2495         /*
2496            prim->c1[0],prim->c1[1],prim->c1[2])
2497            prim->c2[0],prim->c2[1],prim->c2[2],
2498            prim->c3[0],prim->c3[1],prim->c3[2]
2499            UtilConcatVLA(&vla,&oc,buffer);
2500            UtilConcatVLA(&vla,&oc,buffer);
2501          */
2502 
2503         break;
2504       case cPrimSphere:
2505         /*      sprintf(buffer,"v %8.6f %8.6f %8.6f\np %d\n",
2506            vert[0],vert[1],vert[2]-z_corr,vc+1);
2507            UtilConcatVLA(&objVLA,&oc,buffer); */
2508 
2509         sprintf(buffer, "v %8.6f %8.6f %8.6f\n", vert[0], vert[1], vert[2] - z_corr);
2510         UtilConcatVLA(&objVLA, &oc, buffer);
2511         sprintf(buffer, "v %8.6f %8.6f %8.6f\n", vert[0], vert[1], vert[2] - z_corr);
2512         UtilConcatVLA(&objVLA, &oc, buffer);
2513         sprintf(buffer, "v %8.6f %8.6f %8.6f\n", vert[0], vert[1], vert[2] - z_corr);
2514         UtilConcatVLA(&objVLA, &oc, buffer);
2515         sprintf(buffer, "f %d %d %d\n", vc + 1, vc + 2, vc + 3);
2516         UtilConcatVLA(&objVLA, &oc, buffer);
2517         vc += 3;
2518         break;
2519       }
2520     }
2521   }
2522 
2523   *objVLA_ptr = objVLA;
2524   *mtlVLA_ptr = mtlVLA;
2525 }
2526 
2527 
2528 /*========================================================================*/
RayRenderPOV(CRay * I,int width,int height,char ** headerVLA_ptr,char ** charVLA_ptr,float front,float back,float fov,float angle,int antialias)2529 void RayRenderPOV(CRay * I, int width, int height, char **headerVLA_ptr,
2530                   char **charVLA_ptr, float front, float back, float fov,
2531                   float angle, int antialias)
2532 {
2533   float fog;
2534   const float *bkrd;
2535   float fog_start = 0.0F;
2536   float gamma;
2537   float *d;
2538   CBasis *base;
2539   CPrimitive *prim;
2540   OrthoLineType buffer;
2541   float *vert, *norm;
2542   float vert2[3];
2543   ov_size cc, hc;
2544   int a;
2545   int smooth_color_triangle;
2546   int mesh_obj = false;
2547   char *charVLA, *headerVLA;
2548   char transmit[64];
2549   float light[3];
2550   const float *lightv;
2551   float spec_power = SettingGetGlobal_f(I->G, cSetting_spec_power);
2552   int identity = (SettingGetGlobal_i(I->G, cSetting_geometry_export_mode) == 1);
2553 
2554   if(spec_power < 0.0F) {
2555     spec_power = SettingGetGlobal_f(I->G, cSetting_shininess);
2556   }
2557   spec_power /= 4.0F;
2558 
2559   charVLA = *charVLA_ptr;
2560   headerVLA = *headerVLA_ptr;
2561   smooth_color_triangle = SettingGetGlobal_b(I->G, cSetting_smooth_color_triangle);
2562   PRINTFB(I->G, FB_Ray, FB_Blather)
2563     " RayRenderPOV: w %d h %d f %8.3f b %8.3f\n", width, height, front, back ENDFB(I->G);
2564   if(Feedback(I->G, FB_Ray, FB_Blather)) {
2565     dump3f(I->Volume, " RayRenderPOV: vol");
2566     dump3f(I->Volume + 3, " RayRenderPOV: vol");
2567   }
2568   cc = 0;
2569   hc = 0;
2570   gamma = SettingGetGlobal_f(I->G, cSetting_gamma);
2571   if(gamma > R_SMALL4)
2572     gamma = 1.0F / gamma;
2573   else
2574     gamma = 1.0F;
2575 
2576   lightv = SettingGetfv(I->G, cSetting_light);
2577   copy3f(lightv, light);
2578 
2579   fog = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog);
2580   if(fog < 0.0F)
2581     fog = SettingGetGlobal_b(I->G, cSetting_depth_cue);
2582   if(fog != 0.0F) {
2583     if(fog > 1.0F)
2584       fog = 1.0F;
2585     fog_start = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog_start);
2586     if(fog_start < 0.0F)
2587       fog_start = SettingGetGlobal_f(I->G, cSetting_fog_start);
2588     if(fog_start > 1.0F)
2589       fog_start = 1.0F;
2590     if(fog_start < 0.0F)
2591       fog_start = 0.0F;
2592   }
2593 
2594   /* SETUP */
2595 
2596   if(antialias < 0)
2597     antialias = SettingGetGlobal_i(I->G, cSetting_antialias);
2598 
2599   bkrd = ColorGet(I->G, SettingGet_color(I->G, NULL, NULL, cSetting_bg_rgb));
2600   RayExpandPrimitives(I);
2601   RayTransformFirst(I, 0, identity);
2602 
2603   PRINTFB(I->G, FB_Ray, FB_Details)
2604     " RayRenderPovRay: processed %i graphics primitives.\n", I->NPrimitive ENDFB(I->G);
2605   base = I->Basis + 1;
2606 
2607   {
2608     int ortho = SettingGetGlobal_b(I->G, cSetting_ortho);
2609     if(!identity) {
2610       if(!ortho) {
2611         sprintf(buffer, "camera {direction<0.0,0.0,%8.3f>\n location <0.0 , 0.0 , 0.0>\n right %12.10f*x up y \n }\n", -57.3F * cos(fov * cPI / (180 * 2.4)) / fov,     /* by trial and error */
2612                 I->Range[0] / I->Range[1]);
2613       } else {
2614         sprintf(buffer,
2615                 "camera {orthographic location <0.0 , 0.0 , %12.10f>\nlook_at  <0.0 , 0.0 , -1.0> right %12.10f*x up %12.10f*y}\n",
2616                 front, -I->Range[0], I->Range[1]);
2617       }
2618     } else {
2619       float look[3];
2620       float loc[3] = { 0.0F, 0.0F, 0.0F };
2621       SceneViewType view;
2622 
2623       SceneGetCenter(I->G, look);
2624       SceneGetView(I->G, view);
2625       loc[2] = -view[18];
2626       MatrixInvTransformC44fAs33f3f(view, loc, loc);
2627       add3f(look, loc, loc);
2628 
2629       if(!ortho) {
2630         sprintf(buffer,
2631                 "camera {angle %12.10f sky<%12.10f,%12.10f,%12.10f>\nlocation<%12.10f,%12.10f,%12.10f>\nlook_at<%12.10f,%12.10f,%12.10f> right %12.10f*x up y }\n",
2632                 fov * I->Range[0] / I->Range[1],
2633                 view[1], view[5], view[9],
2634                 loc[0], loc[1], loc[2],
2635                 look[0], look[1], look[2], -I->Range[0] / I->Range[1]);
2636       } else {
2637         sprintf(buffer,
2638                 "camera {orthographic sky<%12.10f,%12.10f,%12.10f>\nlocation<%12.10f,%12.10f,%12.10f>\nlook_at<%12.10f,%12.10f,%12.10f> right %12.10f*x up %12.10f*y}\n",
2639                 view[1], view[5], view[9],
2640                 loc[0], loc[1], loc[2],
2641                 look[0], look[1], look[2], -I->Range[0], I->Range[1]);
2642       }
2643     }
2644     UtilConcatVLA(&headerVLA, &hc, buffer);
2645   }
2646 
2647   {
2648     float ambient =
2649       SettingGetGlobal_f(I->G, cSetting_ambient) + SettingGetGlobal_f(I->G, cSetting_direct);
2650     float reflect = SettingGetGlobal_f(I->G, cSetting_reflect);
2651 
2652     if(ambient > 0.5)
2653       ambient = 0.5;
2654 
2655     reflect = 1.2F - 1.5F * ambient;
2656 
2657     sprintf(buffer,
2658             "#default { finish{phong %8.3f ambient %8.3f diffuse %8.3f phong_size %8.6f}}\n",
2659             SettingGetGlobal_f(I->G, cSetting_spec_reflect), ambient, reflect, spec_power);
2660     UtilConcatVLA(&headerVLA, &hc, buffer);
2661   }
2662 
2663   if(!identity) {
2664     if(angle) {
2665       float temp[16];
2666       identity44f(temp);
2667       MatrixRotateC44f(temp, (float) -PI * angle / 180, 0.0F, 1.0F, 0.0F);
2668       MatrixTransformC44fAs33f3f(temp, light, light);
2669     }
2670   }
2671 
2672   {
2673     float lite[3];
2674     if(!identity) {
2675       lite[0] = -light[0] * 10000.0F;
2676       lite[1] = -light[1] * 10000.0F;
2677       lite[2] = -light[2] * 10000.0F - front;
2678     } else {
2679       /* this is not correct unless the camera is in the default orientation */
2680       float look[3];
2681       SceneViewType view;
2682 
2683       SceneGetCenter(I->G, look);
2684       SceneGetView(I->G, view);
2685 
2686       lite[0] = -light[0] * 10000.0F;
2687       lite[1] = -light[1] * 10000.0F;
2688       lite[2] = -light[2] * 10000.0F;
2689       MatrixInvTransformC44fAs33f3f(view, lite, lite);
2690       add3f(look, lite, lite);
2691     }
2692     sprintf(buffer, "light_source{<%6.4f,%6.4f,%6.4f>  rgb<1.0,1.0,1.0>}\n",
2693             lite[0], lite[1], lite[2]);
2694     UtilConcatVLA(&headerVLA, &hc, buffer);
2695   }
2696 
2697   if(!identity) {
2698     int opaque_back = SettingGetGlobal_i(I->G, cSetting_ray_opaque_background);
2699     if(opaque_back < 0)
2700       opaque_back = SettingGetGlobal_i(I->G, cSetting_opaque_background);
2701 
2702     if(opaque_back) {           /* drop a plane into the background for the background color */
2703       sprintf(buffer,
2704               "plane{z , %6.4f \n pigment{color rgb<%6.4f,%6.4f,%6.4f>}\n finish{phong 0 specular 0 diffuse 0 ambient 1.0}}\n",
2705               -back, bkrd[0], bkrd[1], bkrd[2]);
2706       UtilConcatVLA(&headerVLA, &hc, buffer);
2707     }
2708   }
2709 
2710   for(a = 0; a < I->NPrimitive; a++) {
2711     char cap1 = cCylCapRound;
2712     char cap2 = cCylCapRound;
2713     prim = I->Primitive + a;
2714     vert = base->Vertex + 3 * (prim->vert);
2715     if(prim->type == cPrimTriangle) {
2716       if(smooth_color_triangle)
2717         if(!mesh_obj) {
2718           sprintf(buffer, "mesh {\n");
2719           UtilConcatVLA(&charVLA, &cc, buffer);
2720           mesh_obj = true;
2721         }
2722     } else if(mesh_obj) {
2723       sprintf(buffer, " pigment{color rgb <1,1,1>}}");
2724       UtilConcatVLA(&charVLA, &cc, buffer);
2725       mesh_obj = false;
2726     }
2727     switch (prim->type) {
2728     case cPrimSphere:
2729       sprintf(buffer, "sphere{<%12.10f,%12.10f,%12.10f>, %12.10f\n",
2730               vert[0], vert[1], vert[2], prim->r1);
2731       UtilConcatVLA(&charVLA, &cc, buffer);
2732       sprintf(buffer, "pigment{color rgb<%6.4f,%6.4f,%6.4f>}}\n",
2733               prim->c1[0], prim->c1[1], prim->c1[2]);
2734       UtilConcatVLA(&charVLA, &cc, buffer);
2735       break;
2736     case cPrimCylinder:
2737       cap1 = prim->cap1;
2738       cap2 = prim->cap2;
2739     case cPrimSausage:
2740       d = base->Normal + 3 * base->Vert2Normal[prim->vert];
2741       scale3f(d, prim->l1, vert2);
2742       add3f(vert, vert2, vert2);
2743       sprintf(buffer,
2744               "cylinder{<%12.10f,%12.10f,%12.10f>,\n<%12.10f,%12.10f,%12.10f>,\n %12.10f\n",
2745               vert[0], vert[1], vert[2], vert2[0], vert2[1], vert2[2], prim->r1);
2746       UtilConcatVLA(&charVLA, &cc, buffer);
2747 
2748       if (cap1 != cCylCapFlat && cap2 != cCylCapFlat) {
2749         UtilConcatVLA(&charVLA, &cc, "open\n");
2750       }
2751 
2752       sprintf(buffer, "pigment{color rgb<%6.4f1,%6.4f,%6.4f>}}\n",
2753               (prim->c1[0] + prim->c2[0]) / 2,
2754               (prim->c1[1] + prim->c2[1]) / 2, (prim->c1[2] + prim->c2[2]) / 2);
2755       UtilConcatVLA(&charVLA, &cc, buffer);
2756 
2757       if (cap1 == cCylCapRound) {
2758       sprintf(buffer, "sphere{<%12.10f,%12.10f,%12.10f>, %12.10f\n",
2759               vert[0], vert[1], vert[2], prim->r1);
2760       UtilConcatVLA(&charVLA, &cc, buffer);
2761       sprintf(buffer, "pigment{color rgb<%6.4f1,%6.4f,%6.4f>}}\n",
2762               prim->c1[0], prim->c1[1], prim->c1[2]);
2763       UtilConcatVLA(&charVLA, &cc, buffer);
2764       }
2765 
2766       if (cap2 == cCylCapRound) {
2767       sprintf(buffer, "sphere{<%12.10f,%12.10f,%12.10f>, %12.10f\n",
2768               vert2[0], vert2[1], vert2[2], prim->r1);
2769       UtilConcatVLA(&charVLA, &cc, buffer);
2770       sprintf(buffer, "pigment{color rgb<%6.4f1,%6.4f,%6.4f>}}\n",
2771               prim->c2[0], prim->c2[1], prim->c2[2]);
2772       UtilConcatVLA(&charVLA, &cc, buffer);
2773       }
2774 
2775       break;
2776     case cPrimTriangle:
2777       norm = base->Normal + 3 * base->Vert2Normal[prim->vert] + 3;      /* first normal is the average */
2778 
2779       if(!TriangleDegenerate(vert, norm, vert + 3, norm + 3, vert + 6, norm + 6)) {
2780 
2781         if(smooth_color_triangle) {
2782           sprintf(buffer,
2783                   "smooth_color_triangle{<%12.10f,%12.10f,%12.10f>,\n<%12.10f,%12.10f,%12.10f>,\n<%6.4f1,%6.4f,%6.4f>,\n<%12.10f,%12.10f,%12.10f>,\n<%12.10f,%12.10f,%12.10f>,\n<%6.4f1,%6.4f,%6.4f>,\n<%12.10f,%12.10f,%12.10f>,\n<%12.10f,%12.10f,%12.10f>,\n<%6.4f1,%6.4f,%6.4f> }\n",
2784                   vert[0], vert[1], vert[2], norm[0], norm[1], norm[2], prim->c1[0],
2785                   prim->c1[1], prim->c1[2], vert[3], vert[4], vert[5], norm[3], norm[4],
2786                   norm[5], prim->c2[0], prim->c2[1], prim->c2[2], vert[6], vert[7],
2787                   vert[8], norm[6], norm[7], norm[8], prim->c3[0], prim->c3[1],
2788                   prim->c3[2]
2789             );
2790           UtilConcatVLA(&charVLA, &cc, buffer);
2791         } else {
2792           /* nowadays we use mesh2 to generate smooth_color_triangles */
2793 
2794           UtilConcatVLA(&charVLA, &cc, "mesh2 { ");
2795           sprintf(buffer,
2796                   "vertex_vectors { 3, <%12.10f,%12.10f,%12.10f>,\n<%12.10f,%12.10f,%12.10f>,\n<%12.10f,%12.10f,%12.10f>}\n normal_vectors { 3,\n<%12.10f,%12.10f,%12.10f>,\n<%12.10f,%12.10f,%12.10f>,\n<%12.10f,%12.10f,%12.10f>}\n",
2797                   vert[0], vert[1], vert[2], vert[3], vert[4], vert[5], vert[6], vert[7],
2798                   vert[8], norm[0], norm[1], norm[2], norm[3], norm[4], norm[5], norm[6],
2799                   norm[7], norm[8]
2800             );
2801           UtilConcatVLA(&charVLA, &cc, buffer);
2802 
2803           if(prim->trans > R_SMALL4)
2804             sprintf(transmit, "transmit %4.6f", prim->trans);
2805           else
2806             transmit[0] = 0;
2807 
2808           sprintf(buffer, "texture_list { 3, ");
2809           UtilConcatVLA(&charVLA, &cc, buffer);
2810 
2811           sprintf(buffer, "texture { pigment{color rgb<%6.4f1,%6.4f,%6.4f> %s}}\n",
2812                   prim->c1[0], prim->c1[1], prim->c1[2], transmit);
2813           UtilConcatVLA(&charVLA, &cc, buffer);
2814 
2815           sprintf(buffer, ",texture { pigment{color rgb<%6.4f1,%6.4f,%6.4f> %s}}\n",
2816                   prim->c2[0], prim->c2[1], prim->c2[2], transmit);
2817           UtilConcatVLA(&charVLA, &cc, buffer);
2818 
2819           sprintf(buffer, ",texture { pigment{color rgb<%6.4f1,%6.4f,%6.4f> %s}} }\n",
2820                   prim->c3[0], prim->c3[1], prim->c3[2], transmit);
2821           UtilConcatVLA(&charVLA, &cc, buffer);
2822 
2823           sprintf(buffer, "face_indices { 1, <0,1,2>, 0, 1, 2 } }\n");
2824           UtilConcatVLA(&charVLA, &cc, buffer);
2825         }
2826       }
2827       break;
2828     }
2829   }
2830 
2831   if(mesh_obj) {
2832     sprintf(buffer, " pigment{color rgb <1,1,1>}}");
2833     UtilConcatVLA(&charVLA, &cc, buffer);
2834     mesh_obj = false;
2835   }
2836   *charVLA_ptr = charVLA;
2837   *headerVLA_ptr = headerVLA;
2838 }
2839 
2840 
2841 /*========================================================================*/
RayProjectTriangle(CRay * I,RayInfo * r,float * light,float * v0,float * n0,float scale)2842 void RayProjectTriangle(CRay * I, RayInfo * r, float *light, float *v0, float *n0,
2843                         float scale)
2844 {
2845   float w2;
2846   float d1[3], d2[3], d3[3];
2847   float p1[3], p2[3], p3[3];
2848   int c = 0;
2849   const float _0 = 0.0F;
2850   float *impact = r->impact;
2851 
2852   if(dot_product3f(light, n0 - 3) >= _0)
2853     c++;
2854   else if(dot_product3f(light, n0) >= _0)
2855     c++;
2856   else if(dot_product3f(light, n0 + 3) >= _0)
2857     c++;
2858   else if(dot_product3f(light, n0 + 6) >= _0)
2859     c++;
2860 
2861   if(c) {
2862 
2863     w2 = 1.0F - (r->tri1 + r->tri2);
2864 
2865     subtract3f(v0, impact, d1);
2866     subtract3f(v0 + 3, impact, d2);
2867     subtract3f(v0 + 6, impact, d3);
2868     project3f(d1, n0, p1);
2869     project3f(d2, n0 + 3, p2);
2870     project3f(d3, n0 + 6, p3);
2871     scale3f(p1, w2, d1);
2872     scale3f(p2, r->tri1, d2);
2873     scale3f(p3, r->tri2, d3);
2874     add3f(d1, d2, d2);
2875     add3f(d2, d3, d3);
2876     scale3f(d3, scale, d3);
2877     if(dot_product3f(r->surfnormal, d3) >= _0)
2878       add3f(d3, impact, impact);
2879   }
2880 }
2881 
2882 #ifndef _PYMOL_NOPY
RayHashSpawn(CRayHashThreadInfo * Thread,int n_thread,int n_total)2883 static void RayHashSpawn(CRayHashThreadInfo * Thread, int n_thread, int n_total)
2884 {
2885   int blocked;
2886   PyObject *info_list;
2887   int a, c, n = 0;
2888   CRay *I = Thread->ray;
2889   PyMOLGlobals *G = I->G;
2890 
2891   blocked = PAutoBlock(G);
2892 
2893   PRINTFB(I->G, FB_Ray, FB_Blather)
2894     " Ray: filling voxels with %d threads...\n", n_thread ENDFB(I->G);
2895   while(n < n_total) {
2896     c = n;
2897     info_list = PyList_New(n_thread);
2898     for(a = 0; a < n_thread; a++) {
2899       if((c + a) < n_total) {
2900         PyList_SetItem(info_list, a, PyCObject_FromVoidPtr(Thread + c + a, NULL));
2901       } else {
2902         PyList_SetItem(info_list, a, PConvAutoNone(NULL));
2903       }
2904       n++;
2905     }
2906     PXDecRef(PYOBJECT_CALLMETHOD
2907              (G->P_inst->cmd, "_ray_hash_spawn", "OO", info_list, G->P_inst->cmd));
2908     Py_DECREF(info_list);
2909   }
2910   PAutoUnblock(G, blocked);
2911 }
2912 #endif
2913 
2914 #ifndef _PYMOL_NOPY
RayAntiSpawn(CRayAntiThreadInfo * Thread,int n_thread)2915 static void RayAntiSpawn(CRayAntiThreadInfo * Thread, int n_thread)
2916 {
2917   int blocked;
2918   PyObject *info_list;
2919   int a;
2920   CRay *I = Thread->ray;
2921   PyMOLGlobals *G = I->G;
2922 
2923   blocked = PAutoBlock(G);
2924 
2925   PRINTFB(I->G, FB_Ray, FB_Blather)
2926     " Ray: antialiasing with %d threads...\n", n_thread ENDFB(I->G);
2927   info_list = PyList_New(n_thread);
2928   for(a = 0; a < n_thread; a++) {
2929     PyList_SetItem(info_list, a, PyCObject_FromVoidPtr(Thread + a, NULL));
2930   }
2931   PXDecRef(PYOBJECT_CALLMETHOD
2932            (G->P_inst->cmd, "_ray_anti_spawn", "OO", info_list, G->P_inst->cmd));
2933   Py_DECREF(info_list);
2934   PAutoUnblock(G, blocked);
2935 }
2936 #endif
2937 
RayHashThread(CRayHashThreadInfo * T)2938 int RayHashThread(CRayHashThreadInfo * T)
2939 {
2940   BasisMakeMap(T->basis, T->vert2prim, T->prim, T->n_prim, T->clipBox, T->phase,
2941                cCache_ray_map, T->perspective, T->front, T->size_hint);
2942 
2943   /* utilize a little extra wasted CPU time in thread 0 which computes the smaller map... */
2944   if(!T->phase) {
2945     if (T->ray->bkgrd_data){
2946       fill_background_image(T->ray, T->image,  T->width, T->height, T->width * (unsigned int) T->height);
2947     } else if (T->bkrd_is_gradient){
2948       fill_gradient(T->ray, T->opaque_back, T->image, T->bkrd_top, T->bkrd_bottom, T->width, T->height, T->width * (unsigned int) T->height);
2949     } else {
2950       fill(T->image, T->background, T->bytes);
2951     }
2952     RayComputeBox(T->ray);
2953   }
2954   return 1;
2955 }
2956 
2957 #ifndef _PYMOL_NOPY
RayTraceSpawn(CRayThreadInfo * Thread,int n_thread)2958 static void RayTraceSpawn(CRayThreadInfo * Thread, int n_thread)
2959 {
2960   int blocked;
2961   PyObject *info_list;
2962   int a;
2963   CRay *I = Thread->ray;
2964   PyMOLGlobals *G = I->G;
2965 
2966   blocked = PAutoBlock(G);
2967 
2968   PRINTFB(I->G, FB_Ray, FB_Blather)
2969     " Ray: rendering with %d threads...\n", n_thread ENDFB(I->G);
2970   info_list = PyList_New(n_thread);
2971   for(a = 0; a < n_thread; a++) {
2972     PyList_SetItem(info_list, a, PyCObject_FromVoidPtr(Thread + a, NULL));
2973   }
2974   PXDecRef(PYOBJECT_CALLMETHOD
2975            (G->P_inst->cmd, "_ray_spawn", "OO", info_list, G->P_inst->cmd));
2976   Py_DECREF(info_list);
2977   PAutoUnblock(G, blocked);
2978 
2979 }
2980 #endif
2981 
find_edge(unsigned int * ptr,float * depth,unsigned int width,int threshold,int back)2982 static int find_edge(unsigned int *ptr, float *depth, unsigned int width,
2983                      int threshold, int back)
2984 {                               /* can only be called for a pixel NOT on the edge */
2985   {                             /* color testing */
2986     int compare0, compare1, compare2, compare3, compare4, compare5, compare6,
2987       compare7, compare8;
2988     {
2989       int back_test, back_two = false;
2990       compare0 = (signed int) *(ptr);
2991       compare1 = (signed int) *(ptr - 1);
2992       back_test = (compare0 == back);
2993       compare2 = (signed int) *(ptr + 1);
2994       back_two = back_two || ((compare1 == back) == back_test);
2995       compare3 = (signed int) *(ptr - width);
2996       back_two = back_two || ((compare2 == back) == back_test);
2997       compare4 = (signed int) *(ptr + width);
2998       back_two = back_two || ((compare3 == back) == back_test);
2999       compare5 = (signed int) *(ptr - width - 1);
3000       back_two = back_two || ((compare4 == back) == back_test);
3001       compare6 = (signed int) *(ptr + width - 1);
3002       back_two = back_two || ((compare5 == back) == back_test);
3003       compare7 = (signed int) *(ptr - width + 1);
3004       back_two = back_two || ((compare6 == back) == back_test);
3005       compare8 = (signed int) *(ptr + width + 1);
3006       back_two = back_two || ((compare7 == back) == back_test);
3007       if(back_two)
3008 	threshold = (threshold >> 1);   // halve threshold for pixels that hit background
3009     }
3010 
3011     {
3012       int current;
3013       unsigned int shift = 0;
3014       int sum1 = 0, sum2 = 3, sum3 = 0, sum4 = 0, sum5 = 0, sum6 = 0, sum7 = 0, sum8 = 0;
3015       int a;
3016       for(a = 0; a < 4; a++) {
3017 	current = ((compare0 >> shift) & 0xFF);
3018 	sum1 += abs(current - ((compare1 >> shift) & 0xFF));
3019 	sum2 += abs(current - ((compare2 >> shift) & 0xFF));
3020 	if(sum1 >= threshold)
3021 	  return 1;
3022 	sum3 += abs(current - ((compare3 >> shift) & 0xFF));
3023 	if(sum2 >= threshold)
3024 	  return 1;
3025 	sum4 += abs(current - ((compare4 >> shift) & 0xFF));
3026 	if(sum3 >= threshold)
3027 	  return 1;
3028 	sum5 += abs(current - ((compare5 >> shift) & 0xFF));
3029 	if(sum4 >= threshold)
3030 	  return 1;
3031 	sum6 += abs(current - ((compare6 >> shift) & 0xFF));
3032 	if(sum5 >= threshold)
3033 	  return 1;
3034 	sum7 += abs(current - ((compare7 >> shift) & 0xFF));
3035 	if(sum6 >= threshold)
3036 	  return 1;
3037 	sum8 += abs(current - ((compare8 >> shift) & 0xFF));
3038 	if(sum7 >= threshold)
3039 	  return 1;
3040 	if(sum8 >= threshold)
3041 	  return 1;
3042 	shift += 8;
3043       }
3044     }
3045   }
3046 
3047   if(depth) {                   /* depth testing */
3048     float compare0, compare1, compare2, compare3, compare4, compare5, compare6,
3049       compare7, compare8;
3050     float dcutoff = threshold / 128.0F;
3051 
3052     compare1 = *(depth - 1);
3053     compare0 = *(depth);
3054     compare2 = *(depth + 1);
3055     if(fabs(compare0 - compare1) > dcutoff)
3056       return 1;
3057     compare5 = *(depth - width - 1);
3058     if(fabs(compare0 - compare2) > dcutoff)
3059       return 1;
3060     compare3 = *(depth - width);
3061     if(fabs(compare0 - compare5) > dcutoff)
3062       return 1;
3063     compare7 = *(depth - width + 1);
3064     if(fabs(compare0 - compare3) > dcutoff)
3065       return 1;
3066     compare6 = *(depth + width - 1);
3067     if(fabs(compare0 - compare7) > dcutoff)
3068       return 1;
3069     compare4 = *(depth + width);
3070     if(fabs(compare0 - compare6) > dcutoff)
3071       return 1;
3072     compare8 = *(depth + width + 1);
3073     if(fabs(compare0 - compare4) > dcutoff)
3074       return 1;
3075     if(fabs(compare0 - compare8) > dcutoff)
3076       return 1;
3077     /*    if(fabs(compare0-compare1)>0.001F)
3078        printf("%8.3f \n",compare0-compare1);
3079        if(fabs(compare0-compare2)>0.001F)
3080        printf("%8.3f \n",compare0-compare2);
3081        if(fabs(compare0-compare3)>0.001F)
3082        printf("%8.3f \n",compare0-compare3);
3083        if(fabs(compare0-compare4)>0.001F)
3084        printf("%8.3f \n",compare0-compare4);
3085        if(fabs(compare0-compare5)>0.001F)
3086        printf("%8.3f \n",compare0-compare5);
3087        if(fabs(compare0-compare6)>0.001F)
3088        printf("%8.3f \n",compare0-compare6);
3089        if(fabs(compare0-compare7)>0.001F)
3090        printf("%8.3f \n",compare0-compare7);
3091        if(fabs(compare0-compare8)>0.001F)
3092        printf("%8.3f \n",compare0-compare8); */
3093 
3094   }
3095   return 0;
3096 }
3097 
RayPrimGetColorRamped(PyMOLGlobals * G,float * matrix,RayInfo * r,float * fc)3098 static void RayPrimGetColorRamped(PyMOLGlobals * G, float *matrix, RayInfo * r, float *fc)
3099 {
3100   float fc1[3], fc2[3], fc3[3];
3101   float *c1, *c2, *c3, w2;
3102   float back_pact[3];
3103   const float _0 = 0.0F, _1 = 1.0F, _01 = 0.1F;
3104   CPrimitive *lprim = r->prim;
3105   inverse_transformC44f3f(matrix, r->impact, back_pact);
3106 
3107   switch (lprim->type) {
3108   case cPrimTriangle:
3109     w2 = 1.0F - (r->tri1 + r->tri2);
3110     c1 = lprim->c1;
3111     if(c1[0] <= _0) {
3112       ColorGetRamped(G, (int) (c1[0] - _01), back_pact, fc1, -1);
3113       c1 = fc1;
3114     }
3115     c2 = lprim->c2;
3116     if(c2[0] <= _0) {
3117       ColorGetRamped(G, (int) (c2[0] - _01), back_pact, fc2, -1);
3118       c2 = fc2;
3119     }
3120     c3 = lprim->c3;
3121     if(c3[0] <= _0) {
3122       ColorGetRamped(G, (int) (c3[0] - _01), back_pact, fc3, -1);
3123       c3 = fc3;
3124     }
3125     fc[0] = (c2[0] * r->tri1) + (c3[0] * r->tri2) + (c1[0] * w2);
3126     fc[1] = (c2[1] * r->tri1) + (c3[1] * r->tri2) + (c1[1] * w2);
3127     fc[2] = (c2[2] * r->tri1) + (c3[2] * r->tri2) + (c1[2] * w2);
3128     break;
3129   case cPrimSphere:
3130     c1 = lprim->c1;
3131     if(c1[0] <= _0) {
3132       ColorGetRamped(G, (int) (c1[0] - _01), back_pact, fc1, -1);
3133       c1 = fc1;
3134     }
3135     copy3f(c1, fc);
3136     break;
3137   case cPrimEllipsoid:
3138     /* TO DO */
3139     break;
3140   case cPrimCone:
3141   case cPrimCylinder:
3142   case cPrimSausage:
3143     w2 = r->tri1;
3144     c1 = lprim->c1;
3145     if(c1[0] <= _0) {
3146       ColorGetRamped(G, (int) (c1[0] - _01), back_pact, fc1, -1);
3147       c1 = fc1;
3148     }
3149     c2 = lprim->c2;
3150     if(c2[0] <= _0) {
3151       ColorGetRamped(G, (int) (c2[0] - _01), back_pact, fc2, -1);
3152       c2 = fc2;
3153     }
3154     /* TODO : here is where we would set the correct color if we implemented
3155        non-linear (smoothstep) half bonds. We probably need to add another
3156        parameter/variable to the primitive to tell this function what interpolation
3157        to do */
3158     fc[0] = (c1[0] * (_1 - w2)) + (c2[0] * w2);
3159     fc[1] = (c1[1] * (_1 - w2)) + (c2[1] * w2);
3160     fc[2] = (c1[2] * (_1 - w2)) + (c2[2] * w2);
3161     break;
3162   default:
3163     fc[0] = _1;
3164     fc[1] = _1;
3165     fc[2] = _1;
3166     break;
3167   }
3168 }
3169 
RayTraceThread(CRayThreadInfo * T)3170 int RayTraceThread(CRayThreadInfo * T)
3171 {
3172   CRay *I = T->ray;
3173   int x, y, yy;
3174   float excess = 0.0F;
3175   float dotgle;
3176   float bright, direct_cmp, reflect_cmp, fc[4];
3177   float ambient, direct, lreflect, ft, ffact = 0.0F, ffact1m;
3178   unsigned int cc0, cc1, cc2, cc3;
3179   int i;
3180   RayInfo r1, r2;
3181   int fogFlag = false;
3182   int fogRangeFlag = false;
3183   int opaque_back = 0, orig_opaque_back = 0;
3184   int n_hit = 0;
3185   int two_sided_lighting;
3186   float fog;
3187   float inter[3] = { 0.0F, 0.0F, 0.0F };
3188   float fog_start = 0.0F;
3189   /*    float gamma,inp,sig=1.0F; */
3190   float persist, persist_inv;
3191   float new_front;
3192   int pass;
3193   unsigned int last_pixel = 0, *pixel;
3194   int exclude1, exclude2;
3195   float lit;
3196   int backface_cull;
3197   float project_triangle;
3198   float excl_trans;
3199   int shadows;
3200   int trans_shadows;
3201   int trans_mode;
3202   float first_excess;
3203   int pixel_flag;
3204   float ray_trans_spec, ray_lab_spec;
3205   float shadow_fudge;
3206   int label_shadow_mode;
3207   int interior_color;
3208   int interior_flag;
3209   int interior_shadows;
3210   int interior_wobble;
3211   int interior_mode;
3212   float interior_reflect;
3213   int wobble_save;
3214   float settingPower, settingReflectPower, settingSpecPower, settingSpecReflect,
3215     settingSpecDirect;
3216   float settingSpecDirectPower;
3217   float invHgt, invFrontMinusBack, inv1minusFogStart, invWdth, invHgtRange;
3218   float invWdthRange, vol0;
3219   float vol2;
3220   CBasis *bp1, *bp2;
3221   int render_height;
3222   int offset = 0;
3223   BasisCallRec BasisCall[MAX_BASIS];
3224   float border_offset;
3225   int edge_sampling = false;
3226   unsigned int edge_avg[4] = { 0, 0, 0, 0 };
3227   unsigned int edge_alpha_avg[4] = { 0, 0, 0, 0 };
3228   int edge_cnt = 0;
3229   float edge_base[2] = { 0.0F, 0.0F };
3230   float interior_normal[3] = {0.0F, 0.0F, 0.0F};
3231   float edge_width = 0.35356F;
3232   float edge_height = 0.35356F;
3233   float trans_spec_cut, trans_spec_scale, trans_oblique, oblique_power;
3234   float direct_shade;
3235   float red_blend = 0.0F;
3236   float blue_blend = 0.0F;
3237   float green_blend = 0.0F;
3238   float trans_cont;
3239   float pixel_base[3];
3240   float inv_trans_cont = 1.0F;
3241   float trans_cutoff, persist_cutoff;
3242   int trans_cont_flag = false;
3243   int blend_colors;
3244   int max_pass;
3245   float BasisFudge0, BasisFudge1;
3246   int perspective = T->perspective;
3247   float eye[3] = { 0.0F, 0.0F, 0.0F };
3248   float start[3] = { 0.0F, 0.0F, 0.0F };
3249   float nudge[3] = { 0.0F, 0.0F, 0.0F };
3250   float back_pact[3];
3251   float *depth = T->depth;
3252   float ray_scatter = SettingGetGlobal_f(I->G, cSetting_ray_scatter);
3253   const float shadow_decay = SettingGetGlobal_f(I->G, cSetting_ray_shadow_decay_factor);
3254   const float shadow_range = SettingGetGlobal_f(I->G, cSetting_ray_shadow_decay_range);
3255   const int clip_shadows = SettingGetGlobal_b(I->G, cSetting_ray_clip_shadows);
3256   const int spec_local = SettingGetGlobal_i(I->G, cSetting_ray_spec_local);
3257   float legacy = SettingGetGlobal_f(I->G, cSetting_ray_legacy_lighting);
3258   int spec_count = SettingGetGlobal_i(I->G, cSetting_spec_count);
3259   const float _0 = 0.0F;
3260   const float _1 = 1.0F;
3261   const float _p5 = 0.5F;
3262   const float _2 = 2.0F;
3263   const float _255 = 255.0F;
3264   const float _p499 = 0.499F;
3265   const float _persistLimit = 0.0001F;
3266   float legacy_1m = _1 - legacy;
3267   int n_basis = I->NBasis;
3268   int bg_image_mode = SettingGetGlobal_i(I->G, cSetting_bg_image_mode);
3269   int bg_image_linear = SettingGetGlobal_b(I->G, cSetting_bg_image_linear);
3270   auto bg_image_tilesize = SettingGet<const float*>(I->G, cSetting_bg_image_tilesize);
3271   float hpixelx = floor(T->width/2.f)  - floor(T->bgWidth / 2.f),
3272     hpixely = floor(T->height/2.f) - floor(T->bgHeight / 2.f);
3273   float hl;
3274   float wr = T->bgWidth/(float)T->width, hr = T->bgHeight/(float)T->height;
3275   float bg_rgb[3];
3276   const float *tmpf;
3277   int chromadepth;
3278 
3279   tmpf = ColorGet(I->G, SettingGet_color(I->G, NULL, NULL, cSetting_bg_rgb));
3280   mult3f(tmpf, 255.f, bg_rgb);
3281 
3282   /*   MemoryDebugDump();
3283      printf("%d\n",sizeof(CPrimitive));
3284    */
3285 
3286   {
3287     float fudge = SettingGetGlobal_f(I->G, cSetting_ray_triangle_fudge);
3288 
3289     BasisFudge0 = 0.0F - fudge;
3290     BasisFudge1 = 1.0F + fudge;
3291   }
3292   if(spec_count < 0) {
3293     spec_count = SettingGetGlobal_i(I->G, cSetting_light_count);
3294   }
3295   /* SETUP */
3296 
3297   /*  if(T->n_thread>1)
3298      printf(" Ray: Thread %d: Spawned.\n",T->phase+1);
3299    */
3300 
3301   interior_shadows = SettingGetGlobal_i(I->G, cSetting_ray_interior_shadows);
3302   interior_wobble = SettingGetGlobal_i(I->G, cSetting_ray_interior_texture);
3303   interior_color = SettingGetGlobal_i(I->G, cSetting_ray_interior_color);
3304   interior_reflect = 1.0F - SettingGetGlobal_f(I->G, cSetting_ray_interior_reflect);
3305   interior_mode = SettingGetGlobal_i(I->G, cSetting_ray_interior_mode);
3306   label_shadow_mode = SettingGetGlobal_i(I->G, cSetting_label_shadow_mode);
3307   project_triangle = SettingGetGlobal_f(I->G, cSetting_ray_improve_shadows);
3308   shadows = SettingGetGlobal_i(I->G, cSetting_ray_shadows);
3309   trans_shadows = SettingGetGlobal_i(I->G, cSetting_ray_transparency_shadows);
3310 
3311   backface_cull = SettingGetGlobal_i(I->G, cSetting_backface_cull);
3312   opaque_back = SettingGetGlobal_i(I->G, cSetting_ray_opaque_background);
3313   if(opaque_back < 0)
3314     opaque_back = SettingGetGlobal_i(I->G, cSetting_opaque_background);
3315   orig_opaque_back = opaque_back;
3316 
3317   if (T->bkrd_data){
3318     opaque_back = 1;
3319   }
3320 
3321   two_sided_lighting = SettingGetGlobal_i(I->G, cSetting_two_sided_lighting);
3322   if(two_sided_lighting<0) {
3323     if(SettingGetGlobal_i(I->G, cSetting_surface_cavity_mode))
3324       two_sided_lighting = true;
3325     else
3326       two_sided_lighting = false;
3327   }
3328 
3329   ray_trans_spec = SettingGetGlobal_f(I->G, cSetting_ray_transparency_specular);
3330   ray_lab_spec = SettingGetGlobal_f(I->G, cSetting_ray_label_specular);
3331   trans_cont = SettingGetGlobal_f(I->G, cSetting_ray_transparency_contrast);
3332   trans_mode = SettingGetGlobal_i(I->G, cSetting_transparency_mode);
3333   trans_oblique = SettingGetGlobal_f(I->G, cSetting_ray_transparency_oblique);
3334   oblique_power = SettingGetGlobal_f(I->G, cSetting_ray_transparency_oblique_power);
3335   trans_cutoff = SettingGetGlobal_f(I->G, cSetting_ray_trace_trans_cutoff);
3336   persist_cutoff = SettingGetGlobal_f(I->G, cSetting_ray_trace_persist_cutoff);
3337   chromadepth = SettingGetGlobal_i(I->G, cSetting_chromadepth);
3338 
3339   if(trans_mode == 1)
3340     two_sided_lighting = true;
3341   if(trans_cont > 1.0F) {
3342     trans_cont_flag = true;
3343     inv_trans_cont = 1.0F / trans_cont;
3344   }
3345   ambient = T->ambient;
3346   /* divide up the reflected light component over all lights */
3347   {
3348     float reflect_scale = SceneGetReflectScaleValue(I->G, 10);
3349     lreflect = reflect_scale * (SettingGetGlobal_f(I->G, cSetting_reflect) - ray_scatter);
3350     if(lreflect < _0)
3351       lreflect = _0;
3352     ray_scatter = ray_scatter * reflect_scale;
3353   }
3354   direct = SettingGetGlobal_f(I->G, cSetting_direct);
3355 
3356   /* apply legacy adjustments */
3357 
3358   ambient *= (1.0F - legacy) + (legacy * (0.22F / 0.12F));
3359   lreflect *= (1.0F - legacy) + (legacy * (0.72F / 0.45F));
3360   direct *= (1.0F - legacy) + (legacy * (0.24F / 0.45F));
3361 
3362   direct_shade = SettingGetGlobal_f(I->G, cSetting_ray_direct_shade);
3363   trans_spec_cut = SettingGetGlobal_f(I->G, cSetting_ray_transparency_spec_cut);
3364   blend_colors = SettingGetGlobal_i(I->G, cSetting_ray_blend_colors);
3365   max_pass = SettingGetGlobal_i(I->G, cSetting_ray_max_passes);
3366   if(blend_colors) {
3367     red_blend = SettingGetGlobal_f(I->G, cSetting_ray_blend_red);
3368     green_blend = SettingGetGlobal_f(I->G, cSetting_ray_blend_green);
3369     blue_blend = SettingGetGlobal_f(I->G, cSetting_ray_blend_blue);
3370   }
3371 
3372   if(trans_spec_cut < _1)
3373     trans_spec_scale = _1 / (_1 - trans_spec_cut);
3374   else
3375     trans_spec_scale = _0;
3376 
3377   /* COOP */
3378   settingPower = SettingGetGlobal_f(I->G, cSetting_power);
3379   settingReflectPower = SettingGetGlobal_f(I->G, cSetting_reflect_power);
3380 
3381   SceneGetAdjustedLightValues(I->G,
3382       &settingSpecReflect,
3383       &settingSpecPower,
3384       &settingSpecDirect,
3385       &settingSpecDirectPower, 10);
3386 
3387   if((interior_color != -1) || (two_sided_lighting) || (trans_mode == 1)
3388      || I->CheckInterior)
3389     backface_cull = 0;
3390 
3391   shadow_fudge = SettingGetGlobal_f(I->G, cSetting_ray_shadow_fudge);
3392 
3393   inv1minusFogStart = _1;
3394 
3395   fog = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog);
3396   if(fog < 0.0F) {
3397     if(SettingGetGlobal_b(I->G, cSetting_depth_cue)) {
3398       fog = SettingGetGlobal_f(I->G, cSetting_fog);
3399     } else
3400       fog = _0;
3401   }
3402 
3403   if(fog != _0) {
3404     fogFlag = true;
3405     fog_start = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog_start);
3406     if(fog_start < 0.0F)
3407       fog_start = SettingGetGlobal_f(I->G, cSetting_fog_start);
3408     if(fog_start > 1.0F)
3409       fog_start = 1.0F;
3410     if(fog_start < 0.0F)
3411       fog_start = 0.0F;
3412     if(fog_start > R_SMALL4) {
3413       fogRangeFlag = true;
3414       if(fabs(fog_start - 1.0F) < R_SMALL4)     /* prevent div/0 */
3415         fogFlag = false;
3416     }
3417     inv1minusFogStart = _1 / (_1 - fog_start);
3418   }
3419 
3420   /* ray-trace */
3421 
3422   if(T->border) {
3423     invHgt = _1 / (float) (T->height - (3.0F + T->border));
3424     invWdth = _1 / (float) (T->width - (3.0F + T->border));
3425   } else {
3426 
3427     invHgt = _1 / (float) (T->height);
3428     invWdth = _1 / (float) (T->width);
3429   }
3430 
3431   if(perspective) {
3432     float height_range, width_range;
3433 
3434     /* subpixel-offsets for antialiasing naturally correspond to
3435        effective pixel sizes at the front of the visible slab... */
3436 
3437     height_range = (T->front) * 2 * ((float) tan((T->fov / 2.0F) * PI / 180.0F));
3438     width_range = height_range * (I->Range[0] / I->Range[1]);
3439     invWdthRange = invWdth * width_range;
3440     invHgtRange = invHgt * height_range;
3441     vol0 = eye[0] - width_range / 2.0F;
3442     vol2 = eye[1] - height_range / 2.0F;
3443   } else {
3444     invWdthRange = invWdth * I->Range[0];
3445     invHgtRange = invHgt * I->Range[1];
3446     vol0 = I->Volume[0];
3447     vol2 = I->Volume[2];
3448   }
3449   invFrontMinusBack = _1 / (T->front - T->back);
3450 
3451   edge_width *= invWdthRange;
3452   edge_height *= invHgtRange;
3453 
3454   bp1 = I->Basis + 1;
3455   if(I->NBasis > 2)
3456     bp2 = I->Basis + 2;
3457   else
3458     bp2 = NULL;
3459 
3460   render_height = T->y_stop - T->y_start;
3461 
3462   if(render_height) {
3463     offset = (T->phase * render_height / T->n_thread);
3464     offset = offset - (offset % T->n_thread) + T->phase;
3465   }
3466   if((interior_color != -1) || I->CheckInterior) {
3467 
3468     if(interior_color != -1)
3469       ColorGetEncoded(I->G, interior_color, inter);
3470     if(bp2) {
3471       interior_normal[0] = interior_reflect * bp2->LightNormal[0];
3472       interior_normal[1] = interior_reflect * bp2->LightNormal[1];
3473       interior_normal[2] = 1.0F + interior_reflect * bp2->LightNormal[2];
3474     } else {
3475       interior_normal[0] = 0.0;
3476       interior_normal[1] = 0.0;
3477       interior_normal[2] = 1.0F;
3478     }
3479     normalize3f(interior_normal);
3480   }
3481 
3482   r1.base[2] = _0;
3483 
3484   BasisCall[0].Basis = I->Basis + 1;
3485   BasisCall[0].rr = &r1;
3486   BasisCall[0].vert2prim = I->Vert2Prim;
3487   BasisCall[0].prim = I->Primitive;
3488   BasisCall[0].shadow = false;
3489   BasisCall[0].back = T->back;
3490   BasisCall[0].trans_shadows = trans_shadows;
3491   BasisCall[0].nearest_shadow = (shadow_decay != _0);
3492   BasisCall[0].check_interior = ((interior_color != -1) || I->CheckInterior);
3493   BasisCall[0].fudge0 = BasisFudge0;
3494   BasisCall[0].fudge1 = BasisFudge1;
3495 
3496   MapCacheInit(&BasisCall[0].cache, I->Basis[1].Map, T->phase, cCache_map_scene_cache);
3497 
3498   if(shadows && (n_basis > 2)) {
3499     int bc;
3500     for(bc = 2; bc < n_basis; bc++) {
3501       BasisCall[bc].Basis = I->Basis + bc;
3502       BasisCall[bc].rr = &r2;
3503       BasisCall[bc].vert2prim = I->Vert2Prim;
3504       BasisCall[bc].prim = I->Primitive;
3505       BasisCall[bc].shadow = true;
3506       BasisCall[bc].front = _0;
3507       BasisCall[bc].back = _0;
3508       BasisCall[bc].excl_trans = _0;
3509       BasisCall[bc].trans_shadows = trans_shadows;
3510       BasisCall[bc].nearest_shadow = (shadow_decay != _0) || (clip_shadows);
3511       BasisCall[bc].check_interior = false;
3512       BasisCall[bc].fudge0 = BasisFudge0;
3513       BasisCall[bc].fudge1 = BasisFudge1;
3514       BasisCall[bc].label_shadow_mode = label_shadow_mode;
3515       MapCacheInit(&BasisCall[bc].cache, I->Basis[bc].Map, T->phase,
3516                    cCache_map_shadow_cache);
3517     }
3518   }
3519 
3520   if(T->border) {
3521     border_offset = -1.50F + T->border / 2.0F;
3522   } else {
3523     border_offset = 0.0F;
3524   }
3525 
3526   unsigned int back_mask = 0x00000000;
3527   if (T->bkrd_is_gradient){
3528     if(opaque_back) {
3529       if(I->BigEndian)
3530 	back_mask = 0x000000FF;
3531       else
3532 	back_mask = 0xFF000000;
3533     }
3534   }
3535   for(yy = T->y_start; (yy < T->y_stop); yy++) {
3536     float perc, bkrd[4] = {0.f, 0.f, 0.f, 1.f};
3537     unsigned int bkrd_value = 0;
3538     short isOutsideInY = 0;
3539 
3540     if(I->G->Interrupt)
3541       break;
3542 
3543     y = T->y_start + ((yy - T->y_start) + offset) % (render_height);    /* make sure threads write to different pages */
3544     if (T->bkrd_data){
3545       switch (bg_image_mode){
3546       case 1: // isCentered
3547 	{
3548 	  float tmpy = floor(y - hpixely);
3549 	  isOutsideInY = (tmpy < 0.f || tmpy > (float)T->bgHeight);
3550 	  hl = fmodpos(tmpy, (float)T->bgHeight);
3551 	}
3552 	break;
3553       case 2: // isTiled
3554 	hl = (float)T->bgHeight * (fmodpos((float)y, bg_image_tilesize[1])/bg_image_tilesize[1]);
3555 	break;
3556       case 3: // isCenteredRepeated
3557 	hl = fmodpos(floor(y - hpixely), (float)T->bgHeight);
3558 	break;
3559       default:
3560 	hl = y * hr;
3561 	break;
3562       }
3563     } else if (T->bkrd_is_gradient){
3564       /* for RayTraceThread, y is from bottom to top */
3565       perc = y/(float)T->height;
3566       bkrd[0] = T->bkrd_bottom[0] + perc * (T->bkrd_top[0] - T->bkrd_bottom[0]);
3567       bkrd[1] = T->bkrd_bottom[1] + perc * (T->bkrd_top[1] - T->bkrd_bottom[1]);
3568       bkrd[2] = T->bkrd_bottom[2] + perc * (T->bkrd_top[2] - T->bkrd_bottom[2]);
3569       bkrd[3] = 1.f;
3570       if(T->ray->BigEndian){
3571 	bkrd_value = back_mask |
3572 	  ((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))) << 24) |
3573 	  ((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 16) |
3574 	  ((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 8);
3575       } else {
3576 	bkrd_value = back_mask |
3577 	  ((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 16) |
3578 	  ((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 8) |
3579 	  ((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))));
3580       }
3581     } else {
3582       bkrd_value = T->background;
3583       bkrd[0] = T->bkrd_top[0];
3584       bkrd[1] = T->bkrd_top[1];
3585       bkrd[2] = T->bkrd_top[2];
3586       if (orig_opaque_back){
3587 	bkrd[3] = 1.f;
3588       } else {
3589 	bkrd[3] = 0.f;
3590       }
3591     }
3592     if((!T->phase) && !(yy & 0xF)) {    /* don't slow down rendering too much */
3593       if(T->edging_cutoff) {
3594         if(T->edging) {
3595           OrthoBusyFast(I->G, (int) (2.5F * T->height / 3 + 0.5F * y), 4 * T->height / 3);
3596         } else {
3597           OrthoBusyFast(I->G, (int) (T->height / 3 + 0.5F * y), 4 * T->height / 3);
3598         }
3599       } else {
3600         OrthoBusyFast(I->G, T->height / 3 + y, 4 * T->height / 3);
3601       }
3602     }
3603     pixel = T->image + (T->width * y) + T->x_start;
3604 
3605     if((y % T->n_thread) == T->phase) { /* this is my scan line */
3606       pixel_base[1] = ((y + 0.5F + border_offset) * invHgtRange) + vol2;
3607 
3608       for(x = T->x_start; (x < T->x_stop); x++) {
3609 	if (T->bkrd_data){
3610 	  // Need to compute background for every pixel if image-based
3611 	  unsigned char bkrd_uc[4];
3612 	  compute_background_for_pixel(bkrd_uc, isOutsideInY,
3613               bg_image_mode, bg_image_tilesize, bg_rgb, bg_image_linear,
3614               (unsigned char*) T->bkrd_data, T->bgWidth, T->bgHeight,
3615               x, wr, hl, hpixelx, orig_opaque_back );
3616 	  bkrd[0] = bkrd_uc[0] / 255.f;
3617 	  bkrd[1] = bkrd_uc[1] / 255.f;
3618 	  bkrd[2] = bkrd_uc[2] / 255.f;
3619 	  bkrd[3] = bkrd_uc[3] / 255.f;
3620 	  if(T->ray->BigEndian){
3621 	    bkrd_value = back_mask |
3622 	      ((0xFF & ((unsigned int) (bkrd_uc[0] * 255 + _p499))) << 24) |
3623 	      ((0xFF & ((unsigned int) (bkrd_uc[1] * 255 + _p499))) << 16) |
3624 	      ((0xFF & ((unsigned int) (bkrd_uc[2] * 255 + _p499))) << 8);
3625 	  } else {
3626 	    bkrd_value = back_mask |
3627 	      ((0xFF & ((unsigned int) (bkrd_uc[2] * 255 + _p499))) << 16) |
3628 	      ((0xFF & ((unsigned int) (bkrd_uc[1] * 255 + _p499))) << 8) |
3629 	      ((0xFF & ((unsigned int) (bkrd_uc[0] * 255 + _p499))));
3630 	  }
3631 	}
3632 
3633         pixel_base[0] = (((x + 0.5F + border_offset)) * invWdthRange) + vol0;
3634 
3635         while(1) {
3636           if(T->edging) {
3637             if(!edge_sampling) {
3638               if(x && y && (x < (T->width - 1)) && (y < (T->height - 1))) {     /* not on the edge... */
3639                 if(find_edge(T->edging + (pixel - T->image),
3640                              depth + (pixel - T->image),
3641                              T->width, T->edging_cutoff, bkrd_value)) {
3642                   unsigned char *pixel_c = (unsigned char *) pixel;
3643                   unsigned int c1, c2, c3, c4;
3644                   edge_cnt = 1;
3645                   edge_sampling = true;
3646 
3647                   edge_avg[0] = (c1 = pixel_c[0]);
3648                   edge_avg[1] = (c2 = pixel_c[1]);
3649                   edge_avg[2] = (c3 = pixel_c[2]);
3650                   edge_avg[3] = (c4 = pixel_c[3]);
3651 
3652                   edge_alpha_avg[0] = c1 * c4;
3653                   edge_alpha_avg[1] = c2 * c4;
3654                   edge_alpha_avg[2] = c3 * c4;
3655                   edge_alpha_avg[3] = c4;
3656 
3657                   edge_base[0] = pixel_base[0];
3658                   edge_base[1] = pixel_base[1];
3659                 }
3660               }
3661             }
3662             if(edge_sampling) {
3663               if(edge_cnt == 5) {
3664                 /* done with edging, so store averaged value */
3665 
3666                 unsigned char *pixel_c = (unsigned char *) pixel;
3667                 unsigned int c1, c2, c3, c4;
3668 
3669                 edge_sampling = false;
3670                 /* done with edging, so store averaged value */
3671 
3672                 if(edge_alpha_avg[3]) {
3673                   c4 = edge_alpha_avg[3];
3674                   c1 = edge_alpha_avg[0] / c4;
3675                   c2 = edge_alpha_avg[1] / c4;
3676                   c3 = edge_alpha_avg[2] / c4;
3677                   c4 /= edge_cnt;
3678                 } else {
3679                   c1 = edge_avg[0] / edge_cnt;
3680                   c2 = edge_avg[1] / edge_cnt;
3681                   c3 = edge_avg[2] / edge_cnt;
3682                   c4 = edge_avg[3] / edge_cnt;
3683                 }
3684                 pixel_c[0] = c1;
3685                 pixel_c[1] = c2;
3686                 pixel_c[2] = c3;
3687                 pixel_c[3] = c4;
3688 
3689 		/* Need to account for alpha, if exists */
3690 		if (orig_opaque_back && c4 < 255){
3691 		  float bkpart = (255 - c4) / 255.f;
3692 		  float ppart = 1.f - bkpart;
3693 		  pixel_c[0] = pymol_roundf(bkpart * bkrd[0] * 255 + ppart * pixel_c[0]);
3694 		  pixel_c[1] = pymol_roundf(bkpart * bkrd[1] * 255 + ppart * pixel_c[1]);
3695 		  pixel_c[2] = pymol_roundf(bkpart * bkrd[2] * 255 + ppart * pixel_c[2]);
3696 		  pixel_c[3] = 255;
3697 		}
3698 
3699                 /* restore X,Y coordinates */
3700                 r1.base[0] = pixel_base[0];
3701                 r1.base[1] = pixel_base[1];
3702 
3703               } else {
3704                 *pixel = 0;
3705 		//                *pixel = bkrd_value;
3706                 switch (edge_cnt) {
3707                 case 1:
3708                   r1.base[0] = edge_base[0] + edge_width;
3709                   r1.base[1] = edge_base[1] + edge_height;
3710                   break;
3711                 case 2:
3712                   r1.base[0] = edge_base[0] + edge_width;
3713                   r1.base[1] = edge_base[1] - edge_height;
3714                   break;
3715                 case 3:
3716                   r1.base[0] = edge_base[0] - edge_width;
3717                   r1.base[1] = edge_base[1] + edge_height;
3718                   break;
3719                 case 4:
3720                   r1.base[0] = edge_base[0] - edge_width;
3721                   r1.base[1] = edge_base[1] - edge_height;
3722                   break;
3723                 }
3724 
3725               }
3726             }
3727             if(!edge_sampling)  /* not oversampling this edge or already done... */
3728               break;
3729           } else {
3730             r1.base[0] = pixel_base[0];
3731             r1.base[1] = pixel_base[1];
3732           }
3733 
3734           exclude1 = -1;
3735           exclude2 = -1;
3736           persist = _1;
3737           first_excess = _0;
3738           excl_trans = _0;
3739           pass = 0;
3740           new_front = T->front;
3741 
3742           if(perspective) {
3743             r1.base[2] = -T->front;
3744             r1.dir[0] = (r1.base[0] - eye[0]);
3745             r1.dir[1] = (r1.base[1] - eye[1]);
3746             r1.dir[2] = (r1.base[2] - eye[2]);
3747             if(BasisCall[0].check_interior) {
3748               start[0] = r1.base[0];
3749               start[1] = r1.base[1];
3750               start[2] = r1.base[2];
3751             }
3752             normalize3f(r1.dir);
3753             {
3754               float scale = I->max_box[2] / r1.base[2];
3755 
3756               r1.skip[0] = r1.base[0] * scale;
3757               r1.skip[1] = r1.base[1] * scale;
3758               r1.skip[2] = I->max_box[2];
3759             }
3760 
3761           }
3762           while((persist > _persistLimit) && (pass <= max_pass)) {
3763             char fogFlagTmp = fogFlag;
3764             pixel_flag = false;
3765             BasisCall[0].except1 = exclude1;
3766             BasisCall[0].except2 = exclude2;
3767             BasisCall[0].front = new_front;
3768             BasisCall[0].excl_trans = excl_trans;
3769             BasisCall[0].interior_flag = false;
3770             BasisCall[0].pass = pass;
3771 
3772             if(perspective) {
3773               if(pass) {
3774                 add3f(nudge, r1.base, r1.base);
3775                 copy3f(r1.base, r1.skip);
3776               }
3777               BasisCall[0].back_dist = -(T->back + r1.base[2]) / r1.dir[2];
3778               i = BasisHitPerspective(&BasisCall[0]);
3779             } else {
3780               i = BasisHitOrthoscopic(&BasisCall[0]);
3781             }
3782             interior_flag = BasisCall[0].interior_flag && (!pass);
3783 
3784             if(((i >= 0) || interior_flag) && (pass < max_pass)) {
3785 	      int n_basis_tmp = r1.prim->no_lighting ? 0 : n_basis;
3786               pixel_flag = true;
3787               n_hit++;
3788               if(((r1.trans = r1.prim->trans) != _0) && trans_cont_flag) {
3789                 r1.trans = (float) pow(r1.trans, inv_trans_cont);
3790               }
3791               if(interior_flag) {
3792                 copy3f(interior_normal, r1.surfnormal);
3793                 if(perspective) {
3794                   copy3f(start, r1.impact);
3795                   r1.dist = _0;
3796                 } else {
3797                   copy3f(r1.base, r1.impact);
3798                   r1.dist = T->front;
3799                   r1.impact[2] -= T->front;
3800                 }
3801 
3802                 if(interior_wobble >= 0) {
3803                   wobble_save = r1.prim->wobble;        /* This is a no-no for multithreading! */
3804                   r1.prim->wobble = interior_wobble;
3805 
3806                   RayReflectAndTexture(I, &r1, perspective);
3807 
3808                   r1.prim->wobble = wobble_save;
3809                 } else
3810                   RayReflectAndTexture(I, &r1, perspective);
3811 
3812                 dotgle = -r1.dotgle;
3813                 if((interior_color < 0) && (interior_color > cColorExtCutoff)) {
3814                   copy3f(r1.prim->ic, fc);
3815                 } else {
3816                   copy3f(inter, fc);
3817                 }
3818               } else {
3819                 if(!perspective)
3820                   new_front = r1.dist;
3821 
3822                 switch (r1.prim->type) {
3823                 case cPrimTriangle:
3824 
3825                   BasisGetTriangleNormal(bp1, &r1, i, fc, perspective);
3826                   r1.trans = (float) pow(r1.trans, inv_trans_cont);
3827 
3828                   if(r1.prim->ramped) {
3829                     RayPrimGetColorRamped(I->G, I->ModelView, &r1, fc);
3830                   }
3831                   if(bp2) {
3832                     RayProjectTriangle(I, &r1, bp2->LightNormal,
3833                                        bp1->Vertex + i * 3,
3834                                        bp1->Normal + bp1->Vert2Normal[i] * 3 + 3,
3835                                        project_triangle);
3836                   }
3837 
3838                   RayReflectAndTexture(I, &r1, perspective);
3839                   if(perspective) {
3840                     BasisGetTriangleFlatDotglePerspective(bp1, &r1, i);
3841                   } else {
3842                     BasisGetTriangleFlatDotgle(bp1, &r1, i);
3843                   }
3844                   break;
3845                 case cPrimCharacter:
3846                   BasisGetTriangleNormal(bp1, &r1, i, fc, perspective);
3847 
3848                   r1.trans = CharacterInterpolate(I->G, r1.prim->char_id, fc);
3849 		  fogFlagTmp = false;
3850                   RayReflectAndTexture(I, &r1, perspective);
3851                   BasisGetTriangleFlatDotgle(bp1, &r1, i);
3852                   break;
3853 
3854                 case cPrimEllipsoid:
3855 
3856                   BasisGetEllipsoidNormal(bp1, &r1, i, perspective);
3857                   RayReflectAndTexture(I, &r1, perspective);
3858 
3859                   fc[0] = r1.prim->c1[0];
3860                   fc[1] = r1.prim->c1[1];
3861                   fc[2] = r1.prim->c1[2];
3862                   break;
3863 
3864                 default:       /* sphere, cylinder, sausage, etc. */
3865 
3866                   /* must be a sphere (effectively speaking) */
3867 
3868                   if(perspective) {
3869                     RayGetSphereNormalPerspective(I, &r1);
3870                   } else {
3871                     RayGetSphereNormal(I, &r1);
3872                   }
3873 
3874                   RayReflectAndTexture(I, &r1, perspective);
3875 
3876                   if(r1.prim->ramped) {
3877                     RayPrimGetColorRamped(I->G, I->ModelView, &r1, fc);
3878                   } else {
3879                     switch (r1.prim->type) {
3880                     case cPrimCylinder:
3881                     case cPrimSausage:
3882                     case cPrimCone:
3883                       ft = r1.tri1;
3884                       fc[0] = (r1.prim->c1[0] * (_1 - ft)) + (r1.prim->c2[0] * ft);
3885                       fc[1] = (r1.prim->c1[1] * (_1 - ft)) + (r1.prim->c2[1] * ft);
3886                       fc[2] = (r1.prim->c1[2] * (_1 - ft)) + (r1.prim->c2[2] * ft);
3887                       break;
3888                     default:
3889                       fc[0] = r1.prim->c1[0];
3890                       fc[1] = r1.prim->c1[1];
3891                       fc[2] = r1.prim->c1[2];
3892                       break;
3893                     }
3894                   }
3895                   break;
3896                 }
3897 
3898                 if((trans_oblique != _0) && (r1.trans != _0)) {
3899                   if((r1.surfnormal[2] > _0) || two_sided_lighting) {
3900                     float oblique_factor = r1.surfnormal[2];
3901                     if(oblique_factor < _0)
3902                       oblique_factor = -oblique_factor;
3903                     if(oblique_factor != _1) {
3904                       if(oblique_factor > _p5) {
3905                         oblique_factor =
3906                           (float) (_p5 +
3907                                    _p5 * (_1 -
3908                                           pow((_1 - oblique_factor) * _2,
3909                                               oblique_power)));
3910                       } else {
3911                         oblique_factor =
3912                           (float) (_p5 * pow(oblique_factor * _2, oblique_power));
3913                       }
3914                     }
3915                     r1.trans *= (trans_oblique * oblique_factor) + (1.0F - trans_oblique);
3916                     if(r1.trans < 0.06F)
3917                       r1.trans = 0.06F; /* don't allow transparent to become opaque */
3918                   }
3919                 }
3920 
3921                 dotgle = -r1.dotgle;
3922 
3923                 if(r1.flat_dotgle < _0) {
3924                   if((!two_sided_lighting) && (BasisCall[0].check_interior)
3925                      && (interior_mode != 2)) {
3926                     interior_flag = true;
3927                     copy3f(interior_normal, r1.surfnormal);
3928                     if(perspective) {
3929                       copy3f(start, r1.impact);
3930                       r1.dist = _0;
3931                     } else {
3932                       copy3f(r1.base, r1.impact);
3933                       r1.impact[2] -= T->front;
3934                       r1.dist = T->front;
3935                     }
3936 
3937                     if(interior_wobble >= 0) {
3938                       wobble_save = r1.prim->wobble;
3939                       r1.prim->wobble = interior_wobble;
3940                       RayReflectAndTexture(I, &r1, perspective);
3941                       r1.prim->wobble = wobble_save;
3942                     } else {
3943                       RayReflectAndTexture(I, &r1, perspective);
3944                     }
3945 
3946                     dotgle = -r1.dotgle;
3947                     if((interior_color < 0) && (interior_color > cColorExtCutoff)) {
3948                       copy3f(r1.prim->ic, fc);
3949                     } else {
3950                       copy3f(inter, fc);
3951                     }
3952                   }
3953                 }
3954 
3955                 if((r1.flat_dotgle < _0) && (!interior_flag)) {
3956                   if(two_sided_lighting) {
3957                     dotgle = -dotgle;
3958                     invert3f(r1.surfnormal);
3959                   }
3960                 }
3961               }
3962 
3963               {
3964                 double pow_dotgle;
3965                 float pow_surfnormal2;
3966 
3967                 if(settingPower != _1) {
3968                   pow_dotgle = pow(dotgle, settingPower);
3969                   pow_surfnormal2 = (float) pow(r1.surfnormal[2], settingPower);
3970                 } else {
3971                   pow_dotgle = dotgle;
3972                   pow_surfnormal2 = r1.surfnormal[2];
3973                 }
3974                 direct_cmp = legacy_1m * pow_surfnormal2 +      /* new model */
3975                   legacy * ((float) (dotgle + pow_dotgle) * _p5);       /* legacy model */
3976               }
3977 
3978               reflect_cmp = _0;
3979               if(settingSpecDirect != _0) {
3980                 if(r1.surfnormal[2] > _0) {
3981                   excess =
3982                     (float) (pow(r1.surfnormal[2], settingSpecDirectPower) *
3983                              settingSpecDirect);
3984                 } else {
3985                   excess = _0;
3986                 }
3987               } else {
3988                 excess = _0;
3989               }
3990 
3991               lit = _1;
3992               if(n_basis_tmp < 3) {
3993                 reflect_cmp = direct_cmp;
3994               } else {
3995                 int bc;
3996                 CBasis *bp;
3997                 for(bc = 2; bc < n_basis; bc++) {
3998                   lit = _1;
3999                   bp = I->Basis + bc;
4000 
4001                   if(shadows && ((!interior_flag) || (interior_shadows)) &&
4002                      ((r1.prim->type != cPrimCharacter) || (label_shadow_mode & 0x1))) {
4003                     matrix_transform33f3f(bp->Matrix, r1.impact, r2.base);
4004                     r2.base[2] -= shadow_fudge;
4005                     BasisCall[bc].except2 = -1;
4006                     BasisCall[bc].except1 = i;  /* exclude current prim from shadow comp */
4007                     if(BasisHitShadow(&BasisCall[bc]) > -1) {
4008                       if((!clip_shadows) || (bp->LightNormal[2] >= _0) ||
4009                          ((T->front + r1.impact[2] - (r2.dist * bp->LightNormal[2])) <
4010                           _0)) {
4011                         lit = (float) pow(r2.trans, _p5);
4012                         if((shadow_decay != _0) && (r2.dist > shadow_range)) {
4013                           if(shadow_decay > 0) {
4014                             lit +=
4015                               ((_1 - lit) * (_1 -
4016                                              _1 / exp((r2.dist - shadow_range) *
4017                                                       shadow_decay)));
4018                           } else {
4019                             lit +=
4020                               ((_1 - lit) * (_1 -
4021                                              _1 / pow(r2.dist / shadow_range,
4022                                                       -shadow_decay)));
4023                           }
4024                         }
4025                       }
4026                     }
4027                   }
4028 
4029                   if(lit > _0) {
4030                     {
4031                       double pow_dotgle;
4032 
4033                       dotgle = -dot_product3f(r1.surfnormal, bp->LightNormal);
4034                       if(dotgle < _0)
4035                         dotgle = _0;
4036 
4037                       if(settingReflectPower != _1)
4038                         pow_dotgle = pow(dotgle, settingReflectPower);
4039                       else
4040                         pow_dotgle = dotgle;
4041 
4042                       reflect_cmp += legacy_1m * ((float) (lit * pow_dotgle)) + /* new model */
4043                         legacy * ((float) (lit * (dotgle + pow_dotgle) * _p5)); /* legacy model */
4044                     }
4045 
4046                     if(bc < (spec_count + 2)) {
4047 
4048                       if(ray_scatter != _0)     /* scattered specular light */
4049                         excess += ray_scatter * dotgle;
4050 
4051                       if(spec_local && perspective) {
4052                         /* slower, C4D-like local specular */
4053                         float tmp[3];
4054 
4055                         add3f(r1.surfnormal, r1.surfnormal, tmp);
4056                         add3f(tmp, bp->LightNormal, tmp);
4057                         normalize3f(tmp);
4058                         dotgle = -(dot_product3f(r1.dir, tmp)) * 1.004F;
4059                         if(dotgle > _1)
4060                           dotgle = _1;
4061                         else if(dotgle < _0)
4062                           dotgle = _0;
4063                         dotgle = powf(dotgle, 0.29F);
4064                       } else {
4065                         dotgle = -dot_product3f(r1.surfnormal, bp->SpecNormal); /* fast OpenGL-like global specular */
4066                       }
4067                       if(dotgle < _0)
4068                         dotgle = _0;
4069                       if(r1.prim->type != cPrimCharacter) {
4070                         excess +=
4071                           (float) (pow(dotgle, settingSpecPower) * settingSpecReflect *
4072                                    lit);
4073                       } else {
4074                         excess +=
4075                           (float) (pow(dotgle, settingSpecPower) * settingSpecReflect *
4076                                    lit * ray_lab_spec);
4077                       }
4078                     }
4079                   }
4080                 }
4081                 if (chromadepth > 0) {
4082                   float d = -(r1.impact[2] + T->front) / (T->back - T->front);
4083                   const float margin = 1. / 4.;
4084                   float h = d * (1. + 2. * margin) - margin;
4085                   if (h < 0.0) h = 0.0;
4086                   if (h > 1.0) h = 1.0;
4087                   float hue6 = 6. * 240. / 360. * h;
4088                   float rgb[3];
4089                   rgb[0] = fabs(hue6 - 3.) - 1.;
4090                   rgb[1] = 2. - fabs(hue6 - 2.);
4091                   rgb[2] = 2. - fabs(hue6 - 4.);
4092                   clamp3f(rgb);
4093                   if (chromadepth == 2) {
4094                       float lum = 0.30 * fc[0] + 0.59 * fc[1] + 0.11 * fc[2];
4095                       rgb[0] *= lum;
4096                       rgb[1] *= lum;
4097                       rgb[2] *= lum;
4098                   }
4099                   copy3(rgb, fc);
4100                 }
4101               }
4102 
4103               if(fc[0] <= ((float) cColorExtCutoff)) {  /* ramped color */
4104                 inverse_transformC44f3f(I->ModelView, r1.impact, back_pact);
4105                 ColorGetRamped(I->G, (int) (fc[0] - 0.1F), back_pact, fc, -1);
4106               }
4107 
4108               bright = ambient + (((_1 - direct_shade) + direct_shade * lit) * direct * direct_cmp + lreflect * reflect_cmp * (legacy_1m + legacy * direct_cmp));       /* blend legacy */
4109               if(excess > _1)
4110                 excess = _1;
4111               if(bright > _1)
4112                 bright = _1;
4113               else if(bright < _0)
4114                 bright = _0;
4115 
4116               /*                      bright *= (_1-excess); */
4117 
4118               fc[0] = (bright * fc[0] + excess);
4119               fc[1] = (bright * fc[1] + excess);
4120               fc[2] = (bright * fc[2] + excess);
4121 
4122               if(n_basis_tmp && fogFlagTmp) {
4123                 if(perspective) {
4124                   ffact = (T->front + r1.impact[2]) * invFrontMinusBack;
4125                 } else {
4126                   ffact = (T->front - r1.dist) * invFrontMinusBack;
4127                 }
4128                 if(fogRangeFlag)
4129                   ffact = (ffact - fog_start) * inv1minusFogStart;
4130 
4131                 ffact *= fog;
4132 
4133                 if(ffact < _0)
4134                   ffact = _0;
4135                 if(ffact > _1)
4136                   ffact = _1;
4137 
4138                 ffact1m = _1 - ffact;
4139 
4140 		if(orig_opaque_back) {
4141 		  fc[0] = ffact * bkrd[0] + fc[0] * ffact1m;
4142 		  fc[1] = ffact * bkrd[1] + fc[1] * ffact1m;
4143 		  fc[2] = ffact * bkrd[2] + fc[2] * ffact1m;
4144 		  fc[3] = _1;
4145 		} else {
4146                   fc[3] = ffact1m * (_1 - r1.trans);
4147 		}
4148 
4149                 if(!pass) {
4150                   if(r1.trans < trans_spec_cut) {
4151                     first_excess = excess * ffact1m * ray_trans_spec;
4152                   } else {
4153                     first_excess = excess * ffact1m * ray_trans_spec *
4154                       trans_spec_scale * (_1 - r1.trans);
4155                   }
4156                 } else {
4157                   fc[0] += first_excess;        /* dubious? */
4158                   fc[1] += first_excess;
4159                   fc[2] += first_excess;
4160                 }
4161               } else {
4162                 if(!pass) {
4163                   if(r1.trans < trans_spec_cut) {
4164                     first_excess = excess * ray_trans_spec;
4165                   } else {
4166                     first_excess = excess * ray_trans_spec *
4167                       trans_spec_scale * (_1 - r1.trans);
4168                   }
4169                 } else {
4170                   fc[0] += first_excess;
4171                   fc[1] += first_excess;
4172                   fc[2] += first_excess;
4173                 }
4174                 if(orig_opaque_back) {
4175                   fc[3] = _1;
4176 		} else {
4177 		  fc[3] = _1 - r1.trans;
4178                 }
4179               }
4180             } else if(pass) {
4181               /* hit nothing, and we're on on second or greater pass,
4182                  or we're on the last pass of a dead-end loop */
4183               i = -1;
4184 
4185 	      fc[0] = first_excess + bkrd[0];
4186 	      fc[1] = first_excess + bkrd[1];
4187 	      fc[2] = first_excess + bkrd[2];
4188 
4189 	      if(orig_opaque_back) {
4190                 fc[3] = _1;
4191 	      } else {
4192 		fc[3] = _0;
4193 		//		fc[3] = bkrd[3];
4194 	      }
4195 
4196               ffact = 1.0F;
4197               ffact1m = 0.0F;
4198 
4199               pixel_flag = true;
4200               if(trans_cont_flag)
4201                 persist = (float) pow(persist, trans_cont);
4202 
4203             }
4204 
4205             if(pixel_flag) {
4206               /*
4207                  inp    = (fc[0]+fc[1]+fc[2]) * _inv3;
4208                  if(inp < R_SMALL4)
4209                  sig = _1;
4210                  else
4211                  sig = (float)(pow(inp,gamma) / inp);
4212 
4213                  cc0 = (uint)(sig * fc[0] * _255);
4214                  cc1 = (uint)(sig * fc[1] * _255);
4215                  cc2 = (uint)(sig * fc[2] * _255);
4216                */
4217 
4218               cc0 = (uint) (fc[0] * _255);
4219               cc1 = (uint) (fc[1] * _255);
4220               cc2 = (uint) (fc[2] * _255);
4221 
4222               if(cc0 > 255)
4223                 cc0 = 255;
4224               if(cc1 > 255)
4225                 cc1 = 255;
4226               if(cc2 > 255)
4227                 cc2 = 255;
4228 
4229               if(orig_opaque_back) {
4230                 if(I->BigEndian)
4231                   *pixel = T->fore_mask | (cc0 << 24) | (cc1 << 16) | (cc2 << 8);
4232                 else
4233                   *pixel = T->fore_mask | (cc2 << 16) | (cc1 << 8) | cc0;
4234               } else {
4235                 /* use alpha channel for fog with transparent backgrounds */
4236                 cc3 = (uint) (fc[3] * _255);
4237                 if(cc3 > 255)
4238                   cc3 = 255;
4239 
4240                 if(I->BigEndian)
4241                   *pixel = (cc0 << 24) | (cc1 << 16) | (cc2 << 8) | cc3;
4242                 else
4243                   *pixel = (cc3 << 24) | (cc2 << 16) | (cc1 << 8) | cc0;
4244               }
4245             }
4246             if(pass && persist < 1.f) {          /* average all four channels */
4247               float mix_in;
4248               if(i >= 0) {
4249                 if(fogFlagTmp) {
4250                   if(trans_cont_flag && (ffact > _p5)) {
4251                     mix_in =
4252                       2 * (persist * (_1 - ffact) +
4253                            ((float) pow(persist, trans_cont) * (ffact - _p5)))
4254                       * (_1 - r1.trans * ffact);
4255                   } else {
4256                     mix_in = persist * (_1 - r1.trans * ffact);
4257                   }
4258                 } else {
4259                   mix_in = persist * (_1 - r1.trans);
4260                 }
4261               } else {
4262                 mix_in = persist;
4263               }
4264 
4265               persist_inv = _1 - mix_in;
4266 
4267               if(!orig_opaque_back) {
4268                 if(i < 0) {     /* hit nothing -- so don't blend */
4269                   fc[0] = (float) (0xFF & (last_pixel >> 24));
4270                   fc[1] = (float) (0xFF & (last_pixel >> 16));
4271                   fc[2] = (float) (0xFF & (last_pixel >> 8));
4272                   fc[3] = (float) (0xFF & (last_pixel));
4273                   if(trans_cont_flag) { /* unless we are increasing contrast */
4274                     float m;
4275                     if(I->BigEndian) {
4276                       m = _1 - (float) (0xFF & (last_pixel)) / _255;
4277                     } else {
4278                       m = _1 - (float) (0xFF & (last_pixel >> 24)) / _255;
4279                     }
4280                     m = _1 - (float) pow(m, trans_cont);
4281                     if(I->BigEndian) {
4282                       fc[3] = m * _255 + _p499;
4283                     } else {
4284                       fc[0] = m * _255 + _p499;
4285                     }
4286                   }
4287                 } else {        /* hit something -- so keep blend and compute cumulative alpha */
4288 
4289                   fc[0] =
4290                     (0xFF & ((*pixel) >> 24)) * mix_in +
4291                     (0xFF & (last_pixel >> 24)) * persist_inv;
4292                   fc[1] =
4293                     (0xFF & ((*pixel) >> 16)) * mix_in +
4294                     (0xFF & (last_pixel >> 16)) * persist_inv;
4295                   fc[2] =
4296                     (0xFF & ((*pixel) >> 8)) * mix_in +
4297                     (0xFF & (last_pixel >> 8)) * persist_inv;
4298                   fc[3] =
4299                     (0xFF & ((*pixel))) * mix_in + (0xFF & (last_pixel)) * persist_inv;
4300 
4301                   if(i >= 0) {  /* make sure opaque objects get opaque alpha */
4302                     float o1, o2;
4303                     float m;
4304 
4305                     if(I->BigEndian) {
4306                       o1 = (float) (0xFF & (last_pixel)) / _255;
4307                       o2 = (float) (0xFF & (*pixel)) / _255;
4308                     } else {
4309                       o1 = (float) (0xFF & (last_pixel >> 24)) / _255;
4310                       o2 = (float) (0xFF & ((*pixel) >> 24)) / _255;
4311                     }
4312 
4313                     if(o1 < o2) {       /* make sure o1 is largest opacity */
4314                       m = o1;
4315                       o1 = o2;
4316                       o2 = m;
4317                     }
4318                     m = o1 + (1.0F - o1) * o2;
4319                     if(I->BigEndian) {
4320                       fc[3] = m * _255 + _p499;
4321                     } else {
4322                       fc[0] = m * _255 + _p499;
4323                     }
4324                   }
4325                 }
4326               } else {          /* opaque background, so just blend */
4327                 fc[0] =
4328                   (0xFF & ((*pixel) >> 24)) * mix_in +
4329                   (0xFF & (last_pixel >> 24)) * persist_inv;
4330                 fc[1] =
4331                   (0xFF & ((*pixel) >> 16)) * mix_in +
4332                   (0xFF & (last_pixel >> 16)) * persist_inv;
4333                 fc[2] =
4334                   (0xFF & ((*pixel) >> 8)) * mix_in +
4335                   (0xFF & (last_pixel >> 8)) * persist_inv;
4336                 fc[3] =
4337                   (0xFF & ((*pixel))) * mix_in + (0xFF & (last_pixel)) * persist_inv;
4338               }
4339 
4340               cc0 = (uint) (fc[0]);
4341               cc1 = (uint) (fc[1]);
4342               cc2 = (uint) (fc[2]);
4343               cc3 = (uint) (fc[3]);
4344 
4345               if(cc0 > 255)
4346                 cc0 = 255;
4347               if(cc1 > 255)
4348                 cc1 = 255;
4349               if(cc2 > 255)
4350                 cc2 = 255;
4351               if(cc3 > 255)
4352                 cc3 = 255;
4353 
4354               *pixel = (cc0 << 24) | (cc1 << 16) | (cc2 << 8) | cc3;
4355 
4356             }
4357 
4358             if(depth && (i >= 0) &&
4359                (r1.trans < trans_cutoff) && (persist > persist_cutoff)) {
4360               depth[pixel - T->image] = (T->front + r1.impact[2]);
4361             }
4362 
4363             if(i >= 0) {
4364               if(r1.prim->type == cPrimSausage) {       /* carry ray through the stick */
4365                 if(perspective)
4366                   excl_trans = (2 * r1.surfnormal[2] * r1.prim->r1 / r1.dir[2]);
4367                 else
4368                   excl_trans = new_front + (2 * r1.surfnormal[2] * r1.prim->r1);
4369               }
4370 
4371               if((!backface_cull) && (trans_mode != 2))
4372                 persist = persist * r1.trans;
4373               else {
4374                 if(!r1.prim->no_lighting && (persist < 0.9999F) && (r1.trans > 0.05F)) {
4375                   /* don't combine transparent surfaces */
4376                   *pixel = last_pixel;
4377                 } else {
4378                   persist = persist * r1.trans;
4379                 }
4380               }
4381             }
4382 
4383             if(i < 0) {         /* nothing hit */
4384               break;
4385             } else {
4386               if(perspective) {
4387                 if(r1.prim->type != cPrimCharacter) {
4388                   float extend = r1.dist + 0.00001F;
4389                   scale3f(r1.dir, extend, nudge);
4390                 } else {
4391                   float extend = r1.dist;
4392                   scale3f(r1.dir, extend, nudge);
4393                 }
4394               }
4395               last_pixel = *pixel;
4396               exclude2 = exclude1;
4397               exclude1 = i;
4398               pass++;
4399             }
4400 
4401           }                     /* end of ray while */
4402 
4403           if(blend_colors) {
4404 
4405             float red_min = _0;
4406             float green_min = _0;
4407             float blue_min = _0;
4408             float red_part;
4409             float green_part;
4410             float blue_part;
4411 
4412             if(I->BigEndian) {
4413               fc[0] = (float) (0xFF & (*pixel >> 24));
4414               fc[1] = (float) (0xFF & (*pixel >> 16));
4415               fc[2] = (float) (0xFF & (*pixel >> 8));
4416               cc3 = (0xFF & (*pixel));
4417             } else {
4418               cc3 = (0xFF & (*pixel >> 24));
4419               fc[2] = (float) (0xFF & (*pixel >> 16));
4420               fc[1] = (float) (0xFF & (*pixel >> 8));
4421               fc[0] = (float) (0xFF & (*pixel));
4422             }
4423 
4424             red_part = red_blend * fc[0];
4425             green_part = green_blend * fc[1];
4426             blue_part = blue_blend * fc[2];
4427 
4428             red_min = (green_part > blue_part) ? green_part : blue_part;
4429             green_min = (red_part > blue_part) ? red_part : blue_part;
4430             blue_min = (green_part > red_part) ? green_part : red_part;
4431 
4432             if(fc[0] < red_min)
4433               fc[0] = red_min;
4434             if(fc[1] < green_min)
4435               fc[1] = green_min;
4436             if(fc[2] < blue_min)
4437               fc[2] = blue_min;
4438 
4439             cc0 = (uint) (fc[0]);
4440             cc1 = (uint) (fc[1]);
4441             cc2 = (uint) (fc[2]);
4442 
4443             if(cc0 > 255)
4444               cc0 = 255;
4445             if(cc1 > 255)
4446               cc1 = 255;
4447             if(cc2 > 255)
4448               cc2 = 255;
4449 
4450             if(I->BigEndian)
4451               *pixel = (cc0 << 24) | (cc1 << 16) | (cc2 << 8) | cc3;
4452             else
4453               *pixel = (cc3 << 24) | (cc2 << 16) | (cc1 << 8) | cc0;
4454           }
4455 
4456 	  {
4457 	    /* If final pixel has alpha, then the background should be
4458 	       blended into it */
4459 	    unsigned char *pixel_c = (unsigned char *) pixel;
4460 	    if (pixel_c[3] < 255){
4461 	      float pixa = (pixel_c[3]/255.f);
4462 	      float pixam1 = _1 - pixa;
4463 	      float pixam1255 = pixam1 * 255.f;
4464 	      if (T->bkrd_data || T->bkrd_is_gradient){
4465 		pixel_c[0] = (unsigned char)pymol_roundf(pixel_c[0] * pixa + bkrd[0] * pixam1255);
4466 		pixel_c[1] = (unsigned char)pymol_roundf(pixel_c[1] * pixa + bkrd[1] * pixam1255);
4467 		pixel_c[2] = (unsigned char)pymol_roundf(pixel_c[2] * pixa + bkrd[2] * pixam1255);
4468 		pixel_c[3] = (unsigned char)pymol_roundf(pixel_c[3] * pixa + bkrd[3] * pixam1255);
4469 	      }
4470 	    }
4471 	  }
4472 
4473           if(!T->edging)
4474             break;
4475           /* if here, then we're edging...
4476              so accumulate averages */
4477           {
4478 
4479             unsigned char *pixel_c = (unsigned char *) pixel;
4480             unsigned int c1, c2, c3, c4;
4481 
4482             edge_avg[0] += (c1 = pixel_c[0]);
4483             edge_avg[1] += (c2 = pixel_c[1]);
4484             edge_avg[2] += (c3 = pixel_c[2]);
4485             edge_avg[3] += (c4 = pixel_c[3]);
4486 
4487             edge_alpha_avg[0] += c1 * c4;
4488             edge_alpha_avg[1] += c2 * c4;
4489             edge_alpha_avg[2] += c3 * c4;
4490             edge_alpha_avg[3] += c4;
4491 
4492             edge_cnt++;
4493           }
4494 
4495         }                       /* end of edging while */
4496         pixel++;
4497       }                         /* end of for */
4498 
4499     }
4500     /* end of if */
4501   }                             /* end of for */
4502   /*  if(T->n_thread>1)
4503      printf(" Ray: Thread %d: Complete.\n",T->phase+1); */
4504   MapCacheFree(&BasisCall[0].cache, T->phase, cCache_map_scene_cache);
4505 
4506   if(shadows && (I->NBasis > 2)) {
4507     int bc;
4508     for(bc = 2; bc < I->NBasis; bc++) {
4509       MapCacheFree(&BasisCall[bc].cache, T->phase, cCache_map_shadow_cache);
4510     }
4511   }
4512   return (n_hit);
4513 }
4514 
4515 
4516 /* This is both an antialias and a slight blur */
4517 
4518 
4519 /* for whatever reason, greatly GCC perfers a linear sequence of
4520    accumulates over a single large expression -- the difference is
4521    huge: over 10% !!! */
4522 
4523 #define combine4by4(var,src,mask) { \
4524   var =  ((src)[0 ] & mask)   ; \
4525   var += ((src)[1 ] & mask)   ; \
4526   var += ((src)[2 ] & mask)   ; \
4527   var += ((src)[3 ] & mask)   ; \
4528   var += ((src)[4 ] & mask)   ; \
4529   var +=(((src)[5 ] & mask)*13) ; \
4530   var +=(((src)[6 ] & mask)*13) ; \
4531   var += ((src)[7 ] & mask)   ; \
4532   var += ((src)[8 ] & mask)    ; \
4533   var +=(((src)[9 ] & mask)*13) ; \
4534   var +=(((src)[10] & mask)*13) ; \
4535   var += ((src)[11] & mask)   ; \
4536   var += ((src)[12] & mask)   ; \
4537   var += ((src)[13] & mask)   ; \
4538   var += ((src)[14] & mask)   ; \
4539   var += ((src)[15] & mask)   ; \
4540   var = (var >> 6) & mask; \
4541 }
4542 
4543 #define combine5by5(var,src,mask) { \
4544   var =  ((src)[0 ] & mask)   ; \
4545   var += ((src)[1 ] & mask)   ; \
4546   var += ((src)[2 ] & mask)   ; \
4547   var += ((src)[3 ] & mask)   ; \
4548   var += ((src)[4 ] & mask)   ; \
4549   var += ((src)[5 ] & mask)   ; \
4550   var +=(((src)[6 ] & mask)*5); \
4551   var +=(((src)[7 ] & mask)*5); \
4552   var +=(((src)[8 ] & mask)*5); \
4553   var += ((src)[9 ] & mask)   ; \
4554   var += ((src)[10] & mask)   ; \
4555   var +=(((src)[11] & mask)*5); \
4556   var +=(((src)[12] & mask)*8); \
4557   var +=(((src)[13] & mask)*5); \
4558   var += ((src)[14] & mask)   ; \
4559   var += ((src)[15] & mask)   ; \
4560   var +=(((src)[16] & mask)*5); \
4561   var +=(((src)[17] & mask)*5); \
4562   var +=(((src)[18] & mask)*5); \
4563   var += ((src)[19] & mask)   ; \
4564   var += ((src)[20] & mask)   ; \
4565   var += ((src)[21] & mask)   ; \
4566   var += ((src)[22] & mask)   ; \
4567   var += ((src)[23] & mask)   ; \
4568   var += ((src)[24] & mask)   ; \
4569   var = (var >> 6) & mask; \
4570  }
4571 
4572 #define combine6by6(var,src,mask) { \
4573   var =  ((src)[0 ] & mask)   ; \
4574   var += ((src)[1 ] & mask)   ; \
4575   var += ((src)[2 ] & mask)   ; \
4576   var += ((src)[3 ] & mask)   ; \
4577   var += ((src)[4 ] & mask)   ; \
4578   var += ((src)[5 ] & mask)   ; \
4579   var += ((src)[6 ] & mask)   ; \
4580   var +=(((src)[7 ] & mask)*5); \
4581   var +=(((src)[8 ] & mask)*7); \
4582   var +=(((src)[9 ] & mask)*7); \
4583   var +=(((src)[10] & mask)*5); \
4584   var += ((src)[11] & mask)   ; \
4585   var += ((src)[12] & mask)   ; \
4586   var +=(((src)[13] & mask)*7); \
4587   var +=(((src)[14] & mask)*8); \
4588   var +=(((src)[15] & mask)*8); \
4589   var +=(((src)[16] & mask)*7); \
4590   var += ((src)[17] & mask)   ; \
4591   var += ((src)[18] & mask)   ; \
4592   var +=(((src)[19] & mask)*7); \
4593   var +=(((src)[20] & mask)*8); \
4594   var +=(((src)[21] & mask)*8); \
4595   var +=(((src)[22] & mask)*7); \
4596   var += ((src)[23] & mask)   ; \
4597   var += ((src)[24] & mask)   ; \
4598   var +=(((src)[25] & mask)*5); \
4599   var +=(((src)[26] & mask)*7); \
4600   var +=(((src)[27] & mask)*7); \
4601   var +=(((src)[28] & mask)*5); \
4602   var += ((src)[29] & mask)   ; \
4603   var += ((src)[30] & mask)   ; \
4604   var += ((src)[31] & mask)   ; \
4605   var += ((src)[32] & mask)   ; \
4606   var += ((src)[33] & mask)   ; \
4607   var += ((src)[34] & mask)   ; \
4608   var += ((src)[35] & mask)   ; \
4609   var = (var >> 7) & mask; \
4610  }
4611 
4612 #define m00FF 0x00FF
4613 #define mFF00 0xFF00
4614 #define mFFFF 0xFFFF
4615 
RayAntiThread(CRayAntiThreadInfo * T)4616 int RayAntiThread(CRayAntiThreadInfo * T)
4617 {
4618   int src_row_pixels;
4619 
4620   unsigned int *pSrc;
4621   unsigned int *pDst;
4622   /*   unsigned int m00FF=0x00FF,mFF00=0xFF00,mFFFF=0xFFFF; */
4623   int width;
4624   int height;
4625   int x, y, yy;
4626   unsigned int *p;
4627   int offset = 0;
4628   CRay *I = T->ray;
4629 
4630   OrthoBusyFast(I->G, 9, 10);
4631   width = (T->width / T->mag) - 2;
4632   height = (T->height / T->mag) - 2;
4633 
4634   src_row_pixels = T->width;
4635 
4636   offset = (T->phase * height) / T->n_thread;
4637   offset = offset - (offset % T->n_thread) + T->phase;
4638 
4639   for(yy = 0; yy < height; yy++) {
4640     y = (yy + offset) % height; /* make sure threads write to different pages */
4641 
4642     if((y % T->n_thread) == T->phase) { /* this is my scan line */
4643       unsigned long c1, c2, c3, c4, a;
4644       unsigned char *c;
4645 
4646       pSrc = T->image + src_row_pixels * (y * T->mag);
4647       pDst = T->image_copy + width * y;
4648       switch (T->mag) {
4649       case 2:
4650         {
4651           for(x = 0; x < width; x++) {
4652 
4653             c = (unsigned char *) (p = pSrc + (x * T->mag));
4654             c1 = c2 = c3 = c4 = a = 0;
4655 
4656             c4 += (a = c[3]);
4657             c1 += c[0] * a;
4658             c2 += c[1] * a;
4659             c3 += c[2] * a;
4660             c += 4;
4661             c4 += (a = c[3]);
4662             c1 += c[0] * a;
4663             c2 += c[1] * a;
4664             c3 += c[2] * a;
4665             c += 4;
4666             c4 += (a = c[3]);
4667             c1 += c[0] * a;
4668             c2 += c[1] * a;
4669             c3 += c[2] * a;
4670             c += 4;
4671             c4 += (a = c[3]);
4672             c1 += c[0] * a;
4673             c2 += c[1] * a;
4674             c3 += c[2] * a;
4675             c += 4;
4676 
4677             c = (unsigned char *) (p += src_row_pixels);
4678 
4679             c4 += (a = c[3]);
4680             c1 += c[0] * a;
4681             c2 += c[1] * a;
4682             c3 += c[2] * a;
4683             c += 4;
4684             c4 += (a = c[3] * 13);
4685             c1 += c[0] * a;
4686             c2 += c[1] * a;
4687             c3 += c[2] * a;
4688             c += 4;
4689             c4 += (a = c[3] * 13);
4690             c1 += c[0] * a;
4691             c2 += c[1] * a;
4692             c3 += c[2] * a;
4693             c += 4;
4694             c4 += (a = c[3]);
4695             c1 += c[0] * a;
4696             c2 += c[1] * a;
4697             c3 += c[2] * a;
4698             c += 4;
4699 
4700             c = (unsigned char *) (p += src_row_pixels);
4701 
4702             c4 += (a = c[3]);
4703             c1 += c[0] * a;
4704             c2 += c[1] * a;
4705             c3 += c[2] * a;
4706             c += 4;
4707             c4 += (a = c[3] * 13);
4708             c1 += c[0] * a;
4709             c2 += c[1] * a;
4710             c3 += c[2] * a;
4711             c += 4;
4712             c4 += (a = c[3] * 13);
4713             c1 += c[0] * a;
4714             c2 += c[1] * a;
4715             c3 += c[2] * a;
4716             c += 4;
4717             c4 += (a = c[3]);
4718             c1 += c[0] * a;
4719             c2 += c[1] * a;
4720             c3 += c[2] * a;
4721             c += 4;
4722 
4723             c = (unsigned char *) (p += src_row_pixels);
4724 
4725             c4 += (a = c[3]);
4726             c1 += c[0] * a;
4727             c2 += c[1] * a;
4728             c3 += c[2] * a;
4729             c += 4;
4730             c4 += (a = c[3]);
4731             c1 += c[0] * a;
4732             c2 += c[1] * a;
4733             c3 += c[2] * a;
4734             c += 4;
4735             c4 += (a = c[3]);
4736             c1 += c[0] * a;
4737             c2 += c[1] * a;
4738             c3 += c[2] * a;
4739             c += 4;
4740             c4 += (a = c[3]);
4741             c1 += c[0] * a;
4742             c2 += c[1] * a;
4743             c3 += c[2] * a;
4744             c += 4;
4745 
4746             if(c4) {
4747               c1 /= c4;
4748               c2 /= c4;
4749               c3 /= c4;
4750             } else {            /* compute straight RGB average */
4751 
4752               c = (unsigned char *) (p = pSrc + (x * T->mag));
4753               c1 = c2 = c3 = 0;
4754 
4755               c1 += c[0];
4756               c2 += c[1];
4757               c3 += c[2];
4758               c += 4;
4759               c1 += c[0];
4760               c2 += c[1];
4761               c3 += c[2];
4762               c += 4;
4763               c1 += c[0];
4764               c2 += c[1];
4765               c3 += c[2];
4766               c += 4;
4767               c1 += c[0];
4768               c2 += c[1];
4769               c3 += c[2];
4770               c += 4;
4771 
4772               c = (unsigned char *) (p += src_row_pixels);
4773 
4774               c1 += c[0];
4775               c2 += c[1];
4776               c3 += c[2];
4777               c += 4;
4778               c1 += 13 * c[0];
4779               c2 += 13 * c[1];
4780               c3 += 13 * c[2];
4781               c += 4;
4782               c1 += 13 * c[0];
4783               c2 += 13 * c[1];
4784               c3 += 13 * c[2];
4785               c += 4;
4786               c1 += c[0];
4787               c2 += c[1];
4788               c3 += c[2];
4789               c += 4;
4790 
4791               c = (unsigned char *) (p += src_row_pixels);
4792 
4793               c1 += c[0];
4794               c2 += c[1];
4795               c3 += c[2];
4796               c += 4;
4797               c1 += 13 * c[0];
4798               c2 += 13 * c[1];
4799               c3 += 13 * c[2];
4800               c += 4;
4801               c1 += 13 * c[0];
4802               c2 += 13 * c[1];
4803               c3 += 13 * c[2];
4804               c += 4;
4805               c1 += c[0];
4806               c2 += c[1];
4807               c3 += c[2];
4808               c += 4;
4809 
4810               c = (unsigned char *) (p += src_row_pixels);
4811 
4812               c1 += c[0];
4813               c2 += c[1];
4814               c3 += c[2];
4815               c += 4;
4816               c1 += c[0];
4817               c2 += c[1];
4818               c3 += c[2];
4819               c += 4;
4820               c1 += c[0];
4821               c2 += c[1];
4822               c3 += c[2];
4823               c += 4;
4824               c1 += c[0];
4825               c2 += c[1];
4826               c3 += c[2];
4827               c += 4;
4828 
4829               c1 = c1 >> 6;
4830               c2 = c2 >> 6;
4831               c3 = c3 >> 6;
4832             }
4833 
4834             c = (unsigned char *) (pDst++);
4835 
4836             *(c++) = (unsigned char) c1;
4837             *(c++) = (unsigned char) c2;
4838             *(c++) = (unsigned char) c3;
4839             *(c++) = (unsigned char) (c4 >> 6);
4840           }
4841         }
4842         break;
4843       case 3:
4844         {
4845           for(x = 0; x < width; x++) {
4846 
4847             c = (unsigned char *) (p = pSrc + (x * T->mag));
4848             c1 = c2 = c3 = c4 = a = 0;
4849 
4850             c4 += (a = c[3]);
4851             c1 += c[0] * a;
4852             c2 += c[1] * a;
4853             c3 += c[2] * a;
4854             c += 4;
4855             c4 += (a = c[3]);
4856             c1 += c[0] * a;
4857             c2 += c[1] * a;
4858             c3 += c[2] * a;
4859             c += 4;
4860             c4 += (a = c[3]);
4861             c1 += c[0] * a;
4862             c2 += c[1] * a;
4863             c3 += c[2] * a;
4864             c += 4;
4865             c4 += (a = c[3]);
4866             c1 += c[0] * a;
4867             c2 += c[1] * a;
4868             c3 += c[2] * a;
4869             c += 4;
4870             c4 += (a = c[3]);
4871             c1 += c[0] * a;
4872             c2 += c[1] * a;
4873             c3 += c[2] * a;
4874             c += 4;
4875 
4876             c = (unsigned char *) (p += src_row_pixels);
4877 
4878             c4 += (a = c[3]);
4879             c1 += c[0] * a;
4880             c2 += c[1] * a;
4881             c3 += c[2] * a;
4882             c += 4;
4883             c4 += (a = c[3] * 5);
4884             c1 += c[0] * a;
4885             c2 += c[1] * a;
4886             c3 += c[2] * a;
4887             c += 4;
4888             c4 += (a = c[3] * 5);
4889             c1 += c[0] * a;
4890             c2 += c[1] * a;
4891             c3 += c[2] * a;
4892             c += 4;
4893             c4 += (a = c[3] * 5);
4894             c1 += c[0] * a;
4895             c2 += c[1] * a;
4896             c3 += c[2] * a;
4897             c += 4;
4898             c4 += (a = c[3]);
4899             c1 += c[0] * a;
4900             c2 += c[1] * a;
4901             c3 += c[2] * a;
4902             c += 4;
4903 
4904             c = (unsigned char *) (p += src_row_pixels);
4905 
4906             c4 += (a = c[3]);
4907             c1 += c[0] * a;
4908             c2 += c[1] * a;
4909             c3 += c[2] * a;
4910             c += 4;
4911             c4 += (a = c[3] * 5);
4912             c1 += c[0] * a;
4913             c2 += c[1] * a;
4914             c3 += c[2] * a;
4915             c += 4;
4916             c4 += (a = c[3] * 8);
4917             c1 += c[0] * a;
4918             c2 += c[1] * a;
4919             c3 += c[2] * a;
4920             c += 4;
4921             c4 += (a = c[3] * 5);
4922             c1 += c[0] * a;
4923             c2 += c[1] * a;
4924             c3 += c[2] * a;
4925             c += 4;
4926             c4 += (a = c[3]);
4927             c1 += c[0] * a;
4928             c2 += c[1] * a;
4929             c3 += c[2] * a;
4930             c += 4;
4931 
4932             c = (unsigned char *) (p += src_row_pixels);
4933 
4934             c4 += (a = c[3]);
4935             c1 += c[0] * a;
4936             c2 += c[1] * a;
4937             c3 += c[2] * a;
4938             c += 4;
4939             c4 += (a = c[3] * 5);
4940             c1 += c[0] * a;
4941             c2 += c[1] * a;
4942             c3 += c[2] * a;
4943             c += 4;
4944             c4 += (a = c[3] * 5);
4945             c1 += c[0] * a;
4946             c2 += c[1] * a;
4947             c3 += c[2] * a;
4948             c += 4;
4949             c4 += (a = c[3] * 5);
4950             c1 += c[0] * a;
4951             c2 += c[1] * a;
4952             c3 += c[2] * a;
4953             c += 4;
4954             c4 += (a = c[3]);
4955             c1 += c[0] * a;
4956             c2 += c[1] * a;
4957             c3 += c[2] * a;
4958             c += 4;
4959 
4960             c = (unsigned char *) (p += src_row_pixels);
4961 
4962             c4 += (a = c[3]);
4963             c1 += c[0] * a;
4964             c2 += c[1] * a;
4965             c3 += c[2] * a;
4966             c += 4;
4967             c4 += (a = c[3]);
4968             c1 += c[0] * a;
4969             c2 += c[1] * a;
4970             c3 += c[2] * a;
4971             c += 4;
4972             c4 += (a = c[3]);
4973             c1 += c[0] * a;
4974             c2 += c[1] * a;
4975             c3 += c[2] * a;
4976             c += 4;
4977             c4 += (a = c[3]);
4978             c1 += c[0] * a;
4979             c2 += c[1] * a;
4980             c3 += c[2] * a;
4981             c += 4;
4982             c4 += (a = c[3]);
4983             c1 += c[0] * a;
4984             c2 += c[1] * a;
4985             c3 += c[2] * a;
4986             c += 4;
4987 
4988             if(c4) {
4989               c1 /= c4;
4990               c2 /= c4;
4991               c3 /= c4;
4992             } else {            /* compute straight RGB average */
4993 
4994               c = (unsigned char *) (p = pSrc + (x * T->mag));
4995               c1 = c2 = c3 = 0;
4996 
4997               c1 += c[0];
4998               c2 += c[1];
4999               c3 += c[2];
5000               c += 4;
5001               c1 += c[0];
5002               c2 += c[1];
5003               c3 += c[2];
5004               c += 4;
5005               c1 += c[0];
5006               c2 += c[1];
5007               c3 += c[2];
5008               c += 4;
5009               c1 += c[0];
5010               c2 += c[1];
5011               c3 += c[2];
5012               c += 4;
5013               c1 += c[0];
5014               c2 += c[1];
5015               c3 += c[2];
5016               c += 4;
5017 
5018               c = (unsigned char *) (p += src_row_pixels);
5019 
5020               c1 += c[0];
5021               c2 += c[1];
5022               c3 += c[2];
5023               c += 4;
5024               c1 += 5 * c[0];
5025               c2 += 5 * c[1];
5026               c3 += 5 * c[2];
5027               c += 4;
5028               c1 += 5 * c[0];
5029               c2 += 5 * c[1];
5030               c3 += 5 * c[2];
5031               c += 4;
5032               c1 += 5 * c[0];
5033               c2 += 5 * c[1];
5034               c3 += 5 * c[2];
5035               c += 4;
5036               c1 += c[0];
5037               c2 += c[1];
5038               c3 += c[2];
5039               c += 4;
5040 
5041               c = (unsigned char *) (p += src_row_pixels);
5042 
5043               c1 += c[0];
5044               c2 += c[1];
5045               c3 += c[2];
5046               c += 4;
5047               c1 += 5 * c[0];
5048               c2 += 5 * c[1];
5049               c3 += 5 * c[2];
5050               c += 4;
5051               c1 += 8 * c[0];
5052               c2 += 8 * c[1];
5053               c3 += 8 * c[2];
5054               c += 4;
5055               c1 += 5 * c[0];
5056               c2 += 5 * c[1];
5057               c3 += 5 * c[2];
5058               c += 4;
5059               c1 += c[0];
5060               c2 += c[1];
5061               c3 += c[2];
5062               c += 4;
5063 
5064               c = (unsigned char *) (p += src_row_pixels);
5065 
5066               c1 += c[0];
5067               c2 += c[1];
5068               c3 += c[2];
5069               c += 4;
5070               c1 += 5 * c[0];
5071               c2 += 5 * c[1];
5072               c3 += 5 * c[2];
5073               c += 4;
5074               c1 += 5 * c[0];
5075               c2 += 5 * c[1];
5076               c3 += 5 * c[2];
5077               c += 4;
5078               c1 += 5 * c[0];
5079               c2 += 5 * c[1];
5080               c3 += 5 * c[2];
5081               c += 4;
5082               c1 += c[0];
5083               c2 += c[1];
5084               c3 += c[2];
5085               c += 4;
5086 
5087               c = (unsigned char *) (p += src_row_pixels);
5088 
5089               c1 += c[0];
5090               c2 += c[1];
5091               c3 += c[2];
5092               c += 4;
5093               c1 += c[0];
5094               c2 += c[1];
5095               c3 += c[2];
5096               c += 4;
5097               c1 += c[0];
5098               c2 += c[1];
5099               c3 += c[2];
5100               c += 4;
5101               c1 += c[0];
5102               c2 += c[1];
5103               c3 += c[2];
5104               c += 4;
5105 
5106               c1 = c1 >> 6;
5107               c2 = c2 >> 6;
5108               c3 = c3 >> 6;
5109             }
5110 
5111             c = (unsigned char *) (pDst++);
5112 
5113             *(c++) = (unsigned char) c1;
5114             *(c++) = (unsigned char) c2;
5115             *(c++) = (unsigned char) c3;
5116             *(c++) = (unsigned char) (c4 >> 6);
5117           }
5118         }
5119         break;
5120       case 4:
5121         {
5122           for(x = 0; x < width; x++) {
5123 
5124             c = (unsigned char *) (p = pSrc + (x * T->mag));
5125             c1 = c2 = c3 = c4 = a = 0;
5126 
5127             c4 += (a = c[3]);
5128             c1 += c[0] * a;
5129             c2 += c[1] * a;
5130             c3 += c[2] * a;
5131             c += 4;
5132             c4 += (a = c[3]);
5133             c1 += c[0] * a;
5134             c2 += c[1] * a;
5135             c3 += c[2] * a;
5136             c += 4;
5137             c4 += (a = c[3]);
5138             c1 += c[0] * a;
5139             c2 += c[1] * a;
5140             c3 += c[2] * a;
5141             c += 4;
5142             c4 += (a = c[3]);
5143             c1 += c[0] * a;
5144             c2 += c[1] * a;
5145             c3 += c[2] * a;
5146             c += 4;
5147             c4 += (a = c[3]);
5148             c1 += c[0] * a;
5149             c2 += c[1] * a;
5150             c3 += c[2] * a;
5151             c += 4;
5152             c4 += (a = c[3]);
5153             c1 += c[0] * a;
5154             c2 += c[1] * a;
5155             c3 += c[2] * a;
5156             c += 4;
5157 
5158             c = (unsigned char *) (p += src_row_pixels);
5159 
5160             c4 += (a = c[3]);
5161             c1 += c[0] * a;
5162             c2 += c[1] * a;
5163             c3 += c[2] * a;
5164             c += 4;
5165             c4 += (a = c[3] * 5);
5166             c1 += c[0] * a;
5167             c2 += c[1] * a;
5168             c3 += c[2] * a;
5169             c += 4;
5170             c4 += (a = c[3] * 7);
5171             c1 += c[0] * a;
5172             c2 += c[1] * a;
5173             c3 += c[2] * a;
5174             c += 4;
5175             c4 += (a = c[3] * 7);
5176             c1 += c[0] * a;
5177             c2 += c[1] * a;
5178             c3 += c[2] * a;
5179             c += 4;
5180             c4 += (a = c[3] * 5);
5181             c1 += c[0] * a;
5182             c2 += c[1] * a;
5183             c3 += c[2] * a;
5184             c += 4;
5185             c4 += (a = c[3]);
5186             c1 += c[0] * a;
5187             c2 += c[1] * a;
5188             c3 += c[2] * a;
5189             c += 4;
5190 
5191             c = (unsigned char *) (p += src_row_pixels);
5192 
5193             c4 += (a = c[3]);
5194             c1 += c[0] * a;
5195             c2 += c[1] * a;
5196             c3 += c[2] * a;
5197             c += 4;
5198             c4 += (a = c[3] * 7);
5199             c1 += c[0] * a;
5200             c2 += c[1] * a;
5201             c3 += c[2] * a;
5202             c += 4;
5203             c4 += (a = c[3] * 8);
5204             c1 += c[0] * a;
5205             c2 += c[1] * a;
5206             c3 += c[2] * a;
5207             c += 4;
5208             c4 += (a = c[3] * 8);
5209             c1 += c[0] * a;
5210             c2 += c[1] * a;
5211             c3 += c[2] * a;
5212             c += 4;
5213             c4 += (a = c[3] * 7);
5214             c1 += c[0] * a;
5215             c2 += c[1] * a;
5216             c3 += c[2] * a;
5217             c += 4;
5218             c4 += (a = c[3]);
5219             c1 += c[0] * a;
5220             c2 += c[1] * a;
5221             c3 += c[2] * a;
5222             c += 4;
5223 
5224             c = (unsigned char *) (p += src_row_pixels);
5225 
5226             c4 += (a = c[3]);
5227             c1 += c[0] * a;
5228             c2 += c[1] * a;
5229             c3 += c[2] * a;
5230             c += 4;
5231             c4 += (a = c[3] * 7);
5232             c1 += c[0] * a;
5233             c2 += c[1] * a;
5234             c3 += c[2] * a;
5235             c += 4;
5236             c4 += (a = c[3] * 8);
5237             c1 += c[0] * a;
5238             c2 += c[1] * a;
5239             c3 += c[2] * a;
5240             c += 4;
5241             c4 += (a = c[3] * 8);
5242             c1 += c[0] * a;
5243             c2 += c[1] * a;
5244             c3 += c[2] * a;
5245             c += 4;
5246             c4 += (a = c[3] * 7);
5247             c1 += c[0] * a;
5248             c2 += c[1] * a;
5249             c3 += c[2] * a;
5250             c += 4;
5251             c4 += (a = c[3]);
5252             c1 += c[0] * a;
5253             c2 += c[1] * a;
5254             c3 += c[2] * a;
5255             c += 4;
5256 
5257             c = (unsigned char *) (p += src_row_pixels);
5258 
5259             c4 += (a = c[3]);
5260             c1 += c[0] * a;
5261             c2 += c[1] * a;
5262             c3 += c[2] * a;
5263             c += 4;
5264             c4 += (a = c[3] * 5);
5265             c1 += c[0] * a;
5266             c2 += c[1] * a;
5267             c3 += c[2] * a;
5268             c += 4;
5269             c4 += (a = c[3] * 7);
5270             c1 += c[0] * a;
5271             c2 += c[1] * a;
5272             c3 += c[2] * a;
5273             c += 4;
5274             c4 += (a = c[3] * 7);
5275             c1 += c[0] * a;
5276             c2 += c[1] * a;
5277             c3 += c[2] * a;
5278             c += 4;
5279             c4 += (a = c[3] * 5);
5280             c1 += c[0] * a;
5281             c2 += c[1] * a;
5282             c3 += c[2] * a;
5283             c += 4;
5284             c4 += (a = c[3]);
5285             c1 += c[0] * a;
5286             c2 += c[1] * a;
5287             c3 += c[2] * a;
5288             c += 4;
5289 
5290             c = (unsigned char *) (p += src_row_pixels);
5291 
5292             c4 += (a = c[3]);
5293             c1 += c[0] * a;
5294             c2 += c[1] * a;
5295             c3 += c[2] * a;
5296             c += 4;
5297             c4 += (a = c[3]);
5298             c1 += c[0] * a;
5299             c2 += c[1] * a;
5300             c3 += c[2] * a;
5301             c += 4;
5302             c4 += (a = c[3]);
5303             c1 += c[0] * a;
5304             c2 += c[1] * a;
5305             c3 += c[2] * a;
5306             c += 4;
5307             c4 += (a = c[3]);
5308             c1 += c[0] * a;
5309             c2 += c[1] * a;
5310             c3 += c[2] * a;
5311             c += 4;
5312             c4 += (a = c[3]);
5313             c1 += c[0] * a;
5314             c2 += c[1] * a;
5315             c3 += c[2] * a;
5316             c += 4;
5317             c4 += (a = c[3]);
5318             c1 += c[0] * a;
5319             c2 += c[1] * a;
5320             c3 += c[2] * a;
5321             c += 4;
5322 
5323             if(c4) {
5324               c1 /= c4;
5325               c2 /= c4;
5326               c3 /= c4;
5327             } else {            /* compute straight RGB average */
5328 
5329               c = (unsigned char *) (p = pSrc + (x * T->mag));
5330               c1 = c2 = c3 = 0;
5331 
5332               c1 += c[0];
5333               c2 += c[1];
5334               c3 += c[2];
5335               c += 4;
5336               c1 += c[0];
5337               c2 += c[1];
5338               c3 += c[2];
5339               c += 4;
5340               c1 += c[0];
5341               c2 += c[1];
5342               c3 += c[2];
5343               c += 4;
5344               c1 += c[0];
5345               c2 += c[1];
5346               c3 += c[2];
5347               c += 4;
5348               c1 += c[0];
5349               c2 += c[1];
5350               c3 += c[2];
5351               c += 4;
5352               c1 += c[0];
5353               c2 += c[1];
5354               c3 += c[2];
5355               c += 4;
5356 
5357               c = (unsigned char *) (p += src_row_pixels);
5358 
5359               c1 += c[0];
5360               c2 += c[1];
5361               c3 += c[2];
5362               c += 4;
5363               c1 += 5 * c[0];
5364               c2 += 5 * c[1];
5365               c3 += 5 * c[2];
5366               c += 4;
5367               c1 += 7 * c[0];
5368               c2 += 7 * c[1];
5369               c3 += 7 * c[2];
5370               c += 4;
5371               c1 += 7 * c[0];
5372               c2 += 7 * c[1];
5373               c3 += 7 * c[2];
5374               c += 4;
5375               c1 += 5 * c[0];
5376               c2 += 5 * c[1];
5377               c3 += 5 * c[2];
5378               c += 4;
5379               c1 += c[0];
5380               c2 += c[1];
5381               c3 += c[2];
5382               c += 4;
5383 
5384               c = (unsigned char *) (p += src_row_pixels);
5385 
5386               c1 += c[0];
5387               c2 += c[1];
5388               c3 += c[2];
5389               c += 4;
5390               c1 += 7 * c[0];
5391               c2 += 7 * c[1];
5392               c3 += 7 * c[2];
5393               c += 4;
5394               c1 += 8 * c[0];
5395               c2 += 8 * c[1];
5396               c3 += 8 * c[2];
5397               c += 4;
5398               c1 += 8 * c[0];
5399               c2 += 8 * c[1];
5400               c3 += 8 * c[2];
5401               c += 4;
5402               c1 += 7 * c[0];
5403               c2 += 7 * c[1];
5404               c3 += 7 * c[2];
5405               c += 4;
5406               c1 += c[0];
5407               c2 += c[1];
5408               c3 += c[2];
5409               c += 4;
5410 
5411               c = (unsigned char *) (p += src_row_pixels);
5412 
5413               c1 += c[0];
5414               c2 += c[1];
5415               c3 += c[2];
5416               c += 4;
5417               c1 += 7 * c[0];
5418               c2 += 7 * c[1];
5419               c3 += 7 * c[2];
5420               c += 4;
5421               c1 += 8 * c[0];
5422               c2 += 8 * c[1];
5423               c3 += 8 * c[2];
5424               c += 4;
5425               c1 += 8 * c[0];
5426               c2 += 8 * c[1];
5427               c3 += 8 * c[2];
5428               c += 4;
5429               c1 += 7 * c[0];
5430               c2 += 7 * c[1];
5431               c3 += 7 * c[2];
5432               c += 4;
5433               c1 += c[0];
5434               c2 += c[1];
5435               c3 += c[2];
5436               c += 4;
5437 
5438               c = (unsigned char *) (p += src_row_pixels);
5439 
5440               c1 += c[0];
5441               c2 += c[1];
5442               c3 += c[2];
5443               c += 4;
5444               c1 += 5 * c[0];
5445               c2 += 5 * c[1];
5446               c3 += 5 * c[2];
5447               c += 4;
5448               c1 += 7 * c[0];
5449               c2 += 7 * c[1];
5450               c3 += 7 * c[2];
5451               c += 4;
5452               c1 += 7 * c[0];
5453               c2 += 7 * c[1];
5454               c3 += 7 * c[2];
5455               c += 4;
5456               c1 += 5 * c[0];
5457               c2 += 5 * c[1];
5458               c3 += 5 * c[2];
5459               c += 4;
5460               c1 += c[0];
5461               c2 += c[1];
5462               c3 += c[2];
5463               c += 4;
5464 
5465               c = (unsigned char *) (p += src_row_pixels);
5466 
5467               c1 += c[0];
5468               c2 += c[1];
5469               c3 += c[2];
5470               c += 4;
5471               c1 += c[0];
5472               c2 += c[1];
5473               c3 += c[2];
5474               c += 4;
5475               c1 += c[0];
5476               c2 += c[1];
5477               c3 += c[2];
5478               c += 4;
5479               c1 += c[0];
5480               c2 += c[1];
5481               c3 += c[2];
5482               c += 4;
5483               c1 += c[0];
5484               c2 += c[1];
5485               c3 += c[2];
5486               c += 4;
5487 
5488               c1 = c1 >> 7;
5489               c2 = c2 >> 7;
5490               c3 = c3 >> 7;
5491             }
5492 
5493             c = (unsigned char *) (pDst++);
5494 
5495             *(c++) = (unsigned char) c1;
5496             *(c++) = (unsigned char) c2;
5497             *(c++) = (unsigned char) c3;
5498             *(c++) = (unsigned char) (c4 >> 7);
5499           }
5500         }
5501         break;
5502 
5503       }
5504     }
5505   }
5506   return 1;
5507 }
5508 
5509 #ifdef PROFILE_BASIS
5510 extern int n_cells;
5511 extern int n_prims;
5512 extern int n_triangles;
5513 extern int n_spheres;
5514 extern int n_cylinders;
5515 extern int n_sausages;
5516 extern int n_skipped;
5517 #endif
5518 
5519 float *rayDepthPixels = NULL;
5520 int rayVolume = 0, rayWidth = 0, rayHeight = 0;
5521 
5522 /*========================================================================*/
RayRender(CRay * I,unsigned int * image,double timing,float angle,int antialias,unsigned int * return_bg)5523 void RayRender(CRay * I, unsigned int *image, double timing,
5524                float angle, int antialias, unsigned int *return_bg)
5525 {
5526   int a, x, y;
5527   unsigned int *image_copy = NULL;
5528   unsigned int back_mask, fore_mask = 0, trace_word = 0;
5529   unsigned int background;
5530   size_t buffer_size;
5531   int orig_opaque_back = 0, opaque_back = 0;
5532   int n_hit = 0;
5533   const float *bkrd_ptr;
5534   float bkrd_top[3], bkrd_bottom[3];
5535   short bkrd_is_gradient; /* if not gradient, use bkrd_top as bkrd */
5536   double now;
5537   int shadows;
5538   int n_thread;
5539   int mag = 1;
5540   int oversample_cutoff;
5541   int perspective = SettingGetGlobal_i(I->G, cSetting_ray_orthoscopic);
5542   int n_light = SettingGetGlobal_i(I->G, cSetting_light_count);
5543   float ambient;
5544   float *depth = NULL;
5545   float front = I->Volume[4];
5546   float back = I->Volume[5];
5547   float fov = I->Fov;
5548   float *pos = I->Pos;
5549   size_t width = I->Width;
5550   size_t height = I->Height;
5551   int ray_trace_mode;
5552   const float _0 = 0.0F, _p499 = 0.499F;
5553   int volume;
5554   const char * bg_image_filename;
5555   int ok = true;
5556 
5557   if(n_light > 10)
5558     n_light = 10;
5559 
5560   if(perspective < 0)
5561     perspective = SettingGetGlobal_b(I->G, cSetting_ortho);
5562   perspective = !perspective;
5563 
5564   VLACacheSize(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
5565 #ifdef PROFILE_BASIS
5566   n_cells = 0;
5567   n_prims = 0;
5568   n_triangles = 0;
5569   n_spheres = 0;
5570   n_cylinders = 0;
5571   n_sausages = 0;
5572   n_skipped = 0;
5573 #endif
5574 
5575   n_thread = SettingGetGlobal_i(I->G, cSetting_max_threads);
5576   if(n_thread < 1)
5577     n_thread = 1;
5578   if(n_thread > PYMOL_MAX_THREADS)
5579     n_thread = PYMOL_MAX_THREADS;
5580   opaque_back = SettingGetGlobal_i(I->G, cSetting_ray_opaque_background);
5581   if(opaque_back < 0)
5582     opaque_back = SettingGetGlobal_i(I->G, cSetting_opaque_background);
5583 
5584   orig_opaque_back = opaque_back;
5585   ray_trace_mode = SettingGetGlobal_i(I->G, cSetting_ray_trace_mode);
5586 
5587   shadows = SettingGetGlobal_i(I->G, cSetting_ray_shadows);
5588 
5589   oversample_cutoff = SettingGetGlobal_i(I->G, cSetting_ray_oversample_cutoff);
5590 
5591   if(antialias < 0) {
5592     antialias = SettingGetGlobal_i(I->G, cSetting_antialias);
5593   }
5594 
5595   if(ray_trace_mode && (antialias == 1))
5596     antialias = 2;
5597   else if(ray_trace_mode && antialias)
5598     antialias++;
5599 
5600   if(antialias < 0)
5601     antialias = 0;
5602   if(antialias > 4)
5603     antialias = 4;
5604 
5605   if((!antialias) || ray_trace_mode)
5606     oversample_cutoff = 0;
5607 
5608   mag = antialias;
5609   if(mag < 1)
5610     mag = 1;
5611 
5612   if(antialias > 1) {
5613     width = (width + 2) * mag;
5614     height = (height + 2) * mag;
5615     image_copy = image;
5616     buffer_size = width * height;
5617     image = CacheAlloc(I->G, unsigned int, buffer_size, 0, cCache_ray_antialias_buffer);
5618     ErrChkPtr(I->G, image);
5619   } else {
5620     buffer_size = width * height;
5621   }
5622   if(ray_trace_mode) {
5623     depth = pymol::calloc<float>(width * height);
5624   } else if(oversample_cutoff) {
5625     depth = pymol::calloc<float>(width * height);
5626   }
5627   ambient = SettingGetGlobal_f(I->G, cSetting_ambient);
5628 
5629   bkrd_is_gradient = SettingGetGlobal_b(I->G, cSetting_bg_gradient);
5630   bg_image_filename = SettingGet_s(I->G, NULL, NULL, cSetting_bg_image_filename);
5631   I->bkgrd_data = OrthoBackgroundDataGet(*I->G->Ortho);
5632   if (!I->bkgrd_data && bg_image_filename && bg_image_filename[0]){
5633     I->bkgrd_data = MyPNGRead(bg_image_filename);
5634     bkrd_is_gradient = 0;
5635   }
5636   if (I->bkgrd_data){
5637     opaque_back = 1;
5638   }
5639 
5640   if (!opaque_back){
5641     bkrd_is_gradient = 0;
5642   }
5643   if (bkrd_is_gradient){
5644     bkrd_ptr = ColorGet(I->G, SettingGet_color(I->G, NULL, NULL, cSetting_bg_rgb_top));
5645     copy3f(bkrd_ptr, bkrd_top);
5646     bkrd_ptr = ColorGet(I->G, SettingGet_color(I->G, NULL, NULL, cSetting_bg_rgb_bottom));
5647     copy3f(bkrd_ptr, bkrd_bottom);
5648   } else {
5649     bkrd_ptr = ColorGet(I->G, SettingGet_color(I->G, NULL, NULL, cSetting_bg_rgb));
5650     copy3f(bkrd_ptr, bkrd_top);
5651     copy3f(bkrd_ptr, bkrd_bottom);
5652   }
5653   {                             /* adjust bkrd and trace to offset the effect of gamma correction */
5654     float gamma = SettingGetGlobal_f(I->G, cSetting_gamma);
5655     float inp;
5656     float sig;
5657     inp = (bkrd_top[0] + bkrd_top[1] + bkrd_top[2]) / 3.0F;
5658     if(inp < R_SMALL4)
5659       sig = 1.0F;
5660     else
5661       sig = (float) (pow(inp, gamma)) / inp;
5662     bkrd_top[0] *= sig;
5663     bkrd_top[1] *= sig;
5664     bkrd_top[2] *= sig;
5665     if(bkrd_top[0] > 1.0F)
5666       bkrd_top[0] = 1.0F;
5667     if(bkrd_top[1] > 1.0F)
5668       bkrd_top[1] = 1.0F;
5669     if(bkrd_top[2] > 1.0F)
5670       bkrd_top[2] = 1.0F;
5671 
5672     if (bkrd_is_gradient) {
5673       float inp;
5674       float sig;
5675       inp = (bkrd_bottom[0] + bkrd_bottom[1] + bkrd_bottom[2]) / 3.0F;
5676       if(inp < R_SMALL4)
5677         sig = 1.0F;
5678       else
5679         sig = (float) (pow(inp, gamma)) / inp;
5680       bkrd_bottom[0] *= sig;
5681       bkrd_bottom[1] *= sig;
5682       bkrd_bottom[2] *= sig;
5683       if(bkrd_bottom[0] > 1.0F)
5684         bkrd_bottom[0] = 1.0F;
5685       if(bkrd_bottom[1] > 1.0F)
5686         bkrd_bottom[1] = 1.0F;
5687       if(bkrd_bottom[2] > 1.0F)
5688         bkrd_bottom[2] = 1.0F;
5689     } else {
5690       copy3f(bkrd_top, bkrd_bottom);
5691     }
5692     if(ray_trace_mode) {
5693       float inp;
5694       float sig;
5695       int trace_color = SettingGetGlobal_color(I->G, cSetting_ray_trace_color);
5696       float trgb[3];
5697       const float *trgb_v = ColorGet(I->G, trace_color);
5698 
5699       copy3f(trgb_v, trgb);
5700       inp = (trgb[0] + trgb[1] + trgb[2]) / 3.0F;
5701       if(inp < R_SMALL4)
5702         sig = 1.0F;
5703       else
5704         sig = (float) (pow(inp, gamma)) / inp;
5705       trgb[0] *= sig;
5706       trgb[1] *= sig;
5707       trgb[2] *= sig;
5708       if(trgb[0] > 1.0F)
5709         trgb[0] = 1.0F;
5710       if(trgb[1] > 1.0F)
5711         trgb[1] = 1.0F;
5712       if(trgb[2] > 1.0F)
5713         trgb[2] = 1.0F;
5714 
5715       if(I->BigEndian) {
5716         trace_word =
5717           ((0xFF & ((unsigned int) (trgb[0] * 255 + _p499))) << 24) |
5718           ((0xFF & ((unsigned int) (trgb[1] * 255 + _p499))) << 16) |
5719           ((0xFF & ((unsigned int) (trgb[2] * 255 + _p499))) << 8) | 0xFF;
5720       } else {
5721         trace_word =
5722           0xFF000000 |
5723           ((0xFF & ((unsigned int) (trgb[2] * 255 + _p499))) << 16) |
5724           ((0xFF & ((unsigned int) (trgb[1] * 255 + _p499))) << 8) |
5725           ((0xFF & ((unsigned int) (trgb[0] * 255 + _p499))));
5726       }
5727     }
5728   }
5729   if(opaque_back) {
5730     if(I->BigEndian)
5731       back_mask = 0x000000FF;
5732     else
5733       back_mask = 0xFF000000;
5734     fore_mask = back_mask;
5735   } else {
5736     back_mask = 0x00000000;
5737   }
5738   if (!bkrd_is_gradient) {
5739     if(I->BigEndian) {
5740       background = back_mask |
5741 	((0xFF & ((unsigned int) (bkrd_top[0] * 255 + _p499))) << 24) |
5742 	((0xFF & ((unsigned int) (bkrd_top[1] * 255 + _p499))) << 16) |
5743 	((0xFF & ((unsigned int) (bkrd_top[2] * 255 + _p499))) << 8);
5744     } else {
5745       background = back_mask |
5746 	((0xFF & ((unsigned int) (bkrd_top[2] * 255 + _p499))) << 16) |
5747 	((0xFF & ((unsigned int) (bkrd_top[1] * 255 + _p499))) << 8) |
5748 	((0xFF & ((unsigned int) (bkrd_top[0] * 255 + _p499))));
5749     }
5750   } else {
5751     background = back_mask;
5752   }
5753   OrthoBusyFast(I->G, 2, 20);
5754 
5755   if (!bkrd_is_gradient) {
5756     PRINTFB(I->G, FB_Ray, FB_Blather)
5757       " RayNew: Background = %x %d %d %d\n", background, (int) (bkrd_top[0] * 255),
5758       (int) (bkrd_top[1] * 255), (int) (bkrd_top[2] * 255)
5759       ENDFB(I->G);
5760   }
5761   if(return_bg)
5762     *return_bg = background;
5763 
5764   if(!I->NPrimitive) {          /* nothing to render! */
5765     if (I->bkgrd_data){
5766       fill_background_image(I, image, width, height, width * (unsigned int) height);
5767     } else if (bkrd_is_gradient) {
5768       fill_gradient(I, opaque_back, image, bkrd_top, bkrd_bottom, width, height, width * (unsigned int) height);
5769     } else {
5770       fill(image, background, width * (unsigned int) height);
5771     }
5772   } else {
5773 
5774     if(I->PrimSizeCnt) {
5775       float factor = SettingGetGlobal_f(I->G, cSetting_ray_hint_camera);
5776       I->PrimSize = I->PrimSize / (I->PrimSizeCnt * factor);
5777       /*      printf("avg dist %8.7f\n",I->PrimSize); */
5778     } else {
5779       I->PrimSize = 0.0F;
5780     }
5781     ok &= !I->G->Interrupt;
5782     if (ok)
5783       ok &= RayExpandPrimitives(I);
5784     if (ok)
5785       ok &= RayTransformFirst(I, perspective, false);
5786 
5787     OrthoBusyFast(I->G, 3, 20);
5788 
5789     now = UtilGetSeconds(I->G) - timing;
5790 
5791     PRINTFB(I->G, FB_Ray, FB_Blather)
5792       " Ray: processed %i graphics primitives in %4.2f sec.\n", I->NPrimitive, now
5793       ENDFB(I->G);
5794 
5795     if (ok) {                           /* light sources */
5796       int bc;
5797       I->NBasis = n_light + 1;
5798       if(I->NBasis > MAX_BASIS)
5799 	I->NBasis = MAX_BASIS;
5800       if(I->NBasis < 2)
5801 	I->NBasis = 2;
5802       for(bc = 2; ok && bc < I->NBasis; bc++) {
5803         ok &= BasisInit(I->G, I->Basis + bc, bc);
5804       }
5805       for(bc = 2; ok && bc < I->NBasis; bc++) {
5806         {                       /* setup light & rotate if necessary  */
5807           float light[3];
5808           const float *lightv;
5809           switch (bc) {
5810           default:
5811           case 2:
5812             lightv = SettingGetfv(I->G, cSetting_light);
5813             break;
5814           case 3:
5815             lightv = SettingGetfv(I->G, cSetting_light2);
5816             break;
5817           case 4:
5818             lightv = SettingGetfv(I->G, cSetting_light3);
5819             break;
5820           case 5:
5821             lightv = SettingGetfv(I->G, cSetting_light4);
5822             break;
5823           case 6:
5824             lightv = SettingGetfv(I->G, cSetting_light5);
5825             break;
5826           case 7:
5827             lightv = SettingGetfv(I->G, cSetting_light6);
5828             break;
5829           case 8:
5830             lightv = SettingGetfv(I->G, cSetting_light7);
5831             break;
5832           case 9:
5833             lightv = SettingGetfv(I->G, cSetting_light8);
5834             break;
5835           case 10:
5836             lightv = SettingGetfv(I->G, cSetting_light9);
5837             break;
5838           }
5839           copy3f(lightv, light);
5840           normalize3f(light);
5841 
5842           if(angle) {
5843             float temp[16];
5844             identity44f(temp);
5845             MatrixRotateC44f(temp, (float) -PI * angle / 180, 0.0F, 1.0F, 0.0F);
5846             MatrixTransformC44fAs33f3f(temp, light, light);
5847           }
5848 
5849           I->Basis[bc].LightNormal[0] = light[0];
5850           I->Basis[bc].LightNormal[1] = light[1];
5851           I->Basis[bc].LightNormal[2] = light[2];
5852           normalize3f(I->Basis[bc].LightNormal);
5853 
5854           {
5855             float spec_vector[3];
5856             copy3f(I->Basis[bc].LightNormal, spec_vector);
5857             spec_vector[2]--;
5858             normalize3f(spec_vector);
5859             copy3f(spec_vector, I->Basis[bc].SpecNormal);
5860           }
5861         }
5862 
5863         if(ok && shadows) {           /* don't waste time on shadows unless needed */
5864           BasisSetupMatrix(I->Basis + bc);
5865           ok &= RayTransformBasis(I, I->Basis + bc, bc);
5866         }
5867 	ok &= !I->G->Interrupt;
5868       }
5869     }
5870 
5871     OrthoBusyFast(I->G, 4, 20);
5872 #ifndef _PYMOL_NOPY
5873     if(shadows && (n_thread > 1)) {     /* parallel execution */
5874 
5875       CRayHashThreadInfo *thread_info = pymol::calloc<CRayHashThreadInfo>(I->NBasis);
5876 
5877       /* rendering map */
5878 
5879       thread_info[0].basis = I->Basis + 1;
5880       thread_info[0].vert2prim = I->Vert2Prim;
5881       thread_info[0].prim = I->Primitive;
5882       thread_info[0].n_prim = I->NPrimitive;
5883       thread_info[0].clipBox = I->Volume;
5884       thread_info[0].phase = 0;
5885       thread_info[0].perspective = perspective;
5886       thread_info[0].front = front;
5887 
5888       thread_info[0].image = image;
5889       thread_info[0].bkrd_is_gradient = bkrd_is_gradient;
5890       thread_info[0].width = width;
5891       thread_info[0].height = height;
5892       if (I->bkgrd_data){
5893 	thread_info[0].background = background;
5894 	thread_info[0].opaque_back = opaque_back;
5895       } else if (bkrd_is_gradient){
5896 	thread_info[0].bkrd_top = bkrd_top;
5897 	thread_info[0].bkrd_bottom = bkrd_bottom;
5898 	thread_info[0].opaque_back = opaque_back;
5899       } else {
5900 	thread_info[0].background = background;
5901       }
5902       thread_info[0].bytes = width * (unsigned int) height;
5903       thread_info[0].ray = I;   /* for compute box */
5904       thread_info[0].size_hint = I->PrimSize;
5905       /* shadow map */
5906 
5907       {
5908         int bc;
5909         float factor = SettingGetGlobal_f(I->G, cSetting_ray_hint_shadow);
5910         for(bc = 2; bc < I->NBasis; bc++) {
5911           thread_info[bc - 1].basis = I->Basis + bc;
5912           thread_info[bc - 1].vert2prim = I->Vert2Prim;
5913           thread_info[bc - 1].prim = I->Primitive;
5914           thread_info[bc - 1].n_prim = I->NPrimitive;
5915           thread_info[bc - 1].clipBox = NULL;
5916           thread_info[bc - 1].phase = bc - 1;
5917           thread_info[bc - 1].perspective = false;
5918           thread_info[bc - 1].front = _0;
5919           /* allowing these maps to be more fine helps performance */
5920           thread_info[bc - 1].size_hint = I->PrimSize * factor;
5921         }
5922       }
5923 
5924       /* NOTE that we're not limiting the number of threads in this phase
5925          under the assumption that it will usually just be a few threads */
5926       RayHashSpawn(thread_info, n_thread, I->NBasis - 1);
5927 
5928       FreeP(thread_info);
5929     } else
5930 #endif
5931     if (ok){
5932 #ifdef _PYMOL_NOPY
5933       n_thread = 1;          /* serial execution */
5934 #endif
5935       ok &= BasisMakeMap(I->Basis + 1, I->Vert2Prim, I->Primitive, I->NPrimitive,
5936 			 I->Volume, 0, cCache_ray_map, perspective, front, I->PrimSize);
5937       if(ok && shadows) {
5938         int bc;
5939         float factor = SettingGetGlobal_f(I->G, cSetting_ray_hint_shadow);
5940         for(bc = 2; ok && bc < I->NBasis; bc++) {
5941           ok &= BasisMakeMap(I->Basis + bc, I->Vert2Prim, I->Primitive, I->NPrimitive,
5942 			     NULL, bc - 1, cCache_ray_map, false, _0, I->PrimSize * factor);
5943         }
5944       }
5945 
5946       /* serial tasks which RayHashThread does in parallel mode using the first thread */
5947 
5948       if (ok){
5949 	if (I->bkgrd_data){
5950 	  fill_background_image(I, image,  width, height, width * (unsigned int) height);
5951 	} else if (bkrd_is_gradient) {
5952 	  fill_gradient(I, opaque_back, image, bkrd_top, bkrd_bottom, width, height, width * (unsigned int) height);
5953 	} else {
5954 	  fill(image, background, width * (unsigned int) height);
5955 	}
5956 	RayComputeBox(I);
5957 
5958       }
5959     }
5960 
5961     OrthoBusyFast(I->G, 5, 20);
5962     now = UtilGetSeconds(I->G) - timing;
5963 
5964     if (ok){
5965       if(shadows) {
5966 	PRINTFB(I->G, FB_Ray, FB_Blather)
5967 	  " Ray: voxels: [%4.2f:%dx%dx%d], [%4.2f:%dx%dx%d], %4.2f sec.\n",
5968 	  I->Basis[1].Map->Div, I->Basis[1].Map->Dim[0],
5969 	  I->Basis[1].Map->Dim[1], I->Basis[1].Map->Dim[2],
5970 	  I->Basis[2].Map->Div, I->Basis[2].Map->Dim[0],
5971 	  I->Basis[2].Map->Dim[2], I->Basis[2].Map->Dim[2], now ENDFB(I->G);
5972       } else {
5973 	PRINTFB(I->G, FB_Ray, FB_Blather)
5974 	  " Ray: voxels: [%4.2f:%dx%dx%d], %4.2f sec.\n",
5975 	  I->Basis[1].Map->Div, I->Basis[1].Map->Dim[0],
5976 	  I->Basis[1].Map->Dim[1], I->Basis[1].Map->Dim[2], now ENDFB(I->G);
5977       }
5978     }
5979     /* IMAGING */
5980 
5981     if (ok){
5982       /* now spawn threads as needed */
5983       CRayThreadInfo *rt = pymol::calloc<CRayThreadInfo>(n_thread);
5984 
5985       int x_start = 0, y_start = 0;
5986       int x_stop = 0, y_stop = 0;
5987       float x_test = _0, y_test = _0;
5988       int x_pixel, y_pixel;
5989 
5990       if(perspective) {
5991         int c;
5992 
5993         if(I->min_box[2] > -front)
5994           I->min_box[2] = -front;
5995         if(I->max_box[2] > -front)
5996           I->max_box[2] = -front;
5997 
5998         for(c = 0; c < 4; c++) {
5999           switch (c) {
6000           case 0:
6001             x_test = -I->min_box[0] / I->min_box[2];
6002             y_test = -I->min_box[1] / I->min_box[2];
6003             break;
6004           case 1:
6005             x_test = -I->min_box[0] / I->max_box[2];
6006             y_test = -I->min_box[1] / I->max_box[2];
6007             break;
6008           case 2:
6009             x_test = -I->max_box[0] / I->min_box[2];
6010             y_test = -I->max_box[1] / I->min_box[2];
6011             break;
6012           case 3:
6013             x_test = -I->max_box[0] / I->max_box[2];
6014             y_test = -I->max_box[1] / I->max_box[2];
6015             break;
6016           }
6017 
6018           /* project onto back to get the effective range */
6019 
6020           x_pixel =
6021             (int) (width * (((x_test * I->Volume[5]) - I->Volume[0]) / I->Range[0]));
6022           y_pixel =
6023             (int) (height * (((y_test * I->Volume[5]) - I->Volume[2]) / I->Range[1]));
6024 
6025           if(!c) {
6026             x_start = x_pixel;
6027             x_stop = x_pixel;
6028             y_start = y_pixel;
6029             y_stop = y_pixel;
6030           } else {
6031             if(x_start > x_pixel)
6032               x_start = x_pixel;
6033             if(x_stop < x_pixel)
6034               x_stop = x_pixel;
6035             if(y_start > y_pixel)
6036               y_start = y_pixel;
6037             if(y_stop < y_pixel)
6038               y_stop = y_pixel;
6039           }
6040         }
6041         x_start -= 2;
6042         x_stop += 2;
6043         y_start -= 2;
6044         y_stop += 2;
6045 
6046         /*
6047            x_start = 0;
6048            y_start = 0;
6049            x_stop = width;
6050            y_stop = height; */
6051 
6052       } else {
6053         x_start = (int) ((width * (I->min_box[0] - I->Volume[0])) / I->Range[0]) - 2;
6054         x_stop = (int) ((width * (I->max_box[0] - I->Volume[0])) / I->Range[0]) + 2;
6055 
6056         y_stop = (int) ((height * (I->max_box[1] - I->Volume[2])) / I->Range[1]) + 2;
6057         y_start = (int) ((height * (I->min_box[1] - I->Volume[2])) / I->Range[1]) - 2;
6058 
6059       }
6060       if(x_start < 0)
6061         x_start = 0;
6062       if(y_start < 0)
6063         y_start = 0;
6064       if(x_stop > width)
6065         x_stop = width;
6066       if(y_stop > height)
6067         y_stop = height;
6068 
6069       for(a = 0; a < n_thread; a++) {
6070         rt[a].ray = I;
6071         rt[a].width = width;
6072         rt[a].height = height;
6073         rt[a].x_start = x_start;
6074         rt[a].x_stop = x_stop;
6075         rt[a].y_start = y_start;
6076         rt[a].y_stop = y_stop;
6077         rt[a].image = image;
6078         rt[a].border = mag - 1;
6079         rt[a].front = front;
6080         rt[a].back = back;
6081         rt[a].fore_mask = fore_mask;
6082 	rt[a].bkrd_is_gradient = bkrd_is_gradient;
6083 	if (bkrd_is_gradient){
6084 	  rt[a].bkrd_top = bkrd_top;
6085 	  rt[a].bkrd_bottom = bkrd_bottom;
6086 	} else {
6087 	  rt[a].bkrd_top = bkrd_top;
6088 	  rt[a].bkrd_bottom = bkrd_top;
6089 	}
6090         rt[a].ambient = ambient;
6091         rt[a].background = background;
6092         rt[a].phase = a;
6093         rt[a].n_thread = n_thread;
6094         rt[a].edging = NULL;
6095         rt[a].edging_cutoff = oversample_cutoff;        /* info needed for busy indicator */
6096         rt[a].perspective = perspective;
6097         rt[a].fov = fov;
6098         rt[a].pos[2] = pos[2];
6099         rt[a].depth = depth;
6100         if (I->bkgrd_data) {
6101           rt[a].bgWidth = I->bkgrd_data->getWidth();
6102           rt[a].bgHeight = I->bkgrd_data->getHeight();
6103         }
6104         rt[a].bkrd_data = I->bkgrd_data ? I->bkgrd_data->bits() : nullptr;
6105       }
6106 
6107 #ifndef _PYMOL_NOPY
6108       if(n_thread > 1)
6109         RayTraceSpawn(rt, n_thread);
6110       else
6111 #endif
6112         RayTraceThread(rt);
6113 
6114       if(oversample_cutoff) {   /* perform edge oversampling, if requested */
6115         unsigned int *edging;
6116 
6117         edging = CacheAlloc(I->G, unsigned int, buffer_size, 0, cCache_ray_edging_buffer);
6118 
6119         memcpy(edging, image, buffer_size * sizeof(unsigned int));
6120 
6121         for(a = 0; a < n_thread; a++) {
6122           rt[a].edging = edging;
6123         }
6124 
6125 #ifndef _PYMOL_NOPY
6126         if(n_thread > 1)
6127           RayTraceSpawn(rt, n_thread);
6128         else
6129 #endif
6130           RayTraceThread(rt);
6131 
6132         CacheFreeP(I->G, edging, 0, cCache_ray_edging_buffer, false);
6133       }
6134       FreeP(rt);
6135     }
6136   }
6137 
6138   if(ok && depth && ray_trace_mode) {
6139     float *delta = pymol::malloc<float>(3 * width * height);
6140     int x, y;
6141     ErrChkPtr(I->G, delta);
6142     if (ok) {
6143       int xc, yc;
6144       float d, dzdx, dzdy, *p, *q, dd;
6145       p = depth;
6146       q = delta;
6147       for(y = 0; y < height; y++)
6148         for(x = 0; x < width; x++) {
6149           dzdx = 0.0F;
6150           dzdy = 0.0F;
6151           xc = 0;
6152           yc = 0;
6153           d = *p;
6154           if(x) {
6155             dd = d - p[-1];
6156             dzdx += dd;
6157             xc++;
6158           }
6159           if(x < (width - 1)) {
6160             dd = p[1] - d;
6161             if((!xc) || (fabs(dd) > fabs(dzdx)))
6162               dzdx = dd;
6163             xc = 1;
6164           }
6165           if(y) {
6166             dd = d - p[-width];
6167             dzdy += dd;
6168             yc++;
6169           }
6170           if(y < (height - 1)) {
6171             dd = p[width] - d;
6172             if((!yc) || (fabs(dd) > fabs(dzdy)))
6173               dzdy = dd;
6174             yc = 1;
6175           }
6176           p++;
6177           *(q++) = dzdx;
6178           *(q++) = dzdy;
6179           /*
6180              if(((x == y )||(x==width/2)||(y==height/2))&&((dzdx!=0.0F) || (dzdy!=0.0F))) {
6181              printf("%5d %5d : %8.3f %8.3f\n",y,x,dzdx,dzdy);
6182              } */
6183 
6184           *(q++) = sqrt1f(dzdx * dzdx + dzdy * dzdy);
6185         }
6186     }
6187 
6188     if (ok){
6189       int i;
6190       {
6191         const float _1 = 1.0F;
6192 
6193         float invFrontMinusBack = _1 / (front - back);
6194         float inv1minusFogStart = _1;
6195         int fogFlag = false;
6196         float fog_start = 0.0F;
6197         int fogRangeFlag = false;
6198         float fog = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog);
6199         if(fog < 0.0F) {
6200           if(SettingGetGlobal_b(I->G, cSetting_depth_cue)) {
6201             fog = SettingGetGlobal_f(I->G, cSetting_fog);
6202           } else
6203             fog = _0;
6204         }
6205 
6206         if(fog != _0) {
6207           if(fog > 1.0F)
6208             fog = 1.0F;
6209           fogFlag = true;
6210           fog_start = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog_start);
6211           if(fog_start < 0.0F)
6212             fog_start = SettingGetGlobal_f(I->G, cSetting_fog_start);
6213           if(fog_start > 1.0F)
6214             fog_start = 1.0F;
6215           if(fog_start < 0.0F)
6216             fog_start = 0.0F;
6217           if(fog_start > R_SMALL4) {
6218             fogRangeFlag = true;
6219             if(fabs(fog_start - 1.0F) < R_SMALL4)       /* prevent div/0 */
6220               fogFlag = false;
6221           }
6222           inv1minusFogStart = _1 / (_1 - fog_start);
6223         }
6224 
6225         if(fogFlag) {           /* make sure we have depth values at every potentially drawn pixel */
6226           float *tmp = pymol::malloc<float>(width * height);
6227           float dep;
6228           float *p, *q;
6229           int cnt;
6230           for(i = 0; i < 3; i++) {      /* three passes required */
6231             p = depth;
6232             q = tmp;
6233             for(y = 0; y < height; y++)
6234               for(x = 0; x < width; x++) {
6235                 if(fabs(*p) < R_SMALL4) {
6236                   dep = 0.0F;
6237                   cnt = 0;
6238                   if(x) {
6239                     if(fabs(p[-1]) > R_SMALL4) {
6240                       dep += p[-1];
6241                       cnt++;
6242                     }
6243                   }
6244                   if(x < (width - 1)) {
6245                     if(fabs(p[1]) > R_SMALL4) {
6246                       dep += p[1];
6247                       cnt++;
6248                     }
6249                   }
6250                   if(y) {
6251                     if(fabs(p[-width]) > R_SMALL4) {
6252                       dep += p[-width];
6253                       cnt++;
6254                     }
6255                   }
6256                   if(y < (height - 1)) {
6257                     if(fabs(p[width]) > R_SMALL4) {
6258                       dep += p[width];
6259                       cnt++;
6260                     }
6261                   }
6262                   if(cnt) {
6263                     dep /= cnt;
6264                     *q = dep;
6265                   }
6266                 } else {
6267                   *q = *p;
6268                 }
6269                 p++;
6270                 q++;
6271               }
6272             p = tmp;
6273             tmp = depth;
6274             depth = p;
6275           }
6276           FreeP(tmp);
6277         }
6278         {
6279           unsigned int *q = image;
6280           float *p = delta;
6281           int width3 = width * 3;
6282 
6283           float slope_f = SettingGetGlobal_f(I->G, cSetting_ray_trace_slope_factor);
6284           float depth_f = SettingGetGlobal_f(I->G, cSetting_ray_trace_depth_factor);
6285           float disco_f = SettingGetGlobal_f(I->G, cSetting_ray_trace_disco_factor);
6286           float diff, max_depth;
6287           float dot, min_dot, max_slope, max_dz, max_pz;
6288           float dx, dy, dz, px = 0.0F, py = 0.0F, pz = 0.0F, ddx, ddy;
6289           const float _8 = 0.08F;
6290           const float _4 = 0.4F;
6291           const float _25 = 0.25F;
6292           const float _m25 = -0.25F;
6293           float disco_f_625 = disco_f * 0.625F;
6294           float disco_f_5 = disco_f * 0.5F;
6295           float disco_f_45 = disco_f * 0.45F;
6296 
6297           {
6298             float gain =
6299               I->PixelRadius / (SettingGetGlobal_f(I->G, cSetting_ray_trace_gain) *
6300                                 I->Magnified);
6301             if(antialias)
6302               gain /= antialias;
6303             slope_f *= gain;
6304             depth_f *= gain;
6305             disco_f *= gain;
6306           }
6307           for(y = 0; y < height; y++){
6308 	    float bkrd[3], perc = 0.;
6309 	    if (bkrd_is_gradient) {
6310 	      /* for RayRender, y is from bottom to top */
6311 	      perc = y/(float)height;
6312 	      bkrd[0] = bkrd_bottom[0] + perc * (bkrd_top[0] - bkrd_bottom[0]);
6313 	      bkrd[1] = bkrd_bottom[1] + perc * (bkrd_top[1] - bkrd_bottom[1]);
6314 	      bkrd[2] = bkrd_bottom[2] + perc * (bkrd_top[2] - bkrd_bottom[2]);
6315 	      if(I->BigEndian) {
6316 		background = back_mask |
6317 		  ((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))) << 24) |
6318 		  ((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 16) |
6319 		  ((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 8);
6320 	      } else {
6321 		background = back_mask |
6322 		  ((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 16) |
6323 		  ((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 8) |
6324 		  ((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))));
6325 	      }
6326 	    }
6327             for(x = 0; x < width; x++) {
6328               max_slope = 0.0F;
6329               max_depth = 0.0F;
6330               min_dot = 1.0F;
6331               max_dz = 0.0F;
6332               max_pz = 0.0F;
6333               dx = p[0];
6334               dy = p[1];
6335               dz = p[2];
6336               for(i = 0; i < 8; i++) {
6337                 switch (i) {
6338                 case 0:
6339                   if(x) {
6340                     px = p[-3];
6341                     py = p[-2];
6342                     pz = p[-1];
6343                   }
6344                   break;
6345                 case 1:
6346                   if(x < (width - 1)) {
6347                     px = p[3];
6348                     py = p[4];
6349                     pz = p[5];
6350                   }
6351                   break;
6352                 case 2:
6353                   if(y) {
6354                     px = p[-width3];
6355                     py = p[-width3 + 1];
6356                     pz = p[-width3 + 2];
6357                   }
6358                   break;
6359                 case 3:
6360                   if(y < (height - 1)) {
6361                     px = p[width3];
6362                     py = p[width3 + 1];
6363                     pz = p[width3 + 2];
6364                   }
6365                   break;
6366                 case 4:
6367                   if(x && y) {
6368                     px = p[-width3 - 3];
6369                     py = p[-width3 - 2];
6370                     pz = p[-width3 - 1];
6371                   }
6372                   break;
6373                 case 5:
6374                   if(x && (y < (height - 1))) {
6375                     px = p[width3 - 3];
6376                     py = p[width3 - 2];
6377                     pz = p[width3 - 1];
6378                   }
6379                   break;
6380                 case 6:
6381                   if(y && (x < (width - 1))) {
6382                     px = p[-width3 + 3];
6383                     py = p[-width3 + 4];
6384                     pz = p[-width3 + 5];
6385                   }
6386                   break;
6387                 case 7:
6388                   if((y < (height - 1)) && (x < (width - 1))) {
6389                     px = p[width3 + 3];
6390                     py = p[width3 + 4];
6391                     pz = p[width3 + 5];
6392                   }
6393                   break;
6394                 }
6395                 ddx = dx - px;
6396                 ddy = dy - py;
6397                 diff = ddx * ddx + ddy * ddy;
6398                 if(max_depth < diff)
6399                   max_depth = diff;
6400                 if((dz > R_SMALL4) && (pz > R_SMALL4)) {
6401                   dot = (dx / dz) * (px / pz) + (dy / dz) * (py / pz);
6402                   if(dot < min_dot) {
6403                     min_dot = dot;
6404                     max_dz = dz;
6405                     max_pz = pz;
6406                   }
6407                 }
6408                 /*                if(dz>max_dz) max_dz = dz;
6409                    if(pz>max_pz) max_pz = pz; */
6410                 diff = fabs(dz - pz);
6411                 if(diff > max_slope)
6412                   max_slope = diff;
6413               }
6414               if((max_slope > (slope_f))        /* depth */
6415                  ||(max_depth > (depth_f))
6416                  /* slope */
6417                  /* gradient discontinuities -- could probably use more tuning... */
6418                  || ((min_dot < _8) && ((max_dz > disco_f) || (max_pz > disco_f)))
6419                  || ((min_dot < _4) && ((max_dz > disco_f_625) || (max_pz > disco_f_625)))
6420                  || ((min_dot < _25) && ((max_dz > disco_f_5) || (max_pz > disco_f_5)))
6421                  || ((min_dot < _m25) && ((max_dz > disco_f_45) && (max_pz > disco_f_45)))
6422                 ) {
6423                 if(fogFlag) {
6424 
6425                   float ffact = depth[q - image] * invFrontMinusBack;
6426                   float ffact1m;
6427                   float fc[4];
6428                   unsigned int cc0, cc1, cc2, cc3;
6429 
6430                   if(fogRangeFlag)
6431                     ffact = (ffact - fog_start) * inv1minusFogStart;
6432 
6433                   ffact *= fog;
6434 
6435                   if(ffact < _0)
6436                     ffact = _0;
6437                   if(ffact > _1)
6438                     ffact = _1;
6439 
6440                   ffact1m = _1 - ffact;
6441 
6442                   if(orig_opaque_back) {
6443                     fc[0] =
6444                       (0xFF & (background >> 24)) * ffact +
6445                       (0xFF & (trace_word >> 24)) * ffact1m;
6446                     fc[1] =
6447                       (0xFF & (background >> 16)) * ffact +
6448                       (0xFF & (trace_word >> 16)) * ffact1m;
6449                     fc[2] =
6450                       (0xFF & (background >> 8)) * ffact +
6451                       (0xFF & (trace_word >> 8)) * ffact1m;
6452                     fc[3] =
6453                       (0xFF & (background)) * ffact + (0xFF & (trace_word)) * ffact1m;
6454                   } else {      /* if non-opaque background, then use alpha to blend */
6455                     fc[1] = (0xFF & (trace_word >> 16));
6456                     fc[2] = (0xFF & (trace_word >> 8));
6457                     if(I->BigEndian) {
6458                       fc[0] = (0xFF & (trace_word >> 24));
6459                       fc[3] =
6460                         (0xFF & (background)) * ffact + (0xFF & (trace_word)) * ffact1m;
6461                     } else {
6462                       fc[0] =
6463                         (0xFF & (background >> 24)) * ffact +
6464                         (0xFF & (trace_word >> 24)) * ffact1m;
6465                       fc[3] = (0xFF & (trace_word));
6466                     }
6467                   }
6468                   cc0 = (uint) (fc[0]);
6469                   cc1 = (uint) (fc[1]);
6470                   cc2 = (uint) (fc[2]);
6471                   cc3 = (uint) (fc[3]);
6472 
6473                   if(cc0 > 255)
6474                     cc0 = 255;
6475                   if(cc1 > 255)
6476                     cc1 = 255;
6477                   if(cc2 > 255)
6478                     cc2 = 255;
6479                   if(cc3 > 255)
6480                     cc3 = 255;
6481 
6482                   *q = (cc0 << 24) | (cc1 << 16) | (cc2 << 8) | cc3;
6483                 } else {
6484                   *q = trace_word;
6485                 }
6486               } else if(ray_trace_mode == 2) {      /* only draw edge */
6487                 *q = background;
6488               } else if(ray_trace_mode == 3) {      /* quantize */
6489                 *q = (*q & 0xC0C0C0C0);
6490                 *q = *q | ((*q) >> 2) | ((*q) >> 4) | ((*q) >> 6);
6491               }
6492               p += 3;
6493               q++;
6494             }
6495 	  }
6496         }
6497       }
6498     }
6499     FreeP(delta);
6500   }
6501 
6502   if(ok && antialias > 1) {
6503     /* now spawn threads as needed */
6504     CRayAntiThreadInfo *rt = pymol::calloc<CRayAntiThreadInfo>(n_thread);
6505 
6506     for(a = 0; a < n_thread; a++) {
6507       rt[a].width = width;
6508       rt[a].height = height;
6509       rt[a].image = image;
6510       rt[a].image_copy = image_copy;
6511       rt[a].phase = a;
6512       rt[a].mag = mag;          /* fold magnification */
6513       rt[a].n_thread = n_thread;
6514       rt[a].ray = I;
6515     }
6516 
6517 #ifndef _PYMOL_NOPY
6518     if(n_thread > 1)
6519       RayAntiSpawn(rt, n_thread);
6520     else
6521 #endif
6522       RayAntiThread(rt);
6523     FreeP(rt);
6524     CacheFreeP(I->G, image, 0, cCache_ray_antialias_buffer, false);
6525     image = image_copy;
6526   }
6527 
6528   PRINTFD(I->G, FB_Ray)
6529     " RayRender: n_hit %d\n", n_hit ENDFD;
6530 #ifdef PROFILE_BASIS
6531 
6532   printf
6533     ("int n_cells = %d;\nint n_prims = %d;\nint n_triangles = %8.3f;\nint n_spheres = %8.3f;\nint n_cylinders = %8.3f;\nint n_sausages = %8.3f;\nint n_skipped = %8.3f;\n",
6534      n_cells, n_prims, n_triangles / ((float) n_cells), n_spheres / ((float) n_cells),
6535      n_cylinders / ((float) n_cells), n_sausages / ((float) n_cells),
6536      n_skipped / ((float) n_cells));
6537 #endif
6538 
6539   if (ok){
6540     /* EXPERIMENTAL RAY-VOLUME CODE */
6541     volume = SettingGetGlobal_b(I->G, cSetting_ray_volume);
6542 
6543     if (volume) {
6544       for(y = 0; y < height; y++) {
6545 	for(x = 0; x < width; x++) {
6546 	  float dd = depth[x+width*y];
6547 	  if (dd == 0.0) dd = -back;
6548 	  depth[x+width*y] = -dd/(back-front) + 0.1;
6549 	}
6550       }
6551       if (rayDepthPixels)
6552 	FreeP(rayDepthPixels);
6553       rayDepthPixels = depth;
6554       rayWidth = width;
6555       rayHeight = height;
6556       rayVolume = 3;
6557     } else
6558       FreeP(depth);
6559   }
6560   I->bkgrd_data = nullptr;
6561 }
6562 
6563 
RayRenderColorTable(CRay * I,int width,int height,int * image)6564 void RayRenderColorTable(CRay * I, int width, int height, int *image)
6565 {
6566   int x, y;
6567   unsigned int r = 0, g = 0, b = 0;
6568   unsigned int *pixel, mask, *p;
6569 
6570   if(I->BigEndian)
6571     mask = 0x000000FF;
6572   else
6573     mask = 0xFF000000;
6574 
6575   p = (unsigned int *) image;
6576   for(x = 0; x < width; x++)
6577     for(y = 0; y < height; y++)
6578       *(p++) = mask;
6579 
6580   if((width >= 512) && (height >= 512)) {
6581 
6582     for(y = 0; y < 512; y++)
6583       for(x = 0; x < 512; x++) {
6584         pixel = (unsigned int *) (image + ((width) * y) + x);
6585         if(I->BigEndian) {
6586           *(pixel) = mask | (r << 24) | (g << 16) | (b << 8);
6587         } else {
6588           *(pixel) = mask | (b << 16) | (g << 8) | r;
6589         }
6590         b = b + 4;
6591         if(!(0xFF & b)) {
6592           b = 0;
6593           g = g + 4;
6594           if(!(0xFF & g)) {
6595             g = 0;
6596             r = r + 4;
6597           }
6598         }
6599       }
6600   }
6601 }
6602 
6603 
6604 /*========================================================================*/
wobble(int mode,const float * v)6605 void CRay::wobble(int mode, const float *v)
6606 {
6607   CRay * I = this;
6608   I->Wobble = mode;
6609   if(v)
6610     copy3f(v, I->WobbleParam);
6611 }
6612 
6613 
6614 /*========================================================================*/
transparentf(float v)6615 void CRay::transparentf(float v)
6616 {
6617   CRay * I = this;
6618   if(v > 1.0F)
6619     v = 1.0F;
6620   if(v < 0.0F)
6621     v = 0.0F;
6622   I->Trans = v;
6623 }
6624 
interiorColor3fv(const float * v,int passive)6625 void CRay::interiorColor3fv(const float *v, int passive)
6626 {
6627   CRay * I = this;
6628   I->IntColor[0] = (*v++);
6629   I->IntColor[1] = (*v++);
6630   I->IntColor[2] = (*v++);
6631   if(!passive)
6632     I->CheckInterior = true;
6633 }
6634 
6635 
6636 /*========================================================================*/
color3fv(const float * v)6637 void CRay::color3fv(const float *v)
6638 {
6639   CRay * I = this;
6640   I->CurColor[0] = (*v++);
6641   I->CurColor[1] = (*v++);
6642   I->CurColor[2] = (*v++);
6643 }
6644 
6645 
6646 /*========================================================================*/
sphere3fv(const float * v,float r)6647 int CRay::sphere3fv(const float *v, float r)
6648 {
6649   CRay * I = this;
6650   CPrimitive *p;
6651   int ok = true;
6652   float *vv;
6653 
6654   VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
6655   CHECKOK(ok, I->Primitive);
6656   if (!ok)
6657     return false;
6658   p = I->Primitive + I->NPrimitive;
6659 
6660   p->type = cPrimSphere;
6661   p->r1 = r;
6662   p->trans = I->Trans;
6663   p->wobble = I->Wobble;
6664   p->ramped = (I->CurColor[0] < 0.0F);
6665   p->no_lighting = 0;
6666 
6667   I->PrimSize += 2 * r;
6668   I->PrimSizeCnt++;
6669 
6670   /*
6671      copy3f(I->WobbleParam,p->wobble_param); */
6672   vv = p->v1;
6673   (*vv++) = (*v++);
6674   (*vv++) = (*v++);
6675   (*vv++) = (*v++);
6676 
6677   vv = p->c1;
6678   v = I->CurColor;
6679   (*vv++) = (*v++);
6680   (*vv++) = (*v++);
6681   (*vv++) = (*v++);
6682 
6683   vv = p->ic;
6684   v = I->IntColor;
6685   (*vv++) = (*v++);
6686   (*vv++) = (*v++);
6687   (*vv++) = (*v++);
6688 
6689   if(I->TTTFlag) {
6690     p->r1 *= length3f(I->TTT);
6691     transformTTT44f3f(I->TTT, p->v1, p->v1);
6692   }
6693 
6694   if(I->Context) {
6695     RayApplyContextToVertex(I, p->v1);
6696   }
6697 
6698   I->NPrimitive++;
6699   return true;
6700 }
6701 
RayGetScaledAxes(CRay * I,float * xn,float * yn)6702 void RayGetScaledAxes(CRay * I, float *xn, float *yn)
6703 {
6704   float *v;
6705   float vt[3];
6706   float xn0[3] = { 1.0F, 0.0F, 0.0F };
6707   float yn0[3] = { 0.0F, 1.0F, 0.0F };
6708   float v_scale;
6709 
6710   v = TextGetPos(I->G);
6711 
6712   if(I->TTTFlag) {
6713     transformTTT44f3f(I->TTT, v, vt);
6714   } else {
6715     copy3f(v, vt);
6716   }
6717 
6718   v_scale = RayGetScreenVertexScale(I, vt) / I->Sampling;
6719 
6720   RayApplyMatrixInverse33(1, (float3 *) xn0, I->Rotation, (float3 *) xn0);
6721   RayApplyMatrixInverse33(1, (float3 *) yn0, I->Rotation, (float3 *) yn0);
6722 
6723   scale3f(xn0, v_scale, xn);
6724   scale3f(yn0, v_scale, yn);
6725 }
6726 
6727 
6728 /*========================================================================*/
character(int char_id)6729 int CRay::character(int char_id)
6730 {
6731   CRay * I = this;
6732   CPrimitive *p;
6733   float *v;
6734   float vt[3];
6735   float *vv;
6736   float width, height;
6737   float v_scale;
6738   int ok = true;
6739 
6740   v = TextGetPos(I->G);
6741   VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive + 1, 0,
6742                 cCache_ray_primitive);
6743   CHECKOK(ok, I->Primitive);
6744   if (!ok)
6745     return false;
6746   p = I->Primitive + I->NPrimitive;
6747 
6748   p->type = cPrimCharacter;
6749   p->trans = I->Trans;
6750   p->char_id = char_id;
6751   p->wobble = I->Wobble;
6752   p->ramped = 0;
6753   p->no_lighting = 0;
6754   /*
6755      copy3f(I->WobbleParam,p->wobble_param); */
6756 
6757   vv = p->v1;
6758   (*vv++) = v[0];
6759   (*vv++) = v[1];
6760   (*vv++) = v[2];
6761 
6762   if(I->TTTFlag) {
6763     transformTTT44f3f(I->TTT, p->v1, p->v1);
6764   }
6765   /* what's the width of 1 screen window pixel at this point in space? */
6766 
6767   v_scale = RayGetScreenVertexScale(I, p->v1) / I->Sampling;
6768 
6769   if(I->Context) {
6770     RayApplyContextToVertex(I, p->v1);
6771   }
6772 
6773   {
6774     float xn[3] = { 1.0F, 0.0F, 0.0F };
6775     float yn[3] = { 0.0F, 1.0F, 0.0F };
6776     float zn[3] = { 0.0F, 0.0F, 1.0F };
6777     float sc[3];
6778     float scale;
6779     float xorig, yorig, advance;
6780     int width_i, height_i;
6781     CPrimitive *pp = p + 1;
6782 
6783     RayApplyMatrixInverse33(1, (float3 *) xn, I->Rotation, (float3 *) xn);
6784     RayApplyMatrixInverse33(1, (float3 *) yn, I->Rotation, (float3 *) yn);
6785     RayApplyMatrixInverse33(1, (float3 *) zn, I->Rotation, (float3 *) zn);
6786 
6787     CharacterGetGeometry(I->G, char_id, &width_i, &height_i, &xorig, &yorig, &advance);
6788     width = (float) width_i;
6789     height = (float) height_i;
6790 
6791     scale = v_scale * advance;
6792     scale3f(xn, scale, vt);     /* advance raster position in 3-space */
6793     add3f(v, vt, vt);
6794     TextSetPos(I->G, vt);
6795 
6796     /* position the pixmap relative to raster position */
6797 
6798     /*    scale = ((-xorig)-0.5F)*I->PixelRadius; */
6799     scale = ((-xorig) - 0.0F) * v_scale;
6800     scale3f(xn, scale, sc);
6801     add3f(sc, p->v1, p->v1);
6802 
6803     scale = ((-yorig) - 0.0F) * v_scale;
6804     scale3f(yn, scale, sc);
6805     add3f(sc, p->v1, p->v1);
6806 
6807     scale = v_scale * width;
6808     scale3f(xn, scale, xn);
6809     scale = v_scale * height;
6810     scale3f(yn, scale, yn);
6811 
6812     copy3f(zn, p->n0);
6813     copy3f(zn, p->n1);
6814     copy3f(zn, p->n2);
6815     copy3f(zn, p->n3);
6816 
6817     *(pp) = (*p);
6818 
6819     /* define coordinates of first triangle */
6820 
6821     add3f(p->v1, xn, p->v2);
6822     add3f(p->v1, yn, p->v3);
6823 
6824     I->PrimSize +=
6825       2 * (diff3f(p->v1, p->v2) + diff3f(p->v1, p->v3) + diff3f(p->v2, p->v3));
6826     I->PrimSizeCnt += 6;
6827 
6828     /* encode characters coordinates in the colors  */
6829 
6830     zero3f(p->c1);
6831     set3f(p->c2, width, 0.0F, 0.0F);
6832     set3f(p->c3, 0.0F, height, 0.0F);
6833 
6834     /* define coordinates of second triangle */
6835 
6836     add3f(yn, xn, pp->v1);
6837     add3f(p->v1, pp->v1, pp->v1);
6838     add3f(p->v1, yn, pp->v2);
6839     add3f(p->v1, xn, pp->v3);
6840 
6841     {
6842       float *v, *vv;
6843       vv = p->ic;
6844       v = I->IntColor;
6845       (*vv++) = (*v++);
6846       (*vv++) = (*v++);
6847       (*vv++) = (*v++);
6848       vv = pp->ic;
6849       v = I->IntColor;
6850       (*vv++) = (*v++);
6851       (*vv++) = (*v++);
6852       (*vv++) = (*v++);
6853     }
6854 
6855     /* encode integral character coordinates into the vertex colors  */
6856 
6857     set3f(pp->c1, width, height, 0.0F);
6858     set3f(pp->c2, 0.0F, height, 0.0F);
6859     set3f(pp->c3, width, 0.0F, 0.0F);
6860 
6861   }
6862 
6863   I->NPrimitive += 2;
6864   return true;
6865 }
6866 
6867 
6868 /*========================================================================*/
cylinder3fv(const cgo::draw::cylinder & cyl)6869 int CRay::cylinder3fv(const cgo::draw::cylinder &cyl){
6870   return cylinder3fv(cyl.vertex1, cyl.vertex2, cyl.radius, cyl.color1, cyl.color2, 1.0f - Trans, 1.0f - Trans);
6871 }
cylinder3fv(const cgo::draw::cylinder & cyl,const float alpha1,const float alpha2)6872 int CRay::cylinder3fv(const cgo::draw::cylinder &cyl, const float alpha1, const float alpha2){
6873   return cylinder3fv(cyl.vertex1, cyl.vertex2, cyl.radius, cyl.color1, cyl.color2, alpha1, alpha2);
6874 }
6875 
cylinder3fv(const float * v1,const float * v2,float r,const float * c1,const float * c2,const float alpha1,const float alpha2)6876 int CRay::cylinder3fv(const float *v1, const float *v2, float r, const float *c1, const float *c2,
6877                       const float alpha1, const float alpha2)
6878 {
6879   CRay * I = this;
6880   CPrimitive *p;
6881   int ok = true;
6882   float *vv;
6883 
6884   VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
6885   CHECKOK(ok, I->Primitive);
6886   if (!ok)
6887     return false;
6888   p = I->Primitive + I->NPrimitive;
6889 
6890   p->type = cPrimCylinder;
6891   p->r1 = r;
6892   p->cap1 = cCylCapFlat;
6893   p->cap2 = cCylCapFlat;
6894   p->wobble = I->Wobble;
6895   p->ramped = ((c1[0] < 0.0F) || (c2[0] < 0.0F));
6896   p->no_lighting = 0;
6897   /*
6898      copy3f(I->WobbleParam,p->wobble_param); */
6899 
6900   vv = p->v1;
6901   (*vv++) = (*v1++);
6902   (*vv++) = (*v1++);
6903   (*vv++) = (*v1++);
6904   vv = p->v2;
6905   (*vv++) = (*v2++);
6906   (*vv++) = (*v2++);
6907   (*vv++) = (*v2++);
6908 
6909   I->PrimSize += diff3f(p->v1, p->v2) + 2 * r;
6910   I->PrimSizeCnt++;
6911 
6912   if(I->TTTFlag) {
6913     p->r1 *= length3f(I->TTT);
6914     transformTTT44f3f(I->TTT, p->v1, p->v1);
6915     transformTTT44f3f(I->TTT, p->v2, p->v2);
6916   }
6917 
6918   if(I->Context) {
6919     RayApplyContextToVertex(I, p->v1);
6920     RayApplyContextToVertex(I, p->v2);
6921   }
6922 
6923   vv = p->c1;
6924   (*vv++) = (*c1++);
6925   (*vv++) = (*c1++);
6926   (*vv++) = (*c1++);
6927   vv = p->c2;
6928   (*vv++) = (*c2++);
6929   (*vv++) = (*c2++);
6930   (*vv++) = (*c2++);
6931 
6932   // FIXME: alpha1 is not used
6933   p->trans = 1.0 - alpha2;
6934   {
6935     float *v;
6936     vv = p->ic;
6937     v = I->IntColor;
6938     (*vv++) = (*v++);
6939     (*vv++) = (*v++);
6940     (*vv++) = (*v++);
6941   }
6942 
6943   I->NPrimitive++;
6944   return true;
6945 }
6946 
6947 
6948 /*========================================================================*/
customCylinder3fv(const cgo::draw::custom_cylinder & cyl,const float alpha1,const float alpha2)6949 int CRay::customCylinder3fv(const cgo::draw::custom_cylinder& cyl, const float alpha1, const float alpha2){
6950   return customCylinder3fv(cyl.vertex1, cyl.vertex2, cyl.radius, cyl.color1,
6951                         cyl.color2, cyl.cap1, cyl.cap2, alpha1, alpha2);
6952 }
6953 
customCylinder3fv(const cgo::draw::custom_cylinder & cyl)6954 int CRay::customCylinder3fv(const cgo::draw::custom_cylinder& cyl){
6955   return customCylinder3fv(cyl.vertex1, cyl.vertex2, cyl.radius, cyl.color1,
6956                         cyl.color2, cyl.cap1, cyl.cap2, 1.f - Trans, 1.f - Trans);
6957 }
6958 
customCylinderAlpha3fv(const cgo::draw::custom_cylinder_alpha & cyl)6959 int CRay::customCylinderAlpha3fv(const cgo::draw::custom_cylinder_alpha& cyl){
6960   return customCylinder3fv(cyl.vertex1, cyl.vertex2, cyl.radius, cyl.color1,
6961                         cyl.color2, cyl.cap1, cyl.cap2, cyl.color1[3], cyl.color2[3]);
6962 }
6963 
customCylinder3fv(const float * v1,const float * v2,float r,const float * c1,const float * c2,const int cap1,const int cap2)6964 int CRay::customCylinder3fv(const float* v1, const float* v2, float r,
6965     const float* c1, const float* c2, const int cap1, const int cap2)
6966 {
6967   return customCylinder3fv(
6968       v1, v2, r, c1, c2, cap1, cap2, 1.f - Trans, 1.f - Trans);
6969 }
6970 
customCylinder3fv(const float * v1,const float * v2,float r,const float * c1,const float * c2,const int cap1,const int cap2,const float alpha1,const float alpha2)6971 int CRay::customCylinder3fv(const float *v1, const float *v2, float r,
6972                             const float *c1, const float *c2, const int cap1,
6973                             const int cap2, const float alpha1, const float alpha2)
6974 {
6975   CRay * I = this;
6976   CPrimitive *p;
6977   int ok = true;
6978   float *vv;
6979 
6980   VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
6981   CHECKOK(ok, I->Primitive);
6982   if (!ok)
6983     return false;
6984   p = I->Primitive + I->NPrimitive;
6985 
6986   p->type = cPrimCylinder;
6987   p->r1 = r;
6988   p->cap1 = cap1;
6989   p->cap2 = cap2;
6990   p->wobble = I->Wobble;
6991   p->ramped = ((c1[0] < 0.0F) || (c2[0] < 0.0F));
6992   p->no_lighting = 0;
6993   /*
6994      copy3f(I->WobbleParam,p->wobble_param); */
6995 
6996   vv = p->v1;
6997   (*vv++) = (*v1++);
6998   (*vv++) = (*v1++);
6999   (*vv++) = (*v1++);
7000   vv = p->v2;
7001   (*vv++) = (*v2++);
7002   (*vv++) = (*v2++);
7003   (*vv++) = (*v2++);
7004 
7005   I->PrimSize += diff3f(p->v1, p->v2) + 2 * r;
7006   I->PrimSizeCnt++;
7007 
7008   if(I->TTTFlag) {
7009     p->r1 *= length3f(I->TTT);
7010     transformTTT44f3f(I->TTT, p->v1, p->v1);
7011     transformTTT44f3f(I->TTT, p->v2, p->v2);
7012   }
7013 
7014   if(I->Context) {
7015     RayApplyContextToVertex(I, p->v1);
7016     RayApplyContextToVertex(I, p->v2);
7017   }
7018 
7019   vv = p->c1;
7020   (*vv++) = (*c1++);
7021   (*vv++) = (*c1++);
7022   (*vv++) = (*c1++);
7023   vv = p->c2;
7024   (*vv++) = (*c2++);
7025   (*vv++) = (*c2++);
7026   (*vv++) = (*c2++);
7027   vv = p->ic;
7028 
7029   // FIXME: alpha1 is not used
7030   p->trans = 1.0f - alpha2;
7031 
7032   {
7033     float *v;
7034     vv = p->ic;
7035     v = I->IntColor;
7036     (*vv++) = (*v++);
7037     (*vv++) = (*v++);
7038     (*vv++) = (*v++);
7039   }
7040 
7041   I->NPrimitive++;
7042   return true;
7043 }
7044 
cone3fv(const float * v1,const float * v2,float r1,float r2,const float * c1,const float * c2,int cap1,int cap2)7045 int CRay::cone3fv(const float *v1, const float *v2, float r1, float r2,
7046 	       const float *c1, const float *c2, int cap1, int cap2)
7047 {
7048   CRay * I = this;
7049   CPrimitive *p;
7050   float r_max = (r1 > r2) ? r1 : r2;
7051   float *vv;
7052   int ok = true;
7053 
7054   if(r2 > r1) {                 /* make sure r1 is always larger */
7055     float t;
7056     const float *tp;
7057     int ti;
7058     t = r2;
7059     r2 = r1;
7060     r1 = t;
7061     tp = c2;
7062     c2 = c1;
7063     c1 = tp;
7064     tp = v2;
7065     v2 = v1;
7066     v1 = tp;
7067     ti = cap2;
7068     cap2 = cap1;
7069     cap1 = ti;
7070   }
7071 
7072   VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
7073   CHECKOK(ok, I->Primitive);
7074   if (!ok)
7075     return false;
7076   p = I->Primitive + I->NPrimitive;
7077 
7078   p->type = cPrimCone;
7079   p->r1 = r1;
7080   p->r2 = r2;
7081   p->trans = I->Trans;
7082   p->cap1 = cap1;
7083 
7084   if(cap2 >= cCylCapFlat)
7085     cap2 = cCylCapFlat;
7086   if(cap1 >= cCylCapFlat)
7087     cap1 = cCylCapFlat;
7088 
7089   p->cap2 = cap2;
7090   p->wobble = I->Wobble;
7091   p->ramped = ((c1[0] < 0.0F) || (c2[0] < 0.0F));
7092   p->no_lighting = 0;
7093   /*
7094      copy3f(I->WobbleParam,p->wobble_param); */
7095 
7096   vv = p->v1;
7097   (*vv++) = (*v1++);
7098   (*vv++) = (*v1++);
7099   (*vv++) = (*v1++);
7100   vv = p->v2;
7101   (*vv++) = (*v2++);
7102   (*vv++) = (*v2++);
7103   (*vv++) = (*v2++);
7104 
7105   I->PrimSize += diff3f(p->v1, p->v2) + 2 * r_max;
7106   I->PrimSizeCnt++;
7107 
7108   if(I->TTTFlag) {
7109     transformTTT44f3f(I->TTT, p->v1, p->v1);
7110     transformTTT44f3f(I->TTT, p->v2, p->v2);
7111   }
7112 
7113   if(I->Context) {
7114     RayApplyContextToVertex(I, p->v1);
7115     RayApplyContextToVertex(I, p->v2);
7116   }
7117 
7118   vv = p->c1;
7119   (*vv++) = (*c1++);
7120   (*vv++) = (*c1++);
7121   (*vv++) = (*c1++);
7122   vv = p->c2;
7123   (*vv++) = (*c2++);
7124   (*vv++) = (*c2++);
7125   (*vv++) = (*c2++);
7126   vv = p->ic;
7127   {
7128     float *v;
7129     vv = p->ic;
7130     v = I->IntColor;
7131     (*vv++) = (*v++);
7132     (*vv++) = (*v++);
7133     (*vv++) = (*v++);
7134   }
7135 
7136   I->NPrimitive++;
7137   return true;
7138 }
7139 
7140 
7141 /*========================================================================*/
sausage3fv(const float * v1,const float * v2,float r,const float * c1,const float * c2)7142 int CRay::sausage3fv(const float *v1, const float *v2, float r, const float *c1, const float *c2)
7143 {
7144   CRay * I = this;
7145   CPrimitive *p;
7146   int ok = true;
7147   float *vv;
7148 
7149   VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
7150   CHECKOK(ok, I->Primitive);
7151   if (!ok)
7152     return false;
7153   p = I->Primitive + I->NPrimitive;
7154 
7155   p->type = cPrimSausage;
7156   p->r1 = r;
7157   p->trans = I->Trans;
7158   p->wobble = I->Wobble;
7159   p->ramped = ((c1[0] < 0.0F) || (c2[0] < 0.0F));
7160   p->no_lighting = 0;
7161   /*
7162      copy3f(I->WobbleParam,p->wobble_param); */
7163 
7164   vv = p->v1;
7165   (*vv++) = (*v1++);
7166   (*vv++) = (*v1++);
7167   (*vv++) = (*v1++);
7168   vv = p->v2;
7169   (*vv++) = (*v2++);
7170   (*vv++) = (*v2++);
7171   (*vv++) = (*v2++);
7172 
7173   I->PrimSize += diff3f(p->v1, p->v2) + 2 * r;
7174   I->PrimSizeCnt++;
7175 
7176   if(I->TTTFlag) {
7177     p->r1 *= length3f(I->TTT);
7178     transformTTT44f3f(I->TTT, p->v1, p->v1);
7179     transformTTT44f3f(I->TTT, p->v2, p->v2);
7180   }
7181 
7182   if(I->Context) {
7183     RayApplyContextToVertex(I, p->v1);
7184     RayApplyContextToVertex(I, p->v2);
7185   }
7186 
7187   vv = p->c1;
7188   (*vv++) = (*c1++);
7189   (*vv++) = (*c1++);
7190   (*vv++) = (*c1++);
7191   vv = p->c2;
7192   (*vv++) = (*c2++);
7193   (*vv++) = (*c2++);
7194   (*vv++) = (*c2++);
7195   vv = p->ic;
7196 
7197   {
7198     float *v = I->IntColor;
7199     vv = p->ic;
7200     (*vv++) = (*v++);
7201     (*vv++) = (*v++);
7202     (*vv++) = (*v++);
7203   }
7204 
7205   I->NPrimitive++;
7206   return true;
7207 }
7208 
ellipsoid3fv(const float * v,float r,const float * n1,const float * n2,const float * n3)7209 int CRay::ellipsoid3fv(const float *v, float r, const float *n1, const float *n2, const float *n3)
7210 {
7211   CRay * I = this;
7212   CPrimitive *p;
7213   int ok = true;
7214   float *vv;
7215 
7216   VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
7217   CHECKOK(ok, I->Primitive);
7218   if (!ok)
7219     return false;
7220   p = I->Primitive + I->NPrimitive;
7221 
7222   p->type = cPrimEllipsoid;
7223   p->r1 = r;                    /* maximum extent */
7224   p->trans = I->Trans;
7225   p->wobble = I->Wobble;
7226   p->ramped = (I->CurColor[0] < 0.0F);
7227   p->no_lighting = 0;
7228 
7229   I->PrimSize += 2 * r;
7230   I->PrimSizeCnt++;
7231 
7232   vv = p->n0;                   /* storing lengths of the direction vectors in n0 */
7233 
7234   (*vv++) = length3f(n1);
7235   (*vv++) = length3f(n2);
7236   (*vv++) = length3f(n3);
7237 
7238   /* normalize the ellipsoid axes */
7239 
7240   vv = p->n1;
7241   if(p->n0[0] > R_SMALL8) {
7242     float factor;
7243     factor = 1.0F / p->n0[0];
7244     (*vv++) = (*n1++) * factor;
7245     (*vv++) = (*n1++) * factor;
7246     (*vv++) = (*n1++) * factor;
7247   } else {
7248     (*vv++) = 0.0F;
7249     (*vv++) = 0.0F;
7250     (*vv++) = 0.0F;
7251   }
7252 
7253   vv = p->n2;
7254   if(p->n0[1] > R_SMALL8) {
7255     float factor;
7256     factor = 1.0F / p->n0[1];
7257     (*vv++) = (*n2++) * factor;
7258     (*vv++) = (*n2++) * factor;
7259     (*vv++) = (*n2++) * factor;
7260   } else {
7261     (*vv++) = 0.0F;
7262     (*vv++) = 0.0F;
7263     (*vv++) = 0.0F;
7264   }
7265 
7266   vv = p->n3;
7267   if(p->n0[2] > R_SMALL8) {
7268     float factor;
7269     factor = 1.0F / p->n0[2];
7270     (*vv++) = (*n3++) * factor;
7271     (*vv++) = (*n3++) * factor;
7272     (*vv++) = (*n3++) * factor;
7273   } else {
7274     (*vv++) = 0.0F;
7275     (*vv++) = 0.0F;
7276     (*vv++) = 0.0F;
7277   }
7278 
7279   vv = p->v1;
7280   (*vv++) = (*v++);
7281   (*vv++) = (*v++);
7282   (*vv++) = (*v++);
7283 
7284   vv = p->c1;
7285   v = I->CurColor;
7286   (*vv++) = (*v++);
7287   (*vv++) = (*v++);
7288   (*vv++) = (*v++);
7289 
7290   vv = p->ic;
7291   v = I->IntColor;
7292   (*vv++) = (*v++);
7293   (*vv++) = (*v++);
7294   (*vv++) = (*v++);
7295 
7296   if(I->TTTFlag) {
7297     p->r1 *= length3f(I->TTT);
7298     transformTTT44f3f(I->TTT, p->v1, p->v1);
7299     transform_normalTTT44f3f(I->TTT, p->n1, p->n1);
7300     transform_normalTTT44f3f(I->TTT, p->n2, p->n2);
7301     transform_normalTTT44f3f(I->TTT, p->n3, p->n3);
7302   }
7303 
7304   if(I->Context) {
7305     RayApplyContextToVertex(I, p->v1);
7306     RayApplyContextToNormal(I, p->n1);
7307     RayApplyContextToNormal(I, p->n2);
7308     RayApplyContextToNormal(I, p->n3);
7309   }
7310 
7311   I->NPrimitive++;
7312   return true;
7313 }
7314 
setLastToNoLighting(char no_lighting)7315 int CRay::setLastToNoLighting(char no_lighting)
7316 {
7317   CRay * I = this;
7318   CPrimitive *p;
7319   if (!I->NPrimitive)
7320     return false;
7321   p = I->Primitive + I->NPrimitive - 1;
7322   p->no_lighting = no_lighting;
7323   return true;
7324 }
7325 
7326 
7327 /*========================================================================*/
triangle3fv(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)7328 int CRay::triangle3fv(
7329 		   const float *v1, const float *v2, const float *v3,
7330 		   const float *n1, const float *n2, const float *n3, const float *c1, const float *c2, const float *c3)
7331 {
7332   CRay * I = this;
7333   CPrimitive *p;
7334   int ok = true;
7335   float *vv;
7336   float n0[3] = { 0.f, 0.f, 1.f }, nx[3], s1[3], s2[3], s3[3];
7337   float l1, l2, l3;
7338   short normals_exist = n1 && n2 && n3;
7339 
7340   /*  dump3f(v1," v1");
7341      dump3f(v2," v2");
7342      dump3f(v3," v3");
7343      dump3f(n1," n1");
7344      dump3f(n2," n2");
7345      dump3f(n3," n3");
7346      dump3f(c1," c1");
7347      dump3f(c2," c2");
7348      dump3f(c3," c3"); */
7349   VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
7350   CHECKOK(ok, I->Primitive);
7351   if (!ok)
7352     return false;
7353   p = I->Primitive + I->NPrimitive;
7354 
7355   p->type = cPrimTriangle;
7356   p->trans = I->Trans;
7357   p->tr[0] = I->Trans;
7358   p->tr[1] = I->Trans;
7359   p->tr[2] = I->Trans;
7360   p->wobble = I->Wobble;
7361   p->ramped = ((c1[0] < 0.0F) || (c2[0] < 0.0F) || (c3[0] < 0.0F));
7362   p->no_lighting = 0;
7363   /*
7364      copy3f(I->WobbleParam,p->wobble_param); */
7365 
7366   /* determine exact triangle normal */
7367   if (normals_exist){
7368     add3f(n1, n2, nx);
7369     add3f(n3, nx, nx);
7370   }
7371   subtract3f(v1, v2, s1);
7372   subtract3f(v3, v2, s2);
7373   subtract3f(v1, v3, s3);
7374   cross_product3f(s1, s2, n0);
7375   if (normals_exist){
7376     if((fabs(n0[0]) < RAY_SMALL) && (fabs(n0[1]) < RAY_SMALL) && (fabs(n0[2]) < RAY_SMALL)) {
7377       copy3f(nx, n0);
7378     } /* fall-back */
7379     else if(dot_product3f(n0, nx) < 0)
7380       invert3f(n0);
7381   }
7382   normalize3f(n0);
7383 
7384   vv = p->n0;
7385   (*vv++) = n0[0];
7386   (*vv++) = n0[1];
7387   (*vv++) = n0[2];
7388 
7389   /* determine maximum distance from vertex to point */
7390   l1 = (float) length3f(s1);
7391   l2 = (float) length3f(s2);
7392   l3 = (float) length3f(s3);
7393   if(l2 > l1) {
7394     if(l3 > l2)
7395       l1 = l3;
7396     else
7397       l1 = l2;
7398   }
7399   /* store cutoff distance */
7400 
7401   p->r1 = l1 * 0.6F;
7402 
7403   /*  if(l1>20) {
7404      printf("%8.3f\n",l1);
7405      printf("%8.3f %8.3f %8.3f\n",s1[0],s1[1],s1[2]);
7406      printf("%8.3f %8.3f %8.3f\n",s2[0],s2[1],s2[2]);
7407      printf("%8.3f %8.3f %8.3f\n",s3[0],s3[1],s3[2]);
7408      } */
7409 
7410   vv = p->v1;
7411   (*vv++) = (*v1++);
7412   (*vv++) = (*v1++);
7413   (*vv++) = (*v1++);
7414   vv = p->v2;
7415   (*vv++) = (*v2++);
7416   (*vv++) = (*v2++);
7417   (*vv++) = (*v2++);
7418   vv = p->v3;
7419   (*vv++) = (*v3++);
7420   (*vv++) = (*v3++);
7421   (*vv++) = (*v3++);
7422 
7423   I->PrimSize += diff3f(p->v1, p->v2) + diff3f(p->v1, p->v3) + diff3f(p->v2, p->v3);
7424   I->PrimSizeCnt += 3;
7425 
7426   vv = p->c1;
7427   (*vv++) = (*c1++);
7428   (*vv++) = (*c1++);
7429   (*vv++) = (*c1++);
7430   vv = p->c2;
7431   (*vv++) = (*c2++);
7432   (*vv++) = (*c2++);
7433   (*vv++) = (*c2++);
7434   vv = p->c3;
7435   (*vv++) = (*c3++);
7436   (*vv++) = (*c3++);
7437   (*vv++) = (*c3++);
7438 
7439   {
7440     float *v = I->IntColor;
7441     vv = p->ic;
7442     (*vv++) = (*v++);
7443     (*vv++) = (*v++);
7444     (*vv++) = (*v++);
7445   }
7446 
7447   if (normals_exist){
7448     vv = p->n1;
7449     (*vv++) = (*n1++);
7450     (*vv++) = (*n1++);
7451     (*vv++) = (*n1++);
7452     vv = p->n2;
7453     (*vv++) = (*n2++);
7454     (*vv++) = (*n2++);
7455     (*vv++) = (*n2++);
7456     vv = p->n3;
7457     (*vv++) = (*n3++);
7458     (*vv++) = (*n3++);
7459     (*vv++) = (*n3++);
7460   } else {
7461     vv = p->n1;
7462     (*vv++) = n0[0];
7463     (*vv++) = n0[1];
7464     (*vv++) = n0[2];
7465     vv = p->n2;
7466     (*vv++) = n0[0];
7467     (*vv++) = n0[1];
7468     (*vv++) = n0[2];
7469     vv = p->n3;
7470     (*vv++) = n0[0];
7471     (*vv++) = n0[1];
7472     (*vv++) = n0[2];
7473   }
7474 
7475   if(I->TTTFlag) {
7476     transformTTT44f3f(I->TTT, p->v1, p->v1);
7477     transformTTT44f3f(I->TTT, p->v2, p->v2);
7478     transformTTT44f3f(I->TTT, p->v3, p->v3);
7479     transform_normalTTT44f3f(I->TTT, p->n0, p->n0);
7480     transform_normalTTT44f3f(I->TTT, p->n1, p->n1);
7481     transform_normalTTT44f3f(I->TTT, p->n2, p->n2);
7482     transform_normalTTT44f3f(I->TTT, p->n3, p->n3);
7483   }
7484 
7485   if(I->Context) {
7486     RayApplyContextToVertex(I, p->v1);
7487     RayApplyContextToVertex(I, p->v2);
7488     RayApplyContextToVertex(I, p->v3);
7489     RayApplyContextToNormal(I, p->n0);
7490     RayApplyContextToNormal(I, p->n1);
7491     RayApplyContextToNormal(I, p->n2);
7492     RayApplyContextToNormal(I, p->n3);
7493   }
7494 
7495   I->NPrimitive++;
7496   return true;
7497 }
7498 
triangleTrans3fv(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 t1,float t2,float t3)7499 int CRay::triangleTrans3fv(
7500 			const float *v1, const float *v2, const float *v3,
7501 			const float *n1, const float *n2, const float *n3,
7502 			const float *c1, const float *c2, const float *c3, float t1, float t2, float t3)
7503 {
7504   CRay * I = this;
7505   CPrimitive *p;
7506   int ok = true;
7507   ok = I->triangle3fv(v1, v2, v3, n1, n2, n3, c1, c2, c3);
7508   if (!ok)
7509     return false;
7510   p = I->Primitive + I->NPrimitive - 1;
7511 
7512   p->tr[0] = t1;
7513   p->tr[1] = t2;
7514   p->tr[2] = t3;
7515   p->trans = (t1 + t2 + t3) / 3.0F;
7516   return true;
7517 }
7518 
7519 
7520 /*========================================================================*/
RayNew(PyMOLGlobals * G,int antialias)7521 CRay *RayNew(PyMOLGlobals * G, int antialias)
7522 {
7523   unsigned int test;
7524   unsigned char *testPtr;
7525   int a;
7526 
7527   OOCalloc(I->G, CRay);
7528   I->G = G;
7529   test = 0xFF000000;
7530   testPtr = (unsigned char *) &test;
7531   I->BigEndian = (*testPtr) & 0x01;
7532   I->Trans = 0.0F;
7533   I->Wobble = 0;
7534   I->TTTFlag = false;
7535   zero3f(I->WobbleParam);
7536   PRINTFB(I->G, FB_Ray, FB_Blather)
7537     " RayNew: BigEndian = %d\n", I->BigEndian ENDFB(I->G);
7538 
7539   I->Basis = CacheAlloc(I->G, CBasis, 12, 0, cCache_ray_basis);
7540   BasisInit(I->G, I->Basis, 0);
7541   BasisInit(I->G, I->Basis + 1, 1);
7542   I->Vert2Prim = VLACacheAlloc(I->G, int, 1, 0, cCache_ray_vert2prim);
7543   I->NBasis = 2;
7544   I->Primitive = NULL;
7545   I->NPrimitive = 0;
7546   I->TTTStackVLA = NULL;
7547   I->TTTStackDepth = 0;
7548   I->CheckInterior = false;
7549   if(antialias < 0)
7550     antialias = SettingGetGlobal_i(I->G, cSetting_antialias);
7551   I->Sampling = antialias;
7552   if(I->Sampling < 2)           /* always supersample fonts by at least 2X */
7553     I->Sampling = 2;
7554   for(a = 0; a < 256; a++) {
7555     I->Random[a] = (float) ((rand() / (1.0 + RAND_MAX)) - 0.5);
7556   }
7557 
7558   I->Wobble = SettingGet_i(I->G, NULL, NULL, cSetting_ray_texture);
7559   {
7560     auto v = SettingGet<const float*>(I->G, cSetting_ray_texture_settings);
7561     int color = SettingGetGlobal_color(I->G, cSetting_ray_interior_color);
7562     copy3f(v, I->WobbleParam);
7563     v = ColorGet(I->G, color);
7564     copy3f(v, I->IntColor);
7565   }
7566 
7567   return (I);
7568 }
7569 
7570 
7571 /*========================================================================*/
7572 
7573 /* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
7574 #ifdef PYMOL_EVAL
7575 #include "RayEvalMessage.h"
7576 #endif
7577 
7578 /* END PROPRIETARY CODE SEGMENT */
7579 
RayPrepare(CRay * I,float v0,float v1,float v2,float v3,float v4,float v5,float fov,float * pos,float * mat,float * rotMat,float aspRat,int width,int height,float pixel_scale,int ortho,float pixel_ratio,float front_back_ratio,float magnified)7580 void RayPrepare(CRay * I, float v0, float v1, float v2,
7581                 float v3, float v4, float v5,
7582                 float fov, float *pos,
7583                 float *mat, float *rotMat, float aspRat,
7584                 int width, int height, float pixel_scale, int ortho,
7585                 float pixel_ratio, float front_back_ratio, float magnified)
7586 
7587 /*prepare for vertex calls */
7588 {
7589   int a;
7590   if(!I->Primitive)
7591     I->Primitive = VLACacheAlloc(I->G, CPrimitive, 10000, 3, cCache_ray_primitive);
7592   if(!I->Vert2Prim)
7593     I->Vert2Prim = VLACacheAlloc(I->G, int, 10000, 3, cCache_ray_vert2prim);
7594   I->Volume[0] = v0;
7595   I->Volume[1] = v1;
7596   I->Volume[2] = v2;
7597   I->Volume[3] = v3;
7598   I->Volume[4] = v4;
7599   I->Volume[5] = v5;
7600   I->Range[0] = I->Volume[1] - I->Volume[0];
7601   I->Range[1] = I->Volume[3] - I->Volume[2];
7602   I->Range[2] = I->Volume[5] - I->Volume[4];
7603   I->AspRatio = aspRat;
7604   I->Width = width;
7605   I->Height = height;
7606   CharacterSetRetention(I->G, true);
7607 
7608   if(mat)
7609     for(a = 0; a < 16; a++)
7610       I->ModelView[a] = mat[a];
7611   else {
7612     identity44f(I->ModelView);
7613   }
7614   identity44f(I->ProMatrix);
7615   if (ortho){
7616     I->ProMatrix[0] = 2.f/I->Range[0];
7617     I->ProMatrix[5] = 2.f/I->Range[1];
7618     I->ProMatrix[10] = -2.f/I->Range[2];
7619     I->ProMatrix[12] = -(I->Volume[0] + I->Volume[1])/I->Range[0];
7620     I->ProMatrix[13] = -(I->Volume[2] + I->Volume[3])/I->Range[1];
7621     I->ProMatrix[14] = -(I->Volume[4] + I->Volume[5])/I->Range[2];
7622   } else {
7623     I->ProMatrix[0] = I->Volume[4]/(front_back_ratio*I->Volume[1]);
7624     I->ProMatrix[5] = I->Volume[4]/(front_back_ratio*I->Volume[3]);
7625     I->ProMatrix[10] = -(I->Volume[5] + I->Volume[4])/I->Range[2];
7626     I->ProMatrix[11] = -1.f;
7627     I->ProMatrix[14] = (-2.f * I->Volume[5] * I->Volume[4])/I->Range[2];
7628     I->ProMatrix[15] = 0.f;
7629   }
7630   if(rotMat)
7631     for(a = 0; a < 16; a++)
7632       I->Rotation[a] = rotMat[a];
7633   I->Ortho = ortho;
7634   if(ortho) {
7635     I->PixelRadius = (((float) I->Range[0]) / width) * pixel_scale;
7636   } else {
7637     I->PixelRadius = (((float) I->Range[0]) / width) * pixel_scale * pixel_ratio;
7638   }
7639   I->PixelRatio = pixel_ratio;
7640   I->Magnified = magnified;
7641   I->FrontBackRatio = front_back_ratio;
7642   I->PrimSizeCnt = 0;
7643   I->PrimSize = 0.0;
7644   I->Fov = fov;
7645   copy3f(pos, I->Pos);
7646 
7647 
7648 /* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
7649 #ifdef PYMOL_EVAL
7650   RayDrawEvalMessage(I);
7651 #endif
7652 
7653 /* END PROPRIETARY CODE SEGMENT */
7654 
7655 }
7656 
7657 
7658 /*========================================================================*/
7659 
RaySetTTT(CRay * I,int flag,float * ttt)7660 void RaySetTTT(CRay * I, int flag, float *ttt)
7661 {
7662   I->TTTFlag = flag;
7663   if(flag) {
7664     UtilCopyMem(I->TTT, ttt, sizeof(float) * 16);
7665   }
7666 }
7667 
RayGetTTT(CRay * I,float * ttt)7668 void RayGetTTT(CRay * I, float *ttt)
7669 {
7670   if(!I->TTTFlag) {
7671     identity44f(ttt);
7672   } else {
7673     copy44f(I->TTT, ttt);
7674   }
7675 }
7676 
7677 
7678 /*========================================================================*/
RayRelease(CRay * I)7679 void RayRelease(CRay * I)
7680 {
7681   int a;
7682 
7683   for(a = 0; a < I->NBasis; a++) {
7684     BasisFinish(&I->Basis[a], a);
7685   }
7686   I->NBasis = 0;
7687   VLACacheFreeP(I->G, I->Primitive, 0, cCache_ray_primitive, false);
7688   VLACacheFreeP(I->G, I->Vert2Prim, 0, cCache_ray_vert2prim, false);
7689 }
7690 
7691 
7692 /*========================================================================*/
RayFree(CRay * I)7693 void RayFree(CRay * I)
7694 {
7695   RayRelease(I);
7696   CharacterSetRetention(I->G, false);
7697   CacheFreeP(I->G, I->Basis, 0, cCache_ray_basis, false);
7698   VLACacheFreeP(I->G, I->Vert2Prim, 0, cCache_ray_vert2prim, false);
7699   VLAFreeP(I->TTTStackVLA);
7700   OOFreeP(I);
7701 }
7702 
7703 
7704 /*========================================================================*/
RayPushTTT(CRay * I)7705 void RayPushTTT(CRay * I)
7706 {
7707   if(I->TTTFlag) {
7708     if(!I->TTTStackVLA) {
7709       I->TTTStackVLA = VLAlloc(float, 16);
7710       copy44f(I->TTT, I->TTTStackVLA);
7711       I->TTTStackDepth = 1;
7712     } else {
7713       float *p;
7714       VLACheck(I->TTTStackVLA, float, I->TTTStackDepth * 16 + 15);
7715       p = I->TTTStackVLA + 16 * I->TTTStackDepth;
7716       copy44f(I->TTT, p);
7717       I->TTTStackDepth++;
7718     }
7719   }
7720 }
7721 
RayPopTTT(CRay * I)7722 void RayPopTTT(CRay * I)
7723 {
7724   if(I->TTTStackDepth > 0) {
7725     float *p;
7726     I->TTTStackDepth--;
7727     p = I->TTTStackVLA + 16 * I->TTTStackDepth;
7728     copy44f(p, I->TTT);
7729     I->TTTFlag = true;
7730   } else {
7731     I->TTTFlag = false;
7732   }
7733 }
7734 
RayApplyMatrix33(unsigned int n,float3 * q,const float m[16],float3 * p)7735 static void RayApplyMatrix33(unsigned int n, float3 * q, const float m[16], float3 * p)
7736 {
7737   {
7738     unsigned int i;
7739     float m0 = m[0], m4 = m[4], m8 = m[8], m12 = m[12];
7740     float m1 = m[1], m5 = m[5], m9 = m[9], m13 = m[13];
7741     float m2 = m[2], m6 = m[6], m10 = m[10], m14 = m[14];
7742     for(i = 0; i < n; i++) {
7743       float p0 = p[i][0], p1 = p[i][1], p2 = p[i][2];
7744       q[i][0] = m0 * p0 + m4 * p1 + m8 * p2 + m12;
7745       q[i][1] = m1 * p0 + m5 * p1 + m9 * p2 + m13;
7746       q[i][2] = m2 * p0 + m6 * p1 + m10 * p2 + m14;
7747     }
7748   }
7749 }
7750 
RayApplyMatrixInverse33(unsigned int n,float3 * q,const float m[16],float3 * p)7751 static void RayApplyMatrixInverse33(unsigned int n, float3 * q, const float m[16], float3 * p)
7752 {
7753   {
7754     unsigned int i;
7755     float m0 = m[0], m4 = m[4], m8 = m[8], m12 = m[12];
7756     float m1 = m[1], m5 = m[5], m9 = m[9], m13 = m[13];
7757     float m2 = m[2], m6 = m[6], m10 = m[10], m14 = m[14];
7758     for(i = 0; i < n; i++) {
7759       float p0 = p[i][0] - m12, p1 = p[i][1] - m13, p2 = p[i][2] - m14;
7760       q[i][0] = m0 * p0 + m1 * p1 + m2 * p2;
7761       q[i][1] = m4 * p0 + m5 * p1 + m6 * p2;
7762       q[i][2] = m8 * p0 + m9 * p1 + m10 * p2;
7763     }
7764   }
7765 }
7766 
RayTransformNormals33(unsigned int n,float3 * q,const float m[16],float3 * p)7767 static void RayTransformNormals33(unsigned int n, float3 * q, const float m[16], float3 * p)
7768 {
7769   unsigned int i;
7770   float m0 = m[0], m4 = m[4], m8 = m[8];
7771   float m1 = m[1], m5 = m[5], m9 = m[9];
7772   float m2 = m[2], m6 = m[6], m10 = m[10];
7773   for(i = 0; i < n; i++) {
7774     float p0 = p[i][0], p1 = p[i][1], p2 = p[i][2];
7775     q[i][0] = m0 * p0 + m4 * p1 + m8 * p2;
7776     q[i][1] = m1 * p0 + m5 * p1 + m9 * p2;
7777     q[i][2] = m2 * p0 + m6 * p1 + m10 * p2;
7778   }
7779   for(i = 0; i < n; i++) {      /* renormalize - can we do this to the matrix instead? */
7780     normalize3f(q[i]);
7781   }
7782 }
7783 
RayTransformInverseNormals33(unsigned int n,float3 * q,const float m[16],float3 * p)7784 static void RayTransformInverseNormals33(unsigned int n, float3 * q, const float m[16],
7785                                   float3 * p)
7786 {
7787   unsigned int i;
7788   float m0 = m[0], m4 = m[4], m8 = m[8];
7789   float m1 = m[1], m5 = m[5], m9 = m[9];
7790   float m2 = m[2], m6 = m[6], m10 = m[10];
7791   for(i = 0; i < n; i++) {
7792     float p0 = p[i][0], p1 = p[i][1], p2 = p[i][2];
7793     q[i][0] = m0 * p0 + m1 * p1 + m2 * p2;
7794     q[i][1] = m4 * p0 + m5 * p1 + m6 * p2;
7795     q[i][2] = m8 * p0 + m9 * p1 + m10 * p2;
7796   }
7797   for(i = 0; i < n; i++) {      /* renormalize - can we do this to the matrix instead? */
7798     normalize3f(q[i]);
7799   }
7800 }
RayGetScreenVertex(CRay * I,float * v,float * res)7801 void RayGetScreenVertex(CRay * I, float *v, float *res){
7802   MatrixTransformC44f4f(I->ModelView, v, res);
7803   normalize4f(res);
7804 }
7805 
RayAdjustZtoScreenZ(CRay * ray,float * pos,float zarg)7806 void RayAdjustZtoScreenZ(CRay * ray, float *pos, float zarg){
7807   PyMOLGlobals *G = ray->G;
7808   float BackSafe = ray->Volume[5], FrontSafe = ray->Volume[4];
7809   float clipRange = (BackSafe-FrontSafe);
7810   float z = (zarg + 1.f) / 2.f;
7811   float zInPreProj = -(z * clipRange + FrontSafe);
7812   float pos4[4], tpos[4], npos[4];
7813   float InvModMatrix[16];
7814   copy3f(pos, pos4);
7815   pos4[3] = 1.f;
7816   MatrixTransformC44f4f(ray->ModelView, pos4, tpos);
7817   normalize4f(tpos);
7818   /* NEED TO ACCOUNT FOR ORTHO */
7819   if (SettingGetGlobal_b(G, cSetting_ortho)){
7820     npos[0] = tpos[0];
7821     npos[1] = tpos[1];
7822   } else {
7823     npos[0] = zInPreProj * tpos[0] / tpos[2];
7824     npos[1] = zInPreProj * tpos[1] / tpos[2];
7825   }
7826   npos[2] = zInPreProj;
7827   npos[3] = 1.f;
7828   MatrixInvertC44f(ray->ModelView, InvModMatrix);
7829   MatrixTransformC44f4f(InvModMatrix, npos, npos);
7830   normalize4f(npos);
7831   copy3f(npos, pos);
7832 }
7833 
RayGetRawDepth(CRay * ray,float * pos)7834 static float RayGetRawDepth(CRay * ray, float *pos)
7835 {
7836   float pos4[4], tpos[4];
7837   copy3f(pos, pos4);
7838   pos4[3] = 1.f;
7839   MatrixTransformC44f4f(ray->ModelView, pos4, tpos);
7840   normalize4f(tpos);
7841   return -tpos[2];
7842 }
7843 
RayAdjustZtoScreenZofPoint(CRay * ray,float * pos,float * zpoint)7844 void RayAdjustZtoScreenZofPoint(CRay * ray, float *pos, float *zpoint){
7845   float BackSafe = ray->Volume[5], FrontSafe = ray->Volume[4];
7846   float clipRange = (BackSafe-FrontSafe);
7847   float zInClipping = RayGetRawDepth(ray, zpoint);
7848   float z = ((2.f * (zInClipping - FrontSafe)/ clipRange) - 1.f);
7849   RayAdjustZtoScreenZ(ray, pos, z);
7850 }
7851 
RaySetPointToWorldScreenRelative(CRay * ray,float * pos,float * screenPt)7852 void RaySetPointToWorldScreenRelative(CRay * ray, float *pos, float *screenPt)
7853 {
7854   float npos[4];
7855   float PmvMatrix[16], InvPmvMatrix[16];
7856   int width = ray->Width, height = ray->Height;
7857   multiply44f44f44f(ray->ModelView, RayGetProMatrix(ray), PmvMatrix);
7858 
7859   npos[0] = (floor(screenPt[0]*width)) /width ;
7860   npos[1] = (floor(screenPt[1]*height)) /height ;
7861   npos[2] = 0.f;
7862   npos[3] = 1.f;
7863   MatrixInvertC44f(PmvMatrix, InvPmvMatrix);
7864   MatrixTransformC44f4f(InvPmvMatrix, npos, npos);
7865   normalize4f(npos);
7866   RayAdjustZtoScreenZ(ray, npos, screenPt[2]);
7867   copy3f(npos, pos);
7868 }
7869 
RayGetScaledAllAxesAtPoint(CRay * I,float * pt,float * xn,float * yn,float * zn)7870 float RayGetScaledAllAxesAtPoint(CRay * I, float *pt, float *xn, float *yn, float *zn)
7871 {
7872   float xn0[3] = { 1.0F, 0.0F, 0.0F };
7873   float yn0[3] = { 0.0F, 1.0F, 0.0F };
7874   float zn0[3] = { 0.0F, 0.0F, 1.0F };
7875   float v_scale;
7876 
7877   v_scale = RayGetScreenVertexScale(I, pt) / I->Sampling;
7878 
7879   RayApplyMatrixInverse33(1, (float3 *) xn0, I->Rotation, (float3 *) xn0);
7880   RayApplyMatrixInverse33(1, (float3 *) yn0, I->Rotation, (float3 *) yn0);
7881   RayApplyMatrixInverse33(1, (float3 *) zn0, I->Rotation, (float3 *) zn0);
7882 
7883   scale3f(xn0, v_scale, xn);
7884   scale3f(yn0, v_scale, yn);
7885   scale3f(zn0, v_scale, zn);
7886   return v_scale;
7887 }
RayGetProMatrix(CRay * I)7888 float* RayGetProMatrix(CRay * I){
7889   return I->ProMatrix;
7890 }
7891