~ubuntu-branches/ubuntu/maverick/freecad/maverick

« back to all changes in this revision

Viewing changes to src/Mod/Image/Gui/GLImageBox.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Teemu Ikonen
  • Date: 2009-07-16 18:37:41 UTC
  • Revision ID: james.westby@ubuntu.com-20090716183741-oww9kcxqrk991i1n
Tags: upstream-0.8.2237
ImportĀ upstreamĀ versionĀ 0.8.2237

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *                                                                         *
 
3
 *   This is a QGLWidget displaying an image or portion of an image in a   *
 
4
 *   box.                                                                  *
 
5
 *                                                                         *
 
6
 *   Author:    Graeme van der Vlugt                                       *
 
7
 *   Copyright: Imetric 3D GmbH                                            *
 
8
 *   Year:      2004                                                       *
 
9
 *                                                                         *
 
10
 *                                                                         *
 
11
 *   This program is free software; you can redistribute it and/or modify  *
 
12
 *   it under the terms of the GNU Library General Public License as       *
 
13
 *   published by the Free Software Foundation; either version 2 of the    *
 
14
 *   License, or (at your option) any later version.                       *
 
15
 *   for detail see the LICENCE text file.                                 *
 
16
 *                                                                         *
 
17
 ***************************************************************************/
 
18
 
 
19
#include "PreCompiled.h"
 
20
 
 
21
#include "GLImageBox.h"
 
22
 
 
23
using namespace ImageGui;
 
24
 
 
25
#if defined(Q_CC_MSVC)
 
26
#pragma warning(disable:4305) // init: truncation from const double to float
 
27
#endif
 
28
 
 
29
/* TRANSLATOR ImageGui::GLImageBox */
 
30
 
 
31
// Constructor
 
32
GLImageBox::GLImageBox(QWidget * parent, const QGLWidget * shareWidget, Qt::WFlags f)
 
33
    : QGLWidget(parent, shareWidget, f)
 
34
{
 
35
    // uses default display format for the OpenGL rendering context
 
36
    // (double buffering is enabled)
 
37
 
 
38
    // enable mouse tracking when moving even if no buttons are pressed
 
39
    setMouseTracking(true);
 
40
 
 
41
    // initialise variables
 
42
    _x0 = 0;
 
43
    _y0 = 0;
 
44
    _zoomFactor = 1.0;
 
45
    _base_x0 = 0;
 
46
    _base_y0 = 0;
 
47
    _pColorMap = 0;
 
48
    _numMapEntries = 0;
 
49
}
 
50
 
 
51
 
 
52
// Destructor
 
53
GLImageBox::~GLImageBox()
 
54
{
 
55
    try
 
56
    {
 
57
        delete [] _pColorMap;
 
58
    }
 
59
    catch(...) {}
 
60
}
 
61
 
 
62
// Set up the OpenGL rendering state
 
63
void GLImageBox::initializeGL()
 
64
{
 
65
  qglClearColor( Qt::black );           // Let OpenGL clear to black
 
66
}
 
67
 
 
68
 
 
69
// Update the viewport
 
70
void GLImageBox::resizeGL( int w, int h )
 
71
{
 
72
    glViewport( 0, 0, (GLint)w, (GLint)h );
 
73
    glMatrixMode( GL_PROJECTION );
 
74
    glLoadIdentity();
 
75
    gluOrtho2D(0, width() - 1, height() - 1, 0);
 
76
    glMatrixMode(GL_MODELVIEW);
 
77
}
 
78
 
 
79
// Redraw (current image)
 
80
void GLImageBox::redraw()
 
81
{
 
82
    glDraw();
 
83
}
 
84
 
 
85
 
 
86
// Paint the box
 
87
void GLImageBox::paintGL()
 
88
{
 
89
    // clear background (in back buffer)
 
90
    glDrawBuffer(GL_BACK);
 
91
    glClear(GL_COLOR_BUFFER_BIT);
 
92
 
 
93
    // Draw the image
 
94
    drawImage();
 
95
 
 
96
    // Emit a signal for owners to draw any graphics that is needed.
 
97
    if (_image.hasValidData() == true)
 
98
        drawGraphics();
 
99
 
 
100
    // flush the OpenGL graphical pipeline
 
101
    glFinish();
 
102
 
 
103
    // Double buffering is used so we need to swap the buffers
 
104
    // There is no need to explicitly call this function because it is 
 
105
    // done automatically after each widget repaint, i.e. each time after paintGL() has been executed
 
106
    // swapBuffers();
 
107
}
 
108
 
 
109
// Draw the image
 
110
void GLImageBox::drawImage()
 
