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

Last change on this file since 2804 was 2804, checked in by ldelgass, 13 years ago

another vector -> std::vector

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