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

Last change on this file since 2973 was 2973, checked in by ldelgass, 12 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
RevLine 
[2798]1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
[406]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 */
[2822]16#include <stdlib.h>
[1328]17#include <assert.h>
18#include <time.h>
19#include <sys/time.h>
[2973]20#include <float.h>
[2804]21
[2972]22#include <vector>
23
[2822]24#include <GL/glew.h>
25#include <GL/glut.h>
26
27#include <tcl.h>
28
[617]29#include <R2/R2FilePath.h>
[2804]30
31#include "nanovis.h"
[2822]32#include "VolumeRenderer.h"
33#include "ConvexPolygon.h"
[2804]34
[617]35#include "NvStdVertexShader.h"
[884]36#include "Trace.h"
[1028]37#include "Grid.h"
[406]38
[1028]39#define NUMDIGITS       6
[406]40
[2804]41VolumeRenderer::VolumeRenderer() :
[2877]42    _sliceMode(false),
43    _volumeMode(true)
[406]44{
[2877]45    initShaders();
[617]46
[2972]47    std::string path = R2FilePath::getInstance()->getPath("Font.bmp");
48    if (path.empty()) {
[2822]49        ERROR("can't find Font.bmp\n");
[2972]50        assert(!path.empty());
[1111]51    }
[2972]52    initFont(path.c_str());
[884]53    _volumeInterpolator = new VolumeInterpolator();
[418]54}
55
[580]56VolumeRenderer::~VolumeRenderer()
57{
[617]58    delete _zincBlendeShader;
59    delete _regularVolumeShader;
60    delete _stdVertexShader;
[884]61    delete _volumeInterpolator;
[580]62}
[418]63
64//initialize the volume shaders
[2877]65void VolumeRenderer::initShaders()
[2822]66{
67    //standard vertex program
68    _stdVertexShader = new NvStdVertexShader();
[406]69
[2822]70    //volume rendering shader: one cubic volume
71    _regularVolumeShader = new NvRegularVolumeShader();
[524]72
[2822]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();
[406]82}
83
[1258]84struct SortElement {
85    float z;
[2877]86    int volumeId;
87    int sliceId;
[2822]88
[2804]89    SortElement(float _z, int _v, int _s) :
[2877]90        z(_z),
91        volumeId(_v),
92        sliceId(_s)
[2804]93    {}
[415]94};
95
[2877]96static int sliceSort(const void *a, const void *b)
[2822]97{
98    if ((*((SortElement*)a)).z > (*((SortElement*)b)).z)
[2804]99        return 1;
100    else
101        return -1;
[415]102}
103
[1258]104void
[2877]105VolumeRenderer::renderAll()
[580]106{
[1478]107    size_t total_rendered_slices = 0;
[900]108
[2877]109    if (_volumeInterpolator->isStarted()) {
[1478]110#ifdef notdef
[884]111        ani_vol = _volumeInterpolator->getVolume();
[1478]112        ani_tf = ani_vol->transferFunction();
113#endif
[2853]114        TRACE("VOLUME INTERPOLATOR IS STARTED ----------------------------");
[884]115    }
[1478]116    // Determine the volumes that are to be rendered.
[2804]117    std::vector<Volume *> volumes;
[1493]118    Tcl_HashEntry *hPtr;
119    Tcl_HashSearch iter;
120    for (hPtr = Tcl_FirstHashEntry(&NanoVis::volumeTable, &iter); hPtr != NULL;
[2853]121         hPtr = Tcl_NextHashEntry(&iter)) {
122        Volume* volPtr;
123        volPtr = (Volume *)Tcl_GetHashValue(hPtr);
[2804]124        if (!volPtr->visible()) {
[2853]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);
[2877]133        volPtr->numSlices(256 - volumes.size());
[1478]134    }
[884]135
[2932]136    glPushAttrib(GL_ENABLE_BIT);
137
[1258]138    //two dimension pointer array
[2853]139    ConvexPolygon ***polys = new ConvexPolygon**[volumes.size()];
[1258]140    //number of actual slices for each volume
[2932]141    size_t *actual_slices = new size_t[volumes.size()];
[884]142
[1984]143    TRACE("start loop %d\n", volumes.size());
[1478]144    for (size_t i = 0; i < volumes.size(); i++) {
[2853]145        Volume *volPtr = volumes[i];
[1478]146        polys[i] = NULL;
147        actual_slices[i] = 0;
[1429]148
[2877]149        int n_slices = volPtr->numSlices();
[1478]150        if (volPtr->isosurface()) {
[2853]151            // double the number of slices
152            n_slices <<= 1;
153        }
[2804]154
[900]155        //volume start location
[1478]156        Vector3 loc = volPtr->location();
157        Vector4 shift_4d(loc.x, loc.y, loc.z, 0);
[2804]158
[900]159        double x0 = 0;
160        double y0 = 0;
161        double z0 = 0;
[2804]162
[900]163        Mat4x4 model_view_no_trans, model_view_trans;
164        Mat4x4 model_view_no_trans_inverse, model_view_trans_inverse;
[2804]165
[2853]166        //initialize volume plane with world coordinates
[900]167        Plane volume_planes[6];
[2906]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);
[2804]174
[2853]175        //get modelview matrix with no translation
[900]176        glPushMatrix();
[2877]177        glScalef(volPtr->aspectRatioWidth,
178                 volPtr->aspectRatioHeight,
179                 volPtr->aspectRatioDepth);
[2804]180
[900]181        glEnable(GL_DEPTH_TEST);
[2804]182
[900]183        GLfloat mv_no_trans[16];
184        glGetFloatv(GL_MODELVIEW_MATRIX, mv_no_trans);
[2804]185
[900]186        model_view_no_trans = Mat4x4(mv_no_trans);
187        model_view_no_trans_inverse = model_view_no_trans.inverse();
[2804]188
[900]189        glPopMatrix();
[2804]190
[2853]191        //get modelview matrix with translation
[900]192        glPushMatrix();
193        glTranslatef(shift_4d.x, shift_4d.y, shift_4d.z);
[2877]194        glScalef(volPtr->aspectRatioWidth,
195                 volPtr->aspectRatioHeight,
196                 volPtr->aspectRatioDepth);
[900]197        GLfloat mv_trans[16];
198        glGetFloatv(GL_MODELVIEW_MATRIX, mv_trans);
[2804]199
[900]200        model_view_trans = Mat4x4(mv_trans);
201        model_view_trans_inverse = model_view_trans.inverse();
[2804]202
[2853]203        //draw volume bounding box with translation (the correct location in
204        //space)
[1478]205        if (volPtr->outline()) {
[900]206            float olcolor[3];
[2877]207            volPtr->getOutlineColor(olcolor);
208            drawBoundingBox(x0, y0, z0, x0+1, y0+1, z0+1,
[2853]209                (double)olcolor[0], (double)olcolor[1], (double)olcolor[2],
210                1.5);
[900]211        }
212        glPopMatrix();
[2804]213
[900]214        //draw labels
215        glPushMatrix();
216        glTranslatef(shift_4d.x, shift_4d.y, shift_4d.z);
[2932]217        if (volPtr->outline()) {
218            //drawLabel(i);
[900]219        }
220        glPopMatrix();
[2804]221
[2853]222        //transform volume_planes to eye coordinates.
[2804]223        for (size_t j = 0; j < 6; j++) {
[1478]224            volume_planes[j].transform(model_view_no_trans);
[2853]225        }
[2973]226        double eyeMinX, eyeMaxX, eyeMinY, eyeMaxY, zNear, zFar;
227        getEyeSpaceBounds(model_view_no_trans,
228                          eyeMinX, eyeMaxX,
229                          eyeMinY, eyeMaxY,
230                          zNear, zFar);
[2804]231
[2853]232        //compute actual rendering slices
233        float z_step = fabs(zNear-zFar)/n_slices;
[1478]234        size_t n_actual_slices;
[2804]235
[2877]236        if (volPtr->dataEnabled()) {
[900]237            n_actual_slices = (int)(fabs(zNear-zFar)/z_step + 1);
[1478]238            polys[i] = new ConvexPolygon*[n_actual_slices];
[900]239        } else {
240            n_actual_slices = 0;
[1478]241            polys[i] = NULL;
[900]242        }
[1478]243        actual_slices[i] = n_actual_slices;
[2804]244
[2973]245        // These are object coordinates
[900]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));
[2804]250
[2853]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.
[1825]255
[2853]256        ConvexPolygon static_poly;
[2877]257        for (int j = 0; j < volPtr->getCutplaneCount(); j++) {
258            if (!volPtr->isCutplaneEnabled(j)) {
[2853]259                continue;
260            }
[2877]261            float offset = volPtr->getCutplane(j)->offset;
262            int axis = volPtr->getCutplane(j)->orient;
[2853]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            }
[2804]283
[2853]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);
[2804]288
[2853]289            ConvexPolygon *p = &static_poly;
290            p->vertices.clear();
[2804]291
[2877]292            p->appendVertex(vert1);
293            p->appendVertex(vert2);
294            p->appendVertex(vert3);
295            p->appendVertex(vert4);
[2804]296
[2853]297            for (size_t k = 0; k < 6; k++) {
298                p->clip(volume_planes[k], true);
299            }
[2804]300
[2853]301            p->transform(model_view_no_trans_inverse);
302            p->transform(model_view_trans);
[2804]303
[2853]304            glPushMatrix();
[2877]305            glScalef(volPtr->aspectRatioWidth,
306                     volPtr->aspectRatioHeight,
307                     volPtr->aspectRatioDepth);
[2804]308
[2877]309            activateVolumeShader(volPtr, true);
[2853]310            glPopMatrix();
[2804]311
[2853]312            glEnable(GL_DEPTH_TEST);
313            glDisable(GL_BLEND);
[2804]314
[2853]315            glBegin(GL_POLYGON);
[2877]316            p->emit(true);
[2853]317            glEnd();
318            glDisable(GL_DEPTH_TEST);
[2804]319
[2877]320            deactivateVolumeShader();
[2853]321        } //done cutplanes
[2804]322
[2853]323        //Now do volume rendering
324
[2973]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));
[2804]331
[1478]332        size_t counter = 0;
[2804]333
[2853]334        //transform slices and store them
[900]335        float slice_z;
[1478]336        for (size_t j = 0; j < n_actual_slices; j++) {
[2853]337            slice_z = zFar + j * z_step; //back to front
[2804]338
[900]339            ConvexPolygon *poly = new ConvexPolygon();
[1478]340            polys[i][counter] = poly;
[900]341            counter++;
[2804]342
[900]343            poly->vertices.clear();
[2877]344            poly->setId(i);
[2804]345
[2973]346            // Set eye space Z-coordinate of slice
[900]347            vert1.z = slice_z;
348            vert2.z = slice_z;
349            vert3.z = slice_z;
350            vert4.z = slice_z;
[2804]351
[2877]352            poly->appendVertex(vert1);
353            poly->appendVertex(vert2);
354            poly->appendVertex(vert3);
355            poly->appendVertex(vert4);
[2804]356
357            for (size_t k = 0; k < 6; k++) {
[2853]358                poly->clip(volume_planes[k], true);
359            }
[2804]360
[900]361            poly->transform(model_view_no_trans_inverse);
362            poly->transform(model_view_trans);
[2804]363
364            if (poly->vertices.size() >= 3)
[2853]365                total_rendered_slices++;
[900]366        }
[1258]367    } //iterate all volumes
[1984]368    TRACE("end loop\n");
[2804]369
[1493]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
[2804]372
[2853]373    SortElement *slices = (SortElement *)
374        malloc(sizeof(SortElement) * total_rendered_slices);
[2804]375
[1478]376    size_t counter = 0;
[2804]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) {
[900]380                slices[counter] = SortElement(polys[i][j]->vertices[0].z, i, j);
381                counter++;
382            }
383        }
[884]384    }
[2804]385
[1258]386    //sort them
[2877]387    qsort(slices, total_rendered_slices, sizeof(SortElement), sliceSort);
[2804]388
[1258]389    //Now we are ready to render all the slices from back to front
[900]390    glEnable(GL_DEPTH_TEST);
[2932]391    // Non pre-multiplied alpha
392    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
[900]393    glEnable(GL_BLEND);
[2804]394
395    for (size_t i = 0; i < total_rendered_slices; i++) {
[2853]396        Volume *volPtr = NULL;
[1478]397
[2877]398        int volume_index = slices[i].volumeId;
399        int slice_index = slices[i].sliceId;
[2853]400        ConvexPolygon *cur = polys[volume_index][slice_index];
[2804]401
[2853]402        volPtr = volumes[volume_index];
403
[900]404        glPushMatrix();
[2877]405        glScalef(volPtr->aspectRatioWidth,
406                 volPtr->aspectRatioHeight,
407                 volPtr->aspectRatioDepth);
[2804]408
[1493]409#ifdef notdef
[2853]410        TRACE("shading slice: volume %s addr=%x slice=%d, volume=%d\n",
411               volPtr->name(), volPtr, slice_index, volume_index);
[1493]412#endif
[2877]413        activateVolumeShader(volPtr, false);
[900]414        glPopMatrix();
[2804]415
[900]416        glBegin(GL_POLYGON);
[2877]417        cur->emit(true);
[900]418        glEnd();
[884]419
[2877]420        deactivateVolumeShader();
[884]421    }
[2804]422
[2932]423    glPopAttrib();
[2804]424
[900]425    //Deallocate all the memory used
[2804]426    for (size_t i = 0; i < volumes.size(); i++) {
427        for (size_t j = 0; j <actual_slices[i]; j++) {
[900]428            delete polys[i][j];
429        }
[1258]430        if (polys[i]) {
[900]431            delete[] polys[i];
432        }
[452]433    }
[900]434    delete[] polys;
435    delete[] actual_slices;
436    free(slices);
[415]437}
438
[1478]439void
[2877]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)
[406]444{
[2932]445    glPushAttrib(GL_ENABLE_BIT);
446
[1028]447    glEnable(GL_DEPTH_TEST);
448    glDisable(GL_TEXTURE_2D);
449    glEnable(GL_BLEND);
[406]450
[2932]451    glMatrixMode(GL_MODELVIEW);
452    glPushMatrix();
453
[1028]454    glColor4d(r, g, b, 1.0);
455    glLineWidth(line_width);
[2804]456
[1028]457    glBegin(GL_LINE_LOOP);
458    {
[2853]459        glVertex3d(x0, y0, z0);
460        glVertex3d(x1, y0, z0);
461        glVertex3d(x1, y1, z0);
462        glVertex3d(x0, y1, z0);
[1028]463    }
464    glEnd();
[2804]465
[1028]466    glBegin(GL_LINE_LOOP);
467    {
[2853]468        glVertex3d(x0, y0, z1);
469        glVertex3d(x1, y0, z1);
470        glVertex3d(x1, y1, z1);
471        glVertex3d(x0, y1, z1);
[1028]472    }
473    glEnd();
[2853]474
[1028]475    glBegin(GL_LINE_LOOP);
476    {
[2853]477        glVertex3d(x0, y0, z0);
478        glVertex3d(x0, y0, z1);
479        glVertex3d(x0, y1, z1);
480        glVertex3d(x0, y1, z0);
[1028]481    }
482    glEnd();
[2804]483
[1028]484    glBegin(GL_LINE_LOOP);
485    {
[2853]486        glVertex3d(x1, y0, z0);
487        glVertex3d(x1, y0, z1);
488        glVertex3d(x1, y1, z1);
489        glVertex3d(x1, y1, z0);
[1028]490    }
491    glEnd();
[406]492
[1028]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);
[406]499
[1028]500    if (NanoVis::fonts != NULL) {
[2853]501        double mv[16], prjm[16];
502        int viewport[4];
503        double wx, wy, wz;
504        double dx, dy, dz;
[406]505
[2853]506        glGetDoublev(GL_MODELVIEW_MATRIX, mv);
507        glGetDoublev(GL_PROJECTION_MATRIX, prjm);
508        glGetIntegerv(GL_VIEWPORT, viewport);
[406]509
[2853]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;
[406]518
[2853]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;
[406]531
[2853]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();
[1028]554    };
555#endif
556    glPopMatrix();
[2932]557    glPopAttrib();
[406]558}
559
[1478]560void
[2877]561VolumeRenderer::activateVolumeShader(Volume* volPtr, bool sliceMode)
[617]562{
[1478]563    //vertex shader
564    _stdVertexShader->bind();
[1493]565    TransferFunction *tfPtr  = volPtr->transferFunction();
[2877]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);
[1478]570    }
[406]571}
[2877]572
573void VolumeRenderer::deactivateVolumeShader()
[580]574{
[617]575    _stdVertexShader->unbind();
576    _regularVolumeShader->unbind();
577    _zincBlendeShader->unbind();
[406]578}
579
[2973]580void VolumeRenderer::getEyeSpaceBounds(const Mat4x4& mv,
581                                       double& xMin, double& xMax,
582                                       double& yMin, double& yMax,
583                                       double& zNear, double& zFar)
[406]584{
[2822]585    double x0 = 0;
586    double y0 = 0;
587    double z0 = 0;
588    double x1 = 1;
589    double y1 = 1;
590    double z1 = 1;
[406]591
[2822]592    double zMin, zMax;
[2973]593    xMin = DBL_MAX;
594    xMax = -DBL_MAX;
595    yMin = DBL_MAX;
596    yMax = -DBL_MAX;
597    zMin = DBL_MAX;
598    zMax = -DBL_MAX;
[406]599
[2822]600    double vertex[8][4];
[406]601
[2822]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;
[406]610
[2822]611    for (int i = 0; i < 8; i++) {
[2973]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;
[2822]622    }
[406]623
[2822]624    zNear = zMax;
625    zFar = zMin;
[406]626}
627
[1374]628bool
[2877]629VolumeRenderer::initFont(const char *filename)
[1374]630{
631    FILE *f;
[448]632    unsigned short int bfType;
[1177]633    int bfOffBits;
[448]634    short int biPlanes;
635    short int biBitCount;
[1177]636    int biSizeImage;
[448]637    int width, height;
638    int i;
639    unsigned char temp;
[1374]640    unsigned char* data;
[448]641    /* make sure the file is there and open it read-only (binary) */
[1374]642    f = fopen(filename, "rb");
643    if (f == NULL) {
[2853]644        ERROR("can't open font file \"%s\"\n", filename);
645        return false;
[448]646    }
[2804]647
[1374]648    if (fread(&bfType, sizeof(short int), 1, f) != 1) {
[2853]649        ERROR("can't read %lu bytes from font file \"%s\"\n",
650               (unsigned long)sizeof(short int), filename);
651        goto error;
[448]652    }
[2804]653
[448]654    /* check if file is a bitmap */
[1028]655    if (bfType != 19778) {
[2853]656        ERROR("not a bmp file.\n");
657        goto error;
[448]658    }
[2804]659
[448]660    /* get the file size */
661    /* skip file size and reserved fields of bitmap file header */
[1374]662    fseek(f, 8, SEEK_CUR);
[2804]663
[448]664    /* get the position of the actual bitmap data */
[1374]665    if (fread(&bfOffBits, sizeof(int), 1, f) != 1) {
[2853]666        ERROR("error reading file.\n");
667        goto error;
[448]668    }
[2376]669    //TRACE("Data at Offset: %ld\n", bfOffBits);
[2804]670
[448]671    /* skip size of bitmap info header */
[1374]672    fseek(f, 4, SEEK_CUR);
[2804]673
[448]674    /* get the width of the bitmap */
[1374]675    if (fread(&width, sizeof(int), 1, f) != 1) {
[2853]676        ERROR("error reading file.\n");
677        goto error;
[1374]678    }
[2376]679    //TRACE("Width of Bitmap: %d\n", texture->width);
[2804]680
[448]681    /* get the height of the bitmap */
[1374]682    if (fread(&height, sizeof(int), 1, f) != 1) {
[2853]683        ERROR("error reading file.\n");
684        goto error;
[1374]685    }
[2376]686    //TRACE("Height of Bitmap: %d\n", texture->height);
[2804]687
[448]688    /* get the number of planes (must be set to 1) */
[1374]689    if (fread(&biPlanes, sizeof(short int), 1, f) != 1) {
[2853]690        ERROR("error reading file.\n");
691        goto error;
[448]692    }
[1374]693    if (biPlanes != 1) {
[2853]694        ERROR("number of Planes not 1!\n");
695        goto error;
[1374]696    }
[2804]697
[448]698    /* get the number of bits per pixel */
[1374]699    if (fread(&biBitCount, sizeof(short int), 1, f) != 1) {
[2853]700        ERROR("error reading file.\n");
701        goto error;
[448]702    }
[2804]703
[2376]704    //TRACE("Bits per Pixel: %d\n", biBitCount);
[1028]705    if (biBitCount != 24) {
[2853]706        ERROR("Bits per Pixel not 24\n");
707        goto error;
[448]708    }
709
710    /* calculate the size of the image in bytes */
711    biSizeImage = width * height * 3 * sizeof(unsigned char);
[1374]712    data = (unsigned char*) malloc(biSizeImage);
713    if (data == NULL) {
[2853]714        ERROR("Can't allocate memory for image\n");
715        goto error;
[1374]716    }
[448]717
718    /* seek to the actual data */
[1374]719    fseek(f, bfOffBits, SEEK_SET);
720    if (fread(data, biSizeImage, 1, f) != 1) {
[2853]721        ERROR("Error loading file!\n");
722        goto error;
[448]723    }
[1374]724    fclose(f);
725
[448]726    /* swap red and blue (bgr -> rgb) */
[1028]727    for (i = 0; i < biSizeImage; i += 3) {
[448]728       temp = data[i];
729       data[i] = data[i + 2];
730       data[i + 2] = temp;
731    }
732
[452]733    //insert alpha channel
[1374]734    unsigned char* data_with_alpha;
735    data_with_alpha = (unsigned char*)
[2853]736        malloc(width*height*4*sizeof(unsigned char));
[2804]737    for (int i = 0; i < height; i++) {
[2853]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];
[2804]743
[2853]744            if (r==0 && g==0 && b==0)
745                a = 0;
746            else
747                a = 255;
[2804]748
[2853]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        }
[452]754    }
755    free(data);
[2804]756
[448]757    //create opengl texture
[2877]758    glGenTextures(1, &_fontTexture);
759    glBindTexture(GL_TEXTURE_2D, _fontTexture);
[452]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);
[448]762    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
763    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
[452]764    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
[448]765
[452]766    free(data_with_alpha);
[448]767
[2877]768    buildFont();
[1374]769    return (glGetError()==0);
770
771 error:
772    fclose(f);
773    return false;
[448]774}
775
[1374]776void
[2877]777VolumeRenderer::drawLabel(Volume* vol)
[1374]778{
[1478]779    //glEnable(GL_TEXTURE_2D);
780    glDisable(GL_TEXTURE_2D);
781    glEnable(GL_DEPTH_TEST);
[2804]782
[1478]783    //x
784    glColor3f(0.5, 0.5, 0.5);
[2804]785
[1478]786    int length = vol->label[0].size();
787    glPushMatrix();
[2804]788
[2877]789    glTranslatef(.5 * vol->aspectRatioWidth,
790                 vol->aspectRatioHeight,
791                 -0.1 * vol->aspectRatioDepth);
[452]792    glRotatef(180, 0, 0, 1);
793    glRotatef(90, 1, 0, 0);
[2804]794
[455]795    glScalef(0.0008, 0.0008, 0.0008);
[2822]796    for (int i = 0; i < length; i++) {
[2853]797        glutStrokeCharacter(GLUT_STROKE_ROMAN, vol->label[0].c_str()[i]);
798        glTranslatef(0.04, 0., 0.);
[452]799    }
[1478]800    glPopMatrix();
[2804]801
[1478]802    //y
803    length = vol->label[1].size();
804    glPushMatrix();
[2877]805    glTranslatef(vol->aspectRatioWidth,
806                 0.5*vol->aspectRatioHeight,
807                 -0.1*vol->aspectRatioDepth);
[452]808    glRotatef(90, 0, 1, 0);
809    glRotatef(90, 0, 0, 1);
[2822]810
[455]811    glScalef(0.0008, 0.0008, 0.0008);
[2822]812    for (int i = 0; i < length; i++) {
[2853]813        glutStrokeCharacter(GLUT_STROKE_ROMAN, vol->label[1].c_str()[i]);
814        glTranslatef(0.04, 0., 0.);
[452]815    }
[1478]816    glPopMatrix();
[2804]817
[1478]818    //z
819    length = vol->label[2].size();
820    glPushMatrix();
[2877]821    glTranslatef(0.,
822                 1. * vol->aspectRatioHeight,
823                 0.5 * vol->aspectRatioDepth);
[452]824    glRotatef(90, 0, 1, 0);
[2804]825
[455]826    glScalef(0.0008, 0.0008, 0.0008);
[2822]827    for (int i = 0; i < length; i++) {
[2853]828        glutStrokeCharacter(GLUT_STROKE_ROMAN, vol->label[2].c_str()[i]);
829        glTranslatef(0.04, 0., 0.);
[452]830    }
[1478]831    glPopMatrix();
[2804]832
[1478]833    glDisable(GL_TEXTURE_2D);
[448]834}
835
[1478]836void
[2877]837VolumeRenderer::buildFont()
[1478]838{
[448]839    GLfloat cx, cy;         /* the character coordinates in our texture */
[2877]840    _fontBase = glGenLists(256);
841    glBindTexture(GL_TEXTURE_2D, _fontTexture);
[1478]842    for (int loop = 0; loop < 256; loop++) {
[448]843        cx = (float) (loop % 16) / 16.0f;
844        cy = (float) (loop / 16) / 16.0f;
[2877]845        glNewList(_fontBase + loop, GL_COMPILE);
[2822]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);
[448]857        glEndList();
858    }
859}
860
[2804]861void
[1478]862VolumeRenderer::glPrint(char* string, int set)
863{
[2804]864    if (set > 1) {
[2822]865        set = 1;
[1478]866    }
[2877]867    glBindTexture(GL_TEXTURE_2D, _fontTexture);
868    glListBase(_fontBase - 32 + (128 * set));
[448]869    glCallLists(strlen(string), GL_BYTE, string);
870}
Note: See TracBrowser for help on using the repository browser.