Qt 4.8
qgl_wince.cpp
Go to the documentation of this file.
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 #include <qgl.h>
44 #include <qlist.h>
45 #include <qmap.h>
46 #include <qpixmap.h>
47 #include <qevent.h>
48 #include <private/qgl_p.h>
49 #include <qcolormap.h>
50 #include <qvarlengtharray.h>
51 #include <qdebug.h>
52 #include <qapplication.h>
53 #include <qdesktopwidget>
54 
55 #include <windows.h>
56 
57 #include <private/qeglproperties_p.h>
58 #include <private/qeglcontext_p.h>
59 #include <private/qgl_egl_p.h>
60 
61 
63 
64 
65 
66 class QGLCmapPrivate
67 {
68 public:
69  QGLCmapPrivate() : count(1) { }
70  void ref() { ++count; }
71  bool deref() { return !--count; }
72  uint count;
73 
74  enum AllocState{ UnAllocated = 0, Allocated = 0x01, Reserved = 0x02 };
75 
76  int maxSize;
81 };
82 
83 /*****************************************************************************
84  QColorMap class - temporarily here, until it is ready for prime time
85  *****************************************************************************/
86 
87 /****************************************************************************
88 **
89 ** Definition of QColorMap class
90 **
91 ****************************************************************************/
92 
93 #ifndef QGLCMAP_H
94 #define QGLCMAP_H
95 
96 #include <qcolor.h>
97 
98 /*
99  QGLTemporaryContext implementation
100 */
101 
103 {
104 public:
105  QGLWidget *widget;
106 };
107 
110 {
111  d->widget = new QGLWidget;
112  d->widget->makeCurrent();
113 }
114 
116 {
117  delete d->widget;
118 }
119 
120 /*****************************************************************************
121  QGLFormat Win32/WGL-specific code
122  *****************************************************************************/
123 
124 static bool opengl32dll = false;
125 
127 {
128  return false; // ###
129 }
130 
131 
132 bool QGLContext::chooseContext(const QGLContext* shareContext)
133 {
134  Q_D(QGLContext);
135 
136  // Validate the device.
137  if (!device())
138  return false;
139  int devType = device()->devType();
140  if (devType != QInternal::Pixmap && devType != QInternal::Image && devType != QInternal::Widget) {
141  qWarning("QGLContext::chooseContext(): Cannot create QGLContext's for paint device type %d", devType);
142  return false;
143  }
144 
145  // Get the display and initialize it.
146  d->eglContext = new QEglContext();
147  d->ownsEglContext = true;
148  d->eglContext->setApi(QEgl::OpenGL);
149 
150  // Construct the configuration we need for this surface.
151  QEglProperties configProps;
152  qt_eglproperties_set_glformat(configProps, d->glFormat);
153  configProps.setDeviceType(devType);
154  configProps.setPaintDeviceFormat(device());
155  configProps.setRenderableType(QEgl::OpenGL);
156 
157  // Search for a matching configuration, reducing the complexity
158  // each time until we get something that matches.
159  if (!d->eglContext->chooseConfig(configProps)) {
160  delete d->eglContext;
161  d->eglContext = 0;
162  return false;
163  }
164 
165  // Inform the higher layers about the actual format properties.
166  qt_glformat_from_eglconfig(d->glFormat, d->eglContext->config());
167 
168  // Create a new context for the configuration.
169  if (!d->eglContext->createContext
170  (shareContext ? shareContext->d_func()->eglContext : 0)) {
171  delete d->eglContext;
172  d->eglContext = 0;
173  return false;
174  }
175  d->sharing = d->eglContext->isSharing();
176  if (d->sharing && shareContext)
177  const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
178 
179 #if defined(EGL_VERSION_1_1)
180  if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
181  eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval());
182 #endif
183 
184  // Create the EGL surface to draw into.
185  d->eglSurface = d->eglContext->createSurface(device());
186  if (d->eglSurface == EGL_NO_SURFACE) {
187  delete d->eglContext;
188  d->eglContext = 0;
189  return false;
190  }
191 
192  return true;
193 
194 }
195 
196 
197 
198 static bool qLogEq(bool a, bool b)
199 {
200  return (((!a) && (!b)) || (a && b));
201 }
202 
203 int QGLContext::choosePixelFormat(void* , HDC )
204 {
205 
206  return 0;
207 }
208 
209 class QGLCmapPrivate;
210 
211 class /*Q_EXPORT*/ QGLCmap
212 {
213 public:
214  enum Flags { Reserved = 0x01 };
215 
216  QGLCmap(int maxSize = 256);
217  QGLCmap(const QGLCmap& map);
218  ~QGLCmap();
219 
220  QGLCmap& operator=(const QGLCmap& map);
221 
222  // isEmpty and/or isNull ?
223  int size() const;
224  int maxSize() const;
225 
226  void resize(int newSize);
227 
228  int find(QRgb color) const;
229  int findNearest(QRgb color) const;
230  int allocate(QRgb color, uint flags = 0, quint8 context = 0);
231 
232  void setEntry(int idx, QRgb color, uint flags = 0, quint8 context = 0);
233 
234  const QRgb* colors() const;
235 
236 private:
237  void detach();
238  QGLCmapPrivate* d;
239 };
240 
241 #endif
242 
243 
244 QGLCmap::QGLCmap(int maxSize) // add a bool prealloc?
245 {
246  d = new QGLCmapPrivate;
247  d->maxSize = maxSize;
248 }
249 
251 {
252  d = map.d;
253  d->ref();
254 }
255 
257 {
258  if (d && d->deref())
259  delete d;
260  d = 0;
261 }
262 
264 {
265  map.d->ref();
266  if (d->deref())
267  delete d;
268  d = map.d;
269  return *this;
270 }
271 
272 int QGLCmap::size() const
273 {
274  return d->colorArray.size();
275 }
276 
277 int QGLCmap::maxSize() const
278 {
279  return d->maxSize;
280 }
281 
282 void QGLCmap::detach()
283 {
284  if (d->count != 1) {
285  d->deref();
286  QGLCmapPrivate* newd = new QGLCmapPrivate;
287  newd->maxSize = d->maxSize;
288  newd->colorArray = d->colorArray;
289  newd->allocArray = d->allocArray;
290  newd->contextArray = d->contextArray;
291  newd->colorArray.detach();
292  newd->allocArray.detach();
293  newd->contextArray.detach();
294  newd->colorMap = d->colorMap;
295  d = newd;
296  }
297 }
298 
299 
300 void QGLCmap::resize(int newSize)
301 {
302  if (newSize < 0 || newSize > d->maxSize) {
303  qWarning("QGLCmap::resize(): size out of range");
304  return;
305  }
306  int oldSize = size();
307  detach();
308  //if shrinking; remove the lost elems from colorMap
309  d->colorArray.resize(newSize);
310  d->allocArray.resize(newSize);
311  d->contextArray.resize(newSize);
312  if (newSize > oldSize) {
313  memset(d->allocArray.data() + oldSize, 0, newSize - oldSize);
314  memset(d->contextArray.data() + oldSize, 0, newSize - oldSize);
315  }
316 }
317 
318 
319 int QGLCmap::find(QRgb color) const
320 {
321  QMap<uint,int>::ConstIterator it = d->colorMap.find(color);
322  if (it != d->colorMap.end())
323  return *it;
324  return -1;
325 }
326 
327 
328 int QGLCmap::findNearest(QRgb color) const
329 {
330  int idx = find(color);
331  if (idx >= 0)
332  return idx;
333  int mapSize = size();
334  int mindist = 200000;
335  int r = qRed(color);
336  int g = qGreen(color);
337  int b = qBlue(color);
338  int rx, gx, bx, dist;
339  for (int i=0; i < mapSize; i++) {
340  if (!(d->allocArray[i] & QGLCmapPrivate::Allocated))
341  continue;
342  QRgb ci = d->colorArray[i];
343  rx = r - qRed(ci);
344  gx = g - qGreen(ci);
345  bx = b - qBlue(ci);
346  dist = rx*rx + gx*gx + bx*bx; // calculate distance
347  if (dist < mindist) { // minimal?
348  mindist = dist;
349  idx = i;
350  }
351  }
352  return idx;
353 }
354 
355 
356 // Does not always allocate; returns existing c idx if found
357 
358 int QGLCmap::allocate(QRgb color, uint flags, quint8 context)
359 {
360  int idx = find(color);
361  if (idx >= 0)
362  return idx;
363 
364  int mapSize = d->colorArray.size();
365  int newIdx = d->allocArray.indexOf(QGLCmapPrivate::UnAllocated);
366 
367  if (newIdx < 0) { // Must allocate more room
368  if (mapSize < d->maxSize) {
369  newIdx = mapSize;
370  mapSize++;
371  resize(mapSize);
372  }
373  else {
374  //# add a bool param that says what to do in case no more room -
375  // fail (-1) or return nearest?
376  return -1;
377  }
378  }
379 
380  d->colorArray[newIdx] = color;
381  if (flags & QGLCmap::Reserved) {
382  d->allocArray[newIdx] = QGLCmapPrivate::Reserved;
383  }
384  else {
385  d->allocArray[newIdx] = QGLCmapPrivate::Allocated;
386  d->colorMap.insert(color, newIdx);
387  }
388  d->contextArray[newIdx] = context;
389  return newIdx;
390 }
391 
392 
393 void QGLCmap::setEntry(int idx, QRgb color, uint flags, quint8 context)
394 {
395  if (idx < 0 || idx >= d->maxSize) {
396  qWarning("QGLCmap::set(): Index out of range");
397  return;
398  }
399  detach();
400  int mapSize = size();
401  if (idx >= mapSize) {
402  mapSize = idx + 1;
403  resize(mapSize);
404  }
405  d->colorArray[idx] = color;
406  if (flags & QGLCmap::Reserved) {
407  d->allocArray[idx] = QGLCmapPrivate::Reserved;
408  }
409  else {
410  d->allocArray[idx] = QGLCmapPrivate::Allocated;
411  d->colorMap.insert(color, idx);
412  }
413  d->contextArray[idx] = context;
414 }
415 
416 
417 const QRgb* QGLCmap::colors() const
418 {
419  return d->colorArray.data();
420 }
421 
422 
423 /*****************************************************************************
424  QGLWidget Win32/WGL-specific code
425  *****************************************************************************/
426 
427 void QGLWidgetPrivate::init(QGLContext *ctx, const QGLWidget* shareWidget)
428 {
429  Q_Q(QGLWidget);
430  olcx = 0;
431  initContext(ctx, shareWidget);
432 
433  if (q->isValid() && q->context()->format().hasOverlay()) {
435  if (!olcx->create(shareWidget ? shareWidget->overlayContext() : 0)) {
436  delete olcx;
437  olcx = 0;
438  glcx->d_func()->glFormat.setOverlay(false);
439  }
440  } else {
441  olcx = 0;
442  }
443 }
444 
445 /*\internal
446  Store color values in the given colormap.
447 */
448 static void qStoreColors(HPALETTE cmap, const QGLColormap & cols)
449 {
450  QRgb color;
451  PALETTEENTRY pe;
452 
453  for (int i = 0; i < cols.size(); i++) {
454  color = cols.entryRgb(i);
455  pe.peRed = qRed(color);
456  pe.peGreen = qGreen(color);
457  pe.peBlue = qBlue(color);
458  pe.peFlags = 0;
459 
460  SetPaletteEntries(cmap, i, 1, &pe);
461  }
462 }
463 
465 {
466  Q_Q(QGLWidget);
467  if (!cmap.handle())
468  return;
469  HDC hdc = GetDC(q->winId());
470  SelectPalette(hdc, (HPALETTE) cmap.handle(), TRUE);
471  qStoreColors((HPALETTE) cmap.handle(), cmap);
472  RealizePalette(hdc);
473  ReleaseDC(q->winId(), hdc);
474 }
475 
476 bool QGLWidget::event(QEvent *e)
477 {
478  Q_D(QGLWidget);
479  if (e->type() == QEvent::ParentChange) {
480  setContext(new QGLContext(d->glcx->requestedFormat(), this));
481  // the overlay needs to be recreated as well
482  delete d->olcx;
483  if (isValid() && context()->format().hasOverlay()) {
484  d->olcx = new QGLContext(QGLFormat::defaultOverlayFormat(), this);
485  if (!d->olcx->create(isSharing() ? d->glcx : 0)) {
486  delete d->olcx;
487  d->olcx = 0;
488  d->glcx->d_func()->glFormat.setOverlay(false);
489  }
490  } else {
491  d->olcx = 0;
492  }
493  } else if (e->type() == QEvent::Show && !format().rgba()) {
494  d->updateColormap();
495  }
496 
497  return QWidget::event(e);
498 }
499 
500 
502 {
503  Q_D(QGLWidget);
504  if (!isValid())
505  return;
506  makeCurrent();
507  if (!d->glcx->initialized())
508  glInit();
509  resizeGL(width(), height());
510  if (d->olcx) {
511  makeOverlayCurrent();
512  resizeOverlayGL(width(), height());
513  }
514 }
515 
516 
518 {
519  return d_func()->olcx;
520 }
521 
522 
524 {
525  Q_D(QGLWidget);
526  if (d->olcx) {
527  d->olcx->makeCurrent();
528  if (!d->olcx->initialized()) {
529  initializeOverlayGL();
530  d->olcx->setInitialized(true);
531  }
532  }
533 }
534 
535 
537 {
538  Q_D(QGLWidget);
539  if (d->olcx) {
540  makeOverlayCurrent();
541  paintOverlayGL();
542  if (d->olcx->format().doubleBuffer()) {
543  if (d->autoSwap)
544  d->olcx->swapBuffers();
545  }
546  else {
547  glFlush();
548  }
549  }
550 }
551 
552 void QGLWidget::setContext(QGLContext *context,
553  const QGLContext* shareContext,
554  bool deleteOldContext)
555 {
556  Q_D(QGLWidget);
557  if (context == 0) {
558  qWarning("QGLWidget::setContext: Cannot set null context");
559  return;
560  }
561  if (!context->deviceIsPixmap() && context->device() != this) {
562  qWarning("QGLWidget::setContext: Context must refer to this widget");
563  return;
564  }
565 
566  if (d->glcx)
567  d->glcx->doneCurrent();
568  QGLContext* oldcx = d->glcx;
569  d->glcx = context;
570 
571  bool doShow = false;
572  if (oldcx && oldcx->d_func()->win == winId() && !d->glcx->deviceIsPixmap()) {
573  // We already have a context and must therefore create a new
574  // window since Windows does not permit setting a new OpenGL
575  // context for a window that already has one set.
576  doShow = isVisible();
577  QWidget *pW = static_cast<QWidget *>(parent());
578  QPoint pos = geometry().topLeft();
579  setParent(pW, windowFlags());
580  move(pos);
581  }
582 
583  if (!d->glcx->isValid()) {
584  d->glcx->create(shareContext ? shareContext : oldcx);
585  // the above is a trick to keep disp lists etc when a
586  // QGLWidget has been reparented, so remove the sharing
587  // flag if we don't actually have a sharing context.
588  if (!shareContext)
589  d->glcx->d_ptr->sharing = false;
590  }
591 
592  if (deleteOldContext)
593  delete oldcx;
594 
595  if (doShow)
596  show();
597 }
598 
599 
601 {
602  Q_Q(QGLWidget);
603  if (cmap.handle()) {
604  HDC hdc = GetDC(q->winId());
605  SelectPalette(hdc, (HPALETTE) GetStockObject(DEFAULT_PALETTE), FALSE);
606  DeleteObject((HPALETTE) cmap.handle());
607  ReleaseDC(q->winId(), hdc);
608  cmap.setHandle(0);
609  }
610  return;
611 }
612 
613 const QGLColormap & QGLWidget::colormap() const
614 {
615  return d_func()->cmap;
616 }
617 
619 {
620  Q_D(QGLWidget);
621  d->cmap = c;
622 
623  if (d->cmap.handle()) { // already have an allocated cmap
624  d->updateColormap();
625  } else {
626  LOGPALETTE *lpal = (LOGPALETTE *) malloc(sizeof(LOGPALETTE)
627  +c.size()*sizeof(PALETTEENTRY));
628  lpal->palVersion = 0x300;
629  lpal->palNumEntries = c.size();
630  d->cmap.setHandle(CreatePalette(lpal));
631  free(lpal);
632  d->updateColormap();
633  }
634 }
635 
void qt_glformat_from_eglconfig(QGLFormat &format, const EGLConfig config)
Definition: qgl_egl.cpp:145
double d
Definition: qnumeric_p.h:62
static bool opengl32dll
Definition: qgl_wince.cpp:124
unsigned int QRgb
Definition: qrgb.h:53
void detach()
Definition: qvector.h:147
unsigned char c[8]
Definition: qnumeric_p.h:62
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QPointer< QWidget > widget
#define it(className, varName)
int size() const
Returns the number of colorcells in the colormap.
void detach()
Definition: qgl_win.cpp:255
void setEntry(int idx, QRgb color, uint flags=0, quint8 context=0)
Definition: qgl_win.cpp:368
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
static QColor cmap[256]
Definition: qgl_mac.mm:760
long ASN1_INTEGER_get ASN1_INTEGER * a
unsigned char quint8
Definition: qglobal.h:934
int maxSize() const
Definition: qgl_win.cpp:249
void init(QGLContext *context, const QGLWidget *shareWidget)
Definition: qgl_mac.mm:950
#define Q_D(Class)
Definition: qglobal.h:2482
int allocate(QRgb color, uint flags=0, quint8 context=0)
Definition: qgl_win.cpp:333
Q_GUI_EXPORT_INLINE int qRed(QRgb rgb)
Definition: qrgb.h:57
#define Q_Q(Class)
Definition: qglobal.h:2483
int size() const
Definition: qgl_win.cpp:243
int find(QRgb color) const
Definition: qgl_win.cpp:292
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
void setRenderableType(QEgl::API api)
QGLCmapPrivate * d
Definition: qgl_win.cpp:207
QVector< quint8 > contextArray
Definition: qgl_win.cpp:164
The QGLContext class encapsulates an OpenGL rendering context.
Definition: qgl.h:310
The QResizeEvent class contains event parameters for resize events.
Definition: qevent.h:349
Q_CORE_EXPORT void qWarning(const char *,...)
unsigned int uint
Definition: qglobal.h:996
#define FALSE
Synonym for false.
Definition: qglobal.h:1019
~QGLCmap()
Definition: qgl_win.cpp:225
QPaintDevice * device() const
Returns the paint device set for this context.
Definition: qgl.cpp:3507
bool deviceIsPixmap() const
Returns true if the paint device of this context is a pixmap; otherwise returns false.
Definition: qgl.cpp:3513
Q_GUI_EXPORT_INLINE int qBlue(QRgb rgb)
Definition: qrgb.h:63
The QGLColormap class is used for installing custom colormaps into a QGLWidget.
Definition: qglcolormap.h:54
void updateColormap()
Definition: qgl_win.cpp:1441
int findNearest(QRgb color) const
Definition: qgl_win.cpp:301
virtual int choosePixelFormat(void *pfd, HDC pdc)
Win32 only: This virtual function chooses a pixel format that matches the OpenGL format.
Definition: qgl_win.cpp:1015
#define TRUE
Synonym for true.
Definition: qglobal.h:1018
QRgb entryRgb(int idx) const
Returns the QRgb value in the colorcell with index idx.
QGLCmap(int maxSize=256)
Definition: qgl_win.cpp:211
The QGLWidget class is a widget for rendering OpenGL graphics.
Definition: qgl.h:474
void resize(int newSize)
Definition: qgl_win.cpp:273
virtual bool chooseContext(const QGLContext *shareContext=0)
This semi-internal function is called by create().
Definition: qgl_mac.mm:190
const QRgb * colors() const
Definition: qgl_win.cpp:392
static bool hasOpenGLOverlays()
Returns true if the window system supports OpenGL overlays; otherwise returns false.
Definition: qgl_mac.mm:185
static bool qLogEq(bool a, bool b)
Definition: qgl_wince.cpp:198
#define ctx
Definition: qgl.cpp:6094
void resizeEvent(QResizeEvent *)
Handles resize events that are passed in the event parameter.
Definition: qgl_mac.mm:896
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:53
const QGLContext * overlayContext() const
Returns the overlay context of this widget, or 0 if this widget has no overlay.
Definition: qgl_mac.mm:919
void makeOverlayCurrent()
Makes the overlay context of this widget current.
Definition: qgl_mac.mm:924
QGLTemporaryContext(bool directRendering=true, QWidget *parent=0)
Definition: qgl_mac.mm:132
void setPaintDeviceFormat(QPaintDevice *dev)
Definition: qegl_qpa.cpp:93
QVector< quint8 > allocArray
Definition: qgl_win.cpp:163
Q_GUI_EXPORT_INLINE int qGreen(QRgb rgb)
Definition: qrgb.h:60
static QGLFormat defaultOverlayFormat()
Returns the default QGLFormat for overlay contexts.
Definition: qgl.cpp:1559
virtual void updateOverlayGL()
Updates the widget&#39;s overlay (if any).
Definition: qgl_mac.mm:928
bool event(QEvent *)
This is the main event handler; it handles event event.
Definition: qwidget.cpp:8636
static void qStoreColors(HPALETTE cmap, const QGLColormap &cols)
Definition: qgl_wince.cpp:448
const QGLColormap & colormap() const
Returns the colormap for this widget.
Definition: qgl_mac.mm:974
void setColormap(const QGLColormap &map)
Set the colormap for this widget to cmap.
Definition: qgl_mac.mm:979
The QEvent class is the base class of all event classes.
Definition: qcoreevent.h:56
Type type() const
Returns the event type.
Definition: qcoreevent.h:303
void setDeviceType(int devType)
void qt_eglproperties_set_glformat(QEglProperties &eglProperties, const QGLFormat &glFormat)
Definition: qgl_egl.cpp:61
QGLCmap & operator=(const QGLCmap &map)
Definition: qgl_win.cpp:233
QMap< uint, int > colorMap
Definition: qgl_win.cpp:165
void setContext(QGLContext *context, const QGLContext *shareContext=0, bool deleteOldContext=true)
Sets a new QGLContext, context, for this QGLWidget, using the shared context, shareContext.
Definition: qgl_mac.mm:932
void cleanupColormaps()
Free up any allocated colormaps.
Definition: qgl_mac.mm:970
bool event(QEvent *)
Reimplemented Function
Definition: qgl_qpa.cpp:347
QVector< uint > colorArray
Definition: qgl_win.cpp:162