|
|
- //========================================================================
- // 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);
- }
-
|