/* 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 GadgetSetGetCoord(const GadgetSet* I) { std::vector result; result.resize(VLAGetSize(I->Coord)); std::copy_n(I->Coord, result.size(), result.data()); return result; }