source: trunk/packages/vizservers/nanovis/VolumeRenderer.cpp @ 2973

Last change on this file since 2973 was 2973, checked in by ldelgass, 10 years ago

Fix clipping bug in nanovis volume renderer. Use computed eye space bounds of
transformed volume bounding box to initialize view-aligned quads before
clipping. Previously an arbitrary eye-space bound was used, and this was too
small for long volumes like nanowires in omennanowire.

  • Property svn:eol-style set to native
File size: 26.0 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * ----------------------------------------------------------------------
4 * VolumeRenderer.cpp : VolumeRenderer class for volume visualization
5 *
6 * ======================================================================
7 *  AUTHOR:  Wei Qiao <qiaow@purdue.edu>
8 *           Purdue Rendering and Perceptualization Lab (PURPL)
9 *
10 *  Copyright (c) 2004-2006  Purdue Research Foundation
11 *
12 *  See the file "license.terms" for information on usage and
13 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 * ======================================================================
15 */
16#include <stdlib.h>
17#include <assert.h>
18#include <time.h>
19#include <sys/time.h>
20#include <float.h>
21
22#include <vector>
23
24#include <GL/glew.h>
25#include <GL/glut.h>
26
27#include <tcl.h>
28
29#include <R2/R2FilePath.h>
30
31#include "nanovis.h"
32#include "VolumeRenderer.h"
33#include "ConvexPolygon.h"
34
35#include "NvStdVertexShader.h"
36#include "Trace.h"
37#include "Grid.h"
38
39#define NUMDIGITS       6
40
41VolumeRenderer::VolumeRenderer() :
42    _sliceMode(false),
43    _volumeMode(true)
44{
45    initShaders();
46
47    std::string path = R2FilePath::getInstance()->getPath("Font.bmp");
48    if (path.empty()) {
49        ERROR("can't find Font.bmp\n");
50        assert(!path.empty());
51    }
52    initFont(path.c_str());
53    _volumeInterpolator = new VolumeInterpolator();
54}
55
56VolumeRenderer::~VolumeRenderer()
57{
58    delete _zincBlendeShader;
59    delete _regularVolumeShader;
60    delete _stdVertexShader;
61    delete _volumeInterpolator;
62}
63
64//initialize the volume shaders
65void VolumeRenderer::initShaders()
66{
67    //standard vertex program
68    _stdVertexShader = new NvStdVertexShader();
69
70    //volume rendering shader: one cubic volume
71    _regularVolumeShader = new NvRegularVolumeShader();
72
73    //volume rendering shader: one zincblende orbital volume.
74    //This shader renders one orbital of the simulation.
75    //A sim has S, P, D, SS orbitals. thus a full rendering requires 4 zincblende orbital volumes.
76    //A zincblende orbital volume is decomposed into 2 "interlocking" cubic 4-component volumes and passed to the shader.
77    //We render each orbital with a independent transfer functions then blend the result.
78    //
79    //The engine is already capable of rendering multiple volumes and combine them. Thus, we just invoke this shader on
80    //S, P, D and SS orbitals with different transfor functions. The result is a multi-orbital rendering.
81    _zincBlendeShader = new NvZincBlendeVolumeShader();
82}
83
84struct SortElement {
85    float z;
86    int volumeId;
87    int sliceId;
88
89    SortElement(float _z, int _v, int _s) :
90        z(_z),
91        volumeId(_v),
92        sliceId(_s)
93    {}
94};
95
96static int sliceSort(const void *a, const void *b)
97{
98    if ((*((SortElement*)a)).z > (*((SortElement*)b)).z)
99        return 1;
100    else
101        return -1;
102}
103
104void
105VolumeRenderer::renderAll()
106{
107    size_t total_rendered_slices = 0;
108
109    if (_volumeInterpolator->isStarted()) {
110#ifdef notdef
111        ani_vol = _volumeInterpolator->getVolume();
112        ani_tf = ani_vol->transferFunction();
113#endif
114        TRACE("VOLUME INTERPOLATOR IS STARTED ----------------------------");
115    }
116    // Determine the volumes that are to be rendered.
117    std::vector<Volume *> volumes;
118    Tcl_HashEntry *hPtr;
119    Tcl_HashSearch iter;
120    for (hPtr = Tcl_FirstHashEntry(&NanoVis::volumeTable, &iter); hPtr != NULL;
121         hPtr = Tcl_NextHashEntry(&iter)) {
122        Volume* volPtr;
123        volPtr = (Volume *)Tcl_GetHashValue(hPtr);
124        if (!volPtr->visible()) {
125            continue; // Skip this volume
126        }
127        // BE CAREFUL: Set the number of slices to something slightly
128        // different for each volume.  If we have identical volumes at exactly
129        // the same position with exactly the same number of slices, the
130        // second volume will overwrite the first, so the first won't appear
131        // at all.
132        volumes.push_back(volPtr);
133        volPtr->numSlices(256 - volumes.size());
134    }
135
136    glPushAttrib(GL_ENABLE_BIT);
137
138    //two dimension pointer array
139    ConvexPolygon ***polys = new ConvexPolygon**[volumes.size()];
140    //number of actual slices for each volume
141    size_t *actual_slices = new size_t[volumes.size()];
142
143    TRACE("start loop %d\n", volumes.size());
144    for (size_t i = 0; i < volumes.size(); i++) {
145        Volume *volPtr = volumes[i];
146        polys[i] = NULL;
147        actual_slices[i] = 0;
148
149        int n_slices = volPtr->numSlices();
150        if (volPtr->isosurface()) {
151            // double the number of slices
152            n_slices <<= 1;
153        }
154
155        //volume start location
156        Vector3 loc = volPtr->location();
157        Vector4 shift_4d(loc.x, loc.y, loc.z, 0);
158
159        double x0 = 0;
160        double y0 = 0;
161        double z0 = 0;
162
163        Mat4x4 model_view_no_trans, model_view_trans;
164        Mat4x4 model_view_no_trans_inverse, model_view_trans_inverse;
165
166        //initialize volume plane with world coordinates
167        Plane volume_planes[6];
168        volume_planes[0].setCoeffs( 1,  0,  0, -x0);
169        volume_planes[1].setCoeffs(-1,  0,  0,  x0+1);
170        volume_planes[2].setCoeffs( 0,  1,  0, -y0);
171        volume_planes[3].setCoeffs( 0, -1,  0,  y0+1);
172        volume_planes[4].setCoeffs( 0,  0,  1, -z0);
173        volume_planes[5].setCoeffs( 0,  0, -1,  z0+1);
174
175        //get modelview matrix with no translation
176        glPushMatrix();
177        glScalef(volPtr->aspectRatioWidth,
178                 volPtr->aspectRatioHeight,
179                 volPtr->aspectRatioDepth);
180
181        glEnable(GL_DEPTH_TEST);
182
183        GLfloat mv_no_trans[16];
184        glGetFloatv(GL_MODELVIEW_MATRIX, mv_no_trans);
185
186        model_view_no_trans = Mat4x4(mv_no_trans);
187        model_view_no_trans_inverse = model_view_no_trans.inverse();
188
189        glPopMatrix();
190
191        //get modelview matrix with translation
192        glPushMatrix();
193        glTranslatef(shift_4d.x, shift_4d.y, shift_4d.z);
194        glScalef(volPtr->aspectRatioWidth,
195                 volPtr->aspectRatioHeight,
196                 volPtr->aspectRatioDepth);
197        GLfloat mv_trans[16];
198        glGetFloatv(GL_MODELVIEW_MATRIX, mv_trans);
199
200        model_view_trans = Mat4x4(mv_trans);
201        model_view_trans_inverse = model_view_trans.inverse();
202
203        //draw volume bounding box with translation (the correct location in
204        //space)
205        if (volPtr->outline()) {
206            float olcolor[3];
207            volPtr->getOutlineColor(olcolor);
208            drawBoundingBox(x0, y0, z0, x0+1, y0+1, z0+1,
209                (double)olcolor[0], (double)olcolor[1], (double)olcolor[2],
210                1.5);
211        }
212        glPopMatrix();
213
214        //draw labels
215        glPushMatrix();
216        glTranslatef(shift_4d.x, shift_4d.y, shift_4d.z);
217        if (volPtr->outline()) {
218            //drawLabel(i);
219        }
220        glPopMatrix();
221
222        //transform volume_planes to eye coordinates.
223        for (size_t j = 0; j < 6; j++) {
224            volume_planes[j].transform(model_view_no_trans);
225        }
226        double eyeMinX, eyeMaxX, eyeMinY, eyeMaxY, zNear, zFar;
227        getEyeSpaceBounds(model_view_no_trans,
228                          eyeMinX, eyeMaxX,
229                          eyeMinY, eyeMaxY,
230                          zNear, zFar);
231
232        //compute actual rendering slices
233        float z_step = fabs(zNear-zFar)/n_slices;
234        size_t n_actual_slices;
235
236        if (volPtr->dataEnabled()) {
237            n_actual_slices = (int)(fabs(zNear-zFar)/z_step + 1);
238            polys[i] = new ConvexPolygon*[n_actual_slices];
239        } else {
240            n_actual_slices = 0;
241            polys[i] = NULL;
242        }
243        actual_slices[i] = n_actual_slices;
244
245        // These are object coordinates
246        Vector4 vert1 = (Vector4(-10, -10, -0.5, 1));
247        Vector4 vert2 = (Vector4(-10, +10, -0.5, 1));
248        Vector4 vert3 = (Vector4(+10, +10, -0.5, 1));
249        Vector4 vert4 = (Vector4(+10, -10, -0.5, 1));
250
251        // Render cutplanes first with depth test enabled.  They will mark the
252        // image with their depth values.  Then we render other volume slices.
253        // These volume slices will be occluded correctly by the cutplanes and
254        // vice versa.
255
256        ConvexPolygon static_poly;
257        for (int j = 0; j < volPtr->getCutplaneCount(); j++) {
258            if (!volPtr->isCutplaneEnabled(j)) {
259                continue;
260            }
261            float offset = volPtr->getCutplane(j)->offset;
262            int axis = volPtr->getCutplane(j)->orient;
263           
264            if (axis == 3) {
265                vert1 = Vector4(-10, -10, offset, 1);
266                vert2 = Vector4(-10, +10, offset, 1);
267                vert3 = Vector4(+10, +10, offset, 1);
268                vert4 = Vector4(+10, -10, offset, 1);
269                //continue;
270            } else if (axis == 1) {
271                vert1 = Vector4(offset, -10, -10, 1);
272                vert2 = Vector4(offset, +10, -10, 1);
273                vert3 = Vector4(offset, +10, +10, 1);
274                vert4 = Vector4(offset, -10, +10, 1);
275                //continue;
276            } else if (axis == 2) {
277                vert1 = Vector4(-10, offset, -10, 1);
278                vert2 = Vector4(+10, offset, -10, 1);
279                vert3 = Vector4(+10, offset, +10, 1);
280                vert4 = Vector4(-10, offset, +10, 1);
281                //continue;
282            }
283
284            vert1 = model_view_no_trans.transform(vert1);
285            vert2 = model_view_no_trans.transform(vert2);
286            vert3 = model_view_no_trans.transform(vert3);
287            vert4 = model_view_no_trans.transform(vert4);
288
289            ConvexPolygon *p = &static_poly;
290            p->vertices.clear();
291
292            p->appendVertex(vert1);
293            p->appendVertex(vert2);
294            p->appendVertex(vert3);
295            p->appendVertex(vert4);
296
297            for (size_t k = 0; k < 6; k++) {
298                p->clip(volume_planes[k], true);
299            }
300
301            p->transform(model_view_no_trans_inverse);
302            p->transform(model_view_trans);
303
304            glPushMatrix();
305            glScalef(volPtr->aspectRatioWidth,
306                     volPtr->aspectRatioHeight,
307                     volPtr->aspectRatioDepth);
308
309            activateVolumeShader(volPtr, true);
310            glPopMatrix();
311
312            glEnable(GL_DEPTH_TEST);
313            glDisable(GL_BLEND);
314
315            glBegin(GL_POLYGON);
316            p->emit(true);
317            glEnd();
318            glDisable(GL_DEPTH_TEST);
319
320            deactivateVolumeShader();
321        } //done cutplanes
322
323        //Now do volume rendering
324
325        // Initialize view-aligned quads with eye space bounds of
326        // volume
327        vert1 = (Vector4(eyeMinX, eyeMinY, -0.5, 1));
328        vert2 = (Vector4(eyeMaxX, eyeMinY, -0.5, 1));
329        vert3 = (Vector4(eyeMaxX, eyeMaxY, -0.5, 1));
330        vert4 = (Vector4(eyeMinX, eyeMaxY, -0.5, 1));
331
332        size_t counter = 0;
333
334        //transform slices and store them
335        float slice_z;
336        for (size_t j = 0; j < n_actual_slices; j++) {
337            slice_z = zFar + j * z_step; //back to front
338
339            ConvexPolygon *poly = new ConvexPolygon();
340            polys[i][counter] = poly;
341            counter++;
342
343            poly->vertices.clear();
344            poly->setId(i);
345
346            // Set eye space Z-coordinate of slice
347            vert1.z = slice_z;
348            vert2.z = slice_z;
349            vert3.z = slice_z;
350            vert4.z = slice_z;
351
352            poly->appendVertex(vert1);
353            poly->appendVertex(vert2);
354            poly->appendVertex(vert3);
355            poly->appendVertex(vert4);
356
357            for (size_t k = 0; k < 6; k++) {
358                poly->clip(volume_planes[k], true);
359            }
360
361            poly->transform(model_view_no_trans_inverse);
362            poly->transform(model_view_trans);
363
364            if (poly->vertices.size() >= 3)
365                total_rendered_slices++;
366        }
367    } //iterate all volumes
368    TRACE("end loop\n");
369
370    // We sort all the polygons according to their eye-space depth, from
371    // farthest to the closest.  This step is critical for correct blending
372
373    SortElement *slices = (SortElement *)
374        malloc(sizeof(SortElement) * total_rendered_slices);
375
376    size_t counter = 0;
377    for (size_t i = 0; i < volumes.size(); i++) {
378        for (size_t j = 0; j < actual_slices[i]; j++) {
379            if (polys[i][j]->vertices.size() >= 3) {
380                slices[counter] = SortElement(polys[i][j]->vertices[0].z, i, j);
381                counter++;
382            }
383        }
384    }
385
386    //sort them
387    qsort(slices, total_rendered_slices, sizeof(SortElement), sliceSort);
388
389    //Now we are ready to render all the slices from back to front
390    glEnable(GL_DEPTH_TEST);
391    // Non pre-multiplied alpha
392    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
393    glEnable(GL_BLEND);
394
395    for (size_t i = 0; i < total_rendered_slices; i++) {
396        Volume *volPtr = NULL;
397
398        int volume_index = slices[i].volumeId;
399        int slice_index = slices[i].sliceId;
400        ConvexPolygon *cur = polys[volume_index][slice_index];
401
402        volPtr = volumes[volume_index];
403
404        glPushMatrix();
405        glScalef(volPtr->aspectRatioWidth,
406                 volPtr->aspectRatioHeight,
407                 volPtr->aspectRatioDepth);
408
409#ifdef notdef
410        TRACE("shading slice: volume %s addr=%x slice=%d, volume=%d\n",
411               volPtr->name(), volPtr, slice_index, volume_index);
412#endif
413        activateVolumeShader(volPtr, false);
414        glPopMatrix();
415
416        glBegin(GL_POLYGON);
417        cur->emit(true);
418        glEnd();
419
420        deactivateVolumeShader();
421    }
422
423    glPopAttrib();
424
425    //Deallocate all the memory used
426    for (size_t i = 0; i < volumes.size(); i++) {
427        for (size_t j = 0; j <actual_slices[i]; j++) {
428            delete polys[i][j];
429        }
430        if (polys[i]) {
431            delete[] polys[i];
432        }
433    }
434    delete[] polys;
435    delete[] actual_slices;
436    free(slices);
437}
438
439void
440VolumeRenderer::drawBoundingBox(float x0, float y0, float z0,
441                                float x1, float y1, float z1,
442                                float r, float g, float b,
443                                float line_width)
444{
445    glPushAttrib(GL_ENABLE_BIT);
446
447    glEnable(GL_DEPTH_TEST);
448    glDisable(GL_TEXTURE_2D);
449    glEnable(GL_BLEND);
450
451    glMatrixMode(GL_MODELVIEW);
452    glPushMatrix();
453
454    glColor4d(r, g, b, 1.0);
455    glLineWidth(line_width);
456
457    glBegin(GL_LINE_LOOP);
458    {
459        glVertex3d(x0, y0, z0);
460        glVertex3d(x1, y0, z0);
461        glVertex3d(x1, y1, z0);
462        glVertex3d(x0, y1, z0);
463    }
464    glEnd();
465
466    glBegin(GL_LINE_LOOP);
467    {
468        glVertex3d(x0, y0, z1);
469        glVertex3d(x1, y0, z1);
470        glVertex3d(x1, y1, z1);
471        glVertex3d(x0, y1, z1);
472    }
473    glEnd();
474
475    glBegin(GL_LINE_LOOP);
476    {
477        glVertex3d(x0, y0, z0);
478        glVertex3d(x0, y0, z1);
479        glVertex3d(x0, y1, z1);
480        glVertex3d(x0, y1, z0);
481    }
482    glEnd();
483
484    glBegin(GL_LINE_LOOP);
485    {
486        glVertex3d(x1, y0, z0);
487        glVertex3d(x1, y0, z1);
488        glVertex3d(x1, y1, z1);
489        glVertex3d(x1, y1, z0);
490    }
491    glEnd();
492
493#ifdef notdef
494    /* Rappture doesn't supply axis units yet. So turn labeling off until we
495     * can display the proper units with the distance of each bounding box
496     * dimension.
497     */
498    glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
499
500    if (NanoVis::fonts != NULL) {
501        double mv[16], prjm[16];
502        int viewport[4];
503        double wx, wy, wz;
504        double dx, dy, dz;
505
506        glGetDoublev(GL_MODELVIEW_MATRIX, mv);
507        glGetDoublev(GL_PROJECTION_MATRIX, prjm);
508        glGetIntegerv(GL_VIEWPORT, viewport);
509
510        NanoVis::fonts->begin();
511        dx = x1 - x0;
512        dy = y1 - y0;
513        dz = z1 - z0;
514        if (gluProject((x0 + x1) * 0.5, y0, z0, mv, prjm, viewport,
515                       &wx, &wy, &wz)) {
516            char buff[20];
517            double min, max;
518
519            NanoVis::grid->xAxis.GetDataLimits(min, max);
520            glLoadIdentity();
521            glTranslatef((int)wx, viewport[3] - (int) wy, 0.0f);
522            const char *units;
523            units = NanoVis::grid->xAxis.GetUnits();
524            sprintf(buff, "%.*g %s", NUMDIGITS, max - min, units);
525            NanoVis::fonts->draw(buff);
526        }
527        if (gluProject(x0, (y0 + y1) * 0.5, z0, mv, prjm, viewport, &
528                       wx, &wy, &wz)) {
529            char buff[20];
530            double min, max;
531
532            NanoVis::grid->yAxis.GetDataLimits(min, max);
533            glLoadIdentity();
534            glTranslatef((int)wx, viewport[3] - (int) wy, 0.0f);
535            const char *units;
536            units = NanoVis::grid->yAxis.GetUnits();
537            sprintf(buff, "%.*g %s", NUMDIGITS, max - min, units);
538            NanoVis::fonts->draw(buff);
539        }
540        if (gluProject(x0, y0, (z0 + z1) * 0.5, mv, prjm, viewport,
541                       &wx, &wy, &wz)) {
542            glLoadIdentity();
543            glTranslatef((int)wx, viewport[3] - (int) wy, 0.0f);
544
545            double min, max;
546            NanoVis::grid->zAxis.GetDataLimits(min, max);
547            const char *units;
548            units = NanoVis::grid->zAxis.GetUnits();
549            char buff[20];
550            sprintf(buff, "%.*g %s", NUMDIGITS, max - min, units);
551            NanoVis::fonts->draw(buff);
552        }
553        NanoVis::fonts->end();
554    };
555#endif
556    glPopMatrix();
557    glPopAttrib();
558}
559
560void
561VolumeRenderer::activateVolumeShader(Volume* volPtr, bool sliceMode)
562{
563    //vertex shader
564    _stdVertexShader->bind();
565    TransferFunction *tfPtr  = volPtr->transferFunction();
566    if (volPtr->volumeType() == Volume::CUBIC) {
567        _regularVolumeShader->bind(tfPtr->id(), volPtr, sliceMode);
568    } else if (volPtr->volumeType() == Volume::ZINCBLENDE) {
569        _zincBlendeShader->bind(tfPtr->id(), volPtr, sliceMode);
570    }
571}
572
573void VolumeRenderer::deactivateVolumeShader()
574{
575    _stdVertexShader->unbind();
576    _regularVolumeShader->unbind();
577    _zincBlendeShader->unbind();
578}
579
580void VolumeRenderer::getEyeSpaceBounds(const Mat4x4& mv,
581                                       double& xMin, double& xMax,
582                                       double& yMin, double& yMax,
583                                       double& zNear, double& zFar)
584{
585    double x0 = 0;
586    double y0 = 0;
587    double z0 = 0;
588    double x1 = 1;
589    double y1 = 1;
590    double z1 = 1;
591
592    double zMin, zMax;
593    xMin = DBL_MAX;
594    xMax = -DBL_MAX;
595    yMin = DBL_MAX;
596    yMax = -DBL_MAX;
597    zMin = DBL_MAX;
598    zMax = -DBL_MAX;
599
600    double vertex[8][4];
601
602    vertex[0][0]=x0; vertex[0][1]=y0; vertex[0][2]=z0; vertex[0][3]=1.0;
603    vertex[1][0]=x1; vertex[1][1]=y0; vertex[1][2]=z0; vertex[1][3]=1.0;
604    vertex[2][0]=x0; vertex[2][1]=y1; vertex[2][2]=z0; vertex[2][3]=1.0;
605    vertex[3][0]=x0; vertex[3][1]=y0; vertex[3][2]=z1; vertex[3][3]=1.0;
606    vertex[4][0]=x1; vertex[4][1]=y1; vertex[4][2]=z0; vertex[4][3]=1.0;
607    vertex[5][0]=x1; vertex[5][1]=y0; vertex[5][2]=z1; vertex[5][3]=1.0;
608    vertex[6][0]=x0; vertex[6][1]=y1; vertex[6][2]=z1; vertex[6][3]=1.0;
609    vertex[7][0]=x1; vertex[7][1]=y1; vertex[7][2]=z1; vertex[7][3]=1.0;
610
611    for (int i = 0; i < 8; i++) {
612        Vector4 eyeVert = mv.transform(Vector4(vertex[i][0],
613                                               vertex[i][1],
614                                               vertex[i][2],
615                                               vertex[i][3]));
616        if (eyeVert.x < xMin) xMin = eyeVert.x;
617        if (eyeVert.x > xMax) xMax = eyeVert.x;
618        if (eyeVert.y < yMin) yMin = eyeVert.y;
619        if (eyeVert.y > yMax) yMax = eyeVert.y;
620        if (eyeVert.z < zMin) zMin = eyeVert.z;
621        if (eyeVert.z > zMax) zMax = eyeVert.z;
622    }
623
624    zNear = zMax;
625    zFar = zMin;
626}
627
628bool
629VolumeRenderer::initFont(const char *filename)
630{
631    FILE *f;
632    unsigned short int bfType;
633    int bfOffBits;
634    short int biPlanes;
635    short int biBitCount;
636    int biSizeImage;
637    int width, height;
638    int i;
639    unsigned char temp;
640    unsigned char* data;
641    /* make sure the file is there and open it read-only (binary) */
642    f = fopen(filename, "rb");
643    if (f == NULL) {
644        ERROR("can't open font file \"%s\"\n", filename);
645        return false;
646    }
647
648    if (fread(&bfType, sizeof(short int), 1, f) != 1) {
649        ERROR("can't read %lu bytes from font file \"%s\"\n",
650               (unsigned long)sizeof(short int), filename);
651        goto error;
652    }
653
654    /* check if file is a bitmap */
655    if (bfType != 19778) {
656        ERROR("not a bmp file.\n");
657        goto error;
658    }
659
660    /* get the file size */
661    /* skip file size and reserved fields of bitmap file header */
662    fseek(f, 8, SEEK_CUR);
663
664    /* get the position of the actual bitmap data */
665    if (fread(&bfOffBits, sizeof(int), 1, f) != 1) {
666        ERROR("error reading file.\n");
667        goto error;
668    }
669    //TRACE("Data at Offset: %ld\n", bfOffBits);
670
671    /* skip size of bitmap info header */
672    fseek(f, 4, SEEK_CUR);
673
674    /* get the width of the bitmap */
675    if (fread(&width, sizeof(int), 1, f) != 1) {
676        ERROR("error reading file.\n");
677        goto error;
678    }
679    //TRACE("Width of Bitmap: %d\n", texture->width);
680
681    /* get the height of the bitmap */
682    if (fread(&height, sizeof(int), 1, f) != 1) {
683        ERROR("error reading file.\n");
684        goto error;
685    }
686    //TRACE("Height of Bitmap: %d\n", texture->height);
687
688    /* get the number of planes (must be set to 1) */
689    if (fread(&biPlanes, sizeof(short int), 1, f) != 1) {
690        ERROR("error reading file.\n");
691        goto error;
692    }
693    if (biPlanes != 1) {
694        ERROR("number of Planes not 1!\n");
695        goto error;
696    }
697
698    /* get the number of bits per pixel */
699    if (fread(&biBitCount, sizeof(short int), 1, f) != 1) {
700        ERROR("error reading file.\n");
701        goto error;
702    }
703
704    //TRACE("Bits per Pixel: %d\n", biBitCount);
705    if (biBitCount != 24) {
706        ERROR("Bits per Pixel not 24\n");
707        goto error;
708    }
709
710    /* calculate the size of the image in bytes */
711    biSizeImage = width * height * 3 * sizeof(unsigned char);
712    data = (unsigned char*) malloc(biSizeImage);
713    if (data == NULL) {
714        ERROR("Can't allocate memory for image\n");
715        goto error;
716    }
717
718    /* seek to the actual data */
719    fseek(f, bfOffBits, SEEK_SET);
720    if (fread(data, biSizeImage, 1, f) != 1) {
721        ERROR("Error loading file!\n");
722        goto error;
723    }
724    fclose(f);
725
726    /* swap red and blue (bgr -> rgb) */
727    for (i = 0; i < biSizeImage; i += 3) {
728       temp = data[i];
729       data[i] = data[i + 2];
730       data[i + 2] = temp;
731    }
732
733    //insert alpha channel
734    unsigned char* data_with_alpha;
735    data_with_alpha = (unsigned char*)
736        malloc(width*height*4*sizeof(unsigned char));
737    for (int i = 0; i < height; i++) {
738        for (int j = 0; j < width; j++) {
739            unsigned char r, g, b, a;
740            r = data[3*(i*width+j)];
741            g = data[3*(i*width+j)+1];
742            b = data[3*(i*width+j)+2];
743
744            if (r==0 && g==0 && b==0)
745                a = 0;
746            else
747                a = 255;
748
749            data_with_alpha[4*(i*width+j)] = r;
750            data_with_alpha[4*(i*width+j) + 1] = g;
751            data_with_alpha[4*(i*width+j) + 2] = b;
752            data_with_alpha[4*(i*width+j) + 3] = a;
753        }
754    }
755    free(data);
756
757    //create opengl texture
758    glGenTextures(1, &_fontTexture);
759    glBindTexture(GL_TEXTURE_2D, _fontTexture);
760    //glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
761    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data_with_alpha);
762    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
763    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
764    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
765
766    free(data_with_alpha);
767
768    buildFont();
769    return (glGetError()==0);
770
771 error:
772    fclose(f);
773    return false;
774}
775
776void
777VolumeRenderer::drawLabel(Volume* vol)
778{
779    //glEnable(GL_TEXTURE_2D);
780    glDisable(GL_TEXTURE_2D);
781    glEnable(GL_DEPTH_TEST);
782
783    //x
784    glColor3f(0.5, 0.5, 0.5);
785
786    int length = vol->label[0].size();
787    glPushMatrix();
788
789    glTranslatef(.5 * vol->aspectRatioWidth,
790                 vol->aspectRatioHeight,
791                 -0.1 * vol->aspectRatioDepth);
792    glRotatef(180, 0, 0, 1);
793    glRotatef(90, 1, 0, 0);
794
795    glScalef(0.0008, 0.0008, 0.0008);
796    for (int i = 0; i < length; i++) {
797        glutStrokeCharacter(GLUT_STROKE_ROMAN, vol->label[0].c_str()[i]);
798        glTranslatef(0.04, 0., 0.);
799    }
800    glPopMatrix();
801
802    //y
803    length = vol->label[1].size();
804    glPushMatrix();
805    glTranslatef(vol->aspectRatioWidth,
806                 0.5*vol->aspectRatioHeight,
807                 -0.1*vol->aspectRatioDepth);
808    glRotatef(90, 0, 1, 0);
809    glRotatef(90, 0, 0, 1);
810
811    glScalef(0.0008, 0.0008, 0.0008);
812    for (int i = 0; i < length; i++) {
813        glutStrokeCharacter(GLUT_STROKE_ROMAN, vol->label[1].c_str()[i]);
814        glTranslatef(0.04, 0., 0.);
815    }
816    glPopMatrix();
817
818    //z
819    length = vol->label[2].size();
820    glPushMatrix();
821    glTranslatef(0.,
822                 1. * vol->aspectRatioHeight,
823                 0.5 * vol->aspectRatioDepth);
824    glRotatef(90, 0, 1, 0);
825
826    glScalef(0.0008, 0.0008, 0.0008);
827    for (int i = 0; i < length; i++) {
828        glutStrokeCharacter(GLUT_STROKE_ROMAN, vol->label[2].c_str()[i]);
829        glTranslatef(0.04, 0., 0.);
830    }
831    glPopMatrix();
832
833    glDisable(GL_TEXTURE_2D);
834}
835
836void
837VolumeRenderer::buildFont()
838{
839    GLfloat cx, cy;         /* the character coordinates in our texture */
840    _fontBase = glGenLists(256);
841    glBindTexture(GL_TEXTURE_2D, _fontTexture);
842    for (int loop = 0; loop < 256; loop++) {
843        cx = (float) (loop % 16) / 16.0f;
844        cy = (float) (loop / 16) / 16.0f;
845        glNewList(_fontBase + loop, GL_COMPILE);
846        glBegin(GL_QUADS);
847        glTexCoord2f(cx, 1 - cy - 0.0625f);
848        glVertex3f(0, 0, 0);
849        glTexCoord2f(cx + 0.0625f, 1 - cy - 0.0625f);
850        glVertex3f(0.04, 0, 0);
851        glTexCoord2f(cx + 0.0625f, 1 - cy);
852        glVertex3f(0.04, 0.04, 0);
853        glTexCoord2f(cx, 1 - cy);
854        glVertex3f(0, 0.04, 0);
855        glEnd();
856        glTranslated(0.04, 0, 0);
857        glEndList();
858    }
859}
860
861void
862VolumeRenderer::glPrint(char* string, int set)
863{
864    if (set > 1) {
865        set = 1;
866    }
867    glBindTexture(GL_TEXTURE_2D, _fontTexture);
868    glListBase(_fontBase - 32 + (128 * set));
869    glCallLists(strlen(string), GL_BYTE, string);
870}
Note: See TracBrowser for help on using the repository browser.