mirror of
https://github.com/schrodinger/pymol-open-source.git
synced 2026-06-04 20:04:21 +08:00
817 lines
26 KiB
C++
817 lines
26 KiB
C++
|
|
#include"Scene.h"
|
|
#include"SceneRay.h"
|
|
#include"SceneDef.h"
|
|
#include"Util.h"
|
|
#include"ShaderMgr.h"
|
|
#include"Matrix.h"
|
|
#include"PyMOL.h"
|
|
#include"ListMacros.h"
|
|
#include"Color.h"
|
|
#include"P.h"
|
|
#include "Feedback.h"
|
|
|
|
static double accumTiming = 0.0;
|
|
|
|
/* EXPERIMENTAL VOLUME RAYTRACING DATA */
|
|
static std::shared_ptr<pymol::Image> rayVolumeImage;
|
|
extern float *rayDepthPixels;
|
|
extern int rayVolume, rayWidth, rayHeight;
|
|
|
|
|
|
static void SceneRaySetRayView(PyMOLGlobals * G, CScene *I, int stereo_hand,
|
|
float *rayView, float *angle, float shift)
|
|
{
|
|
/* start afresh, looking in the negative Z direction (0,0,-1) from (0,0,0) */
|
|
identity44f(rayView);
|
|
|
|
const auto camPos = I->m_view.pos();
|
|
const auto& camOri = I->m_view.origin();
|
|
if(stereo_hand) {
|
|
/* stereo */
|
|
|
|
float stAng, stShift;
|
|
stAng = SettingGetGlobal_f(G, cSetting_stereo_angle);
|
|
stShift = SettingGetGlobal_f(G, cSetting_stereo_shift);
|
|
/* right hand */
|
|
stShift = (float) (stShift * fabs(camPos.z) / 100.0);
|
|
stAng = (float) (stAng * atan(stShift / fabs(camPos.z)) * 90.0 / cPI);
|
|
if(stereo_hand == 2) { /* left hand */
|
|
stAng = -stAng;
|
|
stShift = -stShift;
|
|
}
|
|
*angle = stAng;
|
|
{
|
|
float temp[16];
|
|
identity44f(temp);
|
|
MatrixRotateC44f(temp, (float) (-PI * stAng / 180), 0.0F, 1.0F, 0.0F); /* y-axis rotation */
|
|
MatrixMultiplyC44f(temp, rayView);
|
|
}
|
|
/* move the camera to the location we are looking at */
|
|
MatrixTranslateC44f(rayView, camPos.x, camPos.y, camPos.z);
|
|
MatrixTranslateC44f(rayView, stShift, 0.0, 0.0);
|
|
MatrixMultiplyC44f(glm::value_ptr(I->m_view.rotMatrix()), rayView);
|
|
} else { /* not stereo mode */
|
|
/* move the camera to the location we are looking at */
|
|
MatrixTranslateC44f(rayView, camPos.x, camPos.y, camPos.z);
|
|
if(shift) {
|
|
MatrixTranslateC44f(rayView, shift, 0.0F, 0.0F);
|
|
}
|
|
/* move the camera so that we can see the origin
|
|
* NOTE, vector is given in the coordinates of the world's motion
|
|
* relative to the camera */
|
|
/* 4. rotate about the origin (the the center of rotation) */
|
|
if(*angle) {
|
|
float temp[16];
|
|
identity44f(temp);
|
|
MatrixRotateC44f(temp, (float) (-PI * *angle / 180), 0.0F, 1.0F, 0.0F);
|
|
MatrixMultiplyC44f(glm::value_ptr(I->m_view.rotMatrix()), temp);
|
|
MatrixMultiplyC44f(temp, rayView);
|
|
} else {
|
|
MatrixMultiplyC44f(glm::value_ptr(I->m_view.rotMatrix()), rayView);
|
|
}
|
|
}
|
|
/* 5. move the origin to the center of rotation */
|
|
MatrixTranslateC44f(rayView, -camOri.x, -camOri.y, -camOri.z);
|
|
|
|
if(Feedback(G, FB_Scene, FB_Debugging)) {
|
|
const auto& pos = I->m_view.pos();
|
|
const auto rotMat = glm::value_ptr(I->m_view.rotMatrix());
|
|
fprintf(stderr, "SceneRay: %8.3f %8.3f %8.3f\n", pos.x, pos.y, pos.z);
|
|
fprintf(stderr, "SceneRay: %8.3f %8.3f %8.3f\n",
|
|
camOri.x, camOri.y, camOri.z);
|
|
fprintf(stderr, "SceneRay: %8.3f %8.3f %8.3f\n",
|
|
rotMat[0], rotMat[1], rotMat[2]);
|
|
}
|
|
}
|
|
|
|
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 = nullptr;
|
|
float height, width;
|
|
float aspRat;
|
|
float rayView[16];
|
|
double timing;
|
|
char *charVLA = nullptr;
|
|
char *headerVLA = nullptr;
|
|
float fov;
|
|
int stereo_hand = 0;
|
|
auto grid_mode = SettingGet<GridMode>(G, cSetting_grid_mode);
|
|
std::shared_ptr<pymol::Image> stereo_image;
|
|
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 = GridMode::NoGrid; /* 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:
|
|
case cStereo_openvr:
|
|
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 != GridMode::NoGrid) {
|
|
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) {
|
|
I->grid.cur_view.offset = Offset2D{};
|
|
I->grid.cur_view.extent = Extent2D{static_cast<std::uint32_t>(ray_width),
|
|
static_cast<std::uint32_t>(ray_height)};
|
|
}
|
|
|
|
for(slot = 0; slot <= I->grid.last_slot; slot++) {
|
|
|
|
if (I->grid.active) {
|
|
auto ray_rect = GridSetRayViewport(I->grid, slot);
|
|
ray_x = ray_rect.offset.x;
|
|
ray_y = ray_rect.offset.y;
|
|
ray_width = ray_rect.extent.width;
|
|
ray_height = ray_rect.extent.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->m_view.pos().z) * 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->m_view.m_clipSafe().m_front,
|
|
I->m_view.m_clipSafe().m_back, fov, I->m_view.pos(), rayView, I->m_view.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->m_view.pos().z;
|
|
|
|
if((-pos) < I->m_view.m_clipSafe().m_front) {
|
|
pos = -I->m_view.m_clipSafe().m_front;
|
|
}
|
|
|
|
back_ratio = -I->m_view.m_clipSafe().m_back / pos;
|
|
back_height = back_ratio * height;
|
|
back_width = aspRat * back_height;
|
|
RayPrepare(ray,
|
|
-back_width, back_width,
|
|
-back_height, back_height,
|
|
I->m_view.m_clipSafe().m_front, I->m_view.m_clipSafe().m_back,
|
|
fov, I->m_view.pos(),
|
|
rayView, I->m_view.rotMatrix(), aspRat,
|
|
ray_width, ray_height,
|
|
pixel_scale_value, ortho,
|
|
height / back_height,
|
|
I->m_view.m_clipSafe().m_front / I->m_view.m_clipSafe().m_back, ((float) ray_height) / I->Height);
|
|
}
|
|
}
|
|
{
|
|
auto slot_vla = I->m_slots.data();
|
|
int state = SceneGetState(G);
|
|
RenderInfo info;
|
|
info.ray = ray;
|
|
info.ortho = ortho;
|
|
info.vertex_scale = SceneGetScreenVertexScale(G, nullptr);
|
|
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* obj : I->Obj) {
|
|
// ObjectGroup used to have fRender = nullptr
|
|
if (obj->type != cObjectGroup) {
|
|
if(SceneGetDrawFlag(&I->grid, slot_vla, obj->grid_slot)) {
|
|
float color[3];
|
|
ColorGetEncoded(G, obj->Color, color);
|
|
RaySetContext(ray, obj->getRenderContext());
|
|
ray->color3fv(color);
|
|
|
|
auto icx = SettingGetWD<int>(
|
|
obj->Setting.get(), cSetting_ray_interior_color, cColorDefault);
|
|
|
|
if (icx == cColorDefault) {
|
|
ray->interiorColor3fv(color, true);
|
|
} else if (icx == cColorObject) {
|
|
ray->interiorColor3fv(color, false);
|
|
} else {
|
|
float icolor[3];
|
|
ColorGetEncoded(G, icx, icolor);
|
|
ray->interiorColor3fv(icolor, false);
|
|
}
|
|
|
|
if(!I->grid.active ||
|
|
I->grid.mode == GridMode::NoGrid ||
|
|
I->grid.mode == GridMode::ByObject) {
|
|
info.state = ObjectGetCurrentState(obj, false);
|
|
obj->render(&info);
|
|
} else if (I->grid.slot) {
|
|
if (I->grid.mode == GridMode::ByObjectStates) {
|
|
if((info.state = state + I->grid.slot - 1) >= 0)
|
|
obj->render(&info);
|
|
} else if (I->grid.mode == GridMode::ByObjectByState) {
|
|
info.state = I->grid.slot - obj->grid_slot - 1;
|
|
if (info.state >= 0 && info.state < obj->getNFrame())
|
|
obj->render(&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 */
|
|
{
|
|
auto image = std::make_unique<pymol::Image>(ray_width, ray_height);
|
|
std::uint32_t background;
|
|
|
|
RayRender(ray, image->pixels(), timing, angle, antialias, &background);
|
|
|
|
/* RayRenderColorTable(ray,ray_width,ray_height,buffer); */
|
|
if(!I->grid.active) {
|
|
I->Image = std::move(image);
|
|
} else {
|
|
if(!I->Image) { /* alloc on first pass */
|
|
I->Image = std::make_unique<pymol::Image>(tot_width, tot_height);
|
|
if(I->Image) {
|
|
unsigned int tot_size = tot_width * tot_height;
|
|
{ /* fill with background color */
|
|
unsigned int *ptr = I->Image->pixels();
|
|
for(size_t i = 0; i < tot_size; ++i) {
|
|
*(ptr++) = background;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* merge in the latest rendering */
|
|
if(I->Image && I->Image->bits()) {
|
|
int i, j;
|
|
unsigned int *src = image->pixels();
|
|
unsigned int *dst = I->Image->pixels();
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
I->DirtyFlag = false;
|
|
I->CopyType = true;
|
|
I->CopyForced = true;
|
|
|
|
if (SettingGet<bool>(G, cSetting_ray_volume) && !I->Image->empty()) {
|
|
rayVolumeImage = I->Image;
|
|
} else {
|
|
rayVolumeImage = nullptr;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 1: /* mode 1 is povray */
|
|
charVLA = VLACalloc(char, 100000);
|
|
headerVLA = VLACalloc(char, 2000);
|
|
RayRenderPOV(ray, ray_width, ray_height, &headerVLA, &charVLA,
|
|
I->m_view.m_clipSafe().m_front, I->m_view.m_clipSafe().m_back, fov, angle, antialias);
|
|
if(!(charVLA_ptr && headerVLA_ptr)) { /* immediate mode */
|
|
strcpy(prefix, SettingGet_s(G, nullptr, nullptr, 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->m_view.m_clipSafe().m_front, I->m_view.m_clipSafe().m_back, fov);
|
|
break;
|
|
case 3: /* mode 3 is for Jmol */
|
|
{
|
|
G3dPrimitive *jp =
|
|
RayRenderG3d(ray, ray_width, ray_height, I->m_view.m_clipSafe().m_front, I->m_view.m_clipSafe().m_back, 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->m_view.m_clipSafe().m_front, I->m_view.m_clipSafe().m_back, fov, angle, I->m_view.pos().z);
|
|
*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->m_view.m_clipSafe().m_front, I->m_view.m_clipSafe().m_back, fov, angle, I->m_view.pos().z);
|
|
*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->m_view.m_clipSafe().m_front, I->m_view.m_clipSafe().m_back, fov, angle, I->m_view.pos().z);
|
|
*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->m_view.m_clipSafe().m_front, I->m_view.m_clipSafe().m_back, fov);
|
|
}
|
|
break;
|
|
|
|
}
|
|
RayFree(ray);
|
|
}
|
|
if(I->grid.active) {
|
|
auto ray_rect = GridSetRayViewport(I->grid, -1);
|
|
ray_x = ray_rect.offset.x;
|
|
ray_y = ray_rect.offset.y;
|
|
ray_width = ray_rect.extent.width;
|
|
ray_height = ray_rect.extent.height;
|
|
}
|
|
|
|
if((mode == 0) && I->Image && !I->Image->empty()) {
|
|
SceneApplyImageGamma(G, I->Image->pixels(), I->Image->getWidth(),
|
|
I->Image->getHeight());
|
|
}
|
|
|
|
stereo_hand--;
|
|
if((I->StereoMode == 0) || (stereo_hand <= 0))
|
|
break;
|
|
else {
|
|
stereo_image = I->Image;
|
|
}
|
|
}
|
|
|
|
if(stereo_image) {
|
|
if(I->Image) {
|
|
switch (I->StereoMode) {
|
|
case cStereo_quadbuffer:
|
|
case cStereo_geowall:
|
|
case cStereo_openvr:
|
|
/* merge the two images into one */
|
|
I->Image->merge(*stereo_image);
|
|
break;
|
|
case cStereo_crosseye:
|
|
case cStereo_walleye:
|
|
{
|
|
/* merge the two images into one */
|
|
auto merged_image =
|
|
pymol::Image(I->Image->getWidth() * 2, I->Image->getHeight());
|
|
|
|
unsigned int *q = merged_image.pixels();
|
|
unsigned int *l;
|
|
unsigned int *r;
|
|
int height, width;
|
|
int a, b;
|
|
|
|
if(I->StereoMode == 2) {
|
|
l = (unsigned int *) stereo_image->bits();
|
|
r = (unsigned int *) I->Image->bits();
|
|
} else {
|
|
r = (unsigned int *) stereo_image->bits();
|
|
l = (unsigned int *) I->Image->bits();
|
|
}
|
|
height = I->Image->getHeight();
|
|
width = I->Image->getWidth();
|
|
|
|
for(a = 0; a < height; a++) {
|
|
for(b = 0; b < width; b++)
|
|
*(q++) = *(l++);
|
|
for(b = 0; b < width; b++)
|
|
*(q++) = *(r++);
|
|
}
|
|
*I->Image = std::move(merged_image);
|
|
}
|
|
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 = stereo_image->pixels();
|
|
unsigned int *r = I->Image->pixels();
|
|
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->getHeight();
|
|
width = I->Image->getWidth();
|
|
|
|
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 */
|
|
|
|
int parity = 0;
|
|
|
|
if(I->StereoMode == cStereo_stencil_by_row) {
|
|
parity = I->StencilParity;
|
|
if(I->rect.bottom & 0x1)
|
|
parity = 1 - parity;
|
|
}
|
|
|
|
unsigned int* l = stereo_image->pixels();
|
|
unsigned int* r = I->Image->pixels();
|
|
|
|
int height = I->Image->getHeight();
|
|
int width = I->Image->getWidth();
|
|
|
|
auto merged_image = pymol::Image(width, height);
|
|
unsigned int *q = merged_image.pixels();
|
|
|
|
for (int a = 0; a < height; ++a) {
|
|
for (int 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;
|
|
}
|
|
}
|
|
}
|
|
*I->Image = std::move(merged_image);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
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
|
|
}
|
|
|
|
int SceneDeferRay(PyMOLGlobals * G,
|
|
int ray_width,
|
|
int ray_height,
|
|
int mode,
|
|
float angle, float shift, int quiet, int show_timing, int antialias)
|
|
{
|
|
auto deferred = [=]() {
|
|
SceneRay(G, ray_width, ray_height, mode, nullptr, nullptr, angle, shift,
|
|
quiet, nullptr, show_timing, antialias);
|
|
if ((mode == 0) && G->HaveGUI &&
|
|
SettingGet<bool>(G, cSetting_auto_copy_images)) {
|
|
#ifdef _PYMOL_IP_EXTRAS
|
|
PParse(G, "cmd._copy_image(quiet=0)");
|
|
#else
|
|
#ifdef PYMOL_EVAL
|
|
PRINTFB(G, FB_Scene, FB_Warnings)
|
|
" Warning: Clipboard image transfers disabled in Evaluation "
|
|
"Builds.\n" ENDFB(G);
|
|
#endif
|
|
#endif
|
|
}
|
|
};
|
|
OrthoDefer(G, std::move(deferred));
|
|
return 1;
|
|
}
|
|
|
|
void SceneRenderRayVolume(PyMOLGlobals * G, CScene *I){
|
|
#ifndef PURE_OPENGL_ES_2
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glOrtho(0, I->Width, 0, I->Height, -100, 100);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
#endif
|
|
|
|
#ifndef PURE_OPENGL_ES_2
|
|
glRasterPos3f(0, 0, -1);
|
|
#endif
|
|
glDepthMask(GL_FALSE);
|
|
#ifndef PURE_OPENGL_ES_2
|
|
if (PIsGlutThread() && rayVolumeImage) {
|
|
if (rayWidth == I->Width && rayHeight == I->Height){
|
|
glDrawPixels(rayVolumeImage->getWidth(), rayVolumeImage->getHeight(),
|
|
GL_RGBA, GL_UNSIGNED_BYTE, rayVolumeImage->bits());
|
|
} else {
|
|
SceneDrawImageOverlay(G, 1, nullptr);
|
|
}
|
|
}
|
|
#endif
|
|
glDepthMask(GL_TRUE);
|
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
|
glDepthFunc(GL_ALWAYS);
|
|
#ifndef PURE_OPENGL_ES_2
|
|
if (PIsGlutThread() && rayWidth == I->Width && rayHeight == I->Height)
|
|
glDrawPixels(I->Width, I->Height, GL_DEPTH_COMPONENT, GL_FLOAT, rayDepthPixels);
|
|
#endif
|
|
glDepthFunc(GL_LESS);
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
|
|
#ifdef PURE_OPENGL_ES_2
|
|
/* TODO */
|
|
#else
|
|
glPopMatrix();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
#endif
|
|
}
|