1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
/*
* Color picking
*
* (C) Schrodinger, Inc.
*/
#pragma once
#include <vector>
//! With shaders we have to pre-allocate picking color buffers, so
//! limit this to 2 passes.
constexpr auto SHADER_PICKING_PASSES_MAX = 2;
//! Transparency cutoff for cPickableThrough, smaller values are considered
//! opaque.
constexpr auto PICKABLE_THROUGH_CUTOFF = 0.1f;
//! Valid values for the `transparency_picking_mode` setting
enum {
cTransparencyPickingModePickable = 1,
cTransparencyPickingModeAuto = 2, // 0 has same effect
};
enum cPickable_t {
cPickableAtom = -1,
cPickableLabel = -2,
cPickableGadget = -3,
cPickableNoPick = -4,
cPickableThrough = -5,
};
/**
* Identifier for a pickable item like an atom, half-bond or label, within a
* pick context (object state).
*/
struct Pickable {
//! Primary index (e.g. atom index within object)
unsigned int index;
//! Secondary index (>= 0, e.g. bond index) or special value (::cPickable_t)
int bond;
// comparison
bool operator==(const Pickable& rhs) const
{
return index == rhs.index && bond == rhs.bond;
}
};
namespace pymol
{
struct CObject;
}
/**
* Generic object state identifier
*/
struct PickContext {
pymol::CObject* object = nullptr;
int state;
// comparison
bool operator==(const PickContext& rhs) const
{
return object == rhs.object && state == rhs.state;
}
};
/**
* Global identifier for a pickable item like an atom, half-bond or label
*/
struct Picking {
Pickable src;
PickContext context;
// comparison
bool operator==(const Picking& rhs) const
{
return src == rhs.src && context == rhs.context;
}
bool operator!=(const Picking& rhs) const { return !(*this == rhs); }
};
/**
* For picking everything within a rectangle (Shift+click drag selection)
*/
struct Multipick {
int x, y, w, h;
std::vector<Picking> picked;
};
/**
* Color picking index conversions
*/
class PickColorConverter
{
typedef unsigned char channel_t;
typedef unsigned int index_t;
// 12 bit default
unsigned char m_rgba_bits[4]{4, 4, 4, 0};
// Number of used bits plus check bits
unsigned char m_rgba_and_check_bits[4]{4, 4, 4, 0};
public:
// (only public for testing)
bool validateCheckBits(const channel_t* rgba) const;
//! Set the number of bits for each channel
void setRgbaBits(const int* rgba_bits, int max_check_bits = 0);
//! Get the sum of bits from all channels
unsigned getTotalBits() const
{
return m_rgba_bits[0] + m_rgba_bits[1] + m_rgba_bits[2] + m_rgba_bits[3];
}
//! Picking index from picked color
index_t indexFromColor(const channel_t* rgba) const;
//! RGBA color from picking index
void colorFromIndex(channel_t* rgba, index_t idx) const;
//! RGBA color for "no-pick" (blocks pick, but doesn't pick anything)
void colorNoPick(channel_t* rgba) const;
//! RGBA color for "pick-through" (doesn't block, can pick items below)
void colorPickThrough(channel_t* rgba) const;
};
class PickColorManager : public PickColorConverter
{
unsigned m_count = 0;
std::vector<Picking> m_identifiers;
public:
//! picking pass
unsigned m_pass = 0;
//! whether `m_identifiers` and `m_count` are complete
bool m_valid = false;
//! Running index while `!m_valid`, equal to `m_identifiers.size()` at the end
//! of a picking pass or if `m_valid`.
unsigned count() const { return m_count; }
//! Reset the count, but don't invalidate identifiers (they will be identical
//! in the next pass)
void resetCount()
{
m_count = 0;
m_valid = false;
}
//! Invalidate identifiers
void invalidate()
{
if (!m_valid) {
// protect against calls during rendering
return;
}
m_identifiers.clear();
m_valid = false;
}
bool pickColorsValid() const { return m_valid; }
void colorNext(unsigned char* color, const PickContext* context,
unsigned int index, int bond);
const Picking* getIdentifier(unsigned index) const;
};
|