This next sample program is considerably more advanced. It uses double.c and Listing 1.3 from the Red Book. It illustrates the use of the mouse and various call-back functions. We will convert it to ClearWin+.
1 #include "glos.h"
2
3 #include <GL/gl.h>
4 #include <GL/glu.h>
5 #include <GL/glaux.h>
6
7 void myinit(void);
8 void CALLBACK spinDisplay (void);
9 void CALLBACK startIdleFunc (AUX_EVENTREC *event);
10 void CALLBACK stopIdleFunc (AUX_EVENTREC *event);
11 void CALLBACK myReshape(GLsizei w, GLsizei h);
12 void CALLBACK display(void);
13
14 static GLfloat spin = 0.0;
15
16 void CALLBACK display(void)
17 {
18 glClear (GL_COLOR_BUFFER_BIT);
19
20 glPushMatrix ();
21 glRotatef (spin, 0.0, 0.0, 1.0);
22 glRectf (-25.0, -25.0, 25.0, 25.0);
23 glPopMatrix ();
24
25 glFlush();
26 auxSwapBuffers();
27 }
28
29 void CALLBACK spinDisplay (void)
30 {
31 spin = spin + 2.0;
32 if (spin > 360.0)
33 spin = spin - 360.0;
34 display();
35 }
36
37 void CALLBACK startIdleFunc (AUX_EVENTREC *event)
38 {
39 auxIdleFunc(spinDisplay);
40 }
41
42 void CALLBACK stopIdleFunc (AUX_EVENTREC *event)
43 {
44 auxIdleFunc(0);
45 }
46
47 void myinit (void)
48 {
49 glClearColor (0.0, 0.0, 0.0, 1.0);
50 glColor3f (1.0, 1.0, 1.0);
51 glShadeModel (GL_FLAT);
52 }
53
54 void CALLBACK myReshape(GLsizei w, GLsizei h)
55 {
56 if (!h) return;
57 glViewport(0, 0, w, h);
58 glMatrixMode(GL_PROJECTION);
59 glLoadIdentity();
50 if (w <= h)
61 glOrtho (-50.0, 50.0, -50.0*(GLfloat)h/(GLfloat)w,
62 50.0*(GLfloat)h/(GLfloat)w, -1.0, 1.0);
63 else
64 glOrtho (-50.0*(GLfloat)w/(GLfloat)h,
65 50.0*(GLfloat)w/(GLfloat)h, -50.0, 50.0, -1.0, 1.0);
66 glMatrixMode(GL_MODELVIEW);
67 glLoadIdentity ();
68 }
69
60 /* Main Loop
71 * Open window with initial window size, title bar,
72 * RGBA display mode, and handle input events.
73 */
74 int main(int argc, char** argv)
75 {
76 auxInitDisplayMode (AUX_DOUBLE | AUX_RGB);
77 auxInitPosition (0, 0, 500, 500);
78 auxInitWindow ("Double Buffering");
79 myinit ();
70 auxReshapeFunc (myReshape);
81 auxIdleFunc (spinDisplay);
82 auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, startIdleFunc);
83 auxMouseFunc (AUX_RIGHTBUTTON, AUX_MOUSEDOWN, stopIdleFunc);
84 auxMainLoop(display);
85 return(0);
86 }
The converted program double.for is presented below. Note the use of common blocks rather than C global variables.
Lines 76 to 78 in the Red Book sample have been replaced by a few ClearWin+ calls at lines 109 to 111. %og (OpenGL Graphics Region) has been replaced by %^og indicating that a call-back function, opengl_proc, has been provided to handle messages. The use of %pv (Pivot) means that RESIZE messages are sent to the call-back.
Mouse messages are also sent to opengl_proc, as are the special SETUP and DIRTY messages. SETUP is sent only once, just after the window has been created and its arrival precedes that of RESIZE. DIRTY is sent when the window needs repainting, for example, after RESIZE or when the window is brought to the top after being partially obscured. If you take action on the DIRTY call-back, you will not need the static option on %og.
The Red Book variant of the program supplies several functions to handle events. These functions are still needed and perform the same task, but they are called directly in response to ClearWin+ messages sent to opengl_proc. The reshape function myReshape(x,y) is called in response to RESIZE. display is called in response to DIRTY. The mouse handling functions startIdleFunc and stopIdleFunc are called in response to MOUSE_LEFT_CLICK and MOUSE_RIGHT_CLICK. These are registered as call-backs with GLAUX at lines 70 and 82-83.
In the Red Book example, the initialising call to myinit at line 79 (just after the window has been created) is handled by ClearWin+ as a message sent to opengl_proc. This message is SETUP and is always sent before the first RESIZE message. The GLAUX idle function has no direct ClearWin+ equivalent. Instead, %lw is used in the winio@ call and program execution falls through into the following idle loop. The test for ctrl<0 at line 113 in the ClearWin+ example, allows the program to detect when the window has been closed so that program termination can proceed.
1 SUBROUTINE display()
2 INCLUDE <opengl.ins>,nolist
3 REAL spin
4 LOGICAL do_draw
5 COMMON /double_com/do_draw,spin
6
7 CALL glClear(GL_COLOR_BUFFER_BIT)
8
9 CALL glPushMatrix()
10 CALL glRotatef(spin, 0.0, 0.0, 1.0)
11 CALL glRectf(-25.0, -25.0, 25.0, 25.0)
12 CALL glPopMatrix()
13
14 CALL glFlush()
15 CALL swap_opengl_buffers()
16 END
17
18 SUBROUTINE spinDisplay()
19 INCLUDE <clearwin.ins>,nolist
20 REAL spin
21 LOGICAL do_draw
22 COMMON /DOUBLE_COM/do_draw,spin
23
24 IF(do_draw)THEN
25 spin = spin + 2.0
26 IF(spin.GT.360.0)THEN
27 spin = spin - 360.0
28 ENDIF
29 CALL display()
30 ENDIF
31 CALL temporary_yield@()
32 END
33
34 SUBROUTINE startIdleFunc ()
35 REAL spin
36 LOGICAL do_draw
37 COMMON /DOUBLE_COM/do_draw,spin
38 do_draw=.TRUE.
39 END
40
41 SUBROUTINE stopIdleFunc ()
42 REAL spin
43 LOGICAL do_draw
44 COMMON /double_com/do_draw,spin
45 do_draw=.FALSE.
46 END
47
48 SUBROUTINE myinit ()
49 INCLUDE <opengl.ins>,nolist
50 CALL glClearColor (0.0, 0.0, 0.0, 1.0)
51 CALL glColor3f (1.0, 1.0, 1.0)
52 CALL glShadeModel (GL_FLAT)
53 END
54
55 SUBROUTINE myReshape(w, h)
56 INCLUDE <opengl.ins>,nolist
57 INTEGER w,h
58 DOUBLE PRECISION aspect_ratio
59 IF(h.NE.0) THEN
60 aspect_ratio=REAL(w)/h
61
62 CALL glViewport(0, 0, w, h)
63 CALL glMatrixMode(GL_PROJECTION)
64 CALL glLoadIdentity()
65 IF (w.LE.h) THEN
66 CALL glOrtho(-50d0, 50d0, -50d0/aspect_ratio,
67 & 50d0/aspect_ratio, -1d0, 1d0)
68 ELSE
69 CALL glOrtho(-50d0*aspect_ratio,
70 & 50d0*aspect_ratio, -50d0, 50d0, -1d0, 1d0)
71 ENDIF
72 CALL glMatrixMode(GL_MODELVIEW)
73 CALL glLoadIdentity ()
74 CALL display()
75 ENDIF
76 END
77
78
79 INTEGER FUNCTION opengl_proc()
80 INCLUDE <clearwin.ins>,nolist
81 CHARACTER*256 reason
82 INTEGER w,h
83 REASON=clearwin_string@('CALLBACK_REASON')
84 IF(reason.EQ.'SETUP')THEN
85 CALL myinit()
86 ELSE IF(reason.EQ.'RESIZE')THEN
87 w=clearwin_info@('OPENGL_WIDTH')
88 h=clearwin_info@('OPENGL_DEPTH')
89 CALL myReshape(w,h)
90 ELSE IF(reason.EQ.'MOUSE_LEFT_CLICK')THEN
91 CALL startIdleFunc()
92 ELSE IF(reason.EQ.'MOUSE_RIGHT_CLICK')THEN
93 CALL stopIdleFunc()
94 END IF
95
96 opengl_proc=2
97 END
98
99 PROGRAM double
100 INCLUDE <clearwin.ins>,nolist
101 INTEGER i
102 INTEGER opengl_proc,ctrl
103 EXTERNAL opengl_proc
104 REAL spin
105 LOGICAL do_draw
106 COMMON /double_com/do_draw,spin
107 DATA spin,do_draw/0.0,.TRUE./
108
109 i=winio@('%es%ca[Double Buffering]&')
110 i=winio@('%sp%ww[no_border]%pv%^og[double]%lw',
111 & 0,0,500,500,opengl_proc,ctrl)
112
113 WHILE(ctrl.LT.0)DO
114 CALL spinDisplay()
115 ENDWHILE
116 END
This program follows the structure that will be used throughout this chapter, and your attention is drawn again to the use of opengl_proc to call the reshape, display, initialisation and mouse handling functions.