/* 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"os_gl.h" #include"Err.h" #include"RepNonbonded.h" #include"Color.h" #include"Scene.h" #include"main.h" #include"Setting.h" #include"ShaderMgr.h" #include"CGO.h" #include"CoordSet.h" struct RepNonbonded : Rep { using Rep::Rep; ~RepNonbonded() override; cRep_t type() const override { return cRepNonbonded; } void render(RenderInfo* info) override; CGO *primitiveCGO; CGO *shaderCGO; bool shaderCGO_has_cylinders; }; #include"ObjectMolecule.h" RepNonbonded::~RepNonbonded() { CGOFree(primitiveCGO); CGOFree(shaderCGO); } void RepNonbondedRenderImmediate(CoordSet * cs, RenderInfo * info) { #ifndef PURE_OPENGL_ES_2 PyMOLGlobals *G = cs->G; if(info->ray || info->pick || (!(G->HaveGUI && G->ValidContext))) return; else { int active = false; ObjectMolecule *obj = cs->Obj; float line_width = SettingGet_f(G, cs->Setting.get(), obj->Setting.get(), cSetting_line_width); float nonbonded_size = SettingGet_f(G, cs->Setting.get(), obj->Setting.get(), cSetting_nonbonded_size); if(info->width_scale_flag) glLineWidth(line_width * info->width_scale); else glLineWidth(line_width); SceneResetNormal(G, true); if(!info->line_lighting) glDisable(GL_LIGHTING); glBegin(GL_LINES); { int a; int nIndex = cs->NIndex; const AtomInfoType* atomInfo = obj->AtomInfo.data(); const int* i2a = cs->IdxToAtm.data(); int last_color = -1; const float *v = cs->Coord; for(a = 0; a < nIndex; a++) { const AtomInfoType* ai = atomInfo + *(i2a++); if((!ai->bonded) && (ai->visRep & cRepNonbondedBit)) { int c = ai->color; float v0 = v[0]; float v1 = v[1]; float v2 = v[2]; active = true; if(c != last_color) { last_color = c; glColor3fv(ColorGet(G, c)); } glVertex3f(v0 - nonbonded_size, v1, v2); glVertex3f(v0 + nonbonded_size, v1, v2); glVertex3f(v0, v1 - nonbonded_size, v2); glVertex3f(v0, v1 + nonbonded_size, v2); glVertex3f(v0, v1, v2 - nonbonded_size); glVertex3f(v0, v1, v2 + nonbonded_size); } v += 3; } } glEnd(); glEnable(GL_LIGHTING); if(!active) cs->Active[cRepNonbonded] = false; } #endif } static int RepNonbondedCGOGenerate(RepNonbonded * I, RenderInfo * info) { PyMOLGlobals *G = I->G; float alpha; int ok = true; CGO *convertcgo = nullptr; short nonbonded_as_cylinders ; short use_shader; float nonbonded_size = SettingGet_f(G, I->cs->Setting.get(), I->obj->Setting.get(), cSetting_nonbonded_size); nonbonded_as_cylinders = SettingGetGlobal_b(G, cSetting_render_as_cylinders) && SettingGetGlobal_b(G, cSetting_nonbonded_as_cylinders); use_shader = SettingGetGlobal_b(G, cSetting_nonbonded_use_shader) & SettingGetGlobal_b(G, cSetting_use_shaders); alpha = SettingGet_f(G, I->cs->Setting.get(), I->obj->Setting.get(), cSetting_nonbonded_transparency); alpha = 1.0F - alpha; if(fabs(alpha - 1.0) < R_SMALL4) alpha = 1.0F; if (use_shader){ if (ok && I->shaderCGO){ CGOFree(I->shaderCGO); } if (ok){ if (nonbonded_as_cylinders){ CGO *tmpCGO = CGONew(G); if (ok) ok &= CGOEnable(tmpCGO, GL_CYLINDER_SHADER); if (ok) ok &= CGOSpecial(tmpCGO, CYLINDER_WIDTH_FOR_REPWIRE); convertcgo = CGOConvertCrossesToCylinderShader(I->primitiveCGO, tmpCGO, nonbonded_size); if (ok) ok &= CGOAppendNoStop(tmpCGO, convertcgo); if (ok) ok &= CGODisable(tmpCGO, GL_CYLINDER_SHADER); if (ok) ok &= CGOStop(tmpCGO); CGOFreeWithoutVBOs(convertcgo); I->shaderCGO_has_cylinders = true; convertcgo = tmpCGO; } else { bool trilines = SettingGetGlobal_b(G, cSetting_trilines); CGO *tmpCGO = CGONew(G), *tmp2CGO; int shader = trilines ? GL_TRILINES_SHADER : GL_LINE_SHADER; if (ok) ok &= CGOEnable(tmpCGO, shader); if (ok) ok &= CGODisable(tmpCGO, CGO_GL_LIGHTING); if (trilines) { if (ok) ok &= CGOSpecial(tmpCGO, LINEWIDTH_DYNAMIC_WITH_SCALE); tmp2CGO = CGOConvertCrossesToTrilinesShader(I->primitiveCGO, tmpCGO, nonbonded_size); } else { tmp2CGO = CGOConvertCrossesToLinesShader(I->primitiveCGO, tmpCGO, nonbonded_size); } if (ok) ok &= CGOAppendNoStop(tmpCGO, tmp2CGO); if (ok) ok &= CGODisable(tmpCGO, shader); if (ok) ok &= CGOStop(tmpCGO); CGOFreeWithoutVBOs(tmp2CGO); convertcgo = tmpCGO; I->shaderCGO_has_cylinders = false; } convertcgo->use_shader = true; } CHECKOK(ok, convertcgo); if (!ok || convertcgo){ CGOFree(I->shaderCGO); I->shaderCGO = convertcgo; I->shaderCGO->use_shader = use_shader; convertcgo = nullptr; } } else { // no shaders convertcgo = CGOCombineBeginEnd(I->shaderCGO, 0); CGOFree(I->shaderCGO); I->shaderCGO = convertcgo; I->shaderCGO->use_shader = use_shader; convertcgo = nullptr; } return ok; } void RepNonbonded::render(RenderInfo* info) { auto I = this; CRay *ray = info->ray; auto pick = info->pick; int ok = true; float alpha = SettingGet_f(G, I->cs->Setting.get(), I->obj->Setting.get(), cSetting_nonbonded_transparency); alpha = 1.0F - alpha; if(fabs(alpha - 1.0) < R_SMALL4) alpha = 1.0F; if(ray) { #ifndef _PYMOL_NO_RAY CGORenderRay(I->primitiveCGO, ray, info, nullptr, nullptr, I->cs->Setting.get(), I->cs->Obj->Setting.get()); ray->transparentf(0.0); #endif } else if(G->HaveGUI && G->ValidContext) { if(pick) { CGORenderPicking(I->shaderCGO ? I->shaderCGO : I->primitiveCGO, info, &I->context, I->cs->Setting.get(), I->obj->Setting.get()); } else { /* not pick, but render */ bool use_shader = SettingGetGlobal_b(G, cSetting_nonbonded_use_shader) && SettingGetGlobal_b(G, cSetting_use_shaders); if (!use_shader){ CGORender(I->primitiveCGO, nullptr, nullptr, nullptr, info, I); return; } bool nonbonded_as_cylinders = SettingGetGlobal_b(G, cSetting_render_as_cylinders) && SettingGetGlobal_b(G, cSetting_nonbonded_as_cylinders); if (I->shaderCGO && use_shader != I->shaderCGO->use_shader){ CGOFree(I->shaderCGO); I->shaderCGO = 0; } if (I->shaderCGO && (nonbonded_as_cylinders ^ I->shaderCGO_has_cylinders)){ CGOFree(I->shaderCGO); I->shaderCGO = 0; } if (!I->shaderCGO){ I->shaderCGO = CGONew(G); CHECKOK(ok, I->shaderCGO); if (ok){ I->shaderCGO->use_shader = use_shader; } ok &= RepNonbondedCGOGenerate(I, info); } CGORender(I->shaderCGO, nullptr, nullptr, nullptr, info, I); } } } Rep *RepNonbondedNew(CoordSet * cs, int state) { PyMOLGlobals *G = cs->G; bool hasNonbondedAtoms = false; ObjectMolecule *obj = cs->Obj; if((obj->RepVisCache & cRepNonbondedBit)){ for(int a = 0; a < cs->NIndex; a++) { AtomInfoType *ai = obj->AtomInfo + cs->IdxToAtm[a]; if (!ai->bonded && (ai->visRep & cRepNonbondedBit)){ hasNonbondedAtoms = true; break; } } } if(!hasNonbondedAtoms) { return (nullptr); /* skip if no dots are visible */ } auto I = new RepNonbonded(cs, state); I->shaderCGO = nullptr; I->primitiveCGO = CGONew(G); CGOSpecialWithArg(I->primitiveCGO, LINE_LIGHTING, 0.f); CGOSpecial(I->primitiveCGO, LINEWIDTH_FOR_LINES); CGOBegin(I->primitiveCGO, GL_LINES); // for immediate mode bool first = true; int a1, c1; float tmpColor[3]; for(int a = 0; a < cs->NIndex; a++){ a1 = cs->IdxToAtm[a]; AtomInfoType *ai = obj->AtomInfo + a1; if(!ai->bonded && (ai->visRep & cRepNonbondedBit)) { c1 = ai->color; const float* v1 = cs->coordPtr(a); ColorGetCheckRamped(G, c1, v1, tmpColor, state); if (first || !equal3f(I->primitiveCGO->color, tmpColor)){ CGOColorv(I->primitiveCGO, tmpColor); } CGOPickColor(I->primitiveCGO, a1, (ai->masked) ? cPickableNoPick : cPickableAtom); CGOVertexCrossv(I->primitiveCGO, v1); first = false; } } CGOEnd(I->primitiveCGO); // for immediate mode CGOSpecialWithArg(I->primitiveCGO, LINE_LIGHTING, 1.f); return (Rep *) I; }