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