111
{
 
112
    if (_image.hasValidData() == false)
 
113
        return;
 
114
 
 
115
    // Gets the size of the diplayed image area using the current display settings 
 
116
    // (in units of image pixels)
 
117
    int dx, dy;
 
118
    getDisplayedImageAreaSize(dx, dy);
 
119
 
 
120
   // Draw the visible image region with the correct position and zoom
 
121
    if ((dx > 0) && (dy > 0))
 
122
    {
 
123
        // Get top left image pixel to display
 
124
        int tlx = std::max<int>(0, _x0);
 
125
        int tly = std::max<int>(0, _y0);
 
126
 
 
127
        // Get pointer to first pixel in source image rectangle
 
128
        unsigned char* pPix = (unsigned char *)(_image.getPixelDataPtr());
 
129
        pPix += (unsigned long)(_image.getNumBytesPerPixel()) * (tly * _image.getWidth() + tlx);
 
130
 
 
131
        // Draw in the back buffer, using the following parameters
 
132
        glDrawBuffer(GL_BACK);
 
133
        glPixelStorei(GL_UNPACK_ROW_LENGTH, _image.getWidth()); // defines number of pixels in a row
 
134
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // defines byte alignment of rows
 
135
        glPixelZoom(_zoomFactor, -_zoomFactor); // defines the zoom factors to draw at
 
136
 
 
137
        // set current raster position to coincide with top left image pixel to display
 
138
        // the first pixel is always displayed in full when zoomed in
 
139
         // round to nearest widget pixel that coincides with top left corner of top left image pixel to display
 
140
        int xx = (int)floor(ICToWC_X(tlx - 0.5) + 0.5);
 
141
        int yy = (int)floor(ICToWC_Y(tly - 0.5) + 0.5);
 
142
        glRasterPos2f(xx, yy);
 
143
 
 
144
        // Compute scale to stretch number of significant bits to full range
 
145
        // e.g. stretch 12 significant bits to 16-bit range: 0-4095 -> 0-65535, therefore scale = 65535/4095
 
146
        double scale = (pow(2.0, _image.getNumBitsPerSample()) - 1.0) / (pow(2.0, _image.getNumSigBitsPerSample()) - 1.0);
 
147
        glPixelTransferf(GL_RED_SCALE, (float)scale);
 
148
        glPixelTransferf(GL_GREEN_SCALE, (float)scale);
 
149
        glPixelTransferf(GL_BLUE_SCALE, (float)scale);
 
150
 
 
151
        // Load the color map if present
 
152
        if (_pColorMap != 0)
 
153
        {
 
154
            glPixelTransferf(GL_MAP_COLOR, 1.0);
 
155
            glPixelMapfv(GL_PIXEL_MAP_R_TO_R, _numMapEntries, _pColorMap);
 
156
            glPixelMapfv(GL_PIXEL_MAP_G_TO_G, _numMapEntries, _pColorMap + _numMapEntries);
 
157
            glPixelMapfv(GL_PIXEL_MAP_B_TO_B, _numMapEntries, _pColorMap + _numMapEntries * 2);
 
158
            glPixelMapfv(GL_PIXEL_MAP_A_TO_A, _numMapEntries, _pColorMap + _numMapEntries * 3);
 
159
        }
 
160
        else
 
161
        {
 
162
            glPixelTransferf(GL_MAP_COLOR, 0.0);
 
163
            float zero = 0.0;
 
164
            float one = 1.0;
 
165
            glPixelMapfv(GL_PIXEL_MAP_R_TO_R, 1, &zero);
 
166
            glPixelMapfv(GL_PIXEL_MAP_G_TO_G, 1, &zero);
 
167
            glPixelMapfv(GL_PIXEL_MAP_B_TO_B, 1, &zero);
 
168
            glPixelMapfv(GL_PIXEL_MAP_A_TO_A, 1, &one);
 
169
        }
 
170
 
 
171
        // Get the pixel format
 
172
        GLenum pixFormat;
 
173
        GLenum pixType;
 
174
        getPixFormat(pixFormat, pixType);
 
175
 
 
176
        // Draw the defined source rectangle
 
177
        glDrawPixels(dx, dy, pixFormat, pixType, (GLvoid *)pPix);
 
178
        glFlush();
 
179
    }
 
180
}
 
181
 
 
182
// Gets the size of the diplayed image area using the current display settings 
 
183
// (in units of image pixels)
 
184
void GLImageBox::getDisplayedImageAreaSize(int &dx, int &dy)
 
