mirror of
https://github.com/schrodinger/pymol-open-source.git
synced 2026-06-04 20:04:21 +08:00
509 lines
11 KiB
C++
509 lines
11 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_gl.h"
|
|
#include "os_predef.h"
|
|
#include "os_std.h"
|
|
|
|
#include "Base.h"
|
|
#include "CGO.h"
|
|
#include "Color.h"
|
|
#include "GadgetSet.h"
|
|
#include "MemoryDebug.h"
|
|
#include "ObjectGadget.h"
|
|
#include "ObjectGadgetRamp.h"
|
|
#include "PConv.h"
|
|
#include "Scene.h"
|
|
#include "Setting.h"
|
|
#include "VFont.h"
|
|
#include "main.h"
|
|
|
|
CGO* ObjectGadgetPyListFloatToCGO(PyObject* list);
|
|
|
|
int ObjectGadgetGetVertex(const ObjectGadget* I, int index, int base, float* v)
|
|
{
|
|
GadgetSet* gs;
|
|
int ok = false;
|
|
if (I->CurGSet < I->NGSet) {
|
|
gs = I->GSet[I->CurGSet];
|
|
if (gs) {
|
|
ok = GadgetSetGetVertex(gs, index, base, v);
|
|
}
|
|
}
|
|
return (ok);
|
|
}
|
|
|
|
int ObjectGadgetSetVertex(ObjectGadget* I, int index, int base, const float* v)
|
|
{
|
|
GadgetSet* gs;
|
|
int ok = false;
|
|
if (I->CurGSet < I->NGSet) {
|
|
gs = I->GSet[I->CurGSet];
|
|
if (gs) {
|
|
ok = GadgetSetSetVertex(gs, index, base, v);
|
|
}
|
|
}
|
|
if (index) // if 0 - xyz doesn't change, 1 - mouse position when changing
|
|
// colors
|
|
I->Changed = true;
|
|
return (ok);
|
|
}
|
|
|
|
/* in current state */
|
|
ObjectGadget* ObjectGadgetTest(PyMOLGlobals* G)
|
|
{
|
|
ObjectGadget* I = nullptr;
|
|
GadgetSet* gs = nullptr;
|
|
CGO* cgo = nullptr;
|
|
int a;
|
|
|
|
float coord[] = {
|
|
0.5F,
|
|
0.5F,
|
|
0.0F,
|
|
0.0F,
|
|
0.0F,
|
|
0.0F,
|
|
0.3F,
|
|
0.0F,
|
|
0.0F,
|
|
0.0F,
|
|
-0.3F,
|
|
0.0F,
|
|
0.3F,
|
|
-0.3F,
|
|
0.0F,
|
|
0.03F,
|
|
-0.03F,
|
|
0.03F,
|
|
0.27F,
|
|
-0.03F,
|
|
0.03F,
|
|
0.03F,
|
|
-0.27F,
|
|
0.03F,
|
|
0.27F,
|
|
-0.27F,
|
|
0.03F,
|
|
0.02F,
|
|
-0.02F,
|
|
0.01F,
|
|
0.28F,
|
|
-0.02F,
|
|
0.01F,
|
|
0.02F,
|
|
-0.28F,
|
|
0.01F,
|
|
0.28F,
|
|
-0.28F,
|
|
0.01F,
|
|
};
|
|
|
|
float normal[] = {
|
|
1.0,
|
|
0.0,
|
|
0.0,
|
|
0.0,
|
|
1.0,
|
|
0.0,
|
|
0.0,
|
|
0.0,
|
|
1.0,
|
|
-1.0,
|
|
0.0,
|
|
0.0,
|
|
0.0,
|
|
-1.0,
|
|
0.0,
|
|
};
|
|
|
|
I = new ObjectGadget(G);
|
|
gs = GadgetSetNew(G);
|
|
|
|
gs->NCoord = 13;
|
|
gs->Coord = VLAlloc(float, gs->NCoord * 3);
|
|
for (a = 0; a < gs->NCoord * 3; a++) {
|
|
gs->Coord[a] = coord[a];
|
|
}
|
|
|
|
gs->NNormal = 5;
|
|
gs->Normal = VLAlloc(float, gs->NNormal * 3);
|
|
for (a = 0; a < gs->NNormal * 3; a++) {
|
|
gs->Normal[a] = normal[a];
|
|
}
|
|
|
|
cgo = CGONewSized(G, 100);
|
|
CGOColor(cgo, 1.0, 1.0, 1.0);
|
|
|
|
/* top */
|
|
CGOBegin(cgo, GL_TRIANGLE_STRIP);
|
|
CGONormal(cgo, 2.0, 2.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 5.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 6.0, 0.0);
|
|
|
|
CGONormal(cgo, 2.0, 1.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 1.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 2.0, 0.0);
|
|
CGOEnd(cgo);
|
|
|
|
/* bottom */
|
|
CGOBegin(cgo, GL_TRIANGLE_STRIP);
|
|
CGONormal(cgo, 2.0, 4.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 3.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 4.0, 0.0);
|
|
|
|
CGONormal(cgo, 2.0, 2.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 7.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 8.0, 0.0);
|
|
CGOEnd(cgo);
|
|
|
|
/* left */
|
|
CGOBegin(cgo, GL_TRIANGLE_STRIP);
|
|
CGONormal(cgo, 2.0, 3.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 1.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 3.0, 0.0);
|
|
|
|
CGONormal(cgo, 2.0, 2.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 5.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 7.0, 0.0);
|
|
CGOEnd(cgo);
|
|
|
|
/* right */
|
|
CGOBegin(cgo, GL_TRIANGLE_STRIP);
|
|
CGONormal(cgo, 2.0, 2.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 6.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 8.0, 0.0);
|
|
|
|
CGONormal(cgo, 2.0, 0.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 2.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 4.0, 0.0);
|
|
CGOEnd(cgo);
|
|
|
|
CGOColor(cgo, 1.0, 0.0, 0.0);
|
|
|
|
/* center */
|
|
CGOBegin(cgo, GL_TRIANGLE_STRIP);
|
|
CGONormal(cgo, 2.0, 2.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 5.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 7.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 6.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 8.0, 0.0);
|
|
CGOEnd(cgo);
|
|
|
|
CGOColor(cgo, 0.0, 1.0, 0.0);
|
|
/* backr */
|
|
CGOBegin(cgo, GL_TRIANGLE_STRIP);
|
|
CGONormal(cgo, 2.0, 2.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 9.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 10.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 11.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 12.0, 0.0);
|
|
CGOEnd(cgo);
|
|
CGOStop(cgo);
|
|
|
|
gs->ShapeCGO = cgo;
|
|
|
|
cgo = CGONewSized(G, 100);
|
|
CGODotwidth(cgo, 5);
|
|
|
|
CGOPickColor(cgo, 0, cPickableGadget);
|
|
|
|
/* top */
|
|
CGOBegin(cgo, GL_TRIANGLE_STRIP);
|
|
CGOVertex(cgo, 1.0, 1.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 2.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 5.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 6.0, 0.0);
|
|
CGOEnd(cgo);
|
|
|
|
/* bottom */
|
|
CGOBegin(cgo, GL_TRIANGLE_STRIP);
|
|
CGOVertex(cgo, 1.0, 3.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 4.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 7.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 8.0, 0.0);
|
|
CGOEnd(cgo);
|
|
|
|
/* left */
|
|
CGOBegin(cgo, GL_TRIANGLE_STRIP);
|
|
CGOVertex(cgo, 1.0, 1.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 3.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 5.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 7.0, 0.0);
|
|
CGOEnd(cgo);
|
|
|
|
/* right */
|
|
CGOBegin(cgo, GL_TRIANGLE_STRIP);
|
|
CGOVertex(cgo, 1.0, 6.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 8.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 2.0, 0.0);
|
|
CGOVertex(cgo, 1.0, 4.0, 0.0);
|
|
CGOEnd(cgo);
|
|
CGOEnd(cgo);
|
|
CGOStop(cgo);
|
|
gs->PickShapeCGO = cgo;
|
|
|
|
gs->Obj = I;
|
|
gs->State = 0;
|
|
|
|
I->GSet[0] = gs;
|
|
I->NGSet = 1;
|
|
gs->update();
|
|
ObjectGadgetUpdateExtents(I);
|
|
return (I);
|
|
}
|
|
|
|
void ObjectGadgetUpdateExtents(ObjectGadget* I)
|
|
{
|
|
float maxv[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
|
|
float minv[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
|
|
int a;
|
|
GadgetSet* ds;
|
|
|
|
/* update extents */
|
|
copy3f(maxv, I->ExtentMin);
|
|
copy3f(minv, I->ExtentMax);
|
|
I->ExtentFlag = false;
|
|
for (a = 0; a < I->NGSet; a++) {
|
|
ds = I->GSet[a];
|
|
if (ds) {
|
|
if (GadgetSetGetExtent(ds, I->ExtentMin, I->ExtentMax))
|
|
I->ExtentFlag = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
static PyObject* ObjectGadgetGSetAsPyList(ObjectGadget* I, bool incl_cgos)
|
|
{
|
|
PyObject* result = nullptr;
|
|
int a;
|
|
result = PyList_New(I->NGSet);
|
|
for (a = 0; a < I->NGSet; a++) {
|
|
if (I->GSet[a]) {
|
|
PyList_SetItem(result, a, GadgetSetAsPyList(I->GSet[a], incl_cgos));
|
|
} else {
|
|
PyList_SetItem(result, a, PConvAutoNone(Py_None));
|
|
}
|
|
}
|
|
return (PConvAutoNone(result));
|
|
}
|
|
|
|
static int ObjectGadgetGSetFromPyList(
|
|
ObjectGadget* I, PyObject* list, int version)
|
|
{
|
|
|
|
int ok = true;
|
|
int a;
|
|
if (ok)
|
|
ok = PyList_Check(list);
|
|
if (ok) {
|
|
VLACheck(I->GSet, GadgetSet*, I->NGSet);
|
|
for (a = 0; a < I->NGSet; a++) {
|
|
if (ok) {
|
|
auto* val = PyList_GetItem(list, a);
|
|
ok = GadgetSetFromPyList(I->G, val, &I->GSet[a], version);
|
|
}
|
|
if (ok && I->GSet[a]) {
|
|
I->GSet[a]->Obj = I;
|
|
I->GSet[a]->State = a;
|
|
}
|
|
}
|
|
}
|
|
return (ok);
|
|
}
|
|
|
|
int ObjectGadgetInitFromPyList(
|
|
PyMOLGlobals* G, PyObject* list, ObjectGadget* I, int version)
|
|
{
|
|
int ok = true;
|
|
if (ok)
|
|
ok = (I != nullptr) && (list != nullptr);
|
|
if (ok)
|
|
ok = PyList_Check(list);
|
|
/* TO SUPPORT BACKWARDS COMPATIBILITY...
|
|
Always check ll when adding new PyList_GetItem's */
|
|
if (ok) {
|
|
auto* val = PyList_GetItem(list, 0);
|
|
ok = ObjectFromPyList(G, val, I);
|
|
}
|
|
if (ok)
|
|
ok = PConvPyIntToInt(PyList_GetItem(list, 1), &I->GadgetType);
|
|
if (ok)
|
|
ok = PConvPyIntToInt(PyList_GetItem(list, 2), &I->NGSet);
|
|
if (ok)
|
|
ok = ObjectGadgetGSetFromPyList(I, PyList_GetItem(list, 3), version);
|
|
if (ok)
|
|
ok = PConvPyIntToInt(PyList_GetItem(list, 4), &I->CurGSet);
|
|
|
|
/* ObjectGadgetInvalidateRep(I,cRepAll); */
|
|
if (ok) {
|
|
ObjectGadgetUpdateExtents(I);
|
|
} else {
|
|
/* cleanup? */
|
|
}
|
|
return (ok);
|
|
}
|
|
|
|
int ObjectGadgetNewFromPyList(
|
|
PyMOLGlobals* G, PyObject* list, ObjectGadget** result, int version)
|
|
{
|
|
int ok = true;
|
|
ObjectGadget* I = nullptr;
|
|
int gadget_type = -1;
|
|
PyObject* plain;
|
|
(*result) = nullptr;
|
|
|
|
if (ok)
|
|
ok = (list != nullptr);
|
|
if (ok)
|
|
ok = PyList_Check(list);
|
|
|
|
/* NOTE there is a serious screw-up here...ramp gadgets aren't saved right,
|
|
but we've got to maintain backward compat...ugh */
|
|
|
|
if (ok)
|
|
ok = ((plain = PyList_GetItem(list, 0)) != nullptr);
|
|
if (ok)
|
|
ok = PyList_Check(plain);
|
|
if (ok)
|
|
ok = PConvPyIntToInt(PyList_GetItem(plain, 1), &gadget_type);
|
|
if (ok)
|
|
switch (gadget_type) { /* call the right routine to restore the gadget! */
|
|
case cGadgetRamp:
|
|
ok = ObjectGadgetRampNewFromPyList(
|
|
G, list, (ObjectGadgetRamp**) result, version);
|
|
break;
|
|
case cGadgetPlain:
|
|
I = new ObjectGadget(G);
|
|
if (ok)
|
|
ok = (I != nullptr);
|
|
if (ok)
|
|
ok = ObjectGadgetInitFromPyList(G, list, I, version);
|
|
if (ok)
|
|
(*result) = I;
|
|
break;
|
|
default:
|
|
ok = false;
|
|
break;
|
|
}
|
|
return (ok);
|
|
}
|
|
|
|
PyObject* ObjectGadgetPlainAsPyList(ObjectGadget* I, bool incl_cgos)
|
|
{
|
|
PyObject* result = nullptr;
|
|
|
|
/* first, dump the atoms */
|
|
|
|
result = PyList_New(5);
|
|
PyList_SetItem(result, 0, ObjectAsPyList(I));
|
|
PyList_SetItem(result, 1, PyInt_FromLong(I->GadgetType));
|
|
PyList_SetItem(result, 2, PyInt_FromLong(I->NGSet));
|
|
PyList_SetItem(result, 3, ObjectGadgetGSetAsPyList(I, incl_cgos));
|
|
PyList_SetItem(result, 4, PyInt_FromLong(I->CurGSet));
|
|
return (PConvAutoNone(result));
|
|
}
|
|
|
|
PyObject* ObjectGadgetAsPyList(ObjectGadget* I)
|
|
{
|
|
PyObject* result = nullptr;
|
|
|
|
/* first, dump the atoms */
|
|
|
|
switch (I->GadgetType) {
|
|
case cGadgetRamp:
|
|
result = ObjectGadgetRampAsPyList((ObjectGadgetRamp*) I);
|
|
break;
|
|
case cGadgetPlain:
|
|
result = ObjectGadgetPlainAsPyList(I);
|
|
break;
|
|
}
|
|
return (PConvAutoNone(result));
|
|
}
|
|
|
|
ObjectGadget::~ObjectGadget()
|
|
{
|
|
auto I = this;
|
|
for (int a = 0; a < I->NGSet; a++)
|
|
if (I->GSet[a]) {
|
|
delete I->GSet[a];
|
|
I->GSet[a] = nullptr;
|
|
}
|
|
}
|
|
|
|
void ObjectGadgetUpdateStates(ObjectGadget* I)
|
|
{
|
|
int a;
|
|
OrthoBusyPrime(I->G);
|
|
for (a = 0; a < I->NGSet; a++)
|
|
if (I->GSet[a]) {
|
|
OrthoBusySlow(I->G, a, I->NGSet);
|
|
/* printf(" ObjectGadget: updating state %d of \"%s\".\n" , a+1,
|
|
* I->Name); */
|
|
I->GSet[a]->update();
|
|
}
|
|
}
|
|
|
|
/*========================================================================*/
|
|
void ObjectGadget::update()
|
|
{
|
|
auto I = this;
|
|
if (I->Changed) {
|
|
ObjectGadgetUpdateStates(I);
|
|
ObjectGadgetUpdateExtents(I);
|
|
I->Changed = false;
|
|
}
|
|
}
|
|
|
|
/*========================================================================*/
|
|
|
|
int ObjectGadget::getNFrame() const
|
|
{
|
|
return NGSet;
|
|
}
|
|
|
|
/*========================================================================*/
|
|
void ObjectGadget::render(RenderInfo* info)
|
|
{
|
|
auto I = this;
|
|
int state = info->state;
|
|
const RenderPass pass = info->pass;
|
|
if (pass == RenderPass::Transparent || info->ray || info->pick) {
|
|
|
|
ObjectPrepareContext(I, info);
|
|
for (StateIterator iter(I->G, I->Setting.get(), state, I->NGSet);
|
|
iter.next();) {
|
|
GadgetSet* gs = I->GSet[iter.state];
|
|
gs->render(info);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*========================================================================*/
|
|
ObjectGadget::ObjectGadget(PyMOLGlobals* G)
|
|
: pymol::CObject(G)
|
|
{
|
|
type = cObjectGadget;
|
|
GSet = pymol::vla<GadgetSet*>(10); /* auto-zero */
|
|
}
|
|
|
|
pymol::RenderContext ObjectGadget::getRenderContext() const
|
|
{
|
|
return pymol::RenderContext::UnitWindow;
|
|
}
|