Merge commit 'a120e3f70101ebe90f92fe59436a37e6caf42adf' as 'deps/glfw'
This commit is contained in:
546
deps/glfw/examples/splitview.c
vendored
Normal file
546
deps/glfw/examples/splitview.c
vendored
Normal file
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user