185
{
 
186
    if (_image.hasValidData() == false)
 
187
    {
 
188
        dx = 0;
 
189
        dy = 0;
 
190
    }
 
191
    else
 
192
    {
 
193
        // Make sure drawing position and zoom factor are valid
 
194
        limitCurrPos();
 
195
        limitZoomFactor();
 
196
 
 
197
        // Image coordinates of top left widget pixel = (_x0, _y0)
 
198
        // Get image coordinates of bottom right widget pixel
 
199
        int brx = (int)ceil(WCToIC_X(width() - 1));
 
200
        int bry = (int)ceil(WCToIC_Y(height() - 1));
 
201
 
 
202
        // Find the outer coordinates of the displayed image area
 
203
        int itlx = std::max<int>(_x0, 0);
 
204
        int itly = std::max<int>(_y0, 0);
 
205
        int ibrx = std::min<int>(brx, (int)(_image.getWidth()) - 1);
 
206
        int ibry = std::min<int>(bry, (int)(_image.getHeight()) - 1);
 
207
        if ((itlx >= (int)(_image.getWidth())) || 
 
208
            (itly >= (int)(_image.getHeight())) || 
 
209
            (ibrx < 0) || 
 
210
            (ibry < 0))
 
211
        {
 
212
            dx = 0;
 
213
            dy = 0;
 
214
        }
 
215
        dx = ibrx - itlx + 1;
 
216
        dy = ibry - itly + 1;
 
217
    }
 
218
}
 
219
 
 
220
// Gets the value of an image sample at the given image pixel position
 
221
// Returns 0 for valid value or -1 if coordinates or sample index are out of range or 
 
222
// if there is no image data
 
223
int GLImageBox::getImageSample(int x, int y, unsigned short sampleIndex, double &value)
 
224
{
 
225
    return (_image.getSample(x, y, sampleIndex, value));
 
226
}
 
227
 
 
228
// Gets the number of samples per pixel for the image
 
229
unsigned short GLImageBox::getImageNumSamplesPerPix()
 
230
{
 
231
    return (_image.getNumSamples());
 
232
}
 
233
 
 
234
// Gets the format (color space format) of the image
 
235
int GLImageBox::getImageFormat()
 
236
{
 
237
    return (_image.getFormat());
 
238
}
 
239
 
 
240
 
 
241
// Get the OpenGL pixel format and pixel type from the image properties
 
242
void GLImageBox::getPixFormat(GLenum &pixFormat, GLenum &pixType)
 
243
{
 
244
    switch(_image.getFormat())
 
245
    {
 
246
        case IB_CF_GREY8:
 
247
            pixFormat = GL_LUMINANCE;
 
248
            pixType = GL_UNSIGNED_BYTE;
 
249
            break;
 
250
        case IB_CF_GREY16:
 
251
            pixFormat = GL_LUMINANCE;
 
252
            pixType = GL_UNSIGNED_SHORT;
 
253
            break;
 
254
        case IB_CF_GREY32:
 
255
            pixFormat = GL_LUMINANCE;
 
256
            pixType = GL_UNSIGNED_INT;
 
257
            break;
 
258
        case IB_CF_RGB24:
 
259
            pixFormat = GL_RGB;
 
260
            pixType = GL_UNSIGNED_BYTE;
 
261
            break;
 
262
#ifndef FC_OS_CYGWIN
 
263
        case IB_CF_BGR24:
 
264
            pixFormat = GL_BGR_EXT;
 
265
            pixType = GL_UNSIGNED_BYTE;
 
266
            break;
 
267
        case IB_CF_RGB48:
 
268
            pixFormat = GL_RGB;
 
269
            pixType = GL_UNSIGNED_SHORT;
 
270
            break;
 
271
        case IB_CF_BGR48:
 
272
            pixFormat = GL_BGR_EXT;
 
273
            pixType = GL_UNSIGNED_SHORT;
 
274
            break;
 
275
#endif
 
276
        case IB_CF_RGBA32:
 
277
            pixFormat = GL_RGBA;
 
278
            pixType = GL_UNSIGNED_BYTE;
 
279
            break;
 
280
        case IB_CF_RGBA64:
 
281
            pixFormat = GL_RGBA;
 
282
            pixType = GL_UNSIGNED_SHORT;
 
283
            break;
 
284
#ifndef FC_OS_CYGWIN
 
285
        case IB_CF_BGRA32:
 
286
            pixFormat = GL_BGRA_EXT;
 
287
            pixType = GL_UNSIGNED_BYTE;
 
288
            break;
 
289
        case IB_CF_BGRA64:
 
290
            pixFormat = GL_BGRA_EXT;
 
291
            pixType = GL_UNSIGNED_SHORT;
 
292
            break;
 
293
#endif
 
294
        default:
 
295
            // Should never happen
 
296
            pixFormat = GL_LUMINANCE;
 
297
            pixType = GL_UNSIGNED_BYTE;
 
298
            QMessageBox::warning((QWidget *)this, tr("GLImageBox::getPixFormat"),
 
299
                tr("Undefined type of colour space for image viewing"));
 
300
            return;
 
301
    }
 
302
}
 
