~siretart/ubuntu/utopic/blender/libav10

« back to all changes in this revision

Viewing changes to extern/eltopo/common/gluvi.cpp

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2012-07-23 08:54:18 UTC
  • mfrom: (14.2.16 sid)
  • mto: (14.2.19 sid)
  • mto: This revision was merged to the branch mainline in revision 42.
  • Revision ID: package-import@ubuntu.com-20120723085418-9foz30v6afaf5ffs
Tags: 2.63a-2
* debian/: Cycles support added (Closes: #658075)
  For now, this top feature has been enabled only
  on [any-amd64 any-i386] architectures because
  of OpenImageIO failing on all others
* debian/: scripts installation path changed
  from /usr/lib to /usr/share:
  + debian/patches/: patchset re-worked for path changing
  + debian/control: "Breaks" field added on yafaray-exporter

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
#include <cmath>
 
3
#include <cstdarg>
 
4
#include <cstdlib>
 
5
#include <fstream>
 
6
#include <gluvi.h>
 
7
#include <limits>
 
8
#include <vec.h>
 
9
 
 
10
#ifdef __APPLE__
 
11
#include <OpenGL/OpenGL.h>
 
12
#else
 
13
#include <GL/gl.h>
 
14
#include <GL/glu.h>
 
15
#include <GL/glut.h>
 
16
#include <GL/glext.h>
 
17
#endif
 
18
 
 
19
#ifndef M_PI
 
20
#define M_PI 3.14159265358979323846f
 
21
#endif
 
22
 
 
23
using namespace std;
 
24
 
 
25
namespace Gluvi{
 
26
    
 
27
    bool taking_screenshot = false;
 
28
    GLuint screenshot_fbo;
 
29
    
 
30
    
 
31
    Target3D::
 
32
    Target3D(float target_[3], float dist_, float heading_, float pitch_, float fovy_, float near_clip_factor_, float far_clip_factor_)
 
33
    : dist(dist_), heading(heading_), pitch(pitch_),
 
34
    default_dist(dist_), default_heading(heading_), default_pitch(pitch_),
 
35
    fovy(fovy_), 
 
36
    near_clip_factor(near_clip_factor_), far_clip_factor(far_clip_factor_),
 
37
    action_mode(INACTIVE),
 
38
    oldmousex(0), oldmousey(0)
 
39
    {
 
40
        if(target_){
 
41
            target[0]=target_[0];
 
42
            target[1]=target_[1];
 
43
            target[2]=target_[2];
 
44
        }else{
 
45
            target[0]=0;
 
46
            target[1]=0;
 
47
            target[2]=0;
 
48
        }
 
49
        default_target[0]=target[0];
 
50
        default_target[1]=target[1];
 
51
        default_target[2]=target[2];
 
52
    }
 
53
    
 
54
    void Target3D::
 
55
    click(int button, int state, int x, int y)
 
56
    {
 
57
        if(state==GLUT_UP)
 
58
            action_mode=INACTIVE;
 
59
        else if(button==GLUT_LEFT_BUTTON)
 
60
            action_mode=ROTATE;
 
61
        else if(button==GLUT_MIDDLE_BUTTON)
 
62
            action_mode=TRUCK;
 
63
        else if(button==GLUT_RIGHT_BUTTON)
 
64
            action_mode=DOLLY;
 
65
        oldmousex=x;
 
66
        oldmousey=y;
 
67
    }
 
68
    
 
69
    void Target3D::
 
70
    drag(int x, int y)
 
71
    {
 
72
        switch(action_mode){
 
73
            case INACTIVE:
 
74
                return; // nothing to do
 
75
            case ROTATE:
 
76
                heading+=0.007f*(oldmousex-x);
 
77
                if(heading<-M_PI) heading+=2.0f*(float)M_PI;
 
78
                else if(heading>M_PI) heading-=2.0f*(float)M_PI;
 
79
                pitch+=0.007f*(oldmousey-y);
 
80
                if(pitch<-0.5*M_PI) pitch=-0.5f*(float)M_PI;
 
81
                else if(pitch>0.5*M_PI) pitch=0.5f*(float)M_PI;
 
82
                break;
 
83
            case TRUCK:
 
84
                target[0]+=(0.002f*dist)*cos(heading)*(oldmousex-x);
 
85
                target[1]-=(0.002f*dist)*(oldmousey-y);
 
86
                target[2]-=(0.002f*dist)*sin(heading)*(oldmousex-x);
 
87
                break;
 
88
            case DOLLY:
 
89
                dist*=pow(1.01f, oldmousey-y + x-oldmousex);
 
90
                break;
 
91
        }
 
92
        oldmousex=x;
 
93
        oldmousey=y;
 
94
        glutPostRedisplay();
 
95
    }
 
96
    
 
97
    void Target3D::
 
98
    return_to_default(void)
 
99
    {
 
100
        target[0]=default_target[0];
 
101
        target[1]=default_target[1];
 
102
        target[2]=default_target[2];
 
103
        dist=default_dist;
 
104
        heading=default_heading;
 
105
        pitch=default_pitch;
 
106
    }
 
107
    
 
108
    void Target3D::
 
109
    transform_mouse(int x, int y, float ray_origin[3], float ray_direction[3])
 
110
    {
 
111
        float ch=cos(heading), sh=sin(heading);
 
112
        float cp=cos(pitch), sp=sin(pitch);
 
113
        
 
114
        ray_origin[0]=target[0]+dist*sh*cp;
 
115
        ray_origin[1]=target[1]-dist*sp;
 
116
        ray_origin[2]=target[2]+dist*ch*cp;
 
117
        
 
118
        float scale=0.5f*tan(fovy)/winheight;
 
119
        float camx=(x-0.5f*winwidth)*scale, camy=(0.5f*winheight-y)*scale, camz=-1.0f; // in camera coordinates, this is ray_direction (but not normalized)
 
120
        // now need to rotate into world space from camera space
 
121
        float px=camx, py=camy*cp-camz*sp, pz=camy*sp+camz*cp;
 
122
        ray_direction[0]=px*ch+pz*sh;
 
123
        ray_direction[1]=py;
 
124
        ray_direction[2]=-px*sh+pz*ch;
 
125
        
 
126
        //@@@ is this right to get us to the near clipping plane?
 
127
        ray_origin[0]+=near_clip_factor*dist*ray_direction[0];
 
128
        ray_origin[1]+=near_clip_factor*dist*ray_direction[1];
 
129
        ray_origin[2]+=near_clip_factor*dist*ray_direction[2];
 
130
        
 
131
        // normalize direction vector
 
132
        float mag=sqrt(ray_direction[0]*ray_direction[0]
 
133
                       + ray_direction[1]*ray_direction[1]
 
134
                       + ray_direction[2]*ray_direction[2]);
 
135
        ray_direction[0]/=mag;
 
136
        ray_direction[1]/=mag;
 
137
        ray_direction[2]/=mag;
 
138
    }
 
139
    
 
140
    void Target3D::
 
141
    get_viewing_direction(float direction[3])
 
142
    {
 
143
        float ch=cos(heading), sh=sin(heading);
 
144
        float cp=cos(pitch), sp=sin(pitch);
 
145
        direction[0]=-sh*cp;
 
146
        direction[1]=sp;
 
147
        direction[2]=-ch*cp;
 
148
    }
 
149
    
 
150
    void Target3D::get_up_vector(float up[3])
 
151
    {
 
152
        // Rotate the y-coordinate vector about the x-axis by pitch, then the y-axis by heading
 
153
        // up = R_y(h) * R_x(p) * <0,1,0>
 
154
        
 
155
        float ch=cos(heading), sh=sin(heading);
 
156
        float cp=cos(pitch), sp=sin(pitch);
 
157
        up[0] = sh*sp;
 
158
        up[1] = cp;
 
159
        up[2] = ch*sp;   
 
160
    }
 
161
    
 
162
    void Target3D::
 
163
    gl_transform(void)
 
164
    {
 
165
        glViewport(0, 0, (GLsizei)winwidth, (GLsizei)winheight);
 
166
        
 
167
        glMatrixMode(GL_PROJECTION);
 
168
        glLoadIdentity();
 
169
        //gluPerspective(fovy, winwidth/(float)winheight, near_clip_factor*dist, far_clip_factor*dist);
 
170
        
 
171
        gluPerspective(fovy, winwidth/(float)winheight, near_clip_factor, far_clip_factor);
 
172
        
 
173
        glMatrixMode(GL_MODELVIEW);
 
174
        glLoadIdentity();
 
175
        //   GLfloat pos[3];
 
176
        //   pos[0]=target[0]-dist*sin(heading)*cos(pitch);
 
177
        //   pos[1]=target[1]-dist*sin(pitch);
 
178
        //   pos[2]=target[2]-dist*cos(heading)*cos(pitch);
 
179
        glTranslatef(0, 0, -dist); // translate target dist away in the z direction
 
180
        glRotatef(-180.0f/(float)M_PI*pitch, 1.0f, 0.0f, 0.0f); // rotate pitch in the yz plane
 
181
        glRotatef(-180.0f/(float)M_PI*heading, 0.0f, 1.0f, 0.0f); // rotate heading in the xz plane
 
182
        glTranslatef(-target[0], -target[1], -target[2]); // translate target to origin
 
183
    }
 
184
    
 
185
    void Target3D::
 
186
    export_rib(ostream &output)
 
187
    {
 
188
        output<<"Clipping "<<near_clip_factor*dist<<" "<<far_clip_factor*dist<<endl; // could be more generous here!
 
189
        output<<"Projection \"perspective\" \"fov\" "<<fovy<<endl;
 
190
        output<<"ReverseOrientation"<<endl;  // RenderMan has a different handedness from OpenGL's default
 
191
        output<<"Scale 1 1 -1"<<endl;        // so we need to correct for that here
 
192
        output<<"Translate 0 0 "<<-dist<<endl;
 
193
        output<<"Rotate "<<-180/M_PI*pitch<<" 1 0 0"<<endl;
 
194
        output<<"Rotate "<<-180/M_PI*heading<<" 0 1 0"<<endl;
 
195
        output<<"Translate "<<-target[0]<<" "<<-target[1]<<" "<<-target[2]<<endl;
 
196
    }
 
197
    
 
198
    //=================================================================================
 
199
    
 
200
    TargetOrtho3D::
 
201
    TargetOrtho3D(float target_[3], float dist_, float heading_, float pitch_, float height_factor_, float near_clip_factor_, float far_clip_factor_)
 
202
    : dist(dist_), heading(heading_), pitch(pitch_),
 
203
    default_dist(dist_), default_heading(heading_), default_pitch(pitch_),
 
204
    height_factor(height_factor_),
 
205
    near_clip_factor(near_clip_factor_), far_clip_factor(far_clip_factor_), action_mode(INACTIVE),   
 
206
    oldmousex(0), oldmousey(0)
 
207
    {
 
208
        if(target_){
 
209
            target[0]=target_[0];
 
210
            target[1]=target_[1];
 
211
            target[2]=target_[2];
 
212
        }else{
 
213
            target[0]=0;
 
214
            target[1]=0;
 
215
            target[2]=0;
 
216
        }
 
217
        default_target[0]=target[0];
 
218
        default_target[1]=target[1];
 
219
        default_target[2]=target[2];
 
220
        default_dist=dist;
 
221
        default_heading=heading;
 
222
        default_pitch=pitch;
 
223
    }
 
224
    
 
225
    void TargetOrtho3D::
 
226
    click(int button, int state, int x, int y)
 
227
    {
 
228
        if(state==GLUT_UP)
 
229
            action_mode=INACTIVE;
 
230
        else if(button==GLUT_LEFT_BUTTON)
 
231
            action_mode=ROTATE;
 
232
        else if(button==GLUT_MIDDLE_BUTTON)
 
233
            action_mode=TRUCK;
 
234
        else if(button==GLUT_RIGHT_BUTTON)
 
235
            action_mode=DOLLY;
 
236
        oldmousex=x;
 
237
        oldmousey=y;
 
238
    }
 
239
    
 
240
    void TargetOrtho3D::
 
241
    drag(int x, int y)
 
242
    {
 
243
        switch(action_mode){
 
244
            case INACTIVE:
 
245
                return; // nothing to do
 
246
            case ROTATE:
 
247
                heading+=0.007f*(oldmousex-x);
 
248
                if(heading<-M_PI) heading+=2.0f*(float)M_PI;
 
249
                else if(heading>M_PI) heading-=2.0f*(float)M_PI;
 
250
                pitch+=0.007f*(oldmousey-y);
 
251
                if(pitch<-0.5f*(float)M_PI) pitch=-0.5f*(float)M_PI;
 
252
                else if(pitch>0.5f*(float)M_PI) pitch=0.5f*(float)M_PI;
 
253
                break;
 
254
            case TRUCK:
 
255
                target[0]+=(0.002f*dist)*cos(heading)*(oldmousex-x);
 
256
                target[1]-=(0.002f*dist)*(oldmousey-y);
 
257
                target[2]-=(0.002f*dist)*sin(heading)*(oldmousex-x);
 
258
                break;
 
259
            case DOLLY:
 
260
                dist*=pow(1.01f, oldmousey-y + x-oldmousex);
 
261
                break;
 
262
        }
 
263
        oldmousex=x;
 
264
        oldmousey=y;
 
265
        glutPostRedisplay();
 
266
    }
 
267
    
 
268
    void TargetOrtho3D::
 
269
    return_to_default(void)
 
270
    {
 
271
        target[0]=default_target[0];
 
272
        target[1]=default_target[1];
 
273
        target[2]=default_target[2];
 
274
        dist=default_dist;
 
275
        heading=default_heading;
 
276
        pitch=default_pitch;
 
277
    }
 
278
    
 
279
    void TargetOrtho3D::
 
280
    transform_mouse(int, int, float* /*ray_origin[3]*/, float* /*ray_direction[3]*/ )
 
281
    {
 
282
        // @@@ unimplemented
 
283
    }
 
284
    
 
285
    void TargetOrtho3D::
 
286
    get_viewing_direction(float direction[3])
 
287
    {
 
288
        float ch=cos(heading), sh=sin(heading);
 
289
        float cp=cos(pitch), sp=sin(pitch);
 
290
        direction[0]=-sh*cp;
 
291
        direction[1]=sp;
 
292
        direction[2]=-ch*cp;
 
293
    }
 
294
    
 
295
    void TargetOrtho3D::
 
296
    gl_transform(void)
 
297
    {
 
298
        glViewport(0, 0, (GLsizei)winwidth, (GLsizei)winheight);
 
299
        
 
300
        glMatrixMode(GL_PROJECTION);
 
301
        glLoadIdentity();
 
302
        float halfheight=0.5f*height_factor*dist, halfwidth=halfheight*winwidth/(float)winheight;
 
303
        glOrtho(-halfwidth, halfwidth, -halfheight, halfheight, near_clip_factor*dist, far_clip_factor*dist);
 
304
        
 
305
        glMatrixMode(GL_MODELVIEW);
 
306
        glLoadIdentity();
 
307
        glTranslatef(0, 0, -dist); // translate target dist away in the z direction
 
308
        glRotatef(-180.0f/(float)M_PI*pitch, 1.0f, 0.0f, 0.0f); // rotate pitch in the yz plane
 
309
        glRotatef(-180.0f/(float)M_PI*heading, 0.0f, 1.0f, 0.0f); // rotate heading in the xz plane
 
310
        glTranslatef(-target[0], -target[1], -target[2]); // translate target to origin
 
311
    }
 
312
    
 
313
    void TargetOrtho3D::
 
314
    export_rib(ostream &output)
 
315
    {
 
316
        output<<"Clipping "<<near_clip_factor*dist<<" "<<far_clip_factor*dist<<endl; // could be more generous here!
 
317
        output<<"Projection \"orthographic\""<<endl;
 
318
        //@@@ incomplete: need a scaling according to height_factor*dist somewhere in here
 
319
        output<<"ReverseOrientation"<<endl;  // RenderMan has a different handedness from OpenGL's default
 
320
        output<<"Scale 1 1 -1"<<endl;        // so we need to correct for that here
 
321
        output<<"Translate 0 0 "<<-dist<<endl;
 
322
        output<<"Rotate "<<-180/M_PI*pitch<<" 1 0 0"<<endl;
 
323
        output<<"Rotate "<<-180/M_PI*heading<<" 0 1 0"<<endl;
 
324
        output<<"Translate "<<-target[0]<<" "<<-target[1]<<" "<<-target[2]<<endl;
 
325
    }
 
326
    
 
327
    //=================================================================================
 
328
    
 
329
    PanZoom2D::
 
330
    PanZoom2D(float bottom_, float left_, float height_)
 
331
    : bottom(bottom_), left(left_), height(height_), 
 
332
    default_bottom(bottom_), default_left(left_), default_height(height_), action_mode(INACTIVE),
 
333
    oldmousex(0), oldmousey(0), moved_since_mouse_down(false),
 
334
    clickx(~0), clicky(~0)
 
335
    {}
 
336
    
 
337
    void PanZoom2D::
 
338
    click(int button, int state, int x, int y)
 
339
    {
 
340
        if(state==GLUT_UP){
 
341
            float r=height/winheight;
 
342
            switch(action_mode){
 
343
                case PAN:
 
344
                    if(!moved_since_mouse_down){
 
345
                        // make mouse click the centre of the window
 
346
                        left+=r*(x-0.5f*winwidth);
 
347
                        bottom+=r*(0.5f*winheight-y);
 
348
                        glutPostRedisplay();
 
349
                    }
 
350
                    break;
 
351
                case ZOOM_IN:
 
352
                    if(moved_since_mouse_down){
 
353
                        // zoom in to selection
 
354
                        float desired_width=fabs((x-clickx)*height/winheight);
 
355
                        float desired_height=fabs((y-clicky)*height/winheight);
 
356
                        if(desired_height==0) desired_height=height/winheight;
 
357
                        if(desired_width*winheight > desired_height*winwidth)
 
358
                            desired_height=winheight*desired_width/winwidth;
 
359
                        else
 
360
                            desired_width=winwidth*desired_height/winheight;
 
361
                        left+=0.5f*(x+clickx)*height/winheight-0.5f*desired_width;
 
362
                        bottom+=(winheight-0.5f*(y+clicky))*height/winheight-0.5f*desired_height;
 
363
                        height=desired_height;
 
364
                        
 
365
                    }else{
 
366
                        // zoom in by some constant factor on the mouse click
 
367
                        float factor=0.70710678118654752440084f;
 
368
                        left+=(1-factor)*height*(x/(float)winheight);
 
369
                        bottom+=(1-factor)*height*(1-y/(float)winheight);
 
370
                        height*=factor;
 
371
                    }
 
372
                    glutPostRedisplay();
 
373
                    break;
 
374
                case ZOOM_OUT:
 
375
                    // zoom out by some constant factor
 
376
                {
 
377
                    float factor=1.41421356237309504880168f;
 
378
                    left-=0.5f*(factor-1)*height;
 
379
                    bottom-=0.5f*(factor-1)*winwidth*height/winheight;
 
380
                    height*=factor;
 
381
                }
 
382
                    glutPostRedisplay();
 
383
                    break;
 
384
                default:
 
385
                    ;// nothing to do
 
386
            }
 
387
            action_mode=INACTIVE;
 
388
            
 
389
        }else if(button==GLUT_LEFT_BUTTON)
 
390
        {
 
391
            action_mode=PAN;
 
392
        }
 
393
        else if(button==GLUT_MIDDLE_BUTTON){
 
394
            clickx=x;
 
395
            clicky=y;
 
396
            action_mode=ZOOM_IN;
 
397
        }else if(button==GLUT_RIGHT_BUTTON)
 
398
            action_mode=ZOOM_OUT;
 
399
        moved_since_mouse_down=false;
 
400
        oldmousex=x;
 
401
        oldmousey=y;
 
402
    }
 
403
    
 
404
    void PanZoom2D::
 
405
    drag(int x, int y)
 
406
    {
 
407
        if(x!=oldmousex || y!=oldmousey){
 
408
            moved_since_mouse_down=true;
 
409
            if(action_mode==PAN){
 
410
                float r=height/winheight;
 
411
                left-=r*(x-oldmousex);
 
412
                bottom+=r*(y-oldmousey);
 
413
                glutPostRedisplay();
 
414
            }else if(action_mode==ZOOM_IN)
 
415
                glutPostRedisplay();
 
416
            
 
417
            glutPostRedisplay();
 
418
            oldmousex=x;
 
419
            oldmousey=y;
 
420
        }
 
421
    }
 
422
    
 
423
    void PanZoom2D::
 
424
    return_to_default(void)
 
425
    {
 
426
        bottom=default_bottom;
 
427
        left=default_left;
 
428
        height=default_height;
 
429
    }
 
430
    
 
431
    void PanZoom2D::
 
432
    transform_mouse(int x, int y, float coords[2])
 
433
    {
 
434
        float r=height/winheight;
 
435
        coords[0]=x*r+left;
 
436
        coords[1]=(winheight-y)*r+bottom;
 
437
    }
 
438
    
 
439
    void PanZoom2D::
 
440
    gl_transform(void)
 
441
    {
 
442
        glViewport(0, 0, (GLsizei)winwidth, (GLsizei)winheight);
 
443
        glMatrixMode(GL_PROJECTION);
 
444
        glLoadIdentity();
 
445
        glOrtho(left, left+(height*winwidth)/winheight, bottom, bottom+height, 0, 1);
 
446
        glMatrixMode(GL_MODELVIEW);
 
447
        glLoadIdentity();
 
448
    }
 
449
    
 
450
    void PanZoom2D::
 
451
    export_rib(ostream &output)
 
452
    {
 
453
        // no projection matrix
 
454
        output<<"Clipping 1 2000"<<endl; // somewhat arbitrary - hopefully this is plenty of space
 
455
        output<<"ReverseOrientation"<<endl;  // RenderMan has a different handedness from OpenGL's default
 
456
        output<<"Scale 1 1 -1"<<endl;        // so we need to correct for that here
 
457
        // scale so that smaller dimension gets scaled to size 2
 
458
        float scalefactor;
 
459
        if(winwidth>winheight) scalefactor=2.0f/height;
 
460
        else scalefactor=2.0f/(winwidth*height/winheight);
 
461
        output<<"Scale "<<scalefactor<<" "<<scalefactor<<" 1"<<endl;
 
462
        // translate so centre of view gets mapped to (0,0,1000)
 
463
        output<<"Translate "<<-(left+0.5*winwidth*height/winheight)<<" "<<-(bottom+0.5*height)<< " 1000"<<endl;
 
464
    }
 
465
    
 
466
    void PanZoom2D::
 
467
    display_screen(void)
 
468
    {
 
469
        if(action_mode==ZOOM_IN && moved_since_mouse_down){
 
470
            glColor3f(1,1,1);
 
471
            glBegin(GL_LINE_STRIP);
 
472
            glVertex2i(clickx, winheight-clicky);
 
473
            glVertex2i(oldmousex, winheight-clicky);
 
474
            glVertex2i(oldmousex, winheight-oldmousey);
 
475
            glVertex2i(clickx, winheight-oldmousey);
 
476
            glVertex2i(clickx, winheight-clicky);
 
477
            glEnd();
 
478
        }
 
479
    }
 
480
    
 
481
    //=================================================================================
 
482
    
 
483
    StaticText::
 
484
    StaticText(const char *text_)
 
485
    : text(text_)
 
486
    {}
 
487
    
 
488
    void StaticText::
 
489
    display(int x, int y)
 
490
    {
 
491
        dispx=x;
 
492
        dispy=y;
 
493
        width=glutBitmapLength(GLUT_BITMAP_HELVETICA_12, (const unsigned char*)text)+1;
 
494
        height=15;
 
495
        glColor3f(0.3f, 0.3f, 0.3f);
 
496
        glRasterPos2i(x, y-height+2);
 
497
        for(int i=0; text[i]!=0; ++i)
 
498
            glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, text[i]);
 
499
        glColor3f(1, 1, 1);
 
500
        glRasterPos2i(x+1, y-height+3);
 
501
        for(int i=0; text[i]!=0; ++i)
 
502
            glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, text[i]);
 
503
    }
 
