/* 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"ObjectGadgetRamp.h" #include"GadgetSet.h" #include"Base.h" #include"MemoryDebug.h" #include"CGO.h" #include"Scene.h" #include"Setting.h" #include"PConv.h" #include"main.h" #include"Color.h" #include"VFont.h" #include"ObjectMolecule.h" #include"Executive.h" #include"Util.h" #include"P.h" #include"PyMOLObject.h" #include "Feedback.h" static void ObjectGadgetRampBuild(ObjectGadgetRamp *); static int ObjectGadgetRampHandleInputColors(ObjectGadgetRamp *); ObjectGadgetRamp::~ObjectGadgetRamp() { auto I = this; ColorForgetExt(I->G, I->Name); } static void ObjectGadgetRampCalculate(ObjectGadgetRamp * I, float v, float *result) { const float _1 = 1.0F; const float _0 = 0.0F; /* from Filipe Maia */ /* All of this functions are taken right of the gnuplot manual */ if(v > _1) v = _1; else if(v < _0) v = _0; switch (I->CalcMode) { case cRAMP_TRADITIONAL: result[0] = (float) sqrt(v); result[1] = v * v * v; result[2] = (float) sin(v * 2 * cPI); break; case cRAMP_SLUDGE: result[0] = v; result[1] = (float) fabs(v - 0.5F); result[2] = v * v * v * v; break; case cRAMP_OCEAN: result[0] = 3 * v - 2; result[1] = (float) fabs((3 * v - 1) / 2); result[2] = v; break; case cRAMP_HOT: result[0] = 3 * v; result[1] = 3 * v - 1; result[2] = 3 * v - 2; break; case cRAMP_GRAYABLE: result[0] = v / 0.32F - 0.78125F; result[1] = 2 * v - 0.84F; result[2] = v / 0.08F - 11.5F; /* I'm not so sure about this one */ break; case cRAMP_RAINBOW: result[0] = (float) fabs(2 * v - 0.5F); result[1] = (float) sin(v * cPI); result[2] = (float) cos(v * cPI / 2.0F); break; case cRAMP_AFMHOT: result[0] = 2 * v; result[1] = 2 * v - 0.5F; result[2] = 2 * v - 1.0F; break; case cRAMP_GRAYSCALE: result[0] = v; result[1] = v; result[2] = v; break; default: /* default is simply white */ result[0] = 1.0F; result[1] = 1.0F; result[2] = 1.0F; break; } clamp3f(result); } /** * Get the "Level" array, eventually spaced out to match number of colors. */ static const float * ObjectGadgetRampGetLevel(ObjectGadgetRamp * I) { if (!I->Level || !I->Color) return I->Level; int n_color = VLAGetSize(I->Color) / 3; if (n_color == I->NLevel || n_color < 2) return I->Level; if (!I->LevelTmp) { float level0 = I->Level[0], level1 = I->Level[I->NLevel - 1]; I->LevelTmp = pymol::vla(n_color); for (int i = 0; i < n_color; ++i) { float a = i / (float) (n_color - 1); I->LevelTmp[i] = level0 * (1.f - a) + level1 * a; } } return I->LevelTmp; } /** * We support storing special color indices as negative R in the RGB color */ inline int GetSpecial(const float * rgb) { if (rgb[0] < 0.f) return (int) rgb[0]; return 0; } static int _ObjectGadgetRampInterpolate(ObjectGadgetRamp * I, float level, float *color, const float *table) { const float *i_level = ObjectGadgetRampGetLevel(I); int n_level = VLAGetSize(i_level); const float _0 = 0.0F; const float _1 = 1.0F; int ok = true; if(i_level && table) { int level_is_ge = -1; int level_is_le = n_level; int i = 0; i = n_level - 1; while(i >= 0) { float f = i_level[i]; if(level >= f) { level_is_ge = i; break; } i--; } i = 0; while(i < n_level) { float f = i_level[i]; if(level <= f) { level_is_le = i; break; } else i++; } if(level_is_ge != level_is_le) { if(level_is_le == 0) { /* lower extreme */ copy3f(table, color); } else if(level_is_ge == (n_level - 1)) { /* upper extreme */ copy3f(table + 3 * (n_level - 1), color); } else { float d, x0, x1; d = i_level[level_is_ge] - i_level[level_is_le]; if(fabs(d) > R_SMALL8) { x0 = (level - i_level[level_is_le]) / d; x1 = 1.0F - x0; for(i = 0; i < 3; i++) { color[i] = x0 * table[3 * level_is_ge + i] + x1 * table[3 * level_is_le + i]; } clamp3f(color); } else { copy3f(table + 3 * level_is_ge, color); } } } else { /* dead on the specified level */ copy3f(table + 3 * level_is_ge, color); clamp3f(color); } } else { float base, range; if(n_level && i_level) { base = i_level[0]; range = i_level[n_level - 1] - base; if(fabs(range) < R_SMALL8) range = _1; } else { base = _0; range = _1; } level = (level - base) / range; ObjectGadgetRampCalculate(I, level, color); } return (ok); } static int _ObjectGadgetRampBlend(ObjectGadgetRamp * I, float *color, const float *table, int mode) { /* this capability needs to be re-thought */ const float *i_level = ObjectGadgetRampGetLevel(I); int n_level = VLAGetSize(i_level); const float _1 = 1.0F; float avg[3]; int ok = true; zero3f(avg); { int cnt = 0; switch (mode) { case 1: case 2: break; default: if(i_level && table) { int i; for(i = 0; i < n_level; i++) { add3f(table + 3 * i, avg, avg); cnt++; } if(cnt) { float fact = _1 / cnt; scale3f(avg, fact, avg); } clamp3f(avg); } copy3f(avg, color); } } switch (mode) { case 1: /* min components */ case 3: ones3f(color); if(i_level && table) { int i, j; for(i = 0; i < n_level; i++) { for(j = 0; j < 3; j++) { color[j] = (color[j] < table[3 * i + j]) ? color[j] : table[3 * i + j]; } } clamp3f(color); } if(mode == 3) { /* average serves as a minimum */ int j; for(j = 0; j < 3; j++) { color[j] = (color[j] > avg[j]) ? color[j] : avg[j]; } } break; case 2: /* max components */ zero3f(color); if(i_level && table) { int i, j; for(i = 0; i < n_level; i++) { for(j = 0; j < 3; j++) { color[j] = (color[j] > table[3 * i + j]) ? color[j] : table[3 * i + j]; } } clamp3f(color); } break; default: /* simple average of all colors */ copy3f(avg, color); break; } return (ok); } #define MAX_COLORS 64 static int ObjectGadgetRampInterpolateWithSpecial(ObjectGadgetRamp * I, float level, float *color, const float *atomic, const float *object, const float *vertex, int state, int blend_all) { /* now thread-safe...via stack copy of colors */ float stack_color[MAX_COLORS * 3]; const float *i_level = ObjectGadgetRampGetLevel(I); const float *i_color = I->Color; if(i_level && i_color) { int i = 0; int n_level = VLAGetSize(i_level); /* mix special coloring into the table */ const float *src = i_color; float *dst = stack_color; if((n_level + 2) > MAX_COLORS) n_level = MAX_COLORS - 2; while(i < n_level) { int index = GetSpecial(src); switch (index) { case 0: copy3f(src, dst); break; case cColorDefault: case cColorAtomic: copy3f(atomic, dst); break; case cColorObject: copy3f(object, dst); break; default: /* allow nested ramps */ ColorGetRamped(I->G, index, vertex, dst, state); break; } dst += 3; src += 3; i++; } i_color = stack_color; } /* interpolate using static tables */ if(blend_all) return _ObjectGadgetRampBlend(I, color, i_color, I->SrcState); return _ObjectGadgetRampInterpolate(I, level, color, i_color); } int ObjectGadgetRampInterpolate(ObjectGadgetRamp * I, float level, float *color) { int result = _ObjectGadgetRampInterpolate(I, level, color, I->Color); return result; } PyObject *ObjectGadgetRampAsPyList(ObjectGadgetRamp * I) { PyObject *result = nullptr; result = PyList_New(11); PyList_SetItem(result, 0, ObjectGadgetPlainAsPyList(I, false)); PyList_SetItem(result, 1, PyInt_FromLong(I->RampType)); PyList_SetItem(result, 2, PyInt_FromLong(I->NLevel)); if(I->Level && I->NLevel) { PyList_SetItem(result, 3, PConvFloatVLAToPyList(I->Level)); } else { PyList_SetItem(result, 3, PConvAutoNone(nullptr)); } if(I->Color && I->NLevel) { PyList_SetItem(result, 4, PConvFloatVLAToPyList(I->Color)); } else { PyList_SetItem(result, 4, PConvAutoNone(nullptr)); } PyList_SetItem(result, 5, PyInt_FromLong(I->var_index)); PyList_SetItem(result, 6, PyString_FromString(I->SrcName)); PyList_SetItem(result, 7, PyInt_FromLong(I->SrcState)); PyList_SetItem(result, 8, PyInt_FromLong(I->CalcMode)); // I->Special, removed in PyMOL 1.8 bool any = false; int* special = nullptr; int pse_export_version = SettingGetGlobal_f(I->G, cSetting_pse_export_version) * 1000; if (I->Color && pse_export_version < 1800) { int n_color = VLAGetSize(I->Color) / 3; special = VLAlloc(int, n_color); for (int a = 0; a < n_color; ++a) { any = (special[a] = GetSpecial(I->Color + a * 3)) || any; } } PyList_SetItem(result, 9, any ? PConvIntVLAToPyList(special) : PConvAutoNone(nullptr)); VLAFreeP(special); PyList_SetItem(result, 10, PConvAutoNone(nullptr) /* I->Extreme, removed in PyMOL 1.8 */); return (PConvAutoNone(result)); } int ObjectGadgetRampNewFromPyList(PyMOLGlobals * G, PyObject * list, ObjectGadgetRamp ** result, int version) { ObjectGadgetRamp *I = nullptr; int ok = true; int ll = 0; if(ok) I = new ObjectGadgetRamp(G); if(ok) ok = (I != nullptr); if(ok) ok = (list != nullptr); if(ok) ok = PyList_Check(list); if(ok) ll = PyList_Size(list); /* TO SUPPORT BACKWARDS COMPATIBILITY... Always check ll when adding new PyList_GetItem's */ if(ok){ auto val = PyList_GetItem(list, 0); ok = ObjectGadgetInitFromPyList(G, val, I, version); } if(ok) ok = PConvPyIntToInt(PyList_GetItem(list, 1), &I->RampType); if(ok) ok = PConvPyIntToInt(PyList_GetItem(list, 2), &I->NLevel); if(ok && I->NLevel) ok = PConvPyListToFloatVLA(PyList_GetItem(list, 3), &I->Level); if(ok && I->NLevel) { PyObject *item = PyList_GetItem(list, 4); if(item != Py_None) { ok = PConvPyListToFloatVLA(item, &I->Color); } } if(ok) ok = CPythonVal_PConvPyStrToStr_From_List(G, list, 6, I->SrcName, WordLength); if(ok) ok = PConvPyIntToInt(PyList_GetItem(list, 7), &I->SrcState); if(ok && (ll > 8)) ok = CPythonVal_PConvPyIntToInt_From_List(G, list, 8, &I->CalcMode); if(ok && I->NLevel && (ll > 10)) { CPythonVal *item = CPythonVal_PyList_GetItem(G, list, 10); if(!CPythonVal_IsNone(item)) { // ObjectGadgetRamp::Extreme removed in PyMOL 1.8 // Copy extreme colors to the beginning and end of the Color array // and repeat the first and last level value float *extreme = nullptr; PConvPyListToFloatVLA(item, &extreme); if (extreme) { I->NLevel += 2; VLASize(I->Level, float, I->NLevel); for (int i = I->NLevel - 2; i >= 1; --i) I->Level[i] = I->Level[i - 1]; I->Level[I->NLevel - 1] = I->Level[I->NLevel - 2]; if (I->Color) { VLASize(I->Color, float, I->NLevel * 3); for (int i = (I->NLevel - 1) * 3 - 1; i >= 3; --i) I->Color[i] = I->Color[i - 3]; copy3f(extreme, I->Color.data()); copy3f(extreme + 3, I->Color + (I->NLevel - 1) * 3); } VLAFreeP(extreme); } } CPythonVal_Free(item); } ObjectGadgetRampHandleInputColors(I); ObjectGadgetRampBuild(I); if(ok) (*result) = I; return (ok); } int ObjectGadgetRampInterVertex(ObjectGadgetRamp * I, const float *pos, float *color, int state) { float level; int ok = true; switch (I->RampType) { case cRampMap: if(!I->Map) I->Map = ExecutiveFindObjectMapByName(I->G, I->SrcName); if(!ExecutiveValidateObjectPtr(I->G, I->Map, cObjectMap)) ok = false; else { int src_state; if(I->SrcState >= 0) src_state = I->SrcState; else src_state = state; if(src_state < 0) src_state = SceneGetState(I->G); if(ok) ok = (I->Map != nullptr); if(ok) ok = ObjectMapInterpolate(I->Map, src_state, pos, &level, nullptr, 1); if(ok) ok = ObjectGadgetRampInterpolate(I, level, color); } break; case cRampMol: if(!I->Mol) I->Mol = ExecutiveFindObjectMoleculeByName(I->G, I->SrcName); if(!ExecutiveValidateObjectPtr(I->G, I->Mol, cObjectMolecule)) ok = false; else { float cutoff = 1.0F; float dist; int sub_vdw = false; if(state < 0) state = SceneGetState(I->G); if(I->Level && I->NLevel) { cutoff = I->Level[I->NLevel - 1]; if(I->Level[0] < 0.0F) { sub_vdw = true; cutoff += MAX_VDW; } } if(ok) ok = (I->Mol != nullptr); if(ok) { if (I->Mol->NCSet==1) // if only one state, then set state to 0 state = 0; if(SettingGet_b (I->G, I->Setting.get(), nullptr, cSetting_ramp_blend_nearby_colors)) { float atomic[3]; int index = ObjectMoleculeGetNearestBlendedColor(I->Mol, pos, cutoff, state, &dist, atomic, sub_vdw); if(index >= 0) { const float *object = ColorGetRaw(I->G, I->Mol->Color); if(!ObjectGadgetRampInterpolateWithSpecial(I, dist, color, atomic, object, pos, state, false)) { copy3f(I->Color.data(), color); } } else { float white[3] = { 1.0F, 1.0F, 1.0F }; if(!ObjectGadgetRampInterpolateWithSpecial(I, cutoff + 1.0F, color, white, white, pos, state, false)) { copy3f(I->Color.data(), color); } } } else { int index = ObjectMoleculeGetNearestAtomIndex(I->Mol, pos, cutoff, state, &dist); if(index >= 0) { const float *atomic = ColorGetRaw(I->G, I->Mol->AtomInfo[index].color); const float *object = ColorGetRaw(I->G, I->Mol->Color); if(sub_vdw) { dist -= I->Mol->AtomInfo[index].vdw; if(dist < 0.0F) dist = 0.0F; } if(!ObjectGadgetRampInterpolateWithSpecial(I, dist, color, atomic, object, pos, state, false)) { copy3f(I->Color.data(), color); } } else { float white[3] = { 1.0F, 1.0F, 1.0F }; if(!ObjectGadgetRampInterpolateWithSpecial(I, cutoff + 1.0F, color, white, white, pos, state, false)) { copy3f(I->Color.data(), color); } } } } } break; case cRampNone: { float white[3] = { 1.0F, 1.0F, 1.0F }; if(!ObjectGadgetRampInterpolateWithSpecial(I, 0.0F, color, white, white, pos, state, true)) { /* simple blend */ copy3f(I->Color.data(), color); } } break; default: ok = false; break; } return (ok); } static void ObjectGadgetRampUpdateCGO(ObjectGadgetRamp * I, GadgetSet * gs) { CGO *cgo; int a; char buffer[255]; int blocked = false; int font_id = 0; int n_color = I->Color ? VLAGetSize(I->Color) / 3 : 0; blocked = PAutoBlock(I->G); font_id = VFontLoad(I->G, 1.0, 1, 1, true); if(blocked) PUnblock(I->G); cgo = CGONewSized(I->G, 100); /* behind text */ CGOBegin(cgo, GL_TRIANGLE_STRIP); CGOColor(cgo, 0.05F, 0.05F, 0.05F); CGONormal(cgo, 0.f, 0.f, 1.f); // normal 2 CGOVertex(cgo, I->border, -(I->border + I->bar_height), I->border); // 9 CGOVertex(cgo, I->border, -(I->height + I->border), I->border); // 7 CGOVertex(cgo, I->width + I->border, -(I->border + I->bar_height), I->border); // 10 CGOVertex(cgo, I->width + I->border, -(I->height + I->border), I->border); // 8 CGOEnd(cgo); CGOColor(cgo, 1.0F, 1.0F, 1.0F); CGONormal(cgo, 0.f, 0.f, 1.f); // text/characters need z-normal to include normals in vbo if(I->Level && I->NLevel) { float exindent = (n_color > 0) ? I->bar_height : 0.f; float pos[] = { I->border + I->text_border + exindent, I->text_border - (I->border + I->height), I->border + I->text_raise }; float scale[] = { I->text_scale_h, I->text_scale_v }; float axes[] = { 1.0F, 0.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 0.0F, 1.0F }; float color[] = { 1.f, 1.f, 1.f }; /* left text for ramp */ sprintf(buffer, "%0.3f", I->Level[0]); VFontWriteToCGO(I->G, font_id, cgo, buffer, pos, scale, axes, color); /* right text, right justified for ramp */ pos[0] = I->width + I->border - exindent; pos[1] = I->text_border - (I->border + I->height); pos[2] = I->border + I->text_raise ; sprintf(buffer, "%0.3f", I->Level[I->NLevel - 1]); /* indent for right justification */ VFontIndent(I->G, font_id, buffer, pos, scale, axes, -1.f); VFontWriteToCGO(I->G, font_id, cgo, buffer, pos, scale, axes, color); } /* center */ CGOBegin(cgo, GL_TRIANGLE_STRIP); CGONormal(cgo, 0.f, 0.f, 1.f); // normal 2 if(n_color > 0) { const float *i_level = ObjectGadgetRampGetLevel(I); const float *src = I->Color; float stack_color[6], stack_level[2] = {0.f, 1.f}; if(n_color == 1) { n_color = 2; copy3f(src, stack_color); copy3f(src, stack_color + 3); src = stack_color; i_level = stack_level; } // can this ever happen? if (!i_level) { i_level = stack_level; n_color = 2; } float range = i_level[n_color - 1] - i_level[0]; // avoid devide by zero if (fabs(range) < R_SMALL8) { range = 1.f; i_level = stack_level; n_color = 2; } // repeat first and last color in a `bar_height` wide square for(a = -1; a <= n_color; a++) { float tmp[3] = {1.f, 1.f, 1.f}; float v1 = I->border; if(!GetSpecial(src)) { copy3f(src, tmp); ColorLookupColor(I->G, tmp); } if (a == n_color) { v1 += I->width; } else if (a != -1) { v1 += I->bar_height + (I->width - 2 * I->bar_height) * (i_level[a] - i_level[0]) / range; if (a != n_color - 1) { src += 3; } } CGOColorv(cgo, tmp); CGOVertex(cgo, v1, -I->border, I->border); CGOVertex(cgo, v1, -I->border - I->bar_height, I->border); } } else { int samples = 20; float fxn; float color[3]; for(a = 0; a < samples; a++) { fxn = a / (samples - 1.0F); ObjectGadgetRampCalculate(I, fxn, color); CGOColorv(cgo, color); CGOVertex(cgo, I->border + (I->width * fxn), -I->border, I->border); CGOVertex(cgo, I->border + (I->width * fxn), -(I->border + I->bar_height), I->border); } } /* center */ CGOEnd(cgo); CGOColor(cgo, 1.F, 1.F, 1.F); /* top */ CGOBegin(cgo, GL_TRIANGLE_STRIP); CGONormal(cgo, 0.f, 0.f, 1.f); // normal 2 CGOVertex(cgo, I->border, -I->border, I->border); // 5 CGOVertex(cgo, I->width + I->border, -I->border, I->border); // 6 CGONormal(cgo, 0.f, 1.f, .1f); // normal 1 CGOVertex(cgo, 0.0, 0.0, 0.0); // 1 CGOVertex(cgo, I->width + I->border * 2, 0.0, 0.0); // 2 CGOEnd(cgo); /* bottom */ CGOBegin(cgo, GL_TRIANGLE_STRIP); CGONormal(cgo, 0.f, -1.f, .1f); // normal 4 CGOVertex(cgo, 0.f, -(I->height + I->border * 2), 0.f); // 3 CGOVertex(cgo, I->width + I->border * 2, -(I->height + I->border * 2), 0.f); // 4 CGONormal(cgo, 0.f, 0.f, 1.f); // normal 2 CGOVertex(cgo, I->border, -(I->height + I->border), I->border); // 7 CGOVertex(cgo, I->width + I->border, -(I->height + I->border), I->border); // 8 CGOEnd(cgo); /* left */ CGOBegin(cgo, GL_TRIANGLE_STRIP); CGONormal(cgo, -1.f, 0.f, 0.1f); // normal 3 CGOVertex(cgo, 0.f, 0.f, 0.f); // 1 CGOVertex(cgo, 0.f, -(I->height + I->border * 2), 0.f); // 3 CGONormal(cgo, 0.f, 0.f, 1.f); // normal 2 CGOVertex(cgo, I->border, -I->border, I->border); // 5 CGOVertex(cgo, I->border, -(I->height + I->border), I->border); // 7 CGOEnd(cgo); /* right */ CGOBegin(cgo, GL_TRIANGLE_STRIP); CGONormal(cgo, 0.f, 0.f, 1.f); // normal 2 CGOVertex(cgo, I->width + I->border, -I->border, I->border); // 6 CGOVertex(cgo, I->width + I->border, -(I->height + I->border), I->border); // 8 CGONormal(cgo, 1.f, 0.f, .1f); // normal 0 CGOVertex(cgo, I->width + I->border * 2, 0.f, 0.f); // 2 CGOVertex(cgo, I->width + I->border * 2, -(I->height + I->border * 2), 0.f); // 4 CGOEnd(cgo); CGOStop(cgo); CGOFree(gs->ShapeCGO); gs->ShapeCGO = cgo; //#ifndef _PYMOL_NOPY CGOPreloadFonts(gs->ShapeCGO); //#endif cgo = CGONewSized(I->G, 100); CGODotwidth(cgo, 5); CGOPickColor(cgo, 0, cPickableGadget); /* top */ CGOBegin(cgo, GL_TRIANGLE_STRIP); CGOVertex(cgo, 0.f, 0.f, 0.f); // 1 CGOVertex(cgo, I->width + I->border * 2, 0.f, 0.f); // 2 CGOVertex(cgo, I->border, -I->border, I->border); // 5 CGOVertex(cgo, I->width + I->border, -I->border, I->border); // 6 CGOEnd(cgo); /* bottom */ CGOBegin(cgo, GL_TRIANGLE_STRIP); CGOVertex(cgo, 0.f, -(I->height + I->border * 2), 0.f); // 3 CGOVertex(cgo, I->width + I->border * 2, -(I->height + I->border * 2), 0.f); // 4 CGOVertex(cgo, I->border, -(I->height + I->border), I->border); // 7 CGOVertex(cgo, I->width + I->border, -(I->height + I->border), I->border); // 8 CGOEnd(cgo); /* left */ CGOBegin(cgo, GL_TRIANGLE_STRIP); CGOVertex(cgo, 0.f, 0.f, 0.f); // 1 CGOVertex(cgo, 0.f, -(I->height + I->border * 2), 0.f); // 3 CGOVertex(cgo, I->border, -I->border, I->border); // 5 CGOVertex(cgo, I->border, -(I->height + I->border), I->border); // 7 CGOEnd(cgo); /* right */ CGOBegin(cgo, GL_TRIANGLE_STRIP); CGOVertex(cgo, I->width + I->border, -I->border, I->border); // 6 CGOVertex(cgo, I->width + I->border, -(I->height + I->border), I->border); // 8 CGOVertex(cgo, I->width + I->border * 2, 0.f, 0.f); // 2 CGOVertex(cgo, I->width + I->border * 2, -(I->height + I->border * 2), 0.f); // 4 CGOEnd(cgo); /* band */ CGOPickColor(cgo, 1, cPickableGadget); CGOBegin(cgo, GL_TRIANGLE_STRIP); CGOVertex(cgo, I->border, -I->border, I->border); // 5 CGOVertex(cgo, I->width + I->border, -I->border, I->border); // 6 CGOVertex(cgo, I->border, -(I->height + I->border), I->border); // 7 CGOVertex(cgo, I->width + I->border, -(I->height + I->border), I->border); // 8 CGOEnd(cgo); CGOStop(cgo); CGOFree(gs->PickShapeCGO); gs->PickShapeCGO = cgo; } static void ObjectGadgetRampBuild(ObjectGadgetRamp * I) { GadgetSet *gs = nullptr; ObjectGadget *og; OrthoBusyPrime(I->G); og = I; gs = GadgetSetNew(I->G); gs->NCoord = 2; I->var_index = gs->NCoord; gs->Coord = VLAlloc(float, gs->NCoord * 3); gs->Coord[0] = I->x; gs->Coord[1] = I->y; gs->Coord[2] = .3f; gs->Coord[3] = gs->Coord[4] = gs->Coord[5] = 0.f; gs->NNormal = 0; gs->Normal = nullptr; // was a memory leak in < 1.8.3.1 for (int i = 0; i < og->NGSet; ++i) { delete og->GSet[i]; og->GSet[i] = nullptr; } og->GSet[0] = gs; og->NGSet = 1; gs->Obj = (ObjectGadget *) I; gs->State = 0; ObjectGadgetRampUpdateCGO(I, gs); gs->update(); } /*========================================================================*/ void ObjectGadgetRamp::update() { auto I = this; float scale; if(I->Changed) { scale = (1.0F + 5 * I->GSet[0]->Coord[1 * 3]); I->GSet[0]->Coord[1 * 3] = 0.0; switch (I->RampType) { case cRampMol: { int a; for(a = 0; a < I->NLevel; a++) { I->Level[a] = I->Level[a] * scale; } ExecutiveInvalidateRep(I->G, cKeywordAll, cRepAll, cRepInvColor); } break; default: if(I->NLevel == 2) { { float mean = (I->Level[0] + I->Level[1]) / 2.0F; I->Level[0] = (I->Level[0] - mean) * scale + mean; I->Level[1] = (I->Level[1] - mean) * scale + mean; ExecutiveInvalidateRep(I->G, cKeywordAll, cRepAll, cRepInvColor); } break; } else if(I->NLevel == 3) { I->Level[0] = (I->Level[0] - I->Level[1]) * scale + I->Level[1]; I->Level[2] = (I->Level[2] - I->Level[1]) * scale + I->Level[1]; ExecutiveInvalidateRep(I->G, cKeywordAll, cRepAll, cRepInvColor); } } VLAFreeP(I->LevelTmp); if(I->NGSet) if(I->GSet[0]) { ObjectGadgetRampUpdateCGO(I, I->GSet[0]); ObjectGadgetUpdateStates(I); } ObjectGadgetUpdateExtents(I); I->Changed = false; SceneChanged(I->G); } } static int ObjectGadgetRampHandleInputColors(ObjectGadgetRamp * I) { VLAFreeP(I->LevelTmp); if(I->NLevel < 1) { VLASize(I->Level, float, 1); I->NLevel = 1; I->Level[0] = 0.0F; } if(I->Color) { int n_color = VLAGetSize(I->Color) / 3; /* handle cases where number of colors doesn't make expectation */ if(!n_color) { VLASize(I->Color, float, 3); I->Color[0] = I->Color[1] = I->Color[2] = 1.0F; n_color++; } if(n_color != I->NLevel && I->NLevel != 2) { PRINTFB(I->G, FB_ObjectGadget, FB_Warnings) " GadgetRamp-Warning: number of colors (%d) and number of levels (%d) don't\n" " match and n_level != 2. Support for trailing extreme colors dropped in 1.8.", n_color, I->NLevel ENDFB(I->G); } if(n_color < I->NLevel) { // repeat last color until n_color == NLevel VLASize(I->Color, float, 3 * I->NLevel); while(n_color < I->NLevel) { copy3f(I->Color + 3 * (n_color - 1), I->Color + 3 * n_color); n_color++; } } } return true; } /*========================================================================*/ ObjectGadgetRamp *ObjectGadgetRampMapNewAsDefined(PyMOLGlobals * G, ObjectGadgetRamp *I, ObjectMap * map, pymol::vla&& level_vla, pymol::vla&& color_vla, int map_state, float *vert_vla, float beyond, float within, float sigma, int zero, int calc_mode) { if (!I) I = new ObjectGadgetRamp(G); I->RampType = cRampMap; if (color_vla || calc_mode > 0) { I->Color = std::move(color_vla); I->CalcMode = calc_mode; } { ObjectMapState *ms; float tmp_level[3]; if(map_state < 0) map_state = 0; if(vert_vla && map && (ms = ObjectMapGetState(map, map_state))) { if(ObjectMapStateGetExcludedStats(G, ms, vert_vla, beyond, within, tmp_level)) { tmp_level[0] = tmp_level[1] + (tmp_level[0] - tmp_level[1]) * sigma; tmp_level[2] = tmp_level[1] + (tmp_level[2] - tmp_level[1]) * sigma; if(zero) { if(tmp_level[1] < 0.0F) { tmp_level[1] = 0.0F; tmp_level[2] = -tmp_level[0]; } else if(tmp_level[1] > 0.0F) { tmp_level[1] = 0.0F; tmp_level[0] = -tmp_level[2]; } } } I->Level = pymol::vla(3); copy3f(tmp_level, I->Level.data()); VLAFreeP(level_vla); } else if (level_vla) { I->Level = std::move(level_vla); } } I->NLevel = VLAGetSize(I->Level); ObjectGadgetRampHandleInputColors(I); ObjectGadgetRampBuild(I); if (map) { I->Map = map; I->SrcState = map_state; UtilNCopy(I->SrcName, map->Name, WordLength); } return (I); } /*========================================================================*/ ObjectGadgetRamp *ObjectGadgetRampMolNewAsDefined(PyMOLGlobals * G, ObjectGadgetRamp *I, ObjectMolecule * mol, pymol::vla&& level_vla, pymol::vla&& color_vla, int mol_state, int calc_mode) { if (!I) { I = new ObjectGadgetRamp(G); I->RampType = cRampNone; UtilNCopy(I->SrcName, "none", WordLength); } if(mol) { I->RampType = cRampMol; I->Mol = mol; I->SrcState = mol_state; UtilNCopy(I->SrcName, mol->Name, WordLength); } if (color_vla || calc_mode > 0) { I->Color = std::move(color_vla); I->CalcMode = calc_mode; } if(level_vla) { I->Level = std::move(level_vla); I->NLevel = VLAGetSize(I->Level); } ObjectGadgetRampHandleInputColors(I); ObjectGadgetRampBuild(I); return (I); } void ObjectGadgetRamp::invalidate(cRep_t rep, cRepInv_t level, int state) { } /*========================================================================*/ ObjectGadgetRamp::ObjectGadgetRamp(PyMOLGlobals * G) : ObjectGadget(G) { auto I = this; I->GadgetType = cGadgetRamp; I->SrcName[0] = 0; }