You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
		
		
		
		
		
			
		
			
				
					
					
						
							545 lines
						
					
					
						
							15 KiB
						
					
					
				
			
		
		
	
	
							545 lines
						
					
					
						
							15 KiB
						
					
					
				| //======================================================================== | |
| // This is an example program for the GLFW library | |
| // | |
| // The program uses a "split window" view, rendering four views of the | |
| // same scene in one window (e.g. uesful for 3D modelling software). This | |
| // demo uses scissors to separete the four different rendering areas from | |
| // each other. | |
| // | |
| // (If the code seems a little bit strange here and there, it may be | |
| //  because I am not a friend of orthogonal projections) | |
| //======================================================================== | |
|  | |
| #include <glad/glad.h> | |
| #include <GLFW/glfw3.h> | |
|  | |
| #if defined(_MSC_VER) | |
|  // Make MS math.h define M_PI | |
|  #define _USE_MATH_DEFINES | |
| #endif | |
|  | |
| #include <math.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
|  | |
| #include <linmath.h> | |
|  | |
| 
 | |
| //======================================================================== | |
| // Global variables | |
| //======================================================================== | |
|  | |
| // Mouse position | |
| static double xpos = 0, ypos = 0; | |
| 
 | |
| // Window size | |
| static int width, height; | |
| 
 | |
| // Active view: 0 = none, 1 = upper left, 2 = upper right, 3 = lower left, | |
| // 4 = lower right | |
| static int active_view = 0; | |
| 
 | |
| // Rotation around each axis | |
| static int rot_x = 0, rot_y = 0, rot_z = 0; | |
| 
 | |
| // Do redraw? | |
| static int do_redraw = 1; | |
| 
 | |
| 
 | |
| //======================================================================== | |
| // Draw a solid torus (use a display list for the model) | |
| //======================================================================== | |
|  | |
| #define TORUS_MAJOR     1.5 | |
| #define TORUS_MINOR     0.5 | |
| #define TORUS_MAJOR_RES 32 | |
| #define TORUS_MINOR_RES 32 | |
|  | |
| static void drawTorus(void) | |
| { | |
|     static GLuint torus_list = 0; | |
|     int    i, j, k; | |
|     double s, t, x, y, z, nx, ny, nz, scale, twopi; | |
| 
 | |
|     if (!torus_list) | |
|     { | |
|         // Start recording displaylist | |
|         torus_list = glGenLists(1); | |
|         glNewList(torus_list, GL_COMPILE_AND_EXECUTE); | |
| 
 | |
|         // Draw torus | |
|         twopi = 2.0 * M_PI; | |
|         for (i = 0;  i < TORUS_MINOR_RES;  i++) | |
|         { | |
|             glBegin(GL_QUAD_STRIP); | |
|             for (j = 0;  j <= TORUS_MAJOR_RES;  j++) | |
|             { | |
|                 for (k = 1;  k >= 0;  k--) | |
|                 { | |
|                     s = (i + k) % TORUS_MINOR_RES + 0.5; | |
|                     t = j % TORUS_MAJOR_RES; | |
| 
 | |
|                     // Calculate point on surface | |
|                     x = (TORUS_MAJOR + TORUS_MINOR * cos(s * twopi / TORUS_MINOR_RES)) * cos(t * twopi / TORUS_MAJOR_RES); | |
|                     y = TORUS_MINOR * sin(s * twopi / TORUS_MINOR_RES); | |
|                     z = (TORUS_MAJOR + TORUS_MINOR * cos(s * twopi / TORUS_MINOR_RES)) * sin(t * twopi / TORUS_MAJOR_RES); | |
| 
 | |
|                     // Calculate surface normal | |
|                     nx = x - TORUS_MAJOR * cos(t * twopi / TORUS_MAJOR_RES); | |
|                     ny = y; | |
|                     nz = z - TORUS_MAJOR * sin(t * twopi / TORUS_MAJOR_RES); | |
|                     scale = 1.0 / sqrt(nx*nx + ny*ny + nz*nz); | |
|                     nx *= scale; | |
|                     ny *= scale; | |
|                     nz *= scale; | |
| 
 | |
|                     glNormal3f((float) nx, (float) ny, (float) nz); | |
|                     glVertex3f((float) x, (float) y, (float) z); | |
|                 } | |
|             } | |
| 
 | |
|             glEnd(); | |
|         } | |
| 
 | |
|         // Stop recording displaylist | |
|         glEndList(); | |
|     } | |
|     else | |
|     { | |
|         // Playback displaylist | |
|         glCallList(torus_list); | |
|     } | |
| } | |
| 
 | |