504
    
 
505
    //=================================================================================
 
506
    
 
507
    DynamicText::DynamicText( const std::string& text_ )
 
508
    : 
 
509
    text(text_)
 
510
    {
 
511
        color[0] = 0.0f;
 
512
        color[1] = 0.0f;
 
513
        color[2] = 0.0f;
 
514
    }
 
515
    
 
516
    void DynamicText::set_color( float r, float g, float b )
 
517
    {
 
518
        color[0] = r;
 
519
        color[1] = g;
 
520
        color[2] = b;
 
521
    }
 
522
    
 
523
    void DynamicText::display( int x, int y )
 
524
    {
 
525
        dispx=x;
 
526
        dispy=y;
 
527
        width=glutBitmapLength(GLUT_BITMAP_HELVETICA_12, (const unsigned char*)text.c_str())+1;
 
528
        height=15;
 
529
        
 
530
        //   glColor3f(0.3f, 0.3f, 0.3f);
 
531
        //   glRasterPos2i(x, y-height+2);
 
532
        //   for(int i=0; text[i]!=0; ++i)
 
533
        //      glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, text[i]);
 
534
        
 
535
        glColor3f( color[0], color[1], color[2] );
 
536
        
 
537
        glRasterPos2i(x+1, y-height+3);
 
538
        for(int i=0; text[i]!=0; ++i)
 
539
            glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, text[i]);   
 
