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