| 
 | |
| //======================================================================== | |
| // Draw the scene (a rotating torus) | |
| //======================================================================== | |
|  | |
| static void drawScene(void) | |
| { | |
|     const GLfloat model_diffuse[4]  = {1.0f, 0.8f, 0.8f, 1.0f}; | |
|     const GLfloat model_specular[4] = {0.6f, 0.6f, 0.6f, 1.0f}; | |
|     const GLfloat model_shininess   = 20.0f; | |
| 
 | |
|     glPushMatrix(); | |
| 
 | |
|     // Rotate the object | |
|     glRotatef((GLfloat) rot_x * 0.5f, 1.0f, 0.0f, 0.0f); | |
|     glRotatef((GLfloat) rot_y * 0.5f, 0.0f, 1.0f, 0.0f); | |
|     glRotatef((GLfloat) rot_z * 0.5f, 0.0f, 0.0f, 1.0f); | |
| 
 | |
|     // Set model color (used for orthogonal views, lighting disabled) | |
|     glColor4fv(model_diffuse); | |
| 
 | |
|     // Set model material (used for perspective view, lighting enabled) | |
|     glMaterialfv(GL_FRONT, GL_DIFFUSE, model_diffuse); | |
|     glMaterialfv(GL_FRONT, GL_SPECULAR, model_specular); | |
|     glMaterialf(GL_FRONT, GL_SHININESS, model_shininess); | |
| 
 | |
|     // Draw torus | |
|     drawTorus(); | |
| 
 | |
|     glPopMatrix(); | |
| } | |
| 
 | |
| 
 | |
| //======================================================================== | |
| // Draw a 2D grid (used for orthogonal views) | |
| //======================================================================== | |
|  | |
| static void drawGrid(float scale, int steps) | |
| { | |
|     int i; | |
|     float x, y; | |
|     mat4x4 view; | |
| 
 | |
|     glPushMatrix(); | |
| 
 | |
|     // Set background to some dark bluish grey | |
|     glClearColor(0.05f, 0.05f, 0.2f, 0.0f); | |
|     glClear(GL_COLOR_BUFFER_BIT); | |
| 
 | |
|     // Setup modelview matrix (flat XY view) | |
|     { | |
|         vec3 eye = { 0.f, 0.f, 1.f }; | |
|         vec3 center = { 0.f, 0.f, 0.f }; | |
|         vec3 up = { 0.f, 1.f, 0.f }; | |
|         mat4x4_look_at(view, eye, center, up); | |
|     } | |
|     glLoadMatrixf((const GLfloat*) view); | |
| 
 | |
|     // We don't want to update the Z-buffer | |
|     glDepthMask(GL_FALSE); | |
| 
 | |
|     // Set grid color | |
|     glColor3f(0.0f, 0.5f, 0.5f); | |
| 
 | |
|     glBegin(GL_LINES); | |
| 
 | |
|     // Horizontal lines | |
|     x = scale * 0.5f * (float) (steps - 1); | |
|     y = -scale * 0.5f * (float) (steps - 1); | |
|     for (i = 0;  i < steps;  i++) | |
|     { | |
|         glVertex3f(-x, y, 0.0f); | |
|         glVertex3f(x, y, 0.0f); | |
|         y += scale; | |
|     } | |
| 
 | |
|     // Vertical lines | |
|     x = -scale * 0.5f * (float) (steps - 1); | |
|     y = scale * 0.5f * (float) (steps - 1); | |
|     for (i = 0;  i < steps;  i++) | |
|     { | |
|         glVertex3f(x, -y, 0.0f); | |
|         glVertex3f(x, y, 0.0f); | |
|         x += scale; | |
|     } | |
| 
 | |
|     glEnd(); | |
| 
 | |
|     // Enable Z-buffer writing again | |
|     glDepthMask(GL_TRUE); | |
| 
 | |
|     glPopMatrix(); | |
| } | |
| 
 | |
| 
 | |