540
    }
 
541
    
 
542
    
 
543
    //=================================================================================
 
544
    
 
545
    Button::
 
546
    Button(const char *text_, int minwidth_)
 
547
    : status(UNINVOLVED), text(text_), minwidth(minwidth_)
 
548
    {}
 
549
    
 
550
    void Button::
 
551
    display(int x, int y)
 
552
    {
 
553
        dispx=x;
 
554
        dispy=y;
 
555
        int textwidth=glutBitmapLength(GLUT_BITMAP_HELVETICA_12, (const unsigned char*)text);
 
556
        if(textwidth<minwidth) width=minwidth+24;
 
557
        else width=textwidth+24;
 
558
        height=17;
 
559
        if(status==UNINVOLVED){
 
560
            glColor3f(0.7f, 0.7f, 0.7f);
 
561
            glBegin(GL_QUADS);
 
562
            glVertex2i(x+1, y-1);
 
563
            glVertex2i(x+width, y-1);
 
564
            glVertex2i(x+width, y-height+1);
 
565
            glVertex2i(x+1, y-height+1);
 
566
            glEnd();
 
567
            glColor3f(0.3f, 0.3f, 0.3f);
 
568
            glLineWidth(1);
 
569
            glBegin(GL_LINE_STRIP);
 
570
            glVertex2i(x, y-2);
 
571
            glVertex2i(x, y-height);
 
572
            glVertex2i(x+width-1, y-height);
 
573
            glEnd();
 
574
            glColor3f(0.3f, 0.3f, 0.3f);
 
575
        }else{
 
576
            if(status==SELECTED) glColor3f(0.8f, 0.8f, 0.8f);
 
577
            else                 glColor3f(1, 1, 1);
 
578
            glBegin(GL_QUADS);
 
579
            glVertex2i(x, y-1);
 
580
            glVertex2i(x+width, y-1);
 
581
            glVertex2i(x+width, y-height);
 
582
            glVertex2i(x, y-height);
 
583
            glEnd();
 
584
            glColor3f(0, 0, 0);
 
585
        }
 
586
        glRasterPos2i(x+(width-textwidth)/2, y-height+5);
 
587
        for(int i=0; text[i]!=0; ++i)
 
588
            glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, text[i]);
 
