mirror of
https://github.com/schrodinger/pymol-open-source.git
synced 2026-06-04 20:04:21 +08:00
1924 lines
57 KiB
C++
1924 lines
57 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"MemoryDebug.h"
|
|
#include"Ortho.h"
|
|
#include"Word.h"
|
|
|
|
#include"Color.h"
|
|
#include"PConv.h"
|
|
#include"ObjectGadgetRamp.h"
|
|
#include"Util.h"
|
|
#include"Executive.h"
|
|
#include"MyPNG.h"
|
|
#include"Scene.h"
|
|
#include "Feedback.h"
|
|
|
|
static int AutoColor[] = {
|
|
26, /* carbon */
|
|
5, /* cyan */
|
|
154, /* lightmagenta */
|
|
6, /* yellow */
|
|
9, /* salmon */
|
|
29, /* hydrogen */
|
|
11, /* slate */
|
|
13, /* orange */
|
|
10, /* lime */
|
|
5262, /* deepteal */
|
|
12, /* hotpink */
|
|
36, /* yelloworange */
|
|
5271, /* violetpurple */
|
|
124, /* grey70 */
|
|
17, /* marine */
|
|
18, /* olive */
|
|
5270, /* smudge */
|
|
20, /* teal */
|
|
5272, /* dirtyviolet */
|
|
52, /* wheat */
|
|
5258, /* deepsalmon */
|
|
5274, /* lightpink */
|
|
5257, /* aquamarine */
|
|
5256, /* paleyellow */
|
|
15, /* limegreen */
|
|
5277, /* skyblue */
|
|
5279, /* warmpink */
|
|
5276, /* limon */
|
|
53, /* violet */
|
|
5278, /* bluewhite */
|
|
5275, /* greencyan */
|
|
5269, /* sand */
|
|
22, /* forest */
|
|
5266, /* lightteal */
|
|
5280, /* darksalmon */
|
|
5267, /* splitpea */
|
|
5268, /* raspberry */
|
|
104, /* grey50 */
|
|
23, /* deepblue */
|
|
51, /* brown */
|
|
};
|
|
|
|
static int nAutoColor = 40;
|
|
static void lookup_color(CColor * I, const float *in, float *out, int big_endian);
|
|
|
|
void ColorGetBkrdContColor(PyMOLGlobals * G, float *rgb, int invert_flag)
|
|
{
|
|
const float *bkrd = ColorGet(G, SettingGet_color(G, nullptr, nullptr, cSetting_bg_rgb));
|
|
|
|
if(!invert_flag) {
|
|
if((bkrd[0] + bkrd[1] + bkrd[2]) > 0.5F) {
|
|
rgb[0] = 1.0F;
|
|
rgb[1] = 1.0F;
|
|
rgb[2] = 1.0F;
|
|
} else {
|
|
rgb[0] = 0.0F;
|
|
rgb[1] = 0.0F;
|
|
rgb[2] = 0.0F;
|
|
}
|
|
}
|
|
|
|
{
|
|
int a;
|
|
for(a = 0; a < 3; a++)
|
|
if(fabs(bkrd[a] - rgb[a]) < 0.5F) {
|
|
rgb[a] = 1.0F - rgb[a];
|
|
if(fabs(bkrd[a] - rgb[a]) < 0.5F) {
|
|
if(bkrd[a] > 0.5F)
|
|
rgb[a] = 0.0F;
|
|
else
|
|
rgb[a] = 1.0F;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned int ColorGet32BitWord(PyMOLGlobals * G, const float *rgba)
|
|
{
|
|
CColor *I = G->Color;
|
|
unsigned int rc, gc, bc, ac;
|
|
unsigned int result;
|
|
|
|
rc = (int) (255 * rgba[0] + 0.49999F);
|
|
gc = (int) (255 * rgba[1] + 0.49999F);
|
|
bc = (int) (255 * rgba[2] + 0.49999F);
|
|
ac = (int) (255 * rgba[3] + 0.49999F);
|
|
|
|
if(rc > 255)
|
|
rc = 255;
|
|
if(bc > 255)
|
|
bc = 255;
|
|
if(gc > 255)
|
|
gc = 255;
|
|
if(ac > 255)
|
|
ac = 255;
|
|
|
|
if(I->BigEndian) {
|
|
result = (rc << 24) | (gc << 16) | (bc << 8) | ac;
|
|
} else {
|
|
result = (ac << 24) | (bc << 16) | (gc << 8) | rc;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int ColorGetNext(PyMOLGlobals * G)
|
|
{
|
|
int result;
|
|
int next;
|
|
next = SettingGetGlobal_i(G, cSetting_auto_color_next);
|
|
|
|
if(next >= nAutoColor)
|
|
next = 0;
|
|
result = AutoColor[next];
|
|
next++;
|
|
if(next >= nAutoColor)
|
|
next = 0;
|
|
SettingSetGlobal_i(G, cSetting_auto_color_next, next);
|
|
return (result);
|
|
}
|
|
|
|
int ColorGetCurrent(PyMOLGlobals * G)
|
|
{
|
|
int result;
|
|
int next;
|
|
next = SettingGetGlobal_i(G, cSetting_auto_color_next);
|
|
next--;
|
|
if(next < 0)
|
|
next = (nAutoColor - 1);
|
|
result = AutoColor[next];
|
|
return (result);
|
|
}
|
|
|
|
int ColorCheckRamped(PyMOLGlobals * G, int index)
|
|
{
|
|
return (index <= (cColorExtCutoff));
|
|
}
|
|
|
|
ObjectGadgetRamp *ColorGetRamp(PyMOLGlobals * G, int index)
|
|
{
|
|
CColor *I = G->Color;
|
|
if(index <= cColorExtCutoff) {
|
|
index = cColorExtCutoff - index;
|
|
if (index < I->Ext.size()) {
|
|
auto& ext = I->Ext[index];
|
|
if (!ext.Ptr && ext.Name) {
|
|
ext.Ptr = ExecutiveFindObject<ObjectGadgetRamp>(G, ext.Name);
|
|
}
|
|
return ext.Ptr;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
int ColorGetRamped(PyMOLGlobals * G, int index, const float *vertex, float *color, int state)
|
|
{
|
|
CColor *I = G->Color;
|
|
int ok = false;
|
|
if (auto* ptr = ColorGetRamp(G, index)) {
|
|
ok = ObjectGadgetRampInterVertex(ptr, vertex, color, state);
|
|
}
|
|
if(!ok) {
|
|
color[0] = 1.0;
|
|
color[1] = 1.0;
|
|
color[2] = 1.0;
|
|
} else if(I->LUTActive) {
|
|
lookup_color(I, color, color, I->BigEndian);
|
|
}
|
|
return (ok);
|
|
}
|
|
|
|
/**
|
|
* Gets a color as 3 floats from an index and writes it into
|
|
* the color argument. If the index is a ramp, then it uses the vertex and state arguments to lookup the
|
|
* color value in the ramp.
|
|
* NOTES: does not support index values cColorObject(-5) or cColorAtomic(-4) color since the object
|
|
* or atom color is not passed in.
|
|
*
|
|
* @param index - color index value
|
|
* @param vertex - x/y/z used for ramp lookup (if color index is a ramp)
|
|
* @param[out] color - output color array of 3 floats
|
|
* @param state - state lookup if ramp
|
|
*
|
|
* @return whether the color index is dependent on a ramp.
|
|
*/
|
|
bool ColorGetCheckRamped(PyMOLGlobals * G, int index, const float *vertex, float *color, int state)
|
|
{
|
|
bool isRamped = false;
|
|
if(ColorCheckRamped(G, index)) {
|
|
ColorGetRamped(G, index, vertex, color, state);
|
|
isRamped = true;
|
|
} else {
|
|
copy3f(ColorGet(G, index), color);
|
|
}
|
|
return isRamped;
|
|
}
|
|
|
|
/**
|
|
* Find a record by case-insensitive name
|
|
*
|
|
* @param seq Indexable container (Color or Ext)
|
|
* @param name Color name
|
|
* @return seq index or -1 if not found
|
|
*/
|
|
template <typename Sequence>
|
|
static int findByCaseInsensitiveName(
|
|
PyMOLGlobals* G, const Sequence& seq, const char* name)
|
|
{
|
|
for (int a = 0; a < seq.size(); ++a) {
|
|
auto* color_name = seq[a].Name;
|
|
if (color_name) {
|
|
int wm = WordMatch(G, name, color_name, true);
|
|
if (wm < 0) {
|
|
return a;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Find a record by case-insensitive and/or partial name
|
|
*
|
|
* @param seq Indexable container (Color or Ext)
|
|
* @param name Color name
|
|
* @param[in,out] best Word match score (0 for perfect match), must not be
|
|
* negative
|
|
* @return seq index or -1 if not found
|
|
*/
|
|
template <typename Sequence>
|
|
static int findByCaseInsensitivePrefix(
|
|
PyMOLGlobals* G, const Sequence& seq, const char* name, int& best)
|
|
{
|
|
int best_a = -1;
|
|
assert(best >= 0);
|
|
|
|
// search for an imperfect match
|
|
for (int a = 0; a < seq.size(); ++a) {
|
|
auto* color_name = seq[a].Name;
|
|
if (color_name) {
|
|
auto wm = WordMatch(G, name, color_name, true);
|
|
if (wm < 0) {
|
|
// perfect case-insensitive match
|
|
best = 0;
|
|
return a;
|
|
}
|
|
|
|
if (best < wm) {
|
|
// prefix match
|
|
best = wm;
|
|
best_a = a;
|
|
}
|
|
}
|
|
}
|
|
|
|
return best_a;
|
|
}
|
|
|
|
/**
|
|
* Find a color ramp by case-insensitive name
|
|
*
|
|
* @param name Color name (ramp name)
|
|
* @return Ext index or -1 if not found
|
|
*/
|
|
static int ColorFindExtByName(PyMOLGlobals* G, const char* name)
|
|
{
|
|
return findByCaseInsensitiveName(G, G->Color->Ext, name);
|
|
}
|
|
|
|
/**
|
|
* Map name to index (idx[name] = index)
|
|
*
|
|
* If the name is already in use and the index can't be reused, then clear the
|
|
* name on the existing color or ext record.
|
|
*
|
|
* @param index Color index
|
|
* @param name Color name
|
|
* @param reuse If the name already exists, reuse the existing index if possible
|
|
* (not possible to reuse a ramp index for a color or vice versa)
|
|
*
|
|
* @return pointer to stored name string
|
|
*/
|
|
static const char* reg_name(CColor* const I, CColor::ColorIdx const index,
|
|
const char* name, bool reuse = false)
|
|
{
|
|
auto handle = I->Idx.emplace(name, index);
|
|
auto& handle_name = handle.first->first;
|
|
auto& handle_index = handle.first->second;
|
|
|
|
if (handle_index != index &&
|
|
(!reuse || bool(cColorExtCutoff < handle_index) !=
|
|
bool(cColorExtCutoff < index))) {
|
|
assert(!handle.second);
|
|
|
|
// if we're stealing a name to a new index, clear the name on the old record
|
|
if (handle_index <= cColorExtCutoff) {
|
|
auto& ext = I->Ext[cColorExtCutoff - handle_index];
|
|
assert(ext.Name == handle_name.c_str());
|
|
ext.Name = nullptr;
|
|
} else if (handle_index >= 0) {
|
|
auto& col = I->Color[handle_index];
|
|
assert(col.Name == handle_name.c_str());
|
|
col.Name = nullptr;
|
|
}
|
|
|
|
handle_index = index;
|
|
}
|
|
|
|
return handle_name.c_str();
|
|
}
|
|
|
|
void ColorRegisterExt(PyMOLGlobals* G, const char* name, ObjectGadgetRamp* ptr)
|
|
{
|
|
CColor *I = G->Color;
|
|
int a;
|
|
|
|
a = ColorFindExtByName(G, name);
|
|
if(a < 0) {
|
|
a = I->Ext.size();
|
|
|
|
I->Ext.emplace_back();
|
|
auto& ext = I->Ext.back();
|
|
|
|
ext.Name = reg_name(I, cColorExtCutoff - a, name);
|
|
assert(I->Idx[ext.Name] == cColorExtCutoff - a);
|
|
}
|
|
if(a >= 0) {
|
|
I->Ext[a].Ptr = ptr;
|
|
}
|
|
}
|
|
|
|
void ColorForgetExt(PyMOLGlobals * G, const char *name)
|
|
{
|
|
CColor *I = G->Color;
|
|
auto a = ColorFindExtByName(G, name);
|
|
|
|
if (a < 0)
|
|
return;
|
|
|
|
// currently leaks memory in I->Ext array
|
|
auto& ext = I->Ext[a];
|
|
ext.Ptr = nullptr;
|
|
|
|
// HaveOldSessionExtColors should only be true while we're loading a partial
|
|
// session, and ColorForgetExt probably means that we're replacing the ramp
|
|
// object with a another one, so we don't want to lose the name+index
|
|
// relationship.
|
|
if (ext.Name && !I->HaveOldSessionExtColors) {
|
|
I->Idx.erase(ext.Name);
|
|
ext.Name = nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject *ColorExtAsPyList(PyMOLGlobals * G)
|
|
{
|
|
CColor *I = G->Color;
|
|
|
|
auto* result = PyList_New(I->Ext.size());
|
|
|
|
size_t a = 0;
|
|
|
|
for (const auto& ext : I->Ext) {
|
|
auto* list = PyList_New(2);
|
|
const char* name = ext.Name ? ext.Name : "";
|
|
PyList_SetItem(list, 0, PyString_FromString(name));
|
|
|
|
// obsolete since PyMOL 2.5, store for backwards compatibility
|
|
PyList_SetItem(list, 1, PyInt_FromLong(cColorGadgetRamp));
|
|
|
|
PyList_SetItem(result, a++, list);
|
|
}
|
|
|
|
assert(a == I->Ext.size());
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
PyObject *ColorAsPyList(PyMOLGlobals * G)
|
|
{
|
|
CColor *I = G->Color;
|
|
|
|
size_t n_custom = 0;
|
|
for (const auto& color : I->Color) {
|
|
if (color.Custom || color.LutColorFlag) {
|
|
n_custom++;
|
|
}
|
|
}
|
|
|
|
auto* result = PyList_New(n_custom);
|
|
|
|
size_t a = 0;
|
|
size_t c = 0;
|
|
|
|
for (const auto& color : I->Color) {
|
|
if (color.Custom || color.LutColorFlag) {
|
|
auto* list = PyList_New(7);
|
|
PyList_SetItem(list, 0, PyString_FromString(color.Name ? color.Name : ""));
|
|
PyList_SetItem(list, 1, PyInt_FromLong(a));
|
|
PyList_SetItem(list, 2, PConvFloatArrayToPyList(color.Color, 3));
|
|
PyList_SetItem(list, 3, PyInt_FromLong(color.Custom));
|
|
PyList_SetItem(list, 4, PyInt_FromLong(color.LutColorFlag));
|
|
PyList_SetItem(list, 5, PConvFloatArrayToPyList(color.LutColor, 3));
|
|
PyList_SetItem(list, 6, PyInt_FromLong(color.Fixed));
|
|
PyList_SetItem(result, c++, list);
|
|
}
|
|
++a;
|
|
}
|
|
|
|
assert(c == n_custom);
|
|
|
|
return result;
|
|
}
|
|
|
|
/*========================================================================*/
|
|
int ColorConvertOldSessionIndex(PyMOLGlobals * G, int index)
|
|
{
|
|
CColor *I = G->Color;
|
|
if(index > cColorExtCutoff) {
|
|
if(I->HaveOldSessionColors) {
|
|
for (int a = int(I->Color.size()) - 1; a >= 0; --a) {
|
|
if (index == I->Color[a].old_session_index) {
|
|
return a;
|
|
}
|
|
}
|
|
}
|
|
} else if(I->HaveOldSessionExtColors) {
|
|
for (int a = int(I->Ext.size()) - 1; a >= 0; --a) {
|
|
if (index == I->Ext[a].old_session_index) {
|
|
return cColorExtCutoff - a;
|
|
}
|
|
}
|
|
}
|
|
return index; /* failsafe */
|
|
}
|
|
|
|
#define return_error_if_fail(e) p_return_val_if_fail((e), false);
|
|
|
|
int ColorExtFromPyList(PyMOLGlobals * G, PyObject * list, int partial_restore)
|
|
{
|
|
CColor *I = G->Color;
|
|
size_t n_ext = 0;
|
|
|
|
assert(!I->HaveOldSessionExtColors);
|
|
|
|
if (list && PyList_Check(list)) {
|
|
n_ext = PyList_Size(list);
|
|
}
|
|
|
|
/* TO SUPPORT BACKWARDS COMPATIBILITY...
|
|
Always check ll when adding new PyList_GetItem's */
|
|
|
|
if (partial_restore) {
|
|
I->HaveOldSessionExtColors = I->Ext.size() > 0;
|
|
|
|
for (auto& ext : I->Ext) {
|
|
ext.old_session_index = 0;
|
|
}
|
|
} else {
|
|
I->Ext.clear();
|
|
}
|
|
|
|
for (int a = 0; a < n_ext; ++a) {
|
|
auto* rec = PyList_GetItem(list, a);
|
|
|
|
return_error_if_fail(rec != nullptr);
|
|
return_error_if_fail(PyList_Check(rec));
|
|
|
|
std::string name;
|
|
return_error_if_fail(PConvFromPyListItem(G, rec, 0, name));
|
|
|
|
char const* name_ptr =
|
|
reg_name(I, cColorExtCutoff - I->Ext.size(), name.c_str(), true);
|
|
int const a_new = cColorExtCutoff - I->Idx[name];
|
|
|
|
assert(a_new >= 0);
|
|
assert(a_new <= I->Ext.size());
|
|
assert(a_new == a || partial_restore);
|
|
|
|
if (a_new == I->Ext.size()) {
|
|
I->Ext.emplace_back();
|
|
} else {
|
|
assert(partial_restore);
|
|
}
|
|
|
|
auto& ext = I->Ext[a_new];
|
|
ext.Name = name_ptr;
|
|
ext.old_session_index = cColorExtCutoff - a;
|
|
|
|
CPythonVal_Free(rec);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
int ColorFromPyList(PyMOLGlobals * G, PyObject * list, int partial_restore)
|
|
{
|
|
CColor* I = G->Color;
|
|
|
|
assert(!I->HaveOldSessionColors);
|
|
|
|
if (partial_restore) {
|
|
for (auto& color : I->Color) {
|
|
color.old_session_index = 0;
|
|
}
|
|
}
|
|
|
|
return_error_if_fail(list != nullptr );
|
|
return_error_if_fail(PyList_Check(list));
|
|
|
|
int const n_custom = PyList_Size(list);
|
|
|
|
for (int a = 0; a < n_custom; ++a) {
|
|
auto rec = PyList_GetItem(list, a);
|
|
|
|
return_error_if_fail(rec && PyList_Check(rec));
|
|
|
|
auto const ll = PyList_Size(rec);
|
|
/* TO SUPPORT BACKWARDS COMPATIBILITY...
|
|
Always check ll when adding new PyList_GetItem's */
|
|
|
|
int index = 0;
|
|
return_error_if_fail(PConvFromPyListItem(G, rec, 1, index));
|
|
|
|
std::string name;
|
|
return_error_if_fail(PConvFromPyListItem(G, rec, 0, name));
|
|
|
|
int const old_session_index = index;
|
|
if (partial_restore && I->Color.size() > index) {
|
|
// conflicts with an existing color
|
|
index = I->Color.size();
|
|
I->HaveOldSessionColors = true;
|
|
}
|
|
|
|
if (index >= I->Color.size()) {
|
|
assert(I->Color.size() == index);
|
|
I->Color.emplace_back(reg_name(I, index, name.c_str()));
|
|
}
|
|
|
|
auto& color = I->Color[index];
|
|
color.old_session_index = old_session_index;
|
|
|
|
assert(name == color.Name);
|
|
assert(index == I->Idx[name]);
|
|
|
|
return_error_if_fail(CPythonVal_PConvPyListToFloatArrayInPlace_From_List(
|
|
G, rec, 2, color.Color, 3));
|
|
|
|
if (PyList_Size(rec) >= 6) {
|
|
return_error_if_fail(PConvFromPyListItem(G, rec, 3, color.Custom));
|
|
return_error_if_fail(PConvFromPyListItem(G, rec, 4, color.LutColorFlag));
|
|
return_error_if_fail(CPythonVal_PConvPyListToFloatArrayInPlace_From_List(
|
|
G, rec, 5, color.LutColor, 3));
|
|
} else {
|
|
color.Custom = true;
|
|
}
|
|
|
|
if (ll > 6) {
|
|
PConvFromPyListItem(G, rec, 6, color.Fixed);
|
|
} else {
|
|
color.Fixed = false;
|
|
}
|
|
|
|
CPythonVal_Free(rec);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*========================================================================*/
|
|
void ColorDef(PyMOLGlobals * G, const char *name, const float *v, int mode, int quiet)
|
|
{
|
|
CColor *I = G->Color;
|
|
int color = -1;
|
|
|
|
// Search for a perfect case-sensitive match
|
|
{
|
|
auto it = I->Idx.find(name);
|
|
if (it != I->Idx.end()) {
|
|
color = it->second;
|
|
}
|
|
}
|
|
|
|
if (color < 0) {
|
|
// Not found or ramp index -> do slow search
|
|
color = findByCaseInsensitiveName(G, I->Color, name);
|
|
|
|
if (color < 0) {
|
|
// Not found -> new entry
|
|
color = I->Color.size();
|
|
I->Color.emplace_back(reg_name(I, color, name));
|
|
assert(I->Idx[name] == color);
|
|
}
|
|
}
|
|
|
|
copy3f(v, I->Color[color].Color);
|
|
|
|
switch (mode) {
|
|
case 1:
|
|
I->Color[color].Fixed = true;
|
|
break;
|
|
default:
|
|
I->Color[color].Fixed = false;
|
|
break;
|
|
}
|
|
|
|
I->Color[color].Custom = true;
|
|
ColorUpdateFromLut(G, color);
|
|
|
|
if(!quiet) {
|
|
PRINTFB(G, FB_Executive, FB_Actions)
|
|
" Color: \"%s\" defined as [ %3.3f, %3.3f, %3.3f ].\n", name, v[0], v[1], v[2]
|
|
ENDFB(G);
|
|
|
|
}
|
|
|
|
PRINTFD(G, FB_Color)
|
|
" Color: and assigned number %d.\n", color ENDFD;
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
int ColorGetIndex(PyMOLGlobals * G, const char *name)
|
|
{
|
|
CColor *I = G->Color;
|
|
int i;
|
|
int is_numeric = true;
|
|
|
|
{
|
|
const char *c;
|
|
c = name;
|
|
while(*c) {
|
|
if((((*c) < '0') || ((*c) > '9')) && ((*c) != '-')) {
|
|
is_numeric = false;
|
|
break;
|
|
}
|
|
c++;
|
|
}
|
|
}
|
|
|
|
if(is_numeric) {
|
|
if(sscanf(name, "%d", &i)) {
|
|
if((i < I->Color.size()) && (i >= 0))
|
|
return (i);
|
|
else if(i == cColorNewAuto)
|
|
return (ColorGetNext(G));
|
|
else if(i == cColorCurAuto)
|
|
return (ColorGetCurrent(G));
|
|
else if(i == cColorAtomic)
|
|
return cColorAtomic;
|
|
else if(i == cColorObject)
|
|
return cColorObject;
|
|
else if(i == cColorFront)
|
|
return cColorFront;
|
|
else if(i == cColorBack)
|
|
return cColorBack;
|
|
else if(i == cColorDefault)
|
|
return cColorDefault;
|
|
if (i & cColor_TRGB_Bits)
|
|
return i;
|
|
}
|
|
}
|
|
if((name[0] == '0') && (name[1] == 'x')) { /* explicit hex RGB 0x000000 */
|
|
int tmp_color;
|
|
if(sscanf(name + 2, "%x", (unsigned int *) &tmp_color) == 1) {
|
|
tmp_color = (cColor_TRGB_Bits |
|
|
(tmp_color & 0x00FFFFFF) | ((tmp_color >> 2) & 0x3F000000));
|
|
return tmp_color;
|
|
}
|
|
}
|
|
|
|
// the following block used to allow prefix matches (before PyMOL 2.5)
|
|
if(WordMatch(G, name, "default", true) < 0)
|
|
return cColorDefault;
|
|
if(WordMatch(G, name, "auto", true) < 0)
|
|
return (ColorGetNext(G));
|
|
if(WordMatch(G, name, "current", true) < 0)
|
|
return (ColorGetCurrent(G));
|
|
if(WordMatch(G, name, "atomic", true) < 0)
|
|
return (cColorAtomic);
|
|
if(WordMatch(G, name, "object", true) < 0)
|
|
return (cColorObject);
|
|
if(WordMatch(G, name, "front", true) < 0)
|
|
return (cColorFront);
|
|
if(WordMatch(G, name, "back", true) < 0)
|
|
return (cColorBack);
|
|
|
|
// search for a perfect case-sensitive match (fast!)
|
|
{
|
|
auto it = I->Idx.find(name);
|
|
if (it != I->Idx.end()) {
|
|
return it->second;
|
|
}
|
|
}
|
|
|
|
// search for case-insensitive or partial match
|
|
// TODO does this even make sense? What's the use case? Should this be
|
|
// restricted to non-ambiguous matches? Note that the Python cmd.color()
|
|
// function does its own prefix lookup and rejects ambiguous matches.
|
|
int best = 0;
|
|
int color = findByCaseInsensitivePrefix(G, I->Color, name, best);
|
|
if (best != 0 || color < 0) {
|
|
int const ext_color = findByCaseInsensitivePrefix(G, I->Ext, name, best);
|
|
if (ext_color >= 0) {
|
|
color = cColorExtCutoff - ext_color;
|
|
}
|
|
}
|
|
|
|
return color;
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
const float *ColorGetNamed(PyMOLGlobals * G, const char *name)
|
|
{
|
|
return (ColorGet(G, ColorGetIndex(G, name)));
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
const char *ColorGetName(PyMOLGlobals * G, int index)
|
|
{
|
|
CColor *I = G->Color;
|
|
if((index >= 0) && (index < I->Color.size())) {
|
|
return I->Color[index].Name;
|
|
} else if((index & cColor_TRGB_Mask) == cColor_TRGB_Bits) {
|
|
index = (((index & 0xFFFFFF) | ((index << 2) & 0xFC000000) | /* convert 6 bits of trans into 8 */
|
|
((index >> 4) & 0x03000000)));
|
|
if(index & 0xFF000000) /* if transparent */
|
|
sprintf(I->RGBName, "0x%08x", index);
|
|
else /* else */
|
|
sprintf(I->RGBName, "0x%06x", index);
|
|
return I->RGBName;
|
|
} else if(index <= cColorExtCutoff) {
|
|
int a = cColorExtCutoff - index;
|
|
if (a < I->Ext.size()) {
|
|
return I->Ext[a].Name;
|
|
} else
|
|
return nullptr;
|
|
}
|
|
return (nullptr);
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
int ColorGetStatus(PyMOLGlobals * G, int index)
|
|
{
|
|
CColor *I = G->Color;
|
|
/* return 0 if color is invalid, -1 if hidden;
|
|
1 otherwise */
|
|
int result = 0;
|
|
if((index >= 0) && (index < I->Color.size())) {
|
|
auto* color_name = I->Color[index].Name;
|
|
if(color_name) {
|
|
const char* c = color_name;
|
|
result = 1;
|
|
while(*c) {
|
|
if(((*c) >= '0') && ((*c) <= '9')) {
|
|
result = -1;
|
|
break;
|
|
}
|
|
c++;
|
|
}
|
|
}
|
|
}
|
|
return (result);
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
int ColorGetNColor(PyMOLGlobals * G)
|
|
{
|
|
CColor *I = G->Color;
|
|
return (I->Color.size());
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
void ColorFree(PyMOLGlobals * G)
|
|
{
|
|
DeleteP(G->Color);
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
|
|
void ColorReset(PyMOLGlobals * G)
|
|
{
|
|
|
|
/* PyMOL core color names
|
|
|
|
1 1 1 white
|
|
.5 .5 .5 grey/gray
|
|
0 0 0 black
|
|
|
|
1 0 0 red
|
|
0 1 0 green
|
|
0 0 1 blue
|
|
|
|
1 1 0 yellow
|
|
1 0 1 magenta
|
|
0 1 1 cyan
|
|
|
|
1 1 .5 paleyellow .
|
|
1 .5 1 violet .
|
|
.5 1 1 aquamarine .
|
|
|
|
1 .5 .5 deepsalmon .
|
|
.5 1 .5 palegreen .
|
|
.5 .5 1 slate .
|
|
|
|
.75 .75 0 olive .
|
|
.75 0 .75 purple .
|
|
0 .75 .75 teal .
|
|
|
|
.6 .6 .1 deepolive .
|
|
.6 .1 .6 deeppurple .
|
|
.1 .6 .6 deepteal .
|
|
|
|
1 .5 0 orange .
|
|
1 0 .5 hotpink .
|
|
.5 1 0 chartreuse .
|
|
0 1 .5 limegreen .
|
|
0 .5 1 marine .
|
|
.5 0 1 purpleblue .
|
|
|
|
*/
|
|
|
|
CColor *I = G->Color;
|
|
|
|
I->Idx.clear();
|
|
I->Ext.clear();
|
|
|
|
auto& Color = I->Color;
|
|
Color.clear();
|
|
Color.reserve(5500);
|
|
|
|
char name[10];
|
|
int a;
|
|
int set1;
|
|
float f;
|
|
float spectrumS[13][3] = {
|
|
{1.0, 0.0, 1.0}, /* magenta - 0 */
|
|
{0.5, 0.0, 1.0},
|
|
{0.0, 0.0, 1.0}, /* blue - 166.66 */
|
|
{0.0, 0.5, 1.0},
|
|
{0.0, 1.0, 1.0}, /* cyan - 333.33 */
|
|
|
|
{0.0, 1.0, 0.5},
|
|
{0.0, 1.0, 0.0}, /* green - 500 */
|
|
{0.5, 1.0, 0.0},
|
|
{1.0, 1.0, 0.0}, /* yellow - 666.66 */
|
|
{1.0, 0.5, 0.0},
|
|
|
|
{1.0, 0.0, 0.0}, /* red - 833.33 */
|
|
{1.0, 0.0, 0.5},
|
|
{1.0, 0.0, 1.0}, /* magenta - 999 */
|
|
};
|
|
|
|
float spectrumR[13][3] = {
|
|
{1.0, 1.0, 0.0}, /* yellow - 0 */
|
|
{0.5, 1.0, 0.0}, /* chartreuse */
|
|
{0.0, 1.0, 0.0}, /* green - 166.66 */
|
|
{0.0, 1.0, 0.5}, /* limegreen */
|
|
{0.0, 1.0, 1.0}, /* cyan - 333.33 */
|
|
|
|
{0.0, 0.5, 1.0}, /* marine */
|
|
{0.0, 0.0, 1.0}, /* blue - 500 */
|
|
{0.5, 0.0, 1.0}, /* purpleblue */
|
|
{1.0, 0.0, 1.0}, /* magenta - 666.66 */
|
|
{1.0, 0.0, 0.5}, /* hotpink */
|
|
|
|
{1.0, 0.0, 0.0}, /* red - 833.33 */
|
|
{1.0, 0.5, 0.0}, /* orange */
|
|
{1.0, 1.0, 0.0}, /* yellow - 999 */
|
|
};
|
|
|
|
float spectrumC[][3] = {
|
|
{1.0, 1.0, 0.0}, /* yellow - 0 */
|
|
{0.0, 0.0, 1.0}, /* blue - 83.333 */
|
|
{1.0, 0.0, 0.0}, /* red - 167.67 */
|
|
{0.0, 1.0, 0.0}, /* green - 250.00 */
|
|
{1.0, 0.0, 1.0}, /* magenta - 333.33 */
|
|
|
|
{0.0, 1.0, 1.0}, /* cyan - 416.67 */
|
|
{1.0, 1.0, 0.0}, /* yellow - 500.00 */
|
|
{0.0, 1.0, 0.0}, /* green - 583.33 */
|
|
{0.0, 0.0, 1.0}, /* blue - 666.67 */
|
|
{1.0, 0.0, 1.0}, /* magenta - 750.00 */
|
|
|
|
{1.0, 1.0, 0.0}, /* yellow - 833.33 */
|
|
{1.0, 0.0, 0.0}, /* red - 916.67 */
|
|
{0.0, 1.0, 1.0}, /* cyan - 999 */
|
|
};
|
|
|
|
float spectrumW[][3] = {
|
|
{1.0, 1.0, 0.0}, /* yellow - 0 */
|
|
{1.0, 1.0, 1.0}, /* white */
|
|
{0.0, 0.0, 1.0}, /* blue - 83.333 */
|
|
{1.0, 1.0, 1.0}, /* white */
|
|
{1.0, 0.0, 0.0}, /* red - 166.67 */
|
|
|
|
{1.0, 1.0, 1.0}, /* white */
|
|
{0.0, 1.0, 0.0}, /* green - 250.00 */
|
|
{1.0, 1.0, 1.0}, /* white */
|
|
{1.0, 0.0, 1.0}, /* magenta - 333.33 */
|
|
{1.0, 1.0, 1.0}, /* white */
|
|
|
|
{0.0, 1.0, 1.0}, /* cyan - 416.67 */
|
|
{1.0, 1.0, 1.0}, /* white */
|
|
{1.0, 1.0, 0.0}, /* yellow - 500.00 */
|
|
{1.0, 1.0, 1.0}, /* white */
|
|
{0.0, 1.0, 0.0}, /* green - 583.33 */
|
|
|
|
{1.0, 1.0, 1.0}, /* white */
|
|
{0.0, 0.0, 1.0}, /* blue - 666.67 */
|
|
{1.0, 1.0, 1.0}, /* white */
|
|
{1.0, 0.0, 1.0}, /* magenta - 750.00 */
|
|
{1.0, 1.0, 1.0}, /* white */
|
|
|
|
{1.0, 1.0, 0.0}, /* yellow - 833.33 */
|
|
{1.0, 1.0, 1.0}, /* white */
|
|
{1.0, 0.0, 0.0}, /* red - 916.67 */
|
|
{1.0, 1.0, 1.0}, /* white */
|
|
{0.0, 1.0, 1.0}, /* cyan - 999 */
|
|
};
|
|
|
|
float spectrumO[29][3] = {
|
|
/* a rainbow with perceptive color balancing and extra blue/red at the ends */
|
|
{1.0, 0.0, 1.0}, /* violet */
|
|
{0.8F, 0.0, 1.0},
|
|
|
|
{0.5F, 0.0, 1.0}, /* blend */
|
|
|
|
{0.0, 0.0, 1.0}, /* blue */
|
|
{0.0, 0.0, 1.0}, /* blue */
|
|
{0.0, 0.2F, 1.0},
|
|
|
|
{0.0, 0.5F, 1.0}, /* blend */
|
|
|
|
{0.0, 0.8F, 1.0},
|
|
{0.0, 1.0, 1.0}, /* cyan */
|
|
{0.0, 1.0, 0.8F},
|
|
|
|
{0.0, 1.0, 0.5F}, /* blend */
|
|
|
|
{0.0, 1.0, 0.2F},
|
|
{0.0, 1.0, 0.0}, /* green */
|
|
{0.2F, 1.0, 0.0},
|
|
|
|
{0.5F, 1.0, 0.0}, /* blend */
|
|
|
|
{0.8F, 1.0, 0.0},
|
|
{1.0, 1.0, 0.0}, /* yellow */
|
|
{1.0, 0.9F, 0.0},
|
|
|
|
{1.0, 0.75F, 0.0}, /* blend */
|
|
|
|
{1.0, 0.6F, 0.0},
|
|
{1.0, 0.5F, 0.0}, /* orange */
|
|
{1.0, 0.4F, 0.0},
|
|
|
|
{1.0, 0.3F, 0.0}, /* blend */
|
|
|
|
{1.0, 0.2F, 0.0},
|
|
{1.0, 0.0, 0.0}, /* red */
|
|
{1.0, 0.0, 0.0}, /* red */
|
|
|
|
{1.0, 0.0, 0.5F}, /* blend */
|
|
|
|
{1.0, 0.0, 0.8F}, /* violet */
|
|
{1.0, 0.0, 1.0}, /* violet */
|
|
};
|
|
|
|
/* BLUE->VIOLET->RED r546 to r909 */
|
|
/* BLUE->CYAN->GREEN->YELLOW->RED s182 to s909 */
|
|
/* BLUE->WHITE->RED w00 to */
|
|
|
|
#define reg_named_color(name, R, G, B) \
|
|
{ \
|
|
Color.emplace_back(reg_name(I, Color.size(), name)); \
|
|
set3f(Color.back().Color, R, G, B); \
|
|
assert(I->Idx[name] == Color.size() - 1); \
|
|
}
|
|
|
|
reg_named_color("white", 1.F, 1.F, 1.F);
|
|
reg_named_color("black", 0.F, 0.F, 0.F);
|
|
reg_named_color("blue", 0.F, 0.F, 1.F);
|
|
reg_named_color("green", 0.F, 1.F, 0.F);
|
|
reg_named_color("red", 1.F, 0.F, 0.F);
|
|
reg_named_color("cyan", 0.F, 1.F, 1.F);
|
|
reg_named_color("yellow", 1.F, 1.F, 0.F);
|
|
reg_named_color("dash", 1.F, 1.F, 0.F);
|
|
reg_named_color("magenta", 1.F, 0.F, 1.F);
|
|
reg_named_color("salmon", 1.F, 0.6F, 0.6F);
|
|
reg_named_color("lime", 0.5F, 1.F, 0.5F);
|
|
reg_named_color("slate", 0.5F, 0.5F, 1.F);
|
|
reg_named_color("hotpink", 1.F, 0.F, 0.5F);
|
|
reg_named_color("orange", 1.F, 0.5F, 0.F);
|
|
reg_named_color("chartreuse", 0.5F, 1.F, 0.F); /* AKA puke green */
|
|
reg_named_color("limegreen", 0.F, 1.F, 0.5F);
|
|
reg_named_color("purpleblue", 0.5F, 0.F, 1.F); /* legacy name */
|
|
reg_named_color("marine", 0.F, 0.5F, 1.F);
|
|
reg_named_color("olive", 0.77F, 0.7F, 0.F);
|
|
reg_named_color("purple", 0.75F, 0.F, 0.75F);
|
|
reg_named_color("teal", 0.F, 0.75F, 0.75F);
|
|
reg_named_color("ruby", 0.6F, 0.2F, 0.2F);
|
|
reg_named_color("forest", 0.2F, 0.6F, 0.2F);
|
|
reg_named_color("deepblue", 0.25F, 0.25F, 0.65F); /* was "deep" */
|
|
reg_named_color("grey", 0.5F, 0.5F, 0.5F); /* english spelling */
|
|
reg_named_color("gray", 0.5F, 0.5F, 0.5F); /* american spelling */
|
|
reg_named_color("carbon", 0.2F, 1.F, 0.2F);
|
|
reg_named_color("nitrogen", 0.2F, 0.2F, 1.F);
|
|
reg_named_color("oxygen", 1.F, 0.3F, 0.3F);
|
|
reg_named_color("hydrogen", 0.9F, 0.9F, 0.9F);
|
|
reg_named_color("brightorange", 1.F, 0.7F, 0.2F);
|
|
reg_named_color("sulfur", 0.9F, 0.775F, 0.25F);
|
|
reg_named_color("tv_red", 1.F, 0.2F, 0.2F);
|
|
reg_named_color("tv_green", 0.2F, 1.F, 0.2F);
|
|
reg_named_color("tv_blue", 0.3F, 0.3F, 1.F);
|
|
reg_named_color("tv_yellow", 1.F, 1.F, 0.2F);
|
|
reg_named_color("yelloworange", 1.F, 0.87F, 0.37F);
|
|
reg_named_color("tv_orange", 1.F, 0.55F, 0.15F);
|
|
reg_named_color("br0", 0.1F, 0.1F, 1.F);
|
|
reg_named_color("br1", 0.2F, 0.1F, 0.9F);
|
|
reg_named_color("br2", 0.3F, 0.1F, 0.8F);
|
|
reg_named_color("br3", 0.4F, 0.1F, 0.7F);
|
|
reg_named_color("br4", 0.5F, 0.1F, 0.6F);
|
|
reg_named_color("br5", 0.6F, 0.1F, 0.5F);
|
|
reg_named_color("br6", 0.7F, 0.1F, 0.4F);
|
|
reg_named_color("br7", 0.8F, 0.1F, 0.3F);
|
|
reg_named_color("br8", 0.9F, 0.1F, 0.2F);
|
|
reg_named_color("br9", 1.F, 0.1F, 0.1F);
|
|
reg_named_color("pink", 1.F, 0.65F, 0.85F);
|
|
reg_named_color("firebrick", 0.698F, 0.13F, 0.13F);
|
|
reg_named_color("chocolate", 0.555F, 0.222F, 0.111F);
|
|
reg_named_color("brown", 0.65F, 0.32F, 0.17F);
|
|
reg_named_color("wheat", 0.99F, 0.82F, 0.65F);
|
|
reg_named_color("violet", 1.F, 0.5F, 1.F);
|
|
|
|
/* greybow */
|
|
|
|
strcpy(name, "grey00"); /* english spelling */
|
|
for(a = 0; a < 100; a = a + 1) {
|
|
name[5] = (a % 10) + '0';
|
|
name[4] = ((a % 100) / 10) + '0';
|
|
/* sprintf(color->Name,"grey%02d",a); */
|
|
reg_named_color(name, a / 99.F, a / 99.F, a / 99.F);
|
|
}
|
|
|
|
reg_named_color("lightmagenta", 1.F, 0.2F, 0.8F);
|
|
|
|
#define A_DIV 83.333333333F
|
|
|
|
/* full spectrum (s000-s999) */
|
|
|
|
strcpy(name, "s000");
|
|
for(a = 0; a < 1000; a = a + 1) {
|
|
set1 = (int) (a / A_DIV);
|
|
name[3] = (a % 10) + '0';
|
|
name[2] = ((a % 100) / 10) + '0';
|
|
name[1] = ((a % 1000) / 100) + '0';
|
|
/* sprintf(color->Name,"s%03d",a); */
|
|
f = 1.0F - (a - (set1 * A_DIV)) / A_DIV;
|
|
reg_named_color(name,
|
|
f * spectrumS[set1][0] + (1.F - f) * spectrumS[set1 + 1][0],
|
|
f * spectrumS[set1][1] + (1.F - f) * spectrumS[set1 + 1][1],
|
|
f * spectrumS[set1][2] + (1.F - f) * spectrumS[set1 + 1][2]);
|
|
}
|
|
|
|
/* offset & reversed full spectrum (r000-r999) */
|
|
|
|
strcpy(name, "r000");
|
|
for(a = 0; a < 1000; a = a + 1) {
|
|
set1 = (int) (a / A_DIV);
|
|
/* sprintf(color->Name,"r%03d",a); */
|
|
name[3] = (a % 10) + '0';
|
|
name[2] = ((a % 100) / 10) + '0';
|
|
name[1] = ((a % 1000) / 100) + '0';
|
|
f = 1.0F - (a - (set1 * A_DIV)) / A_DIV;
|
|
reg_named_color(name,
|
|
f * spectrumR[set1][0] + (1.F - f) * spectrumR[set1 + 1][0],
|
|
f * spectrumR[set1][1] + (1.F - f) * spectrumR[set1 + 1][1],
|
|
f * spectrumR[set1][2] + (1.F - f) * spectrumR[set1 + 1][2]);
|
|
}
|
|
|
|
/* complementary spectra (c000-c999) */
|
|
|
|
strcpy(name, "c000");
|
|
for(a = 0; a < 1000; a = a + 1) {
|
|
set1 = (int) (a / A_DIV);
|
|
/* sprintf(color->Name,"c%03d",a); */
|
|
name[3] = (a % 10) + '0';
|
|
name[2] = ((a % 100) / 10) + '0';
|
|
name[1] = ((a % 1000) / 100) + '0';
|
|
f = 1.0F - (a - (set1 * A_DIV)) / A_DIV;
|
|
reg_named_color(name,
|
|
f * spectrumC[set1][0] + (1.F - f) * spectrumC[set1 + 1][0],
|
|
f * spectrumC[set1][1] + (1.F - f) * spectrumC[set1 + 1][1],
|
|
f * spectrumC[set1][2] + (1.F - f) * spectrumC[set1 + 1][2]);
|
|
}
|
|
|
|
#define W_DIV 41.666666667F
|
|
|
|
/* complementary spectra separated by white (w000-w999) */
|
|
|
|
strcpy(name, "w000");
|
|
for(a = 0; a < 1000; a = a + 1) {
|
|
set1 = (int) (a / W_DIV);
|
|
/* sprintf(color->Name,"w%03d",a); */
|
|
name[3] = (a % 10) + '0';
|
|
name[2] = ((a % 100) / 10) + '0';
|
|
name[1] = ((a % 1000) / 100) + '0';
|
|
f = 1.0F - (a - (set1 * W_DIV)) / W_DIV;
|
|
reg_named_color(name,
|
|
f * spectrumW[set1][0] + (1.F - f) * spectrumW[set1 + 1][0],
|
|
f * spectrumW[set1][1] + (1.F - f) * spectrumW[set1 + 1][1],
|
|
f * spectrumW[set1][2] + (1.F - f) * spectrumW[set1 + 1][2]);
|
|
}
|
|
|
|
reg_named_color("density", 0.1F, 0.1F, 0.6F);
|
|
|
|
strcpy(name, "gray00"); /* american */
|
|
for(a = 0; a < 100; a = a + 1) {
|
|
name[5] = (a % 10) + '0';
|
|
name[4] = ((a % 100) / 10) + '0';
|
|
/* sprintf(color->Name,"gray%02d",a); */
|
|
reg_named_color(name, a / 99.F, a / 99.F, a / 99.F);
|
|
}
|
|
|
|
/* original full spectrum, with extra blue and red at the ends (o000-o999) */
|
|
|
|
#define B_DIV 35.7143F
|
|
|
|
strcpy(name, "o000");
|
|
for(a = 0; a < 1000; a = a + 1) {
|
|
set1 = (int) (a / B_DIV);
|
|
name[3] = (a % 10) + '0';
|
|
name[2] = ((a % 100) / 10) + '0';
|
|
name[1] = ((a % 1000) / 100) + '0';
|
|
/* sprintf(color->Name,"o%03d",a); */
|
|
f = 1.0F - (a - (set1 * B_DIV)) / B_DIV;
|
|
reg_named_color(name,
|
|
f * spectrumO[set1][0] + (1.F - f) * spectrumO[set1 + 1][0],
|
|
f * spectrumO[set1][1] + (1.F - f) * spectrumO[set1 + 1][1],
|
|
f * spectrumO[set1][2] + (1.F - f) * spectrumO[set1 + 1][2]);
|
|
}
|
|
|
|
reg_named_color("paleyellow", 1.F, 1.F, 0.5F);
|
|
reg_named_color("aquamarine", 0.5F, 1.F, 1.F);
|
|
reg_named_color("deepsalmon", 1.F, 0.5F, 0.5F);
|
|
reg_named_color("palegreen", 0.65F, 0.9F, 0.65F);
|
|
reg_named_color("deepolive", 0.6F, 0.6F, 0.1F);
|
|
reg_named_color("deeppurple", 0.6F, 0.1F, 0.6F);
|
|
reg_named_color("deepteal", 0.1F, 0.6F, 0.6F);
|
|
reg_named_color("lightblue", 0.75F, 0.75F, 1.F);
|
|
reg_named_color("lightorange", 1.F, 0.8F, 0.5F);
|
|
reg_named_color("palecyan", 0.8F, 1.F, 1.F);
|
|
reg_named_color("lightteal", 0.4F, 0.7F, 0.7F);
|
|
reg_named_color("splitpea", 0.52F, 0.75F, 0.F);
|
|
reg_named_color("raspberry", 0.7F, 0.3F, 0.4F);
|
|
reg_named_color("sand", 0.72F, 0.55F, 0.3F);
|
|
reg_named_color("smudge", 0.55F, 0.7F, 0.4F);
|
|
reg_named_color("violetpurple", 0.55F, 0.25F, 0.6F);
|
|
reg_named_color("dirtyviolet", 0.7F, 0.5F, 0.5F);
|
|
|
|
// was deepsalmon (duplicated name!)
|
|
reg_named_color("_deepsalmon", 1.F, 0.42F, 0.42F);
|
|
|
|
reg_named_color("lightpink", 1.F, 0.75F, 0.87F);
|
|
reg_named_color("greencyan", 0.25F, 1.F, 0.75F);
|
|
reg_named_color("limon", 0.75F, 1.F, 0.25F);
|
|
reg_named_color("skyblue", 0.2F, 0.5F, 0.8F);
|
|
reg_named_color("bluewhite", 0.85F, 0.85F, 1.F);
|
|
reg_named_color("warmpink", 0.85F, 0.2F, 0.5F);
|
|
reg_named_color("darksalmon", 0.73F, 0.55F, 0.52F);
|
|
reg_named_color("helium", 0.850980392F, 1.F, 1.F);
|
|
reg_named_color("lithium", 0.8F, 0.501960784F, 1.F);
|
|
reg_named_color("beryllium", 0.760784314F, 1.F, 0.F);
|
|
reg_named_color("boron", 1.F, 0.709803922F, 0.709803922F);
|
|
reg_named_color("fluorine", 0.701960784F, 1.F, 1.F);
|
|
reg_named_color("neon", 0.701960784F, 0.890196078F, 0.960784314F);
|
|
reg_named_color("sodium", 0.670588235F, 0.360784314F, 0.949019608F);
|
|
reg_named_color("magnesium", 0.541176471F, 1.F, 0.F);
|
|
reg_named_color("aluminum", 0.749019608F, 0.650980392F, 0.650980392F);
|
|
reg_named_color("silicon", 0.941176471F, 0.784313725F, 0.62745098F);
|
|
reg_named_color("phosphorus", 1.F, 0.501960784F, 0.F);
|
|
reg_named_color("chlorine", 0.121568627F, 0.941176471F, 0.121568627F);
|
|
reg_named_color("argon", 0.501960784F, 0.819607843F, 0.890196078F);
|
|
reg_named_color("potassium", 0.560784314F, 0.250980392F, 0.831372549F);
|
|
reg_named_color("calcium", 0.239215686F, 1.F, 0.F);
|
|
reg_named_color("scandium", 0.901960784F, 0.901960784F, 0.901960784F);
|
|
reg_named_color("titanium", 0.749019608F, 0.760784314F, 0.780392157F);
|
|
reg_named_color("vanadium", 0.650980392F, 0.650980392F, 0.670588235F);
|
|
reg_named_color("chromium", 0.541176471F, 0.6F, 0.780392157F);
|
|
reg_named_color("manganese", 0.611764706F, 0.478431373F, 0.780392157F);
|
|
reg_named_color("iron", 0.878431373F, 0.4F, 0.2F);
|
|
reg_named_color("cobalt", 0.941176471F, 0.564705882F, 0.62745098F);
|
|
reg_named_color("nickel", 0.31372549F, 0.815686275F, 0.31372549F);
|
|
reg_named_color("copper", 0.784313725F, 0.501960784F, 0.2F);
|
|
reg_named_color("zinc", 0.490196078F, 0.501960784F, 0.690196078F);
|
|
reg_named_color("gallium", 0.760784314F, 0.560784314F, 0.560784314F);
|
|
reg_named_color("germanium", 0.4F, 0.560784314F, 0.560784314F);
|
|
reg_named_color("arsenic", 0.741176471F, 0.501960784F, 0.890196078F);
|
|
reg_named_color("selenium", 1.F, 0.631372549F, 0.F);
|
|
reg_named_color("bromine", 0.650980392F, 0.160784314F, 0.160784314F);
|
|
reg_named_color("krypton", 0.360784314F, 0.721568627F, 0.819607843F);
|
|
reg_named_color("rubidium", 0.439215686F, 0.180392157F, 0.690196078F);
|
|
reg_named_color("strontium", 0.F, 1.F, 0.F);
|
|
reg_named_color("yttrium", 0.580392157F, 1.F, 1.F);
|
|
reg_named_color("zirconium", 0.580392157F, 0.878431373F, 0.878431373F);
|
|
reg_named_color("niobium", 0.450980392F, 0.760784314F, 0.788235294F);
|
|
reg_named_color("molybdenum", 0.329411765F, 0.709803922F, 0.709803922F);
|
|
reg_named_color("technetium", 0.231372549F, 0.619607843F, 0.619607843F);
|
|
reg_named_color("ruthenium", 0.141176471F, 0.560784314F, 0.560784314F);
|
|
reg_named_color("rhodium", 0.039215686F, 0.490196078F, 0.549019608F);
|
|
reg_named_color("palladium", 0.F, 0.411764706F, 0.521568627F);
|
|
reg_named_color("silver", 0.752941176F, 0.752941176F, 0.752941176F);
|
|
reg_named_color("cadmium", 1.F, 0.850980392F, 0.560784314F);
|
|
reg_named_color("indium", 0.650980392F, 0.458823529F, 0.450980392F);
|
|
reg_named_color("tin", 0.4F, 0.501960784F, 0.501960784F);
|
|
reg_named_color("antimony", 0.619607843F, 0.388235294F, 0.709803922F);
|
|
reg_named_color("tellurium", 0.831372549F, 0.478431373F, 0.F);
|
|
reg_named_color("iodine", 0.580392157F, 0.F, 0.580392157F);
|
|
reg_named_color("xenon", 0.258823529F, 0.619607843F, 0.690196078F);
|
|
reg_named_color("cesium", 0.341176471F, 0.090196078F, 0.560784314F);
|
|
reg_named_color("barium", 0.F, 0.788235294F, 0.F);
|
|
reg_named_color("lanthanum", 0.439215686F, 0.831372549F, 1.F);
|
|
reg_named_color("cerium", 1.F, 1.F, 0.780392157F);
|
|
reg_named_color("praseodymium", 0.850980392F, 1.F, 0.780392157F);
|
|
reg_named_color("neodymium", 0.780392157F, 1.F, 0.780392157F);
|
|
reg_named_color("promethium", 0.639215686F, 1.F, 0.780392157F);
|
|
reg_named_color("samarium", 0.560784314F, 1.F, 0.780392157F);
|
|
reg_named_color("europium", 0.380392157F, 1.F, 0.780392157F);
|
|
reg_named_color("gadolinium", 0.270588235F, 1.F, 0.780392157F);
|
|
reg_named_color("terbium", 0.188235294F, 1.F, 0.780392157F);
|
|
reg_named_color("dysprosium", 0.121568627F, 1.F, 0.780392157F);
|
|
reg_named_color("holmium", 0.F, 1.F, 0.611764706F);
|
|
reg_named_color("erbium", 0.F, 0.901960784F, 0.458823529F);
|
|
reg_named_color("thulium", 0.F, 0.831372549F, 0.321568627F);
|
|
reg_named_color("ytterbium", 0.F, 0.749019608F, 0.219607843F);
|
|
reg_named_color("lutetium", 0.F, 0.670588235F, 0.141176471F);
|
|
reg_named_color("hafnium", 0.301960784F, 0.760784314F, 1.F);
|
|
reg_named_color("tantalum", 0.301960784F, 0.650980392F, 1.F);
|
|
reg_named_color("tungsten", 0.129411765F, 0.580392157F, 0.839215686F);
|
|
reg_named_color("rhenium", 0.149019608F, 0.490196078F, 0.670588235F);
|
|
reg_named_color("osmium", 0.149019608F, 0.4F, 0.588235294F);
|
|
reg_named_color("iridium", 0.090196078F, 0.329411765F, 0.529411765F);
|
|
reg_named_color("platinum", 0.815686275F, 0.815686275F, 0.878431373F);
|
|
reg_named_color("gold", 1.F, 0.819607843F, 0.137254902F);
|
|
reg_named_color("mercury", 0.721568627F, 0.721568627F, 0.815686275F);
|
|
reg_named_color("thallium", 0.650980392F, 0.329411765F, 0.301960784F);
|
|
reg_named_color("lead", 0.341176471F, 0.349019608F, 0.380392157F);
|
|
reg_named_color("bismuth", 0.619607843F, 0.309803922F, 0.709803922F);
|
|
reg_named_color("polonium", 0.670588235F, 0.360784314F, 0.F);
|
|
reg_named_color("astatine", 0.458823529F, 0.309803922F, 0.270588235F);
|
|
reg_named_color("radon", 0.258823529F, 0.509803922F, 0.588235294F);
|
|
reg_named_color("francium", 0.258823529F, 0.F, 0.4F);
|
|
reg_named_color("radium", 0.F, 0.490196078F, 0.F);
|
|
reg_named_color("actinium", 0.439215686F, 0.670588235F, 0.980392157F);
|
|
reg_named_color("thorium", 0.F, 0.729411765F, 1.F);
|
|
reg_named_color("protactinium", 0.F, 0.631372549F, 1.F);
|
|
reg_named_color("uranium", 0.F, 0.560784314F, 1.F);
|
|
reg_named_color("neptunium", 0.F, 0.501960784F, 1.F);
|
|
reg_named_color("plutonium", 0.F, 0.419607843F, 1.F);
|
|
reg_named_color("americium", 0.329411765F, 0.360784314F, 0.949019608F);
|
|
reg_named_color("curium", 0.470588235F, 0.360784314F, 0.890196078F);
|
|
reg_named_color("berkelium", 0.541176471F, 0.309803922F, 0.890196078F);
|
|
reg_named_color("californium", 0.631372549F, 0.211764706F, 0.831372549F);
|
|
reg_named_color("einsteinium", 0.701960784F, 0.121568627F, 0.831372549F);
|
|
reg_named_color("fermium", 0.701960784F, 0.121568627F, 0.729411765F);
|
|
reg_named_color("mendelevium", 0.701960784F, 0.050980392F, 0.650980392F);
|
|
reg_named_color("nobelium", 0.741176471F, 0.050980392F, 0.529411765F);
|
|
reg_named_color("lawrencium", 0.780392157F, 0.F, 0.4F);
|
|
reg_named_color("rutherfordium", 0.8F, 0.F, 0.349019608F);
|
|
reg_named_color("dubnium", 0.819607843F, 0.F, 0.309803922F);
|
|
reg_named_color("seaborgium", 0.850980392F, 0.F, 0.270588235F);
|
|
reg_named_color("bohrium", 0.878431373F, 0.F, 0.219607843F);
|
|
reg_named_color("hassium", 0.901960784F, 0.F, 0.180392157F);
|
|
reg_named_color("meitnerium", 0.921568627F, 0.F, 0.149019608F);
|
|
reg_named_color("deuterium", 0.9F, 0.9F, 0.9F);
|
|
reg_named_color("lonepair", 0.5F, 0.5F, 0.5F);
|
|
reg_named_color("pseudoatom", 0.9F, 0.9F, 0.9F);
|
|
}
|
|
|
|
int ColorTableLoad(PyMOLGlobals * G, const char *fname, float gamma, int quiet)
|
|
{
|
|
CColor *I = G->Color;
|
|
int ok = true;
|
|
|
|
I->Gamma = gamma;
|
|
if(!fname[0]) {
|
|
ColorUpdateFromLut(G, -1);
|
|
} else {
|
|
int width = 512, height = 512;
|
|
if(!strcmp(fname, "rgb")) {
|
|
if(!I->ColorTable.empty()) {
|
|
I->ColorTable.clear();
|
|
PRINTFB(G, FB_Color, FB_Actions)
|
|
" Color: purged table; restoring RGB colors.\n" ENDFB(G);
|
|
}
|
|
ColorUpdateFromLut(G, -1);
|
|
} else if(!strcmp(fname, "greyscale")) {
|
|
|
|
int x, y;
|
|
unsigned int r = 0, g = 0, b = 0;
|
|
unsigned int *pixel, mask, *p;
|
|
unsigned int rc;
|
|
|
|
if(I->BigEndian)
|
|
mask = 0x000000FF;
|
|
else
|
|
mask = 0xFF000000;
|
|
|
|
I->ColorTable.resize(512 * 512);
|
|
|
|
p = I->ColorTable.data();
|
|
for(x = 0; x < width; x++)
|
|
for(y = 0; y < height; y++)
|
|
*(p++) = mask;
|
|
|
|
for(y = 0; y < height; y++)
|
|
for(x = 0; x < width; x++) {
|
|
rc = (r + g + b)/3;
|
|
|
|
pixel = I->ColorTable.data() + ((width) * y) + x;
|
|
if(I->BigEndian) {
|
|
*(pixel) = mask | (rc << 24) | (rc << 16) | (rc << 8);
|
|
} else {
|
|
*(pixel) = mask | (rc << 16) | (rc << 8) | rc;
|
|
}
|
|
b = b + 4;
|
|
if(!(0xFF & b)) {
|
|
b = 0;
|
|
g = g + 4;
|
|
if(!(0xFF & g)) {
|
|
g = 0;
|
|
r = r + 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!quiet) {
|
|
PRINTFB(G, FB_Color, FB_Actions)
|
|
" Color: defined table '%s'.\n", fname ENDFB(G);
|
|
}
|
|
|
|
ColorUpdateFromLut(G, -1);
|
|
ExecutiveInvalidateRep(G, cKeywordAll, cRepAll, cRepInvColor);
|
|
SceneChanged(G);
|
|
|
|
|
|
} else if(!strcmp(fname, "pymol")) {
|
|
|
|
int x, y;
|
|
unsigned int r = 0, g = 0, b = 0;
|
|
unsigned int *pixel, mask, *p;
|
|
unsigned int rc, bc, gc;
|
|
unsigned int gf, bf, rf;
|
|
|
|
float green_max = 0.75F;
|
|
float red_max = 0.95F;
|
|
float blue_max = 0.97F;
|
|
|
|
float min_factor = 0.15F;
|
|
|
|
red_max = SettingGetGlobal_f(G, cSetting_pymol_space_max_red);
|
|
green_max = SettingGetGlobal_f(G, cSetting_pymol_space_max_green);
|
|
blue_max = SettingGetGlobal_f(G, cSetting_pymol_space_max_blue);
|
|
min_factor = SettingGetGlobal_f(G, cSetting_pymol_space_min_factor);
|
|
|
|
if(I->BigEndian)
|
|
mask = 0x000000FF;
|
|
else
|
|
mask = 0xFF000000;
|
|
|
|
I->ColorTable.resize(512 * 512);
|
|
|
|
p = I->ColorTable.data();
|
|
for(x = 0; x < width; x++)
|
|
for(y = 0; y < height; y++)
|
|
*(p++) = mask;
|
|
|
|
for(y = 0; y < height; y++)
|
|
for(x = 0; x < width; x++) {
|
|
rc = r;
|
|
gc = g;
|
|
bc = b;
|
|
|
|
if((r >= g) && (r >= b)) {
|
|
if(rc > 255 * red_max) {
|
|
rc = (unsigned int) (red_max * 255);
|
|
bc = bc * rc / r;
|
|
gc = gc * rc / r;
|
|
}
|
|
} else if((g >= b) && (g >= r)) {
|
|
if(gc > 255 * green_max) {
|
|
gc = (unsigned int) (green_max * 255);
|
|
bc = bc * gc / g;
|
|
rc = rc * gc / g;
|
|
}
|
|
} else if((b >= g) && (b >= r)) {
|
|
if(bc > 255 * blue_max) {
|
|
bc = (unsigned int) (blue_max * 255);
|
|
gc = gc * bc / b;
|
|
rc = rc * bc / b;
|
|
}
|
|
}
|
|
|
|
rf = (int) (min_factor * rc + 0.49999F);
|
|
gf = (int) (min_factor * gc + 0.49999F);
|
|
bf = (int) (min_factor * bc + 0.49999F);
|
|
|
|
if(rc < gf)
|
|
rc = (int) gf;
|
|
if(bc < gf)
|
|
bc = (int) gf;
|
|
|
|
if(rc < bf)
|
|
rc = (int) bf;
|
|
if(gc < bf)
|
|
gc = (int) bf;
|
|
|
|
if(gc < rf)
|
|
gc = (int) rf;
|
|
if(bc < rf)
|
|
bc = (int) rf;
|
|
|
|
if(rc > 255)
|
|
rc = 255;
|
|
if(bc > 255)
|
|
bc = 255;
|
|
if(gc > 255)
|
|
gc = 255;
|
|
|
|
pixel = I->ColorTable.data() + ((width) * y) + x;
|
|
if(I->BigEndian) {
|
|
*(pixel) = mask | (rc << 24) | (gc << 16) | (bc << 8);
|
|
} else {
|
|
*(pixel) = mask | (bc << 16) | (gc << 8) | rc;
|
|
}
|
|
b = b + 4;
|
|
if(!(0xFF & b)) {
|
|
b = 0;
|
|
g = g + 4;
|
|
if(!(0xFF & g)) {
|
|
g = 0;
|
|
r = r + 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!quiet) {
|
|
PRINTFB(G, FB_Color, FB_Actions)
|
|
" Color: defined table '%s'.\n", fname ENDFB(G);
|
|
}
|
|
|
|
ColorUpdateFromLut(G, -1);
|
|
ExecutiveInvalidateRep(G, cKeywordAll, cRepAll, cRepInvColor);
|
|
SceneChanged(G);
|
|
|
|
} else {
|
|
if(strlen(fname)) {
|
|
|
|
auto image = MyPNGRead(fname);
|
|
if(image) {
|
|
std::tie(width, height) = image->getSize();
|
|
if((width == 512) && (height == 512)) {
|
|
auto imageSize = width * height;
|
|
I->ColorTable.resize(imageSize);
|
|
std::copy(image->pixels(), image->pixels() + imageSize, I->ColorTable.data());
|
|
|
|
if(!quiet) {
|
|
PRINTFB(G, FB_Color, FB_Actions)
|
|
" Color: loaded table '%s'.\n", fname ENDFB(G);
|
|
}
|
|
|
|
ColorUpdateFromLut(G, -1);
|
|
|
|
} else {
|
|
PRINTFB(G, FB_Color, FB_Errors)
|
|
" ColorTableLoad-Error: invalid dimensions w x h = %d x %d; should be 512 x 512.\n",
|
|
width, height ENDFB(G);
|
|
|
|
ok = false;
|
|
}
|
|
} else {
|
|
PRINTFB(G, FB_Color, FB_Errors)
|
|
" ColorTableLoad-Error: unable to load '%s'.\n", fname ENDFB(G);
|
|
ok = false;
|
|
}
|
|
} else {
|
|
PRINTFB(G, FB_Color, FB_Actions)
|
|
" Color: purged table; colors unchanged.\n" ENDFB(G);
|
|
I->ColorTable.clear();
|
|
}
|
|
}
|
|
}
|
|
if(ok) {
|
|
ExecutiveInvalidateRep(G, cKeywordAll, cRepAll, cRepInvColor);
|
|
SceneChanged(G);
|
|
}
|
|
return (ok);
|
|
}
|
|
|
|
static void lookup_color(CColor * I, const float *in, float *out, int big_endian)
|
|
{
|
|
const float _1 = 1.0F;
|
|
unsigned int *table = I->ColorTable.data();
|
|
if(table) {
|
|
unsigned int r, g, b, rr, gr, br;
|
|
unsigned int ra, ga, ba;
|
|
unsigned int rc[2][2][2], gc[2][2][2], bc[2][2][2];
|
|
unsigned int *entry;
|
|
int x, y, z;
|
|
float fr, fg, fb, frm1x, fgm1, fbm1, rct, gct, bct;
|
|
const float _2 = 2.0F, _0 = 0.0F, _05 = 0.5F, _04999 = 0.4999F;
|
|
const float inv255 = 1.0F / 255.0F;
|
|
|
|
r = ((int) (255 * in[0] + _05)) & 0xFF;
|
|
g = ((int) (255 * in[1] + _05)) & 0xFF;
|
|
b = ((int) (255 * in[2] + _05)) & 0xFF;
|
|
|
|
rr = r & 0x3;
|
|
gr = g & 0x3;
|
|
br = b & 0x3;
|
|
|
|
r = (r >> 2);
|
|
g = (g >> 2);
|
|
b = (b >> 2);
|
|
|
|
/* now for a crude little trilinear */
|
|
|
|
for(x = 0; x < 2; x++) {
|
|
ra = r + x;
|
|
if(ra > 63)
|
|
ra = 63;
|
|
for(y = 0; y < 2; y++) {
|
|
ga = g + y;
|
|
if(ga > 63)
|
|
ga = 63;
|
|
for(z = 0; z < 2; z++) {
|
|
ba = b + z;
|
|
if(ba > 63)
|
|
ba = 63;
|
|
|
|
entry = table + (ra << 12) + (ga << 6) + ba;
|
|
|
|
if(big_endian) {
|
|
rc[x][y][z] = 0xFF & ((*entry) >> 24);
|
|
gc[x][y][z] = 0xFF & ((*entry) >> 16);
|
|
bc[x][y][z] = 0xFF & ((*entry) >> 8);
|
|
} else {
|
|
rc[x][y][z] = 0xFF & ((*entry));
|
|
gc[x][y][z] = 0xFF & ((*entry) >> 8);
|
|
bc[x][y][z] = 0xFF & ((*entry) >> 16);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
frm1x = rr / 4.0F;
|
|
fgm1 = gr / 4.0F;
|
|
fbm1 = br / 4.0F;
|
|
|
|
fr = 1.0F - frm1x;
|
|
fg = 1.0F - fgm1;
|
|
fb = 1.0F - fbm1;
|
|
|
|
rct = _04999 +
|
|
(fr * fg * fb * rc[0][0][0]) +
|
|
(frm1x * fg * fb * rc[1][0][0]) +
|
|
(fr * fgm1 * fb * rc[0][1][0]) +
|
|
(fr * fg * fbm1 * rc[0][0][1]) +
|
|
(frm1x * fgm1 * fb * rc[1][1][0]) +
|
|
(fr * fgm1 * fbm1 * rc[0][1][1]) +
|
|
(frm1x * fg * fbm1 * rc[1][0][1]) + (frm1x * fgm1 * fbm1 * rc[1][1][1]);
|
|
|
|
gct = _04999 +
|
|
(fr * fg * fb * gc[0][0][0]) +
|
|
(frm1x * fg * fb * gc[1][0][0]) +
|
|
(fr * fgm1 * fb * gc[0][1][0]) +
|
|
(fr * fg * fbm1 * gc[0][0][1]) +
|
|
(frm1x * fgm1 * fb * gc[1][1][0]) +
|
|
(fr * fgm1 * fbm1 * gc[0][1][1]) +
|
|
(frm1x * fg * fbm1 * gc[1][0][1]) + (frm1x * fgm1 * fbm1 * gc[1][1][1]);
|
|
|
|
bct = _04999 +
|
|
(fr * fg * fb * bc[0][0][0]) +
|
|
(frm1x * fg * fb * bc[1][0][0]) +
|
|
(fr * fgm1 * fb * bc[0][1][0]) +
|
|
(fr * fg * fbm1 * bc[0][0][1]) +
|
|
(frm1x * fgm1 * fb * bc[1][1][0]) +
|
|
(fr * fgm1 * fbm1 * bc[0][1][1]) +
|
|
(frm1x * fg * fbm1 * bc[1][0][1]) + (frm1x * fgm1 * fbm1 * bc[1][1][1]);
|
|
|
|
if(r >= 63)
|
|
rct += rr;
|
|
if(g >= 63)
|
|
gct += gr;
|
|
if(b >= 63)
|
|
bct += br;
|
|
|
|
if(rct <= _2)
|
|
rct = _0; /* make sure black is black */
|
|
if(gct <= _2)
|
|
gct = _0;
|
|
if(bct <= _2)
|
|
bct = _0;
|
|
|
|
out[0] = rct * inv255;
|
|
out[1] = gct * inv255;
|
|
out[2] = bct * inv255;
|
|
} else {
|
|
out[0] = in[0];
|
|
out[1] = in[1];
|
|
out[2] = in[2];
|
|
}
|
|
|
|
if((I->Gamma != 1.0F) && (I->Gamma > R_SMALL4)) {
|
|
float inv_gamma = 1.0F / I->Gamma;
|
|
float inp = (out[0] + out[1] + out[2]) * (1 / 3.0F);
|
|
if(inp >= R_SMALL4) {
|
|
float sig = (float) (pow(inp, inv_gamma)) / inp;
|
|
out[0] *= sig;
|
|
out[1] *= sig;
|
|
out[2] *= sig;
|
|
}
|
|
}
|
|
|
|
if(out[0] > _1)
|
|
out[0] = _1;
|
|
if(out[1] > _1)
|
|
out[1] = _1;
|
|
if(out[2] > _1)
|
|
out[2] = _1;
|
|
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
void ColorUpdateFromLut(PyMOLGlobals * G, int index)
|
|
{
|
|
int i;
|
|
int once = false;
|
|
CColor *I = G->Color;
|
|
float *color, *new_color;
|
|
|
|
I->LUTActive = (!I->ColorTable.empty() || (I->Gamma != 1.0F));
|
|
|
|
i = index;
|
|
if(index >= 0) {
|
|
once = true;
|
|
}
|
|
for(i = 0; i < I->Color.size(); i++) {
|
|
if(!once)
|
|
index = i;
|
|
|
|
if(index < I->Color.size()) {
|
|
if(!I->LUTActive) {
|
|
I->Color[index].LutColorFlag = false;
|
|
} else if(!I->Color[index].Fixed) {
|
|
color = I->Color[index].Color;
|
|
new_color = I->Color[index].LutColor;
|
|
lookup_color(I, color, new_color, I->BigEndian);
|
|
|
|
PRINTFD(G, FB_Color)
|
|
"%5.3f %5.3f %5.3f -> %5.3f %5.3f %5.3f\n",
|
|
color[0], color[1], color[2], new_color[0], new_color[1], new_color[2]
|
|
ENDFD;
|
|
|
|
I->Color[index].LutColorFlag = true;
|
|
}
|
|
}
|
|
|
|
if(once)
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
int ColorLookupColor(PyMOLGlobals * G, float *color)
|
|
{
|
|
CColor *I = G->Color;
|
|
if(I->LUTActive) {
|
|
lookup_color(I, color, color, I->BigEndian);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
int ColorInit(PyMOLGlobals * G)
|
|
{
|
|
CColor *I = nullptr;
|
|
|
|
if ((G->Color = new CColor())) {
|
|
I = G->Color;
|
|
unsigned int test;
|
|
unsigned char *testPtr;
|
|
|
|
test = 0xFF000000;
|
|
testPtr = (unsigned char *) &test;
|
|
I->BigEndian = (*testPtr) & 0x01;
|
|
|
|
ColorReset(G); /* will alloc I->Idx and I->Lex */
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void ColorUpdateFront(PyMOLGlobals * G, const float *back)
|
|
{
|
|
CColor *I = G->Color;
|
|
copy3f(back, I->Back);
|
|
I->Front[0] = 1.0F - back[0];
|
|
I->Front[1] = 1.0F - back[1];
|
|
I->Front[2] = 1.0F - back[2];
|
|
if(diff3f(I->Front, back) < 0.5F)
|
|
zero3f(I->Front);
|
|
}
|
|
|
|
void ColorUpdateFrontFromSettings(PyMOLGlobals * G){
|
|
int bg_gradient = SettingGet_b(G, nullptr, nullptr, cSetting_bg_gradient);
|
|
const char * bg_image_filename = SettingGet_s(G, nullptr, nullptr, cSetting_bg_image_filename);
|
|
short bg_image = bg_image_filename && bg_image_filename[0];
|
|
|
|
if (!bg_gradient){
|
|
if (!bg_image && !OrthoBackgroundDataIsSet(*G->Ortho)){
|
|
const float *v = ColorGet(G, SettingGet_color(G, nullptr, nullptr, cSetting_bg_rgb));
|
|
ColorUpdateFront(G, v);
|
|
} else {
|
|
float v[] = { 0.f, 0.f, 0.f };
|
|
ColorUpdateFront(G, v);
|
|
}
|
|
} else {
|
|
float vv[3];
|
|
const float *v = ColorGet(G, SettingGet_color(G, nullptr, nullptr, cSetting_bg_rgb_bottom));
|
|
const float *vb = ColorGet(G, SettingGet_color(G, nullptr, nullptr, cSetting_bg_rgb_top));
|
|
average3f(v, vb, vv);
|
|
ColorUpdateFront(G, vv);
|
|
}
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
const float *ColorGetSpecial(PyMOLGlobals * G, int index)
|
|
{
|
|
if(index >= 0)
|
|
return ColorGet(G, index);
|
|
else {
|
|
CColor *I = G->Color;
|
|
I->RGBColor[0] = (float) index;
|
|
I->RGBColor[1] = -1.0F;
|
|
I->RGBColor[2] = -1.0F;
|
|
return I->RGBColor;
|
|
}
|
|
}
|
|
|
|
const float *ColorGet(PyMOLGlobals * G, int index)
|
|
{
|
|
CColor *I = G->Color;
|
|
const float *ptr;
|
|
if((index >= 0) && (index < I->Color.size())) {
|
|
if(I->Color[index].LutColorFlag && SettingGetGlobal_b(G, cSetting_clamp_colors))
|
|
ptr = I->Color[index].LutColor;
|
|
else
|
|
ptr = I->Color[index].Color;
|
|
return (ptr);
|
|
} else if((index & cColor_TRGB_Mask) == cColor_TRGB_Bits) { /* a 24-bit RGB color */
|
|
I->RGBColor[0] = ((index & 0x00FF0000) >> 16) / 255.0F;
|
|
I->RGBColor[1] = ((index & 0x0000FF00) >> 8) / 255.0F;
|
|
I->RGBColor[2] = ((index & 0x000000FF)) / 255.0F;
|
|
if(I->LUTActive)
|
|
lookup_color(I, I->RGBColor, I->RGBColor, I->BigEndian);
|
|
return I->RGBColor;
|
|
} else if(index == cColorFront) {
|
|
return I->Front;
|
|
} else if(index == cColorBack) {
|
|
return I->Back;
|
|
} else {
|
|
/* invalid color id, then simply return white */
|
|
return (I->Color[0].Color);
|
|
}
|
|
}
|
|
|
|
const float *ColorGetRaw(PyMOLGlobals * G, int index)
|
|
{
|
|
CColor *I = G->Color;
|
|
const float *ptr;
|
|
if((index >= 0) && (index < I->Color.size())) {
|
|
ptr = I->Color[index].Color;
|
|
return (ptr);
|
|
} else if((index & cColor_TRGB_Mask) == cColor_TRGB_Bits) { /* a 24-bit RGB color */
|
|
I->RGBColor[0] = ((index & 0x00FF0000) >> 16) / 255.0F;
|
|
I->RGBColor[1] = ((index & 0x0000FF00) >> 8) / 255.0F;
|
|
I->RGBColor[2] = ((index & 0x000000FF)) / 255.0F;
|
|
return I->RGBColor;
|
|
} else {
|
|
/* invalid color id, then simply return white */
|
|
return (I->Color[0].Color);
|
|
}
|
|
}
|
|
|
|
int ColorGetEncoded(PyMOLGlobals * G, int index, float *color)
|
|
{
|
|
CColor *I = G->Color;
|
|
float *ptr;
|
|
if((index >= 0) && (index < I->Color.size())) {
|
|
if(I->Color[index].LutColorFlag && SettingGetGlobal_b(G, cSetting_clamp_colors))
|
|
ptr = I->Color[index].LutColor;
|
|
else
|
|
ptr = I->Color[index].Color;
|
|
copy3f(ptr, color);
|
|
} else if((index & cColor_TRGB_Mask) == cColor_TRGB_Bits) { /* a 24-bit RGB color */
|
|
float rgb_color[3];
|
|
rgb_color[0] = ((index & 0x00FF0000) >> 16) / 255.0F;
|
|
rgb_color[1] = ((index & 0x0000FF00) >> 8) / 255.0F;
|
|
rgb_color[2] = ((index & 0x000000FF)) / 255.0F;
|
|
if(I->LUTActive)
|
|
lookup_color(I, rgb_color, rgb_color, I->BigEndian);
|
|
copy3f(rgb_color, color);
|
|
} else if(index <= cColorExtCutoff) {
|
|
color[0] = (float) index;
|
|
color[1] = 0.0F;
|
|
color[2] = 0.0F;
|
|
} else if(index == cColorFront) {
|
|
copy3f(I->Front, color);
|
|
} else if(index == cColorBack) {
|
|
copy3f(I->Back, color);
|
|
} else {
|
|
color[0] = 1.0F;
|
|
color[1] = 1.0F;
|
|
color[2] = 1.0F;
|
|
/* invalid color id, then simply return white */
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Color3fToInt(PyMOLGlobals * G, const float *rgb){
|
|
unsigned int rc, gc, bc;
|
|
rc = pymol_roundf(rgb[0] * 255.);
|
|
gc = pymol_roundf(rgb[1] * 255.);
|
|
bc = pymol_roundf(rgb[2] * 255.);
|
|
return ( ( cColor_TRGB_Bits & 0xFF000000) |
|
|
( ( rc << 16 ) & 0x00FF0000) |
|
|
( ( gc << 8 ) & 0x0000FF00) |
|
|
( ( bc & 0x000000FF ) ) );
|
|
}
|
|
|
|
void ColorRenameExt(
|
|
PyMOLGlobals* G, pymol::zstring_view oldName, pymol::zstring_view newName)
|
|
{
|
|
auto I = G->Color;
|
|
|
|
// Find color idx
|
|
auto oldNameIt = I->Idx.find(oldName.c_str());
|
|
if (oldNameIt == I->Idx.end()) {
|
|
return;
|
|
}
|
|
auto idx = oldNameIt->second;
|
|
reg_name(I, idx, newName.c_str(), true);
|
|
if (ExecutiveFindObject<ObjectGadgetRamp>(G, newName) == nullptr) {
|
|
return;
|
|
}
|
|
|
|
// Find corresponding color ext and provide it the new name
|
|
auto extIt = std::find_if(I->Ext.begin(), I->Ext.end(), [oldName](const ExtRec& rec) {
|
|
return oldName == rec.Name;
|
|
});
|
|
if (extIt == I->Ext.end()) {
|
|
return;
|
|
}
|
|
auto newNameit = I->Idx.find(newName.c_str());
|
|
if (newNameit == I->Idx.end()) {
|
|
return;
|
|
}
|
|
auto& ext = *extIt;
|
|
ext.Name = newNameit->first.c_str();
|
|
}
|