303
 
 
304
// Limits the current position (centre of top left image pixel)
 
305
// Currently we don't limit it!
 
306
void GLImageBox::limitCurrPos()
 
307
{
 
308
    if (_image.hasValidData() == false)
 
309
        return;
 
310
 
 
311
    /*
 
312
    if (_x0 < 0)
 
313
        _x0 = 0;
 
314
    else if (_x0 >= (int)(_image.getWidth()))
 
315
        _x0 = _image.getWidth() - 1;
 
316
    if (_y0 < 0)
 
317
        _y0 = 0;
 
318
    else if (_y0 >= (int)(_image.getHeight()))
 
319
        _y0 = _image.getHeight() - 1;
 
320
    */
 
321
}
 
322
 
 
323
// Limits the current zoom factor from 1:64 to 64:1
 
324
void GLImageBox::limitZoomFactor()
 
325
{
 
326
    if (_zoomFactor > 64.0)
 
327
        _zoomFactor = 64.0;
 
328
    else if (_zoomFactor < (1.0 / 64.0))
 
329
        _zoomFactor = 1.0 / 64.0;
 
330
}
 
331
 
 
332
// Set the current position (centre of top left image pixel coordinates)
 
333
// This function does not redraw (call redraw afterwards)
 
334
void GLImageBox::setCurrPos(int x0, int y0)
 
335
{
 
336
    _x0 = x0;
 
337
    _y0 = y0;
 
338
    limitCurrPos();
 
339
}
 
340
 
 
341
// Fixes a base position at the current position
 
342
void GLImageBox::fixBasePosCurr()
 
343
{
 
344
    if (_image.hasValidData() == false)
 
345
    {
 
346
        _base_x0 = 0;
 
347
        _base_y0 = 0;
 
348
    }
 
349
    else
 
350
    {
 
351
        _base_x0 = _x0;
 
352
        _base_y0 = _y0;
 
353
    }
 
354
}
 
355
 
 
356
// Set the current zoom factor
 
357
// Option to centre the zoom at a given image point or not
 
358
// This function does not redraw (call redraw afterwards)
 
359
void GLImageBox::setZoomFactor(double zoomFactor, bool useCentrePt, int ICx, int ICy)
 
360
{
 
361
    if ((useCentrePt == false) || (_image.hasValidData() == false))
 
362
    {
 
363
        _zoomFactor = zoomFactor;
 
364
        limitZoomFactor();
 
365
    }
 
366
    else
 
367
    {
 
368
        // Set new zoom factor
 
369
        _zoomFactor = zoomFactor;
 
370
        limitZoomFactor();
 
371
 
 
372
        // get centre position of widget in image coordinates
 
373
        int ix, iy;
 
374
        getCentrePoint(ix, iy);
 
375
 
 
376
        // try to shift the current position so that defined centre point is in the middle of the widget
 
377
        // (this can be modified by the limitCurrPos function)
 
378
        setCurrPos(_x0 - ix + ICx, _y0 - iy + ICy);
 
379
    }
 
380
}
 
381
 
 
382
// Stretch or shrink the image to fit the view (although the zoom factor is limited so a 
 
383
// very small or very big image may not fit completely (depending on the size of the view)
 
384
// This function redraws
 
385
void GLImageBox::stretchToFit()
 
386
{
 
387
    if (_image.hasValidData() == false)
 
388
        return;
 
389
 
 
390
    setToFit();
 
391
    glDraw();
 
392
}
 
393
 
 
394
// Sets the settings needed to fit the image into the view (although the zoom factor is limited so a 
 
395
// very small or very big image may not fit completely (depending on the size of the view)
 
396
// This function does not redraw (call redraw afterwards)
 
397
void GLImageBox::setToFit()
 
398
{
 
399
    if (_image.hasValidData() == false)
 
400
        return;
 
401
 
 
402
    // Compute ideal zoom factor to fit the image
 
403
    double zoomX = (double)width() / (double)(_image.getWidth());
 
404
    double zoomY = (double)height() / (double)(_image.getHeight());
 
405
    if (zoomX > zoomY)
 
406
        _zoomFactor = zoomY;
 
407
    else
 
408
        _zoomFactor = zoomX;
 
409
    limitZoomFactor();
 
410
 
 
411
    // set current position to top left image pixel
 
412
    setCurrPos(0, 0);
 
413
}
 
414
 
 
415
// Sets the normal viewing position and zoom = 1
 
416
// If the image is smaller than the widget then the image is centred 
 