589
    }
 
590
    
 
591
    bool Button::
 
592
    click(int state, int x, int y)
 
593
    {
 
594
        if(state==GLUT_DOWN && x>dispx && x<=dispx+width && y<dispy-2 && y>=dispy-height){
 
595
            status=HIGHLIGHTED;
 
596
            glutPostRedisplay();
 
597
            return true;
 
598
        }else if(state==GLUT_UP && status!=UNINVOLVED){
 
599
            status=UNINVOLVED;
 
600
            glutPostRedisplay();
 
601
            if(x>=dispx && x<dispx+width && y<dispy-2 && y>=dispy-height)
 
602
                action();
 
603
            return true;
 
604
        }else
 
605
            return false;
 
606
    }
 
607
    
 
608
    void Button::
 
609
    drag(int x, int y)
 
610
    {
 
611
        // needs to control highlighting (SELECTED vs. HIGHLIGHTED)
 
612
        if(status==SELECTED && x>=dispx && x<dispx+width && y<dispy-2 && y>=dispy-height){
 
613
            status=HIGHLIGHTED;
 
614
            glutPostRedisplay();
 
615
        }else if(status==HIGHLIGHTED && !(x>=dispx && x<dispx+width && y<dispy-2 && y>=dispy-height)){
 
616
            status=SELECTED;
 
617
            glutPostRedisplay();
 
618
        }
 
619
    }
 
620
    
 
621
    //=================================================================================
 
622
    
 
623
    Slider::
 
624
    Slider(const char *text_, int length_, int position_, int justify_)
 
625
    : status(UNINVOLVED), text(text_), length(length_), justify(justify_), position(position_),
 
626
    scrollxmin(~0), scrollxmax(~0), scrollymin(~0), scrollymax(~0), clickx(~0) 
 
627
    {}
 
628
    
 
629
    void Slider::
 
630
    display(int x, int y)
 
631
    {
 
632
        dispx=x;
 
633
        dispy=y;
 
634
        width=glutBitmapLength(GLUT_BITMAP_HELVETICA_12, (const unsigned char*)text);
 
635
        if(width<justify) width=justify;
 
636
        width+=11+6+length+1;
 
637
        height=15;
 
638
        glColor3f(0.3f, 0.3f, 0.3f);
 
639
        glRasterPos2i(x, y-height+2);
 
640
        for(int i=0; text[i]!=0; ++i)
 
641
            glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, text[i]);
 
642
        glColor3f(1, 1, 1);
 
