1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtOpenGL module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | /*! |
43 | \class QGLColormap |
44 | \brief The QGLColormap class is used for installing custom colormaps into |
45 | a QGLWidget. |
46 | |
47 | \module OpenGL |
48 | \ingroup painting-3D |
49 | \ingroup shared |
50 | |
51 | QGLColormap provides a platform independent way of specifying and |
52 | installing indexed colormaps for a QGLWidget. QGLColormap is |
53 | especially useful when using the OpenGL color-index mode. |
54 | |
55 | Under X11 you must use an X server that supports either a \c |
56 | PseudoColor or \c DirectColor visual class. If your X server |
57 | currently only provides a \c GrayScale, \c TrueColor, \c |
58 | StaticColor or \c StaticGray visual, you will not be able to |
59 | allocate colorcells for writing. If this is the case, try setting |
60 | your X server to 8 bit mode. It should then provide you with at |
61 | least a \c PseudoColor visual. Note that you may experience |
62 | colormap flashing if your X server is running in 8 bit mode. |
63 | |
64 | The size() of the colormap is always set to 256 |
65 | colors. Note that under Windows you can also install colormaps |
66 | in child widgets. |
67 | |
68 | This class uses \l{implicit sharing} as a memory and speed |
69 | optimization. |
70 | |
71 | Example of use: |
72 | \snippet doc/src/snippets/code/src_opengl_qglcolormap.cpp 0 |
73 | |
74 | \sa QGLWidget::setColormap(), QGLWidget::colormap() |
75 | */ |
76 | |
77 | /*! |
78 | \fn Qt::HANDLE QGLColormap::handle() |
79 | |
80 | \internal |
81 | |
82 | Returns the handle for this color map. |
83 | */ |
84 | |
85 | /*! |
86 | \fn void QGLColormap::setHandle(Qt::HANDLE handle) |
87 | |
88 | \internal |
89 | |
90 | Sets the handle for this color map to \a handle. |
91 | */ |
92 | |
93 | #include "qglcolormap.h" |
94 | |
95 | QT_BEGIN_NAMESPACE |
96 | |
97 | QGLColormap::QGLColormapData QGLColormap::shared_null = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0 }; |
98 | |
99 | /*! |
100 | Construct a QGLColormap. |
101 | */ |
102 | QGLColormap::QGLColormap() |
103 | : d(&shared_null) |
104 | { |
105 | d->ref.ref(); |
106 | } |
107 | |
108 | |
109 | /*! |
110 | Construct a shallow copy of \a map. |
111 | */ |
112 | QGLColormap::QGLColormap(const QGLColormap &map) |
113 | : d(map.d) |
114 | { |
115 | d->ref.ref(); |
116 | } |
117 | |
118 | /*! |
119 | Dereferences the QGLColormap and deletes it if this was the last |
120 | reference to it. |
121 | */ |
122 | QGLColormap::~QGLColormap() |
123 | { |
124 | if (!d->ref.deref()) |
125 | cleanup(d); |
126 | } |
127 | |
128 | void QGLColormap::cleanup(QGLColormap::QGLColormapData *x) |
129 | { |
130 | delete x->cells; |
131 | x->cells = 0; |
132 | delete x; |
133 | } |
134 | |
135 | /*! |
136 | Assign a shallow copy of \a map to this QGLColormap. |
137 | */ |
138 | QGLColormap & QGLColormap::operator=(const QGLColormap &map) |
139 | { |
140 | map.d->ref.ref(); |
141 | if (!d->ref.deref()) |
142 | cleanup(d); |
143 | d = map.d; |
144 | return *this; |
145 | } |
146 | |
147 | /*! |
148 | \fn void QGLColormap::detach() |
149 | \internal |
150 | |
151 | Detaches this QGLColormap from the shared block. |
152 | */ |
153 | |
154 | void QGLColormap::detach_helper() |
155 | { |
156 | QGLColormapData *x = new QGLColormapData; |
157 | x->ref = 1; |
158 | x->cmapHandle = 0; |
159 | x->cells = 0; |
160 | if (d->cells) { |
161 | x->cells = new QVector<QRgb>(256); |
162 | *x->cells = *d->cells; |
163 | } |
164 | if (!d->ref.deref()) |
165 | cleanup(d); |
166 | d = x; |
167 | } |
168 | |
169 | /*! |
170 | Set cell at index \a idx in the colormap to color \a color. |
171 | */ |
172 | void QGLColormap::setEntry(int idx, QRgb color) |
173 | { |
174 | detach(); |
175 | if (!d->cells) |
176 | d->cells = new QVector<QRgb>(256); |
177 | d->cells->replace(idx, color); |
178 | } |
179 | |
180 | /*! |
181 | Set an array of cells in this colormap. \a count is the number of |
182 | colors that should be set, \a colors is the array of colors, and |
183 | \a base is the starting index. The first element in \a colors |
184 | is set at \a base in the colormap. |
185 | */ |
186 | void QGLColormap::setEntries(int count, const QRgb *colors, int base) |
187 | { |
188 | detach(); |
189 | if (!d->cells) |
190 | d->cells = new QVector<QRgb>(256); |
191 | |
192 | Q_ASSERT_X(colors && base >= 0 && (base + count) <= d->cells->size(), "QGLColormap::setEntries" , |
193 | "preconditions not met" ); |
194 | for (int i = 0; i < count; ++i) |
195 | setEntry(base + i, colors[i]); |
196 | } |
197 | |
198 | /*! |
199 | Returns the QRgb value in the colorcell with index \a idx. |
200 | */ |
201 | QRgb QGLColormap::entryRgb(int idx) const |
202 | { |
203 | if (d == &shared_null || !d->cells) |
204 | return 0; |
205 | else |
206 | return d->cells->at(idx); |
207 | } |
208 | |
209 | /*! |
210 | \overload |
211 | |
212 | Set the cell with index \a idx in the colormap to color \a color. |
213 | */ |
214 | void QGLColormap::setEntry(int idx, const QColor &color) |
215 | { |
216 | setEntry(idx, color.rgb()); |
217 | } |
218 | |
219 | /*! |
220 | Returns the QRgb value in the colorcell with index \a idx. |
221 | */ |
222 | QColor QGLColormap::entryColor(int idx) const |
223 | { |
224 | if (d == &shared_null || !d->cells) |
225 | return QColor(); |
226 | else |
227 | return QColor(d->cells->at(idx)); |
228 | } |
229 | |
230 | /*! |
231 | Returns true if the colormap is empty or it is not in use |
232 | by a QGLWidget; otherwise returns false. |
233 | |
234 | A colormap with no color values set is considered to be empty. |
235 | For historical reasons, a colormap that has color values set |
236 | but which is not in use by a QGLWidget is also considered empty. |
237 | |
238 | Compare size() with zero to determine if the colormap is empty |
239 | regardless of whether it is in use by a QGLWidget or not. |
240 | |
241 | \sa size() |
242 | */ |
243 | bool QGLColormap::isEmpty() const |
244 | { |
245 | return d == &shared_null || d->cells == 0 || d->cells->size() == 0 || d->cmapHandle == 0; |
246 | } |
247 | |
248 | |
249 | /*! |
250 | Returns the number of colorcells in the colormap. |
251 | */ |
252 | int QGLColormap::size() const |
253 | { |
254 | return d->cells ? d->cells->size() : 0; |
255 | } |
256 | |
257 | /*! |
258 | Returns the index of the color \a color. If \a color is not in the |
259 | map, -1 is returned. |
260 | */ |
261 | int QGLColormap::find(QRgb color) const |
262 | { |
263 | if (d->cells) |
264 | return d->cells->indexOf(color); |
265 | return -1; |
266 | } |
267 | |
268 | /*! |
269 | Returns the index of the color that is the closest match to color |
270 | \a color. |
271 | */ |
272 | int QGLColormap::findNearest(QRgb color) const |
273 | { |
274 | int idx = find(color); |
275 | if (idx >= 0) |
276 | return idx; |
277 | int mapSize = size(); |
278 | int mindist = 200000; |
279 | int r = qRed(color); |
280 | int g = qGreen(color); |
281 | int b = qBlue(color); |
282 | int rx, gx, bx, dist; |
283 | for (int i = 0; i < mapSize; ++i) { |
284 | QRgb ci = d->cells->at(i); |
285 | rx = r - qRed(ci); |
286 | gx = g - qGreen(ci); |
287 | bx = b - qBlue(ci); |
288 | dist = rx * rx + gx * gx + bx * bx; // calculate distance |
289 | if (dist < mindist) { // minimal? |
290 | mindist = dist; |
291 | idx = i; |
292 | } |
293 | } |
294 | return idx; |
295 | } |
296 | |
297 | QT_END_NAMESPACE |
298 | |