| //======================================================================== | |
| // Draw all views | |
| //======================================================================== | |
|  | |
| static void drawAllViews(void) | |
| { | |
|     const GLfloat light_position[4] = {0.0f, 8.0f, 8.0f, 1.0f}; | |
|     const GLfloat light_diffuse[4]  = {1.0f, 1.0f, 1.0f, 1.0f}; | |
|     const GLfloat light_specular[4] = {1.0f, 1.0f, 1.0f, 1.0f}; | |
|     const GLfloat light_ambient[4]  = {0.2f, 0.2f, 0.3f, 1.0f}; | |
|     float aspect; | |
|     mat4x4 view, projection; | |
| 
 | |
|     // Calculate aspect of window | |
|     if (height > 0) | |
|         aspect = (float) width / (float) height; | |
|     else | |
|         aspect = 1.f; | |
| 
 | |
|     // Clear screen | |
|     glClearColor(0.0f, 0.0f, 0.0f, 0.0f); | |
|     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| 
 | |
|     // Enable scissor test | |
|     glEnable(GL_SCISSOR_TEST); | |
| 
 | |
|     // Enable depth test | |
|     glEnable(GL_DEPTH_TEST); | |
|     glDepthFunc(GL_LEQUAL); | |
| 
 | |
|     // ** ORTHOGONAL VIEWS ** | |
|  | |
|     // For orthogonal views, use wireframe rendering | |
|     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); | |
| 
 | |
|     // Enable line anti-aliasing | |
|     glEnable(GL_LINE_SMOOTH); | |
|     glEnable(GL_BLEND); | |
|     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 
 | |
|     // Setup orthogonal projection matrix | |
|     glMatrixMode(GL_PROJECTION); | |
|     glLoadIdentity(); | |
|     glOrtho(-3.0 * aspect, 3.0 * aspect, -3.0, 3.0, 1.0, 50.0); | |
| 
 | |
|     // Upper left view (TOP VIEW) | |
|     glViewport(0, height / 2, width / 2, height / 2); | |
|     glScissor(0, height / 2, width / 2, height / 2); | |
|     glMatrixMode(GL_MODELVIEW); | |
|     { | |
|         vec3 eye = { 0.f, 10.f, 1e-3f }; | |
|         vec3 center = { 0.f, 0.f, 0.f }; | |
|         vec3 up = { 0.f, 1.f, 0.f }; | |
|         mat4x4_look_at( view, eye, center, up ); | |
|     } | |
|     glLoadMatrixf((const GLfloat*) view); | |
|     drawGrid(0.5, 12); | |
|     drawScene(); | |
| 
 | |
|     // Lower left view (FRONT VIEW) | |
|     glViewport(0, 0, width / 2, height / 2); | |
|     glScissor(0, 0, width / 2, height / 2); | |
|     glMatrixMode(GL_MODELVIEW); | |
|     { | |
|         vec3 eye = { 0.f, 0.f, 10.f }; | |
|         vec3 center = { 0.f, 0.f, 0.f }; | |
|         vec3 up = { 0.f, 1.f, 0.f }; | |
|         mat4x4_look_at( view, eye, center, up ); | |
|     } | |
|     glLoadMatrixf((const GLfloat*) view); | |
|     drawGrid(0.5, 12); | |
|     drawScene(); | |
| 
 | |
|     // Lower right view (SIDE VIEW) | |
|     glViewport(width / 2, 0, width / 2, height / 2); | |
|     glScissor(width / 2, 0, width / 2, height / 2); | |
|     glMatrixMode(GL_MODELVIEW); | |
|     { | |
|         vec3 eye = { 10.f, 0.f, 0.f }; | |
|         vec3 center = { 0.f, 0.f, 0.f }; | |
|         vec3 up = { 0.f, 1.f, 0.f }; | |
|         mat4x4_look_at( view, eye, center, up ); | |
|     } | |
|     glLoadMatrixf((const GLfloat*) view); | |
|     drawGrid(0.5, 12); | |
|     drawScene(); | |
| 
 | |
|     // Disable line anti-aliasing | |
|     glDisable(GL_LINE_SMOOTH); | |
|     glDisable(GL_BLEND); | |
| 
 | |
|     // ** PERSPECTIVE VIEW ** | |
|  | |
|     // For perspective view, use solid rendering | |
|     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | |
| 
 | |
|     // Enable face culling (faster rendering) | |
|     glEnable(GL_CULL_FACE); | |
|     glCullFace(GL_BACK); | |
|     glFrontFace(GL_CW); | |
| 
 | |