643
        glRasterPos2i(x+1, y-height+3);
 
644
        for(int i=0; text[i]!=0; ++i)
 
645
            glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, text[i]);
 
646
        scrollxmin=x+width-length-12;
 
647
        scrollxmax=x+width;
 
648
        scrollymin=y-height+1;
 
649
        scrollymax=y-2;
 
650
        glColor3f(0.3f, 0.3f, 0.3f);
 
651
        glLineWidth(1);
 
652
        glBegin(GL_LINE_STRIP);
 
653
        glVertex2i(scrollxmin, scrollymax-1);
 
654
        glVertex2i(scrollxmin, scrollymin);
 
655
        glVertex2i(scrollxmax-1, scrollymin);
 
656
        glVertex2i(scrollxmax-1, scrollymax-1);
 
657
        glEnd();
 
658
        glColor3f(0.7f, 0.7f, 0.7f);
 
659
        glBegin(GL_LINE_STRIP);
 
660
        glVertex2i(scrollxmin+1, scrollymax);
 
661
        glVertex2i(scrollxmin+1, scrollymin+1);
 
662
        glVertex2i(scrollxmax, scrollymin+1);
 
663
        glVertex2i(scrollxmax, scrollymax);
 
664
        glEnd();
 
665
        if(status==UNINVOLVED){
 
666
            glColor3f(0.3f, 0.3f, 0.3f);
 
667
            glBegin(GL_LINE_STRIP);
 
668
            glVertex2i(scrollxmin+position+2, scrollymax-2);
 
669
            glVertex2i(scrollxmin+position+2, scrollymin+2);
 
670
            glVertex2i(scrollxmin+position+10, scrollymin+2);
 
671
            glEnd();
 
672
            glColor3f(0.7f, 0.7f, 0.7f);
 
673
            glBegin(GL_QUADS);
 
674
            glVertex2i(scrollxmin+position+3, scrollymin+3);
 
675
            glVertex2i(scrollxmin+position+11, scrollymin+3);
 
676
            glVertex2i(scrollxmin+position+11, scrollymax);
 
677
            glVertex2i(scrollxmin+position+3, scrollymax);
 
678
            glEnd();
 
679
        }else{ // SELECTED
 
680
            glColor3f(1, 1, 1);
 
681
            glBegin(GL_QUADS);
 
682
            glVertex2i(scrollxmin+position+2, scrollymin+2);
 
683
            glVertex2i(scrollxmin+position+11, scrollymin+2);
 
684
            glVertex2i(scrollxmin+position+11, scrollymax);
 
685
            glVertex2i(scrollxmin+position+2, scrollymax);
 
686
            glEnd();
 
687
        }
 
688
    }
 
689
    
 
690
    bool Slider::
 
691
    click(int state, int x, int y)
 
692
    {
 
693
        if(state==GLUT_DOWN && x>scrollxmin+position+2 && x<=scrollxmin+position+11 && y<scrollymax-1 && y>=scrollymin+2){
 
694
            status=SELECTED;
 
695
            clickx=x;
 
696
            glutPostRedisplay();
 
697
            return true;
 
698
        }else if(status!=UNINVOLVED && state==GLUT_UP){
 
699
            status=UNINVOLVED;
 
700
            glutPostRedisplay();
 
701
            return true;
 
702
        }else
 
703
            return false;
 
704
    }
 
705
    
 
706
    void Slider::
 
707
    drag(int x, int /*y*/ )
 
708
    {
 
709
        if(status==SELECTED){
 
710
            glutPostRedisplay();
 
711
            int newposition=position+(x-clickx);
 
712
            clickx=x;
 
713
            if(newposition<0){
 
714
                clickx+=(0-newposition);
 
715
                newposition=0;
 
716
            }else if(newposition>length){
 
717
                clickx+=(length-newposition);
 
718
                newposition=length;
 
719
            }
 
720
            if(newposition!=position){
 
721
                position=newposition;
 
722
                action();
 
723
                glutPostRedisplay();
 
724
            }
 
725
        }
 
726
    }
 
727
    
 
728
    //=================================================================================
 
729
    
 
730
    WidgetList::
 
731
    WidgetList(int indent_, bool hidden_)
 
732
    : indent(indent_), hidden(hidden_), list(), downclicked_member(-1)
 
733
    {
 
734
    }
 
735
    
 
736
    void WidgetList::
 
737
    display(int x, int y)
 
738
    {
 
739
        dispx=x;
 
740
        dispy=y;
 
741
        if(hidden){
 
742
            width=height=0;
 
743
        }else{
 
744
            height=0;
 
745
            for(unsigned int i=0; i<list.size(); ++i){
 
746
                list[i]->display(x+indent, y-height);
 
747
                height+=list[i]->height;
 
748
                width=(width<indent+list[i]->width) ? indent+list[i]->width : width;
 
749
            }
 
750
        }
 
751
    }
 
752
    
 
753
    bool WidgetList::
 
754
    click(int state, int x, int y)
 
755
    {
 
756
        //if(hidden || x<dispx || x>=dispx+width || y>=dispy || y<dispy-height) return false; // early exit
 
757
        if(state==GLUT_DOWN){ // search for correct widget
 
758
            for(unsigned int i=0; i<list.size(); ++i){
 
759
                if(list[i]->click(state, x, y)){
 
760
                    downclicked_member=i;
 
761
                    return true;
 
762
                }
 
763
            }
 
764
        }else if(state==GLUT_UP && downclicked_member>=0){
 
765
            list[downclicked_member]->click(state, x, y);
 
766
            downclicked_member=-1;
 
767
        }
 
768
        return false;
 
769
    }
 
770
    
 
771
    void WidgetList::
 
772
    drag(int x, int y)
 
773
    {
 
774
        if(downclicked_member>=0)
 
775
            list[downclicked_member]->drag(x, y);
 
776
    }
 
777
    
 
778
    
 
779
    //=================================================================================
 
780
    
 
781
    typedef enum {NOBODY, CAMERA, WIDGETS, USER} MouseOwnerType;
 
782
    
 
783
    MouseOwnerType mouse_owner = NOBODY;
 
784
    
 
785
    //
 
786
    // Local ("static") functions
 
787
    //
 
