mirror of
https://github.com/schrodinger/pymol-open-source.git
synced 2026-06-04 20:04:21 +08:00
2574 lines
79 KiB
C++
2574 lines
79 KiB
C++
#include "CGOGL.h"
|
|
|
|
#include "CGO.h"
|
|
#include "CGOGL.h"
|
|
#include "CGORenderer.h"
|
|
#include "CoordSet.h"
|
|
#include "Feedback.h"
|
|
#include "GLVertexBuffer.h"
|
|
#include "GraphicsUtil.h"
|
|
#include "Scene.h"
|
|
#include "SceneDef.h"
|
|
#include "ShaderMgr.h"
|
|
#include "Sphere.h"
|
|
#include "os_gl.h"
|
|
#include "os_gl_cgo.h"
|
|
|
|
#define VAR_FOR_NORMAL pl
|
|
#define VERTEX_NORMAL_SIZE 3
|
|
#define VAR_FOR_NORMAL_CNT_PLUS
|
|
|
|
#ifdef PURE_OPENGL_ES_2
|
|
#define glVertexAttrib4ubv(loc, data) glVertexAttrib4f(loc, \
|
|
(data)[0] / 255.f, (data)[1] / 255.f, (data)[2] / 255.f, (data)[3] / 255.f);
|
|
#endif
|
|
|
|
constexpr unsigned VERTEX_PICKCOLOR_RGBA_SIZE = 1; // 4 unsigned bytes
|
|
constexpr unsigned VERTEX_PICKCOLOR_INDEX_SIZE = 2; // index + bond
|
|
constexpr unsigned VERTEX_PICKCOLOR_SIZE = VERTEX_PICKCOLOR_RGBA_SIZE + //
|
|
VERTEX_PICKCOLOR_INDEX_SIZE;
|
|
constexpr unsigned VERTEX_ACCESSIBILITY_SIZE = 1;
|
|
|
|
/* ======== GL Rendering ======== */
|
|
|
|
static int CGO_gl_begin_WARNING_CALLED = false,
|
|
CGO_gl_end_WARNING_CALLED = false,
|
|
CGO_gl_vertex_WARNING_CALLED = false;
|
|
|
|
const float g_ones4f[4] = {1.f, 1.f, 1.f, 1.f};
|
|
|
|
static int CGOConvertDebugMode(int debug, int modeArg)
|
|
{
|
|
int mode = modeArg;
|
|
if (debug == 1) {
|
|
switch (mode) {
|
|
case GL_TRIANGLES:
|
|
mode = GL_LINES;
|
|
break;
|
|
case GL_TRIANGLE_STRIP:
|
|
mode = GL_LINE_STRIP;
|
|
break;
|
|
case GL_TRIANGLE_FAN:
|
|
mode = GL_LINES;
|
|
break;
|
|
}
|
|
} else {
|
|
mode = GL_POINTS;
|
|
}
|
|
return mode;
|
|
}
|
|
|
|
static void CGO_gl_begin(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
#ifndef PURE_OPENGL_ES_2
|
|
if (I->use_shader) {
|
|
#endif
|
|
if (!CGO_gl_begin_WARNING_CALLED) {
|
|
PRINTFB(I->G, FB_CGO, FB_Warnings)
|
|
" CGO_gl_begin() is called but not implemented in OpenGLES\n" ENDFB(I->G);
|
|
CGO_gl_begin_WARNING_CALLED = true;
|
|
}
|
|
#ifndef PURE_OPENGL_ES_2
|
|
} else {
|
|
int mode = CGO_get_int(*pc);
|
|
if (I->debug)
|
|
mode = CGOConvertDebugMode(I->debug, mode);
|
|
glBegin(mode);
|
|
}
|
|
#endif
|
|
}
|
|
static void CGO_gl_end(CCGORenderer* I, CGO_op_data)
|
|
{
|
|
#ifndef PURE_OPENGL_ES_2
|
|
if (I->use_shader) {
|
|
#endif
|
|
if (!CGO_gl_end_WARNING_CALLED) {
|
|
PRINTFB(I->G, FB_CGO, FB_Warnings)
|
|
" CGO_gl_end() is called but not implemented in OpenGLES\n" ENDFB(I->G);
|
|
CGO_gl_end_WARNING_CALLED = true;
|
|
}
|
|
#ifndef PURE_OPENGL_ES_2
|
|
} else {
|
|
glEnd();
|
|
}
|
|
#endif
|
|
}
|
|
static void CGO_gl_vertex(CCGORenderer* I, CGO_op_data v)
|
|
{
|
|
#ifndef PURE_OPENGL_ES_2
|
|
if (I->use_shader) {
|
|
#endif
|
|
if (!CGO_gl_vertex_WARNING_CALLED) {
|
|
PRINTFB(I->G, FB_CGO, FB_Warnings)
|
|
" CGO_gl_vertex() is called but not implemented in OpenGLES\n" ENDFB(
|
|
I->G);
|
|
CGO_gl_vertex_WARNING_CALLED = true;
|
|
}
|
|
#ifndef PURE_OPENGL_ES_2
|
|
} else {
|
|
glVertex3fv(*v);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void CGO_gl_vertex_cross(CCGORenderer* I, CGO_op_data v)
|
|
{
|
|
#ifndef PURE_OPENGL_ES_2
|
|
if (I->use_shader) {
|
|
#endif
|
|
if (!CGO_gl_vertex_WARNING_CALLED) {
|
|
PRINTFB(I->G, FB_CGO, FB_Warnings)
|
|
" CGO_gl_vertex() is called but not implemented in OpenGLES\n" ENDFB(
|
|
I->G);
|
|
CGO_gl_vertex_WARNING_CALLED = true;
|
|
}
|
|
#ifndef PURE_OPENGL_ES_2
|
|
} else {
|
|
CSetting *set1 = nullptr, *set2 = nullptr;
|
|
if (I->rep && I->rep->cs)
|
|
set1 = I->rep->cs->Setting.get();
|
|
if (I->rep && I->rep->obj)
|
|
set2 = I->rep->obj->Setting.get();
|
|
float nonbonded_size =
|
|
SettingGet_f(I->G, set1, set2, cSetting_nonbonded_size);
|
|
float pt[3];
|
|
copy3f(*v, pt);
|
|
pt[0] -= nonbonded_size;
|
|
glVertex3fv(pt);
|
|
pt[0] += 2 * nonbonded_size;
|
|
glVertex3fv(pt);
|
|
copy3f(*v, pt);
|
|
pt[1] -= nonbonded_size;
|
|
glVertex3fv(pt);
|
|
pt[1] += 2 * nonbonded_size;
|
|
glVertex3fv(pt);
|
|
copy3f(*v, pt);
|
|
pt[2] -= nonbonded_size;
|
|
glVertex3fv(pt);
|
|
pt[2] += 2 * nonbonded_size;
|
|
glVertex3fv(pt);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void CGO_gl_line(CCGORenderer* I, CGO_op_data v)
|
|
{
|
|
#ifndef PURE_OPENGL_ES_2
|
|
if (!I->use_shader) {
|
|
auto line = reinterpret_cast<const cgo::draw::line*>(*v);
|
|
glVertex3fv(line->vertex1);
|
|
glVertex3fv(line->vertex2);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void CGO_gl_splitline(CCGORenderer* I, CGO_op_data v)
|
|
{
|
|
#ifndef PURE_OPENGL_ES_2
|
|
if (!I->use_shader) {
|
|
auto splitline = reinterpret_cast<const cgo::draw::splitline*>(*v);
|
|
bool interpolation = splitline->flags & cgo::draw::splitline::interpolation;
|
|
bool equal_colors = splitline->flags & cgo::draw::splitline::equal_colors;
|
|
bool no_split_for_pick =
|
|
splitline->flags & cgo::draw::splitline::no_split_for_pick;
|
|
|
|
if (I->isPicking) {
|
|
if (no_split_for_pick) {
|
|
glVertex3fv(splitline->vertex1);
|
|
glVertex3fv(splitline->vertex2);
|
|
} else {
|
|
float h[3];
|
|
average3f(splitline->vertex1, splitline->vertex2, h);
|
|
glVertex3fv(splitline->vertex1);
|
|
glVertex3fv(h);
|
|
unsigned char col[4];
|
|
AssignNewPickColor(nullptr, I->info->pick, col, &I->rep->context,
|
|
splitline->index, splitline->bond);
|
|
glColor4ubv(col);
|
|
glVertex3fv(h);
|
|
glVertex3fv(splitline->vertex2);
|
|
}
|
|
} else if (interpolation || equal_colors) {
|
|
glVertex3fv(splitline->vertex1);
|
|
if (!equal_colors)
|
|
glColor4ub(splitline->color2[0], splitline->color2[1],
|
|
splitline->color2[2], CLIP_COLOR_VALUE(I->alpha));
|
|
glVertex3fv(splitline->vertex2);
|
|
} else {
|
|
float h[3];
|
|
average3f(splitline->vertex1, splitline->vertex2, h);
|
|
glVertex3fv(splitline->vertex1);
|
|
glVertex3fv(h);
|
|
glColor4ub(splitline->color2[0], splitline->color2[1],
|
|
splitline->color2[2], CLIP_COLOR_VALUE(I->alpha));
|
|
glVertex3fv(h);
|
|
glVertex3fv(splitline->vertex2);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void CGO_gl_normal(CCGORenderer* I, CGO_op_data varg)
|
|
{
|
|
const float* v = *varg;
|
|
#ifdef PURE_OPENGL_ES_2
|
|
if (I->use_shader) {
|
|
glVertexAttrib3fv(VERTEX_NORMAL, v);
|
|
} else {
|
|
#else
|
|
{
|
|
#endif
|
|
#ifndef PURE_OPENGL_ES_2
|
|
glNormal3f(v[0], v[1], v[2]);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void CGO_gl_draw_arrays(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
auto sp = reinterpret_cast<const cgo::draw::arrays*>(*pc);
|
|
int mode = sp->mode, arrays = sp->arraybits, narrays = sp->narrays,
|
|
nverts = sp->nverts;
|
|
const float* data = sp->floatdata;
|
|
(void) narrays;
|
|
#ifndef PURE_OPENGL_ES_2
|
|
if (I->use_shader) {
|
|
#endif
|
|
|
|
#ifdef _WEBGL
|
|
uint buffers[3] = {0, 0, 0};
|
|
glGenBuffers(3, buffers);
|
|
#endif
|
|
|
|
if (arrays & CGO_VERTEX_ARRAY)
|
|
glEnableVertexAttribArray(VERTEX_POS);
|
|
if (arrays & CGO_NORMAL_ARRAY)
|
|
glEnableVertexAttribArray(VERTEX_NORMAL);
|
|
if (I->isPicking) {
|
|
if (arrays & CGO_PICK_COLOR_ARRAY) {
|
|
glEnableVertexAttribArray(VERTEX_COLOR);
|
|
}
|
|
} else {
|
|
if (arrays & CGO_COLOR_ARRAY)
|
|
glEnableVertexAttribArray(VERTEX_COLOR);
|
|
}
|
|
|
|
if (arrays & CGO_VERTEX_ARRAY) {
|
|
#ifdef _WEBGL
|
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
|
glBufferData(
|
|
GL_ARRAY_BUFFER, sizeof(float) * nverts * 3, data, GL_STATIC_DRAW);
|
|
glVertexAttribPointer(
|
|
VERTEX_POS, VERTEX_POS_SIZE, GL_FLOAT, GL_FALSE, 0, 0);
|
|
#else
|
|
glVertexAttribPointer(
|
|
VERTEX_POS, VERTEX_POS_SIZE, GL_FLOAT, GL_FALSE, 0, data);
|
|
#endif
|
|
data += nverts * VERTEX_POS_SIZE;
|
|
}
|
|
if (arrays & CGO_NORMAL_ARRAY) {
|
|
#ifdef _WEBGL
|
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
|
|
glBufferData(
|
|
GL_ARRAY_BUFFER, sizeof(float) * nverts * 3, data, GL_STATIC_DRAW);
|
|
glVertexAttribPointer(
|
|
VERTEX_NORMAL, VERTEX_NORMAL_SIZE, GL_FLOAT, GL_FALSE, 0, 0);
|
|
#else
|
|
glVertexAttribPointer(
|
|
VERTEX_NORMAL, VERTEX_NORMAL_SIZE, GL_FLOAT, GL_FALSE, 0, data);
|
|
#endif
|
|
data += nverts * VERTEX_NORMAL_SIZE;
|
|
}
|
|
if (I->isPicking) {
|
|
if (arrays & CGO_COLOR_ARRAY) {
|
|
data += nverts * VERTEX_COLOR_SIZE;
|
|
}
|
|
if (arrays & CGO_PICK_COLOR_ARRAY) {
|
|
#ifdef _WEBGL
|
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
|
|
glBufferData(GL_ARRAY_BUFFER, nverts * 4, data, GL_STATIC_DRAW);
|
|
glVertexAttribPointer(
|
|
VERTEX_COLOR, VERTEX_COLOR_SIZE, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
|
|
#else
|
|
glVertexAttribPointer(
|
|
VERTEX_COLOR, VERTEX_COLOR_SIZE, GL_UNSIGNED_BYTE, GL_FALSE, 0, data);
|
|
#endif
|
|
data += nverts * VERTEX_PICKCOLOR_SIZE;
|
|
}
|
|
} else {
|
|
if (arrays & CGO_COLOR_ARRAY) {
|
|
#ifdef _WEBGL
|
|
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
|
|
glBufferData(
|
|
GL_ARRAY_BUFFER, sizeof(float) * nverts * 4, data, GL_STATIC_DRAW);
|
|
glVertexAttribPointer(
|
|
VERTEX_COLOR, VERTEX_COLOR_SIZE, GL_FLOAT, GL_FALSE, 0, 0);
|
|
#else
|
|
glVertexAttribPointer(
|
|
VERTEX_COLOR, VERTEX_COLOR_SIZE, GL_FLOAT, GL_FALSE, 0, data);
|
|
#endif
|
|
data += nverts * VERTEX_COLOR_SIZE;
|
|
}
|
|
if (arrays & CGO_PICK_COLOR_ARRAY) {
|
|
data += nverts * VERTEX_PICKCOLOR_SIZE;
|
|
}
|
|
}
|
|
if (I->debug) {
|
|
mode = CGOConvertDebugMode(I->debug, mode);
|
|
}
|
|
glDrawArrays(mode, 0, nverts);
|
|
|
|
if (I->isPicking) {
|
|
if (arrays & CGO_PICK_COLOR_ARRAY) {
|
|
glDisableVertexAttribArray(VERTEX_COLOR);
|
|
}
|
|
} else {
|
|
if (arrays & CGO_COLOR_ARRAY)
|
|
glDisableVertexAttribArray(VERTEX_COLOR);
|
|
}
|
|
if (arrays & CGO_VERTEX_ARRAY)
|
|
glDisableVertexAttribArray(VERTEX_POS);
|
|
if (arrays & CGO_NORMAL_ARRAY)
|
|
glDisableVertexAttribArray(VERTEX_NORMAL);
|
|
#ifdef _WEBGL
|
|
glDeleteBuffers(3, buffers);
|
|
#endif
|
|
|
|
#ifndef PURE_OPENGL_ES_2
|
|
} else {
|
|
int pl, pla, plc;
|
|
const float* vertexVals = nullptr;
|
|
const float *colorVals = 0, *normalVals = 0, *tmp_ptr;
|
|
const uchar *pickColorVals = 0, *tmp_pc_ptr;
|
|
float alpha = I->alpha;
|
|
if (arrays & CGO_VERTEX_ARRAY) {
|
|
vertexVals = data;
|
|
data += nverts * VERTEX_POS_SIZE;
|
|
}
|
|
if (arrays & CGO_NORMAL_ARRAY) {
|
|
normalVals = data;
|
|
data += nverts * VERTEX_NORMAL_SIZE;
|
|
}
|
|
if (I->isPicking) {
|
|
alpha = 1.f;
|
|
if (arrays & CGO_COLOR_ARRAY) {
|
|
data += nverts * VERTEX_COLOR_SIZE;
|
|
}
|
|
if (arrays & CGO_PICK_COLOR_ARRAY) {
|
|
pickColorVals = (uchar*) data;
|
|
data += nverts * VERTEX_PICKCOLOR_SIZE;
|
|
}
|
|
} else {
|
|
if (arrays & CGO_COLOR_ARRAY) {
|
|
colorVals = data;
|
|
data += nverts * 4;
|
|
}
|
|
if (arrays & CGO_PICK_COLOR_ARRAY) {
|
|
data += nverts * VERTEX_PICKCOLOR_SIZE;
|
|
}
|
|
}
|
|
if (arrays & CGO_ACCESSIBILITY_ARRAY) {
|
|
data += nverts * VERTEX_ACCESSIBILITY_SIZE;
|
|
}
|
|
|
|
if (I->debug) {
|
|
mode = CGOConvertDebugMode(I->debug, mode);
|
|
}
|
|
|
|
glBegin(mode);
|
|
for (pl = 0, pla = 0, plc = 0; pl < nverts; pl++, pla += 3, plc += 4) {
|
|
if (pickColorVals) {
|
|
tmp_pc_ptr =
|
|
&pickColorVals[plc]; /* the pick colors are saved with rgba */
|
|
glColor4ub(tmp_pc_ptr[0], tmp_pc_ptr[1], tmp_pc_ptr[2], tmp_pc_ptr[3]);
|
|
} else {
|
|
if (colorVals) {
|
|
tmp_ptr = &colorVals[plc];
|
|
glColor4f(tmp_ptr[0], tmp_ptr[1], tmp_ptr[2], alpha);
|
|
}
|
|
if (normalVals) {
|
|
tmp_ptr = &normalVals[pla];
|
|
glNormal3fv(&normalVals[pla]);
|
|
}
|
|
}
|
|
if (vertexVals) {
|
|
tmp_ptr = &vertexVals[pla];
|
|
glVertex3fv(&vertexVals[pla]);
|
|
}
|
|
}
|
|
glEnd();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* TransparentInfoSortIX - This function sorts all n_tri triangle
|
|
* centroids in the array sum by:
|
|
* 1) computing z-value in array z_value
|
|
* 2) bin sorting z_values and placing indices in ix array (using Util.cpp)
|
|
*
|
|
* - uses sort_mem as pre-allocated memory to sort
|
|
* - t_mode - either forward (1) or backwards (0) sort
|
|
*/
|
|
void TransparentInfoSortIX(PyMOLGlobals* G, float* sum, float* z_value, int* ix,
|
|
int n_tri, int* sort_mem, int t_mode)
|
|
{
|
|
float* zv;
|
|
float* sv;
|
|
float matrix[16];
|
|
int idx;
|
|
|
|
#ifdef PURE_OPENGL_ES_2
|
|
copy44f(SceneGetModelViewMatrixPtr(G), matrix);
|
|
#else
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
|
|
#endif
|
|
zv = z_value;
|
|
sv = sum;
|
|
|
|
/* for each triangle, computes the z */
|
|
for (idx = 0; idx < n_tri; ++idx) {
|
|
*(zv++) = matrix[2] * sv[0] + matrix[6] * sv[1] + matrix[10] * sv[2];
|
|
sv += 3;
|
|
}
|
|
|
|
UtilZeroMem(sort_mem, sizeof(int) * (n_tri + 256));
|
|
|
|
switch (t_mode) {
|
|
case 1:
|
|
UtilSemiSortFloatIndexWithNBinsImpl(
|
|
sort_mem, n_tri, 256, z_value, ix, true); // front to back
|
|
/* UtilSortIndex(n_tri,z_value,ix,(UtilOrderFn*)ZOrderFn); */
|
|
break;
|
|
default:
|
|
UtilSemiSortFloatIndexWithNBinsImpl(
|
|
sort_mem, n_tri, 256, z_value, ix, false); // back to front
|
|
/* UtilSortIndex(n_tri,z_value,ix,(UtilOrderFn*)ZRevOrderFn); */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* CGOReorderIndicesWithTransparentInfo : This function
|
|
* takes the triangle index array ix (result from TransparentInfoSortIX)
|
|
* and sets the vertices (vertexIndices) for each triangle from the original
|
|
* indices (vertexIndicesOriginal), then uses glBufferData to set the
|
|
* GL_ELEMENT_ARRAY_BUFFER to these indices.
|
|
*
|
|
*/
|
|
static void CGOReorderIndicesWithTransparentInfo(PyMOLGlobals* G, int nindices,
|
|
size_t vbuf, int n_tri, int* ix, VertexIndex_t* vertexIndicesOriginal,
|
|
VertexIndex_t* vertexIndices)
|
|
{
|
|
int c, pl, idx;
|
|
auto* ibo = G->ShaderMgr->getGPUBuffer<IndexBufferGL>(vbuf);
|
|
if (!vertexIndices) {
|
|
PRINTFB(G, FB_RepSurface, FB_Errors)
|
|
"ERROR: RepSurfaceRender() vertexIndices is not set, nindices=%d\n",
|
|
nindices ENDFB(G);
|
|
}
|
|
/* updates the vertexIndices from the ix array */
|
|
for (c = 0, pl = 0; c < n_tri; c++) {
|
|
idx = ix[c] * 3;
|
|
vertexIndices[pl++] = vertexIndicesOriginal[idx];
|
|
vertexIndices[pl++] = vertexIndicesOriginal[idx + 1];
|
|
vertexIndices[pl++] = vertexIndicesOriginal[idx + 2];
|
|
}
|
|
ibo->copyFrom(pymol::span{vertexIndices, static_cast<std::size_t>(nindices)});
|
|
}
|
|
|
|
static void CGO_gl_draw_buffers_indexed(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
auto sp = reinterpret_cast<const cgo::draw::buffers_indexed*>(*pc);
|
|
int mode = sp->mode, nindices = sp->nindices, nverts = sp->nverts,
|
|
n_data = sp->n_data;
|
|
size_t vboid = sp->vboid, iboid = sp->iboid;
|
|
auto* vbo = I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(vboid);
|
|
auto* ibo = I->G->ShaderMgr->getGPUBuffer<IndexBufferGL>(iboid);
|
|
CheckGLErrorOK(I->G, "beginning of CGO_gl_draw_buffers_indexed err=%d\n");
|
|
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
|
|
if (I->isPicking) {
|
|
int attr_a_Color = shaderPrg->GetAttribLocation("a_Color");
|
|
vbo->maskAttributes({attr_a_Color});
|
|
shaderPrg->Set1i("fog_enabled", 0);
|
|
shaderPrg->Set1i("lighting_enabled", 0);
|
|
if (I->use_shader) {
|
|
if (sp->pickvboid) {
|
|
auto* pickvbo =
|
|
I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->pickvboid);
|
|
pickvbo->bind(shaderPrg->id, I->pick_pass());
|
|
} else {
|
|
glEnableVertexAttribArray(attr_a_Color);
|
|
glVertexAttribPointer(attr_a_Color, VERTEX_COLOR_SIZE, GL_UNSIGNED_BYTE,
|
|
GL_TRUE, 0, sp->floatdata);
|
|
}
|
|
}
|
|
}
|
|
if (n_data) {
|
|
// if transparency data, then sort it
|
|
int n_tri = nindices / 3;
|
|
float* sum = sp->floatdata + nverts * 3;
|
|
float* z_value = sum + (nindices * 3);
|
|
int* ix = (int*) (z_value + n_tri);
|
|
int* sort_mem = ix + n_tri;
|
|
int t_mode;
|
|
CSetting *set1 = nullptr, *set2 = nullptr;
|
|
if (I->rep && I->rep->cs)
|
|
set1 = I->rep->cs->Setting.get();
|
|
if (I->rep && I->rep->obj)
|
|
set2 = I->rep->obj->Setting.get();
|
|
t_mode = SettingGet_i(I->G, set1, set2, cSetting_transparency_mode);
|
|
if (t_mode != 3) {
|
|
auto vertexIndicesOriginalTI = (VertexIndex_t*) (sort_mem + n_tri + 256);
|
|
auto vertexIndicesTI = vertexIndicesOriginalTI + nindices;
|
|
TransparentInfoSortIX(I->G, sum, z_value, ix, n_tri, sort_mem, t_mode);
|
|
CGOReorderIndicesWithTransparentInfo(I->G, nindices, iboid, n_tri, ix,
|
|
vertexIndicesOriginalTI, vertexIndicesTI);
|
|
}
|
|
}
|
|
|
|
if (I->debug) {
|
|
mode = CGOConvertDebugMode(I->debug, mode);
|
|
}
|
|
vbo->bind(shaderPrg->id);
|
|
ibo->bind();
|
|
|
|
CheckGLErrorOK(
|
|
I->G, "CGO_gl_draw_buffers_indexed: before glDrawElements err=%d\n");
|
|
glDrawElements(mode, nindices, VertexIndex_GL_ENUM, 0);
|
|
CheckGLErrorOK(
|
|
I->G, "CGO_gl_draw_buffers_indexed: after glDrawElements err=%d\n");
|
|
|
|
vbo->unbind();
|
|
ibo->unbind();
|
|
|
|
if (I->isPicking) {
|
|
auto* pickvbo =
|
|
I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->pickvboid);
|
|
if (pickvbo)
|
|
pickvbo->unbind();
|
|
}
|
|
|
|
CheckGLErrorOK(I->G, "CGO_gl_draw_buffers_indexed: end err=%d\n");
|
|
}
|
|
|
|
static void CGO_gl_draw_buffers_not_indexed(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
const cgo::draw::buffers_not_indexed* sp =
|
|
reinterpret_cast<decltype(sp)>(*pc);
|
|
int mode = sp->mode;
|
|
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
auto* vbo = I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->vboid);
|
|
if (!vbo)
|
|
return;
|
|
if (I->isPicking) {
|
|
int attr_a_Color = shaderPrg->GetAttribLocation("a_Color");
|
|
vbo->maskAttributes({attr_a_Color});
|
|
shaderPrg->Set1i("fog_enabled", 0);
|
|
shaderPrg->Set1i("lighting_enabled", 0);
|
|
if (I->use_shader) {
|
|
if (sp->pickvboid) {
|
|
auto* pickvbo =
|
|
I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->pickvboid);
|
|
pickvbo->bind(shaderPrg->id, I->pick_pass());
|
|
} else {
|
|
glEnableVertexAttribArray(attr_a_Color);
|
|
glVertexAttribPointer(attr_a_Color, VERTEX_COLOR_SIZE, GL_UNSIGNED_BYTE,
|
|
GL_TRUE, 0, sp->floatdata);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (I->debug) {
|
|
mode = CGOConvertDebugMode(I->debug, mode);
|
|
}
|
|
|
|
vbo->bind(shaderPrg->id);
|
|
glDrawArrays(mode, 0, sp->nverts);
|
|
vbo->unbind();
|
|
|
|
if (I->isPicking) {
|
|
auto* pickvbo =
|
|
I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->pickvboid);
|
|
if (pickvbo)
|
|
pickvbo->unbind();
|
|
}
|
|
}
|
|
|
|
static void CGO_gl_mask_attribute_if_picking(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
if (I->isPicking) {
|
|
const cgo::draw::mask_attribute_if_picking* sp =
|
|
reinterpret_cast<decltype(sp)>(*pc);
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
auto* vbo = I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->vboid);
|
|
if (!vbo)
|
|
return;
|
|
int loc = shaderPrg->GetAttribLocation(
|
|
I->G->ShaderMgr->GetAttributeName(sp->attr_lookup_idx));
|
|
vbo->maskAttribute(loc);
|
|
}
|
|
}
|
|
|
|
static void CGO_gl_bind_vbo_for_picking(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
if (I->isPicking) {
|
|
const cgo::draw::bind_vbo_for_picking* sp =
|
|
reinterpret_cast<decltype(sp)>(*pc);
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
auto* vbo = I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->vboid);
|
|
if (!vbo)
|
|
return;
|
|
vbo->bind(
|
|
shaderPrg->id, sp->which_attr_idx + sp->npickattrs * I->pick_pass());
|
|
}
|
|
}
|
|
|
|
static void CGO_gl_draw_custom(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
const cgo::draw::custom* sp = reinterpret_cast<decltype(sp)>(*pc);
|
|
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
auto* vbo = I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->vboid);
|
|
if (!vbo)
|
|
return;
|
|
IndexBufferGL* ibo = nullptr;
|
|
if (sp->iboid) {
|
|
ibo = I->G->ShaderMgr->getGPUBuffer<IndexBufferGL>(sp->iboid);
|
|
}
|
|
vbo->bind(shaderPrg->id);
|
|
if (ibo) {
|
|
ibo->bind();
|
|
glDrawElements(sp->mode, sp->nindices, VertexIndex_GL_ENUM, 0);
|
|
} else {
|
|
glDrawArrays(sp->mode, 0, sp->nverts);
|
|
}
|
|
vbo->unbind();
|
|
if (sp->pickvboid) {
|
|
auto* pickvbo =
|
|
I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->pickvboid);
|
|
if (pickvbo)
|
|
pickvbo->unbind();
|
|
}
|
|
if (ibo)
|
|
ibo->unbind();
|
|
}
|
|
|
|
static void CGO_gl_draw_sphere_buffers(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
const cgo::draw::sphere_buffers* sp = reinterpret_cast<decltype(sp)>(*pc);
|
|
int num_spheres = sp->num_spheres;
|
|
int attr_color;
|
|
auto* vbo = I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->vboid);
|
|
auto* pickvbo =
|
|
I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->pickvboid);
|
|
CShaderPrg* shaderPrg;
|
|
int pickable = 0;
|
|
|
|
shaderPrg = I->G->ShaderMgr->Get_DefaultSphereShader(
|
|
I->info ? I->info->pass : RenderPass::Antialias);
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
|
|
attr_color = shaderPrg->GetAttribLocation("a_Color");
|
|
|
|
if (I->isPicking) {
|
|
vbo->maskAttributes({attr_color});
|
|
pickable = SettingGet_i(I->G, I->set1, I->set2, cSetting_pickable);
|
|
shaderPrg->Set1i("lighting_enabled", 0);
|
|
if (pickable) {
|
|
pickvbo->bind(shaderPrg->id, I->pick_pass());
|
|
} else {
|
|
assert(I->info->pick);
|
|
unsigned char nopick[4] = {};
|
|
I->info->pick->colorNoPick(nopick);
|
|
glVertexAttrib4ubv(attr_color, nopick);
|
|
}
|
|
}
|
|
|
|
vbo->bind(shaderPrg->id);
|
|
#if defined(PURE_OPENGL_ES_2)
|
|
glDrawArrays(GL_TRIANGLES, 0, num_spheres * VerticesPerSphere());
|
|
#else
|
|
glDrawArrays(GL_QUADS, 0, num_spheres * 4);
|
|
#endif
|
|
|
|
vbo->unbind();
|
|
}
|
|
|
|
static void CGO_gl_draw_bezier_buffers(CCGORenderer* I, CGO_op_data cgo_data)
|
|
{
|
|
const auto bezier =
|
|
reinterpret_cast<const cgo::draw::bezier_buffers*>(*cgo_data);
|
|
const auto vbo = I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(bezier->vboid);
|
|
auto shaderPrg = I->G->ShaderMgr->Get_BezierShader();
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
|
|
vbo->bind(shaderPrg->id);
|
|
glDrawArrays(GL_PATCHES, 0, 4);
|
|
vbo->unbind();
|
|
}
|
|
|
|
static void CGO_gl_draw_cylinder_buffers(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
const cgo::draw::cylinder_buffers* sp = reinterpret_cast<decltype(sp)>(*pc);
|
|
int num_cyl = sp->num_cyl;
|
|
int min_alpha = sp->alpha;
|
|
int attr_colors, attr_colors2;
|
|
CShaderPrg* shaderPrg;
|
|
int pickable = 0;
|
|
auto* vbo = I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->vboid);
|
|
auto* ibo = I->G->ShaderMgr->getGPUBuffer<IndexBufferGL>(sp->iboid);
|
|
auto* pickvbo =
|
|
I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->pickvboid);
|
|
|
|
shaderPrg = I->G->ShaderMgr->Get_CylinderShader(
|
|
I->info ? I->info->pass : RenderPass::Antialias);
|
|
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
attr_colors = shaderPrg->GetAttribLocation("a_Color");
|
|
attr_colors2 = shaderPrg->GetAttribLocation("a_Color2");
|
|
|
|
if (I->isPicking) {
|
|
pickable = SettingGet_i(I->G, I->set1, I->set2, cSetting_pickable);
|
|
shaderPrg->Set1i("lighting_enabled", 0);
|
|
}
|
|
if (I->isPicking) {
|
|
vbo->maskAttributes({attr_colors, attr_colors2});
|
|
if (pickable) {
|
|
// in first pass: 1st half of vbo, in second pass: 2nd half of vbo
|
|
// first color (offset 0)
|
|
pickvbo->bind(shaderPrg->id, I->pick_pass());
|
|
// second color (offset 4)
|
|
pickvbo->bind(shaderPrg->id, I->pick_pass() + SHADER_PICKING_PASSES_MAX);
|
|
} else {
|
|
assert(I->info->pick);
|
|
unsigned char nopick[4] = {};
|
|
I->info->pick->colorNoPick(nopick);
|
|
glVertexAttrib4ubv(attr_colors, nopick);
|
|
glVertexAttrib4ubv(attr_colors2, nopick);
|
|
}
|
|
}
|
|
|
|
vbo->bind(shaderPrg->id);
|
|
ibo->bind();
|
|
|
|
if (min_alpha < 255) {
|
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
|
glDrawElements(GL_TRIANGLES, num_cyl * NumTotalVerticesPerCylinder(),
|
|
VertexIndex_GL_ENUM, 0);
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
glDepthFunc(GL_LEQUAL);
|
|
}
|
|
glDrawElements(GL_TRIANGLES, num_cyl * NumTotalVerticesPerCylinder(),
|
|
VertexIndex_GL_ENUM, 0);
|
|
|
|
if (min_alpha < 255) {
|
|
glDepthFunc(GL_LESS);
|
|
}
|
|
|
|
ibo->unbind();
|
|
vbo->unbind();
|
|
if (I->isPicking)
|
|
pickvbo->unbind();
|
|
}
|
|
#include "Texture.h"
|
|
|
|
static void CGO_gl_draw_labels(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
const cgo::draw::labels* sp = reinterpret_cast<decltype(sp)>(*pc);
|
|
|
|
CShaderPrg* shaderPrg;
|
|
int t_mode = SettingGetGlobal_i(I->G, cSetting_transparency_mode);
|
|
|
|
if (t_mode == 3 && I->info && I->info->pass != RenderPass::Transparent) {
|
|
// in transparency_mode=3, labels are drawn in the transparency pass=-1
|
|
return;
|
|
}
|
|
shaderPrg = I->G->ShaderMgr->Get_LabelShader(
|
|
I->info ? I->info->pass : RenderPass::Antialias);
|
|
if (I->rep) {
|
|
float label_size;
|
|
CSetting *set1 = nullptr, *set2 = nullptr;
|
|
if (I->rep->cs)
|
|
set1 = I->rep->cs->Setting.get();
|
|
if (I->rep->obj)
|
|
set2 = I->rep->obj->Setting.get();
|
|
label_size = SettingGet_f(I->G, set1, set2, cSetting_label_size);
|
|
shaderPrg->Set1f("scaleByVertexScale", label_size < 0.f ? 1.f : 0.f);
|
|
if (label_size < 0.f) {
|
|
shaderPrg->Set1f("labelTextureSize",
|
|
(float) -2.f * I->info->texture_font_size / label_size);
|
|
}
|
|
}
|
|
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
|
|
auto* vbo = I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->vboid);
|
|
auto* pickvbo =
|
|
I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->pickvboid);
|
|
|
|
if (I->isPicking) {
|
|
pickvbo->bind(shaderPrg->id, I->pick_pass());
|
|
}
|
|
|
|
if (!vbo)
|
|
return;
|
|
vbo->bind(shaderPrg->id);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, sp->ntextures * 6);
|
|
|
|
vbo->unbind();
|
|
pickvbo->unbind();
|
|
}
|
|
|
|
static void CGO_gl_draw_connectors(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
int use_geometry_shaders =
|
|
SettingGetGlobal_b(I->G, cSetting_use_geometry_shaders);
|
|
|
|
const cgo::draw::connectors* sp = reinterpret_cast<decltype(sp)>(*pc);
|
|
|
|
GLenum mode = GL_LINES;
|
|
int factor = 2;
|
|
float lineWidth;
|
|
if (I->isPicking) {
|
|
return;
|
|
}
|
|
CheckGLErrorOK(I->G, "ERROR: CGO_gl_draw_connectors begin returns err=%d\n");
|
|
|
|
if (use_geometry_shaders) {
|
|
mode = GL_POINTS;
|
|
factor = 1;
|
|
} else {
|
|
factor = 4;
|
|
}
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
if (I->rep) {
|
|
float label_size;
|
|
CSetting *set1 = nullptr, *set2 = nullptr;
|
|
float v_scale = SceneGetScreenVertexScale(I->G, nullptr);
|
|
if (I->rep->cs)
|
|
set1 = I->rep->cs->Setting.get();
|
|
if (I->rep->obj)
|
|
set2 = I->rep->obj->Setting.get();
|
|
label_size = SettingGet_f(I->G, set1, set2, cSetting_label_size);
|
|
shaderPrg->Set1f("scaleByVertexScale", label_size < 0.f ? 1.f : 0.f);
|
|
lineWidth = SettingGet_f(I->G, set1, set2, cSetting_label_connector_width);
|
|
if (label_size < 0.f) {
|
|
shaderPrg->Set1f("textureToLabelSize",
|
|
v_scale * (float) I->info->texture_font_size / label_size);
|
|
} else {
|
|
shaderPrg->Set1f("textureToLabelSize", 1.f);
|
|
}
|
|
} else {
|
|
lineWidth = SettingGetGlobal_f(I->G, cSetting_label_connector_width);
|
|
}
|
|
#ifndef _WEBGL
|
|
if (!use_geometry_shaders)
|
|
glLineWidth(lineWidth);
|
|
#endif
|
|
|
|
auto* vbo = I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->vboid);
|
|
if (!vbo)
|
|
return;
|
|
vbo->bind(shaderPrg->id);
|
|
glDrawArrays(mode, 0, sp->nconnectors * factor);
|
|
vbo->unbind();
|
|
CheckGLErrorOK(I->G, "ERROR: CGO_gl_draw_connectors end returns err=%d\n");
|
|
}
|
|
|
|
static void CGO_gl_draw_textures(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
const cgo::draw::textures* sp = reinterpret_cast<decltype(sp)>(*pc);
|
|
int ntextures = sp->ntextures;
|
|
auto* vbo = I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->vboid);
|
|
CShaderPrg* shaderPrg;
|
|
int attr_pickcolor = 0;
|
|
shaderPrg = I->G->ShaderMgr->Get_LabelShader(
|
|
I->info ? I->info->pass : RenderPass::Antialias);
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
if (I->isPicking) {
|
|
attr_pickcolor = shaderPrg->GetAttribLocation("attr_pickcolor");
|
|
}
|
|
if (attr_pickcolor) {
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glEnableVertexAttribArray(attr_pickcolor);
|
|
glVertexAttribPointer(attr_pickcolor, VERTEX_COLOR_SIZE, GL_UNSIGNED_BYTE,
|
|
GL_TRUE, 0, sp->floatdata);
|
|
}
|
|
vbo->bind(shaderPrg->id);
|
|
glDrawArrays(GL_TRIANGLES, 0, ntextures * 6);
|
|
vbo->unbind();
|
|
if (attr_pickcolor) {
|
|
glDisableVertexAttribArray(attr_pickcolor);
|
|
}
|
|
}
|
|
|
|
static void CGO_gl_draw_screen_textures_and_polygons(
|
|
CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
const cgo::draw::screen_textures* sp = reinterpret_cast<decltype(sp)>(*pc);
|
|
int nverts = sp->nverts;
|
|
CShaderPrg* shaderPrg;
|
|
|
|
shaderPrg = I->G->ShaderMgr->Get_ScreenShader();
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
|
|
auto* vb = I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(sp->vboid);
|
|
if (!vb)
|
|
return;
|
|
vb->bind(shaderPrg->id);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, nverts);
|
|
|
|
vb->unbind();
|
|
}
|
|
|
|
static void CGO_gl_draw_trilines(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
int nverts = CGO_get_int(*pc);
|
|
int buffer = CGO_get_int(*pc + 1);
|
|
int a_vertex, a_othervertex, a_uv, a_color, a_color2;
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
a_vertex = 0; // a_Vertex is bound to 0 (see ShaderMgr)
|
|
// CShaderPrg_GetAttribLocation(shaderPrg, "a_Vertex");
|
|
a_othervertex = shaderPrg->GetAttribLocation("a_OtherVertex");
|
|
a_uv = shaderPrg->GetAttribLocation("a_UV");
|
|
a_color = shaderPrg->GetAttribLocation("a_Color");
|
|
a_color2 = shaderPrg->GetAttribLocation("a_Color2");
|
|
|
|
glEnableVertexAttribArray(a_vertex);
|
|
glEnableVertexAttribArray(a_othervertex);
|
|
glEnableVertexAttribArray(a_uv);
|
|
glEnableVertexAttribArray(a_color);
|
|
glEnableVertexAttribArray(a_color2);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
|
|
|
glVertexAttribPointer(a_vertex, 3, GL_FLOAT, GL_FALSE, 32, (const void*) 0);
|
|
glVertexAttribPointer(
|
|
a_othervertex, 3, GL_FLOAT, GL_FALSE, 32, (const void*) 12);
|
|
glVertexAttribPointer(a_uv, 1, GL_FLOAT, GL_FALSE, 32, (const void*) 24);
|
|
glVertexAttribPointer(
|
|
a_color, 4, GL_UNSIGNED_BYTE, GL_TRUE, 32, (const void*) 28);
|
|
glVertexAttribPointer(
|
|
a_color2, 4, GL_UNSIGNED_BYTE, GL_TRUE, 32, (const void*) 28);
|
|
glDrawArrays(GL_TRIANGLES, 0, nverts);
|
|
|
|
glDisableVertexAttribArray(a_vertex);
|
|
glDisableVertexAttribArray(a_othervertex);
|
|
glDisableVertexAttribArray(a_uv);
|
|
glDisableVertexAttribArray(a_color);
|
|
glDisableVertexAttribArray(a_color2);
|
|
}
|
|
|
|
/* CGO_gl_uniform3f - this is the implementation for the
|
|
* CGOUniform3f/CGO_UNIFORM3F operation. From the uniform_id
|
|
* it looks up the uniform location from the current shader,
|
|
* and sets it to the values in this op.
|
|
*
|
|
*/
|
|
static void CGO_gl_uniform3f(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
int uniform_id = CGO_get_int(*pc);
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
if (!shaderPrg) {
|
|
return;
|
|
}
|
|
int loc = shaderPrg->GetUniformLocation(
|
|
shaderPrg->uniformLocations[uniform_id].c_str());
|
|
const float* pcp = *pc + 1;
|
|
glUniform3f(loc, pcp[0], pcp[1], pcp[2]);
|
|
}
|
|
|
|
static void CGO_gl_linewidth(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
#ifndef _WEBGL
|
|
glLineWidth(**pc);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* call glLineWidth and set the "line_width" uniform
|
|
*/
|
|
static void glLineWidthAndUniform(
|
|
float line_width, CShaderPrg* shaderPrg = nullptr)
|
|
{
|
|
#ifndef _WEBGL
|
|
glLineWidth(line_width);
|
|
#endif
|
|
|
|
if (shaderPrg && shaderPrg->name == "trilines")
|
|
shaderPrg->Set1f("line_width", line_width);
|
|
}
|
|
|
|
/* CGO_gl_special - this is the implementation function for
|
|
CGOSpecial/CGO_SPECIAL. Each op has its own implementation.
|
|
*/
|
|
static void CGO_gl_special(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
int mode = CGO_get_int(*pc);
|
|
bool openVR = SceneGetStereo(I->G) == cStereo_openvr;
|
|
char varwidth = 0;
|
|
float vScale =
|
|
(I->info ? I->info->vertex_scale : SceneGetScreenVertexScale(I->G, nullptr));
|
|
|
|
CSetting *csSetting = nullptr, *objSetting = nullptr;
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
if (I->rep && I->rep->cs) {
|
|
csSetting = I->rep->cs->Setting.get();
|
|
}
|
|
if (I->rep && I->rep->obj) {
|
|
objSetting = I->rep->obj->Setting.get();
|
|
}
|
|
switch (mode) {
|
|
case LINEWIDTH_DYNAMIC_WITH_SCALE_RIBBON: {
|
|
float line_width = SettingGet_f(I->G, nullptr, nullptr, cSetting_ribbon_width);
|
|
if (!openVR)
|
|
line_width = SceneGetDynamicLineWidth(I->info, line_width);
|
|
if (I->info && I->info->width_scale_flag) {
|
|
line_width *= I->info->width_scale;
|
|
}
|
|
glLineWidthAndUniform(line_width, shaderPrg);
|
|
} break;
|
|
case LINEWIDTH_DYNAMIC_WITH_SCALE_DASH: {
|
|
float line_width = SettingGet_f(I->G, nullptr, nullptr, cSetting_dash_width);
|
|
if (!openVR)
|
|
line_width = SceneGetDynamicLineWidth(I->info, line_width);
|
|
if (I->info && I->info->width_scale_flag) {
|
|
line_width *= I->info->width_scale;
|
|
}
|
|
glLineWidthAndUniform(line_width, shaderPrg);
|
|
} break;
|
|
case LINEWIDTH_DYNAMIC_WITH_SCALE: {
|
|
float line_width = SettingGet_f(I->G, nullptr, nullptr, cSetting_line_width);
|
|
if (!openVR)
|
|
line_width = SceneGetDynamicLineWidth(I->info, line_width);
|
|
if (I->info && I->info->width_scale_flag) {
|
|
line_width *= I->info->width_scale;
|
|
}
|
|
glLineWidthAndUniform(line_width, shaderPrg);
|
|
} break;
|
|
case LINEWIDTH_WITH_SCALE: {
|
|
float line_width = SettingGet_f(I->G, nullptr, nullptr, cSetting_line_width);
|
|
if (I->info && I->info->width_scale_flag) {
|
|
line_width *= I->info->width_scale;
|
|
}
|
|
glLineWidthAndUniform(line_width, shaderPrg);
|
|
} break;
|
|
case LINEWIDTH_DYNAMIC_MESH: {
|
|
float line_width;
|
|
if (I->rep) {
|
|
line_width = SettingGet_f(I->G, I->rep->cs->Setting.get(),
|
|
I->rep->obj->Setting.get(), cSetting_mesh_width);
|
|
} else {
|
|
line_width = SettingGet_f(I->G, nullptr, nullptr, cSetting_mesh_width);
|
|
}
|
|
if (!openVR)
|
|
line_width = SceneGetDynamicLineWidth(I->info, line_width);
|
|
glLineWidthAndUniform(line_width, shaderPrg);
|
|
} break;
|
|
case POINTSIZE_DYNAMIC_DOT_WIDTH: {
|
|
float ps;
|
|
if (I->info && I->info->width_scale_flag) {
|
|
ps = SettingGet_f(I->G, csSetting, objSetting, cSetting_dot_width) *
|
|
I->info->width_scale;
|
|
} else {
|
|
ps = SettingGet_f(I->G, csSetting, objSetting, cSetting_dot_width);
|
|
}
|
|
#ifdef PURE_OPENGL_ES_2
|
|
if (I->G->ShaderMgr->current_shader) {
|
|
shaderPrg->Set1f("g_pointSize", ps);
|
|
}
|
|
#else
|
|
glPointSize(ps);
|
|
#endif
|
|
break;
|
|
}
|
|
case CYLINDERWIDTH_DYNAMIC_MESH: {
|
|
CSetting* setting = nullptr;
|
|
float mesh_width;
|
|
if (I && I->rep && I->rep->obj) {
|
|
setting = I->rep->obj->Setting.get();
|
|
}
|
|
mesh_width = SettingGet_f(I->G, setting, nullptr, cSetting_mesh_width);
|
|
if (shaderPrg) {
|
|
const float* color = I->color ? I->color : g_ones4f;
|
|
shaderPrg->Set1f("uni_radius",
|
|
SceneGetLineWidthForCylinders(I->G, I->info, mesh_width));
|
|
shaderPrg->SetAttrib4fLocation(
|
|
"a_Color", color[0], color[1], color[2], I->alpha);
|
|
shaderPrg->SetAttrib4fLocation(
|
|
"a_Color2", color[0], color[1], color[2], I->alpha);
|
|
}
|
|
} break;
|
|
case DOTSIZE_WITH_SPHERESCALE: {
|
|
float radius =
|
|
SettingGet_f(I->G, csSetting, objSetting, cSetting_dot_width);
|
|
radius *= vScale;
|
|
if (shaderPrg)
|
|
shaderPrg->Set1f("sphere_size_scale", fabs(radius));
|
|
} break;
|
|
case MESH_WIDTH_FOR_SURFACES: {
|
|
float mesh_width =
|
|
SettingGet_f(I->G, csSetting, objSetting, cSetting_mesh_width);
|
|
if (shaderPrg)
|
|
shaderPrg->Set1f("uni_radius",
|
|
SceneGetLineWidthForCylinders(I->G, I->info, mesh_width));
|
|
} break;
|
|
case CYLINDER_WIDTH_FOR_DISTANCES: {
|
|
float line_width, radius;
|
|
int round_ends;
|
|
round_ends =
|
|
SettingGet_b(I->G, csSetting, objSetting, cSetting_dash_round_ends);
|
|
line_width = SettingGet_f(I->G, csSetting, objSetting, cSetting_dash_width);
|
|
radius = SettingGet_f(I->G, csSetting, objSetting, cSetting_dash_radius);
|
|
|
|
line_width = SceneGetDynamicLineWidth(I->info, line_width);
|
|
|
|
if (shaderPrg) {
|
|
if (radius == 0.0F) {
|
|
float dash_size =
|
|
SettingGet_f(I->G, csSetting, objSetting, cSetting_dash_width);
|
|
shaderPrg->Set1f("uni_radius", SceneGetLineWidthForCylindersStatic(I->G,
|
|
I->info, line_width, dash_size));
|
|
} else {
|
|
shaderPrg->Set1f("uni_radius", radius);
|
|
}
|
|
if (!round_ends) {
|
|
shaderPrg->Set1i("no_flat_caps", 0);
|
|
}
|
|
}
|
|
} break;
|
|
case CYLINDER_WIDTH_FOR_RIBBONS: {
|
|
float pixel_scale_value =
|
|
SettingGetGlobal_f(I->G, cSetting_ray_pixel_scale);
|
|
float line_width, radius;
|
|
line_width =
|
|
SettingGet_f(I->G, csSetting, objSetting, cSetting_ribbon_width);
|
|
radius = SettingGet_f(I->G, csSetting, objSetting, cSetting_ribbon_radius);
|
|
|
|
line_width = SceneGetDynamicLineWidth(I->info, line_width);
|
|
if (pixel_scale_value < 0)
|
|
pixel_scale_value = 1.0F;
|
|
if (shaderPrg) {
|
|
if (radius == 0.0F) {
|
|
shaderPrg->Set1f(
|
|
"uni_radius", vScale * pixel_scale_value * line_width / 2.f);
|
|
} else {
|
|
shaderPrg->Set1f("uni_radius", radius);
|
|
}
|
|
}
|
|
} break;
|
|
case DOT_WIDTH_FOR_DOTS: {
|
|
float dot_width =
|
|
SettingGet_f(I->G, csSetting, objSetting, cSetting_dot_width);
|
|
float radius;
|
|
if (I->info && I->info->width_scale_flag)
|
|
radius = (dot_width * I->info->width_scale);
|
|
else
|
|
radius = dot_width;
|
|
if (shaderPrg)
|
|
shaderPrg->Set1f("g_PointSize", radius);
|
|
glPointSize(radius);
|
|
} break;
|
|
case DOT_WIDTH_FOR_DOT_SPHERES: {
|
|
float dotSize =
|
|
SettingGet_f(I->G, csSetting, objSetting, cSetting_dot_radius);
|
|
float dot_width =
|
|
SettingGet_f(I->G, csSetting, objSetting, cSetting_dot_width);
|
|
float radius;
|
|
if (I->info && dotSize <= 0.0F) {
|
|
if (I->info->width_scale_flag)
|
|
radius =
|
|
dot_width * I->info->width_scale * I->info->vertex_scale / 1.4142F;
|
|
else
|
|
radius = dot_width * I->info->vertex_scale;
|
|
} else {
|
|
radius = dotSize;
|
|
}
|
|
if (shaderPrg)
|
|
shaderPrg->Set1f("sphere_size_scale", fabs(radius));
|
|
} break;
|
|
case CYLINDER_WIDTH_FOR_NONBONDED: {
|
|
if (shaderPrg) {
|
|
float line_width =
|
|
SettingGet_f(I->G, csSetting, objSetting, cSetting_line_width);
|
|
shaderPrg->Set1f("uni_radius", SceneGetLineWidthForCylindersStatic(I->G,
|
|
I->info, line_width, line_width));
|
|
}
|
|
} break;
|
|
case CYLINDER_WIDTH_FOR_REPWIRE_VARWIDTH:
|
|
varwidth = 1;
|
|
case CYLINDER_WIDTH_FOR_REPWIRE: {
|
|
float radius =
|
|
SettingGet_f(I->G, csSetting, objSetting, cSetting_line_radius);
|
|
if (radius < R_SMALL8) {
|
|
float line_width =
|
|
SettingGet_f(I->G, csSetting, objSetting, cSetting_line_width);
|
|
float pixel_scale_value =
|
|
SettingGetGlobal_f(I->G, cSetting_ray_pixel_scale);
|
|
float vertex_scale = vScale;
|
|
float scale_bound = SettingGetGlobal_f(I->G, cSetting_field_of_view) *
|
|
cPI / 180.0f * 0.018f;
|
|
if (!varwidth) {
|
|
line_width = SceneGetDynamicLineWidth(I->info, line_width);
|
|
}
|
|
if (vertex_scale < scale_bound) {
|
|
vertex_scale = scale_bound;
|
|
}
|
|
if (pixel_scale_value < 0)
|
|
pixel_scale_value = 1.0F;
|
|
radius = vertex_scale * pixel_scale_value * line_width / 2.f;
|
|
}
|
|
if (shaderPrg) {
|
|
shaderPrg->Set1f("uni_radius", radius);
|
|
}
|
|
} break;
|
|
case ENABLE_BACK_FACES_IF_NOT_TWO_SIDED: {
|
|
int two_sided_lighting = SettingGet_i(I->G, csSetting, objSetting,
|
|
cSetting_two_sided_lighting) > 0;
|
|
if (!two_sided_lighting) {
|
|
glCullFace(GL_BACK);
|
|
glEnable(GL_CULL_FACE);
|
|
}
|
|
} break;
|
|
case DISABLE_BACK_FACES_IF_NOT_TWO_SIDED: {
|
|
int two_sided_lighting = SettingGet_i(I->G, csSetting, objSetting,
|
|
cSetting_two_sided_lighting) > 0;
|
|
if (!two_sided_lighting) {
|
|
glDisable(GL_CULL_FACE);
|
|
}
|
|
} break;
|
|
case SET_SURFACE_UNIFORMS: {
|
|
float ambient_occlusion_scale = 0.f;
|
|
int ambient_occlusion_mode = SettingGet_i(
|
|
I->G, csSetting, objSetting, cSetting_ambient_occlusion_mode);
|
|
|
|
if (ambient_occlusion_mode) {
|
|
ambient_occlusion_scale = SettingGet_f(
|
|
I->G, csSetting, objSetting, cSetting_ambient_occlusion_scale);
|
|
}
|
|
if (shaderPrg)
|
|
shaderPrg->Set1f("ambient_occlusion_scale", ambient_occlusion_scale);
|
|
} break;
|
|
case SET_ALIGNMENT_UNIFORMS_ATTRIBS: {
|
|
float linewidth =
|
|
SettingGet_f(I->G, csSetting, objSetting, cSetting_cgo_line_width);
|
|
float lineradius =
|
|
SettingGet_f(I->G, csSetting, objSetting, cSetting_cgo_line_radius);
|
|
float pixel_scale_value =
|
|
SettingGetGlobal_f(I->G, cSetting_ray_pixel_scale);
|
|
if (linewidth < 0.f) {
|
|
linewidth = 1.f;
|
|
}
|
|
if (pixel_scale_value < 0)
|
|
pixel_scale_value = 1.0F;
|
|
if (lineradius < 0.f) {
|
|
lineradius = linewidth * vScale * pixel_scale_value / 2.f;
|
|
}
|
|
shaderPrg->Set1f("uni_radius", lineradius);
|
|
if (I->color) {
|
|
shaderPrg->SetAttrib4fLocation(
|
|
"a_Color", I->color[0], I->color[1], I->color[2], 1.f);
|
|
shaderPrg->SetAttrib4fLocation(
|
|
"a_Color2", I->color[0], I->color[1], I->color[2], 1.f);
|
|
}
|
|
glLineWidthAndUniform(lineradius * 2.f / vScale, shaderPrg);
|
|
} break;
|
|
case LINEWIDTH_FOR_LINES: {
|
|
float line_width = SceneGetDynamicLineWidth(
|
|
I->info, SettingGet_f(I->G, nullptr, nullptr, cSetting_line_width));
|
|
if (I->info && I->info->width_scale_flag) {
|
|
line_width *= I->info->width_scale;
|
|
}
|
|
glLineWidthAndUniform(line_width, shaderPrg);
|
|
} break;
|
|
case SET_LABEL_SCALE_UNIFORMS: {
|
|
if (I->rep) {
|
|
float label_size;
|
|
CSetting *set1 = nullptr, *set2 = nullptr;
|
|
if (I->rep->cs)
|
|
set1 = I->rep->cs->Setting.get();
|
|
if (I->rep->obj)
|
|
set2 = I->rep->obj->Setting.get();
|
|
label_size = SettingGet_f(I->G, set1, set2, cSetting_label_size);
|
|
shaderPrg->Set1f("scaleByVertexScale", label_size < 0.f ? 1.f : 0.f);
|
|
if (label_size < 0.f) {
|
|
shaderPrg->Set1f("labelTextureSize",
|
|
(float) -2.f * I->info->texture_font_size / label_size);
|
|
}
|
|
}
|
|
|
|
} break;
|
|
default:
|
|
PRINTFB(I->G, FB_CGO, FB_Warnings)
|
|
" CGO_gl_special(): bad mode=%d\n", mode ENDFB(I->G);
|
|
}
|
|
}
|
|
|
|
/* CGO_gl_special_with_arg - this is the implementation function for
|
|
CGOSpecialWithArg/CGO_SPECIAL_WITH_ARG. Each op has its own implementation.
|
|
*/
|
|
static void CGO_gl_special_with_arg(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
#ifndef PURE_OPENGL_ES_2
|
|
int mode = CGO_get_int(*pc);
|
|
float argval = *((*pc) + 1);
|
|
bool use_shaders = SettingGetGlobal_b(I->G, cSetting_use_shaders);
|
|
bool sphere_use_shaders =
|
|
use_shaders && SettingGetGlobal_b(I->G, cSetting_use_shaders);
|
|
switch (mode) {
|
|
case LINEWIDTH_FOR_LINES: {
|
|
if (!use_shaders) {
|
|
glEnd();
|
|
glLineWidth(argval);
|
|
glBegin(GL_LINES);
|
|
}
|
|
} break;
|
|
case LINE_LIGHTING:
|
|
if (!I->isPicking && !SettingGetGlobal_b(I->G, cSetting_use_shaders)) {
|
|
if (!I->info->line_lighting) {
|
|
bool enableLighting = (int) argval;
|
|
if (enableLighting)
|
|
glEnable(GL_LIGHTING);
|
|
else
|
|
glDisable(GL_LIGHTING);
|
|
}
|
|
}
|
|
break;
|
|
case SPHERE_MODE_OPS: {
|
|
float pixel_scale = 1.0F / I->info->vertex_scale;
|
|
int sphere_mode = (int) fabs(argval);
|
|
bool enable = argval > 0.f;
|
|
if (enable) {
|
|
float pointSize;
|
|
if ((sphere_mode == 1) || (sphere_mode == 6)) {
|
|
pointSize =
|
|
SettingGet_f(I->G, I->set1, I->set2, cSetting_sphere_point_size);
|
|
glDisable(GL_POINT_SMOOTH);
|
|
glDisable(GL_ALPHA_TEST);
|
|
if (!I->isPicking && !sphere_use_shaders) {
|
|
glEnable(GL_LIGHTING);
|
|
glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
|
|
}
|
|
} else {
|
|
float sphere_scale =
|
|
SettingGet_f(I->G, I->set1, I->set2, cSetting_sphere_scale);
|
|
if ((sphere_mode == 3) || (sphere_mode == 8)) {
|
|
glEnable(GL_POINT_SMOOTH);
|
|
glAlphaFunc(GL_GREATER, 0.5F);
|
|
glEnable(GL_ALPHA_TEST);
|
|
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
|
|
pointSize = sphere_scale * pixel_scale * 2.0F;
|
|
} else {
|
|
glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
|
|
glDisable(GL_POINT_SMOOTH);
|
|
glDisable(GL_ALPHA_TEST);
|
|
pointSize = sphere_scale * pixel_scale * 1.4F;
|
|
}
|
|
}
|
|
if (!I->isPicking && ((sphere_mode == 7) || (sphere_mode == 8)))
|
|
glEnable(GL_LIGHTING);
|
|
glPointSize(pointSize);
|
|
} else {
|
|
if (sphere_mode == 3) {
|
|
glDisable(GL_POINT_SMOOTH);
|
|
glAlphaFunc(GL_GREATER, 0.05F);
|
|
} else {
|
|
glEnable(GL_ALPHA_TEST);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void CGO_gl_dotwidth(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
#ifndef PURE_OPENGL_ES_2
|
|
glPointSize(**pc);
|
|
#endif
|
|
}
|
|
|
|
static void CGO_gl_enable(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
GLenum mode = CGO_get_int(*pc);
|
|
CShaderMgr* shaderMgr = I->G->ShaderMgr;
|
|
CShaderPrg* shaderPrg = shaderMgr->Get_Current_Shader();
|
|
if (I->use_shader) {
|
|
if (true) {
|
|
switch (mode) {
|
|
case CGO_GL_LIGHTING: {
|
|
if (shaderPrg) {
|
|
shaderPrg->SetLightingEnabled(1);
|
|
}
|
|
} break;
|
|
case GL_SHADER_LIGHTING:
|
|
if (!I->isPicking) {
|
|
if (shaderPrg) {
|
|
shaderPrg->SetLightingEnabled(1);
|
|
}
|
|
}
|
|
break;
|
|
case GL_TWO_SIDED_LIGHTING: {
|
|
if (shaderPrg) {
|
|
shaderPrg->Set1i("two_sided_lighting_enabled", 1);
|
|
}
|
|
} break;
|
|
case GL_MESH_LIGHTING: {
|
|
int lighting =
|
|
SettingGet_i(I->G, I->set1, I->set2, cSetting_mesh_lighting);
|
|
if (shaderPrg) {
|
|
shaderPrg->SetLightingEnabled(lighting);
|
|
}
|
|
} break;
|
|
case GL_DOT_LIGHTING: {
|
|
int lighting =
|
|
SettingGet_i(I->G, I->set1, I->set2, cSetting_dot_lighting);
|
|
if (shaderPrg && !I->isPicking) {
|
|
shaderPrg->SetLightingEnabled(lighting);
|
|
shaderPrg->Set1i("two_sided_lighting_enabled", 0);
|
|
}
|
|
} break;
|
|
case GL_LABEL_FLOAT_TEXT: {
|
|
int float_text =
|
|
SettingGet_i(I->G, I->set1, I->set2, cSetting_float_labels);
|
|
if (float_text) {
|
|
glDisable(GL_DEPTH_TEST);
|
|
}
|
|
} break;
|
|
case GL_DASH_TRANSPARENCY_DEPTH_TEST: {
|
|
float dash_transparency =
|
|
SettingGet_f(I->G, I->set1, I->set2, cSetting_dash_transparency);
|
|
short dash_transparency_enabled;
|
|
bool t_mode_3 = SettingGet_i(I->G, I->set1, I->set2,
|
|
cSetting_transparency_mode) == 3;
|
|
dash_transparency =
|
|
(dash_transparency < 0.f
|
|
? 0.f
|
|
: (dash_transparency > 1.f ? 1.f : dash_transparency));
|
|
dash_transparency_enabled = (dash_transparency > 0.f);
|
|
if (dash_transparency_enabled && !t_mode_3 && !I->isPicking) {
|
|
glDisable(GL_DEPTH_TEST);
|
|
}
|
|
} break;
|
|
case GL_DEFAULT_SHADER:
|
|
shaderMgr->Enable_DefaultShader(
|
|
I->info ? I->info->pass : RenderPass::Antialias);
|
|
break;
|
|
case GL_LINE_SHADER:
|
|
shaderMgr->Enable_LineShader(
|
|
I->info ? I->info->pass : RenderPass::Antialias);
|
|
break;
|
|
case GL_SURFACE_SHADER:
|
|
shaderMgr->Enable_SurfaceShader(
|
|
I->info ? I->info->pass : RenderPass::Antialias);
|
|
break;
|
|
case GL_CYLINDER_SHADER:
|
|
shaderMgr->Enable_CylinderShader(
|
|
I->info ? I->info->pass : RenderPass::Antialias);
|
|
break;
|
|
case GL_SPHERE_SHADER:
|
|
shaderMgr->Enable_DefaultSphereShader(
|
|
I->info ? I->info->pass : RenderPass::Antialias);
|
|
break;
|
|
case GL_RAMP_SHADER:
|
|
shaderMgr->Enable_RampShader();
|
|
break;
|
|
case GL_DEFAULT_SHADER_WITH_SETTINGS:
|
|
shaderMgr->Enable_DefaultShaderWithSettings(
|
|
I->set1, I->set2, I->info ? I->info->pass : RenderPass::Antialias);
|
|
break;
|
|
case GL_BACKGROUND_SHADER:
|
|
shaderMgr->Enable_BackgroundShader();
|
|
break;
|
|
case GL_LABEL_SHADER:
|
|
shaderMgr->Enable_LabelShader(
|
|
I->info ? I->info->pass : RenderPass::Antialias);
|
|
break;
|
|
case GL_CONNECTOR_SHADER:
|
|
shaderMgr->Enable_ConnectorShader(
|
|
I->info ? I->info->pass : RenderPass::Antialias);
|
|
break;
|
|
case GL_SCREEN_SHADER:
|
|
shaderMgr->Enable_ScreenShader();
|
|
break;
|
|
case GL_TRILINES_SHADER:
|
|
shaderMgr->Enable_TriLinesShader();
|
|
break;
|
|
#ifndef _PYMOL_NO_AA_SHADERS
|
|
case GL_FXAA_SHADER:
|
|
shaderMgr->Enable_FXAAShader();
|
|
break;
|
|
case GL_SMAA1_SHADER:
|
|
shaderMgr->Enable_SMAA1Shader();
|
|
break;
|
|
case GL_SMAA2_SHADER:
|
|
shaderMgr->Enable_SMAA2Shader();
|
|
break;
|
|
case GL_SMAA3_SHADER:
|
|
shaderMgr->Enable_SMAA3Shader();
|
|
break;
|
|
#endif
|
|
case GL_OIT_SHADER:
|
|
shaderMgr->Enable_OITShader();
|
|
break;
|
|
case GL_OIT_COPY_SHADER:
|
|
shaderMgr->Enable_OITCopyShader();
|
|
break;
|
|
case GL_BACK_FACE_CULLING:
|
|
glCullFace(GL_BACK);
|
|
glEnable(GL_CULL_FACE);
|
|
break;
|
|
case GL_DEPTH_TEST:
|
|
glEnable(mode);
|
|
break;
|
|
case GL_DEPTH_TEST_IF_FLOATING: {
|
|
int float_text =
|
|
SettingGet_i(I->G, I->set1, I->set2, cSetting_float_labels);
|
|
if (float_text)
|
|
glEnable(GL_DEPTH_TEST);
|
|
} break;
|
|
case GL_BEZIER_SHADER:
|
|
shaderMgr->Enable_BezierShader();
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
#ifndef PURE_OPENGL_ES_2
|
|
if (!I->isPicking) {
|
|
if (mode == CGO_GL_LIGHTING) {
|
|
glEnable(GL_LIGHTING);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void CGO_gl_disable(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
GLenum mode = CGO_get_int(*pc);
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
if (I->use_shader) {
|
|
switch (mode) {
|
|
case GL_SHADER_LIGHTING: {
|
|
if (shaderPrg) {
|
|
shaderPrg->SetLightingEnabled(0);
|
|
}
|
|
} break;
|
|
case GL_CYLINDER_SHADER:
|
|
glDisable(GL_CULL_FACE);
|
|
case GL_RAMP_SHADER:
|
|
case GL_SCREEN_SHADER:
|
|
case GL_LABEL_SHADER:
|
|
case GL_CONNECTOR_SHADER:
|
|
case GL_DEFAULT_SHADER:
|
|
case GL_SURFACE_SHADER:
|
|
case GL_SPHERE_SHADER:
|
|
case GL_TRILINES_SHADER:
|
|
case GL_OIT_COPY_SHADER:
|
|
case GL_LINE_SHADER:
|
|
I->G->ShaderMgr->Disable_Current_Shader();
|
|
break;
|
|
case GL_LABEL_FLOAT_TEXT: {
|
|
int float_text =
|
|
SettingGet_i(I->G, I->set1, I->set2, cSetting_float_labels);
|
|
if (float_text) {
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
} break;
|
|
case GL_DASH_TRANSPARENCY_DEPTH_TEST: {
|
|
float dash_transparency =
|
|
SettingGet_f(I->G, I->set1, I->set2, cSetting_dash_transparency);
|
|
short dash_transparency_enabled;
|
|
bool t_mode_3 =
|
|
SettingGet_i(I->G, I->set1, I->set2, cSetting_transparency_mode) == 3;
|
|
dash_transparency =
|
|
(dash_transparency < 0.f
|
|
? 0.f
|
|
: (dash_transparency > 1.f ? 1.f : dash_transparency));
|
|
dash_transparency_enabled = (dash_transparency > 0.f);
|
|
if (dash_transparency_enabled && !t_mode_3 && !I->isPicking) {
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
} break;
|
|
case CGO_GL_LIGHTING: {
|
|
if (shaderPrg) {
|
|
shaderPrg->SetLightingEnabled(0);
|
|
}
|
|
} break;
|
|
case GL_TWO_SIDED_LIGHTING: {
|
|
if (shaderPrg) {
|
|
shaderPrg->Set1i("two_sided_lighting_enabled", 0);
|
|
}
|
|
} break;
|
|
#if !defined(PURE_OPENGL_ES_2) || defined(_WEBGL)
|
|
case GL_OIT_SHADER:
|
|
case GL_SMAA1_SHADER:
|
|
case GL_SMAA2_SHADER:
|
|
I->G->ShaderMgr->setDrawBuffer(I->G->ShaderMgr->topLevelConfig);
|
|
break;
|
|
#endif
|
|
case GL_BACK_FACE_CULLING:
|
|
glDisable(GL_CULL_FACE);
|
|
break;
|
|
case GL_DEPTH_TEST:
|
|
glDisable(mode);
|
|
break;
|
|
case GL_DEPTH_TEST_IF_FLOATING: {
|
|
int float_text =
|
|
SettingGet_i(I->G, I->set1, I->set2, cSetting_float_labels);
|
|
if (float_text)
|
|
glDisable(GL_DEPTH_TEST);
|
|
} break;
|
|
}
|
|
#ifndef PURE_OPENGL_ES_2
|
|
} else {
|
|
if (mode != CGO_GL_LIGHTING || !I->isPicking) {
|
|
if (mode == CGO_GL_LIGHTING)
|
|
mode = GL_LIGHTING;
|
|
glDisable(mode);
|
|
}
|
|
}
|
|
#else
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void CGO_gl_alpha(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
I->alpha = **pc;
|
|
}
|
|
|
|
static void CGO_gl_reset_normal(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
SceneResetNormalUseShader(I->G, CGO_get_int(*pc), I->use_shader);
|
|
}
|
|
|
|
static void CGO_gl_null(CCGORenderer* I, CGO_op_data pc) {}
|
|
|
|
static void CGO_gl_error(CCGORenderer* I, CGO_op_data pc)
|
|
{
|
|
PRINTFB(I->G, FB_CGO, FB_Warnings)
|
|
" CGO_gl_error() is not suppose to be called op=%d\n",
|
|
CGO_get_int((*pc) - 1) ENDFB(I->G);
|
|
}
|
|
|
|
static void CGO_gl_color(CCGORenderer* I, CGO_op_data varg)
|
|
{
|
|
auto* v = *varg;
|
|
if (I->use_shader) {
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
if (shaderPrg) {
|
|
int attr_a_Color = shaderPrg->GetAttribLocation("a_Color");
|
|
glVertexAttrib4f(attr_a_Color, v[0], v[1], v[2], I->alpha);
|
|
}
|
|
} else {
|
|
#ifndef PURE_OPENGL_ES_2
|
|
glColor4f(v[0], v[1], v[2], I->alpha);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void CGO_gl_sphere(CCGORenderer* I, CGO_op_data varg)
|
|
{
|
|
auto* v = *varg;
|
|
if (I->isPicking) {
|
|
SphereRender(I->G, 0, v, I->color, I->alpha, v[3]);
|
|
} else {
|
|
SphereRender(I->G, I->sphere_quality, v, nullptr, I->alpha, v[3]);
|
|
}
|
|
}
|
|
|
|
static void CGO_gl_vertex_attribute_3f(CCGORenderer* I, CGO_op_data varg)
|
|
{
|
|
auto vertex_attr =
|
|
reinterpret_cast<const cgo::draw::vertex_attribute_3f*>(*varg);
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
int loc = shaderPrg->GetAttribLocation(
|
|
I->G->ShaderMgr->GetAttributeName(vertex_attr->attr_lookup_idx));
|
|
if (loc >= 0)
|
|
glVertexAttrib3fv(loc, vertex_attr->values);
|
|
}
|
|
|
|
static void CGO_gl_vertex_attribute_4ub(CCGORenderer* I, CGO_op_data varg)
|
|
{
|
|
auto vertex_attr =
|
|
reinterpret_cast<const cgo::draw::vertex_attribute_4ub*>(*varg);
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
int loc = shaderPrg->GetAttribLocation(
|
|
I->G->ShaderMgr->GetAttributeName(vertex_attr->attr_lookup_idx));
|
|
if (loc >= 0)
|
|
glVertexAttrib4ubv(loc, vertex_attr->ubdata);
|
|
}
|
|
|
|
static void CGO_gl_vertex_attribute_4ub_if_picking(
|
|
CCGORenderer* I, CGO_op_data varg)
|
|
{
|
|
if (I->isPicking) {
|
|
auto vertex_attr =
|
|
reinterpret_cast<const cgo::draw::vertex_attribute_4ub_if_picking*>(
|
|
*varg);
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
int loc = shaderPrg->GetAttribLocation(
|
|
I->G->ShaderMgr->GetAttributeName(vertex_attr->attr_lookup_idx));
|
|
if (loc >= 0)
|
|
glVertexAttrib4ubv(loc, vertex_attr->ubdata);
|
|
}
|
|
}
|
|
|
|
static void CGO_gl_vertex_attribute_1f(CCGORenderer* I, CGO_op_data varg)
|
|
{
|
|
auto vertex_attr =
|
|
reinterpret_cast<const cgo::draw::vertex_attribute_1f*>(*varg);
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
const char* name =
|
|
I->G->ShaderMgr->GetAttributeName(vertex_attr->attr_lookup_idx);
|
|
int loc = shaderPrg->GetAttribLocation(name);
|
|
if (loc >= 0)
|
|
glVertexAttrib1f(loc, vertex_attr->value);
|
|
}
|
|
|
|
/* dispatch table for OpenGL */
|
|
|
|
CGO_op_fn CGO_gl[] = {CGO_gl_null, /* 0x00 */
|
|
CGO_gl_null, /* 0x01 */
|
|
CGO_gl_begin, /* 0x02 */
|
|
CGO_gl_end, /* 0x03 */
|
|
CGO_gl_vertex, /* 0x04 */
|
|
CGO_gl_normal, /* 0x05 */
|
|
CGO_gl_color, /* 0x06 */
|
|
CGO_gl_sphere, /* 0x07 */
|
|
CGO_gl_null, /* 0x08 */
|
|
CGO_gl_null, /* 0x09 */
|
|
|
|
CGO_gl_linewidth, /* 0x0A */
|
|
CGO_gl_null, /* 0x0B */
|
|
CGO_gl_enable, /* 0x0C */
|
|
CGO_gl_disable, /* 0x0D */
|
|
CGO_gl_null, /* 0x0E */
|
|
CGO_gl_null, /* 0x0F */
|
|
|
|
CGO_gl_dotwidth, /* 0X10 */
|
|
CGO_gl_null, /* 0x11 */
|
|
CGO_gl_null, /* 0x12 */
|
|
CGO_gl_null, /* 0X13 */
|
|
|
|
CGO_gl_null, /* 0X14 */
|
|
CGO_gl_null, /* 0x15 */
|
|
CGO_gl_null, /* 0x16 */
|
|
CGO_gl_null, /* 0X17 */
|
|
|
|
CGO_gl_null, /* 0X18 */
|
|
CGO_gl_alpha, /* 0x19 */
|
|
CGO_gl_null, /* 0x1A */
|
|
CGO_gl_null, /* 0X1B */
|
|
CGO_gl_draw_arrays, /* 0x1C DrawArrays() */
|
|
CGO_gl_null, /* 0x1D */
|
|
CGO_gl_reset_normal, /* 0x1E */
|
|
CGO_gl_null, /* pick color 0X1F */
|
|
CGO_gl_null, /* 0x20 draw buffers REMOVED */
|
|
CGO_gl_draw_buffers_indexed, /* 0x21 draw buffers indexed */
|
|
CGO_gl_null, /* 0x22 bounding box */
|
|
CGO_gl_draw_buffers_not_indexed, /* 0x23 draw buffers not indexed */
|
|
CGO_gl_special, /* 0x24 special */
|
|
CGO_gl_draw_cylinder_buffers, /* 0x25 draw GLSL cylinders */
|
|
CGO_gl_null, /* 0x26 shader cylinder */
|
|
CGO_gl_null, /* 0x27 shader cylinder with 2nd color */
|
|
CGO_gl_draw_sphere_buffers, /* 0x28 draw sphere buffers */
|
|
CGO_gl_null, /* 0x29 accessibility used for ambient occlusion */
|
|
CGO_gl_error, /* 0x2A draw texture */
|
|
CGO_gl_draw_textures, /* 0x2B draw textures */
|
|
CGO_gl_draw_screen_textures_and_polygons, /* 0x2C draw screen textures and
|
|
polygons */
|
|
CGO_gl_error, CGO_gl_error, CGO_gl_draw_labels, CGO_gl_error,
|
|
CGO_gl_draw_connectors, CGO_gl_draw_trilines, CGO_gl_uniform3f,
|
|
CGO_gl_special_with_arg, CGO_gl_line, CGO_gl_splitline, CGO_gl_draw_custom,
|
|
CGO_gl_vertex_attribute_3f, CGO_gl_vertex_attribute_4ub,
|
|
CGO_gl_vertex_attribute_1f, CGO_gl_mask_attribute_if_picking,
|
|
CGO_gl_bind_vbo_for_picking, CGO_gl_vertex,
|
|
CGO_gl_null, // interpolated
|
|
CGO_gl_vertex_cross, // CGO_VERTEX_CROSS
|
|
CGO_gl_vertex_attribute_4ub_if_picking,
|
|
CGO_gl_null, // custom cylinder alpha
|
|
CGO_gl_null, // bezier
|
|
CGO_gl_draw_bezier_buffers,
|
|
CGO_gl_error};
|
|
|
|
#if 0
|
|
static
|
|
void SetUCColorToPrev(uchar *color){
|
|
color[0] = color[-4];
|
|
color[1] = color[-3];
|
|
color[2] = color[-2];
|
|
color[3] = color[-1];
|
|
}
|
|
|
|
static
|
|
void SetUCColorToPrev8(uchar *color){
|
|
color[0] = color[-8];
|
|
color[1] = color[-7];
|
|
color[2] = color[-6];
|
|
color[3] = color[-5];
|
|
}
|
|
#endif
|
|
|
|
static void SetUCColorToPrevN(int n, uchar* color)
|
|
{
|
|
color[0] = color[-n * 4];
|
|
color[1] = color[-n * 4 + 1];
|
|
color[2] = color[-n * 4 + 2];
|
|
color[3] = color[-n * 4 + 3];
|
|
}
|
|
|
|
static int* get_pickcolorsset_ptr(int op, float* pc)
|
|
{
|
|
#define RETURN_PICKCOLORSETPTR_CASE(cls) \
|
|
case cgo::draw::cls::op_code: \
|
|
return &(reinterpret_cast<cgo::draw::cls*>(pc)->pickcolorsset)
|
|
switch (op) {
|
|
RETURN_PICKCOLORSETPTR_CASE(buffers_indexed);
|
|
RETURN_PICKCOLORSETPTR_CASE(buffers_not_indexed);
|
|
RETURN_PICKCOLORSETPTR_CASE(labels);
|
|
RETURN_PICKCOLORSETPTR_CASE(sphere_buffers);
|
|
RETURN_PICKCOLORSETPTR_CASE(cylinder_buffers);
|
|
RETURN_PICKCOLORSETPTR_CASE(custom);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void CGORenderGLPicking(CGO* I, RenderInfo* info, PickContext* context,
|
|
CSetting* set1, CSetting* set2, Rep* rep)
|
|
{
|
|
PyMOLGlobals* G = I->G;
|
|
|
|
if (!G->ValidContext)
|
|
return;
|
|
|
|
if (!I->c)
|
|
return;
|
|
|
|
CCGORenderer* R = G->CGORenderer;
|
|
bool pickable =
|
|
(!I->no_pick) && SettingGet_b(G, set1, set2, cSetting_pickable);
|
|
auto pick = info->pick;
|
|
bool reset_colors = !pick->pickColorsValid();
|
|
|
|
R->use_shader = I->use_shader;
|
|
R->isPicking = true;
|
|
R->set1 = set1;
|
|
R->set2 = set2;
|
|
R->info = info;
|
|
R->rep = rep;
|
|
|
|
#ifndef _WEBGL
|
|
glLineWidth(SettingGet_f(G, set1, set2, cSetting_cgo_line_width));
|
|
#endif
|
|
|
|
for (auto it = I->begin(); !it.is_stop(); ++it) {
|
|
const auto op = it.op_code();
|
|
CGO_OP_DATA_CONST float* pc = it.data();
|
|
|
|
switch (op) {
|
|
case CGO_COLOR:
|
|
continue;
|
|
|
|
case CGO_PICK_COLOR:
|
|
|
|
if (reset_colors) { // only if picking info is invalid
|
|
unsigned char col[4];
|
|
AssignNewPickColor(I, pick, col, context, CGO_get_uint(pc),
|
|
pickable ? CGO_get_int(pc + 1) : cPickableNoPick);
|
|
#ifndef PURE_OPENGL_ES_2
|
|
if (!I->use_shader) {
|
|
glColor4ubv(col);
|
|
}
|
|
#endif
|
|
} else {
|
|
PRINTFB(G, FB_CGO, FB_Warnings)
|
|
" %s: unexpected CGO_PICK_COLOR with !reset_colors\n",
|
|
__func__ ENDFB(G);
|
|
}
|
|
continue;
|
|
|
|
case CGO_DRAW_ARRAYS: {
|
|
const cgo::draw::arrays* sp = reinterpret_cast<decltype(sp)>(pc);
|
|
int arrays = sp->arraybits;
|
|
if (reset_colors &&
|
|
arrays & CGO_PICK_COLOR_ARRAY) { // only if picking info is invalid
|
|
int nverts = sp->nverts, v, idx = -1, bnd = -1;
|
|
float* pca = sp->floatdata;
|
|
|
|
if (arrays & CGO_VERTEX_ARRAY) {
|
|
pca += nverts * VERTEX_POS_SIZE;
|
|
}
|
|
if (arrays & CGO_NORMAL_ARRAY) {
|
|
pca += nverts * VERTEX_NORMAL_SIZE;
|
|
}
|
|
if (arrays & CGO_COLOR_ARRAY) {
|
|
pca += nverts * VERTEX_COLOR_SIZE;
|
|
}
|
|
|
|
auto pickColorValsUC = (uchar*) pca;
|
|
auto pickColorVals = (int*) (pca + nverts * VERTEX_PICKCOLOR_RGBA_SIZE);
|
|
|
|
for (v = 0; v < nverts; v++) {
|
|
bnd = pickable ? pickColorVals[v * 2 + 1] : cPickableNoPick;
|
|
idx = pickColorVals[v * 2];
|
|
AssignNewPickColor(
|
|
I, pick, pickColorValsUC + (v * 4), context, idx, bnd);
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case CGO_DRAW_BUFFERS_INDEXED:
|
|
case CGO_DRAW_BUFFERS_NOT_INDEXED:
|
|
case CGO_DRAW_TEXTURES:
|
|
case CGO_DRAW_LABELS:
|
|
case CGO_DRAW_SPHERE_BUFFERS:
|
|
case CGO_DRAW_CYLINDER_BUFFERS:
|
|
case CGO_DRAW_CUSTOM: {
|
|
int pickcolors_are_set = true;
|
|
int* pickcolors_are_set_ptr =
|
|
get_pickcolorsset_ptr(op, const_cast<float*>(pc));
|
|
if (!pickcolors_are_set_ptr)
|
|
pickcolors_are_set_ptr = &pickcolors_are_set;
|
|
|
|
// TODO remove `pickcolorsset` fields from CGOs
|
|
// This assert can fail during "Roving Detail" demo. However, I still
|
|
// question the need of the `pickcolorsset` fields.
|
|
// assert(reset_colors || *pickcolors_are_set_ptr);
|
|
|
|
if (reset_colors ||
|
|
!*pickcolors_are_set_ptr) { // only if picking info is invalid
|
|
int nverts = 0;
|
|
int nvertsperfrag = 1;
|
|
int v, pl;
|
|
int bnd = cPickableNoPick;
|
|
unsigned int idx = 0;
|
|
int srcp;
|
|
float* pca = nullptr;
|
|
int* pickDataSrc;
|
|
uchar* pickColorDestUC = nullptr;
|
|
bool free_pick_color_dest = false;
|
|
int destOffset = 0, bufsizemult = 1;
|
|
size_t pickvbo = 0;
|
|
switch (op) {
|
|
case CGO_DRAW_CUSTOM: {
|
|
const cgo::draw::custom* sp = reinterpret_cast<decltype(sp)>(pc);
|
|
nverts = sp->nverts;
|
|
pickvbo = sp->pickvboid;
|
|
if (!pickvbo)
|
|
continue;
|
|
pca = sp->floatdata;
|
|
nvertsperfrag = sp->vertsperpickinfo;
|
|
bufsizemult = sp->npickbufs;
|
|
|
|
pickColorDestUC = new uchar[bufsizemult * nverts * 4];
|
|
} break;
|
|
case CGO_DRAW_BUFFERS_INDEXED: {
|
|
const cgo::draw::buffers_indexed* sp =
|
|
reinterpret_cast<decltype(sp)>(pc);
|
|
nverts = sp->nverts;
|
|
pickvbo = sp->pickvboid;
|
|
pca = sp->floatdata;
|
|
} break;
|
|
case CGO_DRAW_BUFFERS_NOT_INDEXED: {
|
|
const cgo::draw::buffers_not_indexed* sp =
|
|
reinterpret_cast<decltype(sp)>(pc);
|
|
nverts = sp->nverts;
|
|
pickvbo = sp->pickvboid;
|
|
pca = sp->floatdata;
|
|
} break;
|
|
case CGO_DRAW_SPHERE_BUFFERS: {
|
|
const cgo::draw::sphere_buffers* sp =
|
|
reinterpret_cast<decltype(sp)>(pc);
|
|
nverts = sp->num_spheres * VerticesPerSphere();
|
|
nvertsperfrag = VerticesPerSphere();
|
|
pickvbo = sp->pickvboid;
|
|
pca = sp->floatdata;
|
|
|
|
pickColorDestUC = new uchar[nverts * 4];
|
|
} break;
|
|
case CGO_DRAW_CYLINDER_BUFFERS: {
|
|
const cgo::draw::cylinder_buffers* sp =
|
|
reinterpret_cast<decltype(sp)>(pc);
|
|
nverts = sp->num_cyl * NumVerticesPerCylinder();
|
|
nvertsperfrag = NumVerticesPerCylinder();
|
|
pickvbo = sp->pickvboid;
|
|
pca = sp->floatdata;
|
|
bufsizemult = 2;
|
|
|
|
pickColorDestUC = new uchar[bufsizemult * nverts * 4];
|
|
} break;
|
|
case CGO_DRAW_TEXTURES: {
|
|
const cgo::draw::textures* sp = reinterpret_cast<decltype(sp)>(pc);
|
|
nverts = sp->ntextures * 6;
|
|
pca = sp->floatdata;
|
|
} break;
|
|
case CGO_DRAW_LABELS: {
|
|
const cgo::draw::labels* sp;
|
|
sp = reinterpret_cast<decltype(sp)>(pc);
|
|
nverts = sp->ntextures * 6;
|
|
pca = sp->floatdata;
|
|
pickvbo = sp->pickvboid;
|
|
} break;
|
|
}
|
|
|
|
if (pickColorDestUC) {
|
|
free_pick_color_dest = true;
|
|
pickDataSrc = (int*) (pca);
|
|
} else {
|
|
pickColorDestUC = (uchar*) pca;
|
|
pickDataSrc = (int*) (pca + nverts);
|
|
}
|
|
|
|
destOffset = R->pick_pass() * sizeof(float) * nverts * bufsizemult;
|
|
|
|
if (!pickable) {
|
|
for (int i = 0; i < nverts * bufsizemult; ++i) {
|
|
pick->colorNoPick(pickColorDestUC + 4 * i);
|
|
}
|
|
} else {
|
|
int npickbufs = bufsizemult;
|
|
int ploffsetforbuf = 0;
|
|
if (op == CGO_DRAW_CYLINDER_BUFFERS) {
|
|
// disabled 2016-07-19 TH: code looks almost identical to
|
|
// else branch and CGO_DRAW_CYLINDER_BUFFERS seem to be
|
|
// not used anymore.
|
|
PRINTFB(I->G, FB_CGO, FB_Errors)
|
|
" FIXME: SUPPOSEDLY UNUSED CODE EXECUTED in "
|
|
"CGORenderPicking(!\n" ENDFB(I->G);
|
|
} else {
|
|
if (op == CGO_DRAW_CUSTOM) {
|
|
ploffsetforbuf =
|
|
sizeof(float) * nverts; // for multiple picking attributes
|
|
}
|
|
for (v = 0, pl = 0; v < nverts; v++, pl += 4) {
|
|
if (v % nvertsperfrag) {
|
|
// if same fragment, same color
|
|
for (int pi = 0; pi < npickbufs; ++pi) {
|
|
int ploffset = ploffsetforbuf * pi;
|
|
SetUCColorToPrevN(1, &pickColorDestUC[pl + ploffset]);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
int frag = (int) (v / nvertsperfrag);
|
|
for (int pi = 0; pi < npickbufs; ++pi) {
|
|
int ploffset = ploffsetforbuf * pi;
|
|
srcp = 2 * ((npickbufs * frag) + pi);
|
|
idx = pickDataSrc[srcp];
|
|
bnd = pickDataSrc[srcp + 1];
|
|
|
|
AssignNewPickColor(I, pick, &pickColorDestUC[pl + ploffset],
|
|
context, idx, bnd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pickvbo) {
|
|
// reload entire vbo
|
|
auto* vbo =
|
|
I->G->ShaderMgr->getGPUBuffer<VertexBufferGL>(pickvbo);
|
|
auto pickPtrBytes =
|
|
reinterpret_cast<const std::byte*>(pickColorDestUC);
|
|
auto dataSpan =
|
|
pymol::span{pickPtrBytes, sizeof(float) * nverts * bufsizemult};
|
|
vbo->bufferReplaceData(destOffset, dataSpan);
|
|
(*pickcolors_are_set_ptr) = true;
|
|
}
|
|
|
|
if (free_pick_color_dest) {
|
|
delete[] pickColorDestUC;
|
|
pickColorDestUC = nullptr;
|
|
free_pick_color_dest = false;
|
|
}
|
|
}
|
|
} break;
|
|
}
|
|
|
|
CGO_gl[op](R, &pc);
|
|
}
|
|
|
|
R->isPicking = false;
|
|
}
|
|
|
|
void CGORenderGL(CGO* I, const float* color, CSetting* set1, CSetting* set2,
|
|
RenderInfo* info, Rep* rep)
|
|
/* this should be as fast as you can make it...
|
|
|
|
* the ASM loop is about 2X long as raw looped GL calls,
|
|
|
|
* but hopefully superscaler processors won't care */
|
|
{
|
|
PyMOLGlobals* G = I->G;
|
|
|
|
const float zee[] = {0.f, 0.f, 1.f};
|
|
const float color_tmp[] = {1.f, 1.f, 1.f};
|
|
|
|
if (I->render_alpha) {
|
|
// for now, the render_alpha_only flag calls CGOSetZVector/CGORenderGLAlpha
|
|
auto modMatrix = SceneGetModelViewMatrixPtr(G);
|
|
CGOSetZVector(I, modMatrix[2], modMatrix[6], modMatrix[10]);
|
|
CGORenderAlpha(I, info, 1);
|
|
if (I->render_alpha == 1) // right now, render_alpha 1: renders alpha only,
|
|
// 2: renders both alpha and rest
|
|
return;
|
|
}
|
|
|
|
if (!G->ValidContext) {
|
|
return;
|
|
}
|
|
|
|
if (!I->c) {
|
|
return;
|
|
}
|
|
|
|
{
|
|
CCGORenderer* R = G->CGORenderer;
|
|
R->info = info;
|
|
R->use_shader = I->use_shader;
|
|
R->debug = I->debug;
|
|
R->sphere_quality = I->sphere_quality;
|
|
R->rep = rep;
|
|
R->color = color;
|
|
R->alpha = 1.0F - SettingGet_f(G, set1, set2, cSetting_cgo_transparency);
|
|
R->set1 = set1;
|
|
R->set2 = set2;
|
|
// normals should be initialized to the view vector
|
|
// (changed BB 9/14 from SceneResetNormalUseShader(), to
|
|
// CScene->LinesNormal, which was arbitrary, I believe)
|
|
SceneResetNormalToViewVector(I->G, I->use_shader);
|
|
|
|
if (!color) {
|
|
color = color_tmp;
|
|
}
|
|
|
|
{
|
|
auto shaderPrg = I->G->ShaderMgr->Get_Current_Shader();
|
|
if (shaderPrg && I->use_shader) {
|
|
shaderPrg->SetAttrib4fLocation(
|
|
"a_Color", color[0], color[1], color[2], R->alpha);
|
|
}
|
|
#ifndef PURE_OPENGL_ES_2
|
|
else {
|
|
glColor4f(color[0], color[1], color[2], R->alpha);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifndef PURE_OPENGL_ES_2
|
|
const float width_scale =
|
|
(info && info->width_scale_flag) ? info->width_scale : 1.f;
|
|
glLineWidth(
|
|
SettingGet_f(G, set1, set2, cSetting_cgo_line_width) * width_scale);
|
|
glPointSize(
|
|
SettingGet_f(G, set1, set2, cSetting_cgo_dot_width) * width_scale);
|
|
#endif
|
|
|
|
if (!(info && info->alpha_cgo)) {
|
|
// Regular CGO dispatch table rendering
|
|
for (auto it = I->begin(); !it.is_stop(); ++it) {
|
|
const auto op = it.op_code();
|
|
assert(op < CGO_sz_size());
|
|
CGO_OP_DATA_CONST float* const pc = it.data();
|
|
|
|
CGO_gl[op](R, &pc);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* we're sorting transparent triangles globally */
|
|
{
|
|
{
|
|
int mode = -1;
|
|
int vc = 0;
|
|
// triangle normals
|
|
const float *n0 = nullptr, *n1 = nullptr, *n2 = nullptr;
|
|
// triangle vertices
|
|
const float *v0 = nullptr, *v1 = nullptr, *v2 = nullptr;
|
|
// triangle colors
|
|
const float *c0 = color, *c1 = nullptr, *c2 = nullptr;
|
|
|
|
for (auto it = I->begin(); !it.is_stop(); ++it) {
|
|
const auto op = it.op_code();
|
|
assert(op < CGO_sz_size());
|
|
CGO_OP_DATA_CONST float* const pc = it.data();
|
|
|
|
if ((R->alpha != 1.f)) {
|
|
switch (op) { /* transparency */
|
|
case CGO_BEGIN:
|
|
mode = CGO_get_int(pc);
|
|
CGO_gl_begin(R, &pc);
|
|
vc = 0;
|
|
n0 = zee;
|
|
break;
|
|
case CGO_END:
|
|
CGO_gl_end(R, &pc);
|
|
mode = -1;
|
|
break;
|
|
case CGO_NORMAL:
|
|
switch (mode) {
|
|
case GL_TRIANGLES:
|
|
case GL_TRIANGLE_STRIP:
|
|
case GL_TRIANGLE_FAN:
|
|
n0 = pc;
|
|
break;
|
|
default:
|
|
CGO_gl_normal(R, &pc);
|
|
}
|
|
break;
|
|
case CGO_COLOR:
|
|
c0 = pc;
|
|
CGO_gl_color(R, &pc);
|
|
break;
|
|
case CGO_TRIANGLE:
|
|
CGOAlphaTriangle(info->alpha_cgo, pc, pc + 3, pc + 6, pc + 9,
|
|
pc + 12, pc + 15, pc + 18, pc + 21, pc + 24, R->alpha,
|
|
R->alpha, R->alpha, false);
|
|
break;
|
|
case CGO_DRAW_ARRAYS: {
|
|
const cgo::draw::arrays* sp = reinterpret_cast<decltype(sp)>(pc);
|
|
int mode = sp->mode, arrays = sp->arraybits, nverts = sp->nverts;
|
|
float *vertexVals = 0, *nxtVals = 0, *colorVals = 0, *normalVals;
|
|
float *vertexVals_tmp = 0, *colorVals_tmp = 0,
|
|
*normalVals_tmp = 0;
|
|
int step;
|
|
short nxtn = 3;
|
|
nxtVals = vertexVals = vertexVals_tmp = sp->floatdata;
|
|
if (arrays & CGO_NORMAL_ARRAY) {
|
|
nxtVals = normalVals = normalVals_tmp =
|
|
vertexVals + (nxtn * nverts);
|
|
}
|
|
if (arrays & CGO_COLOR_ARRAY) {
|
|
nxtVals = colorVals = colorVals_tmp = nxtVals + (nxtn * nverts);
|
|
nxtn = 4;
|
|
}
|
|
switch (mode) {
|
|
case GL_TRIANGLES: {
|
|
for (step = 0; step < nverts; step += 3) {
|
|
if (colorVals_tmp) {
|
|
c0 = colorVals_tmp;
|
|
c1 = colorVals_tmp + 4;
|
|
c2 = colorVals_tmp + 8;
|
|
} else {
|
|
c1 = c2 = c0;
|
|
}
|
|
if (normalVals_tmp) {
|
|
n0 = normalVals_tmp;
|
|
n1 = normalVals_tmp + 3;
|
|
n2 = normalVals_tmp + 6;
|
|
} else {
|
|
n1 = n2 = n0;
|
|
}
|
|
CGOAlphaTriangle(info->alpha_cgo, vertexVals_tmp,
|
|
vertexVals_tmp + 3, vertexVals_tmp + 6, n0, n1, n2, c0,
|
|
c1, c2, R->alpha, R->alpha, R->alpha, false);
|
|
vertexVals_tmp += 9;
|
|
if (normalVals_tmp) {
|
|
normalVals_tmp += 9;
|
|
}
|
|
if (colorVals_tmp) {
|
|
colorVals_tmp += 12;
|
|
}
|
|
}
|
|
} break;
|
|
case GL_TRIANGLE_STRIP: {
|
|
if (colorVals_tmp) {
|
|
c1 = colorVals_tmp;
|
|
c2 = colorVals_tmp + 4;
|
|
colorVals_tmp += 8;
|
|
} else {
|
|
c1 = c2 = c0;
|
|
}
|
|
if (normalVals_tmp) {
|
|
n1 = normalVals_tmp;
|
|
n2 = normalVals_tmp + 3;
|
|
normalVals_tmp += 6;
|
|
} else {
|
|
n1 = n2 = n0;
|
|
}
|
|
vertexVals_tmp += 6;
|
|
for (step = 2; step < nverts; step++) {
|
|
if (colorVals_tmp) {
|
|
c0 = c1;
|
|
c1 = c2;
|
|
c2 = colorVals_tmp;
|
|
}
|
|
if (normalVals_tmp) {
|
|
n0 = n1;
|
|
n1 = n2;
|
|
n2 = normalVals_tmp;
|
|
}
|
|
CGOAlphaTriangle(info->alpha_cgo, vertexVals_tmp - 6,
|
|
vertexVals_tmp - 3, vertexVals_tmp, n0, n1, n2, c0, c1,
|
|
c2, R->alpha, R->alpha, R->alpha, false);
|
|
vertexVals_tmp += 3;
|
|
if (normalVals_tmp) {
|
|
normalVals_tmp += 3;
|
|
}
|
|
if (colorVals_tmp) {
|
|
colorVals_tmp += 4;
|
|
}
|
|
}
|
|
} break;
|
|
case GL_TRIANGLE_FAN: {
|
|
float* firstVertex = vertexVals_tmp;
|
|
if (colorVals_tmp) {
|
|
c0 = colorVals_tmp;
|
|
c2 = colorVals_tmp + 4;
|
|
colorVals_tmp += 8;
|
|
} else {
|
|
c1 = c2 = c0;
|
|
}
|
|
if (normalVals_tmp) {
|
|
n0 = normalVals_tmp;
|
|
n2 = normalVals_tmp + 3;
|
|
normalVals_tmp += 6;
|
|
}
|
|
vertexVals_tmp += 6;
|
|
for (step = 2; step < nverts; step++) {
|
|
if (colorVals_tmp) {
|
|
c1 = c2;
|
|
c2 = colorVals_tmp;
|
|
}
|
|
if (normalVals_tmp) {
|
|
n1 = n2;
|
|
n2 = normalVals_tmp;
|
|
}
|
|
CGOAlphaTriangle(info->alpha_cgo, firstVertex,
|
|
vertexVals_tmp - 3, vertexVals_tmp, n0, n1, n2, c0, c1,
|
|
c2, R->alpha, R->alpha, R->alpha, false);
|
|
vertexVals_tmp += 3;
|
|
if (normalVals_tmp) {
|
|
normalVals_tmp += 3;
|
|
}
|
|
if (colorVals_tmp) {
|
|
colorVals_tmp += 4;
|
|
}
|
|
}
|
|
} break;
|
|
}
|
|
} break;
|
|
case CGO_VERTEX:
|
|
v0 = pc;
|
|
switch (mode) {
|
|
case GL_TRIANGLES:
|
|
if (3 * ((vc + 1) / 3) == vc + 1) {
|
|
CGOAlphaTriangle(info->alpha_cgo, v0, v1, v2, n0, n1, n2, c0,
|
|
c1, c2, R->alpha, R->alpha, R->alpha, true);
|
|
}
|
|
v2 = v1;
|
|
c2 = c1;
|
|
n2 = n1;
|
|
v1 = v0;
|
|
c1 = c0;
|
|
n1 = n0;
|
|
vc++;
|
|
break;
|
|
case GL_TRIANGLE_STRIP:
|
|
if (vc > 1) {
|
|
CGOAlphaTriangle(info->alpha_cgo, v0, v1, v2, n0, n1, n2, c0,
|
|
c1, c2, R->alpha, R->alpha, R->alpha, !(vc & 0x1));
|
|
}
|
|
v2 = v1;
|
|
c2 = c1;
|
|
n2 = n1;
|
|
v1 = v0;
|
|
c1 = c0;
|
|
n1 = n0;
|
|
vc++;
|
|
break;
|
|
case GL_TRIANGLE_FAN:
|
|
if (vc > 1) {
|
|
CGOAlphaTriangle(info->alpha_cgo, v0, v1, v2, n0, n1, n2, c0,
|
|
c1, c2, R->alpha, R->alpha, R->alpha, false);
|
|
} else if (!vc) {
|
|
n2 = n0;
|
|
v2 = v0;
|
|
c2 = c0;
|
|
}
|
|
v1 = v0;
|
|
c1 = c0;
|
|
n1 = n0;
|
|
vc++;
|
|
break;
|
|
default:
|
|
CGO_gl_vertex(R, &pc);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
CGO_gl[op](R, &pc);
|
|
break;
|
|
}
|
|
} else { /* opaque */
|
|
switch (op) {
|
|
case CGO_COLOR:
|
|
/* Since CGO operations are done in sequence, alpha could happen
|
|
after color is set. In this case, we still need to keep track
|
|
of the color in case there is a transparent object */
|
|
c0 = pc;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
CGO_gl[op](R, &pc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CGORenderGLAlpha(CGO* I, RenderInfo* info, bool calcDepth)
|
|
{
|
|
PyMOLGlobals* G = I->G;
|
|
if (G->ValidContext && I->c) {
|
|
int mode = GL_TRIANGLES;
|
|
if (I->debug) {
|
|
mode = CGOConvertDebugMode(I->debug, GL_TRIANGLES);
|
|
}
|
|
#ifndef PURE_OPENGL_ES_2
|
|
// not sure why shader is set, but disable it for now,
|
|
// since we are doing immediate mode rendering for global transparency
|
|
G->ShaderMgr->Disable_Current_Shader();
|
|
#endif
|
|
/* 1. transform and measure range (if not already known)
|
|
2. bin into linked lists based on Z-centers
|
|
3. render by layer */
|
|
|
|
if (I->z_flag) {
|
|
if (!I->i_start) {
|
|
I->i_size = 256;
|
|
I->i_start = pymol::calloc<int>(I->i_size);
|
|
} else {
|
|
UtilZeroMem(I->i_start, sizeof(int) * I->i_size);
|
|
}
|
|
{
|
|
const int i_size = I->i_size;
|
|
const float* base = I->op;
|
|
int* start = I->i_start;
|
|
int delta = 1, ntris = 0;
|
|
/* bin the triangles */
|
|
if (calcDepth) {
|
|
for (auto it = I->begin(); !it.is_stop(); ++it) {
|
|
if (it.op_code() == CGO_ALPHA_TRIANGLE) {
|
|
float* const pc = it.data();
|
|
const float z = dot_product3f(pc + 1, I->z_vector);
|
|
if (z > I->z_max)
|
|
I->z_max = z;
|
|
if (z < I->z_min)
|
|
I->z_min = z;
|
|
pc[4] = z;
|
|
ntris++;
|
|
}
|
|
}
|
|
}
|
|
|
|
const float range_factor = (0.9999F * i_size) / (I->z_max - I->z_min);
|
|
|
|
for (auto it = I->begin(); !it.is_stop(); ++it) {
|
|
if (it.op_code() == CGO_ALPHA_TRIANGLE) {
|
|
float* const pc = it.data();
|
|
assert(base < pc && pc < I->op + I->c);
|
|
auto i =
|
|
std::clamp<int>((pc[4] - I->z_min) * range_factor, 0, i_size);
|
|
CGO_put_int(pc, start[i]);
|
|
start[i] = (pc - base); /* NOTE: will always be > 0 since we have
|
|
CGO_read_int'd */
|
|
}
|
|
}
|
|
|
|
// for single-layer transparency, render front-to-back
|
|
if (SettingGetGlobal_i(G, cSetting_transparency_mode) == 2) {
|
|
delta = -1;
|
|
start += (i_size - 1);
|
|
}
|
|
|
|
/* now render by bin */
|
|
#ifndef PURE_OPENGL_ES_2
|
|
glBegin(mode);
|
|
for (int i = 0; i < i_size; i++) {
|
|
int ii = *start;
|
|
start += delta;
|
|
while (ii) {
|
|
const float* pc = base + ii;
|
|
glColor4fv(pc + 23);
|
|
glNormal3fv(pc + 14);
|
|
glVertex3fv(pc + 5);
|
|
glColor4fv(pc + 27);
|
|
glNormal3fv(pc + 17);
|
|
glVertex3fv(pc + 8);
|
|
glColor4fv(pc + 31);
|
|
glNormal3fv(pc + 20);
|
|
glVertex3fv(pc + 11);
|
|
|
|
ii = CGO_get_int(pc);
|
|
}
|
|
}
|
|
glEnd();
|
|
#endif
|
|
}
|
|
} else {
|
|
#ifndef PURE_OPENGL_ES_2
|
|
glBegin(mode);
|
|
for (auto it = I->begin(); !it.is_stop(); ++it) {
|
|
if (it.op_code() == CGO_ALPHA_TRIANGLE) {
|
|
float* const pc = it.data();
|
|
glColor4fv(pc + 23);
|
|
glNormal3fv(pc + 14);
|
|
glVertex3fv(pc + 5);
|
|
glColor4fv(pc + 27);
|
|
glNormal3fv(pc + 17);
|
|
glVertex3fv(pc + 8);
|
|
glColor4fv(pc + 31);
|
|
glNormal3fv(pc + 20);
|
|
glVertex3fv(pc + 11);
|
|
}
|
|
}
|
|
glEnd();
|
|
#endif
|
|
}
|
|
}
|
|
}
|