File: Picking.h

package info (click to toggle)
pymol 2.5.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 42,288 kB
  • sloc: cpp: 476,472; python: 76,538; ansic: 29,510; javascript: 6,792; sh: 47; makefile: 24
file content (174 lines) | stat: -rw-r--r-- 3,970 bytes parent folder | download | duplicates (2)
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;
};