417
// otherwise we view the top left part of the image
 
418
// This function does not redraw (call redraw afterwards)
 
419
void GLImageBox::setNormal()
 
420
{
 
421
    if (_image.hasValidData() == false)
 
422
        return;
 
423
 
 
424
    if (((int)(_image.getWidth()) < width()) && ((int)(_image.getHeight()) < height()))
 
425
    {
 
426
        setZoomFactor(1.0, true, _image.getWidth() / 2, _image.getHeight() / 2);
 
427
    }
 
428
    else
 
429
    {
 
430
        _zoomFactor = 1;
 
431
        setCurrPos(0, 0);
 
432
    }
 
433
}
 
434
 
 
435
// Gets the image coordinates of the centre point of the widget 
 
436
void GLImageBox::getCentrePoint(int &ICx, int &ICy)
 
437
{
 
438
    ICx = (int)floor(WCToIC_X((double)(width() - 1) / 2.0) + 0.5);
 
439
    ICy = (int)floor(WCToIC_Y((double)(height() - 1) / 2.0) + 0.5);
 
440
}
 
441
 
 
442
// Moves the image by a relative amount (in widget pixel units) from the base position
 
443
// First use fixBasePosCurr() to fix the base position at a position
 
444
void GLImageBox::relMoveWC(int WCdx, int WCdy)
 
445
{
 
446
    double ICdx = WCdx / _zoomFactor;
 
447
    double ICdy = WCdy / _zoomFactor;
 
448
    setCurrPos(_base_x0 - (int)floor(ICdx + 0.5), _base_y0 - (int)floor(ICdy + 0.5));
 
449
    glDraw();
 
450
}
 
451
 
 
452
// Computes an image x-coordinate from the widget x-coordinate
 
453
// Note: (_x0,_y0) is the centre of the image pixel displayed at the top left of the widget
 
454
// therefore (_x0 - 0.5, _y0 - 0.5) is the top left coordinate of this pixel which will 
 
455
// theoretically coincide with widget coordinate (-0.5,-0.5)
 
456
// Zoom = 4:    Widget(0,0) = Image(_x0 - 0.375,_y0 - 0.375)
 
457
// Zoom = 2:    Widget(0,0) = Image(_x0 - 0.250,_y0 - 0.250)
 
458
// Zoom = 1:    Widget(0,0) = Image(_x0,_y0)
 
459
// Zoom = 0.5:  Widget(0,0) = Image(_x0 + 0.500,_y0 + 0.500)
 
460
// Zoom = 0.25: Widget(0,0) = Image(_x0 + 1.500,_y0 + 1.500)
 
461
double GLImageBox::WCToIC_X(double WidgetX)
 
462
{
 
463
    return ((double)_x0 - 0.5 + (WidgetX + 0.5) / _zoomFactor);
 
464
}
 
465
 
 
466
// Computes an image y-coordinate from the widget y-coordinate
 
467
// Note: (_x0,_y0) is the centre of the image pixel displayed at the top left of the widget
 
468
// therefore (_x0 - 0.5, _y0 - 0.5) is the top left coordinate of this pixel which will 
 
469
// theoretically coincide with widget coordinate (-0.5,-0.5)
 
470
// Zoom = 4:    Widget(0,0) = Image(_x0 - 0.375,_y0 - 0.375)
 
471
// Zoom = 2:    Widget(0,0) = Image(_x0 - 0.250,_y0 - 0.250)
 
472
// Zoom = 1:    Widget(0,0) = Image(_x0,_y0)
 
473
// Zoom = 0.5:  Widget(0,0) = Image(_x0 + 0.500,_y0 + 0.500)
 
474
// Zoom = 0.25: Widget(0,0) = Image(_x0 + 1.500,_y0 + 1.500)
 
475
double GLImageBox::WCToIC_Y(double WidgetY)
 
476
{
 
477
    return ((double)_y0 - 0.5 + (WidgetY + 0.5) / _zoomFactor);
 
478
}
 
479
 
 
480
// Computes a widget x-coordinate from an image x-coordinate
 
481
// Note: (_x0,_y0) is the centre of the image pixel displayed at the top left of the widget
 
482
// therefore (_x0 - 0.5, _y0 - 0.5) is the top left coordinate of this pixel which will 
 
483
// theoretically coincide with widget coordinate (-0.5,-0.5)
 
484
// Zoom = 4:    Widget(0,0) = Image(_x0 - 0.375,_y0 - 0.375)
 
485
// Zoom = 2:    Widget(0,0) = Image(_x0 - 0.250,_y0 - 0.250)
 
486
// Zoom = 1:    Widget(0,0) = Image(_x0,_y0)
 