788
    
 
789
    namespace {
 
790
        
 
791
        //=================================================================================
 
792
        
 
793
        void gluviReshape(int w, int h)
 
794
        {
 
795
            winwidth=w;
 
796
            winheight=h;
 
797
            glutPostRedisplay(); // triggers the camera to adjust itself to the new dimensions
 
798
        }
 
799
        
 
800
        //=================================================================================
 
801
        
 
802
        void gluviDisplay()
 
803
        {
 
804
            
 
805
            glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
 
806
            
 
807
            // draw the scene
 
808
            if(camera) camera->gl_transform();
 
809
            if(userDisplayFunc) userDisplayFunc();
 
810
            
 
811
            // now draw widgets on top
 
812
            glPushAttrib(GL_CURRENT_BIT|GL_ENABLE_BIT|GL_LINE_BIT);
 
813
            glDisable(GL_DEPTH_TEST);
 
814
            glDisable(GL_LIGHTING);
 
815
            glLineWidth(1);
 
816
            // and probably more needs setting before widgets
 
817
            
 
818
            glMatrixMode(GL_MODELVIEW);
 
819
            glLoadIdentity();
 
820
            glMatrixMode(GL_PROJECTION);
 
821
            glLoadIdentity();
 
822
            gluOrtho2D(0, winwidth, 0, winheight);
 
823
            
 
824
            root.display(0, winheight);
 
825
            
 
826
            // and allow the camera to draw something on screen (e.g. for zooming extent)
 
827
            if(camera) camera->display_screen();
 
828
            
 
829
            glPopAttrib();
 
830
            
 
831
            glutSwapBuffers();
 
832
        }
 
833
        
 
834
        void gluviMouse(int button, int state, int x, int y)
 
835
        {
 
836
            if(state==GLUT_DOWN){
 
837
                int mods=glutGetModifiers();
 
838
                if(camera && mods==GLUT_ACTIVE_SHIFT){
 
839
                    camera->click(button, state, x, y);
 
840
                    mouse_owner=CAMERA;
 
841
                    //}else if(button==GLUT_LEFT_BUTTON && root.click(state, x, winheight-y)){
 
842
                    //   mouse_owner=WIDGETS;
 
843
                }else if(userMouseFunc){
 
844
                    userMouseFunc(button, state, x, y);
 
845
                    mouse_owner=USER;
 
846
                }
 
847
            }else{ // mouse up - send event to whoever got the mouse down
 
848
                switch(mouse_owner){
 
849
                    case CAMERA:
 
850
                        camera->click(button, state, x, y);
 
851
                        break;
 
852
                    case WIDGETS:
 
853
                        //root.click(state, x, winheight-y);
 
854
                        break;
 
855
                    case USER:
 
856
                        if(userMouseFunc) userMouseFunc(button, state, x, y);
 
857
                        break;
 
858
                    default:
 
859
                        ;// nothing to do
 
860
                }
 
861
                mouse_owner=NOBODY;
 
862
            }
 
863
        }
 
864
        
 
865
        //=================================================================================
 
866
        
 
867
        void gluviDrag(int x, int y)
 
868
        {
 
869
            switch(mouse_owner){
 
870
                case CAMERA:
 
871
                    camera->drag(x, y);
 
872
                    break;
 
873
                case WIDGETS:
 
874
                    //root.drag(x, winheight-y);
 
875
                    break;
 
876
                case USER:
 
877
                    if(userDragFunc) userDragFunc(x, y);
 
878
                    break;
 
879
                default:
 
880
                    ;// nothing to do
 
881
            }
 
882
        }
 
883
        
 
884
        
 
885
    }  // namespace
 
886
    
 
887
    
 
888
    //=================================================================================
 
889
    
 
890
    void ppm_screenshot(const char *filename_format, ...)
 
891
    {
 
892
        va_list ap;
 
893
        va_start(ap, filename_format);
 
894
#ifdef _MSC_VER
 
895
#define FILENAMELENGTH 256
 
896
        char filename[FILENAMELENGTH];
 
897
        _vsnprintf(filename, FILENAMELENGTH, filename_format, ap);
 
898
        ofstream out(filename, ofstream::binary);
 
899
#else
 
900
        char *filename;
 
901
        vasprintf(&filename, filename_format, ap);
 
902
        ofstream out(filename, ofstream::binary);
 
903
        free(filename);
 
904
#endif
 
905
        if(!out) return;
 
906
        GLubyte *image_buffer=new GLubyte[3*winwidth*winheight];
 
907
        glReadBuffer(GL_FRONT);
 
908
        glReadPixels(0, 0, winwidth, winheight, GL_RGB, GL_UNSIGNED_BYTE, image_buffer);
 
909
        out<<"P6\n"<<winwidth<<' '<<winheight<<" 255\n";
 
910
        for(int i=1; i<=winheight; ++i)
 
911
            out.write((const char*)image_buffer+3*winwidth*(winheight-i), 3*winwidth);
 
912
        delete[] image_buffer;
 
913
    }
 
914
    
 
915
    namespace { 
 
916
        
 
917
        void write_big_endian_ushort(std::ostream &output, unsigned short v)
 
918
        {
 
919
            output.put( static_cast<char>((v>>8)%256) );
 
920
            output.put( static_cast<char>(v%256) );
 
921
        }
 
922
        
 
923
        void write_big_endian_uint(std::ostream &output, unsigned int v)
 
924
        {
 
925
            output.put(static_cast<char>((v>>24)%256));
 
926
            output.put(static_cast<char>((v>>16)%256));
 
927
            output.put(static_cast<char>((v>>8)%256));
 
928
            output.put(static_cast<char>(v%256));
 
929
        }
 
930
        
 
931
    }  // unnamed namespace
 
932
    
 
933
    void sgi_screenshot(const char *filename_format, ...)
 
934
    {
 
935
        va_list ap;
 
936
        va_start(ap, filename_format);
 
937
#ifdef _MSC_VER
 
938
#define FILENAMELENGTH 256
 
939
        char filename[FILENAMELENGTH];
 
940
        _vsnprintf(filename, FILENAMELENGTH, filename_format, ap);
 
941
        ofstream output(filename, ofstream::binary);
 
942
#else
 
943
        char *filename;
 
944
        vasprintf(&filename, filename_format, ap);
 
945
        ofstream output(filename, ofstream::binary);
 
946
#endif
 
947
        if(!output) return;
 
948
        
 
949
        const int mipmap_level = 1;
 
950
        const int size_scale = 1 << (mipmap_level);
 
951
        
 
952
        winwidth = size_scale * winwidth;
 
953
        winheight = size_scale * winheight;
 
954
        
 
955
        glGenFramebuffers(1, &screenshot_fbo);
 
956
        glBindFramebuffer(GL_FRAMEBUFFER, screenshot_fbo);
 
957
        
 
958
        GLuint textureId;
 
959
        glGenTextures(1, &textureId);
 
960
        glBindTexture(GL_TEXTURE_2D, textureId);
 
961
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
962
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
 
963
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 
964
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
965
        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap
 
966
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmap_level);
 
967
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, winwidth, winheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
 
968
        
 
969
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureId, 0);
 
970
        
 
971
        //
 
972
        // Depth/stencil buffer
 
973
        //
 
974
        
 
975
        GLuint depthRenderbuffer;
 
976
        glGenRenderbuffers(1, &depthRenderbuffer);
 
977
        glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
 
978
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, winwidth, winheight);
 
979
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
 
980
        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 
981
        
 
982
        if (status != GL_FRAMEBUFFER_COMPLETE) 
 
983
        {
 
984
            std::cout << "Problem with OpenGL framebuffer after specifying depth/stencil render buffer: " << hex << status << std::endl;
 
985
            assert(0);
 
986
        }
 
987
        
 
988
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
 
989
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);   
 
990
        glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE);
 
991
        
 
992
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
 
993
        
 
994
        // draw the scene
 
995
        
 
996
        taking_screenshot = true;
 
997
        
 
998
        if(camera) camera->gl_transform();
 
999
        if(userDisplayFunc) userDisplayFunc();
 
1000
        
 
1001
        taking_screenshot = false;
 
1002
        
 
1003
        glEnable(GL_TEXTURE_2D);
 
1004
        glGenerateMipmapEXT(GL_TEXTURE_2D);
 
1005
        
 
1006
        GLint file_width, file_height;
 
1007
        glGetTexLevelParameteriv( GL_TEXTURE_2D, mipmap_level, GL_TEXTURE_WIDTH, &file_width );
 
1008
        glGetTexLevelParameteriv( GL_TEXTURE_2D, mipmap_level, GL_TEXTURE_HEIGHT, &file_height );
 
1009
        
 
1010
        GLubyte *buffer = new GLubyte[ 4 * file_width * file_height ]; 
 
