1 //========================================================================
2 // This is an example program for the GLFW library
3 //
4 // The program uses a "split window" view, rendering four views of the
5 // same scene in one window (e.g. uesful for 3D modelling software). This
6 // demo uses scissors to separete the four different rendering areas from
7 // each other.
8 //
9 // (If the code seems a little bit strange here and there, it may be
10 //  because I am not a friend of orthogonal projections)
11 //========================================================================
12 
13 #include <GL/glfw.h>
14 #include <math.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 
18 #ifndef M_PI
19 #define M_PI 3.14159265358979323846
20 #endif
21 
22 
23 //========================================================================
24 // Global variables
25 //========================================================================
26 
27 // Mouse position
28 static int xpos = 0, ypos = 0;
29 
30 // Window size
31 static int width, height;
32 
33 // Active view: 0 = none, 1 = upper left, 2 = upper right, 3 = lower left,
34 // 4 = lower right
35 static int active_view = 0;
36 
37 // Rotation around each axis
38 static int rot_x = 0, rot_y = 0, rot_z = 0;
39 
40 // Do redraw?
41 static int do_redraw = 1;
42 
43 
44 //========================================================================
45 // Draw a solid torus (use a display list for the model)
46 //========================================================================
47 
48 #define TORUS_MAJOR     1.5
49 #define TORUS_MINOR     0.5
50 #define TORUS_MAJOR_RES 32
51 #define TORUS_MINOR_RES 32
52 
drawTorus(void)53 static void drawTorus( void )
54 {
55     static GLuint torus_list = 0;
56     int    i, j, k;
57     double s, t, x, y, z, nx, ny, nz, scale, twopi;
58 
59     if( !torus_list )
60     {
61         // Start recording displaylist
62         torus_list = glGenLists( 1 );
63         glNewList( torus_list, GL_COMPILE_AND_EXECUTE );
64 
65         // Draw torus
66         twopi = 2.0 * M_PI;
67         for( i = 0; i < TORUS_MINOR_RES; i++ )
68         {
69             glBegin( GL_QUAD_STRIP );
70             for( j = 0; j <= TORUS_MAJOR_RES; j++ )
71             {
72                 for( k = 1; k >= 0; k-- )
73                 {
74                     s = (i + k) % TORUS_MINOR_RES + 0.5;
75                     t = j % TORUS_MAJOR_RES;
76 
77                     // Calculate point on surface
78                     x = (TORUS_MAJOR+TORUS_MINOR*cos(s*twopi/TORUS_MINOR_RES))*cos(t*twopi/TORUS_MAJOR_RES);
79                     y = TORUS_MINOR * sin(s * twopi / TORUS_MINOR_RES);
80                     z = (TORUS_MAJOR+TORUS_MINOR*cos(s*twopi/TORUS_MINOR_RES))*sin(t*twopi/TORUS_MAJOR_RES);
81 
82                     // Calculate surface normal
83                     nx = x - TORUS_MAJOR*cos(t*twopi/TORUS_MAJOR_RES);
84                     ny = y;
85                     nz = z - TORUS_MAJOR*sin(t*twopi/TORUS_MAJOR_RES);
86                     scale = 1.0 / sqrt( nx*nx + ny*ny + nz*nz );
87                     nx *= scale;
88                     ny *= scale;
89                     nz *= scale;
90 
91                     glNormal3f( (float)nx, (float)ny, (float)nz );
92                     glVertex3f( (float)x, (float)y, (float)z );
93                 }
94             }
95             glEnd();
96         }
97 
98         // Stop recording displaylist
99         glEndList();
100     }
101     else
102     {
103         // Playback displaylist
104         glCallList( torus_list );
105     }
106 }
107 
108 
109 //========================================================================
110 // Draw the scene (a rotating torus)
111 //========================================================================
112 
drawScene(void)113 static void drawScene( void )
114 {
115     const GLfloat model_diffuse[4]  = {1.0f, 0.8f, 0.8f, 1.0f};
116     const GLfloat model_specular[4] = {0.6f, 0.6f, 0.6f, 1.0f};
117     const GLfloat model_shininess   = 20.0f;
118 
119     glPushMatrix();
120 
121     // Rotate the object
122     glRotatef( (GLfloat)rot_x*0.5f, 1.0f, 0.0f, 0.0f );
123     glRotatef( (GLfloat)rot_y*0.5f, 0.0f, 1.0f, 0.0f );
124     glRotatef( (GLfloat)rot_z*0.5f, 0.0f, 0.0f, 1.0f );
125 
126     // Set model color (used for orthogonal views, lighting disabled)
127     glColor4fv( model_diffuse );
128 
129     // Set model material (used for perspective view, lighting enabled)
130     glMaterialfv( GL_FRONT, GL_DIFFUSE, model_diffuse );
131     glMaterialfv( GL_FRONT, GL_SPECULAR, model_specular );
132     glMaterialf(  GL_FRONT, GL_SHININESS, model_shininess );
133 
134     // Draw torus
135     drawTorus();
136 
137     glPopMatrix();
138 }
139 
140 
141 //========================================================================
142 // Draw a 2D grid (used for orthogonal views)
143 //========================================================================
144 
drawGrid(float scale,int steps)145 static void drawGrid( float scale, int steps )
146 {
147     int   i;
148     float x, y;
149 
150     glPushMatrix();
151 
152     // Set background to some dark bluish grey
153     glClearColor( 0.05f, 0.05f, 0.2f, 0.0f);
154     glClear( GL_COLOR_BUFFER_BIT );
155 
156     // Setup modelview matrix (flat XY view)
157     glLoadIdentity();
158     gluLookAt( 0.0, 0.0, 1.0,
159                0.0, 0.0, 0.0,
160                0.0, 1.0, 0.0 );
161 
162     // We don't want to update the Z-buffer
163     glDepthMask( GL_FALSE );
164 
165     // Set grid color
166     glColor3f( 0.0f, 0.5f, 0.5f );
167 
168     glBegin( GL_LINES );
169 
170     // Horizontal lines
171     x = scale * 0.5f * (float)(steps-1);
172     y = -scale * 0.5f * (float)(steps-1);
173     for( i = 0; i < steps; i ++ )
174     {
175         glVertex3f( -x, y, 0.0f );
176         glVertex3f( x, y, 0.0f );
177         y += scale;
178     }
179 
180     // Vertical lines
181     x = -scale * 0.5f * (float)(steps-1);
182     y = scale * 0.5f * (float)(steps-1);
183     for( i = 0; i < steps; i ++ )
184     {
185         glVertex3f( x, -y, 0.0f );
186         glVertex3f( x, y, 0.0f );
187         x += scale;
188     }
189 
190     glEnd();
191 
192     // Enable Z-buffer writing again
193     glDepthMask( GL_TRUE );
194 
195     glPopMatrix();
196 }
197 
198 
199 //========================================================================
200 // Draw all views
201 //========================================================================
202 
drawAllViews(void)203 static void drawAllViews( void )
204 {
205     const GLfloat light_position[4] = {0.0f, 8.0f, 8.0f, 1.0f};
206     const GLfloat light_diffuse[4]  = {1.0f, 1.0f, 1.0f, 1.0f};
207     const GLfloat light_specular[4] = {1.0f, 1.0f, 1.0f, 1.0f};
208     const GLfloat light_ambient[4]  = {0.2f, 0.2f, 0.3f, 1.0f};
209     double aspect;
210 
211     // Calculate aspect of window
212     if( height > 0 )
213     {
214         aspect = (double)width / (double)height;
215     }
216     else
217     {
218         aspect = 1.0;
219     }
220 
221     // Clear screen
222     glClearColor( 0.0f, 0.0f, 0.0f, 0.0f);
223     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
224 
225     // Enable scissor test
226     glEnable( GL_SCISSOR_TEST );
227 
228     // Enable depth test
229     glEnable( GL_DEPTH_TEST );
230     glDepthFunc( GL_LEQUAL );
231 
232 
233     // ** ORTHOGONAL VIEWS **
234 
235     // For orthogonal views, use wireframe rendering
236     glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
237 
238     // Enable line anti-aliasing
239     glEnable( GL_LINE_SMOOTH );
240     glEnable( GL_BLEND );
241     glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
242 
243     // Setup orthogonal projection matrix
244     glMatrixMode( GL_PROJECTION );
245     glLoadIdentity();
246     glOrtho( -3.0*aspect, 3.0*aspect, -3.0, 3.0, 1.0, 50.0 );
247 
248     // Upper left view (TOP VIEW)
249     glViewport( 0, height/2, width/2, height/2 );
250     glScissor( 0, height/2, width/2, height/2 );
251     glMatrixMode( GL_MODELVIEW );
252     glLoadIdentity();
253     gluLookAt( 0.0f, 10.0f, 1e-3f,   // Eye-position (above)
254                0.0f, 0.0f, 0.0f,     // View-point
255                0.0f, 1.0f, 0.0f );   // Up-vector
256     drawGrid( 0.5, 12 );
257     drawScene();
258 
259     // Lower left view (FRONT VIEW)
260     glViewport( 0, 0, width/2, height/2 );
261     glScissor( 0, 0, width/2, height/2 );
262     glMatrixMode( GL_MODELVIEW );
263     glLoadIdentity();
264     gluLookAt( 0.0f, 0.0f, 10.0f,    // Eye-position (in front of)
265                0.0f, 0.0f, 0.0f,     // View-point
266                0.0f, 1.0f, 0.0f );   // Up-vector
267     drawGrid( 0.5, 12 );
268     drawScene();
269 
270     // Lower right view (SIDE VIEW)
271     glViewport( width/2, 0, width/2, height/2 );
272     glScissor( width/2, 0, width/2, height/2 );
273     glMatrixMode( GL_MODELVIEW );
274     glLoadIdentity();
275     gluLookAt( 10.0f, 0.0f, 0.0f,    // Eye-position (to the right)
276                0.0f, 0.0f, 0.0f,     // View-point
277                0.0f, 1.0f, 0.0f );   // Up-vector
278     drawGrid( 0.5, 12 );
279     drawScene();
280 
281     // Disable line anti-aliasing
282     glDisable( GL_LINE_SMOOTH );
283     glDisable( GL_BLEND );
284 
285 
286     // ** PERSPECTIVE VIEW **
287 
288     // For perspective view, use solid rendering
289     glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
290 
291     // Enable face culling (faster rendering)
292     glEnable( GL_CULL_FACE );
293     glCullFace( GL_BACK );
294     glFrontFace( GL_CW );
295 
296     // Setup perspective projection matrix
297     glMatrixMode( GL_PROJECTION );
298     glLoadIdentity();
299     gluPerspective( 65.0f, aspect, 1.0f, 50.0f );
300 
301     // Upper right view (PERSPECTIVE VIEW)
302     glViewport( width/2, height/2, width/2, height/2 );
303     glScissor( width/2, height/2, width/2, height/2 );
304     glMatrixMode( GL_MODELVIEW );
305     glLoadIdentity();
306     gluLookAt( 3.0f, 1.5f, 3.0f,     // Eye-position
307                0.0f, 0.0f, 0.0f,     // View-point
308                0.0f, 1.0f, 0.0f );   // Up-vector
309 
310     // Configure and enable light source 1
311     glLightfv( GL_LIGHT1, GL_POSITION, light_position );
312     glLightfv( GL_LIGHT1, GL_AMBIENT, light_ambient );
313     glLightfv( GL_LIGHT1, GL_DIFFUSE, light_diffuse );
314     glLightfv( GL_LIGHT1, GL_SPECULAR, light_specular );
315     glEnable( GL_LIGHT1 );
316     glEnable( GL_LIGHTING );
317 
318     // Draw scene
319     drawScene();
320 
321     // Disable lighting
322     glDisable( GL_LIGHTING );
323 
324     // Disable face culling
325     glDisable( GL_CULL_FACE );
326 
327     // Disable depth test
328     glDisable( GL_DEPTH_TEST );
329 
330     // Disable scissor test
331     glDisable( GL_SCISSOR_TEST );
332 
333 
334     // Draw a border around the active view
335     if( active_view > 0 && active_view != 2 )
336     {
337         glViewport( 0, 0, width, height );
338         glMatrixMode( GL_PROJECTION );
339         glLoadIdentity();
340         glOrtho( 0.0, 2.0, 0.0, 2.0, 0.0, 1.0 );
341         glMatrixMode( GL_MODELVIEW );
342         glLoadIdentity();
343         glColor3f( 1.0f, 1.0f, 0.6f );
344         glTranslatef( (GLfloat) ((active_view - 1) & 1), (GLfloat) (1 - (active_view - 1) / 2), 0.0f );
345         glBegin( GL_LINE_STRIP );
346           glVertex2i( 0, 0 );
347           glVertex2i( 1, 0 );
348           glVertex2i( 1, 1 );
349           glVertex2i( 0, 1 );
350           glVertex2i( 0, 0 );
351         glEnd();
352     }
353 }
354 
355 
356 //========================================================================
357 // Window size callback function
358 //========================================================================
359 
windowSizeFun(int w,int h)360 static void GLFWCALL windowSizeFun( int w, int h )
361 {
362     width  = w;
363     height = h > 0 ? h : 1;
364     do_redraw = 1;
365 }
366 
367 
368 //========================================================================
369 // Window refresh callback function
370 //========================================================================
371 
windowRefreshFun(void)372 static void GLFWCALL windowRefreshFun( void )
373 {
374     do_redraw = 1;
375 }
376 
377 
378 //========================================================================
379 // Mouse position callback function
380 //========================================================================
381 
mousePosFun(int x,int y)382 static void GLFWCALL mousePosFun( int x, int y )
383 {
384     // Depending on which view was selected, rotate around different axes
385     switch( active_view )
386     {
387         case 1:
388             rot_x += y - ypos;
389             rot_z += x - xpos;
390             do_redraw = 1;
391             break;
392         case 3:
393             rot_x += y - ypos;
394             rot_y += x - xpos;
395             do_redraw = 1;
396             break;
397         case 4:
398             rot_y += x - xpos;
399             rot_z += y - ypos;
400             do_redraw = 1;
401             break;
402         default:
403             // Do nothing for perspective view, or if no view is selected
404             break;
405     }
406 
407     // Remember mouse position
408     xpos = x;
409     ypos = y;
410 }
411 
412 
413 //========================================================================
414 // Mouse button callback function
415 //========================================================================
416 
mouseButtonFun(int button,int action)417 static void GLFWCALL mouseButtonFun( int button, int action )
418 {
419     // Button clicked?
420     if( ( button == GLFW_MOUSE_BUTTON_LEFT ) && action == GLFW_PRESS )
421     {
422         // Detect which of the four views was clicked
423         active_view = 1;
424         if( xpos >= width/2 )
425         {
426             active_view += 1;
427         }
428         if( ypos >= height/2 )
429         {
430             active_view += 2;
431         }
432     }
433 
434     // Button released?
435     else if( button == GLFW_MOUSE_BUTTON_LEFT )
436     {
437         // Deselect any previously selected view
438         active_view = 0;
439     }
440 
441     do_redraw = 1;
442 }
443 
444 
445 //========================================================================
446 // main()
447 //========================================================================
448 
main(void)449 int main( void )
450 {
451     // Initialise GLFW
452     if( !glfwInit() )
453     {
454         fprintf( stderr, "Failed to initialize GLFW\n" );
455         exit( EXIT_FAILURE );
456     }
457 
458     // Open OpenGL window
459     if( !glfwOpenWindow( 500, 500, 0,0,0,0, 16,0, GLFW_WINDOW ) )
460     {
461         fprintf( stderr, "Failed to open GLFW window\n" );
462         glfwTerminate();
463         exit( EXIT_FAILURE );
464     }
465 
466     // Enable vsync
467     glfwSwapInterval( 1 );
468 
469     // Set window title
470     glfwSetWindowTitle( "Split view demo" );
471 
472     // Enable sticky keys
473     glfwEnable( GLFW_STICKY_KEYS );
474 
475     // Enable mouse cursor (only needed for fullscreen mode)
476     glfwEnable( GLFW_MOUSE_CURSOR );
477 
478     // Disable automatic event polling
479     glfwDisable( GLFW_AUTO_POLL_EVENTS );
480 
481     // Set callback functions
482     glfwSetWindowSizeCallback( windowSizeFun );
483     glfwSetWindowRefreshCallback( windowRefreshFun );
484     glfwSetMousePosCallback( mousePosFun );
485     glfwSetMouseButtonCallback( mouseButtonFun );
486 
487     // Main loop
488     do
489     {
490         // Only redraw if we need to
491         if( do_redraw )
492         {
493             // Draw all views
494             drawAllViews();
495 
496             // Swap buffers
497             glfwSwapBuffers();
498 
499             do_redraw = 0;
500         }
501 
502         // Wait for new events
503         glfwWaitEvents();
504 
505     } // Check if the ESC key was pressed or the window was closed
506     while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS &&
507            glfwGetWindowParam( GLFW_OPENED ) );
508 
509     // Close OpenGL window and terminate GLFW
510     glfwTerminate();
511 
512     exit( EXIT_SUCCESS );
513 }
514 
515