487
// Zoom = 0.5:  Widget(0,0) = Image(_x0 + 0.500,_y0 + 0.500)
 
488
// Zoom = 0.25: Widget(0,0) = Image(_x0 + 1.500,_y0 + 1.500)
 
489
double GLImageBox::ICToWC_X(double ImageX)
 
490
{
 
491
    return ((ImageX - (double)_x0 + 0.5) * _zoomFactor - 0.5);
 
492
}
 
493
 
 
494
// Computes a widget y-coordinate from an image y-coordinate
 
495
// Note: (_x0,_y0) is the centre of the image pixel displayed at the top left of the widget
 
496
// therefore (_x0 - 0.5, _y0 - 0.5) is the top left coordinate of this pixel which will 
 
497
// theoretically coincide with widget coordinate (-0.5,-0.5)
 
498
// Zoom = 4:    Widget(0,0) = Image(_x0 - 0.375,_y0 - 0.375)
 
499
// Zoom = 2:    Widget(0,0) = Image(_x0 - 0.250,_y0 - 0.250)
 
500
// Zoom = 1:    Widget(0,0) = Image(_x0,_y0)
 
501
// Zoom = 0.5:  Widget(0,0) = Image(_x0 + 0.500,_y0 + 0.500)
 
502
// Zoom = 0.25: Widget(0,0) = Image(_x0 + 1.500,_y0 + 1.500)
 
503
double GLImageBox::ICToWC_Y(double ImageY)
 
504
{
 
505
    return ((ImageY - (double)_y0 + 0.5) * _zoomFactor - 0.5);
 
506
}
 
507
 
 
508
 
 
509
// Clears the image data
 
510
void GLImageBox::clearImage()
 
511
{
 
512
    _image.clear();
 
513
    resetDisplay();
 
514
}
 
515
 
 
516
// Load image by copying the pixel data
 
517
// The image object will take ownership of the copied pixel data
 
518
// (the source image is still controlled by the caller)
 
519
// If numSigBitsPerSample = 0 then the full range is assumed to be significant
 
520
// displayMode ... controls the initial display of the image, one of:
 
521
//                      IV_DISPLAY_NOCHANGE  ... no change to view settings when displaying a new image
 
522
//                      IV_DISPLAY_FITIMAGE  ... fit-image when displaying a new image (other settings remain the same)
 
523
//                      IV_DISPLAY_RESET     ... reset settings when displaying a new image (image will be displayed at 1:1 scale with no color map)
 
524
// This function does not redraw (call redraw afterwards)
 
525
// Returns:
 
526
//               0 for OK
 
527
//              -1 for invalid color format
 
528
//              -2 for memory allocation error
 
529
int GLImageBox::createImageCopy(void* pSrcPixelData, unsigned long width, unsigned long height, int format, unsigned short numSigBitsPerSample, int displayMode)
 
530
{
 
531
    // Copy image
 
532
    int ret = _image.createCopy(pSrcPixelData, width, height, format, numSigBitsPerSample);
 
533
 
 
534
    // Set display settings depending on mode
 
535
    if (displayMode == IV_DISPLAY_RESET)
 
536
    {
 
537
        // reset drawing settings (position, scale, colour mapping) if requested
 
538
        resetDisplay();
 
539
    }
 
540
    else if (displayMode == IV_DISPLAY_FITIMAGE)
 
541
    {
 
542
        // compute stretch to fit settings
 
543
        setToFit();
 
544
    }
 
545
    else // if (displayMode == IV_DISPLAY_NOCHANGE)
 
546
    {
 
547
        // use same settings
 
548
        limitCurrPos();
 
549
        limitZoomFactor();
 
550
    }
 
551
    return ret;
 
552
}
 
553
 
 
554
// Make the image object point to another image source
 
555
// If takeOwnership is false then:
 
556
//      This object will not own (control) or copy the pixel data
 
557
//      (the source image is still controlled by the caller)
 
558
// Else if takeOwnership is true then:
 
559
//      This object will take ownership (control) of the pixel data
 
560
//      (the source image is not (should not be) controlled by the caller anymore)
 
561
//      In this case the memory must have been allocated with the new operator (because this class will use the delete operator)
 
562
// If numSigBitsPerSample = 0 then the full range is assumed to be significant
 
563
// displayMode ... controls the initial display of the image, one of:
 
564
//                      IV_DISPLAY_NOCHANGE  ... no change to view settings when displaying a new image
 
565
//                      IV_DISPLAY_FITIMAGE  ... fit-image when displaying a new image (other settings remain the same)
 
566
//                      IV_DISPLAY_RESET     ... reset settings when displaying a new image (image will be displayed at 1:1 scale with no color map)
 
