summaryrefslogtreecommitdiff
path: root/libs/glfw-3.3.8/examples/splitview.c
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2022-08-23 13:38:27 -0500
committersanine <sanine.not@pm.me>2022-08-23 13:38:27 -0500
commit3afbf2a13b2dada445fb667bf25600407fea480a (patch)
tree551329e6f74fc9f177616de0d6739e8b5331ae96 /libs/glfw-3.3.8/examples/splitview.c
parent261e3f991221fbad6bbf262f5e65b773e4b6c73e (diff)
parent25ed7eb9f84e9a822f698ad803901fbb2a5354cf (diff)
:wMerge branch 'gl-window' into main
Diffstat (limited to 'libs/glfw-3.3.8/examples/splitview.c')
-rw-r--r--libs/glfw-3.3.8/examples/splitview.c546
1 files changed, 546 insertions, 0 deletions
diff --git a/libs/glfw-3.3.8/examples/splitview.c b/libs/glfw-3.3.8/examples/splitview.c
new file mode 100644
index 0000000..079c2cb
--- /dev/null
+++ b/libs/glfw-3.3.8/examples/splitview.c
@@ -0,0 +1,546 @@
+//========================================================================
+// 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. useful for 3D modelling software). This
+// demo uses scissors to separate 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/gl.h>
+#define GLFW_INCLUDE_NONE
+#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);
+ gladLoadGL(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);
+}
+