1011
        
 
1012
        glGetTexImage( GL_TEXTURE_2D, mipmap_level, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
 
1013
        
 
1014
        
 
1015
        GLubyte* r_buffer = new GLubyte[file_width*file_height];            
 
1016
        GLubyte* g_buffer = new GLubyte[file_width*file_height];            
 
1017
        GLubyte* b_buffer = new GLubyte[file_width*file_height];            
 
1018
        
 
1019
        for(int y = 0; y < file_height; y++)
 
1020
            for(int x = 0; x < file_width; x++)
 
1021
            {
 
1022
                int startAddressOfPixel = ((y*file_width) + x)*4;
 
1023
                
 
1024
                r_buffer[ ((y*file_width) + x) ] = buffer[startAddressOfPixel+0];
 
1025
                g_buffer[ ((y*file_width) + x) ] = buffer[startAddressOfPixel+1];
 
1026
                b_buffer[ ((y*file_width) + x) ] = buffer[startAddressOfPixel+2];
 
1027
            }
 
1028
        
 
1029
        
 
1030
        // first write the SGI header
 
1031
        
 
1032
        write_big_endian_ushort(output, 474); // magic number to identify this as an SGI image file
 
1033
        output.put(0); // uncompressed
 
1034
        output.put(1); // use 8-bit colour depth
 
1035
        write_big_endian_ushort(output, 3); // number of dimensions
 
1036
        assert( file_width < std::numeric_limits<unsigned short>::max() );
 
1037
        assert( file_height < std::numeric_limits<unsigned short>::max() );   
 
1038
        write_big_endian_ushort(output, static_cast<unsigned short>(file_width) ); // x size
 
1039
        write_big_endian_ushort(output, static_cast<unsigned short>(file_height) ); // y size
 
1040
        write_big_endian_ushort(output, 3); // three colour channels (z size)
 
1041
        write_big_endian_uint(output, 0); // minimum pixel value
 
1042
        write_big_endian_uint(output, 255); // maximum pixel value
 
1043
        write_big_endian_uint(output, 0); // dummy spacing
 
1044
        // image name
 
1045
        int i;
 
1046
        for(i=0; i<80 && filename[i]; ++i)
 
1047
            output.put(filename[i]);
 
1048
        for(; i<80; ++i)
 
1049
            output.put(0);
 
1050
        write_big_endian_uint(output, 0); // colormap is normal
 
1051
        for(i=0; i<404; ++i) output.put(0); // filler to complete header
 
1052
        
 
1053
        // now write the SGI image data
 
1054
        
 
1055
        output.write((const char*)r_buffer, file_width*file_height);
 
1056
        output.write((const char*)g_buffer, file_width*file_height);
 
1057
        output.write((const char*)b_buffer, file_width*file_height);
 
1058
        
 
1059
        delete[] r_buffer;
 
1060
        delete[] g_buffer;
 
1061
        delete[] b_buffer;
 
1062
        delete[] buffer;
 
1063
        
 
1064
        glBindFramebuffer( GL_FRAMEBUFFER, 0 );
 
1065
        glBindTexture(GL_TEXTURE_2D, 0);
 
1066
        
 
1067
        winwidth /= size_scale;
 
1068
        winheight /= size_scale;
 
1069
        if(camera) camera->gl_transform();
 
1070
        
 
1071
        glDeleteTextures( 1, &textureId );
 
1072
        glDeleteRenderbuffers( 1, &depthRenderbuffer );
 
1073
        glDeleteFramebuffers(1, &screenshot_fbo);
 
1074
        
 
1075
#ifndef _MSC_VER
 
1076
        free(filename);
 
1077
#endif
 
1078
    }
 
1079
    
 
1080
    void set_generic_lights(void)
 
1081
    {
 
1082
        glEnable(GL_LIGHTING);
 
1083
        {
 
1084
            GLfloat ambient[4] = {.3f, .3f, .3f, 1.0f};
 
1085
            glLightModelfv (GL_LIGHT_MODEL_AMBIENT,ambient);
 
1086
        }
 
1087
        {
 
1088
            GLfloat color[4] = {.4f, .4f, .4f, 1.0f};
 
1089
            glLightfv (GL_LIGHT0, GL_DIFFUSE, color);
 
1090
            glLightfv (GL_LIGHT0, GL_SPECULAR, color);
 
1091
            glEnable (GL_LIGHT0);
 
1092
        }
 
1093
        {
 
1094
            GLfloat color[4] = {.4f, .4f, .4f, 1.0f};
 
1095
            glLightfv (GL_LIGHT1, GL_DIFFUSE, color);
 
1096
            glLightfv (GL_LIGHT1, GL_SPECULAR, color);
 
1097
            glEnable (GL_LIGHT1);
 
1098
        }
 
1099
        {
 
1100
            GLfloat color[4] = {.2f, .2f, .2f, 1.0f};
 
1101
            glLightfv (GL_LIGHT2, GL_DIFFUSE, color);
 
1102
            glLightfv (GL_LIGHT2, GL_SPECULAR, color);
 
1103
            glEnable (GL_LIGHT2);
 
1104
        }
 
1105
    }
 
1106
    
 
1107
    void set_generic_material(float r, float g, float b, GLenum face)
 
1108
    {
 
1109
        GLfloat ambient[4], diffuse[4], specular[4];
 
1110
        ambient[0]=0.1f*r+0.03f; ambient[1]=0.1f*g+0.03f; ambient[2]=0.1f*b+0.03f; ambient[3]=1.0f;
 
1111
        diffuse[0]=0.7f*r;      diffuse[1]=0.7f*g;      diffuse[2]=0.7f*b;      diffuse[3]=1.0f;
 
1112
        specular[0]=0.1f*r+0.1f; specular[1]=0.1f*g+0.1f; specular[2]=0.1f*b+0.1f; specular[3]=1.0f;
 
1113
        glMaterialfv(face, GL_AMBIENT, ambient);
 
1114
        glMaterialfv(face, GL_DIFFUSE, diffuse);
 
1115
        glMaterialfv(face, GL_SPECULAR, specular);
 
1116
        glMaterialf(face, GL_SHININESS, 32);
 
1117
    }
 
1118
    
 
1119
    void set_matte_material(float r, float g, float b, GLenum face)
 
1120
    {
 
1121
        GLfloat ambient[4], diffuse[4], specular[4];
 
1122
        ambient[0]=0.1f*r+0.03f; ambient[1]=0.1f*g+0.03f; ambient[2]=0.1f*b+0.03f; ambient[3]=1.0f;
 
1123
        diffuse[0]=0.9f*r;      diffuse[1]=0.9f*g;      diffuse[2]=0.9f*b;      diffuse[3]=1.0f;
 
1124
        specular[0]=0;         specular[1]=0;         specular[2]=0;         specular[3]=1;
 
1125
        glMaterialfv(face, GL_AMBIENT, ambient);
 
1126
        glMaterialfv(face, GL_DIFFUSE, diffuse);
 
1127
        glMaterialfv(face, GL_SPECULAR, specular);
 
1128
    }
 
1129
    
 
1130
    /** 
 
1131
     * Draw a vector in 3D.  If arrow_head_length not specified, set it to 10% of vector length.
 
1132
     * Mar 29, 2006
 
1133
     */
 
1134
    void draw_3d_arrow(const float base[3], const float point[3], float arrow_head_length)
 