567
// This function does not redraw (call redraw afterwards)
 
568
// Returns:
 
569
//               0 for OK
 
570
//              -1 for invalid color format
 
571
int GLImageBox::pointImageTo(void* pSrcPixelData, unsigned long width, unsigned long height, int format, unsigned short numSigBitsPerSample, bool takeOwnership, int displayMode)
 
572
{
 
573
    // Point to image
 
574
    int ret = _image.pointTo(pSrcPixelData, width, height, format, numSigBitsPerSample, takeOwnership);
 
575
 
 
576
    // Set display settings depending on mode
 
577
    if (displayMode == IV_DISPLAY_RESET)
 
578
    {
 
579
        // reset drawing settings (position, scale, colour mapping) if requested
 
580
        resetDisplay();
 
581
    }
 
582
    else if (displayMode == IV_DISPLAY_FITIMAGE)
 
583
    {
 
584
        // compute stretch to fit settings
 
585
        setToFit();
 
586
    }
 
587
    else // if (displayMode == IV_DISPLAY_NOCHANGE)
 
588
    {
 
589
        // use same settings
 
590
        limitCurrPos();
 
591
        limitZoomFactor();
 
592
    }
 
593
    return ret;
 
594
}
 
595
 
 
596
// Reset display settings
 
597
void GLImageBox::resetDisplay()
 
598
{
 
599
    clearColorMap();
 
600
    setNormal(); // re-draws as well
 
601
}
 
602
 
 
603
// Clears the color map
 
604
void GLImageBox::clearColorMap()
 
605
{
 
606
    delete [] _pColorMap;
 
607
    _pColorMap = 0;
 
608
    _numMapEntries = 0;
 
609
}
 
610
 
 
611
// Calculate the number of color map entries to use
 
612
int GLImageBox::calcNumColorMapEntries()
 
613
{
 
614
    // Get the maximum number of map entries that the system supports
 
615
    // Get the number of bits per sample for the image if it exists and compute the number of pixel values
 
616
    // Return the fewer amount of entries
 
617
    GLint maxMapEntries;
 
618
    glGetIntegerv(GL_MAX_PIXEL_MAP_TABLE, &maxMapEntries);
 
619
    int NumEntries = maxMapEntries;
 
620
    if (_image.hasValidData() == true)
 
621
        NumEntries = (int)std::min<double>(pow(2.0, (double)(_image.getNumSigBitsPerSample())), (double)maxMapEntries);
 
622
    return NumEntries;
 
623
}
 
624
 
 
625
// Creates a color map (All red entries come first, then green, then blue, then alpha)
 
626
// returns 0 for OK, -1 for memory allocation error
 
627
// numRequestedEntries ... requested number of map entries (used if not greater than maximum possible or number of intensity values)
 
628
// Initialise ... flag to initialise the map to a linear scale or not
 
629
int GLImageBox::createColorMap(int numEntriesReq, bool Initialise)
 
630
{
 
631
    // Get the number of map entries to use
 
632
    int maxNumEntries = calcNumColorMapEntries();
 
633
    int numEntries;
 
634
    if (numEntriesReq <= 0)
 
635
        numEntries = maxNumEntries;
 
636
    else
 
637
        numEntries = std::min<int>(numEntriesReq, maxNumEntries);
 
638
 
 
639
    // Clear and re-create the color map if it's not the desired size
 
640
    if (numEntries != _numMapEntries)
 
641
    {
 
642
        clearColorMap();
 
643
        _numMapEntries = numEntries;
 
644
 
 
645
        // Create the color map (RGBA)
 
646
        try
 
647
        {
 
648
            _pColorMap = new float[4 * _numMapEntries];
 
649
        }
 
650
        catch(...)
 
651
        {
 
652
            clearColorMap();
 
653
            return -1;
 
654
        }
 
655
    }
 
656
 
 
657
    // Initialise the color map if requested
 
658
    // (All red entries come first, then green, then blue, then alpha)
 
659
    if (Initialise == true)
 
660
    {
 
661
        // For each RGB channel
 
662
        int arrayIndex = 0;
 
663
        for (int chan = 0; chan < 3; chan++)
 
664
        {
 
665
            for (int in = 0; in < _numMapEntries; in++)
 
666
            {
 
667
                _pColorMap[arrayIndex] = (float)in / (float)(_numMapEntries - 1);
 
668
                arrayIndex++;
 
669
            }
 
670
        }
 
671
        // For alpha channel
 
672
        for (int in = 0; in < _numMapEntries; in++)
 
673
        {
 
674
            _pColorMap[arrayIndex] = 1.0;
 
675
            arrayIndex++;
 
676
        }
 
677
    }
 
678
 
 
679
    return 0;
 
680
}
 