|     // Setup perspective projection matrix | |
|     glMatrixMode(GL_PROJECTION); | |
|     mat4x4_perspective(projection, | |
|                        65.f * (float) M_PI / 180.f, | |
|                        aspect, | |
|                        1.f, 50.f); | |
|     glLoadMatrixf((const GLfloat*) projection); | |
| 
 | |
|     // Upper right view (PERSPECTIVE VIEW) | |
|     glViewport(width / 2, height / 2, width / 2, height / 2); | |
|     glScissor(width / 2, height / 2, width / 2, height / 2); | |
|     glMatrixMode(GL_MODELVIEW); | |
|     { | |
|         vec3 eye = { 3.f, 1.5f, 3.f }; | |
|         vec3 center = { 0.f, 0.f, 0.f }; | |
|         vec3 up = { 0.f, 1.f, 0.f }; | |
|         mat4x4_look_at( view, eye, center, up ); | |
|     } | |
|     glLoadMatrixf((const GLfloat*) view); | |
| 
 | |
|     // Configure and enable light source 1 | |
|     glLightfv(GL_LIGHT1, GL_POSITION, light_position); | |
|     glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); | |
|     glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); | |
|     glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); | |
|     glEnable(GL_LIGHT1); | |
|     glEnable(GL_LIGHTING); | |
| 
 | |
|     // Draw scene | |
|     drawScene(); | |
| 
 | |
|     // Disable lighting | |
|     glDisable(GL_LIGHTING); | |
| 
 | |
|     // Disable face culling | |
|     glDisable(GL_CULL_FACE); | |
| 
 | |
|     // Disable depth test | |
|     glDisable(GL_DEPTH_TEST); | |
| 
 | |
|     // Disable scissor test | |
|     glDisable(GL_SCISSOR_TEST); | |
| 
 | |
|     // Draw a border around the active view | |
|     if (active_view > 0 && active_view != 2) | |
|     { | |
|         glViewport(0, 0, width, height); | |
| 
 | |
|         glMatrixMode(GL_PROJECTION); | |
|         glLoadIdentity(); | |
|         glOrtho(0.0, 2.0, 0.0, 2.0, 0.0, 1.0); | |
| 
 | |
|         glMatrixMode(GL_MODELVIEW); | |
|         glLoadIdentity(); | |
|         glTranslatef((GLfloat) ((active_view - 1) & 1), (GLfloat) (1 - (active_view - 1) / 2), 0.0f); | |
| 
 | |
|         glColor3f(1.0f, 1.0f, 0.6f); | |
| 
 | |
|         glBegin(GL_LINE_STRIP); | |
|         glVertex2i(0, 0); | |
|         glVertex2i(1, 0); | |
|         glVertex2i(1, 1); | |
|         glVertex2i(0, 1); | |
|         glVertex2i(0, 0); | |
|         glEnd(); | |
|     } | |
| } | |
| 
 | |
| 
 | |
| //======================================================================== | |
| // Framebuffer size callback function | |
| //======================================================================== | |
|  | |
| static void framebufferSizeFun(GLFWwindow* window, int w, int h) | |
| { | |
|     width  = w; | |
|     height = h > 0 ? h : 1; | |
|     do_redraw = 1; | |
| } | |
| 
 | |
| 
 | |
| //======================================================================== | |
| // Window refresh callback function | |
| //======================================================================== | |
|  | |
| static void windowRefreshFun(GLFWwindow* window) | |
| { | |
|     drawAllViews(); | |
|     glfwSwapBuffers(window); | |
|     do_redraw = 0; | |
| } | |
| 
 | |
| 
 | |