1135
    {
 
1136
        //glPushAttrib(GL_CURRENT_BIT|GL_ENABLE_BIT|GL_LINE_BIT);
 
1137
        //glDisable(GL_LIGHTING);
 
1138
        glLineWidth(1);
 
1139
        glColor3f(0.5f,0.5f,0.5f);
 
1140
        
 
1141
        Vec3f w(point[0]-base[0], point[1]-base[1], point[2]-base[2]);
 
1142
        float len = mag(w);
 
1143
        w = w / len;    // normalize to build coordinate system
 
1144
        
 
1145
        // create a coordinate system from the vector:
 
1146
        // get a vector perp to w and y-axis
 
1147
        Vec3f u = cross(w, Vec3f(0,1,0));
 
1148
        
 
1149
        // If vector is parallel to the y-axis, use the x-axis
 
1150
        if (mag(u) == 0)
 
1151
            u = cross(w, Vec3f(1,0,0));
 
1152
        
 
1153
        // get a vector perp to w and u
 
1154
        Vec3f v = cross(w, u/mag(u));
 
1155
        v = v/mag(v);
 
1156
        
 
1157
        if (!arrow_head_length)
 
1158
            arrow_head_length = 0.1f * len;
 
1159
        
 
1160
        // arrow head points
 
1161
        //@@@@@@@ POSSIBILITY: CREATE FOUR ARROW HEAD SEGMENTS INSTEAD OF TWO
 
1162
        Vec3f arrow1, arrow2;
 
1163
        arrow1[0] = point[0] + arrow_head_length * (v[0] - w[0]);
 
1164
        arrow1[1] = point[1] + arrow_head_length * (v[1] - w[1]);
 
1165
        arrow1[2] = point[2] + arrow_head_length * (v[2] - w[2]);
 
1166
        arrow2[0] = point[0] + arrow_head_length * (-v[0] - w[0]);
 
1167
        arrow2[1] = point[1] + arrow_head_length * (-v[1] - w[1]);
 
1168
        arrow2[2] = point[2] + arrow_head_length * (-v[2] - w[2]);
 
1169
        
 
1170
        glBegin(GL_LINES);
 
1171
        glVertex3f(base[0],   base[1],   base[2]);
 
1172
        glVertex3f(point[0],  point[1],  point[2]);
 
1173
        glVertex3f(point[0],  point[1],  point[2]);
 
1174
        glVertex3f(arrow1[0], arrow1[1], arrow1[2]);
 
1175
        glVertex3f(point[0],  point[1],  point[2]);
 
1176
        glVertex3f(arrow2[0], arrow2[1], arrow2[2]);
 
1177
        glEnd();
 
1178
        
 
1179
        //glPopAttrib();
 
1180
    }
 
1181
    
 
1182
    // draw_2d_arrow assumptions: 
 
1183
    // line width, point size, and color are set by the user prior to calling the routine
 
1184
    /*
 
1185
     void draw_2d_arrow(const Vec2f base, const Vec2f point, float arrow_head_length)
 
1186
     {
 
1187
     //glPushAttrib(GL_CURRENT_BIT|GL_ENABLE_BIT|GL_LINE_BIT);
 
1188
     //glDisable(GL_LIGHTING);
 
1189
     
 
1190
     Vec2f w = point-base;
 
1191
     float len = mag(w);
 
1192
     
 
1193
     if (len==0) {
 
1194
     glBegin(GL_POINTS);
 
1195
     glVertex2f(base[0], base[1]);
 
1196
     glEnd();
 
1197
     return;
 
1198
     }
 
1199
     
 
1200
     w = w / len;    // normalize to build coordinate system
 
1201
     
 
1202
     // u = w + 90 
 
1203
     // using rotation matrix  0  1
 
1204
     //                      -1  0
 
1205
     Vec2f u = Vec2f(1*w[1], -1*w[0]);
 
1206
     u = u/mag(u);
 
1207
     
 
1208
     // v = w - 90 (in fact v=-u)
 
1209
     Vec2f v = Vec2f(-1*w[1], 1*w[0]);
 
1210
     v = v/mag(v);
 
1211
     
 
1212
     if (!arrow_head_length) {
 
1213
     arrow_head_length = 0.1f * len;
 
1214
     }
 
1215
     
 
1216
     // arrow head points
 
1217
     Vec2f arrow1, arrow2;
 
1218
     arrow1 = point + arrow_head_length * (v-w);
 
1219
     arrow2 = point + arrow_head_length * (u-w);
 
1220
     
 
1221
     glBegin(GL_LINES);
 
1222
     glVertex2f(base[0], base[1]);
 
1223
     glVertex2f(point[0], point[1]);
 
1224
     glVertex2f(point[0], point[1]);
 
1225
     glVertex2f(arrow1[0], arrow1[1]);
 
1226
     glVertex2f(point[0], point[1]);
 
1227
     glVertex2f(arrow2[0], arrow2[1]);
 
1228
     glEnd();
 
1229
     
 
1230
     //glPopAttrib();
 
1231
     }
 
1232
     */
 
1233
    
 
1234
    void draw_coordinate_grid(float size, int spacing)
 
1235
    {
 
1236
        glPushAttrib(GL_CURRENT_BIT|GL_ENABLE_BIT|GL_LINE_BIT);
 
1237
        glDisable(GL_LIGHTING);
 
1238
        glLineWidth(1);
 
1239
        
 
1240
        glBegin(GL_LINES);
 
1241
        glColor3f(0.5f,0.5f,0.5f);
 
1242
        for(int i=-spacing; i<=spacing; ++i){
 
1243
            glVertex3f(-size,0,i*size/spacing);
 
1244
            glVertex3f((i!=0)*size,0,i*size/spacing);
 
1245
            glVertex3f(i*size/spacing,0,-size);
 
1246
            glVertex3f(i*size/spacing,0,(i!=0)*size);
 
1247
        }
 
1248
        glColor3f(1,0,0);
 
1249
        glVertex3f(0,0,0);
 
1250
        glVertex3f(size,0,0);
 
1251
        glColor3f(0,1,0);
 
1252
        glVertex3f(0,0,0);
 
1253
        glVertex3f(0,size,0);
 
1254
        glColor3f(0,0,1);
 
1255
        glVertex3f(0,0,0);
 
1256
        glVertex3f(0,0,size);
 
1257
        glEnd();
 
1258
        
 
1259
        glPopAttrib();
 
1260
    }
 
1261
    
 
1262
    void draw_text( const float* /*point[3]*/, const char* /*text*/, int /*fontsize*/ )
 
1263
    {
 
1264
        // please implement me!
 
1265
    }
 
1266
    
 
1267
    int windowID = 0;
 
1268
    
 
1269
    //=================================================================================
 
1270
    
 
1271
    void init(const char *windowtitle, int *argc, char **argv)
 
1272
    {
 
1273
        glutInit(argc, argv);
 
1274
        glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_ALPHA|GLUT_DEPTH|GLUT_STENCIL);
 
1275
        glutInitWindowSize(winwidth, winheight);
 
1276
        windowID = glutCreateWindow(windowtitle);
 
1277
        glutReshapeFunc(gluviReshape);
 
1278
        glutDisplayFunc(gluviDisplay);
 
1279
        glutMouseFunc(gluviMouse);
 
1280
        glutMotionFunc(gluviDrag);
 
1281
        glEnable(GL_DEPTH_TEST);
 
1282
        glClearDepth(1);
 
1283
        glPixelStorei(GL_PACK_ALIGNMENT, 1);
 
1284
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
1285
        
 
1286
        glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE);
 
1287
        glClearColor (1.0f, 1.0f, 1.0f, 1.0f);
 
1288
    }
 
1289
    
 
1290
    //=================================================================================
 
1291
    
 
1292
    void (*userDisplayFunc)(void)=0; 
 
1293
    void (*userMouseFunc)(int button, int state, int x, int y)=0;
 
1294
    void (*userDragFunc)(int x, int y)=0;
 
1295
    Camera *camera=0;
 
1296
    WidgetList root(0);
 
1297
    int winwidth=720, winheight=480;
 
1298
    
 
1299
    //=================================================================================
 
1300
    
 
1301
    void run(void)
 
1302
    {
 
1303
        glutMainLoop();
 
1304
    }
 
1305
    
 
1306
}     // namespace Gluvi
 
1307