11
#include <OpenGL/OpenGL.h>
20
#define M_PI 3.14159265358979323846f
27
bool taking_screenshot = false;
28
GLuint screenshot_fbo;
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_),
36
near_clip_factor(near_clip_factor_), far_clip_factor(far_clip_factor_),
37
action_mode(INACTIVE),
38
oldmousex(0), oldmousey(0)
49
default_target[0]=target[0];
50
default_target[1]=target[1];
51
default_target[2]=target[2];
55
click(int button, int state, int x, int y)
59
else if(button==GLUT_LEFT_BUTTON)
61
else if(button==GLUT_MIDDLE_BUTTON)
63
else if(button==GLUT_RIGHT_BUTTON)
74
return; // nothing to do
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;
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);
89
dist*=pow(1.01f, oldmousey-y + x-oldmousex);
98
return_to_default(void)
100
target[0]=default_target[0];
101
target[1]=default_target[1];
102
target[2]=default_target[2];
104
heading=default_heading;
109
transform_mouse(int x, int y, float ray_origin[3], float ray_direction[3])
111
float ch=cos(heading), sh=sin(heading);
112
float cp=cos(pitch), sp=sin(pitch);
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;
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;
124
ray_direction[2]=-px*sh+pz*ch;
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];
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;
141
get_viewing_direction(float direction[3])
143
float ch=cos(heading), sh=sin(heading);
144
float cp=cos(pitch), sp=sin(pitch);
150
void Target3D::get_up_vector(float up[3])
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>
155
float ch=cos(heading), sh=sin(heading);
156
float cp=cos(pitch), sp=sin(pitch);
165
glViewport(0, 0, (GLsizei)winwidth, (GLsizei)winheight);
167
glMatrixMode(GL_PROJECTION);
169
//gluPerspective(fovy, winwidth/(float)winheight, near_clip_factor*dist, far_clip_factor*dist);
171
gluPerspective(fovy, winwidth/(float)winheight, near_clip_factor, far_clip_factor);
173
glMatrixMode(GL_MODELVIEW);
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
186
export_rib(ostream &output)
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;
198
//=================================================================================
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)
209
target[0]=target_[0];
210
target[1]=target_[1];
211
target[2]=target_[2];
217
default_target[0]=target[0];
218
default_target[1]=target[1];
219
default_target[2]=target[2];
221
default_heading=heading;
226
click(int button, int state, int x, int y)
229
action_mode=INACTIVE;
230
else if(button==GLUT_LEFT_BUTTON)
232
else if(button==GLUT_MIDDLE_BUTTON)
234
else if(button==GLUT_RIGHT_BUTTON)
245
return; // nothing to do
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;
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);
260
dist*=pow(1.01f, oldmousey-y + x-oldmousex);
269
return_to_default(void)
271
target[0]=default_target[0];
272
target[1]=default_target[1];
273
target[2]=default_target[2];
275
heading=default_heading;
280
transform_mouse(int, int, float* /*ray_origin[3]*/, float* /*ray_direction[3]*/ )
286
get_viewing_direction(float direction[3])
288
float ch=cos(heading), sh=sin(heading);
289
float cp=cos(pitch), sp=sin(pitch);
298
glViewport(0, 0, (GLsizei)winwidth, (GLsizei)winheight);
300
glMatrixMode(GL_PROJECTION);
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);
305
glMatrixMode(GL_MODELVIEW);
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
314
export_rib(ostream &output)
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;
327
//=================================================================================
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)
338
click(int button, int state, int x, int y)
341
float r=height/winheight;
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);
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;
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;
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);
375
// zoom out by some constant factor
377
float factor=1.41421356237309504880168f;
378
left-=0.5f*(factor-1)*height;
379
bottom-=0.5f*(factor-1)*winwidth*height/winheight;
387
action_mode=INACTIVE;
389
}else if(button==GLUT_LEFT_BUTTON)
393
else if(button==GLUT_MIDDLE_BUTTON){
397
}else if(button==GLUT_RIGHT_BUTTON)
398
action_mode=ZOOM_OUT;
399
moved_since_mouse_down=false;
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);
414
}else if(action_mode==ZOOM_IN)
424
return_to_default(void)
426
bottom=default_bottom;
428
height=default_height;
432
transform_mouse(int x, int y, float coords[2])
434
float r=height/winheight;
436
coords[1]=(winheight-y)*r+bottom;
442
glViewport(0, 0, (GLsizei)winwidth, (GLsizei)winheight);
443
glMatrixMode(GL_PROJECTION);
445
glOrtho(left, left+(height*winwidth)/winheight, bottom, bottom+height, 0, 1);
446
glMatrixMode(GL_MODELVIEW);
451
export_rib(ostream &output)
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
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;
469
if(action_mode==ZOOM_IN && moved_since_mouse_down){
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);
481
//=================================================================================
484
StaticText(const char *text_)
489
display(int x, int y)
493
width=glutBitmapLength(GLUT_BITMAP_HELVETICA_12, (const unsigned char*)text)+1;
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]);
500
glRasterPos2i(x+1, y-height+3);
501
for(int i=0; text[i]!=0; ++i)
502
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, text[i]);
505
//=================================================================================
507
DynamicText::DynamicText( const std::string& text_ )
516
void DynamicText::set_color( float r, float g, float b )
523
void DynamicText::display( int x, int y )
527
width=glutBitmapLength(GLUT_BITMAP_HELVETICA_12, (const unsigned char*)text.c_str())+1;
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]);
535
glColor3f( color[0], color[1], color[2] );
537
glRasterPos2i(x+1, y-height+3);
538
for(int i=0; text[i]!=0; ++i)
539
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, text[i]);
543
//=================================================================================
546
Button(const char *text_, int minwidth_)
547
: status(UNINVOLVED), text(text_), minwidth(minwidth_)
551
display(int x, int 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;
559
if(status==UNINVOLVED){
560
glColor3f(0.7f, 0.7f, 0.7f);
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);
567
glColor3f(0.3f, 0.3f, 0.3f);
569
glBegin(GL_LINE_STRIP);
571
glVertex2i(x, y-height);
572
glVertex2i(x+width-1, y-height);
574
glColor3f(0.3f, 0.3f, 0.3f);
576
if(status==SELECTED) glColor3f(0.8f, 0.8f, 0.8f);
577
else glColor3f(1, 1, 1);
580
glVertex2i(x+width, y-1);
581
glVertex2i(x+width, y-height);
582
glVertex2i(x, y-height);
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]);
592
click(int state, int x, int y)
594
if(state==GLUT_DOWN && x>dispx && x<=dispx+width && y<dispy-2 && y>=dispy-height){
598
}else if(state==GLUT_UP && status!=UNINVOLVED){
601
if(x>=dispx && x<dispx+width && y<dispy-2 && y>=dispy-height)
611
// needs to control highlighting (SELECTED vs. HIGHLIGHTED)
612
if(status==SELECTED && x>=dispx && x<dispx+width && y<dispy-2 && y>=dispy-height){
615
}else if(status==HIGHLIGHTED && !(x>=dispx && x<dispx+width && y<dispy-2 && y>=dispy-height)){
621
//=================================================================================
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)
630
display(int x, int y)
634
width=glutBitmapLength(GLUT_BITMAP_HELVETICA_12, (const unsigned char*)text);
635
if(width<justify) width=justify;
636
width+=11+6+length+1;
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]);
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;
648
scrollymin=y-height+1;
650
glColor3f(0.3f, 0.3f, 0.3f);
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);
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);
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);
672
glColor3f(0.7f, 0.7f, 0.7f);
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);
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);
691
click(int state, int x, int y)
693
if(state==GLUT_DOWN && x>scrollxmin+position+2 && x<=scrollxmin+position+11 && y<scrollymax-1 && y>=scrollymin+2){
698
}else if(status!=UNINVOLVED && state==GLUT_UP){
707
drag(int x, int /*y*/ )
709
if(status==SELECTED){
711
int newposition=position+(x-clickx);
714
clickx+=(0-newposition);
716
}else if(newposition>length){
717
clickx+=(length-newposition);
720
if(newposition!=position){
721
position=newposition;
728
//=================================================================================
731
WidgetList(int indent_, bool hidden_)
732
: indent(indent_), hidden(hidden_), list(), downclicked_member(-1)
737
display(int x, int y)
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;
754
click(int state, int x, int y)
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;
764
}else if(state==GLUT_UP && downclicked_member>=0){
765
list[downclicked_member]->click(state, x, y);
766
downclicked_member=-1;
774
if(downclicked_member>=0)
775
list[downclicked_member]->drag(x, y);
779
//=================================================================================
781
typedef enum {NOBODY, CAMERA, WIDGETS, USER} MouseOwnerType;
783
MouseOwnerType mouse_owner = NOBODY;
786
// Local ("static") functions
791
//=================================================================================
793
void gluviReshape(int w, int h)
797
glutPostRedisplay(); // triggers the camera to adjust itself to the new dimensions
800
//=================================================================================
805
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
808
if(camera) camera->gl_transform();
809
if(userDisplayFunc) userDisplayFunc();
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);
816
// and probably more needs setting before widgets
818
glMatrixMode(GL_MODELVIEW);
820
glMatrixMode(GL_PROJECTION);
822
gluOrtho2D(0, winwidth, 0, winheight);
824
root.display(0, winheight);
826
// and allow the camera to draw something on screen (e.g. for zooming extent)
827
if(camera) camera->display_screen();
834
void gluviMouse(int button, int state, int x, int y)
836
if(state==GLUT_DOWN){
837
int mods=glutGetModifiers();
838
if(camera && mods==GLUT_ACTIVE_SHIFT){
839
camera->click(button, state, x, y);
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);
847
}else{ // mouse up - send event to whoever got the mouse down
850
camera->click(button, state, x, y);
853
//root.click(state, x, winheight-y);
856
if(userMouseFunc) userMouseFunc(button, state, x, y);
865
//=================================================================================
867
void gluviDrag(int x, int y)
874
//root.drag(x, winheight-y);
877
if(userDragFunc) userDragFunc(x, y);
888
//=================================================================================
890
void ppm_screenshot(const char *filename_format, ...)
893
va_start(ap, filename_format);
895
#define FILENAMELENGTH 256
896
char filename[FILENAMELENGTH];
897
_vsnprintf(filename, FILENAMELENGTH, filename_format, ap);
898
ofstream out(filename, ofstream::binary);
901
vasprintf(&filename, filename_format, ap);
902
ofstream out(filename, ofstream::binary);
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;
917
void write_big_endian_ushort(std::ostream &output, unsigned short v)
919
output.put( static_cast<char>((v>>8)%256) );
920
output.put( static_cast<char>(v%256) );
923
void write_big_endian_uint(std::ostream &output, unsigned int v)
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));
931
} // unnamed namespace
933
void sgi_screenshot(const char *filename_format, ...)
936
va_start(ap, filename_format);
938
#define FILENAMELENGTH 256
939
char filename[FILENAMELENGTH];
940
_vsnprintf(filename, FILENAMELENGTH, filename_format, ap);
941
ofstream output(filename, ofstream::binary);
944
vasprintf(&filename, filename_format, ap);
945
ofstream output(filename, ofstream::binary);
949
const int mipmap_level = 1;
950
const int size_scale = 1 << (mipmap_level);
952
winwidth = size_scale * winwidth;
953
winheight = size_scale * winheight;
955
glGenFramebuffers(1, &screenshot_fbo);
956
glBindFramebuffer(GL_FRAMEBUFFER, screenshot_fbo);
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);
969
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureId, 0);
972
// Depth/stencil buffer
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);
982
if (status != GL_FRAMEBUFFER_COMPLETE)
984
std::cout << "Problem with OpenGL framebuffer after specifying depth/stencil render buffer: " << hex << status << std::endl;
988
glPixelStorei(GL_PACK_ALIGNMENT, 1);
989
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
990
glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE);
992
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
996
taking_screenshot = true;
998
if(camera) camera->gl_transform();
999
if(userDisplayFunc) userDisplayFunc();
1001
taking_screenshot = false;
1003
glEnable(GL_TEXTURE_2D);
1004
glGenerateMipmapEXT(GL_TEXTURE_2D);
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 );
1010
GLubyte *buffer = new GLubyte[ 4 * file_width * file_height ];
1012
glGetTexImage( GL_TEXTURE_2D, mipmap_level, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
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];
1019
for(int y = 0; y < file_height; y++)
1020
for(int x = 0; x < file_width; x++)
1022
int startAddressOfPixel = ((y*file_width) + x)*4;
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];
1030
// first write the SGI header
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
1046
for(i=0; i<80 && filename[i]; ++i)
1047
output.put(filename[i]);
1050
write_big_endian_uint(output, 0); // colormap is normal
1051
for(i=0; i<404; ++i) output.put(0); // filler to complete header
1053
// now write the SGI image data
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);
1064
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
1065
glBindTexture(GL_TEXTURE_2D, 0);
1067
winwidth /= size_scale;
1068
winheight /= size_scale;
1069
if(camera) camera->gl_transform();
1071
glDeleteTextures( 1, &textureId );
1072
glDeleteRenderbuffers( 1, &depthRenderbuffer );
1073
glDeleteFramebuffers(1, &screenshot_fbo);
1080
void set_generic_lights(void)
1082
glEnable(GL_LIGHTING);
1084
GLfloat ambient[4] = {.3f, .3f, .3f, 1.0f};
1085
glLightModelfv (GL_LIGHT_MODEL_AMBIENT,ambient);
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);
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);
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);
1107
void set_generic_material(float r, float g, float b, GLenum face)
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);
1119
void set_matte_material(float r, float g, float b, GLenum face)
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);
1131
* Draw a vector in 3D. If arrow_head_length not specified, set it to 10% of vector length.
1134
void draw_3d_arrow(const float base[3], const float point[3], float arrow_head_length)
1136
//glPushAttrib(GL_CURRENT_BIT|GL_ENABLE_BIT|GL_LINE_BIT);
1137
//glDisable(GL_LIGHTING);
1139
glColor3f(0.5f,0.5f,0.5f);
1141
Vec3f w(point[0]-base[0], point[1]-base[1], point[2]-base[2]);
1143
w = w / len; // normalize to build coordinate system
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));
1149
// If vector is parallel to the y-axis, use the x-axis
1151
u = cross(w, Vec3f(1,0,0));
1153
// get a vector perp to w and u
1154
Vec3f v = cross(w, u/mag(u));
1157
if (!arrow_head_length)
1158
arrow_head_length = 0.1f * len;
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]);
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]);
1182
// draw_2d_arrow assumptions:
1183
// line width, point size, and color are set by the user prior to calling the routine
1185
void draw_2d_arrow(const Vec2f base, const Vec2f point, float arrow_head_length)
1187
//glPushAttrib(GL_CURRENT_BIT|GL_ENABLE_BIT|GL_LINE_BIT);
1188
//glDisable(GL_LIGHTING);
1190
Vec2f w = point-base;
1195
glVertex2f(base[0], base[1]);
1200
w = w / len; // normalize to build coordinate system
1203
// using rotation matrix 0 1
1205
Vec2f u = Vec2f(1*w[1], -1*w[0]);
1208
// v = w - 90 (in fact v=-u)
1209
Vec2f v = Vec2f(-1*w[1], 1*w[0]);
1212
if (!arrow_head_length) {
1213
arrow_head_length = 0.1f * len;
1216
// arrow head points
1217
Vec2f arrow1, arrow2;
1218
arrow1 = point + arrow_head_length * (v-w);
1219
arrow2 = point + arrow_head_length * (u-w);
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]);
1234
void draw_coordinate_grid(float size, int spacing)
1236
glPushAttrib(GL_CURRENT_BIT|GL_ENABLE_BIT|GL_LINE_BIT);
1237
glDisable(GL_LIGHTING);
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);
1250
glVertex3f(size,0,0);
1253
glVertex3f(0,size,0);
1256
glVertex3f(0,0,size);
1262
void draw_text( const float* /*point[3]*/, const char* /*text*/, int /*fontsize*/ )
1264
// please implement me!
1269
//=================================================================================
1271
void init(const char *windowtitle, int *argc, char **argv)
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);
1283
glPixelStorei(GL_PACK_ALIGNMENT, 1);
1284
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1286
glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE);
1287
glClearColor (1.0f, 1.0f, 1.0f, 1.0f);
1290
//=================================================================================
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;
1297
int winwidth=720, winheight=480;
1299
//=================================================================================
1306
} // namespace Gluvi