OpenGL achieves animation by using two buffers, the front and the back buffer. When this, so called, double buffering is enabled, drawing (or rendering in OpenGL terminology) is directed to the back buffer. When the image is complete, you transfer it to the front buffer, or display, by calling swap_opengl_buffers@. This ClearWin+ routine merely remembers the current OpenGL context and so saves the programmer effort. When the back buffer is transferred to the display, it is supposed to be no longer valid so two successive swap buffer calls should produce garbage on the display. Although this does not seem to happen under Win32, the retention of the buffer should not be relied upon, as it might not be retained on other platforms.
The program below is not a Red Book sample. It illustrates the use of multiple windows, independently animated. This is something not possible using GLAUX.
The use of multiple OpenGL windows requires that you know the device context and rendering context for each of the windows. Changing from one window to another requires that you swap both the device context and the rendering context. Therefore, you must "enquire" them and store them away. These enquiry and swapping functions (together with some functions) are known as the WGL set. They do not form part of OpenGL, but are essential to the Windows implementation of it. Documentation for these functions will be found in the Microsoft Developer Network help files. You can be sure that when opengl_proc is called, the expected device and rendering contexts are current.
The font is also set by means of a WGL call, wglUseFontOutlines. Note how, in the the program, a C type NULL pointer is simulated by CORE4(0). This function call will only be successful if the format code %fn (Font) is used in the definition of the parent window.
**********************************
* *
* Animation using OpenGL *
* *
**********************************
SUBROUTINE display()
INCLUDE <opengl.ins>,nolist
INCLUDE <clearwin.ins>,nolist
INCLUDE 'danimate.ins'
CALL glClear (OR(GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT))
CALL glMatrixMode (GL_MODELVIEW)
CALL glLoadIdentity()
CALL glTranslated(0d0,0d0,-10d0)
CALL glRotated(spin,1d0,0d0,0d0)
CALL glCallList(101)
CALL swap_opengl_buffers()
CALL glFlush()
END
SUBROUTINE swapContexts(window)
INTEGER window
INCLUDE <opengl.ins>
INCLUDE 'danimate.ins'
CALL wglMakeCurrent(devicecontext(window),
& renderingcontext(window))
END
SUBROUTINE spinSlab(window)
INTEGER window
INCLUDE 'danimate.ins'
do_draw(window)=.TRUE.
END
SUBROUTINE stopSlab(window)
INTEGER window
INCLUDE 'danimate.ins'
do_draw(window)=.FALSE.
END
SUBROUTINE assemble_list
INCLUDE <clearwin.ins>,nolist
INCLUDE <opengl.ins>,nolist
REAL*4 white_colour(4),grey_colour(4),dark_grey_colour(4)
REAL*4 red_colour(4), yellow_colour(4), green_colour(4)
REAL*4 blue_colour(4), purple_colour(4), cyan_colour(4)
REAL*8 dimension,scale,d,fd,front,back
INTEGER flags,k
INTEGER hdc
LOGICAL ok
DATA white_colour/1.0,1.0,1.0,1.0/
DATA grey_colour/0.5,0.5,0.5,1.0/
DATA dark_grey_colour/0.3,0.3,0.3,1.0/
DATA red_colour/1.0,0.0,0.0,1.0/
DATA yellow_colour/1.0,1.0,0.0,1.0/
DATA green_colour/0.0,1.0,0.0,1.0/
DATA blue_colour/0.0,0.0,1.0,1.0/
DATA purple_colour/1.0,0.0,1.0,1.0/
DATA cyan_colour/0.0,1.0,1.0,1.0/
DATA front,back/-0.01d0,-0.5d0/
CALL glEnable(GL_DEPTH_TEST)
hDC=clearwin_info@('OPENGL_DEVICE_CONTEXT')
CALL glColor3f(1.0,1.0,1.0)
ok=wglUseFontOutlines(hDC, 0, 255, 1000, 0.0, 0.1,
& WGL_FONT_POLYGONS,core4(0))
CALL glMatrixMode (GL_MODELVIEW)
CALL glLoadIdentity()
CALL glTranslated(0d0,0d0,-10d0)
c----Clear the color and depth buffers.
CALL glClear (OR(GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT))
dimension=2.2d0
scale=dimension*0.9d0
CALL glDisable(GL_LIGHTING)
CALL glNewList(101,GL_COMPILE)
c----Front face
CALL glBegin(GL_POLYGON)
CALL glColor3fv(blue_colour)
CALL glVertex3d(-dimension,-dimension,front)
CALL glVertex3d(-dimension, dimension,front)
CALL glVertex3d( dimension, dimension,front)
CALL glVertex3d( dimension,-dimension,front)
CALL glEnd()
c----Back face
CALL glBegin(GL_POLYGON)
CALL glColor3fv(yellow_colour)
CALL glVertex3d(-dimension,-dimension,back)
CALL glVertex3d( dimension,-dimension,back)
CALL glVertex3d( dimension, dimension,back)
CALL glVertex3d(-dimension, dimension,back)
CALL glEnd()
c----Top face
CALL glBegin(GL_POLYGON)
CALL glColor3fv(red_colour)
CALL glVertex3d(-dimension, dimension,front)
CALL glVertex3d(-dimension, dimension,back)
CALL glVertex3d( dimension, dimension,back)
CALL glVertex3d( dimension, dimension,front)
CALL glEnd()
c----Bottom face
CALL glBegin(GL_POLYGON)
CALL glColor3fv(green_colour)
CALL glVertex3d( dimension,-dimension,front)
CALL glVertex3d( dimension,-dimension,back)
CALL glVertex3d(-dimension,-dimension,back)
CALL glVertex3d(-dimension,-dimension,front)
CALL glEnd()
c----Draw graph
CALL glBegin(GL_LINES)
CALL glColor3fv(white_colour)
CALL glVertex2d(-scale,0d0)
CALL glVertex2d(scale,0d0)
CALL glVertex2d(0d0,-scale)
CALL glVertex2d(0d0,scale)
k=-10
WHILE(k .LE. 10) DO
CALL glVertex2d((scale/10)*k,0.0d0)
CALL glVertex2d((scale/10)*k,0.1d0)
CALL glVertex2d(0.0d0,(scale/10)*k)
CALL glVertex2d(0.1d0,(scale/10)*k)
k=k+1
ENDWHILE
CALL glEnd()
CALL glColor3fv(red_colour)
CALL glBegin(GL_LINE_STRIP)
d=-10d0
WHILE(d .LT. 10d0)DO
fd=5*(d/10)**3+3*(d/10)**2-d/10
CALL glVertex2d(d*scale/10,fd*scale/10)
d=d+0.05d0
ENDWHILE
CALL glEnd()
CALL glColor3fv(green_colour)
CALL glBegin(GL_LINE_STRIP)
d=-10d0
WHILE(d .LT. 10)DO
fd=5*(d/10)**3+6*(d/10)**2-d/10
CALL glVertex2d(d*scale/10,fd*scale/10)
d=d+0.05d0
ENDWHILE
CALL glEnd()
CALL glColor3fv(red_colour)
CALL glListBase(1000)
CALL glTranslated(0.15d0,scale*0.95,0d0)
CALL glScaled(0.2d0,0.2d0,0.2d0)
CALL glCallLists(5, GL_UNSIGNED_BYTE, '+10.0')
CALL glEndList()
END
SUBROUTINE myinit()
CALL assemble_list()
END
SUBROUTINE myreshape(w,h)
INCLUDE <opengl.ins>,nolist
INTEGER w
INTEGER h
DOUBLE PRECISION aspect_ratio
IF(h.NE.0)THEN
aspect_ratio=dble(w)/h
CALL glMatrixMode(GL_PROJECTION)
CALL glLoadIdentity()
CALL gluPerspective(30.0d0,aspect_ratio,1d0,15d0)
CALL glViewport(0,0,w,h)
ENDIF
END
INTEGER FUNCTION opengl_proc1()
INCLUDE <clearwin.ins>,nolist
INCLUDE <opengl.ins>,nolist
INCLUDE 'danimate.ins',nolist
INTEGER w,h
CHARACTER*256 reason
reason=clearwin_string@('CALLBACK_REASON')
IF(reason.EQ.'SETUP')THEN
CALL myinit()
ELSEIF(reason.EQ.'RESIZE')THEN
w=clearwin_info@('OPENGL_WIDTH')
h=clearwin_info@('OPENGL_DEPTH')
CALL myreshape(w,h)
ELSEIF(reason.EQ.'DIRTY')THEN
CALL display()
window1_active=.true.
ELSEIf(reason.EQ.'MOUSE_LEFT_CLICK')THEN
CALL spinSlab(1)
ELSEIF(reason.EQ.'MOUSE_RIGHT_CLICK')THEN
CALL stopSlab(1)
ENDIF
opengl_proc1=2
END
INTEGER FUNCTION opengl_proc2()
INCLUDE <clearwin.ins>,nolist
INCLUDE <opengl.ins>,nolist
INCLUDE 'danimate.ins'
INTEGER w,h
CHARACTER*256 reason
reason=clearwin_string@('CALLBACK_REASON')
IF(reason.EQ.'SETUP')THEN
CALL myinit()
ELSEIF(reason.EQ.'RESIZE')THEN
w=clearwin_info@('OPENGL_WIDTH')
h=clearwin_info@('OPENGL_DEPTH')
CALL myreshape(w,h)
ELSEIF(reason.EQ.'DIRTY')THEN
CALL display()
window2_active=.true.
ELSEIF(reason.EQ.'MOUSE_LEFT_CLICK')THEN
CALL spinSlab(2)
ELSEIF(reason.EQ.'MOUSE_RIGHT_CLICK')THEN
CALL stopSlab(2)
ENDIF
CALL temporary_yield@()
opengl_proc2=2
END
PROGRAM Animate
INCLUDE <opengl.ins>,nolist
INCLUDE <clearwin.ins>,nolist
DOUBLE PRECISION spin_array(2)
INTEGER i,window1,window2
INTEGER opengl_proc1, opengl_proc2
EXTERNAL opengl_proc1,opengl_proc2
INCLUDE 'danimate.ins'
do_draw(1)=.true.
do_draw(2)=.true.
devicecontext(1)=0
devicecontext(2)=0
renderingcontext(1)=0
renderingcontext(2)=0
spin=0d0
spin_array(1)=0d0
spin_array(2)=0d0
window1_active=.false.
window2_active=.false.
c----Create a couple of OpenGL Windows
c----Window 1
i=winio@('%es%ca[Rotating Slab]&')
i=winio@('%fn[Times New Roman]%ts&',3.0d0)
i=winio@('%sp%ww[no_border]%pv%^og[double,depth16]%lw'.
& 0,0,350,350,opengl_proc1,window1)
c----Get and save hDC and the Rendering Contexts
devicecontext(1)=wglGetCurrentDC()
renderingcontext(1)=wglGetCurrentContext()
c----Create a couple of OpenGL Windows
c----Window 2
i=winio@('%es%ca[Rotating Slab]&')
i=winio@('%fn[Times New Roman]%ts&',3.0d0)
i=winio@('%sp%ww[no_border]%pv%^og[double,depth16]%lw',
& 400,0,350,350,opengl_proc2,window2)
c----Get and save hDC and the Rendering Contexts
devicecontext(2)=wglGetCurrentDC()
renderingcontext(2)=wglGetCurrentContext()
do_draw(1)=.true.
do_draw(2)=.true.
WHILE(window1.LT.0 .OR. window2.LT.0)DO
IF(window1.LT.0)THEN
IF(do_draw(1))THEN
spin_array(1)=spin_array(1)+2d0
spin=spin_array(1)
CALL swapContexts(1)
CALL display()
ENDIF
ENDIF
IF(window2.LT.0)THEN
IF(do_draw(2))THEN
spin_array(2)=spin_array(2)+2d0
spin=spin_array(2)
CALL swapContexts(2)
CALL display()
ENDIF
ENDIF
CALL temporary_yield@()
ENDWHILE
END