layer1/Ray.cpp (6,734 lines of code) (raw):
/*
A* -------------------------------------------------------------------
B* This file contains source code for the PyMOL computer program
C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific.
D* -------------------------------------------------------------------
E* It is unlawful to modify or remove this copyright notice.
F* -------------------------------------------------------------------
G* Please see the accompanying LICENSE file for further information.
H* -------------------------------------------------------------------
I* Additional authors of this source file include:
-* Larry Coopet (various optimizations)
-* Chris Want (RayRenderVRML2, via the public domain )
-*
Z* -------------------------------------------------------------------
*/
#include"os_python.h"
#include"os_predef.h"
#include"os_std.h"
#include"Base.h"
#include"MemoryDebug.h"
#include"Err.h"
#include"Vector.h"
#include"OOMac.h"
#include"Setting.h"
#include"Ortho.h"
#include"Util.h"
#include"Ray.h"
#include"Triangle.h"
#include"Color.h"
#include"Matrix.h"
#include"P.h"
#include"MemoryCache.h"
#include"Character.h"
#include"Text.h"
#include"PyMOL.h"
#include"Scene.h"
#include"PConv.h"
#include"MyPNG.h"
#define SettingGetfv SettingGetGlobal_3fv
#ifdef _PYMOL_INLINE
#undef _PYMOL_INLINE
#include"Basis.cpp"
#define _PYMOL_INLINE
#endif
#ifndef RAY_SMALL
#define RAY_SMALL 0.00001
#endif
/* BASES
0 contains untransformed vertices (vector size = 3)
1 contains transformed vertices (vector size = 3)
2 contains transformed vertices for shadowing
*/
/* note: the following value must be at least one greater than the max
number of lights */
#define MAX_BASIS 12
typedef float float3[3];
typedef float float4[4];
struct _CRayThreadInfo {
CRay *ray;
int width, height;
unsigned int *image;
float front, back;
unsigned int fore_mask;
float *bkrd_top, *bkrd_bottom;
short bkrd_is_gradient; /* if not gradient, use bkrd_top as bkrd */
float ambient;
unsigned int background;
int border;
int phase, n_thread;
int x_start, x_stop;
int y_start, y_stop;
unsigned int *edging;
unsigned int edging_cutoff;
int perspective;
float fov, pos[3];
float *depth;
int bgWidth, bgHeight;
void *bkrd_data; /* used for image-based background */
};
struct _CRayHashThreadInfo {
CBasis *basis;
int *vert2prim;
CPrimitive *prim;
int n_prim;
float *clipBox;
unsigned int *image;
unsigned int background;
size_t bytes;
int perspective;
float front;
int phase;
float size_hint;
CRay *ray;
float *bkrd_top, *bkrd_bottom;
short bkrd_is_gradient; /* if not gradient, use bkrd_top as bkrd */
int width, height;
int opaque_back;
};
struct _CRayAntiThreadInfo {
unsigned int *image;
unsigned int *image_copy;
unsigned int width, height;
int mag;
int phase, n_thread;
CRay *ray;
};
void RayRelease(CRay * I);
static void RayApplyMatrix33(unsigned int n, float3 * q, const float m[16], float3 * p);
static void RayApplyMatrixInverse33(unsigned int n, float3 * q, const float m[16], float3 * p);
int RayExpandPrimitives(CRay * I);
int PrimitiveSphereHit(CRay * I, float *v, float *n, float *minDist, int except);
static void RayTransformNormals33(unsigned int n, float3 * q, const float m[16], float3 * p);
static void RayTransformInverseNormals33(unsigned int n, float3 * q, const float m[16],
float3 * p);
void RayProjectTriangle(CRay * I, RayInfo * r, float *light, float *v0, float *n0,
float scale);
void RaySetContext(CRay * I, int context)
{
if(context >= 0)
I->Context = context;
else
I->Context = 0;
}
float RayGetScreenVertexScale(CRay * I, float *v1)
{
/* what size should a screen pixel be at the coordinate provided? */
float vt[3];
float ratio;
RayApplyMatrix33(1, (float3 *) vt, I->ModelView, (float3 *) v1);
if(I->Ortho) {
ratio =
2 * (float) (fabs(I->Pos[2]) * tan((I->Fov / 2.0) * cPI / 180.0)) / (I->Height);
} else {
float front_size =
2 * I->Volume[4] * ((float) tan((I->Fov / 2.0F) * PI / 180.0F)) / (I->Height);
ratio = fabs(front_size * (-vt[2] / I->Volume[4]));
}
return ratio;
}
static void RayApplyContextToVertex(CRay * I, float *v)
{
switch (I->Context) {
case 1:
{
float tw;
float th;
if(I->AspRatio > 1.0F) {
tw = I->AspRatio;
th = 1.0F;
} else {
th = 1.0F / I->AspRatio;
tw = 1.0F;
}
if(!SettingGetGlobal_b(I->G, cSetting_ortho)) {
float scale = v[2] + 0.5F;
scale = I->FrontBackRatio * scale + 1.0F - scale;
/* z-coodinate is easy... */
v[2] = v[2] * I->Range[2] - (I->Volume[4] + I->Volume[5]) / 2.0F;
v[0] -= 0.5F;
v[1] -= 0.5F;
v[0] = scale * v[0] * I->Range[0] / tw + (I->Volume[0] + I->Volume[1]) / 2.0F;
v[1] = scale * v[1] * I->Range[1] / th + (I->Volume[2] + I->Volume[3]) / 2.0F;
RayApplyMatrixInverse33(1, (float3 *) v, I->ModelView, (float3 *) v);
} else {
v[0] += (tw - 1.0F) / 2;
v[1] += (th - 1.0F) / 2;
v[0] = v[0] * (I->Range[0] / tw) + I->Volume[0];
v[1] = v[1] * (I->Range[1] / th) + I->Volume[2];
v[2] = v[2] * I->Range[2] - (I->Volume[4] + I->Volume[5]) / 2.0F;
RayApplyMatrixInverse33(1, (float3 *) v, I->ModelView, (float3 *) v);
}
}
break;
}
}
static void RayApplyContextToNormal(CRay * I, float *v)
{
switch (I->Context) {
case 1:
RayTransformInverseNormals33(1, (float3 *) v, I->ModelView, (float3 *) v);
break;
}
}
int RayGetNPrimitives(CRay * I)
{
return (I->NPrimitive);
}
/*========================================================================*/
#ifdef _PYMOL_INLINE
__inline__
#endif
static void RayGetSphereNormal(CRay * I, RayInfo * r)
{
r->impact[0] = r->base[0];
r->impact[1] = r->base[1];
r->impact[2] = r->base[2] - r->dist;
r->surfnormal[0] = r->impact[0] - r->sphere[0];
r->surfnormal[1] = r->impact[1] - r->sphere[1];
r->surfnormal[2] = r->impact[2] - r->sphere[2];
normalize3f(r->surfnormal);
}
#ifdef _PYMOL_INLINE
__inline__
#endif
static void RayGetSphereNormalPerspective(CRay * I, RayInfo * r)
{
r->impact[0] = r->base[0] + r->dist * r->dir[0];
r->impact[1] = r->base[1] + r->dist * r->dir[1];
r->impact[2] = r->base[2] + r->dist * r->dir[2];
r->surfnormal[0] = r->impact[0] - r->sphere[0];
r->surfnormal[1] = r->impact[1] - r->sphere[1];
r->surfnormal[2] = r->impact[2] - r->sphere[2];
normalize3f(r->surfnormal);
}
static void fill(unsigned int *buffer, unsigned int value, size_t cnt)
{
// std::fill_n(buffer, cnt, value);
for (auto it_end = buffer + cnt; buffer != it_end;) {
*(buffer++) = value;
}
}
#define MIN(x,y) ((x < y) ? x : y)
#define MAX(x,y) ((x > y) ? x : y)
static void add4ucf(unsigned char *ucval, float *fval, float mulv){
fval[0] += ucval[0] * mulv;
fval[1] += ucval[1] * mulv;
fval[2] += ucval[2] * mulv;
fval[3] += ucval[3] * mulv;
}
static void copy4fuc(float *fval, unsigned char *ucval){
ucval[0] = (0xFF & (int)pymol_roundf(fval[0]));
ucval[1] = (0xFF & (int)pymol_roundf(fval[1]));
ucval[2] = (0xFF & (int)pymol_roundf(fval[2]));
ucval[3] = (0xFF & (int)pymol_roundf(fval[3]));
}
static float fmodpos(float a, float b){
float ret = fmod(a, b);
if (ret < 0.f){
ret = fmod(-ret, b);
ret = fmod( b - ret, b);
}
return ret;
}
static void 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)
{
short isBackground = isOutsideInY;
float wl;
switch (bg_image_mode){
case 1: // isCentered
{
float tmpx = floor(w - hpixelx);
isBackground |= (tmpx < 0.f || tmpx > (float)bkgrd_width);
wl = fmodpos(tmpx, (float)bkgrd_width);
}
break;
case 2: // isTiled
wl = bkgrd_width * (fmodpos((float)w, bg_image_tilesize[0])/bg_image_tilesize[0]);
break;
case 3: // isCenteredRepeated
wl = fmodpos(floor(w - hpixelx), (float)bkgrd_width) ;
break;
default:
wl = w * wr;
}
if (isBackground){
copy3f(bg_rgb, bkrd);
bkrd[3] = 1.f;
} else if (bg_image_linear){
int wlf = floor(wl), hlf = floor(hl);
float xp = (wl - wlf) - .5f, yp = (hl - hlf) - .5f;
float xpa = fabs(xp), ypa = fabs(yp);
float xpam = 1.f - xpa, ypam = 1.f - ypa;
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 };
int xd = (xp > 0.f) ? 1 : -1, yd = (yp > 0.f) ? 1 : -1;
int wlfn = (wlf + xd + bkgrd_width) % bkgrd_width, hlfn = (hlf + yd + bkgrd_height) % bkgrd_height;
add4ucf(&bkgrd_data[(bkgrd_width*hlf + wlf)*4], valx, xpam);
add4ucf(&bkgrd_data[(bkgrd_width*hlf + wlfn)*4], valx, xpa);
add4ucf(&bkgrd_data[(bkgrd_width*hlfn + wlf)*4], valy, xpam);
add4ucf(&bkgrd_data[(bkgrd_width*hlfn + wlfn)*4], valy, xpa);
mult4f(valx, ypam, val);
mult4f(valy, ypa, valy);
add4f(valy, val, val);
copy4fuc(val, bkrd);
} else {
copy4f(&bkgrd_data[(bkgrd_width*(int)floor(hl) + (int)floor(wl))*4], bkrd);
}
// alpha blending with bg_rgb if needed
if (blend_bg && bkrd[3] < 255){
float alpha = (255.f - bkrd[3]) / 255.f;
float tmpadd1[3], tmpadd2[3];
tmpadd1[0] = bkrd[0]; tmpadd1[1] = bkrd[1]; tmpadd1[2] = bkrd[2];
mult3f(tmpadd1, 1.f - alpha, tmpadd1);
mult3f(bg_rgb, alpha, tmpadd2);
add3f(tmpadd1, tmpadd2, tmpadd2);
bkrd[0] = 0xFF & (int)pymol_roundf(tmpadd2[0]);
bkrd[1] = 0xFF & (int)pymol_roundf(tmpadd2[1]);
bkrd[2] = 0xFF & (int)pymol_roundf(tmpadd2[2]);
bkrd[3] = 255;
}
}
static void fill_background_image(CRay * I, unsigned int *buffer, int width, int height, unsigned int cnt){
int bkgrd_width = I->bkgrd_width, bkgrd_height = I->bkgrd_height;
unsigned char *bkgrd_data = I->bkgrd_data;
int bg_image_mode = SettingGetGlobal_i(I->G, cSetting_bg_image_mode);
int bg_image_linear = SettingGetGlobal_b(I->G, cSetting_bg_image_linear);
float bg_rgb[3];
const float *tmpf;
int w, h;
unsigned int value;
float wr = bkgrd_width/(float)width, hr = bkgrd_height/(float)height;
float hl;
unsigned int back_mask;
unsigned char bkrd[4];
float hpixelx = floor(width/2.f) - floor(bkgrd_width / 2.f),
hpixely = floor(height/2.f) - floor(bkgrd_height / 2.f);
auto bg_image_tilesize = SettingGet<const float*>(I->G, cSetting_bg_image_tilesize);
short isOutsideInY = 0;
int opaque_back ;
opaque_back = SettingGetGlobal_i(I->G, cSetting_ray_opaque_background);
if(opaque_back < 0)
opaque_back = SettingGetGlobal_i(I->G, cSetting_opaque_background);
tmpf = ColorGet(I->G, SettingGet_color(I->G, NULL, NULL, cSetting_bg_rgb));
mult3f(tmpf, 255.f, bg_rgb);
if(opaque_back) {
if(I->BigEndian)
back_mask = 0x000000FF;
else
back_mask = 0xFF000000;
} else {
back_mask = 0x00000000;
}
// tiled or stretched
for (h=0; h<height; h++){
switch (bg_image_mode){
case 1: // isCentered
{
float tmpy = floor(h - hpixely);
isOutsideInY = (tmpy < 0.f || tmpy > (float)bkgrd_height);
hl = fmodpos(tmpy, (float)bkgrd_height);
}
break;
case 2: // isTiled
hl = bkgrd_height * (fmodpos((float)h, bg_image_tilesize[1])/bg_image_tilesize[1]);
break;
case 3: // isCenteredRepeated
hl = fmodpos(floor(h - hpixely), (float)bkgrd_height);
break;
default:
hl = h * hr;
break;
}
for (w=0; w<width; w++){
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 );
if(I->BigEndian){
value =
((0xFF & bkrd[0]) << 24) |
((0xFF & bkrd[1]) << 16) |
((0xFF & bkrd[2]) << 8) |
(0xFF & bkrd[3]);
} else {
value =
((0xFF & bkrd[3]) << 24) |
((0xFF & bkrd[2]) << 16) |
((0xFF & bkrd[1]) << 8) |
(0xFF & bkrd[0]);
}
if(opaque_back) {
value = back_mask | value;
}
*(buffer++) = value;
}
}
}
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)
{
const float _p499 = 0.499F;
int w, h;
unsigned int value;
float bkrd[3], perc;
unsigned int back_mask;
if(opaque_back) {
if(I->BigEndian)
back_mask = 0x000000FF;
else
back_mask = 0xFF000000;
} else {
back_mask = 0x00000000;
}
for (h=0; h<height; h++){
/* for fill_gradient, y is from top to bottom */
perc = h/(float)height;
bkrd[0] = bkrd_top[0] + perc * (bkrd_bottom[0] - bkrd_top[0]);
bkrd[1] = bkrd_top[1] + perc * (bkrd_bottom[1] - bkrd_top[1]);
bkrd[2] = bkrd_top[2] + perc * (bkrd_bottom[2] - bkrd_top[2]);
if(I->BigEndian){
value = back_mask | ((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))) << 24) |
((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 16) |
((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 8);
} else {
value = back_mask | ((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 16) |
((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 8) |
((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))));
}
for (w=0; w<width; w++){
*(buffer++) = value;
}
}
}
/*========================================================================*/
#ifdef _PYMOL_INLINE
__inline__
#endif
static void RayReflectAndTexture(CRay * I, RayInfo * r, int perspective)
{
if(r->prim->wobble)
switch (r->prim->wobble) {
case 1:
scatter3f(r->surfnormal, I->WobbleParam[0]);
break;
case 2:
wiggle3f(r->surfnormal, r->impact, I->WobbleParam);
break;
case 3:
{
float3 v;
float3 n;
copy3f(r->impact, v);
RayApplyMatrixInverse33(1, &v, I->ModelView, &v);
n[0] = (float) cos((v[0] + v[1] + v[2]) * I->WobbleParam[1]);
n[1] = (float) cos((v[0] - v[1] + v[2]) * I->WobbleParam[1]);
n[2] = (float) cos((v[0] + v[1] - v[2]) * I->WobbleParam[1]);
RayTransformNormals33(1, &n, I->ModelView, &n);
scale3f(n, I->WobbleParam[0], n);
add3f(n, r->surfnormal, r->surfnormal);
normalize3f(r->surfnormal);
}
case 4:
{
float3 v;
float3 n;
float *tp = I->WobbleParam;
copy3f(r->impact, v);
RayApplyMatrixInverse33(1, &v, I->ModelView, &v);
n[0] = I->Random[0xFF & (int) ((cos((v[0]) * tp[1]) * 256 * tp[2]))];
n[1] = I->Random[0xFF & (int) ((cos((v[1]) * tp[1]) * 256 * tp[2] + 96))];
n[2] = I->Random[0xFF & (int) ((cos((v[2]) * tp[1]) * 256 * tp[2] + 148))];
RayTransformNormals33(1, &n, I->ModelView, &n);
scale3f(n, tp[0], n);
add3f(n, r->surfnormal, r->surfnormal);
normalize3f(r->surfnormal);
}
break;
case 5:
{
float3 v;
float3 n;
float *tp = I->WobbleParam;
copy3f(r->impact, v);
RayApplyMatrixInverse33(1, &v, I->ModelView, &v);
n[0] = I->Random[0xFF & (int) ((v[0] * tp[1]) + 0)] +
I->Random[0xFF & (int) ((v[1] * tp[1]) + 20)] +
I->Random[0xFF & (int) ((v[2] * tp[1]) + 40)];
n[1] = I->Random[0xFF & (int) ((-v[0] * tp[1]) + 90)] +
I->Random[0xFF & (int) ((v[1] * tp[1]) + 100)] +
I->Random[0xFF & (int) ((-v[2] * tp[1]) + 120)];
n[2] = I->Random[0xFF & (int) ((v[0] * tp[1]) + 200)] +
I->Random[0xFF & (int) ((-v[1] * tp[1]) + 70)] +
I->Random[0xFF & (int) ((v[2] * tp[1]) + 30)];
n[0] +=
I->Random[0xFF & ((int) ((v[0] - v[1]) * tp[1]) + 0)] +
I->Random[0xFF & ((int) ((v[1] - v[2]) * tp[1]) + 20)] +
I->Random[0xFF & ((int) ((v[2] - v[0]) * tp[1]) + 40)];
n[1] +=
I->Random[0xFF & ((int) ((v[0] + v[1]) * tp[1]) + 10)] +
I->Random[0xFF & ((int) ((v[1] + v[2]) * tp[1]) + 90)] +
I->Random[0xFF & ((int) ((v[2] + v[0]) * tp[1]) + 30)];
n[2] +=
I->Random[0xFF & ((int) ((-v[0] + v[1]) * tp[1]) + 220)] +
I->Random[0xFF & ((int) ((-v[1] + v[2]) * tp[1]) + 20)] +
I->Random[0xFF & ((int) ((-v[2] + v[0]) * tp[1]) + 50)];
n[0] +=
I->Random[0xFF & ((int) ((v[0] + v[1] + v[2]) * tp[1]) + 5)] +
I->Random[0xFF & ((int) ((v[0] + v[1] + v[2]) * tp[1]) + 25)] +
I->Random[0xFF & ((int) ((v[0] + v[1] + v[2]) * tp[1]) + 46)];
n[1] +=
I->Random[0xFF & ((int) ((-v[0] - v[1] + v[2]) * tp[1]) + 90)] +
I->Random[0xFF & ((int) ((-v[0] - v[1] + v[2]) * tp[1]) + 45)] +
I->Random[0xFF & ((int) ((-v[0] - v[1] + v[2]) * tp[1]) + 176)];
n[2] +=
I->Random[0xFF & ((int) ((v[0] + v[1] - v[2]) * tp[1]) + 192)] +
I->Random[0xFF & ((int) ((v[0] + v[1] - v[2]) * tp[1]) + 223)] +
I->Random[0xFF & ((int) ((v[0] + v[1] - v[2]) * tp[1]) + 250)];
RayTransformNormals33(1, &n, I->ModelView, &n);
scale3f(n, tp[0], n);
add3f(n, r->surfnormal, r->surfnormal);
normalize3f(r->surfnormal);
}
break;
}
if(perspective) {
r->dotgle = dot_product3f(r->dir, r->surfnormal);
r->flat_dotgle = -r->dotgle;
r->reflect[0] = r->dir[0] - (2 * r->dotgle * r->surfnormal[0]);
r->reflect[1] = r->dir[1] - (2 * r->dotgle * r->surfnormal[1]);
r->reflect[2] = r->dir[2] - (2 * r->dotgle * r->surfnormal[2]);
} else {
r->dotgle = -r->surfnormal[2];
r->flat_dotgle = r->surfnormal[2];
r->reflect[0] = -(2 * r->dotgle * r->surfnormal[0]);
r->reflect[1] = -(2 * r->dotgle * r->surfnormal[1]);
r->reflect[2] = -1.0F - (2 * r->dotgle * r->surfnormal[2]);
}
}
/*========================================================================*/
int RayExpandPrimitives(CRay * I)
{
int a;
float *v0, *v1, *n0, *n1;
CBasis *basis;
int nVert, nNorm;
float voxel_floor;
int ok = true;
nVert = 0;
nNorm = 0;
for(a = 0; a < I->NPrimitive; a++) {
switch (I->Primitive[a].type) {
case cPrimSphere:
nVert++;
break;
case cPrimEllipsoid:
nVert++;
nNorm += 3;
break;
case cPrimCone:
case cPrimCylinder:
case cPrimSausage:
nVert++;
nNorm++;
break;
case cPrimTriangle:
case cPrimCharacter:
nVert += 3;
nNorm += 4;
break;
}
}
basis = I->Basis;
VLACacheSize(I->G, basis->Vertex, float, 3 * nVert, 0, cCache_basis_vertex);
VLACacheSize(I->G, basis->Radius, float, nVert, 0, cCache_basis_radius);
VLACacheSize(I->G, basis->Radius2, float, nVert, 0, cCache_basis_radius2);
VLACacheSize(I->G, basis->Vert2Normal, int, nVert, 0, cCache_basis_vert2normal);
VLACacheSize(I->G, basis->Normal, float, 3 * nNorm, 0, cCache_basis_normal);
VLACacheSize(I->G, I->Vert2Prim, int, nVert, 0, cCache_ray_vert2prim);
voxel_floor = I->PixelRadius / 2.0F;
basis->MaxRadius = 0.0F;
basis->MinVoxel = 0.0F;
basis->NVertex = nVert;
basis->NNormal = nNorm;
nVert = 0;
nNorm = 0;
v0 = basis->Vertex;
n0 = basis->Normal;
ok &= !I->G->Interrupt;
for(a = 0; ok && a < I->NPrimitive; a++) {
switch (I->Primitive[a].type) {
case cPrimTriangle:
case cPrimCharacter:
I->Primitive[a].vert = nVert;
I->Vert2Prim[nVert] = a;
I->Vert2Prim[nVert + 1] = a;
I->Vert2Prim[nVert + 2] = a;
basis->Radius[nVert] = I->Primitive[a].r1;
basis->Radius2[nVert] = I->Primitive[a].r1 * I->Primitive[a].r1; /*necessary?? */
/* if(basis->Radius[nVert]>basis->MinVoxel)
basis->MinVoxel=basis->Radius[nVert]; */
if(basis->MinVoxel < voxel_floor)
basis->MinVoxel = voxel_floor;
basis->Vert2Normal[nVert] = nNorm;
basis->Vert2Normal[nVert + 1] = nNorm;
basis->Vert2Normal[nVert + 2] = nNorm;
n1 = I->Primitive[a].n0;
(*n0++) = (*n1++);
(*n0++) = (*n1++);
(*n0++) = (*n1++);
n1 = I->Primitive[a].n1;
(*n0++) = (*n1++);
(*n0++) = (*n1++);
(*n0++) = (*n1++);
n1 = I->Primitive[a].n2;
(*n0++) = (*n1++);
(*n0++) = (*n1++);
(*n0++) = (*n1++);
n1 = I->Primitive[a].n3;
(*n0++) = (*n1++);
(*n0++) = (*n1++);
(*n0++) = (*n1++);
nNorm += 4;
v1 = I->Primitive[a].v1;
(*v0++) = (*v1++);
(*v0++) = (*v1++);
(*v0++) = (*v1++);
v1 = I->Primitive[a].v2;
(*v0++) = (*v1++);
(*v0++) = (*v1++);
(*v0++) = (*v1++);
v1 = I->Primitive[a].v3;
(*v0++) = (*v1++);
(*v0++) = (*v1++);
(*v0++) = (*v1++);
nVert += 3;
break;
case cPrimSphere:
I->Primitive[a].vert = nVert;
I->Vert2Prim[nVert] = a;
v1 = I->Primitive[a].v1;
basis->Radius[nVert] = I->Primitive[a].r1;
basis->Radius2[nVert] = I->Primitive[a].r1 * I->Primitive[a].r1; /*precompute */
if(basis->Radius[nVert] > basis->MaxRadius)
basis->MaxRadius = basis->Radius[nVert];
(*v0++) = (*v1++);
(*v0++) = (*v1++);
(*v0++) = (*v1++);
nVert++;
break;
case cPrimEllipsoid:
I->Primitive[a].vert = nVert;
I->Vert2Prim[nVert] = a;
v1 = I->Primitive[a].v1;
basis->Radius[nVert] = I->Primitive[a].r1;
basis->Radius2[nVert] = I->Primitive[a].r1 * I->Primitive[a].r1; /*precompute */
if(basis->Radius[nVert] > basis->MaxRadius)
basis->MaxRadius = basis->Radius[nVert];
basis->Vert2Normal[nVert] = nNorm;
(*v0++) = (*v1++);
(*v0++) = (*v1++);
(*v0++) = (*v1++);
nVert++;
n1 = I->Primitive[a].n1;
(*n0++) = (*n1++);
(*n0++) = (*n1++);
(*n0++) = (*n1++);
n1 = I->Primitive[a].n2;
(*n0++) = (*n1++);
(*n0++) = (*n1++);
(*n0++) = (*n1++);
n1 = I->Primitive[a].n3;
(*n0++) = (*n1++);
(*n0++) = (*n1++);
(*n0++) = (*n1++);
nNorm += 3;
break;
case cPrimCone:
case cPrimCylinder:
case cPrimSausage:
I->Primitive[a].vert = nVert;
I->Vert2Prim[nVert] = a;
basis->Radius[nVert] = I->Primitive[a].r1;
basis->Radius2[nVert] = I->Primitive[a].r1 * I->Primitive[a].r1; /*precompute */
if(basis->MinVoxel < voxel_floor)
basis->MinVoxel = voxel_floor;
subtract3f(I->Primitive[a].v2, I->Primitive[a].v1, n0);
I->Primitive[a].l1 = (float) length3f(n0);
normalize3f(n0);
n0 += 3;
basis->Vert2Normal[nVert] = nNorm;
nNorm++;
v1 = I->Primitive[a].v1;
(*v0++) = (*v1++);
(*v0++) = (*v1++);
(*v0++) = (*v1++);
nVert++;
break;
}
ok &= !I->G->Interrupt;
}
if(nVert > basis->NVertex) {
fprintf(stderr, "Error: basis->NVertex exceeded\n");
}
PRINTFB(I->G, FB_Ray, FB_Blather)
" Ray: minvoxel %8.3f\n Ray: NPrimit %d nvert %d\n", basis->MinVoxel, I->NPrimitive,
nVert ENDFB(I->G);
return ok;
}
/*========================================================================*/
void RayComputeBox(CRay * I)
{
#define minmax(v,r) { \
xp = v[0] + r;\
xm = v[0] - r;\
yp = v[1] + r;\
ym = v[1] - r;\
zp = v[2] + r;\
zm = v[2] - r;\
if(xmin>xm) xmin = xm;\
if(xmax<xp) xmax = xp;\
if(ymin>ym) ymin = ym;\
if(ymax<yp) ymax = yp;\
if(zmin>zm) zmin = zm;\
if(zmax<zp) zmax = zp;\
}
CPrimitive *prm;
CBasis *basis1;
float xmin = 0.0F, ymin = 0.0F, xmax = 0.0F, ymax = 0.0F, zmin = 0.0F, zmax = 0.0F;
float xp, xm, yp, ym, zp, zm;
float *v, r;
float vt[3];
const float _0 = 0.0F;
int a;
basis1 = I->Basis + 1;
if(basis1->NVertex) {
xmin = xmax = basis1->Vertex[0];
ymin = ymax = basis1->Vertex[1];
zmin = zmax = basis1->Vertex[2];
for(a = 0; a < I->NPrimitive; a++) {
prm = I->Primitive + a;
switch (prm->type) {
case cPrimTriangle:
case cPrimCharacter:
r = _0;
v = basis1->Vertex + prm->vert * 3;
minmax(v, r);
v = basis1->Vertex + prm->vert * 3 + 3;
minmax(v, r);
v = basis1->Vertex + prm->vert * 3 + 6;
minmax(v, r);
break;
case cPrimSphere:
case cPrimEllipsoid:
r = prm->r1;
v = basis1->Vertex + prm->vert * 3;
minmax(v, r);
break;
case cPrimCone:
case cPrimCylinder:
case cPrimSausage:
r = prm->r1;
v = basis1->Vertex + prm->vert * 3;
minmax(v, r);
v = basis1->Normal + basis1->Vert2Normal[prm->vert] * 3;
scale3f(v, prm->l1, vt);
v = basis1->Vertex + prm->vert * 3;
add3f(v, vt, vt);
minmax(vt, r);
break;
} /* end of switch */
}
}
// without the R_SMALL4 padding, this caused ray tracing failure
// on OS X (X11) with a flat ObjectCGO (zmin == zmax).
I->min_box[0] = xmin - R_SMALL4;
I->min_box[1] = ymin - R_SMALL4;
I->min_box[2] = zmin - R_SMALL4;
I->max_box[0] = xmax + R_SMALL4;
I->max_box[1] = ymax + R_SMALL4;
I->max_box[2] = zmax + R_SMALL4;
}
int RayTransformFirst(CRay * I, int perspective, int identity)
{
CBasis *basis0, *basis1;
CPrimitive *prm;
int a;
float *v0;
int backface_cull;
int ok = true;
int two_sided_lighting = SettingGetGlobal_b(I->G, cSetting_two_sided_lighting);
if(two_sided_lighting<0) {
if(SettingGetGlobal_i(I->G, cSetting_surface_cavity_mode))
two_sided_lighting = true;
else
two_sided_lighting = false;
}
backface_cull = SettingGetGlobal_b(I->G, cSetting_backface_cull);
if(two_sided_lighting ||
(SettingGetGlobal_i(I->G, cSetting_transparency_mode) == 1) ||
(SettingGetGlobal_i(I->G, cSetting_ray_interior_color) != -1) || I->CheckInterior)
backface_cull = 0;
basis0 = I->Basis;
basis1 = I->Basis + 1;
if (ok){
VLACacheSize(I->G, basis1->Vertex, float, 3 * basis0->NVertex, 1, cCache_basis_vertex);
CHECKOK(ok, basis1->Vertex);
}
if (ok){
VLACacheSize(I->G, basis1->Normal, float, 3 * basis0->NNormal, 1, cCache_basis_normal);
CHECKOK(ok, basis1->Normal);
}
if (ok){
VLACacheSize(I->G, basis1->Precomp, float, 3 * basis0->NNormal, 1,
cCache_basis_precomp);
CHECKOK(ok, basis1->Precomp);
}
if (ok){
VLACacheSize(I->G, basis1->Vert2Normal, int, basis0->NVertex, 1,
cCache_basis_vert2normal);
CHECKOK(ok, basis1->Vert2Normal);
}
if (ok){
VLACacheSize(I->G, basis1->Radius, float, basis0->NVertex, 1, cCache_basis_radius);
CHECKOK(ok, basis1->Radius);
}
if (ok){
VLACacheSize(I->G, basis1->Radius2, float, basis0->NVertex, 1, cCache_basis_radius2);
CHECKOK(ok, basis1->Radius2);
}
ok &= !I->G->Interrupt;
if (ok){
if(identity) {
UtilCopyMem(basis1->Vertex, basis0->Vertex, basis0->NVertex * sizeof(float) * 3);
} else {
RayApplyMatrix33(basis0->NVertex, (float3 *) basis1->Vertex,
I->ModelView, (float3 *) basis0->Vertex);
}
}
ok &= !I->G->Interrupt;
if (ok){
memcpy(basis1->Radius, basis0->Radius, basis0->NVertex * sizeof(float));
memcpy(basis1->Radius2, basis0->Radius2, basis0->NVertex * sizeof(float));
memcpy(basis1->Vert2Normal, basis0->Vert2Normal, basis0->NVertex * sizeof(int));
}
ok &= !I->G->Interrupt;
if (ok){
basis1->MaxRadius = basis0->MaxRadius;
basis1->MinVoxel = basis0->MinVoxel;
basis1->NVertex = basis0->NVertex;
}
ok &= !I->G->Interrupt;
if (ok){
if(identity) {
UtilCopyMem(basis1->Normal, basis0->Normal, basis0->NNormal * sizeof(float) * 3);
} else {
RayTransformNormals33(basis0->NNormal, (float3 *) basis1->Normal,
I->ModelView, (float3 *) basis0->Normal);
}
basis1->NNormal = basis0->NNormal;
}
ok &= !I->G->Interrupt;
if(perspective) {
for(a = 0; ok && a < I->NPrimitive; a++) {
prm = I->Primitive + a;
prm = I->Primitive + a;
switch (prm->type) {
case cPrimTriangle:
case cPrimCharacter:
BasisTrianglePrecomputePerspective(basis1->Vertex + prm->vert * 3,
basis1->Vertex + prm->vert * 3 + 3,
basis1->Vertex + prm->vert * 3 + 6,
basis1->Precomp +
basis1->Vert2Normal[prm->vert] * 3);
break;
}
ok &= !I->G->Interrupt;
}
} else {
for(a = 0; ok && a < I->NPrimitive; a++) {
prm = I->Primitive + a;
switch (prm->type) {
case cPrimTriangle:
case cPrimCharacter:
BasisTrianglePrecompute(basis1->Vertex + prm->vert * 3,
basis1->Vertex + prm->vert * 3 + 3,
basis1->Vertex + prm->vert * 3 + 6,
basis1->Precomp + basis1->Vert2Normal[prm->vert] * 3);
v0 = basis1->Normal + (basis1->Vert2Normal[prm->vert] * 3 + 3);
prm->cull = (!identity) && backface_cull && ((v0[2] < 0.0F) && (v0[5] < 0.0F)
&& (v0[8] < 0.0F));
break;
case cPrimCone:
case cPrimSausage:
case cPrimCylinder:
BasisCylinderSausagePrecompute(basis1->Normal +
basis1->Vert2Normal[prm->vert] * 3,
basis1->Precomp +
basis1->Vert2Normal[prm->vert] * 3);
break;
}
ok &= !I->G->Interrupt;
}
}
return ok;
}
/*========================================================================*/
static int RayTransformBasis(CRay * I, CBasis * basis1, int group_id)
{
CBasis *basis0;
int a;
float *v0, *v1;
CPrimitive *prm;
int ok = true;
basis0 = I->Basis + 1;
VLACacheSize(I->G, basis1->Vertex, float, 3 * basis0->NVertex, group_id,
cCache_basis_vertex);
CHECKOK(ok, basis1->Vertex);
if (ok)
VLACacheSize(I->G, basis1->Normal, float, 3 * basis0->NNormal, group_id,
cCache_basis_normal);
CHECKOK(ok, basis1->Normal);
if (ok)
VLACacheSize(I->G, basis1->Precomp, float, 3 * basis0->NNormal, group_id,
cCache_basis_precomp);
CHECKOK(ok, basis1->Precomp);
if (ok)
VLACacheSize(I->G, basis1->Vert2Normal, int, basis0->NVertex, group_id,
cCache_basis_vert2normal);
CHECKOK(ok, basis1->Vert2Normal);
if (ok)
VLACacheSize(I->G, basis1->Radius, float, basis0->NVertex, group_id,
cCache_basis_radius);
CHECKOK(ok, basis1->Radius);
if (ok)
VLACacheSize(I->G, basis1->Radius2, float, basis0->NVertex, group_id,
cCache_basis_radius2);
CHECKOK(ok, basis1->Radius2);
v0 = basis0->Vertex;
v1 = basis1->Vertex;
for(a = 0; ok && a < basis0->NVertex; a++) {
matrix_transform33f3f(basis1->Matrix, v0, v1);
v0 += 3;
v1 += 3;
basis1->Radius[a] = basis0->Radius[a];
basis1->Radius2[a] = basis0->Radius2[a];
basis1->Vert2Normal[a] = basis0->Vert2Normal[a];
}
if (ok){
v0 = basis0->Normal;
v1 = basis1->Normal;
}
for(a = 0; ok && a < basis0->NNormal; a++) {
matrix_transform33f3f(basis1->Matrix, v0, v1);
v0 += 3;
v1 += 3;
}
if (ok){
basis1->MaxRadius = basis0->MaxRadius;
basis1->MinVoxel = basis0->MinVoxel;
basis1->NVertex = basis0->NVertex;
basis1->NNormal = basis0->NNormal;
}
for(a = 0; ok && a < I->NPrimitive; a++) {
prm = I->Primitive + a;
switch (prm->type) {
case cPrimTriangle:
case cPrimCharacter:
BasisTrianglePrecompute(basis1->Vertex + prm->vert * 3,
basis1->Vertex + prm->vert * 3 + 3,
basis1->Vertex + prm->vert * 3 + 6,
basis1->Precomp + basis1->Vert2Normal[prm->vert] * 3);
break;
case cPrimCone:
case cPrimSausage:
case cPrimCylinder:
BasisCylinderSausagePrecompute(basis1->Normal + basis1->Vert2Normal[prm->vert] * 3,
basis1->Precomp +
basis1->Vert2Normal[prm->vert] * 3);
break;
}
}
return ok;
}
/*========================================================================*/
void RayRenderTest(CRay * I, int width, int height, float front, float back, float fov)
{
PRINTFB(I->G, FB_Ray, FB_Details)
" RayRenderTest: obtained %i graphics primitives.\n", I->NPrimitive ENDFB(I->G);
}
/*========================================================================*/
G3dPrimitive *RayRenderG3d(CRay * I, int width, int height,
float front, float back, float fov, int quiet)
{
/* generate a rendering stream for Miguel's G3d java rendering engine */
float scale_x, scale_y;
int shift_x, shift_y;
float *d;
CBasis *base;
CPrimitive *prim;
float *vert;
float vert2[3];
int a;
G3dPrimitive *jprim = VLAlloc(G3dPrimitive, 10000), *jp;
int n_jp = 0;
#define convert_r(r) 2*(int)(r*scale_x);
#define convert_x(x) shift_x + (int)(x*scale_x);
#define convert_y(y) height - (shift_y + (int)(y*scale_y));
#define convert_z(z) -(int)((z+front)*scale_x);
#define convert_col(c) (0xFF000000 | (((int)(c[0]*255.0))<<16) | (((int)(c[1]*255.0))<<8) | (((int)(c[2]*255.0))))
RayExpandPrimitives(I);
RayTransformFirst(I, 0, false);
if(!quiet) {
PRINTFB(I->G, FB_Ray, FB_Details)
" RayRenderG3d: processed %i graphics primitives.\n", I->NPrimitive ENDFB(I->G);
}
base = I->Basis + 1;
/* always orthoscopic */
/* front should give a zero Z,
-I->Range[0] should be off the right hand size
I->Range[1] should be off the top */
scale_x = width / I->Range[0];
scale_y = height / I->Range[1];
shift_x = width / 2;
shift_y = height / 2;
for(a = 0; a < I->NPrimitive; a++) {
prim = I->Primitive + a;
vert = base->Vertex + 3 * (prim->vert);
switch (prim->type) {
case cPrimSphere:
VLACheck(jprim, G3dPrimitive, n_jp);
jp = jprim + n_jp;
jp->op = 1;
jp->r = convert_r(prim->r1);
jp->x1 = convert_x(vert[0]);
jp->y1 = convert_y(vert[1]);
jp->z1 = convert_z(vert[2]);
jp->c = convert_col(prim->c1);
n_jp++;
break;
case cPrimSausage:
VLACheck(jprim, G3dPrimitive, n_jp);
d = base->Normal + 3 * base->Vert2Normal[prim->vert];
scale3f(d, prim->l1, vert2);
add3f(vert, vert2, vert2);
jp = jprim + n_jp;
jp->op = 3;
jp->r = convert_r(prim->r1);
jp->x1 = convert_x(vert[0]);
jp->y1 = convert_y(vert[1]);
jp->z1 = convert_z(vert[2]);
jp->x2 = convert_x(vert2[0]);
jp->y2 = convert_y(vert2[1]);
jp->z2 = convert_z(vert2[2]);
jp->c = convert_col(prim->c1);
n_jp++;
break;
case cPrimTriangle:
VLACheck(jprim, G3dPrimitive, n_jp);
jp = jprim + n_jp;
jp->op = 2;
jp->x1 = convert_x(vert[0]);
jp->y1 = convert_y(vert[1]);
jp->z1 = convert_z(vert[2]);
jp->x2 = convert_x(vert[3]);
jp->y2 = convert_y(vert[4]);
jp->z2 = convert_z(vert[5]);
jp->x3 = convert_x(vert[6]);
jp->y3 = convert_y(vert[7]);
jp->z3 = convert_z(vert[8]);
jp->c = convert_col(prim->c1);
n_jp++;
break;
}
}
VLASize(jprim, G3dPrimitive, n_jp);
return jprim;
}
void RayRenderVRML1(CRay * I, int width, int height,
char **vla_ptr, float front, float back,
float fov, float angle, float z_corr)
{
char *vla = *vla_ptr;
ov_size cc = 0; /* character count */
OrthoLineType buffer;
RayExpandPrimitives(I);
RayTransformFirst(I, 0, false);
strcpy(buffer, "#VRML V1.0 ascii\n\n");
UtilConcatVLA(&vla, &cc, buffer);
UtilConcatVLA(&vla, &cc, "MaterialBinding { value OVERALL }\n");
sprintf(buffer,
"Material {\n ambientColor 0 0 0\n diffuseColor 1 1 1\n specularColor 1 1 1\nshininess 0.2\n}\n");
UtilConcatVLA(&vla, &cc, buffer);
{
int a;
CPrimitive *prim;
float *vert;
CBasis *base = I->Basis + 1;
UtilConcatVLA(&vla, &cc, "Separator {\n");
UtilConcatVLA(&vla, &cc, "MatrixTransform {\n");
UtilConcatVLA(&vla, &cc, "matrix 1.0 0.0 0.0 0.0\n");
UtilConcatVLA(&vla, &cc, " 0.0 1.0 0.0 0.0\n");
UtilConcatVLA(&vla, &cc, " 0.0 0.0 1.0 0.0\n");
sprintf(buffer, " %8.6f %8.6f %8.6f 1.0\n",
(I->Volume[0] + I->Volume[1]) / 2, (I->Volume[2] + I->Volume[3]) / 2, 0.0F);
UtilConcatVLA(&vla, &cc, buffer);
UtilConcatVLA(&vla, &cc, "}\n");
for(a = 0; a < I->NPrimitive; a++) {
prim = I->Primitive + a;
vert = base->Vertex + 3 * (prim->vert);
switch (prim->type) {
case cPrimSphere:
sprintf(buffer,
"Material {\ndiffuseColor %6.4f %6.4f %6.4f\n}\n\n",
prim->c1[0], prim->c1[1], prim->c1[2]);
UtilConcatVLA(&vla, &cc, buffer);
UtilConcatVLA(&vla, &cc, "Separator {\n");
sprintf(buffer,
"Transform {\ntranslation %8.6f %8.6f %8.6f\nscaleFactor %8.6f %8.6f %8.6f\n}\n",
vert[0], vert[1], vert[2] - z_corr, prim->r1, prim->r1, prim->r1);
UtilConcatVLA(&vla, &cc, buffer);
sprintf(buffer, "Sphere {}\n");
UtilConcatVLA(&vla, &cc, buffer);
UtilConcatVLA(&vla, &cc, "}\n\n");
break;
case cPrimCylinder:
case cPrimSausage:
case cPrimCone:
break;
case cPrimTriangle:
break;
}
}
UtilConcatVLA(&vla, &cc, "}\n");
}
*vla_ptr = vla;
}
int TriangleReverse(CPrimitive * p)
{
float s1[3], s2[3], n0[3];
subtract3f(p->v1, p->v2, s1);
subtract3f(p->v3, p->v2, s2);
cross_product3f(s1, s2, n0);
if(dot_product3f(p->n0, n0) < 0.0F)
return 0;
else
return 1;
}
void RayRenderVRML2(CRay * I, int width, int height,
char **vla_ptr, float front, float back,
float fov, float angle, float z_corr)
{
/*
From: pymol-users-admin@lists.sourceforge.net on behalf of Chris Want
Sent: Tuesday, February 07, 2006 1:47 PM
To: pymol-users@lists.sourceforge.net
Subject: [PyMOL] VRML patch
Hi Warren,
I took your advice and modified the RayRenderVRML2() function to
support triangles. I also threw out the sphere code that was already
there and rewrote it (the code there was for VRML1, not
VRML2). While I was at it, I also implemented export for cylinders
and sausages.
The code in the attached patch (diff-ed against cvs, and tested with
two VRML2 readers) can be regarded as being in the public domain.
Regards,
Chris
cwant_at_ualberta.ca
*/
char *vla = *vla_ptr;
ov_size cc = 0; /* character count */
OrthoLineType buffer;
float mid[3]; /*, wid[3]; */
float h_fov = cPI * (fov * width) / (180 * height);
int identity = (SettingGetGlobal_i(I->G, cSetting_geometry_export_mode) == 1);
RayExpandPrimitives(I);
RayTransformFirst(I, 0, identity);
RayComputeBox(I);
/*
mid[0] = (I->max_box[0] + I->min_box[0]) / 2.0;
mid[1] = (I->max_box[1] + I->min_box[1]) / 2.0;
mid[2] = (I->max_box[2] + I->min_box[2]) / 2.0;
wid[0] = (I->max_box[0] - I->min_box[0]);
wid[1] = (I->max_box[1] - I->min_box[1]);
wid[2] = (I->max_box[2] - I->min_box[2]);
*/
copy3f(I->Pos, mid);
UtilConcatVLA(&vla, &cc, "#VRML V2.0 utf8\n" /* WLD: most VRML2 readers req. utf8 */
"\n");
if(!identity) {
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 */
"}\n"
/* WLD: only write the viewpoint which matches PyMOL
"Viewpoint {\n"
" position %6.8f 0 0\n"
" orientation 0 1 0 1.570796\n"
" description \"X view\"\n"
"}\n"
"Viewpoint {\n"
" position 0 %6.8f 0\n"
" orientation 0 -0.707106 -0.7071061 3.141592\n"
" description \"Y view\"\n"
"}\n" */ ,
-z_corr, /* *0.96646 for some reason, PyMOL and C4D cameras differ by about 3.5% ... */
h_fov
/*(wid[2] + wid[1]),
(wid[0] + wid[1]),
(wid[1] + wid[2]) */
);
UtilConcatVLA(&vla, &cc, buffer);
}
if(!identity) {
float light[3];
auto lightv = SettingGet<const float*>(I->G, cSetting_light);
copy3f(lightv, light);
normalize3f(light);
sprintf(buffer,
"DirectionalLight {\n"
" direction %8.6f %8.6f %8.3f\n" "}\n", light[0], light[1], light[2]);
UtilConcatVLA(&vla, &cc, buffer);
}
UtilConcatVLA(&vla, &cc,
"NavigationInfo {\n" " headlight TRUE\n" " type \"EXAMINE\"\n" "}\n");
{
int a, b;
CPrimitive *prim;
float *vert;
int mesh_obj = false, mesh_start = 0;
CBasis *base = I->Basis + 1;
for(a = 0; a < I->NPrimitive; a++) {
prim = I->Primitive + a;
vert = base->Vertex + 3 * (prim->vert);
if(prim->type == cPrimTriangle) {
if(!mesh_obj) {
/* start mesh */
mesh_start = a;
UtilConcatVLA(&vla, &cc,
"Shape {\n"
" appearance Appearance {\n"
" material Material { diffuseColor 1.0 1.0 1.0 }\n"
" }\n"
" geometry IndexedFaceSet {\n"
" coord Coordinate {\n" " point [\n");
mesh_obj = true;
}
} else if(mesh_obj) {
CPrimitive *cprim;
int tri = 0;
/* output connectivity */
UtilConcatVLA(&vla, &cc, " ]\n" " }\n" " coordIndex [\n");
for(b = mesh_start; b < a; b++) {
cprim = I->Primitive + b;
if(TriangleReverse(cprim))
sprintf(buffer, "%d %d %d -1,\n", tri, tri + 2, tri + 1);
else
sprintf(buffer, "%d %d %d -1,\n", tri, tri + 1, tri + 2);
UtilConcatVLA(&vla, &cc, buffer);
tri += 3;
}
/* output vertex colors */
UtilConcatVLA(&vla, &cc,
" ]\n"
" colorPerVertex TRUE\n" " color Color {\n" " color [\n");
for(b = mesh_start; b < a; b++) {
cprim = I->Primitive + b;
sprintf(buffer,
"%6.4f %6.4f %6.4f,\n"
"%6.4f %6.4f %6.4f,\n"
"%6.4f %6.4f %6.4f,\n",
cprim->c1[0], cprim->c1[1], cprim->c1[2],
cprim->c2[0], cprim->c2[1], cprim->c2[2],
cprim->c3[0], cprim->c3[1], cprim->c3[2]);
UtilConcatVLA(&vla, &cc, buffer);
}
/* output vertex normals */
UtilConcatVLA(&vla, &cc,
" ] } \n"
" normalPerVertex TRUE\n" " normal Normal {\n" " vector [\n");
for(b = mesh_start; b < a; b++) {
cprim = I->Primitive + b;
{
float *norm = base->Normal + 3 * base->Vert2Normal[cprim->vert];
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 */
norm[6], norm[7], norm[8], /* transformed cprim->n2 */
norm[9], norm[10], norm[11]); /* transformed cprim->n3 */
UtilConcatVLA(&vla, &cc, buffer);
}
}
UtilConcatVLA(&vla, &cc, " ] }\n" " normalIndex [ \n");
tri = 0;
for(b = mesh_start; b < a; b++) {
cprim = I->Primitive + b;
if(TriangleReverse(cprim))
sprintf(buffer, "%d %d %d -1,\n", tri, tri + 2, tri + 1);
else
sprintf(buffer, "%d %d %d -1,\n", tri, tri + 1, tri + 2);
UtilConcatVLA(&vla, &cc, buffer);
tri += 3;
}
/* close mesh */
UtilConcatVLA(&vla, &cc, " ] \n" " }\n" "}\n");
mesh_obj = false;
}
switch (prim->type) {
case cPrimSphere:
sprintf(buffer,
"Transform {\n"
" translation %8.6f %8.6f %8.6f\n"
" children Shape {\n"
" geometry Sphere { radius %8.6f }\n"
" appearance Appearance {\n"
" material Material { diffuseColor %6.4f %6.4f %6.4f \n"
" specularColor 0.8 0.8 0.8 \n"
" shininess 0.8 }\n"
" }\n"
" }\n"
"}\n",
vert[0] - mid[0],
vert[1] - mid[1],
vert[2] - mid[2], prim->r1, prim->c1[0], prim->c1[1], prim->c1[2]);
UtilConcatVLA(&vla, &cc, buffer);
break;
case cPrimCone:
/* TO DO */
break;
case cPrimCylinder:
case cPrimSausage:
{
float *d, vert2[3], axis[3], angle;
OrthoLineType geometry;
/* find the axis and angle that will rotate the y axis onto
* the direction of the length of the cylinder
*/
d = base->Normal + 3 * base->Vert2Normal[prim->vert];
if((d[0] * d[0] + d[2] * d[2]) < 0.000001) {
/* parallel with y */
axis[0] = 1.0;
axis[1] = 0.0;
axis[2] = 0.0;
if(d[1] > 0) {
angle = 0.0;
} else {
angle = cPI;
}
} else {
axis[0] = d[2];
axis[1] = 0.0;
axis[2] = -d[0];
normalize3f(axis);
angle = d[1];
if(angle > 1.0)
angle = 1.0;
else if(angle < -1.0)
angle = -1.0;
angle = acos(angle);
}
/* vrml cylinders have origin in middle, not tip, that is why we
* use prim->l1/2
*/
scale3f(d, prim->l1 / 2, vert2);
add3f(vert, vert2, vert2);
if(prim->type == cPrimSausage) {
OrthoLineType geom_add;
sprintf(geometry,
" Shape {\n"
" geometry Cylinder {\n"
" radius %8.6f\n"
" height %8.6f\n"
" bottom FALSE\n"
" top FALSE\n"
" }\n"
" appearance Appearance {\n"
" material Material { diffuseColor %6.4f %6.4f %6.4f \n"
" specularColor 0.8 0.8 0.8 \n"
" shininess 0.8 }\n"
" }\n",
prim->r1, prim->l1,
(prim->c1[0] + prim->c2[0]) / 2,
(prim->c1[1] + prim->c2[1]) / 2, (prim->c1[2] + prim->c2[2]) / 2);
/* WLD: format string split to comply with ISO C89 standards */
sprintf(geom_add,
" }\n"
" Transform {\n"
" translation 0.0 %8.6f 0.0\n"
" children Shape {\n"
" geometry Sphere { radius %8.6f }\n"
" appearance Appearance {\n"
" material Material { diffuseColor %6.4f %6.4f %6.4f \n"
" specularColor 0.8 0.8 0.8 \n"
" shininess 0.8 }\n"
" }\n"
" }\n"
" }\n", prim->l1 / 2, prim->r1, prim->c1[0], prim->c1[1], prim->c1[2]
);
strcat(geometry, geom_add);
/* WLD: format string split to comply with ISO C89 standards */
sprintf(geom_add,
" Transform {\n"
" translation 0.0 %8.6f 0.0\n"
" children Shape {\n"
" geometry Sphere { radius %8.6f }\n"
" appearance Appearance {\n"
" material Material { diffuseColor %6.4f %6.4f %6.4f \n"
" specularColor 0.8 0.8 0.8 \n"
" shininess 0.8 }\n"
" }\n"
" }\n"
" }\n",
-prim->l1 / 2, prim->r1, prim->c2[0], prim->c2[1], prim->c2[2]);
strcat(geometry, geom_add);
} else {
sprintf(geometry,
" Shape {\n"
" geometry Cylinder {\n"
" radius %8.6f\n"
" height %8.6f\n"
" }\n"
" appearance Appearance {\n"
" material Material { diffuseColor %6.4f %6.4f %6.4f \n"
" specularColor 0.8 0.8 0.8 \n"
" shininess 0.8 }\n"
" }\n"
" }\n",
prim->r1, prim->l1,
(prim->c1[0] + prim->c2[0]) / 2,
(prim->c1[1] + prim->c2[1]) / 2, (prim->c1[2] + prim->c2[2]) / 2);
}
sprintf(buffer,
"Transform {\n"
" translation %8.6f %8.6f %8.6f\n"
" rotation %8.6f %8.6f %8.6f %8.6f\n"
" children [\n"
"%s"
" ]\n"
"}\n",
vert2[0] - mid[0],
vert2[1] - mid[1],
vert2[2] - mid[2], axis[0], axis[1], axis[2], angle, geometry);
UtilConcatVLA(&vla, &cc, buffer);
}
break;
case cPrimTriangle:
/* output coords. connectivity and vertex colors handled above/below */
sprintf(buffer,
"%8.6f %8.6f %8.6f,\n"
"%8.6f %8.6f %8.6f,\n"
"%8.6f %8.6f %8.6f,\n",
vert[0] - mid[0], vert[1] - mid[1], vert[2] - mid[2],
vert[3] - mid[0], vert[4] - mid[1], vert[5] - mid[2],
vert[6] - mid[0], vert[7] - mid[1], vert[8] - mid[2]);
UtilConcatVLA(&vla, &cc, buffer);
break;
}
}
if(mesh_obj) {
CBasis *base = I->Basis + 1;
CPrimitive *cprim;
int tri = 0;
/* output connectivity */
UtilConcatVLA(&vla, &cc, " ]\n" " }\n" " coordIndex [\n");
for(b = mesh_start; b < a; b++) {
cprim = I->Primitive + b;
if(TriangleReverse(cprim))
sprintf(buffer, "%d %d %d -1,\n", tri, tri + 2, tri + 1);
else
sprintf(buffer, "%d %d %d -1,\n", tri, tri + 1, tri + 2);
UtilConcatVLA(&vla, &cc, buffer);
tri += 3;
}
/* output vertex colors */
UtilConcatVLA(&vla, &cc,
" ]\n" " colorPerVertex TRUE\n" " color Color {\n" " color [\n");
for(b = mesh_start; b < a; b++) {
cprim = I->Primitive + b;
sprintf(buffer,
"%6.4f %6.4f %6.4f,\n"
"%6.4f %6.4f %6.4f,\n"
"%6.4f %6.4f %6.4f,\n",
cprim->c1[0], cprim->c1[1], cprim->c1[2],
cprim->c2[0], cprim->c2[1], cprim->c2[2],
cprim->c3[0], cprim->c3[1], cprim->c3[2]);
UtilConcatVLA(&vla, &cc, buffer);
}
/* output vertex normals */
UtilConcatVLA(&vla, &cc,
" ] } \n"
" normalPerVertex TRUE\n" " normal Normal {\n" " vector [\n");
for(b = mesh_start; b < a; b++) {
cprim = I->Primitive + b;
{
float *norm = base->Normal + 3 * base->Vert2Normal[cprim->vert];
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 */
norm[6], norm[7], norm[8], /* transformed cprim->n2 */
norm[9], norm[10], norm[11]); /* transformed cprim->n3 */
UtilConcatVLA(&vla, &cc, buffer);
}
}
UtilConcatVLA(&vla, &cc, " ] }\n" " normalIndex [ \n");
tri = 0;
for(b = mesh_start; b < a; b++) {
cprim = I->Primitive + b;
if(TriangleReverse(cprim))
sprintf(buffer, "%d %d %d -1,\n", tri, tri + 2, tri + 1);
else
sprintf(buffer, "%d %d %d -1,\n", tri, tri + 1, tri + 2);
UtilConcatVLA(&vla, &cc, buffer);
tri += 3;
}
/* close mesh */
UtilConcatVLA(&vla, &cc, " ] \n" " }\n" "}\n");
mesh_obj = false;
}
}
*vla_ptr = vla;
}
/* simple write-once/read-many hash for float-3/4 vectors */
#define VECTOR_HASH_MASK 0xFFFF
typedef struct {
float key[4];
int value;
int next; /* 1-based offsets, 0 = terminal */
} VectorHashElem;
typedef struct {
int first[VECTOR_HASH_MASK + 1];
VectorHashElem *elem;
int size;
} VectorHash;
static void VectorHash_Free(VectorHash * I)
{
if(I) {
VLAFreeP(I->elem);
}
FreeP(I);
}
static VectorHash *VectorHash_New(void)
{
VectorHash *I = Calloc(VectorHash, 1);
if(I) {
I->elem = VLACalloc(VectorHashElem, 100);
if(!I->elem) {
VectorHash_Free(I);
I = NULL;
}
}
return I;
}
static int VectorHash_GetOrSetKeyValue(VectorHash * I, float *key, float *alpha,
int *value)
{
unsigned int hash;
/* returns non-zero if the entry is new */
{
unsigned int a, b, c;
a = ((unsigned int *) key)[0];
b = ((unsigned int *) key)[1];
c = ((unsigned int *) key)[2];
/* Robert Jenkin's 96 to 32 bit hash (public domain)
this is probably way overkill */
a = a - b;
a = a - c;
a = a ^ (c >> 13);
b = b - c;
b = b - a;
b = b ^ (a << 8);
c = c - a;
c = c - b;
c = c ^ (b >> 13);
a = a - b;
a = a - c;
a = a ^ (c >> 12);
b = b - c;
b = b - a;
b = b ^ (a << 16);
c = c - a;
c = c - b;
c = c ^ (b >> 5);
a = a - b;
a = a - c;
a = a ^ (c >> 3);
b = b - c;
b = b - a;
b = b ^ (a << 10);
c = c - a;
c = c - b;
c = c ^ (b >> 15);
/* mix in the fourth key (if present) */
if(alpha) {
unsigned int d = *((unsigned int *) alpha);
c = c + d;
}
/* fold those 32 bits to 16 */
c ^= (c >> 16);
/* apply mask */
hash = c & VECTOR_HASH_MASK;
}
{
int offset = I->first[hash];
while(offset) {
VectorHashElem *elem = I->elem + offset;
float *v = elem->key;
if((v[0] == key[0]) && (v[1] == key[1]) && (v[2] == key[2])) {
if((!alpha) || (*alpha == v[3])) {
*value = elem->value; /* matched, so return value */
return 0; /* key/value exists */
}
}
offset = elem->next;
}
/* not matched -- add new key/value */
if(VLACheck(I->elem, VectorHashElem, ++(I->size))) {
VectorHashElem *elem = I->elem + I->size;
elem->next = I->first[hash];
I->first[hash] = I->size;
copy3f(key, elem->key);
if(alpha)
elem->key[3] = *alpha;
elem->value = *value;
return 1; /* inform caller */
} else {
I->size--;
return -1;
}
}
}
static void unique_vector_add(VectorHash * vh, float *vector,
float *vector_array, int *vector_count,
int *index_array, int *index_count)
{
int index = *vector_count;
switch (VectorHash_GetOrSetKeyValue(vh, vector, NULL, &index)) {
case 1:
{
float *vector_slot = vector_array + 3 * (*vector_count);
copy3f(vector, vector_slot);
(*vector_count)++;
}
/* INTENTIONAL omission of break */
case 0:
index_array[(*index_count)++] = index;
break;
}
}
static void unique_color_add(VectorHash * vh, float *vector,
float *vector_array, int *vector_count,
int *index_array, int *index_count, float alpha)
{
int index = *vector_count;
switch (VectorHash_GetOrSetKeyValue(vh, vector, &alpha, &index)) {
case 1:
{
float *vector_slot = vector_array + 4 * (*vector_count); /* NOTE 4x spacing */
copy3f(vector, vector_slot);
vector_slot[3] = alpha;
(*vector_count)++;
}
/* INTENTIONAL omission of break */
case 0:
index_array[(*index_count)++] = index;
break;
}
}
#define noIDTF_COLOR
typedef struct {
int face_count;
int position_count;
int normal_count;
int *face_position_list;
int *face_normal_list;
int *face_shading_list;
float *model_position_list;
float *model_normal_list;
VectorHash *position_hash;
VectorHash *normal_hash;
int color_count;
int *face_color_list;
float *model_diffuse_color_list;
VectorHash *color_hash;
} IdtfResourceMesh;
typedef struct {
float *color_list;
int color_count;
VectorHash *color_hash;
} IdtfMaterial;
static ov_size idtf_dump_file_header(char **vla, ov_size cnt)
{
UtilConcatVLA(vla, &cnt, "FILE_FORMAT \"IDTF\"\nFORMAT_VERSION 100\n\n");
UtilConcatVLA(vla, &cnt, "NODE \"VIEW\" {\n");
UtilConcatVLA(vla, &cnt, "\tNODE_NAME \"DefaultView\"\n");
UtilConcatVLA(vla, &cnt, "\tPARENT_LIST {\n");
UtilConcatVLA(vla, &cnt, "\t\tPARENT_COUNT 1\n");
UtilConcatVLA(vla, &cnt, "\t\tPARENT 0 {\n\t\t\tPARENT_NAME \"<NULL>\"\n");
UtilConcatVLA(vla, &cnt, "\t\t\tPARENT_TM {\n");
UtilConcatVLA(vla, &cnt, "\t\t\t\t1.000000 0.000000 0.000000 0.0\n");
UtilConcatVLA(vla, &cnt, "\t\t\t\t0.000000 1.000000 0.000000 0.0\n");
UtilConcatVLA(vla, &cnt, "\t\t\t\t0.000000 0.000000 1.000000 0.0\n");
UtilConcatVLA(vla, &cnt, "\t\t\t\t0.000000 0.000000 0.000000 1.0\n");
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
UtilConcatVLA(vla, &cnt, "\t\t}\n");
UtilConcatVLA(vla, &cnt, "\t}\n");
UtilConcatVLA(vla, &cnt, "\tRESOURCE_NAME \"SceneViewResource\"\n");
UtilConcatVLA(vla, &cnt, "\tVIEW_DATA {\n");
UtilConcatVLA(vla, &cnt, "\t\tVIEW_TYPE \"PERSPECTIVE\"\n");
UtilConcatVLA(vla, &cnt, "\t\tVIEW_PROJECTION 34.515877\n");
UtilConcatVLA(vla, &cnt, "\t}\n");
UtilConcatVLA(vla, &cnt, "}\n\n");
UtilConcatVLA(vla, &cnt, "NODE \"LIGHT\"\n");
UtilConcatVLA(vla, &cnt, "{\n");
UtilConcatVLA(vla, &cnt, "\tNODE_NAME \"Omni01\"\n");
UtilConcatVLA(vla, &cnt, "\tPARENT_LIST {\n");
UtilConcatVLA(vla, &cnt, "\t\tPARENT_COUNT 1\n");
UtilConcatVLA(vla, &cnt, "\t\tPARENT 0 {\n");
UtilConcatVLA(vla, &cnt, "\t\t\tPARENT_NAME \"<NULL>\"\n");
UtilConcatVLA(vla, &cnt, "\t\t\tPARENT_TM {\n");
UtilConcatVLA(vla, &cnt, "\t\t\t\t1.000000 0.000000 0.000000 0.000000\n");
UtilConcatVLA(vla, &cnt, "\t\t\t\t0.000000 1.000000 0.000000 0.000000\n");
UtilConcatVLA(vla, &cnt, "\t\t\t\t0.000000 0.000000 1.000000 0.000000\n");
UtilConcatVLA(vla, &cnt, "\t\t\t\t50.000000 -50.00000 50.000000 1.000000\n");
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
UtilConcatVLA(vla, &cnt, "\t\t}\n");
UtilConcatVLA(vla, &cnt, "\t}\n");
UtilConcatVLA(vla, &cnt, "\tRESOURCE_NAME \"DefaultPointLight\"\n");
UtilConcatVLA(vla, &cnt, "}\n\n");
return cnt;
}
static ov_size idtf_dump_model_nodes(char **vla, ov_size cnt,
IdtfResourceMesh * mesh_vla, int n_mesh)
{
int a;
IdtfResourceMesh *mesh = mesh_vla;
for(a = 0; a < n_mesh; a++) {
OrthoLineType buffer;
UtilConcatVLA(vla, &cnt, "NODE \"MODEL\" {\n");
sprintf(buffer, "\tNODE_NAME \"Mesh%d\"\n", a);
UtilConcatVLA(vla, &cnt, buffer);
UtilConcatVLA(vla, &cnt, "\tPARENT_LIST {\n");
UtilConcatVLA(vla, &cnt, "\t\tPARENT_COUNT 1\n");
UtilConcatVLA(vla, &cnt, "\t\tPARENT 0 {\n");
UtilConcatVLA(vla, &cnt, "\t\t\tPARENT_NAME \"<NULL>\"\n");
UtilConcatVLA(vla, &cnt, "\t\t\tPARENT_TM {\n");
UtilConcatVLA(vla, &cnt, "\t\t\t1.000000 0.000000 0.000000 0.0\n");
UtilConcatVLA(vla, &cnt, "\t\t\t0.000000 1.000000 0.000000 0.0\n");
UtilConcatVLA(vla, &cnt, "\t\t\t0.000000 0.000000 1.000000 0.0\n");
UtilConcatVLA(vla, &cnt, "\t\t\t0.000000 0.000000 0.000000 1.0\n");
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
UtilConcatVLA(vla, &cnt, "\t\t}\n");
UtilConcatVLA(vla, &cnt, "\t}\n");
sprintf(buffer, "\tRESOURCE_NAME \"Mesh%d\"\n", a);
UtilConcatVLA(vla, &cnt, buffer);
UtilConcatVLA(vla, &cnt, "}\n\n");
mesh++;
}
return cnt;
}
static ov_size idtf_dump_resource_header(char **vla, ov_size cnt)
{
UtilConcatVLA(vla, &cnt, "RESOURCE_LIST \"VIEW\" {\n");
UtilConcatVLA(vla, &cnt, "\tRESOURCE_COUNT 1\n");
UtilConcatVLA(vla, &cnt, "\tRESOURCE 0 {\n");
UtilConcatVLA(vla, &cnt, "\t\tRESOURCE_NAME \"SceneViewResource\"\n");
UtilConcatVLA(vla, &cnt, "\t\tVIEW_PASS_COUNT 1\n");
UtilConcatVLA(vla, &cnt, "\t\tVIEW_ROOT_NODE_LIST {\n");
UtilConcatVLA(vla, &cnt, "\t\t\tROOT_NODE 0 {\n");
UtilConcatVLA(vla, &cnt, "\t\t\t\tROOT_NODE_NAME \"<NULL>\"\n");
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
UtilConcatVLA(vla, &cnt, "\t\t}\n");
UtilConcatVLA(vla, &cnt, "\t}\n");
UtilConcatVLA(vla, &cnt, "}\n\n");
UtilConcatVLA(vla, &cnt, "RESOURCE_LIST \"LIGHT\" {\n");
UtilConcatVLA(vla, &cnt, "\tRESOURCE_COUNT 1\n");
UtilConcatVLA(vla, &cnt, "\tRESOURCE 0 {\n");
UtilConcatVLA(vla, &cnt, "\t\tRESOURCE_NAME \"DefaultPointLight\"\n");
UtilConcatVLA(vla, &cnt, "\t\tLIGHT_TYPE \"POINT\"\n");
UtilConcatVLA(vla, &cnt, "\t\tLIGHT_COLOR 1.000000 1.000000 1.000000\n");
UtilConcatVLA(vla, &cnt, "\t\tLIGHT_ATTENUATION 1.000000 0.000000 0.000000\n");
UtilConcatVLA(vla, &cnt, "\t\tLIGHT_INTENSITY 1.000000\n");
UtilConcatVLA(vla, &cnt, "\t}\n");
UtilConcatVLA(vla, &cnt, "}\n\n");
return cnt;
}
static ov_size idtf_dump_resources(char **vla, ov_size cnt,
IdtfResourceMesh * mesh_vla, int n_mesh,
IdtfMaterial * material)
{
{
OrthoLineType buffer;
int n_color = material->color_count;
UtilConcatVLA(vla, &cnt, "RESOURCE_LIST \"SHADER\" {\n");
sprintf(buffer, "\tRESOURCE_COUNT %d\n", n_color);
UtilConcatVLA(vla, &cnt, buffer);
{
int c;
for(c = 0; c < n_color; c++) {
sprintf(buffer, "\tRESOURCE %d {\n", c);
UtilConcatVLA(vla, &cnt, buffer);
sprintf(buffer, "\t\tRESOURCE_NAME \"Shader%06d\"\n", c);
UtilConcatVLA(vla, &cnt, buffer);
sprintf(buffer, "\t\tSHADER_MATERIAL_NAME \"Material%06d\"\n", c);
UtilConcatVLA(vla, &cnt, buffer);
UtilConcatVLA(vla, &cnt, "\t\tSHADER_ACTIVE_TEXTURE_COUNT 0\n");
UtilConcatVLA(vla, &cnt, "\t}\n");
}
}
UtilConcatVLA(vla, &cnt, "}\n\n");
}
{
OrthoLineType buffer;
int n_color = material->color_count;
UtilConcatVLA(vla, &cnt, "RESOURCE_LIST \"MATERIAL\" {\n");
sprintf(buffer, "\tRESOURCE_COUNT %d\n", n_color);
UtilConcatVLA(vla, &cnt, buffer);
{
int c;
float *fp = material->color_list;
for(c = 0; c < n_color; c++) {
sprintf(buffer, "\tRESOURCE %d {\n", c);
UtilConcatVLA(vla, &cnt, buffer);
sprintf(buffer, "\t\tRESOURCE_NAME \"Material%06d\"\n", c);
UtilConcatVLA(vla, &cnt, buffer);
sprintf(buffer, "\t\tMATERIAL_AMBIENT %0.6f %0.6f %0.6f\n",
fp[0] * 0, fp[1] * 0, fp[2] * 0);
UtilConcatVLA(vla, &cnt, buffer);
sprintf(buffer, "\t\tMATERIAL_DIFFUSE %0.6f %0.6f %0.6f\n", fp[0], fp[1], fp[2]);
UtilConcatVLA(vla, &cnt, buffer);
UtilConcatVLA(vla, &cnt, "\t\tMATERIAL_SPECULAR 0.750000 0.750000 0.750000\n");
sprintf(buffer, "\t\tMATERIAL_EMISSIVE %0.6f %0.6f %0.6f\n",
fp[0] * 0.13, fp[1] * 0.13, fp[2] * 0.13);
UtilConcatVLA(vla, &cnt, buffer);
UtilConcatVLA(vla, &cnt, "\t\tMATERIAL_REFLECTIVITY 0.40000\n");
sprintf(buffer, "\t\tMATERIAL_OPACITY %0.6f\n", fp[3]);
UtilConcatVLA(vla, &cnt, buffer);
UtilConcatVLA(vla, &cnt, "\t}\n");
fp += 4;
}
}
UtilConcatVLA(vla, &cnt, "}\n\n");
}
{
OrthoLineType buffer;
UtilConcatVLA(vla, &cnt, "RESOURCE_LIST \"MODEL\" {\n");
sprintf(buffer, "\tRESOURCE_COUNT %d\n", n_mesh);
UtilConcatVLA(vla, &cnt, buffer);
{
int a;
IdtfResourceMesh *mesh = mesh_vla;
for(a = 0; a < n_mesh; a++) {
sprintf(buffer, "\tRESOURCE %d {\n", a);
UtilConcatVLA(vla, &cnt, buffer);
sprintf(buffer, "\t\tRESOURCE_NAME \"Mesh%d\"\n", a);
UtilConcatVLA(vla, &cnt, buffer);
UtilConcatVLA(vla, &cnt, "\t\tMODEL_TYPE \"MESH\"\n");
UtilConcatVLA(vla, &cnt, "\t\tMESH {\n");
sprintf(buffer, "\t\t\tFACE_COUNT %d\n", mesh->face_count);
UtilConcatVLA(vla, &cnt, buffer);
sprintf(buffer, "\t\t\tMODEL_POSITION_COUNT %d\n", mesh->position_count);
UtilConcatVLA(vla, &cnt, buffer);
sprintf(buffer, "\t\t\tMODEL_NORMAL_COUNT %d\n", mesh->normal_count);
UtilConcatVLA(vla, &cnt, buffer);
#ifdef IDTF_COLOR
sprintf(buffer, "\t\t\tMODEL_DIFFUSE_COLOR_COUNT %d\n", mesh->color_count);
UtilConcatVLA(vla, &cnt, buffer);
sprintf(buffer, "\t\t\tMODEL_SPECULAR_COLOR_COUNT %d\n", mesh->color_count);
UtilConcatVLA(vla, &cnt, buffer);
#else
UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_DIFFUSE_COLOR_COUNT 0\n");
UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_SPECULAR_COLOR_COUNT 0\n");
#endif
UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_TEXTURE_COORD_COUNT 0\n");
UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_BONE_COUNT 0\n");
{
int n_color = material->color_count;
sprintf(buffer, "\t\t\tMODEL_SHADING_COUNT %d\n", n_color);
UtilConcatVLA(vla, &cnt, buffer);
UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_SHADING_DESCRIPTION_LIST {\n");
{
int c;
for(c = 0; c < n_color; c++) {
sprintf(buffer, "\t\t\t\tSHADING_DESCRIPTION %d {\n", c);
UtilConcatVLA(vla, &cnt, buffer);
UtilConcatVLA(vla, &cnt, "\t\t\t\tTEXTURE_LAYER_COUNT 0\n");
sprintf(buffer, "\t\t\t\tSHADER_ID %d\n", c + 1);
UtilConcatVLA(vla, &cnt, buffer);
UtilConcatVLA(vla, &cnt, "\t\t\t\t}\n");
}
}
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
}
{
int b;
int *ip = mesh->face_position_list;
UtilConcatVLA(vla, &cnt, "\t\t\tMESH_FACE_POSITION_LIST {\n");
for(b = 0; b < mesh->face_count; b++) {
sprintf(buffer, "\t\t\t%d %d %d\n", ip[0], ip[1], ip[2]);
UtilConcatVLA(vla, &cnt, buffer);
ip += 3;
}
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
}
{
int b;
int *ip = mesh->face_normal_list;
UtilConcatVLA(vla, &cnt, "\t\t\tMESH_FACE_NORMAL_LIST {\n");
for(b = 0; b < mesh->face_count; b++) {
sprintf(buffer, "\t\t\t%d %d %d\n", ip[0], ip[1], ip[2]);
UtilConcatVLA(vla, &cnt, buffer);
ip += 3;
}
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
}
{
int b;
int *ip = mesh->face_shading_list;
UtilConcatVLA(vla, &cnt, "\t\t\tMESH_FACE_SHADING_LIST {\n");
for(b = 0; b < mesh->face_count; b++) {
sprintf(buffer, "\t\t\t%d\n", ip[0]);
UtilConcatVLA(vla, &cnt, buffer);
ip++;
}
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
}
#ifdef IDTF_COLOR
{
int b;
int *ip = mesh->face_color_list;
UtilConcatVLA(vla, &cnt, "\t\t\tMESH_FACE_DIFFUSE_COLOR_LIST {\n");
for(b = 0; b < mesh->face_count; b++) {
sprintf(buffer, "\t\t\t%d %d %d\n", ip[0], ip[1], ip[2]);
UtilConcatVLA(vla, &cnt, buffer);
ip += 3;
}
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
}
{
int b;
int *ip = mesh->face_color_list;
UtilConcatVLA(vla, &cnt, "\t\t\tMESH_FACE_SPECULAR_COLOR_LIST {\n");
for(b = 0; b < mesh->face_count; b++) {
sprintf(buffer, "\t\t\t%d %d %d\n", ip[0], ip[1], ip[2]);
UtilConcatVLA(vla, &cnt, buffer);
ip += 3;
}
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
}
#endif
{
int b;
float *fp = mesh->model_position_list;
UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_POSITION_LIST {\n");
for(b = 0; b < mesh->position_count; b++) {
sprintf(buffer, "\t\t\t\t%1.6f %1.6f %1.6f\n", fp[0], fp[1], fp[2]);
UtilConcatVLA(vla, &cnt, buffer);
fp += 3;
}
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
}
{
int b;
float *fp = mesh->model_normal_list;
UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_NORMAL_LIST {\n");
for(b = 0; b < mesh->normal_count; b++) {
sprintf(buffer, "\t\t\t\t%1.6f %1.6f %1.6f\n", fp[0], fp[1], fp[2]);
UtilConcatVLA(vla, &cnt, buffer);
fp += 3;
}
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
}
#ifdef IDTF_COLOR
{
int b;
float *fp = mesh->model_diffuse_color_list;
UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_DIFFUSE_COLOR_LIST {\n");
for(b = 0; b < mesh->color_count; b++) {
sprintf(buffer, "\t\t\t\t%1.6f %1.6f %1.6f %1.6f\n", fp[0], fp[1], fp[2],
fp[3]);
UtilConcatVLA(vla, &cnt, buffer);
fp += 4;
}
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
}
{
int b;
float *fp = mesh->model_diffuse_color_list;
UtilConcatVLA(vla, &cnt, "\t\t\tMODEL_SPECULAR_COLOR_LIST {\n");
for(b = 0; b < mesh->color_count; b++) {
sprintf(buffer, "\t\t\t\t%1.6f %1.6f %1.6f %1.6f\n", fp[0], fp[1], fp[2],
fp[3]);
UtilConcatVLA(vla, &cnt, buffer);
fp += 4;
}
UtilConcatVLA(vla, &cnt, "\t\t\t}\n");
}
#endif
UtilConcatVLA(vla, &cnt, "\t\t}\n");
UtilConcatVLA(vla, &cnt, "\t}\n");
mesh++;
}
}
UtilConcatVLA(vla, &cnt, "}\n\n");
}
return cnt;
}
/*========================================================================*/
void RayRenderIDTF(CRay * I, char **node_vla, char **rsrc_vla)
{
int identity = (SettingGetGlobal_i(I->G, cSetting_geometry_export_mode) == 1);
RayExpandPrimitives(I);
RayTransformFirst(I, 0, identity);
{
CBasis *base = I->Basis + 1;
CPrimitive *prim = I->Primitive;
int mesh_cnt = 0;
IdtfResourceMesh *mesh_vla = VLACalloc(IdtfResourceMesh, 1);
if(mesh_vla) {
IdtfResourceMesh *mesh = NULL;
int a;
for(a = 0; a < I->NPrimitive; a++) {
switch (prim->type) {
case cPrimTriangle:
case cPrimSphere:
if(!mesh) {
/* create a new triangle mesh */
if(VLACheck(mesh_vla, IdtfResourceMesh, mesh_cnt)) {
mesh = mesh_vla + mesh_cnt;
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 */
(mesh->model_position_list = VLAlloc(float, 3)) &&
(mesh->face_color_list = VLACalloc(int, 3)) &&
(mesh->model_diffuse_color_list = VLAlloc(float, 4)) &&
((mesh->color_hash = VectorHash_New())) &&
(mesh->model_normal_list = VLAlloc(float, 3)) &&
((mesh->position_hash = VectorHash_New())) &&
((mesh->normal_hash = VectorHash_New()))
) {
mesh_cnt++;
} else {
mesh = NULL;
}
}
}
break;
default: /* close/terminate mesh */
if(mesh) {
mesh = NULL;
}
break;
}
switch (prim->type) {
case cPrimTriangle:
if(mesh) {
if(VLACheck(mesh->face_position_list, int, mesh->face_count * 3 + 2) &&
VLACheck(mesh->face_normal_list, int, mesh->face_count * 3 + 2) &&
VLACheck(mesh->face_shading_list, int, mesh->face_count) &&
VLACheck(mesh->model_position_list, float, (mesh->position_count + 3) * 3)
&& VLACheck(mesh->face_color_list, int, mesh->face_count * 3 + 2)
&& VLACheck(mesh->model_diffuse_color_list, float,
(mesh->color_count + 3) * 4)
&& VLACheck(mesh->model_normal_list, float, (mesh->normal_count + 3) * 3)
) {
float *vert = base->Vertex + 3 * (prim->vert);
float *norm = base->Normal + 3 * base->Vert2Normal[prim->vert] + 3;
int reverse = TriangleReverse(prim);
int face_position_count = mesh->face_count * 3;
int face_normal_count = face_position_count;
int face_color_count = face_position_count;
unique_vector_add(mesh->position_hash, vert,
mesh->model_position_list, &mesh->position_count,
mesh->face_position_list, &face_position_count);
unique_vector_add(mesh->normal_hash, norm,
mesh->model_normal_list, &mesh->normal_count,
mesh->face_normal_list, &face_normal_count);
unique_color_add(mesh->normal_hash, prim->c1,
mesh->model_diffuse_color_list, &mesh->color_count,
mesh->face_color_list, &face_color_count,
1.0F - prim->trans);
if(reverse) {
vert += 6;
norm += 6;
unique_vector_add(mesh->position_hash, vert,
mesh->model_position_list, &mesh->position_count,
mesh->face_position_list, &face_position_count);
unique_vector_add(mesh->normal_hash, norm,
mesh->model_normal_list, &mesh->normal_count,
mesh->face_normal_list, &face_normal_count);
unique_color_add(mesh->normal_hash, prim->c3,
mesh->model_diffuse_color_list, &mesh->color_count,
mesh->face_color_list, &face_color_count,
1.0F - prim->trans);
vert -= 3;
norm -= 3;
unique_vector_add(mesh->position_hash, vert,
mesh->model_position_list, &mesh->position_count,
mesh->face_position_list, &face_position_count);
unique_vector_add(mesh->normal_hash, norm,
mesh->model_normal_list, &mesh->normal_count,
mesh->face_normal_list, &face_normal_count);
unique_color_add(mesh->normal_hash, prim->c2,
mesh->model_diffuse_color_list, &mesh->color_count,
mesh->face_color_list, &face_color_count,
1.0F - prim->trans);
} else {
vert += 3;
norm += 3;
unique_vector_add(mesh->position_hash, vert,
mesh->model_position_list, &mesh->position_count,
mesh->face_position_list, &face_position_count);
unique_vector_add(mesh->normal_hash, norm,
mesh->model_normal_list, &mesh->normal_count,
mesh->face_normal_list, &face_normal_count);
unique_color_add(mesh->normal_hash, prim->c2,
mesh->model_diffuse_color_list, &mesh->color_count,
mesh->face_color_list, &face_color_count,
1.0F - prim->trans);
vert += 3;
norm += 3;
unique_vector_add(mesh->position_hash, vert,
mesh->model_position_list, &mesh->position_count,
mesh->face_position_list, &face_position_count);
unique_vector_add(mesh->normal_hash, norm,
mesh->model_normal_list, &mesh->normal_count,
mesh->face_normal_list, &face_normal_count);
unique_color_add(mesh->normal_hash, prim->c3,
mesh->model_diffuse_color_list, &mesh->color_count,
mesh->face_color_list, &face_color_count,
1.0F - prim->trans);
}
mesh->face_count++;
}
}
break;
case cPrimSphere:
break;
case cPrimCone:
break;
case cPrimCylinder:
case cPrimSausage:
break;
}
/* looping through each primitive */
prim++;
}
/* now we need to consolidate materials for each color
combination (creating averages as necessary) and update
mesh->face_shading_list appropriately for each face */
{
IdtfMaterial *material = Calloc(IdtfMaterial, 1);
if(material &&
(material->color_list = VLAlloc(float, 4)) &&
(material->color_hash = VectorHash_New())) {
const float one_third = (1 / 3.0F);
int a;
IdtfResourceMesh *mesh = mesh_vla;
for(a = 0; a < mesh_cnt; a++) {
int *ip = mesh->face_color_list;
int shading_count = 0;
int b;
for(b = 0; b < mesh->face_count; b++) {
float *fp0 = mesh->model_diffuse_color_list + 4 * ip[0];
float *fp1 = mesh->model_diffuse_color_list + 4 * ip[1];
float *fp2 = mesh->model_diffuse_color_list + 4 * ip[2];
float avg_rgba[4];
avg_rgba[0] = (fp0[0] + fp1[0] + fp2[0]) * one_third;
avg_rgba[1] = (fp0[1] + fp1[1] + fp2[1]) * one_third;
avg_rgba[2] = (fp0[2] + fp1[2] + fp2[2]) * one_third;
avg_rgba[3] = (fp0[3] + fp1[3] + fp2[3]) * one_third;
if(VLACheck(material->color_list, float, material->color_count * 4 + 3)) {
unique_color_add(material->color_hash, avg_rgba,
material->color_list, &material->color_count,
mesh->face_shading_list, &shading_count, avg_rgba[3]);
}
ip += 3;
}
mesh++;
}
{
int cnt = 0;
cnt = idtf_dump_file_header(node_vla, cnt);
cnt = idtf_dump_model_nodes(node_vla, cnt, mesh_vla, mesh_cnt);
VLASize((*node_vla), char, cnt);
}
{
int cnt = 0;
cnt = idtf_dump_resource_header(rsrc_vla, cnt);
cnt = idtf_dump_resources(rsrc_vla, cnt, mesh_vla, mesh_cnt, material);
VLASize((*rsrc_vla), char, cnt);
}
VLAFreeP(material->color_list);
VectorHash_Free(material->color_hash);
}
FreeP(material);
}
{
/* refactor into a delete method */
IdtfResourceMesh *mesh = mesh_vla;
int i;
for(i = 0; i < mesh_cnt; i++) {
VLAFreeP(mesh->face_position_list);
VLAFreeP(mesh->face_normal_list);
VLAFreeP(mesh->face_shading_list);
VLAFreeP(mesh->face_color_list);
VLAFreeP(mesh->model_position_list);
VLAFreeP(mesh->model_normal_list);
VLAFreeP(mesh->model_diffuse_color_list);
VectorHash_Free(mesh->color_hash);
VectorHash_Free(mesh->position_hash);
VectorHash_Free(mesh->normal_hash);
mesh++;
}
VLAFreeP(mesh_vla);
}
}
}
}
/*========================================================================*/
void RayRenderObjMtl(CRay * I, int width, int height, char **objVLA_ptr,
char **mtlVLA_ptr, float front, float back, float fov,
float angle, float z_corr)
{
char *objVLA = *objVLA_ptr;
char *mtlVLA = *mtlVLA_ptr;
int identity = (SettingGetGlobal_i(I->G, cSetting_geometry_export_mode) == 1);
ov_size oc = 0; /* obj character count */
/* int mc = 0; *//* mtl character count */
OrthoLineType buffer;
RayExpandPrimitives(I);
RayTransformFirst(I, 0, identity);
{
int a;
CPrimitive *prim;
float *vert, *norm;
int vc = 0;
int nc = 0;
CBasis *base = I->Basis + 1;
for(a = 0; a < I->NPrimitive; a++) {
prim = I->Primitive + a;
vert = base->Vertex + 3 * (prim->vert);
norm = base->Normal + 3 * base->Vert2Normal[prim->vert] + 3;
switch (prim->type) {
case cPrimTriangle:
sprintf(buffer, "v %8.6f %8.6f %8.6f\n", vert[0], vert[1], vert[2] - z_corr);
UtilConcatVLA(&objVLA, &oc, buffer);
sprintf(buffer, "v %8.6f %8.6f %8.6f\n", vert[3], vert[4], vert[5] - z_corr);
UtilConcatVLA(&objVLA, &oc, buffer);
sprintf(buffer, "v %8.6f %8.6f %8.6f\n", vert[6], vert[7], vert[8] - z_corr);
UtilConcatVLA(&objVLA, &oc, buffer);
sprintf(buffer, "vn %8.6f %8.6f %8.6f\n", norm[0], norm[1], norm[2]);
UtilConcatVLA(&objVLA, &oc, buffer);
sprintf(buffer, "vn %8.6f %8.6f %8.6f\n", norm[3], norm[4], norm[5]);
UtilConcatVLA(&objVLA, &oc, buffer);
sprintf(buffer, "vn %8.6f %8.6f %8.6f\n", norm[6], norm[7], norm[8]);
UtilConcatVLA(&objVLA, &oc, buffer);
if(TriangleReverse(prim)) {
sprintf(buffer, "f %d//%d %d//%d %d//%d\n",
vc + 1, nc + 1, vc + 3, nc + 3, vc + 2, nc + 2);
} else {
sprintf(buffer, "f %d//%d %d//%d %d//%d\n",
vc + 1, nc + 1, vc + 2, nc + 2, vc + 3, nc + 3);
}
UtilConcatVLA(&objVLA, &oc, buffer);
nc += 3;
vc += 3;
/*
prim->c1[0],prim->c1[1],prim->c1[2])
prim->c2[0],prim->c2[1],prim->c2[2],
prim->c3[0],prim->c3[1],prim->c3[2]
UtilConcatVLA(&vla,&oc,buffer);
UtilConcatVLA(&vla,&oc,buffer);
*/
break;
case cPrimSphere:
/* sprintf(buffer,"v %8.6f %8.6f %8.6f\np %d\n",
vert[0],vert[1],vert[2]-z_corr,vc+1);
UtilConcatVLA(&objVLA,&oc,buffer); */
sprintf(buffer, "v %8.6f %8.6f %8.6f\n", vert[0], vert[1], vert[2] - z_corr);
UtilConcatVLA(&objVLA, &oc, buffer);
sprintf(buffer, "v %8.6f %8.6f %8.6f\n", vert[0], vert[1], vert[2] - z_corr);
UtilConcatVLA(&objVLA, &oc, buffer);
sprintf(buffer, "v %8.6f %8.6f %8.6f\n", vert[0], vert[1], vert[2] - z_corr);
UtilConcatVLA(&objVLA, &oc, buffer);
sprintf(buffer, "f %d %d %d\n", vc + 1, vc + 2, vc + 3);
UtilConcatVLA(&objVLA, &oc, buffer);
vc += 3;
break;
}
}
}
*objVLA_ptr = objVLA;
*mtlVLA_ptr = mtlVLA;
}
/*========================================================================*/
void RayRenderPOV(CRay * I, int width, int height, char **headerVLA_ptr,
char **charVLA_ptr, float front, float back, float fov,
float angle, int antialias)
{
float fog;
const float *bkrd;
float fog_start = 0.0F;
float gamma;
float *d;
CBasis *base;
CPrimitive *prim;
OrthoLineType buffer;
float *vert, *norm;
float vert2[3];
ov_size cc, hc;
int a;
int smooth_color_triangle;
int mesh_obj = false;
char *charVLA, *headerVLA;
char transmit[64];
float light[3];
const float *lightv;
float spec_power = SettingGetGlobal_f(I->G, cSetting_spec_power);
int identity = (SettingGetGlobal_i(I->G, cSetting_geometry_export_mode) == 1);
if(spec_power < 0.0F) {
spec_power = SettingGetGlobal_f(I->G, cSetting_shininess);
}
spec_power /= 4.0F;
charVLA = *charVLA_ptr;
headerVLA = *headerVLA_ptr;
smooth_color_triangle = SettingGetGlobal_b(I->G, cSetting_smooth_color_triangle);
PRINTFB(I->G, FB_Ray, FB_Blather)
" RayRenderPOV: w %d h %d f %8.3f b %8.3f\n", width, height, front, back ENDFB(I->G);
if(Feedback(I->G, FB_Ray, FB_Blather)) {
dump3f(I->Volume, " RayRenderPOV: vol");
dump3f(I->Volume + 3, " RayRenderPOV: vol");
}
cc = 0;
hc = 0;
gamma = SettingGetGlobal_f(I->G, cSetting_gamma);
if(gamma > R_SMALL4)
gamma = 1.0F / gamma;
else
gamma = 1.0F;
lightv = SettingGetfv(I->G, cSetting_light);
copy3f(lightv, light);
fog = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog);
if(fog < 0.0F)
fog = SettingGetGlobal_b(I->G, cSetting_depth_cue);
if(fog != 0.0F) {
if(fog > 1.0F)
fog = 1.0F;
fog_start = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog_start);
if(fog_start < 0.0F)
fog_start = SettingGetGlobal_f(I->G, cSetting_fog_start);
if(fog_start > 1.0F)
fog_start = 1.0F;
if(fog_start < 0.0F)
fog_start = 0.0F;
}
/* SETUP */
if(antialias < 0)
antialias = SettingGetGlobal_i(I->G, cSetting_antialias);
bkrd = ColorGet(I->G, SettingGet_color(I->G, NULL, NULL, cSetting_bg_rgb));
RayExpandPrimitives(I);
RayTransformFirst(I, 0, identity);
PRINTFB(I->G, FB_Ray, FB_Details)
" RayRenderPovRay: processed %i graphics primitives.\n", I->NPrimitive ENDFB(I->G);
base = I->Basis + 1;
{
int ortho = SettingGetGlobal_b(I->G, cSetting_ortho);
if(!identity) {
if(!ortho) {
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 */
I->Range[0] / I->Range[1]);
} else {
sprintf(buffer,
"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",
front, -I->Range[0], I->Range[1]);
}
} else {
float look[3];
float loc[3] = { 0.0F, 0.0F, 0.0F };
SceneViewType view;
SceneGetCenter(I->G, look);
SceneGetView(I->G, view);
loc[2] = -view[18];
MatrixInvTransformC44fAs33f3f(view, loc, loc);
add3f(look, loc, loc);
if(!ortho) {
sprintf(buffer,
"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",
fov * I->Range[0] / I->Range[1],
view[1], view[5], view[9],
loc[0], loc[1], loc[2],
look[0], look[1], look[2], -I->Range[0] / I->Range[1]);
} else {
sprintf(buffer,
"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",
view[1], view[5], view[9],
loc[0], loc[1], loc[2],
look[0], look[1], look[2], -I->Range[0], I->Range[1]);
}
}
UtilConcatVLA(&headerVLA, &hc, buffer);
}
{
float ambient =
SettingGetGlobal_f(I->G, cSetting_ambient) + SettingGetGlobal_f(I->G, cSetting_direct);
float reflect = SettingGetGlobal_f(I->G, cSetting_reflect);
if(ambient > 0.5)
ambient = 0.5;
reflect = 1.2F - 1.5F * ambient;
sprintf(buffer,
"#default { finish{phong %8.3f ambient %8.3f diffuse %8.3f phong_size %8.6f}}\n",
SettingGetGlobal_f(I->G, cSetting_spec_reflect), ambient, reflect, spec_power);
UtilConcatVLA(&headerVLA, &hc, buffer);
}
if(!identity) {
if(angle) {
float temp[16];
identity44f(temp);
MatrixRotateC44f(temp, (float) -PI * angle / 180, 0.0F, 1.0F, 0.0F);
MatrixTransformC44fAs33f3f(temp, light, light);
}
}
{
float lite[3];
if(!identity) {
lite[0] = -light[0] * 10000.0F;
lite[1] = -light[1] * 10000.0F;
lite[2] = -light[2] * 10000.0F - front;
} else {
/* this is not correct unless the camera is in the default orientation */
float look[3];
SceneViewType view;
SceneGetCenter(I->G, look);
SceneGetView(I->G, view);
lite[0] = -light[0] * 10000.0F;
lite[1] = -light[1] * 10000.0F;
lite[2] = -light[2] * 10000.0F;
MatrixInvTransformC44fAs33f3f(view, lite, lite);
add3f(look, lite, lite);
}
sprintf(buffer, "light_source{<%6.4f,%6.4f,%6.4f> rgb<1.0,1.0,1.0>}\n",
lite[0], lite[1], lite[2]);
UtilConcatVLA(&headerVLA, &hc, buffer);
}
if(!identity) {
int opaque_back = SettingGetGlobal_i(I->G, cSetting_ray_opaque_background);
if(opaque_back < 0)
opaque_back = SettingGetGlobal_i(I->G, cSetting_opaque_background);
if(opaque_back) { /* drop a plane into the background for the background color */
sprintf(buffer,
"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",
-back, bkrd[0], bkrd[1], bkrd[2]);
UtilConcatVLA(&headerVLA, &hc, buffer);
}
}
for(a = 0; a < I->NPrimitive; a++) {
char cap1 = cCylCapRound;
char cap2 = cCylCapRound;
prim = I->Primitive + a;
vert = base->Vertex + 3 * (prim->vert);
if(prim->type == cPrimTriangle) {
if(smooth_color_triangle)
if(!mesh_obj) {
sprintf(buffer, "mesh {\n");
UtilConcatVLA(&charVLA, &cc, buffer);
mesh_obj = true;
}
} else if(mesh_obj) {
sprintf(buffer, " pigment{color rgb <1,1,1>}}");
UtilConcatVLA(&charVLA, &cc, buffer);
mesh_obj = false;
}
switch (prim->type) {
case cPrimSphere:
sprintf(buffer, "sphere{<%12.10f,%12.10f,%12.10f>, %12.10f\n",
vert[0], vert[1], vert[2], prim->r1);
UtilConcatVLA(&charVLA, &cc, buffer);
sprintf(buffer, "pigment{color rgb<%6.4f,%6.4f,%6.4f>}}\n",
prim->c1[0], prim->c1[1], prim->c1[2]);
UtilConcatVLA(&charVLA, &cc, buffer);
break;
case cPrimCylinder:
cap1 = prim->cap1;
cap2 = prim->cap2;
case cPrimSausage:
d = base->Normal + 3 * base->Vert2Normal[prim->vert];
scale3f(d, prim->l1, vert2);
add3f(vert, vert2, vert2);
sprintf(buffer,
"cylinder{<%12.10f,%12.10f,%12.10f>,\n<%12.10f,%12.10f,%12.10f>,\n %12.10f\n",
vert[0], vert[1], vert[2], vert2[0], vert2[1], vert2[2], prim->r1);
UtilConcatVLA(&charVLA, &cc, buffer);
if (cap1 != cCylCapFlat && cap2 != cCylCapFlat) {
UtilConcatVLA(&charVLA, &cc, "open\n");
}
sprintf(buffer, "pigment{color rgb<%6.4f1,%6.4f,%6.4f>}}\n",
(prim->c1[0] + prim->c2[0]) / 2,
(prim->c1[1] + prim->c2[1]) / 2, (prim->c1[2] + prim->c2[2]) / 2);
UtilConcatVLA(&charVLA, &cc, buffer);
if (cap1 == cCylCapRound) {
sprintf(buffer, "sphere{<%12.10f,%12.10f,%12.10f>, %12.10f\n",
vert[0], vert[1], vert[2], prim->r1);
UtilConcatVLA(&charVLA, &cc, buffer);
sprintf(buffer, "pigment{color rgb<%6.4f1,%6.4f,%6.4f>}}\n",
prim->c1[0], prim->c1[1], prim->c1[2]);
UtilConcatVLA(&charVLA, &cc, buffer);
}
if (cap2 == cCylCapRound) {
sprintf(buffer, "sphere{<%12.10f,%12.10f,%12.10f>, %12.10f\n",
vert2[0], vert2[1], vert2[2], prim->r1);
UtilConcatVLA(&charVLA, &cc, buffer);
sprintf(buffer, "pigment{color rgb<%6.4f1,%6.4f,%6.4f>}}\n",
prim->c2[0], prim->c2[1], prim->c2[2]);
UtilConcatVLA(&charVLA, &cc, buffer);
}
break;
case cPrimTriangle:
norm = base->Normal + 3 * base->Vert2Normal[prim->vert] + 3; /* first normal is the average */
if(!TriangleDegenerate(vert, norm, vert + 3, norm + 3, vert + 6, norm + 6)) {
if(smooth_color_triangle) {
sprintf(buffer,
"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",
vert[0], vert[1], vert[2], norm[0], norm[1], norm[2], prim->c1[0],
prim->c1[1], prim->c1[2], vert[3], vert[4], vert[5], norm[3], norm[4],
norm[5], prim->c2[0], prim->c2[1], prim->c2[2], vert[6], vert[7],
vert[8], norm[6], norm[7], norm[8], prim->c3[0], prim->c3[1],
prim->c3[2]
);
UtilConcatVLA(&charVLA, &cc, buffer);
} else {
/* nowadays we use mesh2 to generate smooth_color_triangles */
UtilConcatVLA(&charVLA, &cc, "mesh2 { ");
sprintf(buffer,
"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",
vert[0], vert[1], vert[2], vert[3], vert[4], vert[5], vert[6], vert[7],
vert[8], norm[0], norm[1], norm[2], norm[3], norm[4], norm[5], norm[6],
norm[7], norm[8]
);
UtilConcatVLA(&charVLA, &cc, buffer);
if(prim->trans > R_SMALL4)
sprintf(transmit, "transmit %4.6f", prim->trans);
else
transmit[0] = 0;
sprintf(buffer, "texture_list { 3, ");
UtilConcatVLA(&charVLA, &cc, buffer);
sprintf(buffer, "texture { pigment{color rgb<%6.4f1,%6.4f,%6.4f> %s}}\n",
prim->c1[0], prim->c1[1], prim->c1[2], transmit);
UtilConcatVLA(&charVLA, &cc, buffer);
sprintf(buffer, ",texture { pigment{color rgb<%6.4f1,%6.4f,%6.4f> %s}}\n",
prim->c2[0], prim->c2[1], prim->c2[2], transmit);
UtilConcatVLA(&charVLA, &cc, buffer);
sprintf(buffer, ",texture { pigment{color rgb<%6.4f1,%6.4f,%6.4f> %s}} }\n",
prim->c3[0], prim->c3[1], prim->c3[2], transmit);
UtilConcatVLA(&charVLA, &cc, buffer);
sprintf(buffer, "face_indices { 1, <0,1,2>, 0, 1, 2 } }\n");
UtilConcatVLA(&charVLA, &cc, buffer);
}
}
break;
}
}
if(mesh_obj) {
sprintf(buffer, " pigment{color rgb <1,1,1>}}");
UtilConcatVLA(&charVLA, &cc, buffer);
mesh_obj = false;
}
*charVLA_ptr = charVLA;
*headerVLA_ptr = headerVLA;
}
/*========================================================================*/
void RayProjectTriangle(CRay * I, RayInfo * r, float *light, float *v0, float *n0,
float scale)
{
float w2;
float d1[3], d2[3], d3[3];
float p1[3], p2[3], p3[3];
int c = 0;
const float _0 = 0.0F;
float *impact = r->impact;
if(dot_product3f(light, n0 - 3) >= _0)
c++;
else if(dot_product3f(light, n0) >= _0)
c++;
else if(dot_product3f(light, n0 + 3) >= _0)
c++;
else if(dot_product3f(light, n0 + 6) >= _0)
c++;
if(c) {
w2 = 1.0F - (r->tri1 + r->tri2);
subtract3f(v0, impact, d1);
subtract3f(v0 + 3, impact, d2);
subtract3f(v0 + 6, impact, d3);
project3f(d1, n0, p1);
project3f(d2, n0 + 3, p2);
project3f(d3, n0 + 6, p3);
scale3f(p1, w2, d1);
scale3f(p2, r->tri1, d2);
scale3f(p3, r->tri2, d3);
add3f(d1, d2, d2);
add3f(d2, d3, d3);
scale3f(d3, scale, d3);
if(dot_product3f(r->surfnormal, d3) >= _0)
add3f(d3, impact, impact);
}
}
#ifndef _PYMOL_NOPY
static void RayHashSpawn(CRayHashThreadInfo * Thread, int n_thread, int n_total)
{
int blocked;
PyObject *info_list;
int a, c, n = 0;
CRay *I = Thread->ray;
PyMOLGlobals *G = I->G;
blocked = PAutoBlock(G);
PRINTFB(I->G, FB_Ray, FB_Blather)
" Ray: filling voxels with %d threads...\n", n_thread ENDFB(I->G);
while(n < n_total) {
c = n;
info_list = PyList_New(n_thread);
for(a = 0; a < n_thread; a++) {
if((c + a) < n_total) {
PyList_SetItem(info_list, a, PyCObject_FromVoidPtr(Thread + c + a, NULL));
} else {
PyList_SetItem(info_list, a, PConvAutoNone(NULL));
}
n++;
}
PXDecRef(PYOBJECT_CALLMETHOD
(G->P_inst->cmd, "_ray_hash_spawn", "OO", info_list, G->P_inst->cmd));
Py_DECREF(info_list);
}
PAutoUnblock(G, blocked);
}
#endif
#ifndef _PYMOL_NOPY
static void RayAntiSpawn(CRayAntiThreadInfo * Thread, int n_thread)
{
int blocked;
PyObject *info_list;
int a;
CRay *I = Thread->ray;
PyMOLGlobals *G = I->G;
blocked = PAutoBlock(G);
PRINTFB(I->G, FB_Ray, FB_Blather)
" Ray: antialiasing with %d threads...\n", n_thread ENDFB(I->G);
info_list = PyList_New(n_thread);
for(a = 0; a < n_thread; a++) {
PyList_SetItem(info_list, a, PyCObject_FromVoidPtr(Thread + a, NULL));
}
PXDecRef(PYOBJECT_CALLMETHOD
(G->P_inst->cmd, "_ray_anti_spawn", "OO", info_list, G->P_inst->cmd));
Py_DECREF(info_list);
PAutoUnblock(G, blocked);
}
#endif
int RayHashThread(CRayHashThreadInfo * T)
{
BasisMakeMap(T->basis, T->vert2prim, T->prim, T->n_prim, T->clipBox, T->phase,
cCache_ray_map, T->perspective, T->front, T->size_hint);
/* utilize a little extra wasted CPU time in thread 0 which computes the smaller map... */
if(!T->phase) {
if (T->ray->bkgrd_data){
fill_background_image(T->ray, T->image, T->width, T->height, T->width * (unsigned int) T->height);
} else if (T->bkrd_is_gradient){
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);
} else {
fill(T->image, T->background, T->bytes);
}
RayComputeBox(T->ray);
}
return 1;
}
#ifndef _PYMOL_NOPY
static void RayTraceSpawn(CRayThreadInfo * Thread, int n_thread)
{
int blocked;
PyObject *info_list;
int a;
CRay *I = Thread->ray;
PyMOLGlobals *G = I->G;
blocked = PAutoBlock(G);
PRINTFB(I->G, FB_Ray, FB_Blather)
" Ray: rendering with %d threads...\n", n_thread ENDFB(I->G);
info_list = PyList_New(n_thread);
for(a = 0; a < n_thread; a++) {
PyList_SetItem(info_list, a, PyCObject_FromVoidPtr(Thread + a, NULL));
}
PXDecRef(PYOBJECT_CALLMETHOD
(G->P_inst->cmd, "_ray_spawn", "OO", info_list, G->P_inst->cmd));
Py_DECREF(info_list);
PAutoUnblock(G, blocked);
}
#endif
static int find_edge(unsigned int *ptr, float *depth, unsigned int width,
int threshold, int back)
{ /* can only be called for a pixel NOT on the edge */
{ /* color testing */
int compare0, compare1, compare2, compare3, compare4, compare5, compare6,
compare7, compare8;
{
int back_test, back_two = false;
compare0 = (signed int) *(ptr);
compare1 = (signed int) *(ptr - 1);
back_test = (compare0 == back);
compare2 = (signed int) *(ptr + 1);
back_two = back_two || ((compare1 == back) == back_test);
compare3 = (signed int) *(ptr - width);
back_two = back_two || ((compare2 == back) == back_test);
compare4 = (signed int) *(ptr + width);
back_two = back_two || ((compare3 == back) == back_test);
compare5 = (signed int) *(ptr - width - 1);
back_two = back_two || ((compare4 == back) == back_test);
compare6 = (signed int) *(ptr + width - 1);
back_two = back_two || ((compare5 == back) == back_test);
compare7 = (signed int) *(ptr - width + 1);
back_two = back_two || ((compare6 == back) == back_test);
compare8 = (signed int) *(ptr + width + 1);
back_two = back_two || ((compare7 == back) == back_test);
if(back_two)
threshold = (threshold >> 1); // halve threshold for pixels that hit background
}
{
int current;
unsigned int shift = 0;
int sum1 = 0, sum2 = 3, sum3 = 0, sum4 = 0, sum5 = 0, sum6 = 0, sum7 = 0, sum8 = 0;
int a;
for(a = 0; a < 4; a++) {
current = ((compare0 >> shift) & 0xFF);
sum1 += abs(current - ((compare1 >> shift) & 0xFF));
sum2 += abs(current - ((compare2 >> shift) & 0xFF));
if(sum1 >= threshold)
return 1;
sum3 += abs(current - ((compare3 >> shift) & 0xFF));
if(sum2 >= threshold)
return 1;
sum4 += abs(current - ((compare4 >> shift) & 0xFF));
if(sum3 >= threshold)
return 1;
sum5 += abs(current - ((compare5 >> shift) & 0xFF));
if(sum4 >= threshold)
return 1;
sum6 += abs(current - ((compare6 >> shift) & 0xFF));
if(sum5 >= threshold)
return 1;
sum7 += abs(current - ((compare7 >> shift) & 0xFF));
if(sum6 >= threshold)
return 1;
sum8 += abs(current - ((compare8 >> shift) & 0xFF));
if(sum7 >= threshold)
return 1;
if(sum8 >= threshold)
return 1;
shift += 8;
}
}
}
if(depth) { /* depth testing */
float compare0, compare1, compare2, compare3, compare4, compare5, compare6,
compare7, compare8;
float dcutoff = threshold / 128.0F;
compare1 = *(depth - 1);
compare0 = *(depth);
compare2 = *(depth + 1);
if(fabs(compare0 - compare1) > dcutoff)
return 1;
compare5 = *(depth - width - 1);
if(fabs(compare0 - compare2) > dcutoff)
return 1;
compare3 = *(depth - width);
if(fabs(compare0 - compare5) > dcutoff)
return 1;
compare7 = *(depth - width + 1);
if(fabs(compare0 - compare3) > dcutoff)
return 1;
compare6 = *(depth + width - 1);
if(fabs(compare0 - compare7) > dcutoff)
return 1;
compare4 = *(depth + width);
if(fabs(compare0 - compare6) > dcutoff)
return 1;
compare8 = *(depth + width + 1);
if(fabs(compare0 - compare4) > dcutoff)
return 1;
if(fabs(compare0 - compare8) > dcutoff)
return 1;
/* if(fabs(compare0-compare1)>0.001F)
printf("%8.3f \n",compare0-compare1);
if(fabs(compare0-compare2)>0.001F)
printf("%8.3f \n",compare0-compare2);
if(fabs(compare0-compare3)>0.001F)
printf("%8.3f \n",compare0-compare3);
if(fabs(compare0-compare4)>0.001F)
printf("%8.3f \n",compare0-compare4);
if(fabs(compare0-compare5)>0.001F)
printf("%8.3f \n",compare0-compare5);
if(fabs(compare0-compare6)>0.001F)
printf("%8.3f \n",compare0-compare6);
if(fabs(compare0-compare7)>0.001F)
printf("%8.3f \n",compare0-compare7);
if(fabs(compare0-compare8)>0.001F)
printf("%8.3f \n",compare0-compare8); */
}
return 0;
}
static void RayPrimGetColorRamped(PyMOLGlobals * G, float *matrix, RayInfo * r, float *fc)
{
float fc1[3], fc2[3], fc3[3];
float *c1, *c2, *c3, w2;
float back_pact[3];
const float _0 = 0.0F, _1 = 1.0F, _01 = 0.1F;
CPrimitive *lprim = r->prim;
inverse_transformC44f3f(matrix, r->impact, back_pact);
switch (lprim->type) {
case cPrimTriangle:
w2 = 1.0F - (r->tri1 + r->tri2);
c1 = lprim->c1;
if(c1[0] <= _0) {
ColorGetRamped(G, (int) (c1[0] - _01), back_pact, fc1, -1);
c1 = fc1;
}
c2 = lprim->c2;
if(c2[0] <= _0) {
ColorGetRamped(G, (int) (c2[0] - _01), back_pact, fc2, -1);
c2 = fc2;
}
c3 = lprim->c3;
if(c3[0] <= _0) {
ColorGetRamped(G, (int) (c3[0] - _01), back_pact, fc3, -1);
c3 = fc3;
}
fc[0] = (c2[0] * r->tri1) + (c3[0] * r->tri2) + (c1[0] * w2);
fc[1] = (c2[1] * r->tri1) + (c3[1] * r->tri2) + (c1[1] * w2);
fc[2] = (c2[2] * r->tri1) + (c3[2] * r->tri2) + (c1[2] * w2);
break;
case cPrimSphere:
c1 = lprim->c1;
if(c1[0] <= _0) {
ColorGetRamped(G, (int) (c1[0] - _01), back_pact, fc1, -1);
c1 = fc1;
}
copy3f(c1, fc);
break;
case cPrimEllipsoid:
/* TO DO */
break;
case cPrimCone:
case cPrimCylinder:
case cPrimSausage:
w2 = r->tri1;
c1 = lprim->c1;
if(c1[0] <= _0) {
ColorGetRamped(G, (int) (c1[0] - _01), back_pact, fc1, -1);
c1 = fc1;
}
c2 = lprim->c2;
if(c2[0] <= _0) {
ColorGetRamped(G, (int) (c2[0] - _01), back_pact, fc2, -1);
c2 = fc2;
}
/* TODO : here is where we would set the correct color if we implemented
non-linear (smoothstep) half bonds. We probably need to add another
parameter/variable to the primitive to tell this function what interpolation
to do */
fc[0] = (c1[0] * (_1 - w2)) + (c2[0] * w2);
fc[1] = (c1[1] * (_1 - w2)) + (c2[1] * w2);
fc[2] = (c1[2] * (_1 - w2)) + (c2[2] * w2);
break;
default:
fc[0] = _1;
fc[1] = _1;
fc[2] = _1;
break;
}
}
int RayTraceThread(CRayThreadInfo * T)
{
CRay *I = T->ray;
int x, y, yy;
float excess = 0.0F;
float dotgle;
float bright, direct_cmp, reflect_cmp, fc[4];
float ambient, direct, lreflect, ft, ffact = 0.0F, ffact1m;
unsigned int cc0, cc1, cc2, cc3;
int i;
RayInfo r1, r2;
int fogFlag = false;
int fogRangeFlag = false;
int opaque_back = 0, orig_opaque_back = 0;
int n_hit = 0;
int two_sided_lighting;
float fog;
float inter[3] = { 0.0F, 0.0F, 0.0F };
float fog_start = 0.0F;
/* float gamma,inp,sig=1.0F; */
float persist, persist_inv;
float new_front;
int pass;
unsigned int last_pixel = 0, *pixel;
int exclude1, exclude2;
float lit;
int backface_cull;
float project_triangle;
float excl_trans;
int shadows;
int trans_shadows;
int trans_mode;
float first_excess;
int pixel_flag;
float ray_trans_spec, ray_lab_spec;
float shadow_fudge;
int label_shadow_mode;
int interior_color;
int interior_flag;
int interior_shadows;
int interior_wobble;
int interior_mode;
float interior_reflect;
int wobble_save;
float settingPower, settingReflectPower, settingSpecPower, settingSpecReflect,
settingSpecDirect;
float settingSpecDirectPower;
float invHgt, invFrontMinusBack, inv1minusFogStart, invWdth, invHgtRange;
float invWdthRange, vol0;
float vol2;
CBasis *bp1, *bp2;
int render_height;
int offset = 0;
BasisCallRec BasisCall[MAX_BASIS];
float border_offset;
int edge_sampling = false;
unsigned int edge_avg[4] = { 0, 0, 0, 0 };
unsigned int edge_alpha_avg[4] = { 0, 0, 0, 0 };
int edge_cnt = 0;
float edge_base[2] = { 0.0F, 0.0F };
float interior_normal[3] = {0.0F, 0.0F, 0.0F};
float edge_width = 0.35356F;
float edge_height = 0.35356F;
float trans_spec_cut, trans_spec_scale, trans_oblique, oblique_power;
float direct_shade;
float red_blend = 0.0F;
float blue_blend = 0.0F;
float green_blend = 0.0F;
float trans_cont;
float pixel_base[3];
float inv_trans_cont = 1.0F;
float trans_cutoff, persist_cutoff;
int trans_cont_flag = false;
int blend_colors;
int max_pass;
float BasisFudge0, BasisFudge1;
int perspective = T->perspective;
float eye[3] = { 0.0F, 0.0F, 0.0F };
float start[3] = { 0.0F, 0.0F, 0.0F };
float nudge[3] = { 0.0F, 0.0F, 0.0F };
float back_pact[3];
float *depth = T->depth;
float ray_scatter = SettingGetGlobal_f(I->G, cSetting_ray_scatter);
const float shadow_decay = SettingGetGlobal_f(I->G, cSetting_ray_shadow_decay_factor);
const float shadow_range = SettingGetGlobal_f(I->G, cSetting_ray_shadow_decay_range);
const int clip_shadows = SettingGetGlobal_b(I->G, cSetting_ray_clip_shadows);
const int spec_local = SettingGetGlobal_i(I->G, cSetting_ray_spec_local);
float legacy = SettingGetGlobal_f(I->G, cSetting_ray_legacy_lighting);
int spec_count = SettingGetGlobal_i(I->G, cSetting_spec_count);
const float _0 = 0.0F;
const float _1 = 1.0F;
const float _p5 = 0.5F;
const float _2 = 2.0F;
const float _255 = 255.0F;
const float _p499 = 0.499F;
const float _persistLimit = 0.0001F;
float legacy_1m = _1 - legacy;
int n_basis = I->NBasis;
int bg_image_mode = SettingGetGlobal_i(I->G, cSetting_bg_image_mode);
int bg_image_linear = SettingGetGlobal_b(I->G, cSetting_bg_image_linear);
auto bg_image_tilesize = SettingGet<const float*>(I->G, cSetting_bg_image_tilesize);
float hpixelx = floor(T->width/2.f) - floor(T->bgWidth / 2.f),
hpixely = floor(T->height/2.f) - floor(T->bgHeight / 2.f);
float hl;
float wr = T->bgWidth/(float)T->width, hr = T->bgHeight/(float)T->height;
float bg_rgb[3];
const float *tmpf;
int chromadepth;
tmpf = ColorGet(I->G, SettingGet_color(I->G, NULL, NULL, cSetting_bg_rgb));
mult3f(tmpf, 255.f, bg_rgb);
/* MemoryDebugDump();
printf("%d\n",sizeof(CPrimitive));
*/
{
float fudge = SettingGetGlobal_f(I->G, cSetting_ray_triangle_fudge);
BasisFudge0 = 0.0F - fudge;
BasisFudge1 = 1.0F + fudge;
}
if(spec_count < 0) {
spec_count = SettingGetGlobal_i(I->G, cSetting_light_count);
}
/* SETUP */
/* if(T->n_thread>1)
printf(" Ray: Thread %d: Spawned.\n",T->phase+1);
*/
interior_shadows = SettingGetGlobal_i(I->G, cSetting_ray_interior_shadows);
interior_wobble = SettingGetGlobal_i(I->G, cSetting_ray_interior_texture);
interior_color = SettingGetGlobal_i(I->G, cSetting_ray_interior_color);
interior_reflect = 1.0F - SettingGetGlobal_f(I->G, cSetting_ray_interior_reflect);
interior_mode = SettingGetGlobal_i(I->G, cSetting_ray_interior_mode);
label_shadow_mode = SettingGetGlobal_i(I->G, cSetting_label_shadow_mode);
project_triangle = SettingGetGlobal_f(I->G, cSetting_ray_improve_shadows);
shadows = SettingGetGlobal_i(I->G, cSetting_ray_shadows);
trans_shadows = SettingGetGlobal_i(I->G, cSetting_ray_transparency_shadows);
backface_cull = SettingGetGlobal_i(I->G, cSetting_backface_cull);
opaque_back = SettingGetGlobal_i(I->G, cSetting_ray_opaque_background);
if(opaque_back < 0)
opaque_back = SettingGetGlobal_i(I->G, cSetting_opaque_background);
orig_opaque_back = opaque_back;
if (T->bkrd_data){
opaque_back = 1;
}
two_sided_lighting = SettingGetGlobal_i(I->G, cSetting_two_sided_lighting);
if(two_sided_lighting<0) {
if(SettingGetGlobal_i(I->G, cSetting_surface_cavity_mode))
two_sided_lighting = true;
else
two_sided_lighting = false;
}
ray_trans_spec = SettingGetGlobal_f(I->G, cSetting_ray_transparency_specular);
ray_lab_spec = SettingGetGlobal_f(I->G, cSetting_ray_label_specular);
trans_cont = SettingGetGlobal_f(I->G, cSetting_ray_transparency_contrast);
trans_mode = SettingGetGlobal_i(I->G, cSetting_transparency_mode);
trans_oblique = SettingGetGlobal_f(I->G, cSetting_ray_transparency_oblique);
oblique_power = SettingGetGlobal_f(I->G, cSetting_ray_transparency_oblique_power);
trans_cutoff = SettingGetGlobal_f(I->G, cSetting_ray_trace_trans_cutoff);
persist_cutoff = SettingGetGlobal_f(I->G, cSetting_ray_trace_persist_cutoff);
chromadepth = SettingGetGlobal_i(I->G, cSetting_chromadepth);
if(trans_mode == 1)
two_sided_lighting = true;
if(trans_cont > 1.0F) {
trans_cont_flag = true;
inv_trans_cont = 1.0F / trans_cont;
}
ambient = T->ambient;
/* divide up the reflected light component over all lights */
{
float reflect_scale = SceneGetReflectScaleValue(I->G, 10);
lreflect = reflect_scale * (SettingGetGlobal_f(I->G, cSetting_reflect) - ray_scatter);
if(lreflect < _0)
lreflect = _0;
ray_scatter = ray_scatter * reflect_scale;
}
direct = SettingGetGlobal_f(I->G, cSetting_direct);
/* apply legacy adjustments */
ambient *= (1.0F - legacy) + (legacy * (0.22F / 0.12F));
lreflect *= (1.0F - legacy) + (legacy * (0.72F / 0.45F));
direct *= (1.0F - legacy) + (legacy * (0.24F / 0.45F));
direct_shade = SettingGetGlobal_f(I->G, cSetting_ray_direct_shade);
trans_spec_cut = SettingGetGlobal_f(I->G, cSetting_ray_transparency_spec_cut);
blend_colors = SettingGetGlobal_i(I->G, cSetting_ray_blend_colors);
max_pass = SettingGetGlobal_i(I->G, cSetting_ray_max_passes);
if(blend_colors) {
red_blend = SettingGetGlobal_f(I->G, cSetting_ray_blend_red);
green_blend = SettingGetGlobal_f(I->G, cSetting_ray_blend_green);
blue_blend = SettingGetGlobal_f(I->G, cSetting_ray_blend_blue);
}
if(trans_spec_cut < _1)
trans_spec_scale = _1 / (_1 - trans_spec_cut);
else
trans_spec_scale = _0;
/* COOP */
settingPower = SettingGetGlobal_f(I->G, cSetting_power);
settingReflectPower = SettingGetGlobal_f(I->G, cSetting_reflect_power);
SceneGetAdjustedLightValues(I->G,
&settingSpecReflect,
&settingSpecPower,
&settingSpecDirect,
&settingSpecDirectPower, 10);
if((interior_color != -1) || (two_sided_lighting) || (trans_mode == 1)
|| I->CheckInterior)
backface_cull = 0;
shadow_fudge = SettingGetGlobal_f(I->G, cSetting_ray_shadow_fudge);
inv1minusFogStart = _1;
fog = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog);
if(fog < 0.0F) {
if(SettingGetGlobal_b(I->G, cSetting_depth_cue)) {
fog = SettingGetGlobal_f(I->G, cSetting_fog);
} else
fog = _0;
}
if(fog != _0) {
fogFlag = true;
fog_start = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog_start);
if(fog_start < 0.0F)
fog_start = SettingGetGlobal_f(I->G, cSetting_fog_start);
if(fog_start > 1.0F)
fog_start = 1.0F;
if(fog_start < 0.0F)
fog_start = 0.0F;
if(fog_start > R_SMALL4) {
fogRangeFlag = true;
if(fabs(fog_start - 1.0F) < R_SMALL4) /* prevent div/0 */
fogFlag = false;
}
inv1minusFogStart = _1 / (_1 - fog_start);
}
/* ray-trace */
if(T->border) {
invHgt = _1 / (float) (T->height - (3.0F + T->border));
invWdth = _1 / (float) (T->width - (3.0F + T->border));
} else {
invHgt = _1 / (float) (T->height);
invWdth = _1 / (float) (T->width);
}
if(perspective) {
float height_range, width_range;
/* subpixel-offsets for antialiasing naturally correspond to
effective pixel sizes at the front of the visible slab... */
height_range = (T->front) * 2 * ((float) tan((T->fov / 2.0F) * PI / 180.0F));
width_range = height_range * (I->Range[0] / I->Range[1]);
invWdthRange = invWdth * width_range;
invHgtRange = invHgt * height_range;
vol0 = eye[0] - width_range / 2.0F;
vol2 = eye[1] - height_range / 2.0F;
} else {
invWdthRange = invWdth * I->Range[0];
invHgtRange = invHgt * I->Range[1];
vol0 = I->Volume[0];
vol2 = I->Volume[2];
}
invFrontMinusBack = _1 / (T->front - T->back);
edge_width *= invWdthRange;
edge_height *= invHgtRange;
bp1 = I->Basis + 1;
if(I->NBasis > 2)
bp2 = I->Basis + 2;
else
bp2 = NULL;
render_height = T->y_stop - T->y_start;
if(render_height) {
offset = (T->phase * render_height / T->n_thread);
offset = offset - (offset % T->n_thread) + T->phase;
}
if((interior_color != -1) || I->CheckInterior) {
if(interior_color != -1)
ColorGetEncoded(I->G, interior_color, inter);
if(bp2) {
interior_normal[0] = interior_reflect * bp2->LightNormal[0];
interior_normal[1] = interior_reflect * bp2->LightNormal[1];
interior_normal[2] = 1.0F + interior_reflect * bp2->LightNormal[2];
} else {
interior_normal[0] = 0.0;
interior_normal[1] = 0.0;
interior_normal[2] = 1.0F;
}
normalize3f(interior_normal);
}
r1.base[2] = _0;
BasisCall[0].Basis = I->Basis + 1;
BasisCall[0].rr = &r1;
BasisCall[0].vert2prim = I->Vert2Prim;
BasisCall[0].prim = I->Primitive;
BasisCall[0].shadow = false;
BasisCall[0].back = T->back;
BasisCall[0].trans_shadows = trans_shadows;
BasisCall[0].nearest_shadow = (shadow_decay != _0);
BasisCall[0].check_interior = ((interior_color != -1) || I->CheckInterior);
BasisCall[0].fudge0 = BasisFudge0;
BasisCall[0].fudge1 = BasisFudge1;
MapCacheInit(&BasisCall[0].cache, I->Basis[1].Map, T->phase, cCache_map_scene_cache);
if(shadows && (n_basis > 2)) {
int bc;
for(bc = 2; bc < n_basis; bc++) {
BasisCall[bc].Basis = I->Basis + bc;
BasisCall[bc].rr = &r2;
BasisCall[bc].vert2prim = I->Vert2Prim;
BasisCall[bc].prim = I->Primitive;
BasisCall[bc].shadow = true;
BasisCall[bc].front = _0;
BasisCall[bc].back = _0;
BasisCall[bc].excl_trans = _0;
BasisCall[bc].trans_shadows = trans_shadows;
BasisCall[bc].nearest_shadow = (shadow_decay != _0) || (clip_shadows);
BasisCall[bc].check_interior = false;
BasisCall[bc].fudge0 = BasisFudge0;
BasisCall[bc].fudge1 = BasisFudge1;
BasisCall[bc].label_shadow_mode = label_shadow_mode;
MapCacheInit(&BasisCall[bc].cache, I->Basis[bc].Map, T->phase,
cCache_map_shadow_cache);
}
}
if(T->border) {
border_offset = -1.50F + T->border / 2.0F;
} else {
border_offset = 0.0F;
}
unsigned int back_mask = 0x00000000;
if (T->bkrd_is_gradient){
if(opaque_back) {
if(I->BigEndian)
back_mask = 0x000000FF;
else
back_mask = 0xFF000000;
}
}
for(yy = T->y_start; (yy < T->y_stop); yy++) {
float perc, bkrd[4] = {0.f, 0.f, 0.f, 1.f};
unsigned int bkrd_value = 0;
short isOutsideInY = 0;
if(I->G->Interrupt)
break;
y = T->y_start + ((yy - T->y_start) + offset) % (render_height); /* make sure threads write to different pages */
if (T->bkrd_data){
switch (bg_image_mode){
case 1: // isCentered
{
float tmpy = floor(y - hpixely);
isOutsideInY = (tmpy < 0.f || tmpy > (float)T->bgHeight);
hl = fmodpos(tmpy, (float)T->bgHeight);
}
break;
case 2: // isTiled
hl = (float)T->bgHeight * (fmodpos((float)y, bg_image_tilesize[1])/bg_image_tilesize[1]);
break;
case 3: // isCenteredRepeated
hl = fmodpos(floor(y - hpixely), (float)T->bgHeight);
break;
default:
hl = y * hr;
break;
}
} else if (T->bkrd_is_gradient){
/* for RayTraceThread, y is from bottom to top */
perc = y/(float)T->height;
bkrd[0] = T->bkrd_bottom[0] + perc * (T->bkrd_top[0] - T->bkrd_bottom[0]);
bkrd[1] = T->bkrd_bottom[1] + perc * (T->bkrd_top[1] - T->bkrd_bottom[1]);
bkrd[2] = T->bkrd_bottom[2] + perc * (T->bkrd_top[2] - T->bkrd_bottom[2]);
bkrd[3] = 1.f;
if(T->ray->BigEndian){
bkrd_value = back_mask |
((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))) << 24) |
((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 16) |
((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 8);
} else {
bkrd_value = back_mask |
((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 16) |
((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 8) |
((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))));
}
} else {
bkrd_value = T->background;
bkrd[0] = T->bkrd_top[0];
bkrd[1] = T->bkrd_top[1];
bkrd[2] = T->bkrd_top[2];
if (orig_opaque_back){
bkrd[3] = 1.f;
} else {
bkrd[3] = 0.f;
}
}
if((!T->phase) && !(yy & 0xF)) { /* don't slow down rendering too much */
if(T->edging_cutoff) {
if(T->edging) {
OrthoBusyFast(I->G, (int) (2.5F * T->height / 3 + 0.5F * y), 4 * T->height / 3);
} else {
OrthoBusyFast(I->G, (int) (T->height / 3 + 0.5F * y), 4 * T->height / 3);
}
} else {
OrthoBusyFast(I->G, T->height / 3 + y, 4 * T->height / 3);
}
}
pixel = T->image + (T->width * y) + T->x_start;
if((y % T->n_thread) == T->phase) { /* this is my scan line */
pixel_base[1] = ((y + 0.5F + border_offset) * invHgtRange) + vol2;
for(x = T->x_start; (x < T->x_stop); x++) {
if (T->bkrd_data){
// Need to compute background for every pixel if image-based
unsigned char bkrd_uc[4];
compute_background_for_pixel(bkrd_uc, isOutsideInY,
bg_image_mode, bg_image_tilesize, bg_rgb, bg_image_linear,
(unsigned char*) T->bkrd_data, T->bgWidth, T->bgHeight,
x, wr, hl, hpixelx, orig_opaque_back );
bkrd[0] = bkrd_uc[0] / 255.f;
bkrd[1] = bkrd_uc[1] / 255.f;
bkrd[2] = bkrd_uc[2] / 255.f;
bkrd[3] = bkrd_uc[3] / 255.f;
if(T->ray->BigEndian){
bkrd_value = back_mask |
((0xFF & ((unsigned int) (bkrd_uc[0] * 255 + _p499))) << 24) |
((0xFF & ((unsigned int) (bkrd_uc[1] * 255 + _p499))) << 16) |
((0xFF & ((unsigned int) (bkrd_uc[2] * 255 + _p499))) << 8);
} else {
bkrd_value = back_mask |
((0xFF & ((unsigned int) (bkrd_uc[2] * 255 + _p499))) << 16) |
((0xFF & ((unsigned int) (bkrd_uc[1] * 255 + _p499))) << 8) |
((0xFF & ((unsigned int) (bkrd_uc[0] * 255 + _p499))));
}
}
pixel_base[0] = (((x + 0.5F + border_offset)) * invWdthRange) + vol0;
while(1) {
if(T->edging) {
if(!edge_sampling) {
if(x && y && (x < (T->width - 1)) && (y < (T->height - 1))) { /* not on the edge... */
if(find_edge(T->edging + (pixel - T->image),
depth + (pixel - T->image),
T->width, T->edging_cutoff, bkrd_value)) {
unsigned char *pixel_c = (unsigned char *) pixel;
unsigned int c1, c2, c3, c4;
edge_cnt = 1;
edge_sampling = true;
edge_avg[0] = (c1 = pixel_c[0]);
edge_avg[1] = (c2 = pixel_c[1]);
edge_avg[2] = (c3 = pixel_c[2]);
edge_avg[3] = (c4 = pixel_c[3]);
edge_alpha_avg[0] = c1 * c4;
edge_alpha_avg[1] = c2 * c4;
edge_alpha_avg[2] = c3 * c4;
edge_alpha_avg[3] = c4;
edge_base[0] = pixel_base[0];
edge_base[1] = pixel_base[1];
}
}
}
if(edge_sampling) {
if(edge_cnt == 5) {
/* done with edging, so store averaged value */
unsigned char *pixel_c = (unsigned char *) pixel;
unsigned int c1, c2, c3, c4;
edge_sampling = false;
/* done with edging, so store averaged value */
if(edge_alpha_avg[3]) {
c4 = edge_alpha_avg[3];
c1 = edge_alpha_avg[0] / c4;
c2 = edge_alpha_avg[1] / c4;
c3 = edge_alpha_avg[2] / c4;
c4 /= edge_cnt;
} else {
c1 = edge_avg[0] / edge_cnt;
c2 = edge_avg[1] / edge_cnt;
c3 = edge_avg[2] / edge_cnt;
c4 = edge_avg[3] / edge_cnt;
}
pixel_c[0] = c1;
pixel_c[1] = c2;
pixel_c[2] = c3;
pixel_c[3] = c4;
/* Need to account for alpha, if exists */
if (orig_opaque_back && c4 < 255){
float bkpart = (255 - c4) / 255.f;
float ppart = 1.f - bkpart;
pixel_c[0] = pymol_roundf(bkpart * bkrd[0] * 255 + ppart * pixel_c[0]);
pixel_c[1] = pymol_roundf(bkpart * bkrd[1] * 255 + ppart * pixel_c[1]);
pixel_c[2] = pymol_roundf(bkpart * bkrd[2] * 255 + ppart * pixel_c[2]);
pixel_c[3] = 255;
}
/* restore X,Y coordinates */
r1.base[0] = pixel_base[0];
r1.base[1] = pixel_base[1];
} else {
*pixel = 0;
// *pixel = bkrd_value;
switch (edge_cnt) {
case 1:
r1.base[0] = edge_base[0] + edge_width;
r1.base[1] = edge_base[1] + edge_height;
break;
case 2:
r1.base[0] = edge_base[0] + edge_width;
r1.base[1] = edge_base[1] - edge_height;
break;
case 3:
r1.base[0] = edge_base[0] - edge_width;
r1.base[1] = edge_base[1] + edge_height;
break;
case 4:
r1.base[0] = edge_base[0] - edge_width;
r1.base[1] = edge_base[1] - edge_height;
break;
}
}
}
if(!edge_sampling) /* not oversampling this edge or already done... */
break;
} else {
r1.base[0] = pixel_base[0];
r1.base[1] = pixel_base[1];
}
exclude1 = -1;
exclude2 = -1;
persist = _1;
first_excess = _0;
excl_trans = _0;
pass = 0;
new_front = T->front;
if(perspective) {
r1.base[2] = -T->front;
r1.dir[0] = (r1.base[0] - eye[0]);
r1.dir[1] = (r1.base[1] - eye[1]);
r1.dir[2] = (r1.base[2] - eye[2]);
if(BasisCall[0].check_interior) {
start[0] = r1.base[0];
start[1] = r1.base[1];
start[2] = r1.base[2];
}
normalize3f(r1.dir);
{
float scale = I->max_box[2] / r1.base[2];
r1.skip[0] = r1.base[0] * scale;
r1.skip[1] = r1.base[1] * scale;
r1.skip[2] = I->max_box[2];
}
}
while((persist > _persistLimit) && (pass <= max_pass)) {
char fogFlagTmp = fogFlag;
pixel_flag = false;
BasisCall[0].except1 = exclude1;
BasisCall[0].except2 = exclude2;
BasisCall[0].front = new_front;
BasisCall[0].excl_trans = excl_trans;
BasisCall[0].interior_flag = false;
BasisCall[0].pass = pass;
if(perspective) {
if(pass) {
add3f(nudge, r1.base, r1.base);
copy3f(r1.base, r1.skip);
}
BasisCall[0].back_dist = -(T->back + r1.base[2]) / r1.dir[2];
i = BasisHitPerspective(&BasisCall[0]);
} else {
i = BasisHitOrthoscopic(&BasisCall[0]);
}
interior_flag = BasisCall[0].interior_flag && (!pass);
if(((i >= 0) || interior_flag) && (pass < max_pass)) {
int n_basis_tmp = r1.prim->no_lighting ? 0 : n_basis;
pixel_flag = true;
n_hit++;
if(((r1.trans = r1.prim->trans) != _0) && trans_cont_flag) {
r1.trans = (float) pow(r1.trans, inv_trans_cont);
}
if(interior_flag) {
copy3f(interior_normal, r1.surfnormal);
if(perspective) {
copy3f(start, r1.impact);
r1.dist = _0;
} else {
copy3f(r1.base, r1.impact);
r1.dist = T->front;
r1.impact[2] -= T->front;
}
if(interior_wobble >= 0) {
wobble_save = r1.prim->wobble; /* This is a no-no for multithreading! */
r1.prim->wobble = interior_wobble;
RayReflectAndTexture(I, &r1, perspective);
r1.prim->wobble = wobble_save;
} else
RayReflectAndTexture(I, &r1, perspective);
dotgle = -r1.dotgle;
if((interior_color < 0) && (interior_color > cColorExtCutoff)) {
copy3f(r1.prim->ic, fc);
} else {
copy3f(inter, fc);
}
} else {
if(!perspective)
new_front = r1.dist;
switch (r1.prim->type) {
case cPrimTriangle:
BasisGetTriangleNormal(bp1, &r1, i, fc, perspective);
r1.trans = (float) pow(r1.trans, inv_trans_cont);
if(r1.prim->ramped) {
RayPrimGetColorRamped(I->G, I->ModelView, &r1, fc);
}
if(bp2) {
RayProjectTriangle(I, &r1, bp2->LightNormal,
bp1->Vertex + i * 3,
bp1->Normal + bp1->Vert2Normal[i] * 3 + 3,
project_triangle);
}
RayReflectAndTexture(I, &r1, perspective);
if(perspective) {
BasisGetTriangleFlatDotglePerspective(bp1, &r1, i);
} else {
BasisGetTriangleFlatDotgle(bp1, &r1, i);
}
break;
case cPrimCharacter:
BasisGetTriangleNormal(bp1, &r1, i, fc, perspective);
r1.trans = CharacterInterpolate(I->G, r1.prim->char_id, fc);
fogFlagTmp = false;
RayReflectAndTexture(I, &r1, perspective);
BasisGetTriangleFlatDotgle(bp1, &r1, i);
break;
case cPrimEllipsoid:
BasisGetEllipsoidNormal(bp1, &r1, i, perspective);
RayReflectAndTexture(I, &r1, perspective);
fc[0] = r1.prim->c1[0];
fc[1] = r1.prim->c1[1];
fc[2] = r1.prim->c1[2];
break;
default: /* sphere, cylinder, sausage, etc. */
/* must be a sphere (effectively speaking) */
if(perspective) {
RayGetSphereNormalPerspective(I, &r1);
} else {
RayGetSphereNormal(I, &r1);
}
RayReflectAndTexture(I, &r1, perspective);
if(r1.prim->ramped) {
RayPrimGetColorRamped(I->G, I->ModelView, &r1, fc);
} else {
switch (r1.prim->type) {
case cPrimCylinder:
case cPrimSausage:
case cPrimCone:
ft = r1.tri1;
fc[0] = (r1.prim->c1[0] * (_1 - ft)) + (r1.prim->c2[0] * ft);
fc[1] = (r1.prim->c1[1] * (_1 - ft)) + (r1.prim->c2[1] * ft);
fc[2] = (r1.prim->c1[2] * (_1 - ft)) + (r1.prim->c2[2] * ft);
break;
default:
fc[0] = r1.prim->c1[0];
fc[1] = r1.prim->c1[1];
fc[2] = r1.prim->c1[2];
break;
}
}
break;
}
if((trans_oblique != _0) && (r1.trans != _0)) {
if((r1.surfnormal[2] > _0) || two_sided_lighting) {
float oblique_factor = r1.surfnormal[2];
if(oblique_factor < _0)
oblique_factor = -oblique_factor;
if(oblique_factor != _1) {
if(oblique_factor > _p5) {
oblique_factor =
(float) (_p5 +
_p5 * (_1 -
pow((_1 - oblique_factor) * _2,
oblique_power)));
} else {
oblique_factor =
(float) (_p5 * pow(oblique_factor * _2, oblique_power));
}
}
r1.trans *= (trans_oblique * oblique_factor) + (1.0F - trans_oblique);
if(r1.trans < 0.06F)
r1.trans = 0.06F; /* don't allow transparent to become opaque */
}
}
dotgle = -r1.dotgle;
if(r1.flat_dotgle < _0) {
if((!two_sided_lighting) && (BasisCall[0].check_interior)
&& (interior_mode != 2)) {
interior_flag = true;
copy3f(interior_normal, r1.surfnormal);
if(perspective) {
copy3f(start, r1.impact);
r1.dist = _0;
} else {
copy3f(r1.base, r1.impact);
r1.impact[2] -= T->front;
r1.dist = T->front;
}
if(interior_wobble >= 0) {
wobble_save = r1.prim->wobble;
r1.prim->wobble = interior_wobble;
RayReflectAndTexture(I, &r1, perspective);
r1.prim->wobble = wobble_save;
} else {
RayReflectAndTexture(I, &r1, perspective);
}
dotgle = -r1.dotgle;
if((interior_color < 0) && (interior_color > cColorExtCutoff)) {
copy3f(r1.prim->ic, fc);
} else {
copy3f(inter, fc);
}
}
}
if((r1.flat_dotgle < _0) && (!interior_flag)) {
if(two_sided_lighting) {
dotgle = -dotgle;
invert3f(r1.surfnormal);
}
}
}
{
double pow_dotgle;
float pow_surfnormal2;
if(settingPower != _1) {
pow_dotgle = pow(dotgle, settingPower);
pow_surfnormal2 = (float) pow(r1.surfnormal[2], settingPower);
} else {
pow_dotgle = dotgle;
pow_surfnormal2 = r1.surfnormal[2];
}
direct_cmp = legacy_1m * pow_surfnormal2 + /* new model */
legacy * ((float) (dotgle + pow_dotgle) * _p5); /* legacy model */
}
reflect_cmp = _0;
if(settingSpecDirect != _0) {
if(r1.surfnormal[2] > _0) {
excess =
(float) (pow(r1.surfnormal[2], settingSpecDirectPower) *
settingSpecDirect);
} else {
excess = _0;
}
} else {
excess = _0;
}
lit = _1;
if(n_basis_tmp < 3) {
reflect_cmp = direct_cmp;
} else {
int bc;
CBasis *bp;
for(bc = 2; bc < n_basis; bc++) {
lit = _1;
bp = I->Basis + bc;
if(shadows && ((!interior_flag) || (interior_shadows)) &&
((r1.prim->type != cPrimCharacter) || (label_shadow_mode & 0x1))) {
matrix_transform33f3f(bp->Matrix, r1.impact, r2.base);
r2.base[2] -= shadow_fudge;
BasisCall[bc].except2 = -1;
BasisCall[bc].except1 = i; /* exclude current prim from shadow comp */
if(BasisHitShadow(&BasisCall[bc]) > -1) {
if((!clip_shadows) || (bp->LightNormal[2] >= _0) ||
((T->front + r1.impact[2] - (r2.dist * bp->LightNormal[2])) <
_0)) {
lit = (float) pow(r2.trans, _p5);
if((shadow_decay != _0) && (r2.dist > shadow_range)) {
if(shadow_decay > 0) {
lit +=
((_1 - lit) * (_1 -
_1 / exp((r2.dist - shadow_range) *
shadow_decay)));
} else {
lit +=
((_1 - lit) * (_1 -
_1 / pow(r2.dist / shadow_range,
-shadow_decay)));
}
}
}
}
}
if(lit > _0) {
{
double pow_dotgle;
dotgle = -dot_product3f(r1.surfnormal, bp->LightNormal);
if(dotgle < _0)
dotgle = _0;
if(settingReflectPower != _1)
pow_dotgle = pow(dotgle, settingReflectPower);
else
pow_dotgle = dotgle;
reflect_cmp += legacy_1m * ((float) (lit * pow_dotgle)) + /* new model */
legacy * ((float) (lit * (dotgle + pow_dotgle) * _p5)); /* legacy model */
}
if(bc < (spec_count + 2)) {
if(ray_scatter != _0) /* scattered specular light */
excess += ray_scatter * dotgle;
if(spec_local && perspective) {
/* slower, C4D-like local specular */
float tmp[3];
add3f(r1.surfnormal, r1.surfnormal, tmp);
add3f(tmp, bp->LightNormal, tmp);
normalize3f(tmp);
dotgle = -(dot_product3f(r1.dir, tmp)) * 1.004F;
if(dotgle > _1)
dotgle = _1;
else if(dotgle < _0)
dotgle = _0;
dotgle = powf(dotgle, 0.29F);
} else {
dotgle = -dot_product3f(r1.surfnormal, bp->SpecNormal); /* fast OpenGL-like global specular */
}
if(dotgle < _0)
dotgle = _0;
if(r1.prim->type != cPrimCharacter) {
excess +=
(float) (pow(dotgle, settingSpecPower) * settingSpecReflect *
lit);
} else {
excess +=
(float) (pow(dotgle, settingSpecPower) * settingSpecReflect *
lit * ray_lab_spec);
}
}
}
}
if (chromadepth > 0) {
float d = -(r1.impact[2] + T->front) / (T->back - T->front);
const float margin = 1. / 4.;
float h = d * (1. + 2. * margin) - margin;
if (h < 0.0) h = 0.0;
if (h > 1.0) h = 1.0;
float hue6 = 6. * 240. / 360. * h;
float rgb[3];
rgb[0] = fabs(hue6 - 3.) - 1.;
rgb[1] = 2. - fabs(hue6 - 2.);
rgb[2] = 2. - fabs(hue6 - 4.);
clamp3f(rgb);
if (chromadepth == 2) {
float lum = 0.30 * fc[0] + 0.59 * fc[1] + 0.11 * fc[2];
rgb[0] *= lum;
rgb[1] *= lum;
rgb[2] *= lum;
}
copy3(rgb, fc);
}
}
if(fc[0] <= ((float) cColorExtCutoff)) { /* ramped color */
inverse_transformC44f3f(I->ModelView, r1.impact, back_pact);
ColorGetRamped(I->G, (int) (fc[0] - 0.1F), back_pact, fc, -1);
}
bright = ambient + (((_1 - direct_shade) + direct_shade * lit) * direct * direct_cmp + lreflect * reflect_cmp * (legacy_1m + legacy * direct_cmp)); /* blend legacy */
if(excess > _1)
excess = _1;
if(bright > _1)
bright = _1;
else if(bright < _0)
bright = _0;
/* bright *= (_1-excess); */
fc[0] = (bright * fc[0] + excess);
fc[1] = (bright * fc[1] + excess);
fc[2] = (bright * fc[2] + excess);
if(n_basis_tmp && fogFlagTmp) {
if(perspective) {
ffact = (T->front + r1.impact[2]) * invFrontMinusBack;
} else {
ffact = (T->front - r1.dist) * invFrontMinusBack;
}
if(fogRangeFlag)
ffact = (ffact - fog_start) * inv1minusFogStart;
ffact *= fog;
if(ffact < _0)
ffact = _0;
if(ffact > _1)
ffact = _1;
ffact1m = _1 - ffact;
if(orig_opaque_back) {
fc[0] = ffact * bkrd[0] + fc[0] * ffact1m;
fc[1] = ffact * bkrd[1] + fc[1] * ffact1m;
fc[2] = ffact * bkrd[2] + fc[2] * ffact1m;
fc[3] = _1;
} else {
fc[3] = ffact1m * (_1 - r1.trans);
}
if(!pass) {
if(r1.trans < trans_spec_cut) {
first_excess = excess * ffact1m * ray_trans_spec;
} else {
first_excess = excess * ffact1m * ray_trans_spec *
trans_spec_scale * (_1 - r1.trans);
}
} else {
fc[0] += first_excess; /* dubious? */
fc[1] += first_excess;
fc[2] += first_excess;
}
} else {
if(!pass) {
if(r1.trans < trans_spec_cut) {
first_excess = excess * ray_trans_spec;
} else {
first_excess = excess * ray_trans_spec *
trans_spec_scale * (_1 - r1.trans);
}
} else {
fc[0] += first_excess;
fc[1] += first_excess;
fc[2] += first_excess;
}
if(orig_opaque_back) {
fc[3] = _1;
} else {
fc[3] = _1 - r1.trans;
}
}
} else if(pass) {
/* hit nothing, and we're on on second or greater pass,
or we're on the last pass of a dead-end loop */
i = -1;
fc[0] = first_excess + bkrd[0];
fc[1] = first_excess + bkrd[1];
fc[2] = first_excess + bkrd[2];
if(orig_opaque_back) {
fc[3] = _1;
} else {
fc[3] = _0;
// fc[3] = bkrd[3];
}
ffact = 1.0F;
ffact1m = 0.0F;
pixel_flag = true;
if(trans_cont_flag)
persist = (float) pow(persist, trans_cont);
}
if(pixel_flag) {
/*
inp = (fc[0]+fc[1]+fc[2]) * _inv3;
if(inp < R_SMALL4)
sig = _1;
else
sig = (float)(pow(inp,gamma) / inp);
cc0 = (uint)(sig * fc[0] * _255);
cc1 = (uint)(sig * fc[1] * _255);
cc2 = (uint)(sig * fc[2] * _255);
*/
cc0 = (uint) (fc[0] * _255);
cc1 = (uint) (fc[1] * _255);
cc2 = (uint) (fc[2] * _255);
if(cc0 > 255)
cc0 = 255;
if(cc1 > 255)
cc1 = 255;
if(cc2 > 255)
cc2 = 255;
if(orig_opaque_back) {
if(I->BigEndian)
*pixel = T->fore_mask | (cc0 << 24) | (cc1 << 16) | (cc2 << 8);
else
*pixel = T->fore_mask | (cc2 << 16) | (cc1 << 8) | cc0;
} else {
/* use alpha channel for fog with transparent backgrounds */
cc3 = (uint) (fc[3] * _255);
if(cc3 > 255)
cc3 = 255;
if(I->BigEndian)
*pixel = (cc0 << 24) | (cc1 << 16) | (cc2 << 8) | cc3;
else
*pixel = (cc3 << 24) | (cc2 << 16) | (cc1 << 8) | cc0;
}
}
if(pass && persist < 1.f) { /* average all four channels */
float mix_in;
if(i >= 0) {
if(fogFlagTmp) {
if(trans_cont_flag && (ffact > _p5)) {
mix_in =
2 * (persist * (_1 - ffact) +
((float) pow(persist, trans_cont) * (ffact - _p5)))
* (_1 - r1.trans * ffact);
} else {
mix_in = persist * (_1 - r1.trans * ffact);
}
} else {
mix_in = persist * (_1 - r1.trans);
}
} else {
mix_in = persist;
}
persist_inv = _1 - mix_in;
if(!orig_opaque_back) {
if(i < 0) { /* hit nothing -- so don't blend */
fc[0] = (float) (0xFF & (last_pixel >> 24));
fc[1] = (float) (0xFF & (last_pixel >> 16));
fc[2] = (float) (0xFF & (last_pixel >> 8));
fc[3] = (float) (0xFF & (last_pixel));
if(trans_cont_flag) { /* unless we are increasing contrast */
float m;
if(I->BigEndian) {
m = _1 - (float) (0xFF & (last_pixel)) / _255;
} else {
m = _1 - (float) (0xFF & (last_pixel >> 24)) / _255;
}
m = _1 - (float) pow(m, trans_cont);
if(I->BigEndian) {
fc[3] = m * _255 + _p499;
} else {
fc[0] = m * _255 + _p499;
}
}
} else { /* hit something -- so keep blend and compute cumulative alpha */
fc[0] =
(0xFF & ((*pixel) >> 24)) * mix_in +
(0xFF & (last_pixel >> 24)) * persist_inv;
fc[1] =
(0xFF & ((*pixel) >> 16)) * mix_in +
(0xFF & (last_pixel >> 16)) * persist_inv;
fc[2] =
(0xFF & ((*pixel) >> 8)) * mix_in +
(0xFF & (last_pixel >> 8)) * persist_inv;
fc[3] =
(0xFF & ((*pixel))) * mix_in + (0xFF & (last_pixel)) * persist_inv;
if(i >= 0) { /* make sure opaque objects get opaque alpha */
float o1, o2;
float m;
if(I->BigEndian) {
o1 = (float) (0xFF & (last_pixel)) / _255;
o2 = (float) (0xFF & (*pixel)) / _255;
} else {
o1 = (float) (0xFF & (last_pixel >> 24)) / _255;
o2 = (float) (0xFF & ((*pixel) >> 24)) / _255;
}
if(o1 < o2) { /* make sure o1 is largest opacity */
m = o1;
o1 = o2;
o2 = m;
}
m = o1 + (1.0F - o1) * o2;
if(I->BigEndian) {
fc[3] = m * _255 + _p499;
} else {
fc[0] = m * _255 + _p499;
}
}
}
} else { /* opaque background, so just blend */
fc[0] =
(0xFF & ((*pixel) >> 24)) * mix_in +
(0xFF & (last_pixel >> 24)) * persist_inv;
fc[1] =
(0xFF & ((*pixel) >> 16)) * mix_in +
(0xFF & (last_pixel >> 16)) * persist_inv;
fc[2] =
(0xFF & ((*pixel) >> 8)) * mix_in +
(0xFF & (last_pixel >> 8)) * persist_inv;
fc[3] =
(0xFF & ((*pixel))) * mix_in + (0xFF & (last_pixel)) * persist_inv;
}
cc0 = (uint) (fc[0]);
cc1 = (uint) (fc[1]);
cc2 = (uint) (fc[2]);
cc3 = (uint) (fc[3]);
if(cc0 > 255)
cc0 = 255;
if(cc1 > 255)
cc1 = 255;
if(cc2 > 255)
cc2 = 255;
if(cc3 > 255)
cc3 = 255;
*pixel = (cc0 << 24) | (cc1 << 16) | (cc2 << 8) | cc3;
}
if(depth && (i >= 0) &&
(r1.trans < trans_cutoff) && (persist > persist_cutoff)) {
depth[pixel - T->image] = (T->front + r1.impact[2]);
}
if(i >= 0) {
if(r1.prim->type == cPrimSausage) { /* carry ray through the stick */
if(perspective)
excl_trans = (2 * r1.surfnormal[2] * r1.prim->r1 / r1.dir[2]);
else
excl_trans = new_front + (2 * r1.surfnormal[2] * r1.prim->r1);
}
if((!backface_cull) && (trans_mode != 2))
persist = persist * r1.trans;
else {
if(!r1.prim->no_lighting && (persist < 0.9999F) && (r1.trans > 0.05F)) {
/* don't combine transparent surfaces */
*pixel = last_pixel;
} else {
persist = persist * r1.trans;
}
}
}
if(i < 0) { /* nothing hit */
break;
} else {
if(perspective) {
if(r1.prim->type != cPrimCharacter) {
float extend = r1.dist + 0.00001F;
scale3f(r1.dir, extend, nudge);
} else {
float extend = r1.dist;
scale3f(r1.dir, extend, nudge);
}
}
last_pixel = *pixel;
exclude2 = exclude1;
exclude1 = i;
pass++;
}
} /* end of ray while */
if(blend_colors) {
float red_min = _0;
float green_min = _0;
float blue_min = _0;
float red_part;
float green_part;
float blue_part;
if(I->BigEndian) {
fc[0] = (float) (0xFF & (*pixel >> 24));
fc[1] = (float) (0xFF & (*pixel >> 16));
fc[2] = (float) (0xFF & (*pixel >> 8));
cc3 = (0xFF & (*pixel));
} else {
cc3 = (0xFF & (*pixel >> 24));
fc[2] = (float) (0xFF & (*pixel >> 16));
fc[1] = (float) (0xFF & (*pixel >> 8));
fc[0] = (float) (0xFF & (*pixel));
}
red_part = red_blend * fc[0];
green_part = green_blend * fc[1];
blue_part = blue_blend * fc[2];
red_min = (green_part > blue_part) ? green_part : blue_part;
green_min = (red_part > blue_part) ? red_part : blue_part;
blue_min = (green_part > red_part) ? green_part : red_part;
if(fc[0] < red_min)
fc[0] = red_min;
if(fc[1] < green_min)
fc[1] = green_min;
if(fc[2] < blue_min)
fc[2] = blue_min;
cc0 = (uint) (fc[0]);
cc1 = (uint) (fc[1]);
cc2 = (uint) (fc[2]);
if(cc0 > 255)
cc0 = 255;
if(cc1 > 255)
cc1 = 255;
if(cc2 > 255)
cc2 = 255;
if(I->BigEndian)
*pixel = (cc0 << 24) | (cc1 << 16) | (cc2 << 8) | cc3;
else
*pixel = (cc3 << 24) | (cc2 << 16) | (cc1 << 8) | cc0;
}
{
/* If final pixel has alpha, then the background should be
blended into it */
unsigned char *pixel_c = (unsigned char *) pixel;
if (pixel_c[3] < 255){
float pixa = (pixel_c[3]/255.f);
float pixam1 = _1 - pixa;
float pixam1255 = pixam1 * 255.f;
if (T->bkrd_data || T->bkrd_is_gradient){
pixel_c[0] = (unsigned char)pymol_roundf(pixel_c[0] * pixa + bkrd[0] * pixam1255);
pixel_c[1] = (unsigned char)pymol_roundf(pixel_c[1] * pixa + bkrd[1] * pixam1255);
pixel_c[2] = (unsigned char)pymol_roundf(pixel_c[2] * pixa + bkrd[2] * pixam1255);
pixel_c[3] = (unsigned char)pymol_roundf(pixel_c[3] * pixa + bkrd[3] * pixam1255);
}
}
}
if(!T->edging)
break;
/* if here, then we're edging...
so accumulate averages */
{
unsigned char *pixel_c = (unsigned char *) pixel;
unsigned int c1, c2, c3, c4;
edge_avg[0] += (c1 = pixel_c[0]);
edge_avg[1] += (c2 = pixel_c[1]);
edge_avg[2] += (c3 = pixel_c[2]);
edge_avg[3] += (c4 = pixel_c[3]);
edge_alpha_avg[0] += c1 * c4;
edge_alpha_avg[1] += c2 * c4;
edge_alpha_avg[2] += c3 * c4;
edge_alpha_avg[3] += c4;
edge_cnt++;
}
} /* end of edging while */
pixel++;
} /* end of for */
}
/* end of if */
} /* end of for */
/* if(T->n_thread>1)
printf(" Ray: Thread %d: Complete.\n",T->phase+1); */
MapCacheFree(&BasisCall[0].cache, T->phase, cCache_map_scene_cache);
if(shadows && (I->NBasis > 2)) {
int bc;
for(bc = 2; bc < I->NBasis; bc++) {
MapCacheFree(&BasisCall[bc].cache, T->phase, cCache_map_shadow_cache);
}
}
return (n_hit);
}
/* This is both an antialias and a slight blur */
/* for whatever reason, greatly GCC perfers a linear sequence of
accumulates over a single large expression -- the difference is
huge: over 10% !!! */
#define combine4by4(var,src,mask) { \
var = ((src)[0 ] & mask) ; \
var += ((src)[1 ] & mask) ; \
var += ((src)[2 ] & mask) ; \
var += ((src)[3 ] & mask) ; \
var += ((src)[4 ] & mask) ; \
var +=(((src)[5 ] & mask)*13) ; \
var +=(((src)[6 ] & mask)*13) ; \
var += ((src)[7 ] & mask) ; \
var += ((src)[8 ] & mask) ; \
var +=(((src)[9 ] & mask)*13) ; \
var +=(((src)[10] & mask)*13) ; \
var += ((src)[11] & mask) ; \
var += ((src)[12] & mask) ; \
var += ((src)[13] & mask) ; \
var += ((src)[14] & mask) ; \
var += ((src)[15] & mask) ; \
var = (var >> 6) & mask; \
}
#define combine5by5(var,src,mask) { \
var = ((src)[0 ] & mask) ; \
var += ((src)[1 ] & mask) ; \
var += ((src)[2 ] & mask) ; \
var += ((src)[3 ] & mask) ; \
var += ((src)[4 ] & mask) ; \
var += ((src)[5 ] & mask) ; \
var +=(((src)[6 ] & mask)*5); \
var +=(((src)[7 ] & mask)*5); \
var +=(((src)[8 ] & mask)*5); \
var += ((src)[9 ] & mask) ; \
var += ((src)[10] & mask) ; \
var +=(((src)[11] & mask)*5); \
var +=(((src)[12] & mask)*8); \
var +=(((src)[13] & mask)*5); \
var += ((src)[14] & mask) ; \
var += ((src)[15] & mask) ; \
var +=(((src)[16] & mask)*5); \
var +=(((src)[17] & mask)*5); \
var +=(((src)[18] & mask)*5); \
var += ((src)[19] & mask) ; \
var += ((src)[20] & mask) ; \
var += ((src)[21] & mask) ; \
var += ((src)[22] & mask) ; \
var += ((src)[23] & mask) ; \
var += ((src)[24] & mask) ; \
var = (var >> 6) & mask; \
}
#define combine6by6(var,src,mask) { \
var = ((src)[0 ] & mask) ; \
var += ((src)[1 ] & mask) ; \
var += ((src)[2 ] & mask) ; \
var += ((src)[3 ] & mask) ; \
var += ((src)[4 ] & mask) ; \
var += ((src)[5 ] & mask) ; \
var += ((src)[6 ] & mask) ; \
var +=(((src)[7 ] & mask)*5); \
var +=(((src)[8 ] & mask)*7); \
var +=(((src)[9 ] & mask)*7); \
var +=(((src)[10] & mask)*5); \
var += ((src)[11] & mask) ; \
var += ((src)[12] & mask) ; \
var +=(((src)[13] & mask)*7); \
var +=(((src)[14] & mask)*8); \
var +=(((src)[15] & mask)*8); \
var +=(((src)[16] & mask)*7); \
var += ((src)[17] & mask) ; \
var += ((src)[18] & mask) ; \
var +=(((src)[19] & mask)*7); \
var +=(((src)[20] & mask)*8); \
var +=(((src)[21] & mask)*8); \
var +=(((src)[22] & mask)*7); \
var += ((src)[23] & mask) ; \
var += ((src)[24] & mask) ; \
var +=(((src)[25] & mask)*5); \
var +=(((src)[26] & mask)*7); \
var +=(((src)[27] & mask)*7); \
var +=(((src)[28] & mask)*5); \
var += ((src)[29] & mask) ; \
var += ((src)[30] & mask) ; \
var += ((src)[31] & mask) ; \
var += ((src)[32] & mask) ; \
var += ((src)[33] & mask) ; \
var += ((src)[34] & mask) ; \
var += ((src)[35] & mask) ; \
var = (var >> 7) & mask; \
}
#define m00FF 0x00FF
#define mFF00 0xFF00
#define mFFFF 0xFFFF
int RayAntiThread(CRayAntiThreadInfo * T)
{
int src_row_pixels;
unsigned int *pSrc;
unsigned int *pDst;
/* unsigned int m00FF=0x00FF,mFF00=0xFF00,mFFFF=0xFFFF; */
int width;
int height;
int x, y, yy;
unsigned int *p;
int offset = 0;
CRay *I = T->ray;
OrthoBusyFast(I->G, 9, 10);
width = (T->width / T->mag) - 2;
height = (T->height / T->mag) - 2;
src_row_pixels = T->width;
offset = (T->phase * height) / T->n_thread;
offset = offset - (offset % T->n_thread) + T->phase;
for(yy = 0; yy < height; yy++) {
y = (yy + offset) % height; /* make sure threads write to different pages */
if((y % T->n_thread) == T->phase) { /* this is my scan line */
unsigned long c1, c2, c3, c4, a;
unsigned char *c;
pSrc = T->image + src_row_pixels * (y * T->mag);
pDst = T->image_copy + width * y;
switch (T->mag) {
case 2:
{
for(x = 0; x < width; x++) {
c = (unsigned char *) (p = pSrc + (x * T->mag));
c1 = c2 = c3 = c4 = a = 0;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 13);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 13);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 13);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 13);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
if(c4) {
c1 /= c4;
c2 /= c4;
c3 /= c4;
} else { /* compute straight RGB average */
c = (unsigned char *) (p = pSrc + (x * T->mag));
c1 = c2 = c3 = 0;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += 13 * c[0];
c2 += 13 * c[1];
c3 += 13 * c[2];
c += 4;
c1 += 13 * c[0];
c2 += 13 * c[1];
c3 += 13 * c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += 13 * c[0];
c2 += 13 * c[1];
c3 += 13 * c[2];
c += 4;
c1 += 13 * c[0];
c2 += 13 * c[1];
c3 += 13 * c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 = c1 >> 6;
c2 = c2 >> 6;
c3 = c3 >> 6;
}
c = (unsigned char *) (pDst++);
*(c++) = (unsigned char) c1;
*(c++) = (unsigned char) c2;
*(c++) = (unsigned char) c3;
*(c++) = (unsigned char) (c4 >> 6);
}
}
break;
case 3:
{
for(x = 0; x < width; x++) {
c = (unsigned char *) (p = pSrc + (x * T->mag));
c1 = c2 = c3 = c4 = a = 0;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 5);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 5);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 5);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 5);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 8);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 5);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 5);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 5);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 5);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
if(c4) {
c1 /= c4;
c2 /= c4;
c3 /= c4;
} else { /* compute straight RGB average */
c = (unsigned char *) (p = pSrc + (x * T->mag));
c1 = c2 = c3 = 0;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += 5 * c[0];
c2 += 5 * c[1];
c3 += 5 * c[2];
c += 4;
c1 += 5 * c[0];
c2 += 5 * c[1];
c3 += 5 * c[2];
c += 4;
c1 += 5 * c[0];
c2 += 5 * c[1];
c3 += 5 * c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += 5 * c[0];
c2 += 5 * c[1];
c3 += 5 * c[2];
c += 4;
c1 += 8 * c[0];
c2 += 8 * c[1];
c3 += 8 * c[2];
c += 4;
c1 += 5 * c[0];
c2 += 5 * c[1];
c3 += 5 * c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += 5 * c[0];
c2 += 5 * c[1];
c3 += 5 * c[2];
c += 4;
c1 += 5 * c[0];
c2 += 5 * c[1];
c3 += 5 * c[2];
c += 4;
c1 += 5 * c[0];
c2 += 5 * c[1];
c3 += 5 * c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 = c1 >> 6;
c2 = c2 >> 6;
c3 = c3 >> 6;
}
c = (unsigned char *) (pDst++);
*(c++) = (unsigned char) c1;
*(c++) = (unsigned char) c2;
*(c++) = (unsigned char) c3;
*(c++) = (unsigned char) (c4 >> 6);
}
}
break;
case 4:
{
for(x = 0; x < width; x++) {
c = (unsigned char *) (p = pSrc + (x * T->mag));
c1 = c2 = c3 = c4 = a = 0;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 5);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 7);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 7);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 5);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 7);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 8);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 8);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 7);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 7);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 8);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 8);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 7);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 5);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 7);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 7);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3] * 5);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
c4 += (a = c[3]);
c1 += c[0] * a;
c2 += c[1] * a;
c3 += c[2] * a;
c += 4;
if(c4) {
c1 /= c4;
c2 /= c4;
c3 /= c4;
} else { /* compute straight RGB average */
c = (unsigned char *) (p = pSrc + (x * T->mag));
c1 = c2 = c3 = 0;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += 5 * c[0];
c2 += 5 * c[1];
c3 += 5 * c[2];
c += 4;
c1 += 7 * c[0];
c2 += 7 * c[1];
c3 += 7 * c[2];
c += 4;
c1 += 7 * c[0];
c2 += 7 * c[1];
c3 += 7 * c[2];
c += 4;
c1 += 5 * c[0];
c2 += 5 * c[1];
c3 += 5 * c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += 7 * c[0];
c2 += 7 * c[1];
c3 += 7 * c[2];
c += 4;
c1 += 8 * c[0];
c2 += 8 * c[1];
c3 += 8 * c[2];
c += 4;
c1 += 8 * c[0];
c2 += 8 * c[1];
c3 += 8 * c[2];
c += 4;
c1 += 7 * c[0];
c2 += 7 * c[1];
c3 += 7 * c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += 7 * c[0];
c2 += 7 * c[1];
c3 += 7 * c[2];
c += 4;
c1 += 8 * c[0];
c2 += 8 * c[1];
c3 += 8 * c[2];
c += 4;
c1 += 8 * c[0];
c2 += 8 * c[1];
c3 += 8 * c[2];
c += 4;
c1 += 7 * c[0];
c2 += 7 * c[1];
c3 += 7 * c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += 5 * c[0];
c2 += 5 * c[1];
c3 += 5 * c[2];
c += 4;
c1 += 7 * c[0];
c2 += 7 * c[1];
c3 += 7 * c[2];
c += 4;
c1 += 7 * c[0];
c2 += 7 * c[1];
c3 += 7 * c[2];
c += 4;
c1 += 5 * c[0];
c2 += 5 * c[1];
c3 += 5 * c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c = (unsigned char *) (p += src_row_pixels);
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 += c[0];
c2 += c[1];
c3 += c[2];
c += 4;
c1 = c1 >> 7;
c2 = c2 >> 7;
c3 = c3 >> 7;
}
c = (unsigned char *) (pDst++);
*(c++) = (unsigned char) c1;
*(c++) = (unsigned char) c2;
*(c++) = (unsigned char) c3;
*(c++) = (unsigned char) (c4 >> 7);
}
}
break;
}
}
}
return 1;
}
#ifdef PROFILE_BASIS
extern int n_cells;
extern int n_prims;
extern int n_triangles;
extern int n_spheres;
extern int n_cylinders;
extern int n_sausages;
extern int n_skipped;
#endif
float *rayDepthPixels = NULL;
int rayVolume = 0, rayWidth = 0, rayHeight = 0;
/*========================================================================*/
void RayRender(CRay * I, unsigned int *image, double timing,
float angle, int antialias, unsigned int *return_bg)
{
int a, x, y;
unsigned int *image_copy = NULL;
unsigned int back_mask, fore_mask = 0, trace_word = 0;
unsigned int background;
size_t buffer_size;
int orig_opaque_back = 0, opaque_back = 0;
int n_hit = 0;
const float *bkrd_ptr;
float bkrd_top[3], bkrd_bottom[3];
short bkrd_is_gradient; /* if not gradient, use bkrd_top as bkrd */
double now;
int shadows;
int n_thread;
int mag = 1;
int oversample_cutoff;
int perspective = SettingGetGlobal_i(I->G, cSetting_ray_orthoscopic);
int n_light = SettingGetGlobal_i(I->G, cSetting_light_count);
float ambient;
float *depth = NULL;
float front = I->Volume[4];
float back = I->Volume[5];
float fov = I->Fov;
float *pos = I->Pos;
size_t width = I->Width;
size_t height = I->Height;
int ray_trace_mode;
const float _0 = 0.0F, _p499 = 0.499F;
int volume;
short bkgrd_data_allocated = 0;
const char * bg_image_filename;
unsigned char *old_bkgrd_data = NULL;
int ok = true;
if(n_light > 10)
n_light = 10;
if(perspective < 0)
perspective = SettingGetGlobal_b(I->G, cSetting_ortho);
perspective = !perspective;
VLACacheSize(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
#ifdef PROFILE_BASIS
n_cells = 0;
n_prims = 0;
n_triangles = 0;
n_spheres = 0;
n_cylinders = 0;
n_sausages = 0;
n_skipped = 0;
#endif
n_thread = SettingGetGlobal_i(I->G, cSetting_max_threads);
if(n_thread < 1)
n_thread = 1;
if(n_thread > PYMOL_MAX_THREADS)
n_thread = PYMOL_MAX_THREADS;
opaque_back = SettingGetGlobal_i(I->G, cSetting_ray_opaque_background);
if(opaque_back < 0)
opaque_back = SettingGetGlobal_i(I->G, cSetting_opaque_background);
orig_opaque_back = opaque_back;
ray_trace_mode = SettingGetGlobal_i(I->G, cSetting_ray_trace_mode);
shadows = SettingGetGlobal_i(I->G, cSetting_ray_shadows);
oversample_cutoff = SettingGetGlobal_i(I->G, cSetting_ray_oversample_cutoff);
if(antialias < 0) {
antialias = SettingGetGlobal_i(I->G, cSetting_antialias);
}
if(ray_trace_mode && (antialias == 1))
antialias = 2;
else if(ray_trace_mode && antialias)
antialias++;
if(antialias < 0)
antialias = 0;
if(antialias > 4)
antialias = 4;
if((!antialias) || ray_trace_mode)
oversample_cutoff = 0;
mag = antialias;
if(mag < 1)
mag = 1;
if(antialias > 1) {
width = (width + 2) * mag;
height = (height + 2) * mag;
image_copy = image;
buffer_size = width * height;
image = CacheAlloc(I->G, unsigned int, buffer_size, 0, cCache_ray_antialias_buffer);
ErrChkPtr(I->G, image);
} else {
buffer_size = width * height;
}
if(ray_trace_mode) {
depth = Calloc(float, width * height);
} else if(oversample_cutoff) {
depth = Calloc(float, width * height);
}
ambient = SettingGetGlobal_f(I->G, cSetting_ambient);
bkrd_is_gradient = SettingGetGlobal_b(I->G, cSetting_bg_gradient);
bg_image_filename = SettingGet_s(I->G, NULL, NULL, cSetting_bg_image_filename);
old_bkgrd_data = I->bkgrd_data;
I->bkgrd_data = (unsigned char*) OrthoBackgroundDataGet(I->G, &I->bkgrd_width, &I->bkgrd_height);
if (!I->bkgrd_data && bg_image_filename && bg_image_filename[0] && I->bkgrd_width > 0 && I->bkgrd_height > 0){
if (old_bkgrd_data){
free(old_bkgrd_data);
}
if(MyPNGRead(bg_image_filename,
(unsigned char **) &I->bkgrd_data,
(unsigned int *) &I->bkgrd_width, (unsigned int *) &I->bkgrd_height)) {
bkgrd_data_allocated = 1;
bkrd_is_gradient = 0;
}
}
if (I->bkgrd_data){
opaque_back = 1;
}
if (!opaque_back){
bkrd_is_gradient = 0;
}
if (bkrd_is_gradient){
bkrd_ptr = ColorGet(I->G, SettingGet_color(I->G, NULL, NULL, cSetting_bg_rgb_top));
copy3f(bkrd_ptr, bkrd_top);
bkrd_ptr = ColorGet(I->G, SettingGet_color(I->G, NULL, NULL, cSetting_bg_rgb_bottom));
copy3f(bkrd_ptr, bkrd_bottom);
} else {
bkrd_ptr = ColorGet(I->G, SettingGet_color(I->G, NULL, NULL, cSetting_bg_rgb));
copy3f(bkrd_ptr, bkrd_top);
copy3f(bkrd_ptr, bkrd_bottom);
}
{ /* adjust bkrd and trace to offset the effect of gamma correction */
float gamma = SettingGetGlobal_f(I->G, cSetting_gamma);
float inp;
float sig;
inp = (bkrd_top[0] + bkrd_top[1] + bkrd_top[2]) / 3.0F;
if(inp < R_SMALL4)
sig = 1.0F;
else
sig = (float) (pow(inp, gamma)) / inp;
bkrd_top[0] *= sig;
bkrd_top[1] *= sig;
bkrd_top[2] *= sig;
if(bkrd_top[0] > 1.0F)
bkrd_top[0] = 1.0F;
if(bkrd_top[1] > 1.0F)
bkrd_top[1] = 1.0F;
if(bkrd_top[2] > 1.0F)
bkrd_top[2] = 1.0F;
if (bkrd_is_gradient) {
float inp;
float sig;
inp = (bkrd_bottom[0] + bkrd_bottom[1] + bkrd_bottom[2]) / 3.0F;
if(inp < R_SMALL4)
sig = 1.0F;
else
sig = (float) (pow(inp, gamma)) / inp;
bkrd_bottom[0] *= sig;
bkrd_bottom[1] *= sig;
bkrd_bottom[2] *= sig;
if(bkrd_bottom[0] > 1.0F)
bkrd_bottom[0] = 1.0F;
if(bkrd_bottom[1] > 1.0F)
bkrd_bottom[1] = 1.0F;
if(bkrd_bottom[2] > 1.0F)
bkrd_bottom[2] = 1.0F;
} else {
copy3f(bkrd_top, bkrd_bottom);
}
if(ray_trace_mode) {
float inp;
float sig;
int trace_color = SettingGetGlobal_color(I->G, cSetting_ray_trace_color);
float trgb[3];
const float *trgb_v = ColorGet(I->G, trace_color);
copy3f(trgb_v, trgb);
inp = (trgb[0] + trgb[1] + trgb[2]) / 3.0F;
if(inp < R_SMALL4)
sig = 1.0F;
else
sig = (float) (pow(inp, gamma)) / inp;
trgb[0] *= sig;
trgb[1] *= sig;
trgb[2] *= sig;
if(trgb[0] > 1.0F)
trgb[0] = 1.0F;
if(trgb[1] > 1.0F)
trgb[1] = 1.0F;
if(trgb[2] > 1.0F)
trgb[2] = 1.0F;
if(I->BigEndian) {
trace_word =
((0xFF & ((unsigned int) (trgb[0] * 255 + _p499))) << 24) |
((0xFF & ((unsigned int) (trgb[1] * 255 + _p499))) << 16) |
((0xFF & ((unsigned int) (trgb[2] * 255 + _p499))) << 8) | 0xFF;
} else {
trace_word =
0xFF000000 |
((0xFF & ((unsigned int) (trgb[2] * 255 + _p499))) << 16) |
((0xFF & ((unsigned int) (trgb[1] * 255 + _p499))) << 8) |
((0xFF & ((unsigned int) (trgb[0] * 255 + _p499))));
}
}
}
if(opaque_back) {
if(I->BigEndian)
back_mask = 0x000000FF;
else
back_mask = 0xFF000000;
fore_mask = back_mask;
} else {
back_mask = 0x00000000;
}
if (!bkrd_is_gradient) {
if(I->BigEndian) {
background = back_mask |
((0xFF & ((unsigned int) (bkrd_top[0] * 255 + _p499))) << 24) |
((0xFF & ((unsigned int) (bkrd_top[1] * 255 + _p499))) << 16) |
((0xFF & ((unsigned int) (bkrd_top[2] * 255 + _p499))) << 8);
} else {
background = back_mask |
((0xFF & ((unsigned int) (bkrd_top[2] * 255 + _p499))) << 16) |
((0xFF & ((unsigned int) (bkrd_top[1] * 255 + _p499))) << 8) |
((0xFF & ((unsigned int) (bkrd_top[0] * 255 + _p499))));
}
} else {
background = back_mask;
}
OrthoBusyFast(I->G, 2, 20);
if (!bkrd_is_gradient) {
PRINTFB(I->G, FB_Ray, FB_Blather)
" RayNew: Background = %x %d %d %d\n", background, (int) (bkrd_top[0] * 255),
(int) (bkrd_top[1] * 255), (int) (bkrd_top[2] * 255)
ENDFB(I->G);
}
if(return_bg)
*return_bg = background;
if(!I->NPrimitive) { /* nothing to render! */
if (I->bkgrd_data){
fill_background_image(I, image, width, height, width * (unsigned int) height);
} else if (bkrd_is_gradient) {
fill_gradient(I, opaque_back, image, bkrd_top, bkrd_bottom, width, height, width * (unsigned int) height);
} else {
fill(image, background, width * (unsigned int) height);
}
} else {
if(I->PrimSizeCnt) {
float factor = SettingGetGlobal_f(I->G, cSetting_ray_hint_camera);
I->PrimSize = I->PrimSize / (I->PrimSizeCnt * factor);
/* printf("avg dist %8.7f\n",I->PrimSize); */
} else {
I->PrimSize = 0.0F;
}
ok &= !I->G->Interrupt;
if (ok)
ok &= RayExpandPrimitives(I);
if (ok)
ok &= RayTransformFirst(I, perspective, false);
OrthoBusyFast(I->G, 3, 20);
now = UtilGetSeconds(I->G) - timing;
PRINTFB(I->G, FB_Ray, FB_Blather)
" Ray: processed %i graphics primitives in %4.2f sec.\n", I->NPrimitive, now
ENDFB(I->G);
if (ok) { /* light sources */
int bc;
I->NBasis = n_light + 1;
if(I->NBasis > MAX_BASIS)
I->NBasis = MAX_BASIS;
if(I->NBasis < 2)
I->NBasis = 2;
for(bc = 2; ok && bc < I->NBasis; bc++) {
ok &= BasisInit(I->G, I->Basis + bc, bc);
}
for(bc = 2; ok && bc < I->NBasis; bc++) {
{ /* setup light & rotate if necessary */
float light[3];
const float *lightv;
switch (bc) {
default:
case 2:
lightv = SettingGetfv(I->G, cSetting_light);
break;
case 3:
lightv = SettingGetfv(I->G, cSetting_light2);
break;
case 4:
lightv = SettingGetfv(I->G, cSetting_light3);
break;
case 5:
lightv = SettingGetfv(I->G, cSetting_light4);
break;
case 6:
lightv = SettingGetfv(I->G, cSetting_light5);
break;
case 7:
lightv = SettingGetfv(I->G, cSetting_light6);
break;
case 8:
lightv = SettingGetfv(I->G, cSetting_light7);
break;
case 9:
lightv = SettingGetfv(I->G, cSetting_light8);
break;
case 10:
lightv = SettingGetfv(I->G, cSetting_light9);
break;
}
copy3f(lightv, light);
normalize3f(light);
if(angle) {
float temp[16];
identity44f(temp);
MatrixRotateC44f(temp, (float) -PI * angle / 180, 0.0F, 1.0F, 0.0F);
MatrixTransformC44fAs33f3f(temp, light, light);
}
I->Basis[bc].LightNormal[0] = light[0];
I->Basis[bc].LightNormal[1] = light[1];
I->Basis[bc].LightNormal[2] = light[2];
normalize3f(I->Basis[bc].LightNormal);
{
float spec_vector[3];
copy3f(I->Basis[bc].LightNormal, spec_vector);
spec_vector[2]--;
normalize3f(spec_vector);
copy3f(spec_vector, I->Basis[bc].SpecNormal);
}
}
if(ok && shadows) { /* don't waste time on shadows unless needed */
BasisSetupMatrix(I->Basis + bc);
ok &= RayTransformBasis(I, I->Basis + bc, bc);
}
ok &= !I->G->Interrupt;
}
}
OrthoBusyFast(I->G, 4, 20);
#ifndef _PYMOL_NOPY
if(shadows && (n_thread > 1)) { /* parallel execution */
CRayHashThreadInfo *thread_info = Calloc(CRayHashThreadInfo, I->NBasis);
/* rendering map */
thread_info[0].basis = I->Basis + 1;
thread_info[0].vert2prim = I->Vert2Prim;
thread_info[0].prim = I->Primitive;
thread_info[0].n_prim = I->NPrimitive;
thread_info[0].clipBox = I->Volume;
thread_info[0].phase = 0;
thread_info[0].perspective = perspective;
thread_info[0].front = front;
thread_info[0].image = image;
thread_info[0].bkrd_is_gradient = bkrd_is_gradient;
thread_info[0].width = width;
thread_info[0].height = height;
if (I->bkgrd_data){
thread_info[0].background = background;
thread_info[0].opaque_back = opaque_back;
} else if (bkrd_is_gradient){
thread_info[0].bkrd_top = bkrd_top;
thread_info[0].bkrd_bottom = bkrd_bottom;
thread_info[0].opaque_back = opaque_back;
} else {
thread_info[0].background = background;
}
thread_info[0].bytes = width * (unsigned int) height;
thread_info[0].ray = I; /* for compute box */
thread_info[0].size_hint = I->PrimSize;
/* shadow map */
{
int bc;
float factor = SettingGetGlobal_f(I->G, cSetting_ray_hint_shadow);
for(bc = 2; bc < I->NBasis; bc++) {
thread_info[bc - 1].basis = I->Basis + bc;
thread_info[bc - 1].vert2prim = I->Vert2Prim;
thread_info[bc - 1].prim = I->Primitive;
thread_info[bc - 1].n_prim = I->NPrimitive;
thread_info[bc - 1].clipBox = NULL;
thread_info[bc - 1].phase = bc - 1;
thread_info[bc - 1].perspective = false;
thread_info[bc - 1].front = _0;
/* allowing these maps to be more fine helps performance */
thread_info[bc - 1].size_hint = I->PrimSize * factor;
}
}
/* NOTE that we're not limiting the number of threads in this phase
under the assumption that it will usually just be a few threads */
RayHashSpawn(thread_info, n_thread, I->NBasis - 1);
FreeP(thread_info);
} else
#endif
if (ok){
#ifdef _PYMOL_NOPY
n_thread = 1; /* serial execution */
#endif
ok &= BasisMakeMap(I->Basis + 1, I->Vert2Prim, I->Primitive, I->NPrimitive,
I->Volume, 0, cCache_ray_map, perspective, front, I->PrimSize);
if(ok && shadows) {
int bc;
float factor = SettingGetGlobal_f(I->G, cSetting_ray_hint_shadow);
for(bc = 2; ok && bc < I->NBasis; bc++) {
ok &= BasisMakeMap(I->Basis + bc, I->Vert2Prim, I->Primitive, I->NPrimitive,
NULL, bc - 1, cCache_ray_map, false, _0, I->PrimSize * factor);
}
}
/* serial tasks which RayHashThread does in parallel mode using the first thread */
if (ok){
if (I->bkgrd_data){
fill_background_image(I, image, width, height, width * (unsigned int) height);
} else if (bkrd_is_gradient) {
fill_gradient(I, opaque_back, image, bkrd_top, bkrd_bottom, width, height, width * (unsigned int) height);
} else {
fill(image, background, width * (unsigned int) height);
}
RayComputeBox(I);
}
}
OrthoBusyFast(I->G, 5, 20);
now = UtilGetSeconds(I->G) - timing;
if (ok){
if(shadows) {
PRINTFB(I->G, FB_Ray, FB_Blather)
" Ray: voxels: [%4.2f:%dx%dx%d], [%4.2f:%dx%dx%d], %4.2f sec.\n",
I->Basis[1].Map->Div, I->Basis[1].Map->Dim[0],
I->Basis[1].Map->Dim[1], I->Basis[1].Map->Dim[2],
I->Basis[2].Map->Div, I->Basis[2].Map->Dim[0],
I->Basis[2].Map->Dim[2], I->Basis[2].Map->Dim[2], now ENDFB(I->G);
} else {
PRINTFB(I->G, FB_Ray, FB_Blather)
" Ray: voxels: [%4.2f:%dx%dx%d], %4.2f sec.\n",
I->Basis[1].Map->Div, I->Basis[1].Map->Dim[0],
I->Basis[1].Map->Dim[1], I->Basis[1].Map->Dim[2], now ENDFB(I->G);
}
}
/* IMAGING */
if (ok){
/* now spawn threads as needed */
CRayThreadInfo *rt = Calloc(CRayThreadInfo, n_thread);
int x_start = 0, y_start = 0;
int x_stop = 0, y_stop = 0;
float x_test = _0, y_test = _0;
int x_pixel, y_pixel;
if(perspective) {
int c;
if(I->min_box[2] > -front)
I->min_box[2] = -front;
if(I->max_box[2] > -front)
I->max_box[2] = -front;
for(c = 0; c < 4; c++) {
switch (c) {
case 0:
x_test = -I->min_box[0] / I->min_box[2];
y_test = -I->min_box[1] / I->min_box[2];
break;
case 1:
x_test = -I->min_box[0] / I->max_box[2];
y_test = -I->min_box[1] / I->max_box[2];
break;
case 2:
x_test = -I->max_box[0] / I->min_box[2];
y_test = -I->max_box[1] / I->min_box[2];
break;
case 3:
x_test = -I->max_box[0] / I->max_box[2];
y_test = -I->max_box[1] / I->max_box[2];
break;
}
/* project onto back to get the effective range */
x_pixel =
(int) (width * (((x_test * I->Volume[5]) - I->Volume[0]) / I->Range[0]));
y_pixel =
(int) (height * (((y_test * I->Volume[5]) - I->Volume[2]) / I->Range[1]));
if(!c) {
x_start = x_pixel;
x_stop = x_pixel;
y_start = y_pixel;
y_stop = y_pixel;
} else {
if(x_start > x_pixel)
x_start = x_pixel;
if(x_stop < x_pixel)
x_stop = x_pixel;
if(y_start > y_pixel)
y_start = y_pixel;
if(y_stop < y_pixel)
y_stop = y_pixel;
}
}
x_start -= 2;
x_stop += 2;
y_start -= 2;
y_stop += 2;
/*
x_start = 0;
y_start = 0;
x_stop = width;
y_stop = height; */
} else {
x_start = (int) ((width * (I->min_box[0] - I->Volume[0])) / I->Range[0]) - 2;
x_stop = (int) ((width * (I->max_box[0] - I->Volume[0])) / I->Range[0]) + 2;
y_stop = (int) ((height * (I->max_box[1] - I->Volume[2])) / I->Range[1]) + 2;
y_start = (int) ((height * (I->min_box[1] - I->Volume[2])) / I->Range[1]) - 2;
}
if(x_start < 0)
x_start = 0;
if(y_start < 0)
y_start = 0;
if(x_stop > width)
x_stop = width;
if(y_stop > height)
y_stop = height;
for(a = 0; a < n_thread; a++) {
rt[a].ray = I;
rt[a].width = width;
rt[a].height = height;
rt[a].x_start = x_start;
rt[a].x_stop = x_stop;
rt[a].y_start = y_start;
rt[a].y_stop = y_stop;
rt[a].image = image;
rt[a].border = mag - 1;
rt[a].front = front;
rt[a].back = back;
rt[a].fore_mask = fore_mask;
rt[a].bkrd_is_gradient = bkrd_is_gradient;
if (bkrd_is_gradient){
rt[a].bkrd_top = bkrd_top;
rt[a].bkrd_bottom = bkrd_bottom;
} else {
rt[a].bkrd_top = bkrd_top;
rt[a].bkrd_bottom = bkrd_top;
}
rt[a].ambient = ambient;
rt[a].background = background;
rt[a].phase = a;
rt[a].n_thread = n_thread;
rt[a].edging = NULL;
rt[a].edging_cutoff = oversample_cutoff; /* info needed for busy indicator */
rt[a].perspective = perspective;
rt[a].fov = fov;
rt[a].pos[2] = pos[2];
rt[a].depth = depth;
rt[a].bgWidth = I->bkgrd_width;
rt[a].bgHeight = I->bkgrd_height;
rt[a].bkrd_data = I->bkgrd_data;
}
#ifndef _PYMOL_NOPY
if(n_thread > 1)
RayTraceSpawn(rt, n_thread);
else
#endif
RayTraceThread(rt);
if(oversample_cutoff) { /* perform edge oversampling, if requested */
unsigned int *edging;
edging = CacheAlloc(I->G, unsigned int, buffer_size, 0, cCache_ray_edging_buffer);
memcpy(edging, image, buffer_size * sizeof(unsigned int));
for(a = 0; a < n_thread; a++) {
rt[a].edging = edging;
}
#ifndef _PYMOL_NOPY
if(n_thread > 1)
RayTraceSpawn(rt, n_thread);
else
#endif
RayTraceThread(rt);
CacheFreeP(I->G, edging, 0, cCache_ray_edging_buffer, false);
}
FreeP(rt);
}
}
if(ok && depth && ray_trace_mode) {
float *delta = Alloc(float, 3 * width * height);
int x, y;
ErrChkPtr(I->G, delta);
if (ok) {
int xc, yc;
float d, dzdx, dzdy, *p, *q, dd;
p = depth;
q = delta;
for(y = 0; y < height; y++)
for(x = 0; x < width; x++) {
dzdx = 0.0F;
dzdy = 0.0F;
xc = 0;
yc = 0;
d = *p;
if(x) {
dd = d - p[-1];
dzdx += dd;
xc++;
}
if(x < (width - 1)) {
dd = p[1] - d;
if((!xc) || (fabs(dd) > fabs(dzdx)))
dzdx = dd;
xc = 1;
}
if(y) {
dd = d - p[-width];
dzdy += dd;
yc++;
}
if(y < (height - 1)) {
dd = p[width] - d;
if((!yc) || (fabs(dd) > fabs(dzdy)))
dzdy = dd;
yc = 1;
}
p++;
*(q++) = dzdx;
*(q++) = dzdy;
/*
if(((x == y )||(x==width/2)||(y==height/2))&&((dzdx!=0.0F) || (dzdy!=0.0F))) {
printf("%5d %5d : %8.3f %8.3f\n",y,x,dzdx,dzdy);
} */
*(q++) = sqrt1f(dzdx * dzdx + dzdy * dzdy);
}
}
if (ok){
int i;
{
const float _1 = 1.0F;
float invFrontMinusBack = _1 / (front - back);
float inv1minusFogStart = _1;
int fogFlag = false;
float fog_start = 0.0F;
int fogRangeFlag = false;
float fog = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog);
if(fog < 0.0F) {
if(SettingGetGlobal_b(I->G, cSetting_depth_cue)) {
fog = SettingGetGlobal_f(I->G, cSetting_fog);
} else
fog = _0;
}
if(fog != _0) {
if(fog > 1.0F)
fog = 1.0F;
fogFlag = true;
fog_start = SettingGetGlobal_f(I->G, cSetting_ray_trace_fog_start);
if(fog_start < 0.0F)
fog_start = SettingGetGlobal_f(I->G, cSetting_fog_start);
if(fog_start > 1.0F)
fog_start = 1.0F;
if(fog_start < 0.0F)
fog_start = 0.0F;
if(fog_start > R_SMALL4) {
fogRangeFlag = true;
if(fabs(fog_start - 1.0F) < R_SMALL4) /* prevent div/0 */
fogFlag = false;
}
inv1minusFogStart = _1 / (_1 - fog_start);
}
if(fogFlag) { /* make sure we have depth values at every potentially drawn pixel */
float *tmp = Alloc(float, width * height);
float dep;
float *p, *q;
int cnt;
for(i = 0; i < 3; i++) { /* three passes required */
p = depth;
q = tmp;
for(y = 0; y < height; y++)
for(x = 0; x < width; x++) {
if(fabs(*p) < R_SMALL4) {
dep = 0.0F;
cnt = 0;
if(x) {
if(fabs(p[-1]) > R_SMALL4) {
dep += p[-1];
cnt++;
}
}
if(x < (width - 1)) {
if(fabs(p[1]) > R_SMALL4) {
dep += p[1];
cnt++;
}
}
if(y) {
if(fabs(p[-width]) > R_SMALL4) {
dep += p[-width];
cnt++;
}
}
if(y < (height - 1)) {
if(fabs(p[width]) > R_SMALL4) {
dep += p[width];
cnt++;
}
}
if(cnt) {
dep /= cnt;
*q = dep;
}
} else {
*q = *p;
}
p++;
q++;
}
p = tmp;
tmp = depth;
depth = p;
}
FreeP(tmp);
}
{
unsigned int *q = image;
float *p = delta;
int width3 = width * 3;
float slope_f = SettingGetGlobal_f(I->G, cSetting_ray_trace_slope_factor);
float depth_f = SettingGetGlobal_f(I->G, cSetting_ray_trace_depth_factor);
float disco_f = SettingGetGlobal_f(I->G, cSetting_ray_trace_disco_factor);
float diff, max_depth;
float dot, min_dot, max_slope, max_dz, max_pz;
float dx, dy, dz, px = 0.0F, py = 0.0F, pz = 0.0F, ddx, ddy;
const float _8 = 0.08F;
const float _4 = 0.4F;
const float _25 = 0.25F;
const float _m25 = -0.25F;
float disco_f_625 = disco_f * 0.625F;
float disco_f_5 = disco_f * 0.5F;
float disco_f_45 = disco_f * 0.45F;
{
float gain =
I->PixelRadius / (SettingGetGlobal_f(I->G, cSetting_ray_trace_gain) *
I->Magnified);
if(antialias)
gain /= antialias;
slope_f *= gain;
depth_f *= gain;
disco_f *= gain;
}
for(y = 0; y < height; y++){
float bkrd[3], perc = 0.;
if (bkrd_is_gradient) {
/* for RayRender, y is from bottom to top */
perc = y/(float)height;
bkrd[0] = bkrd_bottom[0] + perc * (bkrd_top[0] - bkrd_bottom[0]);
bkrd[1] = bkrd_bottom[1] + perc * (bkrd_top[1] - bkrd_bottom[1]);
bkrd[2] = bkrd_bottom[2] + perc * (bkrd_top[2] - bkrd_bottom[2]);
if(I->BigEndian) {
background = back_mask |
((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))) << 24) |
((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 16) |
((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 8);
} else {
background = back_mask |
((0xFF & ((unsigned int) (bkrd[2] * 255 + _p499))) << 16) |
((0xFF & ((unsigned int) (bkrd[1] * 255 + _p499))) << 8) |
((0xFF & ((unsigned int) (bkrd[0] * 255 + _p499))));
}
}
for(x = 0; x < width; x++) {
max_slope = 0.0F;
max_depth = 0.0F;
min_dot = 1.0F;
max_dz = 0.0F;
max_pz = 0.0F;
dx = p[0];
dy = p[1];
dz = p[2];
for(i = 0; i < 8; i++) {
switch (i) {
case 0:
if(x) {
px = p[-3];
py = p[-2];
pz = p[-1];
}
break;
case 1:
if(x < (width - 1)) {
px = p[3];
py = p[4];
pz = p[5];
}
break;
case 2:
if(y) {
px = p[-width3];
py = p[-width3 + 1];
pz = p[-width3 + 2];
}
break;
case 3:
if(y < (height - 1)) {
px = p[width3];
py = p[width3 + 1];
pz = p[width3 + 2];
}
break;
case 4:
if(x && y) {
px = p[-width3 - 3];
py = p[-width3 - 2];
pz = p[-width3 - 1];
}
break;
case 5:
if(x && (y < (height - 1))) {
px = p[width3 - 3];
py = p[width3 - 2];
pz = p[width3 - 1];
}
break;
case 6:
if(y && (x < (width - 1))) {
px = p[-width3 + 3];
py = p[-width3 + 4];
pz = p[-width3 + 5];
}
break;
case 7:
if((y < (height - 1)) && (x < (width - 1))) {
px = p[width3 + 3];
py = p[width3 + 4];
pz = p[width3 + 5];
}
break;
}
ddx = dx - px;
ddy = dy - py;
diff = ddx * ddx + ddy * ddy;
if(max_depth < diff)
max_depth = diff;
if((dz > R_SMALL4) && (pz > R_SMALL4)) {
dot = (dx / dz) * (px / pz) + (dy / dz) * (py / pz);
if(dot < min_dot) {
min_dot = dot;
max_dz = dz;
max_pz = pz;
}
}
/* if(dz>max_dz) max_dz = dz;
if(pz>max_pz) max_pz = pz; */
diff = fabs(dz - pz);
if(diff > max_slope)
max_slope = diff;
}
if((max_slope > (slope_f)) /* depth */
||(max_depth > (depth_f))
/* slope */
/* gradient discontinuities -- could probably use more tuning... */
|| ((min_dot < _8) && ((max_dz > disco_f) || (max_pz > disco_f)))
|| ((min_dot < _4) && ((max_dz > disco_f_625) || (max_pz > disco_f_625)))
|| ((min_dot < _25) && ((max_dz > disco_f_5) || (max_pz > disco_f_5)))
|| ((min_dot < _m25) && ((max_dz > disco_f_45) && (max_pz > disco_f_45)))
) {
if(fogFlag) {
float ffact = depth[q - image] * invFrontMinusBack;
float ffact1m;
float fc[4];
unsigned int cc0, cc1, cc2, cc3;
if(fogRangeFlag)
ffact = (ffact - fog_start) * inv1minusFogStart;
ffact *= fog;
if(ffact < _0)
ffact = _0;
if(ffact > _1)
ffact = _1;
ffact1m = _1 - ffact;
if(orig_opaque_back) {
fc[0] =
(0xFF & (background >> 24)) * ffact +
(0xFF & (trace_word >> 24)) * ffact1m;
fc[1] =
(0xFF & (background >> 16)) * ffact +
(0xFF & (trace_word >> 16)) * ffact1m;
fc[2] =
(0xFF & (background >> 8)) * ffact +
(0xFF & (trace_word >> 8)) * ffact1m;
fc[3] =
(0xFF & (background)) * ffact + (0xFF & (trace_word)) * ffact1m;
} else { /* if non-opaque background, then use alpha to blend */
fc[1] = (0xFF & (trace_word >> 16));
fc[2] = (0xFF & (trace_word >> 8));
if(I->BigEndian) {
fc[0] = (0xFF & (trace_word >> 24));
fc[3] =
(0xFF & (background)) * ffact + (0xFF & (trace_word)) * ffact1m;
} else {
fc[0] =
(0xFF & (background >> 24)) * ffact +
(0xFF & (trace_word >> 24)) * ffact1m;
fc[3] = (0xFF & (trace_word));
}
}
cc0 = (uint) (fc[0]);
cc1 = (uint) (fc[1]);
cc2 = (uint) (fc[2]);
cc3 = (uint) (fc[3]);
if(cc0 > 255)
cc0 = 255;
if(cc1 > 255)
cc1 = 255;
if(cc2 > 255)
cc2 = 255;
if(cc3 > 255)
cc3 = 255;
*q = (cc0 << 24) | (cc1 << 16) | (cc2 << 8) | cc3;
} else {
*q = trace_word;
}
} else if(ray_trace_mode == 2) { /* only draw edge */
*q = background;
} else if(ray_trace_mode == 3) { /* quantize */
*q = (*q & 0xC0C0C0C0);
*q = *q | ((*q) >> 2) | ((*q) >> 4) | ((*q) >> 6);
}
p += 3;
q++;
}
}
}
}
}
FreeP(delta);
}
if(ok && antialias > 1) {
/* now spawn threads as needed */
CRayAntiThreadInfo *rt = Calloc(CRayAntiThreadInfo, n_thread);
for(a = 0; a < n_thread; a++) {
rt[a].width = width;
rt[a].height = height;
rt[a].image = image;
rt[a].image_copy = image_copy;
rt[a].phase = a;
rt[a].mag = mag; /* fold magnification */
rt[a].n_thread = n_thread;
rt[a].ray = I;
}
#ifndef _PYMOL_NOPY
if(n_thread > 1)
RayAntiSpawn(rt, n_thread);
else
#endif
RayAntiThread(rt);
FreeP(rt);
CacheFreeP(I->G, image, 0, cCache_ray_antialias_buffer, false);
image = image_copy;
}
PRINTFD(I->G, FB_Ray)
" RayRender: n_hit %d\n", n_hit ENDFD;
#ifdef PROFILE_BASIS
printf
("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",
n_cells, n_prims, n_triangles / ((float) n_cells), n_spheres / ((float) n_cells),
n_cylinders / ((float) n_cells), n_sausages / ((float) n_cells),
n_skipped / ((float) n_cells));
#endif
if (ok){
/* EXPERIMENTAL RAY-VOLUME CODE */
volume = SettingGetGlobal_b(I->G, cSetting_ray_volume);
if (volume) {
for(y = 0; y < height; y++) {
for(x = 0; x < width; x++) {
float dd = depth[x+width*y];
if (dd == 0.0) dd = -back;
depth[x+width*y] = -dd/(back-front) + 0.1;
}
}
if (rayDepthPixels)
FreeP(rayDepthPixels);
rayDepthPixels = depth;
rayWidth = width;
rayHeight = height;
rayVolume = 3;
} else
FreeP(depth);
if (bkgrd_data_allocated && I->bkgrd_data){
free(I->bkgrd_data);
}
}
I->bkgrd_data = NULL;
}
void RayRenderColorTable(CRay * I, int width, int height, int *image)
{
int x, y;
unsigned int r = 0, g = 0, b = 0;
unsigned int *pixel, mask, *p;
if(I->BigEndian)
mask = 0x000000FF;
else
mask = 0xFF000000;
p = (unsigned int *) image;
for(x = 0; x < width; x++)
for(y = 0; y < height; y++)
*(p++) = mask;
if((width >= 512) && (height >= 512)) {
for(y = 0; y < 512; y++)
for(x = 0; x < 512; x++) {
pixel = (unsigned int *) (image + ((width) * y) + x);
if(I->BigEndian) {
*(pixel) = mask | (r << 24) | (g << 16) | (b << 8);
} else {
*(pixel) = mask | (b << 16) | (g << 8) | r;
}
b = b + 4;
if(!(0xFF & b)) {
b = 0;
g = g + 4;
if(!(0xFF & g)) {
g = 0;
r = r + 4;
}
}
}
}
}
/*========================================================================*/
void CRay::wobble(int mode, const float *v)
{
CRay * I = this;
I->Wobble = mode;
if(v)
copy3f(v, I->WobbleParam);
}
/*========================================================================*/
void CRay::transparentf(float v)
{
CRay * I = this;
if(v > 1.0F)
v = 1.0F;
if(v < 0.0F)
v = 0.0F;
I->Trans = v;
}
void CRay::interiorColor3fv(const float *v, int passive)
{
CRay * I = this;
I->IntColor[0] = (*v++);
I->IntColor[1] = (*v++);
I->IntColor[2] = (*v++);
if(!passive)
I->CheckInterior = true;
}
/*========================================================================*/
void CRay::color3fv(const float *v)
{
CRay * I = this;
I->CurColor[0] = (*v++);
I->CurColor[1] = (*v++);
I->CurColor[2] = (*v++);
}
/*========================================================================*/
int CRay::sphere3fv(const float *v, float r)
{
CRay * I = this;
CPrimitive *p;
int ok = true;
float *vv;
VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
CHECKOK(ok, I->Primitive);
if (!ok)
return false;
p = I->Primitive + I->NPrimitive;
p->type = cPrimSphere;
p->r1 = r;
p->trans = I->Trans;
p->wobble = I->Wobble;
p->ramped = (I->CurColor[0] < 0.0F);
p->no_lighting = 0;
I->PrimSize += 2 * r;
I->PrimSizeCnt++;
/*
copy3f(I->WobbleParam,p->wobble_param); */
vv = p->v1;
(*vv++) = (*v++);
(*vv++) = (*v++);
(*vv++) = (*v++);
vv = p->c1;
v = I->CurColor;
(*vv++) = (*v++);
(*vv++) = (*v++);
(*vv++) = (*v++);
vv = p->ic;
v = I->IntColor;
(*vv++) = (*v++);
(*vv++) = (*v++);
(*vv++) = (*v++);
if(I->TTTFlag) {
p->r1 *= length3f(I->TTT);
transformTTT44f3f(I->TTT, p->v1, p->v1);
}
if(I->Context) {
RayApplyContextToVertex(I, p->v1);
}
I->NPrimitive++;
return true;
}
void RayGetScaledAxes(CRay * I, float *xn, float *yn)
{
float *v;
float vt[3];
float xn0[3] = { 1.0F, 0.0F, 0.0F };
float yn0[3] = { 0.0F, 1.0F, 0.0F };
float v_scale;
v = TextGetPos(I->G);
if(I->TTTFlag) {
transformTTT44f3f(I->TTT, v, vt);
} else {
copy3f(v, vt);
}
v_scale = RayGetScreenVertexScale(I, vt) / I->Sampling;
RayApplyMatrixInverse33(1, (float3 *) xn0, I->Rotation, (float3 *) xn0);
RayApplyMatrixInverse33(1, (float3 *) yn0, I->Rotation, (float3 *) yn0);
scale3f(xn0, v_scale, xn);
scale3f(yn0, v_scale, yn);
}
/*========================================================================*/
int CRay::character(int char_id)
{
CRay * I = this;
CPrimitive *p;
float *v;
float vt[3];
float *vv;
float width, height;
float v_scale;
int ok = true;
v = TextGetPos(I->G);
VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive + 1, 0,
cCache_ray_primitive);
CHECKOK(ok, I->Primitive);
if (!ok)
return false;
p = I->Primitive + I->NPrimitive;
p->type = cPrimCharacter;
p->trans = I->Trans;
p->char_id = char_id;
p->wobble = I->Wobble;
p->ramped = 0;
p->no_lighting = 0;
/*
copy3f(I->WobbleParam,p->wobble_param); */
vv = p->v1;
(*vv++) = v[0];
(*vv++) = v[1];
(*vv++) = v[2];
if(I->TTTFlag) {
transformTTT44f3f(I->TTT, p->v1, p->v1);
}
/* what's the width of 1 screen window pixel at this point in space? */
v_scale = RayGetScreenVertexScale(I, p->v1) / I->Sampling;
if(I->Context) {
RayApplyContextToVertex(I, p->v1);
}
{
float xn[3] = { 1.0F, 0.0F, 0.0F };
float yn[3] = { 0.0F, 1.0F, 0.0F };
float zn[3] = { 0.0F, 0.0F, 1.0F };
float sc[3];
float scale;
float xorig, yorig, advance;
int width_i, height_i;
CPrimitive *pp = p + 1;
RayApplyMatrixInverse33(1, (float3 *) xn, I->Rotation, (float3 *) xn);
RayApplyMatrixInverse33(1, (float3 *) yn, I->Rotation, (float3 *) yn);
RayApplyMatrixInverse33(1, (float3 *) zn, I->Rotation, (float3 *) zn);
CharacterGetGeometry(I->G, char_id, &width_i, &height_i, &xorig, &yorig, &advance);
width = (float) width_i;
height = (float) height_i;
scale = v_scale * advance;
scale3f(xn, scale, vt); /* advance raster position in 3-space */
add3f(v, vt, vt);
TextSetPos(I->G, vt);
/* position the pixmap relative to raster position */
/* scale = ((-xorig)-0.5F)*I->PixelRadius; */
scale = ((-xorig) - 0.0F) * v_scale;
scale3f(xn, scale, sc);
add3f(sc, p->v1, p->v1);
scale = ((-yorig) - 0.0F) * v_scale;
scale3f(yn, scale, sc);
add3f(sc, p->v1, p->v1);
scale = v_scale * width;
scale3f(xn, scale, xn);
scale = v_scale * height;
scale3f(yn, scale, yn);
copy3f(zn, p->n0);
copy3f(zn, p->n1);
copy3f(zn, p->n2);
copy3f(zn, p->n3);
*(pp) = (*p);
/* define coordinates of first triangle */
add3f(p->v1, xn, p->v2);
add3f(p->v1, yn, p->v3);
I->PrimSize +=
2 * (diff3f(p->v1, p->v2) + diff3f(p->v1, p->v3) + diff3f(p->v2, p->v3));
I->PrimSizeCnt += 6;
/* encode characters coordinates in the colors */
zero3f(p->c1);
set3f(p->c2, width, 0.0F, 0.0F);
set3f(p->c3, 0.0F, height, 0.0F);
/* define coordinates of second triangle */
add3f(yn, xn, pp->v1);
add3f(p->v1, pp->v1, pp->v1);
add3f(p->v1, yn, pp->v2);
add3f(p->v1, xn, pp->v3);
{
float *v, *vv;
vv = p->ic;
v = I->IntColor;
(*vv++) = (*v++);
(*vv++) = (*v++);
(*vv++) = (*v++);
vv = pp->ic;
v = I->IntColor;
(*vv++) = (*v++);
(*vv++) = (*v++);
(*vv++) = (*v++);
}
/* encode integral character coordinates into the vertex colors */
set3f(pp->c1, width, height, 0.0F);
set3f(pp->c2, 0.0F, height, 0.0F);
set3f(pp->c3, width, 0.0F, 0.0F);
}
I->NPrimitive += 2;
return true;
}
/*========================================================================*/
int CRay::cylinder3fv(const float *v1, const float *v2, float r, const float *c1, const float *c2)
{
CRay * I = this;
CPrimitive *p;
int ok = true;
float *vv;
VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
CHECKOK(ok, I->Primitive);
if (!ok)
return false;
p = I->Primitive + I->NPrimitive;
p->type = cPrimCylinder;
p->r1 = r;
p->trans = I->Trans;
p->cap1 = cCylCapFlat;
p->cap2 = cCylCapFlat;
p->wobble = I->Wobble;
p->ramped = ((c1[0] < 0.0F) || (c2[0] < 0.0F));
p->no_lighting = 0;
/*
copy3f(I->WobbleParam,p->wobble_param); */
vv = p->v1;
(*vv++) = (*v1++);
(*vv++) = (*v1++);
(*vv++) = (*v1++);
vv = p->v2;
(*vv++) = (*v2++);
(*vv++) = (*v2++);
(*vv++) = (*v2++);
I->PrimSize += diff3f(p->v1, p->v2) + 2 * r;
I->PrimSizeCnt++;
if(I->TTTFlag) {
p->r1 *= length3f(I->TTT);
transformTTT44f3f(I->TTT, p->v1, p->v1);
transformTTT44f3f(I->TTT, p->v2, p->v2);
}
if(I->Context) {
RayApplyContextToVertex(I, p->v1);
RayApplyContextToVertex(I, p->v2);
}
vv = p->c1;
(*vv++) = (*c1++);
(*vv++) = (*c1++);
(*vv++) = (*c1++);
vv = p->c2;
(*vv++) = (*c2++);
(*vv++) = (*c2++);
(*vv++) = (*c2++);
{
float *v;
vv = p->ic;
v = I->IntColor;
(*vv++) = (*v++);
(*vv++) = (*v++);
(*vv++) = (*v++);
}
I->NPrimitive++;
return true;
}
/*========================================================================*/
int CRay::customCylinder3fv(const float *v1, const float *v2, float r,
const float *c1, const float *c2, int cap1, int cap2)
{
CRay * I = this;
CPrimitive *p;
int ok = true;
float *vv;
VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
CHECKOK(ok, I->Primitive);
if (!ok)
return false;
p = I->Primitive + I->NPrimitive;
p->type = cPrimCylinder;
p->r1 = r;
p->trans = I->Trans;
p->cap1 = cap1;
p->cap2 = cap2;
p->wobble = I->Wobble;
p->ramped = ((c1[0] < 0.0F) || (c2[0] < 0.0F));
p->no_lighting = 0;
/*
copy3f(I->WobbleParam,p->wobble_param); */
vv = p->v1;
(*vv++) = (*v1++);
(*vv++) = (*v1++);
(*vv++) = (*v1++);
vv = p->v2;
(*vv++) = (*v2++);
(*vv++) = (*v2++);
(*vv++) = (*v2++);
I->PrimSize += diff3f(p->v1, p->v2) + 2 * r;
I->PrimSizeCnt++;
if(I->TTTFlag) {
p->r1 *= length3f(I->TTT);
transformTTT44f3f(I->TTT, p->v1, p->v1);
transformTTT44f3f(I->TTT, p->v2, p->v2);
}
if(I->Context) {
RayApplyContextToVertex(I, p->v1);
RayApplyContextToVertex(I, p->v2);
}
vv = p->c1;
(*vv++) = (*c1++);
(*vv++) = (*c1++);
(*vv++) = (*c1++);
vv = p->c2;
(*vv++) = (*c2++);
(*vv++) = (*c2++);
(*vv++) = (*c2++);
vv = p->ic;
{
float *v;
vv = p->ic;
v = I->IntColor;
(*vv++) = (*v++);
(*vv++) = (*v++);
(*vv++) = (*v++);
}
I->NPrimitive++;
return true;
}
int CRay::cone3fv(const float *v1, const float *v2, float r1, float r2,
const float *c1, const float *c2, int cap1, int cap2)
{
CRay * I = this;
CPrimitive *p;
float r_max = (r1 > r2) ? r1 : r2;
float *vv;
int ok = true;
if(r2 > r1) { /* make sure r1 is always larger */
float t;
const float *tp;
int ti;
t = r2;
r2 = r1;
r1 = t;
tp = c2;
c2 = c1;
c1 = tp;
tp = v2;
v2 = v1;
v1 = tp;
ti = cap2;
cap2 = cap1;
cap1 = ti;
}
VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
CHECKOK(ok, I->Primitive);
if (!ok)
return false;
p = I->Primitive + I->NPrimitive;
p->type = cPrimCone;
p->r1 = r1;
p->r2 = r2;
p->trans = I->Trans;
p->cap1 = cap1;
if(cap2 >= cCylCapFlat)
cap2 = cCylCapFlat;
if(cap1 >= cCylCapFlat)
cap1 = cCylCapFlat;
p->cap2 = cap2;
p->wobble = I->Wobble;
p->ramped = ((c1[0] < 0.0F) || (c2[0] < 0.0F));
p->no_lighting = 0;
/*
copy3f(I->WobbleParam,p->wobble_param); */
vv = p->v1;
(*vv++) = (*v1++);
(*vv++) = (*v1++);
(*vv++) = (*v1++);
vv = p->v2;
(*vv++) = (*v2++);
(*vv++) = (*v2++);
(*vv++) = (*v2++);
I->PrimSize += diff3f(p->v1, p->v2) + 2 * r_max;
I->PrimSizeCnt++;
if(I->TTTFlag) {
transformTTT44f3f(I->TTT, p->v1, p->v1);
transformTTT44f3f(I->TTT, p->v2, p->v2);
}
if(I->Context) {
RayApplyContextToVertex(I, p->v1);
RayApplyContextToVertex(I, p->v2);
}
vv = p->c1;
(*vv++) = (*c1++);
(*vv++) = (*c1++);
(*vv++) = (*c1++);
vv = p->c2;
(*vv++) = (*c2++);
(*vv++) = (*c2++);
(*vv++) = (*c2++);
vv = p->ic;
{
float *v;
vv = p->ic;
v = I->IntColor;
(*vv++) = (*v++);
(*vv++) = (*v++);
(*vv++) = (*v++);
}
I->NPrimitive++;
return true;
}
/*========================================================================*/
int CRay::sausage3fv(const float *v1, const float *v2, float r, const float *c1, const float *c2)
{
CRay * I = this;
CPrimitive *p;
int ok = true;
float *vv;
VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
CHECKOK(ok, I->Primitive);
if (!ok)
return false;
p = I->Primitive + I->NPrimitive;
p->type = cPrimSausage;
p->r1 = r;
p->trans = I->Trans;
p->wobble = I->Wobble;
p->ramped = ((c1[0] < 0.0F) || (c2[0] < 0.0F));
p->no_lighting = 0;
/*
copy3f(I->WobbleParam,p->wobble_param); */
vv = p->v1;
(*vv++) = (*v1++);
(*vv++) = (*v1++);
(*vv++) = (*v1++);
vv = p->v2;
(*vv++) = (*v2++);
(*vv++) = (*v2++);
(*vv++) = (*v2++);
I->PrimSize += diff3f(p->v1, p->v2) + 2 * r;
I->PrimSizeCnt++;
if(I->TTTFlag) {
p->r1 *= length3f(I->TTT);
transformTTT44f3f(I->TTT, p->v1, p->v1);
transformTTT44f3f(I->TTT, p->v2, p->v2);
}
if(I->Context) {
RayApplyContextToVertex(I, p->v1);
RayApplyContextToVertex(I, p->v2);
}
vv = p->c1;
(*vv++) = (*c1++);
(*vv++) = (*c1++);
(*vv++) = (*c1++);
vv = p->c2;
(*vv++) = (*c2++);
(*vv++) = (*c2++);
(*vv++) = (*c2++);
vv = p->ic;
{
float *v = I->IntColor;
vv = p->ic;
(*vv++) = (*v++);
(*vv++) = (*v++);
(*vv++) = (*v++);
}
I->NPrimitive++;
return true;
}
int CRay::ellipsoid3fv(const float *v, float r, const float *n1, const float *n2, const float *n3)
{
CRay * I = this;
CPrimitive *p;
int ok = true;
float *vv;
VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
CHECKOK(ok, I->Primitive);
if (!ok)
return false;
p = I->Primitive + I->NPrimitive;
p->type = cPrimEllipsoid;
p->r1 = r; /* maximum extent */
p->trans = I->Trans;
p->wobble = I->Wobble;
p->ramped = (I->CurColor[0] < 0.0F);
p->no_lighting = 0;
I->PrimSize += 2 * r;
I->PrimSizeCnt++;
vv = p->n0; /* storing lengths of the direction vectors in n0 */
(*vv++) = length3f(n1);
(*vv++) = length3f(n2);
(*vv++) = length3f(n3);
/* normalize the ellipsoid axes */
vv = p->n1;
if(p->n0[0] > R_SMALL8) {
float factor;
factor = 1.0F / p->n0[0];
(*vv++) = (*n1++) * factor;
(*vv++) = (*n1++) * factor;
(*vv++) = (*n1++) * factor;
} else {
(*vv++) = 0.0F;
(*vv++) = 0.0F;
(*vv++) = 0.0F;
}
vv = p->n2;
if(p->n0[1] > R_SMALL8) {
float factor;
factor = 1.0F / p->n0[1];
(*vv++) = (*n2++) * factor;
(*vv++) = (*n2++) * factor;
(*vv++) = (*n2++) * factor;
} else {
(*vv++) = 0.0F;
(*vv++) = 0.0F;
(*vv++) = 0.0F;
}
vv = p->n3;
if(p->n0[2] > R_SMALL8) {
float factor;
factor = 1.0F / p->n0[2];
(*vv++) = (*n3++) * factor;
(*vv++) = (*n3++) * factor;
(*vv++) = (*n3++) * factor;
} else {
(*vv++) = 0.0F;
(*vv++) = 0.0F;
(*vv++) = 0.0F;
}
vv = p->v1;
(*vv++) = (*v++);
(*vv++) = (*v++);
(*vv++) = (*v++);
vv = p->c1;
v = I->CurColor;
(*vv++) = (*v++);
(*vv++) = (*v++);
(*vv++) = (*v++);
vv = p->ic;
v = I->IntColor;
(*vv++) = (*v++);
(*vv++) = (*v++);
(*vv++) = (*v++);
if(I->TTTFlag) {
p->r1 *= length3f(I->TTT);
transformTTT44f3f(I->TTT, p->v1, p->v1);
transform_normalTTT44f3f(I->TTT, p->n1, p->n1);
transform_normalTTT44f3f(I->TTT, p->n2, p->n2);
transform_normalTTT44f3f(I->TTT, p->n3, p->n3);
}
if(I->Context) {
RayApplyContextToVertex(I, p->v1);
RayApplyContextToNormal(I, p->n1);
RayApplyContextToNormal(I, p->n2);
RayApplyContextToNormal(I, p->n3);
}
I->NPrimitive++;
return true;
}
int CRay::setLastToNoLighting(char no_lighting)
{
CRay * I = this;
CPrimitive *p;
if (!I->NPrimitive)
return false;
p = I->Primitive + I->NPrimitive - 1;
p->no_lighting = no_lighting;
return true;
}
/*========================================================================*/
int CRay::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)
{
CRay * I = this;
CPrimitive *p;
int ok = true;
float *vv;
float n0[3] = { 0.f, 0.f, 1.f }, nx[3], s1[3], s2[3], s3[3];
float l1, l2, l3;
short normals_exist = n1 && n2 && n3;
/* dump3f(v1," v1");
dump3f(v2," v2");
dump3f(v3," v3");
dump3f(n1," n1");
dump3f(n2," n2");
dump3f(n3," n3");
dump3f(c1," c1");
dump3f(c2," c2");
dump3f(c3," c3"); */
VLACacheCheck(I->G, I->Primitive, CPrimitive, I->NPrimitive, 0, cCache_ray_primitive);
CHECKOK(ok, I->Primitive);
if (!ok)
return false;
p = I->Primitive + I->NPrimitive;
p->type = cPrimTriangle;
p->trans = I->Trans;
p->tr[0] = I->Trans;
p->tr[1] = I->Trans;
p->tr[2] = I->Trans;
p->wobble = I->Wobble;
p->ramped = ((c1[0] < 0.0F) || (c2[0] < 0.0F) || (c3[0] < 0.0F));
p->no_lighting = 0;
/*
copy3f(I->WobbleParam,p->wobble_param); */
/* determine exact triangle normal */
if (normals_exist){
add3f(n1, n2, nx);
add3f(n3, nx, nx);
}
subtract3f(v1, v2, s1);
subtract3f(v3, v2, s2);
subtract3f(v1, v3, s3);
cross_product3f(s1, s2, n0);
if (normals_exist){
if((fabs(n0[0]) < RAY_SMALL) && (fabs(n0[1]) < RAY_SMALL) && (fabs(n0[2]) < RAY_SMALL)) {
copy3f(nx, n0);
} /* fall-back */
else if(dot_product3f(n0, nx) < 0)
invert3f(n0);
}
normalize3f(n0);
vv = p->n0;
(*vv++) = n0[0];
(*vv++) = n0[1];
(*vv++) = n0[2];
/* determine maximum distance from vertex to point */
l1 = (float) length3f(s1);
l2 = (float) length3f(s2);
l3 = (float) length3f(s3);
if(l2 > l1) {
if(l3 > l2)
l1 = l3;
else
l1 = l2;
}
/* store cutoff distance */
p->r1 = l1 * 0.6F;
/* if(l1>20) {
printf("%8.3f\n",l1);
printf("%8.3f %8.3f %8.3f\n",s1[0],s1[1],s1[2]);
printf("%8.3f %8.3f %8.3f\n",s2[0],s2[1],s2[2]);
printf("%8.3f %8.3f %8.3f\n",s3[0],s3[1],s3[2]);
} */
vv = p->v1;
(*vv++) = (*v1++);
(*vv++) = (*v1++);
(*vv++) = (*v1++);
vv = p->v2;
(*vv++) = (*v2++);
(*vv++) = (*v2++);
(*vv++) = (*v2++);
vv = p->v3;
(*vv++) = (*v3++);
(*vv++) = (*v3++);
(*vv++) = (*v3++);
I->PrimSize += diff3f(p->v1, p->v2) + diff3f(p->v1, p->v3) + diff3f(p->v2, p->v3);
I->PrimSizeCnt += 3;
vv = p->c1;
(*vv++) = (*c1++);
(*vv++) = (*c1++);
(*vv++) = (*c1++);
vv = p->c2;
(*vv++) = (*c2++);
(*vv++) = (*c2++);
(*vv++) = (*c2++);
vv = p->c3;
(*vv++) = (*c3++);
(*vv++) = (*c3++);
(*vv++) = (*c3++);
{
float *v = I->IntColor;
vv = p->ic;
(*vv++) = (*v++);
(*vv++) = (*v++);
(*vv++) = (*v++);
}
if (normals_exist){
vv = p->n1;
(*vv++) = (*n1++);
(*vv++) = (*n1++);
(*vv++) = (*n1++);
vv = p->n2;
(*vv++) = (*n2++);
(*vv++) = (*n2++);
(*vv++) = (*n2++);
vv = p->n3;
(*vv++) = (*n3++);
(*vv++) = (*n3++);
(*vv++) = (*n3++);
} else {
vv = p->n1;
(*vv++) = n0[0];
(*vv++) = n0[1];
(*vv++) = n0[2];
vv = p->n2;
(*vv++) = n0[0];
(*vv++) = n0[1];
(*vv++) = n0[2];
vv = p->n3;
(*vv++) = n0[0];
(*vv++) = n0[1];
(*vv++) = n0[2];
}
if(I->TTTFlag) {
transformTTT44f3f(I->TTT, p->v1, p->v1);
transformTTT44f3f(I->TTT, p->v2, p->v2);
transformTTT44f3f(I->TTT, p->v3, p->v3);
transform_normalTTT44f3f(I->TTT, p->n0, p->n0);
transform_normalTTT44f3f(I->TTT, p->n1, p->n1);
transform_normalTTT44f3f(I->TTT, p->n2, p->n2);
transform_normalTTT44f3f(I->TTT, p->n3, p->n3);
}
if(I->Context) {
RayApplyContextToVertex(I, p->v1);
RayApplyContextToVertex(I, p->v2);
RayApplyContextToVertex(I, p->v3);
RayApplyContextToNormal(I, p->n0);
RayApplyContextToNormal(I, p->n1);
RayApplyContextToNormal(I, p->n2);
RayApplyContextToNormal(I, p->n3);
}
I->NPrimitive++;
return true;
}
int CRay::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)
{
CRay * I = this;
CPrimitive *p;
int ok = true;
ok = I->triangle3fv(v1, v2, v3, n1, n2, n3, c1, c2, c3);
if (!ok)
return false;
p = I->Primitive + I->NPrimitive - 1;
p->tr[0] = t1;
p->tr[1] = t2;
p->tr[2] = t3;
p->trans = (t1 + t2 + t3) / 3.0F;
return true;
}
/*========================================================================*/
CRay *RayNew(PyMOLGlobals * G, int antialias)
{
unsigned int test;
unsigned char *testPtr;
int a;
OOAlloc(I->G, CRay);
I->G = G;
test = 0xFF000000;
testPtr = (unsigned char *) &test;
I->BigEndian = (*testPtr) & 0x01;
I->Trans = 0.0F;
I->Wobble = 0;
I->TTTFlag = false;
zero3f(I->WobbleParam);
PRINTFB(I->G, FB_Ray, FB_Blather)
" RayNew: BigEndian = %d\n", I->BigEndian ENDFB(I->G);
I->Basis = CacheAlloc(I->G, CBasis, 12, 0, cCache_ray_basis);
BasisInit(I->G, I->Basis, 0);
BasisInit(I->G, I->Basis + 1, 1);
I->Vert2Prim = VLACacheAlloc(I->G, int, 1, 0, cCache_ray_vert2prim);
I->NBasis = 2;
I->Primitive = NULL;
I->NPrimitive = 0;
I->TTTStackVLA = NULL;
I->TTTStackDepth = 0;
I->CheckInterior = false;
if(antialias < 0)
antialias = SettingGetGlobal_i(I->G, cSetting_antialias);
I->Sampling = antialias;
if(I->Sampling < 2) /* always supersample fonts by at least 2X */
I->Sampling = 2;
for(a = 0; a < 256; a++) {
I->Random[a] = (float) ((rand() / (1.0 + RAND_MAX)) - 0.5);
}
I->Wobble = SettingGet_i(I->G, NULL, NULL, cSetting_ray_texture);
{
auto v = SettingGet<const float*>(I->G, cSetting_ray_texture_settings);
int color = SettingGetGlobal_color(I->G, cSetting_ray_interior_color);
copy3f(v, I->WobbleParam);
v = ColorGet(I->G, color);
copy3f(v, I->IntColor);
}
I->bkgrd_data = NULL;
I->bkgrd_width = I->bkgrd_height = 0;
return (I);
}
/*========================================================================*/
/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
#ifdef PYMOL_EVAL
#include "RayEvalMessage.h"
#endif
/* END PROPRIETARY CODE SEGMENT */
void 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)
/*prepare for vertex calls */
{
int a;
if(!I->Primitive)
I->Primitive = VLACacheAlloc(I->G, CPrimitive, 10000, 3, cCache_ray_primitive);
if(!I->Vert2Prim)
I->Vert2Prim = VLACacheAlloc(I->G, int, 10000, 3, cCache_ray_vert2prim);
I->Volume[0] = v0;
I->Volume[1] = v1;
I->Volume[2] = v2;
I->Volume[3] = v3;
I->Volume[4] = v4;
I->Volume[5] = v5;
I->Range[0] = I->Volume[1] - I->Volume[0];
I->Range[1] = I->Volume[3] - I->Volume[2];
I->Range[2] = I->Volume[5] - I->Volume[4];
I->AspRatio = aspRat;
I->Width = width;
I->Height = height;
CharacterSetRetention(I->G, true);
if(mat)
for(a = 0; a < 16; a++)
I->ModelView[a] = mat[a];
else {
identity44f(I->ModelView);
}
identity44f(I->ProMatrix);
if (ortho){
I->ProMatrix[0] = 2.f/I->Range[0];
I->ProMatrix[5] = 2.f/I->Range[1];
I->ProMatrix[10] = -2.f/I->Range[2];
I->ProMatrix[12] = -(I->Volume[0] + I->Volume[1])/I->Range[0];
I->ProMatrix[13] = -(I->Volume[2] + I->Volume[3])/I->Range[1];
I->ProMatrix[14] = -(I->Volume[4] + I->Volume[5])/I->Range[2];
} else {
I->ProMatrix[0] = I->Volume[4]/(front_back_ratio*I->Volume[1]);
I->ProMatrix[5] = I->Volume[4]/(front_back_ratio*I->Volume[3]);
I->ProMatrix[10] = -(I->Volume[5] + I->Volume[4])/I->Range[2];
I->ProMatrix[11] = -1.f;
I->ProMatrix[14] = (-2.f * I->Volume[5] * I->Volume[4])/I->Range[2];
I->ProMatrix[15] = 0.f;
}
if(rotMat)
for(a = 0; a < 16; a++)
I->Rotation[a] = rotMat[a];
I->Ortho = ortho;
if(ortho) {
I->PixelRadius = (((float) I->Range[0]) / width) * pixel_scale;
} else {
I->PixelRadius = (((float) I->Range[0]) / width) * pixel_scale * pixel_ratio;
}
I->PixelRatio = pixel_ratio;
I->Magnified = magnified;
I->FrontBackRatio = front_back_ratio;
I->PrimSizeCnt = 0;
I->PrimSize = 0.0;
I->Fov = fov;
copy3f(pos, I->Pos);
/* BEGIN PROPRIETARY CODE SEGMENT (see disclaimer in "os_proprietary.h") */
#ifdef PYMOL_EVAL
RayDrawEvalMessage(I);
#endif
/* END PROPRIETARY CODE SEGMENT */
}
/*========================================================================*/
void RaySetTTT(CRay * I, int flag, float *ttt)
{
I->TTTFlag = flag;
if(flag) {
UtilCopyMem(I->TTT, ttt, sizeof(float) * 16);
}
}
void RayGetTTT(CRay * I, float *ttt)
{
if(!I->TTTFlag) {
identity44f(ttt);
} else {
copy44f(I->TTT, ttt);
}
}
/*========================================================================*/
void RayRelease(CRay * I)
{
int a;
for(a = 0; a < I->NBasis; a++) {
BasisFinish(&I->Basis[a], a);
}
I->NBasis = 0;
VLACacheFreeP(I->G, I->Primitive, 0, cCache_ray_primitive, false);
VLACacheFreeP(I->G, I->Vert2Prim, 0, cCache_ray_vert2prim, false);
}
/*========================================================================*/
void RayFree(CRay * I)
{
RayRelease(I);
CharacterSetRetention(I->G, false);
CacheFreeP(I->G, I->Basis, 0, cCache_ray_basis, false);
VLACacheFreeP(I->G, I->Vert2Prim, 0, cCache_ray_vert2prim, false);
VLAFreeP(I->TTTStackVLA);
OOFreeP(I);
}
/*========================================================================*/
void RayPushTTT(CRay * I)
{
if(I->TTTFlag) {
if(!I->TTTStackVLA) {
I->TTTStackVLA = VLAlloc(float, 16);
copy44f(I->TTT, I->TTTStackVLA);
I->TTTStackDepth = 1;
} else {
float *p;
VLACheck(I->TTTStackVLA, float, I->TTTStackDepth * 16 + 15);
p = I->TTTStackVLA + 16 * I->TTTStackDepth;
copy44f(I->TTT, p);
I->TTTStackDepth++;
}
}
}
void RayPopTTT(CRay * I)
{
if(I->TTTStackDepth > 0) {
float *p;
I->TTTStackDepth--;
p = I->TTTStackVLA + 16 * I->TTTStackDepth;
copy44f(p, I->TTT);
I->TTTFlag = true;
} else {
I->TTTFlag = false;
}
}
static void RayApplyMatrix33(unsigned int n, float3 * q, const float m[16], float3 * p)
{
{
unsigned int i;
float m0 = m[0], m4 = m[4], m8 = m[8], m12 = m[12];
float m1 = m[1], m5 = m[5], m9 = m[9], m13 = m[13];
float m2 = m[2], m6 = m[6], m10 = m[10], m14 = m[14];
for(i = 0; i < n; i++) {
float p0 = p[i][0], p1 = p[i][1], p2 = p[i][2];
q[i][0] = m0 * p0 + m4 * p1 + m8 * p2 + m12;
q[i][1] = m1 * p0 + m5 * p1 + m9 * p2 + m13;
q[i][2] = m2 * p0 + m6 * p1 + m10 * p2 + m14;
}
}
}
static void RayApplyMatrixInverse33(unsigned int n, float3 * q, const float m[16], float3 * p)
{
{
unsigned int i;
float m0 = m[0], m4 = m[4], m8 = m[8], m12 = m[12];
float m1 = m[1], m5 = m[5], m9 = m[9], m13 = m[13];
float m2 = m[2], m6 = m[6], m10 = m[10], m14 = m[14];
for(i = 0; i < n; i++) {
float p0 = p[i][0] - m12, p1 = p[i][1] - m13, p2 = p[i][2] - m14;
q[i][0] = m0 * p0 + m1 * p1 + m2 * p2;
q[i][1] = m4 * p0 + m5 * p1 + m6 * p2;
q[i][2] = m8 * p0 + m9 * p1 + m10 * p2;
}
}
}
static void RayTransformNormals33(unsigned int n, float3 * q, const float m[16], float3 * p)
{
unsigned int i;
float m0 = m[0], m4 = m[4], m8 = m[8];
float m1 = m[1], m5 = m[5], m9 = m[9];
float m2 = m[2], m6 = m[6], m10 = m[10];
for(i = 0; i < n; i++) {
float p0 = p[i][0], p1 = p[i][1], p2 = p[i][2];
q[i][0] = m0 * p0 + m4 * p1 + m8 * p2;
q[i][1] = m1 * p0 + m5 * p1 + m9 * p2;
q[i][2] = m2 * p0 + m6 * p1 + m10 * p2;
}
for(i = 0; i < n; i++) { /* renormalize - can we do this to the matrix instead? */
normalize3f(q[i]);
}
}
static void RayTransformInverseNormals33(unsigned int n, float3 * q, const float m[16],
float3 * p)
{
unsigned int i;
float m0 = m[0], m4 = m[4], m8 = m[8];
float m1 = m[1], m5 = m[5], m9 = m[9];
float m2 = m[2], m6 = m[6], m10 = m[10];
for(i = 0; i < n; i++) {
float p0 = p[i][0], p1 = p[i][1], p2 = p[i][2];
q[i][0] = m0 * p0 + m1 * p1 + m2 * p2;
q[i][1] = m4 * p0 + m5 * p1 + m6 * p2;
q[i][2] = m8 * p0 + m9 * p1 + m10 * p2;
}
for(i = 0; i < n; i++) { /* renormalize - can we do this to the matrix instead? */
normalize3f(q[i]);
}
}
void RayGetScreenVertex(CRay * I, float *v, float *res){
MatrixTransformC44f4f(I->ModelView, v, res);
normalize4f(res);
}
void RayAdjustZtoScreenZ(CRay * ray, float *pos, float zarg){
PyMOLGlobals *G = ray->G;
float BackSafe = ray->Volume[5], FrontSafe = ray->Volume[4];
float clipRange = (BackSafe-FrontSafe);
float z = (zarg + 1.f) / 2.f;
float zInPreProj = -(z * clipRange + FrontSafe);
float pos4[4], tpos[4], npos[4];
float InvModMatrix[16];
copy3f(pos, pos4);
pos4[3] = 1.f;
MatrixTransformC44f4f(ray->ModelView, pos4, tpos);
normalize4f(tpos);
/* NEED TO ACCOUNT FOR ORTHO */
if (SettingGetGlobal_b(G, cSetting_ortho)){
npos[0] = tpos[0];
npos[1] = tpos[1];
} else {
npos[0] = zInPreProj * tpos[0] / tpos[2];
npos[1] = zInPreProj * tpos[1] / tpos[2];
}
npos[2] = zInPreProj;
npos[3] = 1.f;
MatrixInvertC44f(ray->ModelView, InvModMatrix);
MatrixTransformC44f4f(InvModMatrix, npos, npos);
normalize4f(npos);
copy3f(npos, pos);
}
static float RayGetRawDepth(CRay * ray, float *pos)
{
float pos4[4], tpos[4];
copy3f(pos, pos4);
pos4[3] = 1.f;
MatrixTransformC44f4f(ray->ModelView, pos4, tpos);
normalize4f(tpos);
return -tpos[2];
}
void RayAdjustZtoScreenZofPoint(CRay * ray, float *pos, float *zpoint){
float BackSafe = ray->Volume[5], FrontSafe = ray->Volume[4];
float clipRange = (BackSafe-FrontSafe);
float zInClipping = RayGetRawDepth(ray, zpoint);
float z = ((2.f * (zInClipping - FrontSafe)/ clipRange) - 1.f);
RayAdjustZtoScreenZ(ray, pos, z);
}
void RaySetPointToWorldScreenRelative(CRay * ray, float *pos, float *screenPt)
{
float npos[4];
float PmvMatrix[16], InvPmvMatrix[16];
int width = ray->Width, height = ray->Height;
multiply44f44f44f(ray->ModelView, RayGetProMatrix(ray), PmvMatrix);
npos[0] = (floor(screenPt[0]*width)) /width ;
npos[1] = (floor(screenPt[1]*height)) /height ;
npos[2] = 0.f;
npos[3] = 1.f;
MatrixInvertC44f(PmvMatrix, InvPmvMatrix);
MatrixTransformC44f4f(InvPmvMatrix, npos, npos);
normalize4f(npos);
RayAdjustZtoScreenZ(ray, npos, screenPt[2]);
copy3f(npos, pos);
}
float RayGetScaledAllAxesAtPoint(CRay * I, float *pt, float *xn, float *yn, float *zn)
{
float xn0[3] = { 1.0F, 0.0F, 0.0F };
float yn0[3] = { 0.0F, 1.0F, 0.0F };
float zn0[3] = { 0.0F, 0.0F, 1.0F };
float v_scale;
v_scale = RayGetScreenVertexScale(I, pt) / I->Sampling;
RayApplyMatrixInverse33(1, (float3 *) xn0, I->Rotation, (float3 *) xn0);
RayApplyMatrixInverse33(1, (float3 *) yn0, I->Rotation, (float3 *) yn0);
RayApplyMatrixInverse33(1, (float3 *) zn0, I->Rotation, (float3 *) zn0);
scale3f(xn0, v_scale, xn);
scale3f(yn0, v_scale, yn);
scale3f(zn0, v_scale, zn);
return v_scale;
}
float* RayGetProMatrix(CRay * I){
return I->ProMatrix;
}