in layer1/SceneRay.cpp [83:741]
bool SceneRay(PyMOLGlobals * G,
int ray_width, int ray_height, int mode,
char **headerVLA_ptr,
char **charVLA_ptr, float angle,
float shift, int quiet, G3dPrimitive ** g3d, int show_timing, int antialias)
{
#ifdef _PYMOL_NO_RAY
FeedbackAdd(G, "" _PYMOL_NO_RAY);
return false;
#else
CScene *I = G->Scene;
CRay *ray = NULL;
float height, width;
float aspRat;
float rayView[16];
double timing;
char *charVLA = NULL;
char *headerVLA = NULL;
float fov;
int stereo_hand = 0;
int grid_mode = SettingGetGlobal_i(G, cSetting_grid_mode);
ImageType *stereo_image = NULL;
OrthoLineType prefix = "";
int ortho = SettingGetGlobal_i(G, cSetting_ray_orthoscopic);
int last_grid_active = I->grid.active;
int grid_size = 0;
if(SettingGetGlobal_i(G, cSetting_defer_builds_mode) == 5)
SceneUpdate(G, true);
if(ortho < 0)
ortho = SettingGetGlobal_b(G, cSetting_ortho);
if(mode != 0)
grid_mode = 0; /* only allow grid mode with PyMOL renderer */
SceneUpdateAnimation(G);
if(mode == 0)
SceneInvalidateCopy(G, true);
if(antialias < 0) {
antialias = SettingGetGlobal_i(G, cSetting_antialias);
}
if(ray_width < 0)
ray_width = 0;
if(ray_height < 0)
ray_height = 0;
if((!ray_width) || (!ray_height)) {
if(ray_width && (!ray_height)) {
ray_height = (ray_width * I->Height) / I->Width;
} else if(ray_height && (!ray_width)) {
ray_width = (ray_height * I->Width) / I->Height;
} else {
ray_width = I->Width;
ray_height = I->Height;
}
}
fov = SettingGetGlobal_f(G, cSetting_field_of_view);
timing = UtilGetSeconds(G); /* start timing the process */
SceneUpdate(G, false);
switch (I->StereoMode) {
case cStereo_quadbuffer:
stereo_hand = 2;
break;
case cStereo_crosseye:
case cStereo_walleye:
ray_width = ray_width / 2;
stereo_hand = 2;
break;
case cStereo_geowall:
case cStereo_sidebyside:
stereo_hand = 2;
break;
case cStereo_stencil_by_row:
case cStereo_stencil_by_column:
case cStereo_stencil_checkerboard:
case cStereo_stencil_custom:
case cStereo_anaglyph:
stereo_hand = 2;
break;
}
aspRat = ((float) ray_width) / ((float) ray_height);
if(grid_mode) {
grid_size = SceneGetGridSize(G, grid_mode);
GridUpdate(&I->grid, aspRat, grid_mode, grid_size);
if(I->grid.active)
aspRat *= I->grid.asp_adjust;
}
if (last_grid_active != I->grid.active || grid_size != I->last_grid_size){
// ExecutiveInvalidateRep(G, cKeywordAll, cRepLabel, cRepInvAll);
G->ShaderMgr->ResetUniformSet();
}
I->last_grid_size = grid_size;
while(1) {
int slot;
int tot_width = ray_width;
int tot_height = ray_height;
int ray_x = 0, ray_y = 0;
if(I->grid.active)
GridGetRayViewport(&I->grid, ray_width, ray_height);
for(slot = 0; slot <= I->grid.last_slot; slot++) {
if(I->grid.active) {
GridSetRayViewport(&I->grid, slot, &ray_x, &ray_y, &ray_width, &ray_height);
OrthoBusySlow(G, slot, I->grid.last_slot);
}
ray = RayNew(G, antialias);
if(!ray)
break;
SceneRaySetRayView(G, I, stereo_hand, rayView, &angle, shift);
/* define the viewing volume */
height = (float) (fabs(I->Pos[2]) * tan((fov / 2.0) * cPI / 180.0));
width = height * aspRat;
PyMOL_SetBusy(G->PyMOL, true);
OrthoBusyFast(G, 0, 20);
{
float pixel_scale_value = SettingGetGlobal_f(G, cSetting_ray_pixel_scale);
if(pixel_scale_value < 0)
pixel_scale_value = 1.0F;
pixel_scale_value *= ((float) tot_height) / I->Height;
if(ortho) {
const float _1 = 1.0F;
RayPrepare(ray, -width, width, -height, height, I->FrontSafe,
I->BackSafe, fov, I->Pos, rayView, I->RotMatrix,
aspRat, ray_width, ray_height,
pixel_scale_value, ortho, _1, _1,
((float) ray_height) / I->Height);
} else {
float back_ratio;
float back_height;
float back_width;
float pos;
pos = I->Pos[2];
if((-pos) < I->FrontSafe) {
pos = -I->FrontSafe;
}
back_ratio = -I->Back / pos;
back_height = back_ratio * height;
back_width = aspRat * back_height;
RayPrepare(ray,
-back_width, back_width,
-back_height, back_height,
I->FrontSafe, I->BackSafe,
fov, I->Pos,
rayView, I->RotMatrix, aspRat,
ray_width, ray_height,
pixel_scale_value, ortho,
height / back_height,
I->FrontSafe / I->BackSafe, ((float) ray_height) / I->Height);
}
}
{
int *slot_vla = I->SlotVLA;
int state = SceneGetState(G);
RenderInfo info;
UtilZeroMem(&info, sizeof(RenderInfo));
info.ray = ray;
info.ortho = ortho;
info.vertex_scale = SceneGetScreenVertexScale(G, NULL);
info.use_shaders = SettingGetGlobal_b(G, cSetting_use_shaders);
if(SettingGetGlobal_b(G, cSetting_dynamic_width)) {
info.dynamic_width = true;
info.dynamic_width_factor =
SettingGetGlobal_f(G, cSetting_dynamic_width_factor);
info.dynamic_width_min = SettingGetGlobal_f(G, cSetting_dynamic_width_min);
info.dynamic_width_max = SettingGetGlobal_f(G, cSetting_dynamic_width_max);
}
for ( auto it = I->Obj.begin(); it != I->Obj.end(); ++it) {
if((*it)->fRender) {
if(SceneGetDrawFlag(&I->grid, slot_vla, (*it)->grid_slot)) {
int obj_color = (*it)->Color;
float color[3];
int icx;
ColorGetEncoded(G, obj_color, color);
RaySetContext(ray, (*it)->Context);
ray->color3fv(color);
if(SettingGetIfDefined_i
(G, (*it)->Setting, cSetting_ray_interior_color, &icx)) {
float icolor[3];
if(icx != -1) {
if(icx == cColorObject) {
ray->interiorColor3fv(color, false);
} else {
ColorGetEncoded(G, icx, icolor);
ray->interiorColor3fv(icolor, false);
}
} else {
ray->interiorColor3fv(color, true);
}
} else {
ray->interiorColor3fv(color, true);
}
if((!I->grid.active) || (I->grid.mode != 2)) {
info.state = ObjectGetCurrentState((*it), false);
(*it)->fRender(*it, &info);
} else if(I->grid.slot) {
if((info.state = state + I->grid.slot - 1) >= 0)
(*it)->fRender(*it, &info);
}
}
}
}
}
OrthoBusyFast(G, 1, 20);
if(mode != 2) { /* don't show pixel count for tests */
if(!quiet) {
PRINTFB(G, FB_Ray, FB_Blather)
" Ray: tracing %dx%d = %d rays against %d primitives.\n", ray_width,
ray_height, ray_width * ray_height, RayGetNPrimitives(ray)
ENDFB(G);
}
}
switch (mode) {
case 0: /* mode 0 is built-in */
{
unsigned int buffer_size = 4 * ray_width * ray_height;
unsigned int *buffer = (unsigned int*) Alloc(unsigned int, ray_width * ray_height);
unsigned int background;
ErrChkPtr(G, buffer);
RayRender(ray, buffer, timing, angle, antialias, &background);
/* RayRenderColorTable(ray,ray_width,ray_height,buffer); */
if(!I->grid.active) {
I->Image = Calloc(ImageType, 1);
I->Image->data = (unsigned char *) buffer;
I->Image->size = buffer_size;
I->Image->width = ray_width;
I->Image->height = ray_height;
} else {
if(!I->Image) { /* alloc on first pass */
I->Image = Calloc(ImageType, 1);
if(I->Image) {
unsigned int tot_size = 4 * tot_width * tot_height;
I->Image->data = Alloc(unsigned char, tot_size);
I->Image->size = tot_size;
I->Image->width = tot_width;
I->Image->height = tot_height;
{ /* fill with background color */
unsigned int i;
unsigned int *ptr = (unsigned int *) I->Image->data;
for(i = 0; i < tot_size; i += 4) {
*(ptr++) = background;
}
}
}
}
/* merge in the latest rendering */
if(I->Image && I->Image->data) {
int i, j;
unsigned int *src = buffer;
unsigned int *dst = (unsigned int *) I->Image->data;
dst += (ray_x + ray_y * tot_width);
for(i = 0; i < ray_height; i++) {
for(j = 0; j < ray_width; j++) {
if(*src != background)
*(dst) = *(src);
dst++;
src++;
}
dst += (tot_width - ray_width);
}
}
FreeP(buffer);
}
I->DirtyFlag = false;
I->CopyType = true;
I->CopyForced = true;
I->MovieOwnsImageFlag = false;
}
break;
case 1: /* mode 1 is povray */
charVLA = VLACalloc(char, 100000);
headerVLA = VLACalloc(char, 2000);
RayRenderPOV(ray, ray_width, ray_height, &headerVLA, &charVLA,
I->FrontSafe, I->BackSafe, fov, angle, antialias);
if(!(charVLA_ptr && headerVLA_ptr)) { /* immediate mode */
strcpy(prefix, SettingGet_s(G, NULL, NULL, cSetting_batch_prefix));
#ifndef _PYMOL_NOPY
if(PPovrayRender(G, headerVLA, charVLA, prefix, ray_width,
ray_height, antialias)) {
strcat(prefix, ".png");
SceneLoadPNG(G, prefix, false, 0, false);
I->DirtyFlag = false;
}
#endif
VLAFreeP(charVLA);
VLAFreeP(headerVLA);
} else { /* get_povray mode */
*charVLA_ptr = charVLA;
*headerVLA_ptr = headerVLA;
}
break;
case 2: /* mode 2 is for testing of geometries */
RayRenderTest(ray, ray_width, ray_height, I->FrontSafe, I->BackSafe, fov);
break;
case 3: /* mode 3 is for Jmol */
{
G3dPrimitive *jp =
RayRenderG3d(ray, ray_width, ray_height, I->FrontSafe, I->BackSafe, fov,
quiet);
if(0) {
int cnt = VLAGetSize(jp);
int a;
for(a = 0; a < cnt; a++) {
switch (jp[a].op) {
case 1:
printf("g3d.fillSphereCentered(gray,%d,%d,%d,%d);\n", jp[a].r, jp[a].x1,
jp[a].y1, jp[a].z1);
break;
case 2:
printf("triangle(%d,%d,%d,%d,%d,%d,%d,%d,%d);\n",
jp[a].x1, jp[a].y1, jp[a].z1,
jp[a].x2, jp[a].y2, jp[a].z2, jp[a].x3, jp[a].y3, jp[a].z3);
break;
case 3:
printf("g3d.fillCylinder(gray,gray,(byte)3,%d,%d,%d,%d,%d,%d,%d);\n",
jp[a].r,
jp[a].x1, jp[a].y1, jp[a].z1, jp[a].x2, jp[a].y2, jp[a].z2);
break;
}
}
}
if(g3d) {
*g3d = jp;
} else {
VLAFreeP(jp);
}
}
break;
case 4: /* VRML2 */
{
char *vla = VLACalloc(char, 100000);
RayRenderVRML2(ray, ray_width, ray_height, &vla,
I->FrontSafe, I->BackSafe, fov, angle, I->Pos[2]);
*charVLA_ptr = vla;
}
break;
case 5: /* mode 5 is OBJ MTL */
{
char *objVLA = VLACalloc(char, 100000);
char *mtlVLA = VLACalloc(char, 1000);
RayRenderObjMtl(ray, ray_width, ray_height, &objVLA, &mtlVLA,
I->FrontSafe, I->BackSafe, fov, angle, I->Pos[2]);
*headerVLA_ptr = objVLA;
*charVLA_ptr = mtlVLA;
}
break;
case 6: /* VRML1 -- more compatible with tools like blender */
{
char *vla = VLACalloc(char, 100000);
RayRenderVRML1(ray, ray_width, ray_height, &vla,
I->FrontSafe, I->BackSafe, fov, angle, I->Pos[2]);
*charVLA_ptr = vla;
}
break;
case cSceneRay_MODE_IDTF:
{
*headerVLA_ptr = VLACalloc(char, 10000);
*charVLA_ptr = VLACalloc(char, 10000);
RayRenderIDTF(ray, headerVLA_ptr, charVLA_ptr);
}
break;
case 8: /* mode 8 is COLLADA (.dae) */
{
*charVLA_ptr = VLACalloc(char, 100000);
RayRenderCOLLADA(ray, ray_width, ray_height, charVLA_ptr,
I->FrontSafe, I->BackSafe, fov);
}
break;
}
RayFree(ray);
}
if(I->grid.active)
GridSetRayViewport(&I->grid, -1, &ray_x, &ray_y, &ray_width, &ray_height);
if((mode == 0) && I->Image && I->Image->data) {
SceneApplyImageGamma(G, (unsigned int *) I->Image->data, I->Image->width,
I->Image->height);
}
stereo_hand--;
if((I->StereoMode == 0) || (stereo_hand <= 0))
break;
else {
stereo_image = I->Image;
I->Image = NULL;
}
}
if(stereo_image) {
if(I->Image) {
switch (I->StereoMode) {
case cStereo_quadbuffer:
case cStereo_geowall:
/* merge the two images into one pointer */
I->Image->data = Realloc(I->Image->data, unsigned char, I->Image->size * 2);
UtilCopyMem(I->Image->data + I->Image->size, stereo_image->data, I->Image->size);
I->Image->stereo = true;
break;
case cStereo_crosseye:
case cStereo_walleye:
{
/* merge the two images into one */
unsigned char *merged_image = Alloc(unsigned char, I->Image->size * 2);
unsigned int *q = (unsigned int *) merged_image;
unsigned int *l;
unsigned int *r;
int height, width;
int a, b;
if(I->StereoMode == 2) {
l = (unsigned int *) stereo_image->data;
r = (unsigned int *) I->Image->data;
} else {
r = (unsigned int *) stereo_image->data;
l = (unsigned int *) I->Image->data;
}
height = I->Image->height;
width = I->Image->width;
for(a = 0; a < height; a++) {
for(b = 0; b < width; b++)
*(q++) = *(l++);
for(b = 0; b < width; b++)
*(q++) = *(r++);
}
FreeP(I->Image->data);
I->Image->data = merged_image;
I->Image->width *= 2;
I->Image->size *= 2;
}
break;
case cStereo_anaglyph:
{
int big_endian;
{
unsigned int test;
unsigned char *testPtr;
test = 0xFF000000;
testPtr = (unsigned char *) &test;
big_endian = (*testPtr) & 0x01;
}
{
extern float anaglyphR_constants[6][9];
extern float anaglyphL_constants[6][9];
unsigned int *l = (unsigned int *) stereo_image->data;
unsigned int *r = (unsigned int *) I->Image->data;
int anaglyph_mode = SettingGetGlobal_i(G, cSetting_anaglyph_mode);
/* anaglyph scalars */
float * a_r = anaglyphR_constants[anaglyph_mode];
float * a_l = anaglyphL_constants[anaglyph_mode];
int height, width;
int a, b;
float _r[3] = {0.F,0.F,0.F}, _l[3] = {0.F,0.F,0.F}, _b[3] = {0.F,0.F,0.F};
height = I->Image->height;
width = I->Image->width;
for(a = 0; a < height; a++) {
for(b = 0; b < width; b++) {
if(big_endian) {
/* original : RGBA
*r = (*l & 0x00FFFFFF) | (*r & 0xFF000000);
*/
/* UNTESTED */
_l[0] = (float)((*r & 0xFF000000));
_l[1] = (float)((*r & 0x00FF0000) >> 16);
_l[2] = (float)((*r & 0x0000FF00) >> 8);
_r[0] = (float)((*l & 0xFF000000));
_r[1] = (float)((*l & 0x00FF0000) >> 16);
_r[2] = (float)((*l & 0x0000FF00) >> 8);
_b[0] = (a_l[0] * _l[0] + a_l[3] * _l[1] + a_l[6] * _l[2]); // R
_b[1] = (a_l[1] * _l[0] + a_l[4] * _l[1] + a_l[7] * _l[2]); // G
_b[2] = (a_l[2] * _l[0] + a_l[5] * _l[1] + a_l[8] * _l[2]); // B
*l = (unsigned int) (0x000000FF & *l) |
(unsigned int) (1.0 * _b[0]) |
((unsigned int) (1.0 * _b[1]))<<8 |
((unsigned int) (1.0 * _b[2]))<<16;
_b[0] = (a_r[0] * _r[0] + a_r[3] * _r[1] + a_r[6] * _r[2]); // R
_b[1] = (a_r[1] * _r[0] + a_r[4] * _r[1] + a_r[7] * _r[2]); // G
_b[2] = (a_r[2] * _r[0] + a_r[5] * _r[1] + a_r[8] * _r[2]); // B
*r = (unsigned int) (0x000000FF & *r) |
(unsigned int) (1.0 * _b[0]) |
((unsigned int) (1.0 * _b[1]))<<8 |
((unsigned int) (1.0 * _b[2]))<<16;
*r = (*l | *r);
} else {
/* original : AGBR
*r = (*l & 0xFFFFFF00) | (*r & 0x000000FF);
*/
/* Right and Left as unsigned ints */
/* CORRECT */
_l[0] = (float)((*r & 0x000000FF));
_l[1] = (float)((*r & 0x0000FF00) >> 8);
_l[2] = (float)((*r & 0x00FF0000) >> 16);
_r[0] = (float)((*l & 0x000000FF));
_r[1] = (float)((*l & 0x0000FF00) >> 8);
_r[2] = (float)((*l & 0x00FF0000) >> 16);
_b[0] = (a_l[0] * _l[0] + a_l[3] * _l[1] + a_l[6] * _l[2]); // R
_b[1] = (a_l[1] * _l[0] + a_l[4] * _l[1] + a_l[7] * _l[2]); // G
_b[2] = (a_l[2] * _l[0] + a_l[5] * _l[1] + a_l[8] * _l[2]); // B
*l = (unsigned int) (0xFF000000 & *l) |
(unsigned int) (1.0 * _b[0]) |
((unsigned int) (1.0 * _b[1]))<<8 |
((unsigned int) (1.0 * _b[2]))<<16;
_b[0] = (a_r[0] * _r[0] + a_r[3] * _r[1] + a_r[6] * _r[2]); // R
_b[1] = (a_r[1] * _r[0] + a_r[4] * _r[1] + a_r[7] * _r[2]); // G
_b[2] = (a_r[2] * _r[0] + a_r[5] * _r[1] + a_r[8] * _r[2]); // B
*r = (unsigned int) (0xFF000000 & *r) |
(unsigned int) (1.0 * _b[0]) |
((unsigned int) (1.0 * _b[1]))<<8 |
((unsigned int) (1.0 * _b[2]))<<16;
*r = (*l | *r);
}
l++;
r++;
}
}
}
}
break;
case cStereo_stencil_by_row:
case cStereo_stencil_by_column:
case cStereo_stencil_checkerboard:
{
/* merge the two images into one */
unsigned char *merged_image = Alloc(unsigned char, I->Image->size);
unsigned int *q = (unsigned int *) merged_image;
unsigned int *l;
unsigned int *r;
int height, width;
int a, b;
int parity = 0;
if(I->StereoMode == cStereo_stencil_by_row) {
parity = I->StencilParity;
if(I->rect.bottom & 0x1)
parity = 1 - parity;
}
l = (unsigned int *) stereo_image->data;
r = (unsigned int *) I->Image->data;
height = I->Image->height;
width = I->Image->width;
for(a = 0; a < height; a++) {
for(b = 0; b < width; b++) {
switch (I->StereoMode) {
case cStereo_stencil_by_row:
if((a + parity) & 0x1) {
*(q++) = *(l++);
r++;
} else {
*(q++) = *(r++);
l++;
}
break;
case cStereo_stencil_by_column:
if(b & 0x1) {
*(q++) = *(l++);
r++;
} else {
*(q++) = *(r++);
l++;
}
break;
case cStereo_stencil_checkerboard:
if((a + b) & 0x1) {
*(q++) = *(l++);
r++;
} else {
*(q++) = *(r++);
l++;
}
break;
}
}
}
FreeP(I->Image->data);
I->Image->data = merged_image;
}
break;
}
}
FreeP(stereo_image->data);
FreeP(stereo_image);
}
timing = UtilGetSeconds(G) - timing;
if(mode != 2) { /* don't show timings for tests */
accumTiming += timing;
if(show_timing && !quiet) {
if(!G->Interrupt) {
PRINTFB(G, FB_Ray, FB_Details)
" Ray: render time: %4.2f sec. = %3.1f frames/hour (%4.2f sec. accum.).\n",
timing, 3600 / timing, accumTiming ENDFB(G);
} else {
PRINTFB(G, FB_Ray, FB_Details)
" Ray: render aborted.\n" ENDFB(G);
}
}
}
if(mode != 3) {
OrthoDirty(G);
}
/* EXPERIMENTAL VOLUME CODE */
if (rayVolume) {
SceneUpdate(G, true);
}
OrthoBusyFast(G, 20, 20);
PyMOL_SetBusy(G->PyMOL, false);
return true;
#endif
}