| //======================================================================== | |
| // Mouse position callback function | |
| //======================================================================== | |
|  | |
| static void cursorPosFun(GLFWwindow* window, double x, double y) | |
| { | |
|     int wnd_width, wnd_height, fb_width, fb_height; | |
|     double scale; | |
| 
 | |
|     glfwGetWindowSize(window, &wnd_width, &wnd_height); | |
|     glfwGetFramebufferSize(window, &fb_width, &fb_height); | |
| 
 | |
|     scale = (double) fb_width / (double) wnd_width; | |
| 
 | |
|     x *= scale; | |
|     y *= scale; | |
| 
 | |
|     // Depending on which view was selected, rotate around different axes | |
|     switch (active_view) | |
|     { | |
|         case 1: | |
|             rot_x += (int) (y - ypos); | |
|             rot_z += (int) (x - xpos); | |
|             do_redraw = 1; | |
|             break; | |
|         case 3: | |
|             rot_x += (int) (y - ypos); | |
|             rot_y += (int) (x - xpos); | |
|             do_redraw = 1; | |
|             break; | |
|         case 4: | |
|             rot_y += (int) (x - xpos); | |
|             rot_z += (int) (y - ypos); | |
|             do_redraw = 1; | |
|             break; | |
|         default: | |
|             // Do nothing for perspective view, or if no view is selected | |
|             break; | |
|     } | |
| 
 | |
|     // Remember cursor position | |
|     xpos = x; | |
|     ypos = y; | |
| } | |
| 
 | |
| 
 | |
| //======================================================================== | |
| // Mouse button callback function | |
| //======================================================================== | |
|  | |
| static void mouseButtonFun(GLFWwindow* window, int button, int action, int mods) | |
| { | |
|     if ((button == GLFW_MOUSE_BUTTON_LEFT) && action == GLFW_PRESS) | |
|     { | |
|         // Detect which of the four views was clicked | |
|         active_view = 1; | |
|         if (xpos >= width / 2) | |
|             active_view += 1; | |
|         if (ypos >= height / 2) | |
|             active_view += 2; | |
|     } | |
|     else if (button == GLFW_MOUSE_BUTTON_LEFT) | |
|     { | |
|         // Deselect any previously selected view | |
|         active_view = 0; | |
|     } | |
| 
 | |
|     do_redraw = 1; | |
| } | |
| 
 | |
| static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) | |
| { | |
|     if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) | |
|         glfwSetWindowShouldClose(window, GLFW_TRUE); | |
| } | |
| 
 | |
| 
 | |
| //======================================================================== | |
| // main | |
| //======================================================================== | |
|  | |
| int main(void) | |
| { | |
|     GLFWwindow* window; | |
| 
 | |
|     // Initialise GLFW | |
|     if (!glfwInit()) | |
|     { | |
|         fprintf(stderr, "Failed to initialize GLFW\n"); | |
|         exit(EXIT_FAILURE); | |
|     } | |
| 
 | |
|     glfwWindowHint(GLFW_SAMPLES, 4); | |
| 
 | |
|     // Open OpenGL window | |
|     window = glfwCreateWindow(500, 500, "Split view demo", NULL, NULL); | |
|     if (!window) | |
|     { | |
|         fprintf(stderr, "Failed to open GLFW window\n"); | |
| 
 | |
|         glfwTerminate(); | |
|         exit(EXIT_FAILURE); | |
|     } | |
| 
 | |
|     // Set callback functions | |
|     glfwSetFramebufferSizeCallback(window, framebufferSizeFun); | |
|     glfwSetWindowRefreshCallback(window, windowRefreshFun); | |
|     glfwSetCursorPosCallback(window, cursorPosFun); | |
|     glfwSetMouseButtonCallback(window, mouseButtonFun); | |
|     glfwSetKeyCallback(window, key_callback); | |
| 
 | |
|     // Enable vsync | |
|     glfwMakeContextCurrent(window); | |
|     gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); | |
|     glfwSwapInterval(1); | |
| 
 | |
|     if (GLAD_GL_ARB_multisample || GLAD_GL_VERSION_1_3) | |
|         glEnable(GL_MULTISAMPLE_ARB); | |
| 
 | |
|     glfwGetFramebufferSize(window, &width, &height); | |
|     framebufferSizeFun(window, width, height); | |
| 
 | |
|     // Main loop | |
|     for (;;) | |
|     { | |
|         // Only redraw if we need to | |
|         if (do_redraw) | |
|             windowRefreshFun(window); | |
| 
 | |
|         // Wait for new events | |
|         glfwWaitEvents(); | |
| 
 | |
|         // Check if the window should be closed | |
|         if (glfwWindowShouldClose(window)) | |
|             break; | |
|     } | |
| 
 | |
|     // Close OpenGL window and terminate GLFW | |
|     glfwTerminate(); | |
| 
 | |
|     exit(EXIT_SUCCESS); | |
| } | |
| 
 | |
| 
 |