mirror of
https://github.com/schrodinger/pymol-open-source.git
synced 2026-06-03 19:54:24 +08:00
389 lines
10 KiB
C++
389 lines
10 KiB
C++
|
|
/*
|
|
A* -------------------------------------------------------------------
|
|
B* This file contains source code for the PyMOL computer program
|
|
C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific.
|
|
D* -------------------------------------------------------------------
|
|
E* It is unlawful to modify or remove this copyright notice.
|
|
F* -------------------------------------------------------------------
|
|
G* Please see the accompanying LICENSE file for further information.
|
|
H* -------------------------------------------------------------------
|
|
I* Additional authors of this source file include:
|
|
-*
|
|
-*
|
|
-*
|
|
Z* -------------------------------------------------------------------
|
|
*/
|
|
#include "os_python.h"
|
|
|
|
#include "os_predef.h"
|
|
#include "os_std.h"
|
|
|
|
#include "Base.h"
|
|
#include "CGO.h"
|
|
#include "Color.h"
|
|
#include "Err.h"
|
|
#include "GadgetSet.h"
|
|
#include "MemoryDebug.h"
|
|
#include "ObjectGadget.h"
|
|
#include "PConv.h"
|
|
#include "Ray.h"
|
|
#include "Scene.h"
|
|
#include "ShaderMgr.h"
|
|
#include "main.h"
|
|
|
|
int GadgetSetGetVertex(const GadgetSet* I, int index, int base, float* v)
|
|
{
|
|
int ok = true;
|
|
float *v0, *v1;
|
|
if (index < I->NCoord) {
|
|
v0 = I->Coord + 3 * index;
|
|
if (base < 0) {
|
|
copy3f(v0, v);
|
|
if (index) {
|
|
add3f(I->Coord, v, v);
|
|
}
|
|
} else if (base < I->NCoord) {
|
|
v1 = I->Coord + 3 * base;
|
|
add3f(v1, v0, v);
|
|
if (index)
|
|
add3f(I->Coord, v, v);
|
|
} else {
|
|
ok = false;
|
|
}
|
|
} else
|
|
ok = false;
|
|
return (ok);
|
|
}
|
|
|
|
int GadgetSetSetVertex(GadgetSet* I, int index, int base, const float* v)
|
|
{
|
|
int ok = true;
|
|
float *v0, *v1;
|
|
if (index < I->NCoord) {
|
|
v0 = I->Coord + 3 * index;
|
|
if (base < 0) {
|
|
copy3f(v, v0);
|
|
if (index) {
|
|
subtract3f(v0, I->Coord, v0);
|
|
} else {
|
|
if (I->offsetPtOP)
|
|
copy3f(v0, &I->StdCGO->op[I->offsetPtOP]);
|
|
if (I->offsetPtOPick)
|
|
copy3f(v0, &I->PickCGO->op[I->offsetPtOPick]);
|
|
}
|
|
} else if (base < I->NCoord) {
|
|
v1 = I->Coord + 3 * base;
|
|
subtract3f(v, v1, v0);
|
|
if (index)
|
|
subtract3f(v0, I->Coord, v0);
|
|
} else {
|
|
ok = false;
|
|
}
|
|
} else
|
|
ok = false;
|
|
return (ok);
|
|
}
|
|
|
|
int GadgetSetFromPyList(
|
|
PyMOLGlobals* G, PyObject* list, GadgetSet** gs, int version)
|
|
{
|
|
int ok = true;
|
|
GadgetSet* I = nullptr;
|
|
PyObject* tmp = nullptr;
|
|
|
|
if (*gs) {
|
|
delete *gs;
|
|
*gs = nullptr;
|
|
}
|
|
|
|
if (list == Py_None) { /* allow None for GSet */
|
|
*gs = nullptr;
|
|
} else {
|
|
|
|
if (ok)
|
|
I = GadgetSetNew(G);
|
|
if (ok)
|
|
ok = (I != nullptr);
|
|
if (ok)
|
|
ok = (list != nullptr);
|
|
if (ok)
|
|
ok = PyList_Check(list);
|
|
/* TO SUPPORT BACKWARDS COMPATIBILITY...
|
|
Always check ll when adding new PyList_GetItem's */
|
|
|
|
if (ok)
|
|
ok = PConvPyIntToInt(PyList_GetItem(list, 0), &I->NCoord);
|
|
if (ok && I->NCoord)
|
|
ok = PConvPyListToFloatVLA(PyList_GetItem(list, 1), &I->Coord);
|
|
|
|
if (ok)
|
|
ok = PConvPyIntToInt(PyList_GetItem(list, 2), &I->NNormal);
|
|
if (ok && I->NNormal)
|
|
ok = PConvPyListToFloatVLA(PyList_GetItem(list, 3), &I->Normal);
|
|
|
|
if (ok)
|
|
ok = PConvPyIntToInt(PyList_GetItem(list, 4), &I->NColor);
|
|
if (ok && I->NColor)
|
|
ok = PConvPyListToFloatVLA(PyList_GetItem(list, 5), &I->Color);
|
|
|
|
if (ok)
|
|
ok = ((tmp = PyList_GetItem(list, 6)) != nullptr);
|
|
if (ok && (tmp != Py_None))
|
|
ok = ((I->ShapeCGO = CGONewFromPyList(I->G, tmp, version)) != nullptr);
|
|
|
|
if (ok)
|
|
ok = ((tmp = PyList_GetItem(list, 7)) != nullptr);
|
|
if (ok && (tmp != Py_None))
|
|
ok =
|
|
((I->PickShapeCGO = CGONewFromPyList(I->G, tmp, version)) != nullptr);
|
|
|
|
if (ok && I->ShapeCGO)
|
|
if (CGOCheckForText(I->ShapeCGO)) {
|
|
CGOPreloadFonts(I->ShapeCGO);
|
|
}
|
|
|
|
if (!ok) {
|
|
if (I)
|
|
delete I;
|
|
} else {
|
|
*gs = I;
|
|
}
|
|
}
|
|
|
|
return (ok);
|
|
}
|
|
|
|
PyObject* GadgetSetAsPyList(GadgetSet* I, bool incl_cgos)
|
|
{
|
|
PyObject* result = nullptr;
|
|
|
|
if (I) {
|
|
result = PyList_New(8);
|
|
|
|
PyList_SetItem(result, 0, PyInt_FromLong(I->NCoord));
|
|
|
|
if (I->NCoord) {
|
|
PyList_SetItem(
|
|
result, 1, PConvFloatArrayToPyList(I->Coord, I->NCoord * 3));
|
|
} else {
|
|
PyList_SetItem(result, 1, PConvAutoNone(nullptr));
|
|
}
|
|
|
|
PyList_SetItem(result, 2, PyInt_FromLong(I->NNormal));
|
|
|
|
if (I->NNormal) {
|
|
PyList_SetItem(
|
|
result, 3, PConvFloatArrayToPyList(I->Normal, I->NNormal * 3));
|
|
} else {
|
|
PyList_SetItem(result, 3, PConvAutoNone(nullptr));
|
|
}
|
|
|
|
PyList_SetItem(result, 4, PyInt_FromLong(I->NColor));
|
|
|
|
if (I->NColor) {
|
|
PyList_SetItem(result, 5, PConvFloatArrayToPyList(I->Color, I->NColor));
|
|
} else {
|
|
PyList_SetItem(result, 5, PConvAutoNone(nullptr));
|
|
}
|
|
|
|
if (incl_cgos && I->ShapeCGO) {
|
|
PyList_SetItem(result, 6, CGOAsPyList(I->ShapeCGO));
|
|
} else {
|
|
PyList_SetItem(result, 6, PConvAutoNone(nullptr));
|
|
}
|
|
|
|
if (incl_cgos && I->PickShapeCGO) {
|
|
PyList_SetItem(result, 7, CGOAsPyList(I->PickShapeCGO));
|
|
} else {
|
|
PyList_SetItem(result, 7, PConvAutoNone(nullptr));
|
|
}
|
|
}
|
|
return (PConvAutoNone(result));
|
|
}
|
|
|
|
/*========================================================================*/
|
|
int GadgetSetGetExtent(GadgetSet* I, float* mn, float* mx)
|
|
{
|
|
float* v;
|
|
int a;
|
|
v = I->Coord;
|
|
for (a = 0; a < I->NCoord; a++) {
|
|
min3f(v, mn, mn);
|
|
max3f(v, mx, mx);
|
|
v += 3;
|
|
}
|
|
return (I->NCoord);
|
|
}
|
|
|
|
/*========================================================================*/
|
|
void GadgetSet::invalidateRep(cRep_t type, cRepInv_t level) {}
|
|
|
|
/*========================================================================*/
|
|
void GadgetSet::update()
|
|
{
|
|
GadgetSet* I = this;
|
|
if (I->StdCGO) {
|
|
CGOFree(I->StdCGO);
|
|
I->offsetPtOP = 0;
|
|
I->StdCGO = nullptr;
|
|
}
|
|
if (I->PickCGO) {
|
|
CGOFree(I->PickCGO);
|
|
I->offsetPtOPick = 0;
|
|
I->PickCGO = nullptr;
|
|
}
|
|
}
|
|
|
|
/*========================================================================*/
|
|
void GadgetSet::render(RenderInfo* info)
|
|
{
|
|
GadgetSet* I = this;
|
|
const RenderPass pass = info->pass;
|
|
CRay* ray = info->ray;
|
|
auto pick = info->pick;
|
|
const float* color;
|
|
PickContext context;
|
|
|
|
context.object = I->Obj;
|
|
context.state = I->State;
|
|
|
|
color = ColorGet(I->G, I->Obj->Color);
|
|
|
|
if (pass == RenderPass::Transparent || ray || pick) {
|
|
PyMOLGlobals* G = I->G;
|
|
|
|
if (ray) {
|
|
if (I->ShapeCGO) {
|
|
float mat[16] = {1.f, 0.f, 0.f, I->Coord[0], 0.f, 1.f, 0.f, I->Coord[1],
|
|
0.f, 0.f, 1.f, I->Coord[2], 0.f, 0.f, 0.f, 1.f};
|
|
RayPushTTT(ray);
|
|
RaySetTTT(ray, true,
|
|
mat); /* Used to set the ray-tracing matrix,
|
|
this works, but is there another way to do this? */
|
|
CGORenderRay(I->ShapeCGO, ray, info, color, nullptr,
|
|
I->Obj->Setting.get(), nullptr);
|
|
RayPopTTT(ray);
|
|
}
|
|
} else if (G->HaveGUI && G->ValidContext) {
|
|
short use_shader = (short) SettingGetGlobal_b(I->G, cSetting_use_shaders);
|
|
if (pick) {
|
|
if (!I->PickCGO && I->PickShapeCGO) {
|
|
CGO* convertcgo;
|
|
int ok = true;
|
|
convertcgo = CGOCombineBeginEnd(I->PickShapeCGO, 0);
|
|
CHECKOK(ok, convertcgo);
|
|
if (ok) {
|
|
if (use_shader) {
|
|
CGO* tmpCGO;
|
|
tmpCGO = CGOOptimizeToVBOIndexedNoShader(convertcgo, 0);
|
|
I->PickCGO = CGONew(G);
|
|
CGODisable(I->PickCGO, GL_DEPTH_TEST);
|
|
CGOEnable(I->PickCGO, GL_RAMP_SHADER);
|
|
I->offsetPtOPick = CGOUniform3f(
|
|
I->PickCGO, RAMP_OFFSETPT, (const float*) I->Coord);
|
|
CGOAppendNoStop(I->PickCGO, tmpCGO);
|
|
CGOFreeWithoutVBOs(tmpCGO);
|
|
CGODisable(I->PickCGO, GL_RAMP_SHADER);
|
|
CGOEnable(I->PickCGO, GL_DEPTH_TEST);
|
|
CGOStop(I->PickCGO);
|
|
I->PickCGO->use_shader = true;
|
|
CGOFree(convertcgo);
|
|
} else {
|
|
I->PickCGO = convertcgo;
|
|
}
|
|
} else {
|
|
CGOFree(convertcgo);
|
|
}
|
|
}
|
|
if (I->PickCGO) {
|
|
if (use_shader) {
|
|
CGORenderPicking(
|
|
I->PickCGO, info, &context, I->Obj->Setting.get(), nullptr);
|
|
#ifndef PURE_OPENGL_ES_2
|
|
} else {
|
|
glDisable(GL_DEPTH_TEST);
|
|
glTranslatef(I->Coord[0], I->Coord[1], I->Coord[2]);
|
|
CGORenderPicking(I->PickShapeCGO, info, &context,
|
|
I->Obj->Setting.get(), nullptr);
|
|
glTranslatef(-I->Coord[0], -I->Coord[1], -I->Coord[2]);
|
|
glEnable(GL_DEPTH_TEST);
|
|
#endif
|
|
}
|
|
}
|
|
} else {
|
|
if (!I->StdCGO && I->ShapeCGO) {
|
|
if (!use_shader) {
|
|
I->StdCGO = CGOCombineBeginEnd(I->ShapeCGO);
|
|
assert(!I->StdCGO->has_begin_end);
|
|
} else {
|
|
I->StdCGO = CGONew(G);
|
|
CGODisable(I->StdCGO, GL_DEPTH_TEST);
|
|
CGOEnable(I->StdCGO, GL_RAMP_SHADER);
|
|
I->offsetPtOP = CGOUniform3f(I->StdCGO, RAMP_OFFSETPT, I->Coord);
|
|
I->StdCGO->free_append(
|
|
CGOOptimizeToVBONotIndexedNoShader(I->ShapeCGO));
|
|
CGODisable(I->StdCGO, GL_RAMP_SHADER);
|
|
CGOEnable(I->StdCGO, GL_DEPTH_TEST);
|
|
CGOStop(I->StdCGO);
|
|
assert(I->StdCGO->use_shader);
|
|
assert(!I->StdCGO->has_begin_end);
|
|
}
|
|
}
|
|
if (I->StdCGO) {
|
|
if (use_shader) {
|
|
if (color)
|
|
CGORender(I->StdCGO, nullptr, I->Obj->Setting.get(), nullptr,
|
|
info, nullptr);
|
|
#ifndef PURE_OPENGL_ES_2
|
|
} else {
|
|
glDisable(GL_DEPTH_TEST);
|
|
glTranslatef(I->Coord[0], I->Coord[1], I->Coord[2]);
|
|
CGORender(I->ShapeCGO, nullptr, I->Obj->Setting.get(), nullptr,
|
|
info, nullptr);
|
|
glTranslatef(-I->Coord[0], -I->Coord[1], -I->Coord[2]);
|
|
glEnable(GL_DEPTH_TEST);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*========================================================================*/
|
|
GadgetSet* GadgetSetNew(PyMOLGlobals* G)
|
|
{
|
|
auto I = new GadgetSet();
|
|
I->G = G;
|
|
return (I);
|
|
}
|
|
|
|
/*========================================================================*/
|
|
GadgetSet::~GadgetSet()
|
|
{
|
|
GadgetSet* I = this;
|
|
if (I) {
|
|
CGOFree(I->PickCGO);
|
|
CGOFree(I->PickShapeCGO);
|
|
CGOFree(I->StdCGO);
|
|
CGOFree(I->ShapeCGO);
|
|
VLAFreeP(I->Coord);
|
|
VLAFreeP(I->Normal);
|
|
VLAFreeP(I->Color);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieve coordinate buffer of Gadget set
|
|
* @param I target Gadget set
|
|
*/
|
|
|
|
std::vector<float> GadgetSetGetCoord(const GadgetSet* I)
|
|
{
|
|
std::vector<float> result;
|
|
result.resize(VLAGetSize(I->Coord));
|
|
std::copy_n(I->Coord, result.size(), result.data());
|
|
return result;
|
|
}
|