in layer2/RepSurface.cpp [1426:2139]
static void RepSurfaceRender(RepSurface * I, RenderInfo * info)
{
CRay *ray = info->ray;
auto pick = info->pick;
PyMOLGlobals *G = I->R.G;
float *v = I->V;
float *vn = I->VN;
float *vc = I->VC;
float *va = I->VA;
int *rc = I->RC;
int *t = I->T;
int *s = I->S;
int c = I->N;
int *vi = I->Vis;
int ok = true;
float alpha;
int t_mode;
float ambient_occlusion_scale = 0.f;
int ambient_occlusion_mode = SettingGet_i(G, I->R.cs->Setting, I->R.obj->Setting, cSetting_ambient_occlusion_mode);
int ambient_occlusion_mode_div_4 = 0;
if (ambient_occlusion_mode){
ambient_occlusion_scale = SettingGet_f(G, I->R.cs->Setting, I->R.obj->Setting, cSetting_ambient_occlusion_scale);
ambient_occlusion_mode_div_4 = ambient_occlusion_mode / 4;
}
if((I->Type != 1) && (!s)) {
return;
}
alpha = SettingGet_f(G, I->R.cs->Setting, I->R.obj->Setting, cSetting_transparency);
alpha = 1.0F - alpha;
if(fabs(alpha - 1.0) < R_SMALL4)
alpha = 1.0F;
if(ray) {
#ifndef _PYMOL_NO_RAY
ray->transparentf(1.0F - alpha);
if(I->Type == 1) {
/* dot surface */
float radius;
radius = SettingGet_f(G, I->R.cs->Setting, I->R.obj->Setting, cSetting_dot_radius);
if(radius == 0.0F) {
radius = ray->PixelRadius * SettingGet_f(G, I->R.cs->Setting,
I->R.obj->Setting,
cSetting_dot_width) / 1.4142F;
}
if(I->oneColorFlag) {
float col[3];
ColorGetEncoded(G, I->oneColor, col);
ray->color3fv(col);
}
if(c)
while(ok && c--) {
if(*vi) {
if(!I->oneColorFlag) {
ray->color3fv(vc);
}
ok &= ray->sphere3fv(v, radius);
}
vi++;
vc += 3;
v += 3;
}
} else if((I->Type == 0) || (I->Type == 3) || (I->Type == 4) || (I->Type == 5)) { /* solid surface */
c = I->NT;
if(I->oneColorFlag) {
float col[3], col1[3], col2[3], col3[3];
ColorGetEncoded(G, I->oneColor, col);
while(ok && c--) {
if (visibility_test(I->proximity, vi, t)) {
copy3f(col, col1);
copy3f(col, col2);
copy3f(col, col3);
if (I->VAO){
float ao1, ao2, ao3;
switch (ambient_occlusion_mode_div_4){
case 1:
ao1 = 1.f-ambient_occlusion_scale*(*(I->VAO + *t));
ao2 = 1.f-ambient_occlusion_scale*(*(I->VAO + *(t+1)));
ao3 = 1.f-ambient_occlusion_scale*(*(I->VAO + *(t+2)));
break;
case 2:
ao1 = cos(.5f * PI * CLAMP_VALUE(ambient_occlusion_scale*(*(I->VAO + *t))));
ao2 = cos(.5f * PI * CLAMP_VALUE(ambient_occlusion_scale*(*(I->VAO + *(t+1)))));
ao3 = cos(.5f * PI * CLAMP_VALUE(ambient_occlusion_scale*(*(I->VAO + *(t+2)))));
break;
default:
ao1 = CLAMP_VALUE(1.f / (1.f + exp(.5f*((ambient_occlusion_scale*(*(I->VAO + *t))) - 10.f))));
ao2 = CLAMP_VALUE(1.f / (1.f + exp(.5f*((ambient_occlusion_scale*(*(I->VAO + *(t+1)))) - 10.f))));
ao3 = CLAMP_VALUE(1.f / (1.f + exp(.5f*((ambient_occlusion_scale*(*(I->VAO + *(t+2)))) - 10.f))));
}
mult3f(col1, ao1, col1);
mult3f(col2, ao2, col2);
mult3f(col3, ao3, col3);
}
ok &= ray->triangle3fv(v + (*t) * 3, v + (*(t + 1)) * 3, v + (*(t + 2)) * 3,
vn + (*t) * 3, vn + (*(t + 1)) * 3, vn + (*(t + 2)) * 3,
col1, col2, col3);
}
t += 3;
}
} else {
while(ok && c--) {
int ttA = *t, ttB = *(t + 1), ttC = *(t + 2);
if (visibility_test(I->proximity, vi, t)) {
int ttA3 = ttA * 3, ttB3 = ttB * 3, ttC3 = ttC * 3;
float cA[3], cB[3], cC[3];
copy3f(vc + ttA3, cA);
copy3f(vc + ttB3, cB);
copy3f(vc + ttC3, cC);
// register float *cA = vc + ttA3, *cB = vc + ttB3, *cC = vc + ttC3;
if(rc) {
if(rc[ttA] < -1)
ColorGetEncoded(G, rc[ttA], cA);
// ColorGetEncoded(G, rc[ttA], (cA = colA));
if(rc[ttB] < -1)
ColorGetEncoded(G, rc[ttB], cB);
// ColorGetEncoded(G, rc[ttB], (cB = colB));
if(rc[ttC] < -1)
ColorGetEncoded(G, rc[ttC], cC);
// ColorGetEncoded(G, rc[ttC], (cC = colC));
}
if((*(vi + ttA)) || (*(vi + ttB)) || (*(vi + ttC))) {
if (I->VAO){
float ao1, ao2, ao3;
switch (ambient_occlusion_mode_div_4){
case 1:
ao1 = 1.f-ambient_occlusion_scale*(*(I->VAO + *t));
ao2 = 1.f-ambient_occlusion_scale*(*(I->VAO + *(t+1)));
ao3 = 1.f-ambient_occlusion_scale*(*(I->VAO + *(t+2)));
break;
case 2:
ao1 = cos(.5f * PI * CLAMP_VALUE(ambient_occlusion_scale*(*(I->VAO + *t))));
ao2 = cos(.5f * PI * CLAMP_VALUE(ambient_occlusion_scale*(*(I->VAO + *(t+1)))));
ao3 = cos(.5f * PI * CLAMP_VALUE(ambient_occlusion_scale*(*(I->VAO + *(t+2)))));
break;
default:
ao1 = CLAMP_VALUE(1.f / (1.f + exp(.5f*((ambient_occlusion_scale*(*(I->VAO + *t))) - 10.f))));
ao2 = CLAMP_VALUE(1.f / (1.f + exp(.5f*((ambient_occlusion_scale*(*(I->VAO + *(t+1)))) - 10.f))));
ao3 = CLAMP_VALUE(1.f / (1.f + exp(.5f*((ambient_occlusion_scale*(*(I->VAO + *(t+2)))) - 10.f))));
}
mult3f(cA, ao1, cA);
mult3f(cB, ao2, cB);
mult3f(cC, ao3, cC);
}
if(va) {
ok &= ray->triangleTrans3fv(v + ttA3, v + ttB3, v + ttC3,
vn + ttA3, vn + ttB3, vn + ttC3,
cA, cB, cC,
1.0F - va[ttA], 1.0F - va[ttB], 1.0F - va[ttC]);
} else {
ok &= ray->triangle3fv(v + ttA3, v + ttB3, v + ttC3,
vn + ttA3, vn + ttB3, vn + ttC3, cA, cB, cC);
}
}
}
t += 3;
}
}
} else if(I->Type == 2) { /* triangle mesh surface */
float radius;
int t0, t1, t2;
int spacing = 10;
int *cache = Calloc(int, spacing * (I->N + 1));
CHECKOK(ok, cache);
radius = SettingGet_f(G, I->R.cs->Setting, I->R.obj->Setting, cSetting_mesh_radius);
if(ok && radius == 0.0F) {
float line_width =
SettingGet_f(G, I->R.cs->Setting, I->R.obj->Setting, cSetting_mesh_width);
line_width = SceneGetDynamicLineWidth(info, line_width);
radius = ray->PixelRadius * line_width / 2.0F;
}
if (ok){
float col[3], *col0, *col1, *col2;
c = I->NT;
if(I->oneColorFlag) {
ColorGetEncoded(G, I->oneColor, col);
col0 = col1 = col2 = col;
}
while(ok && c--) {
t0 = (*t);
t1 = (*(t + 1));
t2 = (*(t + 2));
if (visibility_test(I->proximity, vi, t)) {
if (!I->oneColorFlag) {
col0 = vc + t0 * 3;
col1 = vc + t1 * 3;
col2 = vc + t2 * 3;
}
if(!check_and_add(cache, spacing, t0, t1))
ok &= ray->sausage3fv(v + t0 * 3, v + t1 * 3, radius, col0, col1);
if(!check_and_add(cache, spacing, t1, t2))
ok &= ray->sausage3fv(v + t1 * 3, v + t2 * 3, radius, col1, col2);
if(!check_and_add(cache, spacing, t2, t0))
ok &= ray->sausage3fv(v + t2 * 3, v + t0 * 3, radius, col2, col0);
}
t += 3;
}
FreeP(cache);
}
}
if (ok){
ray->transparentf(0.0);
} else {
/* If not ok, then Clear Entire RepSurface, not just the ray object */
}
#endif
} else if(G->HaveGUI && G->ValidContext) {
/* Not ray tracing, but rendering */
if(pick) {
// Don't render transparent unpickable surfaces. Do render solid but
// unpickable surfaces to write the depth buffer and prevent
// through-picking.
if (I->pickingCGO && !(I->pickingCGO->no_pick && alpha < 1.F)) {
CGORenderGLPicking(I->pickingCGO, info, &I->R.context, I->R.cs->Setting, I->R.obj->Setting);
}
} else {
#ifndef PURE_OPENGL_ES_2
bool use_shader = SettingGetGlobal_b(G, cSetting_surface_use_shader) &&
SettingGetGlobal_b(G, cSetting_use_shaders);
if (use_shader && !info->alpha_cgo)
#endif
{
bool dot_as_spheres = SettingGet_b(G, I->R.cs->Setting, I->R.obj->Setting, cSetting_dot_as_spheres);
if (!I->shaderCGO || CGOCheckWhetherToFree(G, I->shaderCGO) ||
(I->Type == 1 && I->dot_as_spheres != dot_as_spheres)) {
ok &= RepSurfaceCGOGenerate(I, info);
}
if (ok && I->shaderCGO) {
const float *color = ColorGet(G, I->R.obj->Color);
CGORenderGL(I->shaderCGO, color, NULL, NULL, info, &I->R);
return;
}
PRINTFB(G, FB_RepSurface, FB_Errors)
" RepSurfaceCGOGenerate failed\n" ENDFB(G);
}
setShaderCGO(I, NULL);
#ifndef PURE_OPENGL_ES_2
bool two_sided_lighting =
SettingGet_i(G, I->R.cs->Setting, I->R.obj->Setting,
cSetting_two_sided_lighting) > 0;
if (two_sided_lighting){
GLLIGHTMODELI(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
}
if(I->Type == 1) {
/* no triangle information, so we're rendering dots only */
{
int normals =
SettingGet_i(G, I->R.cs->Setting, I->R.obj->Setting, cSetting_dot_normals);
int lighting = info->line_lighting ||
SettingGet_i(G, I->R.cs->Setting, I->R.obj->Setting, cSetting_dot_lighting);
if(!normals){
SceneResetNormal(G, true);
vn = NULL;
}
if(!lighting)
glDisable(GL_LIGHTING);
glPointSize(SettingGet_f
(G, I->R.cs->Setting, I->R.obj->Setting, cSetting_dot_width));
if(c) {
glBegin(GL_POINTS);
if(I->oneColorFlag) {
glColor3fv(ColorGet(G, I->oneColor));
vc = NULL;
} else {
glColor3f(1.0, 0.0, 0.0);
}
immediate_draw_masked_vertices(vc, vn, v, vi, c);
glEnd();
}
if(!lighting)
glEnable(GL_LIGHTING);
} /* else use shader */
} else if(I->Type == 2) { /* rendering triangle mesh */
if (ok) {
c = I->NT;
if(ok && c) {
int normals =
SettingGet_i(G, I->R.cs->Setting, I->R.obj->Setting, cSetting_mesh_normals);
int lighting = info->line_lighting ||
SettingGet_i(G, I->R.cs->Setting, I->R.obj->Setting, cSetting_mesh_lighting);
if(!normals){
SceneResetNormal(G, true);
vn = NULL;
}
if(!lighting)
glDisable(GL_LIGHTING);
float line_width =
SettingGet_f(G, I->R.cs->Setting, I->R.obj->Setting, cSetting_mesh_width);
glLineWidth(SceneGetDynamicLineWidth(info, line_width));
if(I->oneColorFlag) {
glColor3fv(ColorGet(G, I->oneColor));
vc = NULL;
}
glBegin(GL_LINES);
for (; c--; t += 3) {
if (visibility_test(I->proximity, vi, t)) {
int indices[] = {t[0], t[1], t[1], t[2], t[2], t[0]};
immediate_draw_indexed_vertices(vc, vn, v, indices, 6);
}
}
glEnd();
if(!lighting)
glEnable(GL_LIGHTING);
}
}
} else {
/* we're rendering triangles */
if((alpha != 1.0) || va) {
t_mode =
SettingGet_i(G, I->R.cs->Setting, I->R.obj->Setting,
cSetting_transparency_mode);
if(info && info->alpha_cgo) {
t_mode = 0;
}
if(t_mode) {
float **t_buf = NULL, **tb;
float *z_value = NULL, *zv;
int *ix = NULL;
int n_tri = 0;
float sum[3];
float matrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
if(I->oneColorFlag) {
t_buf = Alloc(float *, I->NT * 6);
} else {
t_buf = Alloc(float *, I->NT * 12);
}
CHECKOK(ok, t_buf);
if (ok){
z_value = Alloc(float, I->NT);
CHECKOK(ok, z_value);
}
if (ok){
ix = Alloc(int, I->NT);
CHECKOK(ok, ix);
}
zv = z_value;
tb = t_buf;
c = I->NT;
if (ok){
if(I->oneColorFlag) {
while(c--) {
if (visibility_test(I->proximity, vi, t)) {
*(tb++) = vn + (*t) * 3;
*(tb++) = v + (*t) * 3;
*(tb++) = vn + (*(t + 1)) * 3;
*(tb++) = v + (*(t + 1)) * 3;
*(tb++) = vn + (*(t + 2)) * 3;
*(tb++) = v + (*(t + 2)) * 3;
add3f(tb[-1], tb[-3], sum);
add3f(sum, tb[-5], sum);
*(zv++) = matrix[2] * sum[0] + matrix[6] * sum[1] + matrix[10] * sum[2];
n_tri++;
}
t += 3;
}
} else {
while(c--) {
if (visibility_test(I->proximity, vi, t)) {
if(va)
*(tb++) = va + (*t);
else
*(tb++) = α
*(tb++) = vc + (*t) * 3;
*(tb++) = vn + (*t) * 3;
*(tb++) = v + (*t) * 3;
if(va)
*(tb++) = va + (*(t + 1));
else
*(tb++) = α
*(tb++) = vc + (*(t + 1)) * 3;
*(tb++) = vn + (*(t + 1)) * 3;
*(tb++) = v + (*(t + 1)) * 3;
if(va)
*(tb++) = va + (*(t + 2));
else
*(tb++) = α
*(tb++) = vc + (*(t + 2)) * 3;
*(tb++) = vn + (*(t + 2)) * 3;
*(tb++) = v + (*(t + 2)) * 3;
add3f(tb[-1], tb[-5], sum);
add3f(sum, tb[-9], sum);
*(zv++) =
matrix[2] * sum[0] + matrix[6] * sum[1] + matrix[10] * sum[2];
n_tri++;
}
t += 3;
}
}
}
switch (t_mode) {
case 1:
ok &= UtilSemiSortFloatIndex(n_tri, z_value, ix, true);
/* UtilSortIndex(n_tri,z_value,ix,(UtilOrderFn*)ZOrderFn); */
break;
default:
ok &= UtilSemiSortFloatIndex(n_tri, z_value, ix, false);
/* UtilSortIndex(n_tri,z_value,ix,(UtilOrderFn*)ZRevOrderFn); */
break;
}
c = n_tri;
if(I->oneColorFlag) {
float col[3];
ColorGetEncoded(G, I->oneColor, col);
if (ok){
glColor4f(col[0], col[1], col[2], alpha);
glBegin(GL_TRIANGLES);
for(c = 0; c < n_tri; c++) {
tb = t_buf + 6 * ix[c];
glNormal3fv(*(tb++));
glVertex3fv(*(tb++));
glNormal3fv(*(tb++));
glVertex3fv(*(tb++));
glNormal3fv(*(tb++));
glVertex3fv(*(tb++));
}
glEnd();
}
} else { /* else I->oneColorFlag */
glBegin(GL_TRIANGLES);
for(c = 0; c < n_tri; c++) {
float *vv, *v_alpha;
tb = t_buf + 12 * ix[c];
v_alpha = *(tb++);
vv = *(tb++);
glColor4f(vv[0], vv[1], vv[2], *v_alpha);
glNormal3fv(*(tb++));
glVertex3fv(*(tb++));
v_alpha = *(tb++);
vv = *(tb++);
glColor4f(vv[0], vv[1], vv[2], *v_alpha);
glNormal3fv(*(tb++));
glVertex3fv(*(tb++));
v_alpha = *(tb++);
vv = *(tb++);
glColor4f(vv[0], vv[1], vv[2], *v_alpha);
glNormal3fv(*(tb++));
glVertex3fv(*(tb++));
}
glEnd();
}
{
FreeP(ix);
FreeP(z_value);
FreeP(t_buf);
}
} else if (ok) {
if(info->alpha_cgo) { /* global transparency sort */
if(I->allVisibleFlag) {
if(I->oneColorFlag) {
float col[3];
ColorGetEncoded(G, I->oneColor, col);
glColor4f(col[0], col[1], col[2], alpha);
c = *(s++);
while(c) {
int parity = 0;
s += 2;
while(ok && c--) {
ok &= CGOAlphaTriangle(info->alpha_cgo,
v + s[-2] * 3, v + s[-1] * 3, v + (*s) * 3,
vn + s[-2] * 3, vn + s[-1] * 3, vn + (*s) * 3,
col, col, col, alpha, alpha, alpha, parity);
s++;
parity = !parity;
}
c = *(s++);
}
} else {
c = *(s++);
while(ok && c) {
float *col0, *col1, *col2;
int parity = 0;
float alpha0, alpha1, alpha2;
col0 = vc + (*s) * 3;
if(va) {
alpha0 = va[(*s)];
} else {
alpha0 = alpha;
}
s++;
col1 = vc + (*s) * 3;
if(va) {
alpha1 = va[(*s)];
} else {
alpha1 = alpha;
}
s++;
while(ok && c--) {
col2 = vc + (*s) * 3;
if(va) {
alpha2 = va[(*s)];
} else {
alpha2 = alpha;
}
ok &= CGOAlphaTriangle(info->alpha_cgo,
v + s[-2] * 3, v + s[-1] * 3, v + (*s) * 3,
vn + s[-2] * 3, vn + s[-1] * 3, vn + (*s) * 3,
col0, col1, col2, alpha0, alpha1, alpha2, parity);
alpha0 = alpha1;
alpha1 = alpha2;
col0 = col1;
col1 = col2;
s++;
parity = !parity;
}
c = *(s++);
}
}
} else if (ok){ /* subset s */
c = I->NT;
if(c) {
if(I->oneColorFlag) {
float color[3];
ColorGetEncoded(G, I->oneColor, color);
while(ok && c--) {
if (visibility_test(I->proximity, vi, t))
{
ok &= CGOAlphaTriangle(info->alpha_cgo,
v + t[0] * 3, v + t[1] * 3, v + t[2] * 3,
vn + t[0] * 3, vn + t[1] * 3, vn + t[2] * 3,
color, color, color, alpha, alpha, alpha, 0);
}
t += 3;
}
} else {
while(ok && c--) {
if (visibility_test(I->proximity, vi, t))
{
if(va) {
ok &= CGOAlphaTriangle(info->alpha_cgo,
v + t[0] * 3, v + t[1] * 3, v + t[2] * 3,
vn + t[0] * 3, vn + t[1] * 3, vn + t[2] * 3,
vc + t[0] * 3, vc + t[1] * 3, vc + t[2] * 3,
va[t[0]], va[t[1]], va[t[2]], 0);
} else {
ok &= CGOAlphaTriangle(info->alpha_cgo,
v + t[0] * 3, v + t[1] * 3, v + t[2] * 3,
vn + t[0] * 3, vn + t[1] * 3, vn + t[2] * 3,
vc + t[0] * 3, vc + t[1] * 3, vc + t[2] * 3,
alpha, alpha, alpha, 0);
}
}
t += 3;
}
}
if (ok)
CGOEnd(info->alpha_cgo);
}
}
} else if (ok){
/* fast and ugly */
if(I->oneColorFlag) {
float col[3];
ColorGetEncoded(G, I->oneColor, col);
glColor4f(col[0], col[1], col[2], alpha);
vc = NULL;
}
if(I->allVisibleFlag) {
for (; (c = *(s++)); s += c + 2) {
glBegin(GL_TRIANGLE_STRIP);
immediate_draw_indexed_vertices_alpha(vc, va, alpha, vn, v, s, c + 2);
glEnd();
}
} else {
c = I->NT;
if(c) {
glBegin(GL_TRIANGLES);
for (; c--; t += 3) {
if (visibility_test(I->proximity, vi, t)) {
immediate_draw_indexed_vertices_alpha(vc, va, alpha, vn, v, t, 3);
}
}
glEnd();
}
}
}
}
} else if (ok) { /* opaque */
if(I->oneColorFlag) {
glColor3fv(ColorGet(G, I->oneColor));
vc = NULL;
}
if(I->allVisibleFlag) {
for (; (c = *(s++)); s += c + 2) {
glBegin(GL_TRIANGLE_STRIP);
immediate_draw_indexed_vertices(vc, vn, v, s, c + 2);
glEnd();
}
} else {
c = I->NT;
if(c) {
glBegin(GL_TRIANGLES);
for (; c--; t += 3) {
if (visibility_test(I->proximity, vi, t)) {
immediate_draw_indexed_vertices(vc, vn, v, t, 3);
}
}
glEnd();
}
}
}
}
if(ok && SettingGetGlobal_i(G, cSetting_surface_debug)) {
t = I->T;
c = I->NT;
glLineWidth(1.0F);
// draw green triangles, either filled or as line edges,
// depending on surface_type
if(c) {
glColor3f(0.0, 1.0, 0.0);
if (I->Type == 2) {
// filled green triangles for surface as mesh
glBegin(GL_TRIANGLES);
for (; c--; t += 3) {
if(I->allVisibleFlag
|| visibility_test(I->proximity, vi, t)) {
immediate_draw_indexed_vertices(NULL, vn, v, t, 3);
}
}
glEnd();
} else {
// line edges as green lines
glBegin(GL_LINES);
for (; c--; t += 3) {
if(I->allVisibleFlag
|| visibility_test(I->proximity, vi, t)) {
int indices[] = {t[0], t[1], t[1], t[2], t[2], t[0]};
immediate_draw_indexed_vertices(NULL, vn, v, indices, 6);
}
}
glEnd();
}
}
// draw normals as red lines
c = I->N;
if(c) {
SceneResetNormal(G, true);
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_LINES);
while(c--) {
glVertex3fv(v);
glVertex3f(v[0] + vn[0] / 2, v[1] + vn[1] / 2, v[2] + vn[2] / 2);
v += 3;
vn += 3;
}
glEnd();
}
}
if (two_sided_lighting){
GLLIGHTMODELI(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
}
#endif
}
}
if (!ok){
I->R.fInvalidate(&I->R, I->R.cs, cRepInvPurge);
I->R.cs->Active[cRepSurface] = false;
}
}