681
 
 
682
// Sets a color map RGBA value
 
683
// (All red entries come first, then green, then blue, then alpha)
 
684
// index ... index of color map RGBA entry
 
685
// red ... intensity value for this red entry (range 0 to 1)
 
686
// green ... intensity value for this green entry (range 0 to 1)
 
687
// blue ... intensity value for this blue entry (range 0 to 1)
 
688
// alpha ... value for this alpha entry (range 0 to 1)
 
689
int GLImageBox::setColorMapRGBAValue(int index, float red, float green, float blue, float alpha)
 
690
{
 
691
    if ((index < 0) || (index >= _numMapEntries) || 
 
692
        (red < 0.0) || (red > 1.0) || 
 
693
        (green < 0.0) || (green > 1.0) || 
 
694
        (blue < 0.0) || (blue > 1.0) || 
 
695
        (alpha < 0.0) || (alpha > 1.0))
 
696
        return -1;
 
697
 
 
698
    _pColorMap[index] = red;
 
699
    _pColorMap[_numMapEntries + index] = green;
 
700
    _pColorMap[_numMapEntries * 2 + index] = blue;
 
701
    _pColorMap[_numMapEntries * 3 + index] = alpha;
 
702
    return 0;
 
703
}
 
704
 
 
705
// Sets a color map red value
 
706
// (All red entries come first, then green, then blue, then alpha)
 
707
// index ... index of color map red entry
 
708
// value ... intensity value for this red entry (range 0 to 1)
 
709
int GLImageBox::setColorMapRedValue(int index, float value)
 
710
{
 
711
    if ((index < 0) || (index >= _numMapEntries) || (value < 0.0) || (value > 1.0))
 
712
        return -1;
 
713
 
 
714
    _pColorMap[index] = value;
 
715
    return 0;
 
716
}
 
717
 
 
718
// Sets a color map green value
 
719
// (All red entries come first, then green, then blue, then alpha)
 
720
// index ... index of color map green entry
 
721
// value ... intensity value for this green entry (range 0 to 1)
 
722
int GLImageBox::setColorMapGreenValue(int index, float value)
 
723
{
 
724
    if ((index < 0) || (index >= _numMapEntries) || (value < 0.0) || (value > 1.0))
 
725
        return -1;
 
726
 
 
727
    _pColorMap[_numMapEntries + index] = value;
 
728
    return 0;
 
729
}
 
730
 
 
731
// Sets a color map blue value
 
732
// (All red entries come first, then green, then blue, then alpha)
 
733
// index ... index of color map blue entry
 
734
// value ... intensity value for this blue entry (range 0 to 1)
 
735
int GLImageBox::setColorMapBlueValue(int index, float value)
 
736
{
 
737
    if ((index < 0) || (index >= _numMapEntries) || (value < 0.0) || (value > 1.0))
 
738
        return -1;
 
739
 
 
740
    _pColorMap[_numMapEntries * 2 + index] = value;
 
741
    return 0;
 
742
}
 
743
 
 
744
// Sets a color map alpha value
 
745
// (All red entries come first, then green, then blue, then alpha)
 
746
// index ... index of color map alpha entry
 
747
// value ... value for this alpha entry (range 0 to 1)
 
748
int GLImageBox::setColorMapAlphaValue(int index, float value)
 
749
{
 
750
    if ((index < 0) || (index >= _numMapEntries) || (value < 0.0) || (value > 1.0))
 
751
        return -1;
 
752
 
 
753
    _pColorMap[_numMapEntries * 3 + index] = value;
 
754
    return 0;
 
755
}
 
756
 
 
757
// Helper function to convert a pixel's value (of a sample) to the color map index (i.e. the map index that will be used for that pixel value)
 
758
unsigned int GLImageBox::pixValToMapIndex(double PixVal)
 
759
{
 
760
    if (_pColorMap != NULL)
 
761
    {
 
762
        double MaxVal = pow(2.0, _image.getNumBitsPerSample()) - 1.0;
 
763
        double Scale = (pow(2.0, _image.getNumBitsPerSample()) - 1.0) / (pow(2.0, _image.getNumSigBitsPerSample()) - 1.0);
 
764
        double PixVal01 = Scale * PixVal / MaxVal;
 
765
        int numMapEntries = getNumColorMapEntries();
 
766
        unsigned int MapIndex = (unsigned int)floor(0.5 + PixVal01 * (double)(numMapEntries - 1));
 
767
        return MapIndex;
 
768
    }
 
769
    else
 
770
    {
 
771
        return 0;
 
772
    }
 
773
}
 
774
 
 
775
 
 
776
#include "moc_GLImageBox.cpp"