1b877906bSopenharmony_ci//======================================================================== 2b877906bSopenharmony_ci// This is an example program for the GLFW library 3b877906bSopenharmony_ci// 4b877906bSopenharmony_ci// The program uses a "split window" view, rendering four views of the 5b877906bSopenharmony_ci// same scene in one window (e.g. useful for 3D modelling software). This 6b877906bSopenharmony_ci// demo uses scissors to separate the four different rendering areas from 7b877906bSopenharmony_ci// each other. 8b877906bSopenharmony_ci// 9b877906bSopenharmony_ci// (If the code seems a little bit strange here and there, it may be 10b877906bSopenharmony_ci// because I am not a friend of orthogonal projections) 11b877906bSopenharmony_ci//======================================================================== 12b877906bSopenharmony_ci 13b877906bSopenharmony_ci#define GLAD_GL_IMPLEMENTATION 14b877906bSopenharmony_ci#include <glad/gl.h> 15b877906bSopenharmony_ci#define GLFW_INCLUDE_NONE 16b877906bSopenharmony_ci#include <GLFW/glfw3.h> 17b877906bSopenharmony_ci 18b877906bSopenharmony_ci#if defined(_MSC_VER) 19b877906bSopenharmony_ci // Make MS math.h define M_PI 20b877906bSopenharmony_ci #define _USE_MATH_DEFINES 21b877906bSopenharmony_ci#endif 22b877906bSopenharmony_ci 23b877906bSopenharmony_ci#include <math.h> 24b877906bSopenharmony_ci#include <stdio.h> 25b877906bSopenharmony_ci#include <stdlib.h> 26b877906bSopenharmony_ci 27b877906bSopenharmony_ci#include <linmath.h> 28b877906bSopenharmony_ci 29b877906bSopenharmony_ci 30b877906bSopenharmony_ci//======================================================================== 31b877906bSopenharmony_ci// Global variables 32b877906bSopenharmony_ci//======================================================================== 33b877906bSopenharmony_ci 34b877906bSopenharmony_ci// Mouse position 35b877906bSopenharmony_cistatic double xpos = 0, ypos = 0; 36b877906bSopenharmony_ci 37b877906bSopenharmony_ci// Window size 38b877906bSopenharmony_cistatic int width, height; 39b877906bSopenharmony_ci 40b877906bSopenharmony_ci// Active view: 0 = none, 1 = upper left, 2 = upper right, 3 = lower left, 41b877906bSopenharmony_ci// 4 = lower right 42b877906bSopenharmony_cistatic int active_view = 0; 43b877906bSopenharmony_ci 44b877906bSopenharmony_ci// Rotation around each axis 45b877906bSopenharmony_cistatic int rot_x = 0, rot_y = 0, rot_z = 0; 46b877906bSopenharmony_ci 47b877906bSopenharmony_ci// Do redraw? 48b877906bSopenharmony_cistatic int do_redraw = 1; 49b877906bSopenharmony_ci 50b877906bSopenharmony_ci 51b877906bSopenharmony_ci//======================================================================== 52b877906bSopenharmony_ci// Draw a solid torus (use a display list for the model) 53b877906bSopenharmony_ci//======================================================================== 54b877906bSopenharmony_ci 55b877906bSopenharmony_ci#define TORUS_MAJOR 1.5 56b877906bSopenharmony_ci#define TORUS_MINOR 0.5 57b877906bSopenharmony_ci#define TORUS_MAJOR_RES 32 58b877906bSopenharmony_ci#define TORUS_MINOR_RES 32 59b877906bSopenharmony_ci 60b877906bSopenharmony_cistatic void drawTorus(void) 61b877906bSopenharmony_ci{ 62b877906bSopenharmony_ci static GLuint torus_list = 0; 63b877906bSopenharmony_ci int i, j, k; 64b877906bSopenharmony_ci double s, t, x, y, z, nx, ny, nz, scale, twopi; 65b877906bSopenharmony_ci 66b877906bSopenharmony_ci if (!torus_list) 67b877906bSopenharmony_ci { 68b877906bSopenharmony_ci // Start recording displaylist 69b877906bSopenharmony_ci torus_list = glGenLists(1); 70b877906bSopenharmony_ci glNewList(torus_list, GL_COMPILE_AND_EXECUTE); 71b877906bSopenharmony_ci 72b877906bSopenharmony_ci // Draw torus 73b877906bSopenharmony_ci twopi = 2.0 * M_PI; 74b877906bSopenharmony_ci for (i = 0; i < TORUS_MINOR_RES; i++) 75b877906bSopenharmony_ci { 76b877906bSopenharmony_ci glBegin(GL_QUAD_STRIP); 77b877906bSopenharmony_ci for (j = 0; j <= TORUS_MAJOR_RES; j++) 78b877906bSopenharmony_ci { 79b877906bSopenharmony_ci for (k = 1; k >= 0; k--) 80b877906bSopenharmony_ci { 81b877906bSopenharmony_ci s = (i + k) % TORUS_MINOR_RES + 0.5; 82b877906bSopenharmony_ci t = j % TORUS_MAJOR_RES; 83b877906bSopenharmony_ci 84b877906bSopenharmony_ci // Calculate point on surface 85b877906bSopenharmony_ci x = (TORUS_MAJOR + TORUS_MINOR * cos(s * twopi / TORUS_MINOR_RES)) * cos(t * twopi / TORUS_MAJOR_RES); 86b877906bSopenharmony_ci y = TORUS_MINOR * sin(s * twopi / TORUS_MINOR_RES); 87b877906bSopenharmony_ci z = (TORUS_MAJOR + TORUS_MINOR * cos(s * twopi / TORUS_MINOR_RES)) * sin(t * twopi / TORUS_MAJOR_RES); 88b877906bSopenharmony_ci 89b877906bSopenharmony_ci // Calculate surface normal 90b877906bSopenharmony_ci nx = x - TORUS_MAJOR * cos(t * twopi / TORUS_MAJOR_RES); 91b877906bSopenharmony_ci ny = y; 92b877906bSopenharmony_ci nz = z - TORUS_MAJOR * sin(t * twopi / TORUS_MAJOR_RES); 93b877906bSopenharmony_ci scale = 1.0 / sqrt(nx*nx + ny*ny + nz*nz); 94b877906bSopenharmony_ci nx *= scale; 95b877906bSopenharmony_ci ny *= scale; 96b877906bSopenharmony_ci nz *= scale; 97b877906bSopenharmony_ci 98b877906bSopenharmony_ci glNormal3f((float) nx, (float) ny, (float) nz); 99b877906bSopenharmony_ci glVertex3f((float) x, (float) y, (float) z); 100b877906bSopenharmony_ci } 101b877906bSopenharmony_ci } 102b877906bSopenharmony_ci 103b877906bSopenharmony_ci glEnd(); 104b877906bSopenharmony_ci } 105b877906bSopenharmony_ci 106b877906bSopenharmony_ci // Stop recording displaylist 107b877906bSopenharmony_ci glEndList(); 108b877906bSopenharmony_ci } 109b877906bSopenharmony_ci else 110b877906bSopenharmony_ci { 111b877906bSopenharmony_ci // Playback displaylist 112b877906bSopenharmony_ci glCallList(torus_list); 113b877906bSopenharmony_ci } 114b877906bSopenharmony_ci} 115b877906bSopenharmony_ci 116b877906bSopenharmony_ci 117b877906bSopenharmony_ci//======================================================================== 118b877906bSopenharmony_ci// Draw the scene (a rotating torus) 119b877906bSopenharmony_ci//======================================================================== 120b877906bSopenharmony_ci 121b877906bSopenharmony_cistatic void drawScene(void) 122b877906bSopenharmony_ci{ 123b877906bSopenharmony_ci const GLfloat model_diffuse[4] = {1.0f, 0.8f, 0.8f, 1.0f}; 124b877906bSopenharmony_ci const GLfloat model_specular[4] = {0.6f, 0.6f, 0.6f, 1.0f}; 125b877906bSopenharmony_ci const GLfloat model_shininess = 20.0f; 126b877906bSopenharmony_ci 127b877906bSopenharmony_ci glPushMatrix(); 128b877906bSopenharmony_ci 129b877906bSopenharmony_ci // Rotate the object 130b877906bSopenharmony_ci glRotatef((GLfloat) rot_x * 0.5f, 1.0f, 0.0f, 0.0f); 131b877906bSopenharmony_ci glRotatef((GLfloat) rot_y * 0.5f, 0.0f, 1.0f, 0.0f); 132b877906bSopenharmony_ci glRotatef((GLfloat) rot_z * 0.5f, 0.0f, 0.0f, 1.0f); 133b877906bSopenharmony_ci 134b877906bSopenharmony_ci // Set model color (used for orthogonal views, lighting disabled) 135b877906bSopenharmony_ci glColor4fv(model_diffuse); 136b877906bSopenharmony_ci 137b877906bSopenharmony_ci // Set model material (used for perspective view, lighting enabled) 138b877906bSopenharmony_ci glMaterialfv(GL_FRONT, GL_DIFFUSE, model_diffuse); 139b877906bSopenharmony_ci glMaterialfv(GL_FRONT, GL_SPECULAR, model_specular); 140b877906bSopenharmony_ci glMaterialf(GL_FRONT, GL_SHININESS, model_shininess); 141b877906bSopenharmony_ci 142b877906bSopenharmony_ci // Draw torus 143b877906bSopenharmony_ci drawTorus(); 144b877906bSopenharmony_ci 145b877906bSopenharmony_ci glPopMatrix(); 146b877906bSopenharmony_ci} 147b877906bSopenharmony_ci 148b877906bSopenharmony_ci 149b877906bSopenharmony_ci//======================================================================== 150b877906bSopenharmony_ci// Draw a 2D grid (used for orthogonal views) 151b877906bSopenharmony_ci//======================================================================== 152b877906bSopenharmony_ci 153b877906bSopenharmony_cistatic void drawGrid(float scale, int steps) 154b877906bSopenharmony_ci{ 155b877906bSopenharmony_ci int i; 156b877906bSopenharmony_ci float x, y; 157b877906bSopenharmony_ci mat4x4 view; 158b877906bSopenharmony_ci 159b877906bSopenharmony_ci glPushMatrix(); 160b877906bSopenharmony_ci 161b877906bSopenharmony_ci // Set background to some dark bluish grey 162b877906bSopenharmony_ci glClearColor(0.05f, 0.05f, 0.2f, 0.0f); 163b877906bSopenharmony_ci glClear(GL_COLOR_BUFFER_BIT); 164b877906bSopenharmony_ci 165b877906bSopenharmony_ci // Setup modelview matrix (flat XY view) 166b877906bSopenharmony_ci { 167b877906bSopenharmony_ci vec3 eye = { 0.f, 0.f, 1.f }; 168b877906bSopenharmony_ci vec3 center = { 0.f, 0.f, 0.f }; 169b877906bSopenharmony_ci vec3 up = { 0.f, 1.f, 0.f }; 170b877906bSopenharmony_ci mat4x4_look_at(view, eye, center, up); 171b877906bSopenharmony_ci } 172b877906bSopenharmony_ci glLoadMatrixf((const GLfloat*) view); 173b877906bSopenharmony_ci 174b877906bSopenharmony_ci // We don't want to update the Z-buffer 175b877906bSopenharmony_ci glDepthMask(GL_FALSE); 176b877906bSopenharmony_ci 177b877906bSopenharmony_ci // Set grid color 178b877906bSopenharmony_ci glColor3f(0.0f, 0.5f, 0.5f); 179b877906bSopenharmony_ci 180b877906bSopenharmony_ci glBegin(GL_LINES); 181b877906bSopenharmony_ci 182b877906bSopenharmony_ci // Horizontal lines 183b877906bSopenharmony_ci x = scale * 0.5f * (float) (steps - 1); 184b877906bSopenharmony_ci y = -scale * 0.5f * (float) (steps - 1); 185b877906bSopenharmony_ci for (i = 0; i < steps; i++) 186b877906bSopenharmony_ci { 187b877906bSopenharmony_ci glVertex3f(-x, y, 0.0f); 188b877906bSopenharmony_ci glVertex3f(x, y, 0.0f); 189b877906bSopenharmony_ci y += scale; 190b877906bSopenharmony_ci } 191b877906bSopenharmony_ci 192b877906bSopenharmony_ci // Vertical lines 193b877906bSopenharmony_ci x = -scale * 0.5f * (float) (steps - 1); 194b877906bSopenharmony_ci y = scale * 0.5f * (float) (steps - 1); 195b877906bSopenharmony_ci for (i = 0; i < steps; i++) 196b877906bSopenharmony_ci { 197b877906bSopenharmony_ci glVertex3f(x, -y, 0.0f); 198b877906bSopenharmony_ci glVertex3f(x, y, 0.0f); 199b877906bSopenharmony_ci x += scale; 200b877906bSopenharmony_ci } 201b877906bSopenharmony_ci 202b877906bSopenharmony_ci glEnd(); 203b877906bSopenharmony_ci 204b877906bSopenharmony_ci // Enable Z-buffer writing again 205b877906bSopenharmony_ci glDepthMask(GL_TRUE); 206b877906bSopenharmony_ci 207b877906bSopenharmony_ci glPopMatrix(); 208b877906bSopenharmony_ci} 209b877906bSopenharmony_ci 210b877906bSopenharmony_ci 211b877906bSopenharmony_ci//======================================================================== 212b877906bSopenharmony_ci// Draw all views 213b877906bSopenharmony_ci//======================================================================== 214b877906bSopenharmony_ci 215b877906bSopenharmony_cistatic void drawAllViews(void) 216b877906bSopenharmony_ci{ 217b877906bSopenharmony_ci const GLfloat light_position[4] = {0.0f, 8.0f, 8.0f, 1.0f}; 218b877906bSopenharmony_ci const GLfloat light_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f}; 219b877906bSopenharmony_ci const GLfloat light_specular[4] = {1.0f, 1.0f, 1.0f, 1.0f}; 220b877906bSopenharmony_ci const GLfloat light_ambient[4] = {0.2f, 0.2f, 0.3f, 1.0f}; 221b877906bSopenharmony_ci float aspect; 222b877906bSopenharmony_ci mat4x4 view, projection; 223b877906bSopenharmony_ci 224b877906bSopenharmony_ci // Calculate aspect of window 225b877906bSopenharmony_ci if (height > 0) 226b877906bSopenharmony_ci aspect = (float) width / (float) height; 227b877906bSopenharmony_ci else 228b877906bSopenharmony_ci aspect = 1.f; 229b877906bSopenharmony_ci 230b877906bSopenharmony_ci // Clear screen 231b877906bSopenharmony_ci glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 232b877906bSopenharmony_ci glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 233b877906bSopenharmony_ci 234b877906bSopenharmony_ci // Enable scissor test 235b877906bSopenharmony_ci glEnable(GL_SCISSOR_TEST); 236b877906bSopenharmony_ci 237b877906bSopenharmony_ci // Enable depth test 238b877906bSopenharmony_ci glEnable(GL_DEPTH_TEST); 239b877906bSopenharmony_ci glDepthFunc(GL_LEQUAL); 240b877906bSopenharmony_ci 241b877906bSopenharmony_ci // ** ORTHOGONAL VIEWS ** 242b877906bSopenharmony_ci 243b877906bSopenharmony_ci // For orthogonal views, use wireframe rendering 244b877906bSopenharmony_ci glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 245b877906bSopenharmony_ci 246b877906bSopenharmony_ci // Enable line anti-aliasing 247b877906bSopenharmony_ci glEnable(GL_LINE_SMOOTH); 248b877906bSopenharmony_ci glEnable(GL_BLEND); 249b877906bSopenharmony_ci glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 250b877906bSopenharmony_ci 251b877906bSopenharmony_ci // Setup orthogonal projection matrix 252b877906bSopenharmony_ci glMatrixMode(GL_PROJECTION); 253b877906bSopenharmony_ci glLoadIdentity(); 254b877906bSopenharmony_ci glOrtho(-3.0 * aspect, 3.0 * aspect, -3.0, 3.0, 1.0, 50.0); 255b877906bSopenharmony_ci 256b877906bSopenharmony_ci // Upper left view (TOP VIEW) 257b877906bSopenharmony_ci glViewport(0, height / 2, width / 2, height / 2); 258b877906bSopenharmony_ci glScissor(0, height / 2, width / 2, height / 2); 259b877906bSopenharmony_ci glMatrixMode(GL_MODELVIEW); 260b877906bSopenharmony_ci { 261b877906bSopenharmony_ci vec3 eye = { 0.f, 10.f, 1e-3f }; 262b877906bSopenharmony_ci vec3 center = { 0.f, 0.f, 0.f }; 263b877906bSopenharmony_ci vec3 up = { 0.f, 1.f, 0.f }; 264b877906bSopenharmony_ci mat4x4_look_at( view, eye, center, up ); 265b877906bSopenharmony_ci } 266b877906bSopenharmony_ci glLoadMatrixf((const GLfloat*) view); 267b877906bSopenharmony_ci drawGrid(0.5, 12); 268b877906bSopenharmony_ci drawScene(); 269b877906bSopenharmony_ci 270b877906bSopenharmony_ci // Lower left view (FRONT VIEW) 271b877906bSopenharmony_ci glViewport(0, 0, width / 2, height / 2); 272b877906bSopenharmony_ci glScissor(0, 0, width / 2, height / 2); 273b877906bSopenharmony_ci glMatrixMode(GL_MODELVIEW); 274b877906bSopenharmony_ci { 275b877906bSopenharmony_ci vec3 eye = { 0.f, 0.f, 10.f }; 276b877906bSopenharmony_ci vec3 center = { 0.f, 0.f, 0.f }; 277b877906bSopenharmony_ci vec3 up = { 0.f, 1.f, 0.f }; 278b877906bSopenharmony_ci mat4x4_look_at( view, eye, center, up ); 279b877906bSopenharmony_ci } 280b877906bSopenharmony_ci glLoadMatrixf((const GLfloat*) view); 281b877906bSopenharmony_ci drawGrid(0.5, 12); 282b877906bSopenharmony_ci drawScene(); 283b877906bSopenharmony_ci 284b877906bSopenharmony_ci // Lower right view (SIDE VIEW) 285b877906bSopenharmony_ci glViewport(width / 2, 0, width / 2, height / 2); 286b877906bSopenharmony_ci glScissor(width / 2, 0, width / 2, height / 2); 287b877906bSopenharmony_ci glMatrixMode(GL_MODELVIEW); 288b877906bSopenharmony_ci { 289b877906bSopenharmony_ci vec3 eye = { 10.f, 0.f, 0.f }; 290b877906bSopenharmony_ci vec3 center = { 0.f, 0.f, 0.f }; 291b877906bSopenharmony_ci vec3 up = { 0.f, 1.f, 0.f }; 292b877906bSopenharmony_ci mat4x4_look_at( view, eye, center, up ); 293b877906bSopenharmony_ci } 294b877906bSopenharmony_ci glLoadMatrixf((const GLfloat*) view); 295b877906bSopenharmony_ci drawGrid(0.5, 12); 296b877906bSopenharmony_ci drawScene(); 297b877906bSopenharmony_ci 298b877906bSopenharmony_ci // Disable line anti-aliasing 299b877906bSopenharmony_ci glDisable(GL_LINE_SMOOTH); 300b877906bSopenharmony_ci glDisable(GL_BLEND); 301b877906bSopenharmony_ci 302b877906bSopenharmony_ci // ** PERSPECTIVE VIEW ** 303b877906bSopenharmony_ci 304b877906bSopenharmony_ci // For perspective view, use solid rendering 305b877906bSopenharmony_ci glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 306b877906bSopenharmony_ci 307b877906bSopenharmony_ci // Enable face culling (faster rendering) 308b877906bSopenharmony_ci glEnable(GL_CULL_FACE); 309b877906bSopenharmony_ci glCullFace(GL_BACK); 310b877906bSopenharmony_ci glFrontFace(GL_CW); 311b877906bSopenharmony_ci 312b877906bSopenharmony_ci // Setup perspective projection matrix 313b877906bSopenharmony_ci glMatrixMode(GL_PROJECTION); 314b877906bSopenharmony_ci mat4x4_perspective(projection, 315b877906bSopenharmony_ci 65.f * (float) M_PI / 180.f, 316b877906bSopenharmony_ci aspect, 317b877906bSopenharmony_ci 1.f, 50.f); 318b877906bSopenharmony_ci glLoadMatrixf((const GLfloat*) projection); 319b877906bSopenharmony_ci 320b877906bSopenharmony_ci // Upper right view (PERSPECTIVE VIEW) 321b877906bSopenharmony_ci glViewport(width / 2, height / 2, width / 2, height / 2); 322b877906bSopenharmony_ci glScissor(width / 2, height / 2, width / 2, height / 2); 323b877906bSopenharmony_ci glMatrixMode(GL_MODELVIEW); 324b877906bSopenharmony_ci { 325b877906bSopenharmony_ci vec3 eye = { 3.f, 1.5f, 3.f }; 326b877906bSopenharmony_ci vec3 center = { 0.f, 0.f, 0.f }; 327b877906bSopenharmony_ci vec3 up = { 0.f, 1.f, 0.f }; 328b877906bSopenharmony_ci mat4x4_look_at( view, eye, center, up ); 329b877906bSopenharmony_ci } 330b877906bSopenharmony_ci glLoadMatrixf((const GLfloat*) view); 331b877906bSopenharmony_ci 332b877906bSopenharmony_ci // Configure and enable light source 1 333b877906bSopenharmony_ci glLightfv(GL_LIGHT1, GL_POSITION, light_position); 334b877906bSopenharmony_ci glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); 335b877906bSopenharmony_ci glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); 336b877906bSopenharmony_ci glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); 337b877906bSopenharmony_ci glEnable(GL_LIGHT1); 338b877906bSopenharmony_ci glEnable(GL_LIGHTING); 339b877906bSopenharmony_ci 340b877906bSopenharmony_ci // Draw scene 341b877906bSopenharmony_ci drawScene(); 342b877906bSopenharmony_ci 343b877906bSopenharmony_ci // Disable lighting 344b877906bSopenharmony_ci glDisable(GL_LIGHTING); 345b877906bSopenharmony_ci 346b877906bSopenharmony_ci // Disable face culling 347b877906bSopenharmony_ci glDisable(GL_CULL_FACE); 348b877906bSopenharmony_ci 349b877906bSopenharmony_ci // Disable depth test 350b877906bSopenharmony_ci glDisable(GL_DEPTH_TEST); 351b877906bSopenharmony_ci 352b877906bSopenharmony_ci // Disable scissor test 353b877906bSopenharmony_ci glDisable(GL_SCISSOR_TEST); 354b877906bSopenharmony_ci 355b877906bSopenharmony_ci // Draw a border around the active view 356b877906bSopenharmony_ci if (active_view > 0 && active_view != 2) 357b877906bSopenharmony_ci { 358b877906bSopenharmony_ci glViewport(0, 0, width, height); 359b877906bSopenharmony_ci 360b877906bSopenharmony_ci glMatrixMode(GL_PROJECTION); 361b877906bSopenharmony_ci glLoadIdentity(); 362b877906bSopenharmony_ci glOrtho(0.0, 2.0, 0.0, 2.0, 0.0, 1.0); 363b877906bSopenharmony_ci 364b877906bSopenharmony_ci glMatrixMode(GL_MODELVIEW); 365b877906bSopenharmony_ci glLoadIdentity(); 366b877906bSopenharmony_ci glTranslatef((GLfloat) ((active_view - 1) & 1), (GLfloat) (1 - (active_view - 1) / 2), 0.0f); 367b877906bSopenharmony_ci 368b877906bSopenharmony_ci glColor3f(1.0f, 1.0f, 0.6f); 369b877906bSopenharmony_ci 370b877906bSopenharmony_ci glBegin(GL_LINE_STRIP); 371b877906bSopenharmony_ci glVertex2i(0, 0); 372b877906bSopenharmony_ci glVertex2i(1, 0); 373b877906bSopenharmony_ci glVertex2i(1, 1); 374b877906bSopenharmony_ci glVertex2i(0, 1); 375b877906bSopenharmony_ci glVertex2i(0, 0); 376b877906bSopenharmony_ci glEnd(); 377b877906bSopenharmony_ci } 378b877906bSopenharmony_ci} 379b877906bSopenharmony_ci 380b877906bSopenharmony_ci 381b877906bSopenharmony_ci//======================================================================== 382b877906bSopenharmony_ci// Framebuffer size callback function 383b877906bSopenharmony_ci//======================================================================== 384b877906bSopenharmony_ci 385b877906bSopenharmony_cistatic void framebufferSizeFun(GLFWwindow* window, int w, int h) 386b877906bSopenharmony_ci{ 387b877906bSopenharmony_ci width = w; 388b877906bSopenharmony_ci height = h > 0 ? h : 1; 389b877906bSopenharmony_ci do_redraw = 1; 390b877906bSopenharmony_ci} 391b877906bSopenharmony_ci 392b877906bSopenharmony_ci 393b877906bSopenharmony_ci//======================================================================== 394b877906bSopenharmony_ci// Window refresh callback function 395b877906bSopenharmony_ci//======================================================================== 396b877906bSopenharmony_ci 397b877906bSopenharmony_cistatic void windowRefreshFun(GLFWwindow* window) 398b877906bSopenharmony_ci{ 399b877906bSopenharmony_ci drawAllViews(); 400b877906bSopenharmony_ci glfwSwapBuffers(window); 401b877906bSopenharmony_ci do_redraw = 0; 402b877906bSopenharmony_ci} 403b877906bSopenharmony_ci 404b877906bSopenharmony_ci 405b877906bSopenharmony_ci//======================================================================== 406b877906bSopenharmony_ci// Mouse position callback function 407b877906bSopenharmony_ci//======================================================================== 408b877906bSopenharmony_ci 409b877906bSopenharmony_cistatic void cursorPosFun(GLFWwindow* window, double x, double y) 410b877906bSopenharmony_ci{ 411b877906bSopenharmony_ci int wnd_width, wnd_height, fb_width, fb_height; 412b877906bSopenharmony_ci double scale; 413b877906bSopenharmony_ci 414b877906bSopenharmony_ci glfwGetWindowSize(window, &wnd_width, &wnd_height); 415b877906bSopenharmony_ci glfwGetFramebufferSize(window, &fb_width, &fb_height); 416b877906bSopenharmony_ci 417b877906bSopenharmony_ci scale = (double) fb_width / (double) wnd_width; 418b877906bSopenharmony_ci 419b877906bSopenharmony_ci x *= scale; 420b877906bSopenharmony_ci y *= scale; 421b877906bSopenharmony_ci 422b877906bSopenharmony_ci // Depending on which view was selected, rotate around different axes 423b877906bSopenharmony_ci switch (active_view) 424b877906bSopenharmony_ci { 425b877906bSopenharmony_ci case 1: 426b877906bSopenharmony_ci rot_x += (int) (y - ypos); 427b877906bSopenharmony_ci rot_z += (int) (x - xpos); 428b877906bSopenharmony_ci do_redraw = 1; 429b877906bSopenharmony_ci break; 430b877906bSopenharmony_ci case 3: 431b877906bSopenharmony_ci rot_x += (int) (y - ypos); 432b877906bSopenharmony_ci rot_y += (int) (x - xpos); 433b877906bSopenharmony_ci do_redraw = 1; 434b877906bSopenharmony_ci break; 435b877906bSopenharmony_ci case 4: 436b877906bSopenharmony_ci rot_y += (int) (x - xpos); 437b877906bSopenharmony_ci rot_z += (int) (y - ypos); 438b877906bSopenharmony_ci do_redraw = 1; 439b877906bSopenharmony_ci break; 440b877906bSopenharmony_ci default: 441b877906bSopenharmony_ci // Do nothing for perspective view, or if no view is selected 442b877906bSopenharmony_ci break; 443b877906bSopenharmony_ci } 444b877906bSopenharmony_ci 445b877906bSopenharmony_ci // Remember cursor position 446b877906bSopenharmony_ci xpos = x; 447b877906bSopenharmony_ci ypos = y; 448b877906bSopenharmony_ci} 449b877906bSopenharmony_ci 450b877906bSopenharmony_ci 451b877906bSopenharmony_ci//======================================================================== 452b877906bSopenharmony_ci// Mouse button callback function 453b877906bSopenharmony_ci//======================================================================== 454b877906bSopenharmony_ci 455b877906bSopenharmony_cistatic void mouseButtonFun(GLFWwindow* window, int button, int action, int mods) 456b877906bSopenharmony_ci{ 457b877906bSopenharmony_ci if ((button == GLFW_MOUSE_BUTTON_LEFT) && action == GLFW_PRESS) 458b877906bSopenharmony_ci { 459b877906bSopenharmony_ci // Detect which of the four views was clicked 460b877906bSopenharmony_ci active_view = 1; 461b877906bSopenharmony_ci if (xpos >= width / 2) 462b877906bSopenharmony_ci active_view += 1; 463b877906bSopenharmony_ci if (ypos >= height / 2) 464b877906bSopenharmony_ci active_view += 2; 465b877906bSopenharmony_ci } 466b877906bSopenharmony_ci else if (button == GLFW_MOUSE_BUTTON_LEFT) 467b877906bSopenharmony_ci { 468b877906bSopenharmony_ci // Deselect any previously selected view 469b877906bSopenharmony_ci active_view = 0; 470b877906bSopenharmony_ci } 471b877906bSopenharmony_ci 472b877906bSopenharmony_ci do_redraw = 1; 473b877906bSopenharmony_ci} 474b877906bSopenharmony_ci 475b877906bSopenharmony_cistatic void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) 476b877906bSopenharmony_ci{ 477b877906bSopenharmony_ci if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) 478b877906bSopenharmony_ci glfwSetWindowShouldClose(window, GLFW_TRUE); 479b877906bSopenharmony_ci} 480b877906bSopenharmony_ci 481b877906bSopenharmony_ci 482b877906bSopenharmony_ci//======================================================================== 483b877906bSopenharmony_ci// main 484b877906bSopenharmony_ci//======================================================================== 485b877906bSopenharmony_ci 486b877906bSopenharmony_ciint main(void) 487b877906bSopenharmony_ci{ 488b877906bSopenharmony_ci GLFWwindow* window; 489b877906bSopenharmony_ci 490b877906bSopenharmony_ci // Initialise GLFW 491b877906bSopenharmony_ci if (!glfwInit()) 492b877906bSopenharmony_ci { 493b877906bSopenharmony_ci fprintf(stderr, "Failed to initialize GLFW\n"); 494b877906bSopenharmony_ci exit(EXIT_FAILURE); 495b877906bSopenharmony_ci } 496b877906bSopenharmony_ci 497b877906bSopenharmony_ci glfwWindowHint(GLFW_SAMPLES, 4); 498b877906bSopenharmony_ci 499b877906bSopenharmony_ci // Open OpenGL window 500b877906bSopenharmony_ci window = glfwCreateWindow(500, 500, "Split view demo", NULL, NULL); 501b877906bSopenharmony_ci if (!window) 502b877906bSopenharmony_ci { 503b877906bSopenharmony_ci fprintf(stderr, "Failed to open GLFW window\n"); 504b877906bSopenharmony_ci 505b877906bSopenharmony_ci glfwTerminate(); 506b877906bSopenharmony_ci exit(EXIT_FAILURE); 507b877906bSopenharmony_ci } 508b877906bSopenharmony_ci 509b877906bSopenharmony_ci // Set callback functions 510b877906bSopenharmony_ci glfwSetFramebufferSizeCallback(window, framebufferSizeFun); 511b877906bSopenharmony_ci glfwSetWindowRefreshCallback(window, windowRefreshFun); 512b877906bSopenharmony_ci glfwSetCursorPosCallback(window, cursorPosFun); 513b877906bSopenharmony_ci glfwSetMouseButtonCallback(window, mouseButtonFun); 514b877906bSopenharmony_ci glfwSetKeyCallback(window, key_callback); 515b877906bSopenharmony_ci 516b877906bSopenharmony_ci // Enable vsync 517b877906bSopenharmony_ci glfwMakeContextCurrent(window); 518b877906bSopenharmony_ci gladLoadGL(glfwGetProcAddress); 519b877906bSopenharmony_ci glfwSwapInterval(1); 520b877906bSopenharmony_ci 521b877906bSopenharmony_ci if (GLAD_GL_ARB_multisample || GLAD_GL_VERSION_1_3) 522b877906bSopenharmony_ci glEnable(GL_MULTISAMPLE_ARB); 523b877906bSopenharmony_ci 524b877906bSopenharmony_ci glfwGetFramebufferSize(window, &width, &height); 525b877906bSopenharmony_ci framebufferSizeFun(window, width, height); 526b877906bSopenharmony_ci 527b877906bSopenharmony_ci // Main loop 528b877906bSopenharmony_ci for (;;) 529b877906bSopenharmony_ci { 530b877906bSopenharmony_ci // Only redraw if we need to 531b877906bSopenharmony_ci if (do_redraw) 532b877906bSopenharmony_ci windowRefreshFun(window); 533b877906bSopenharmony_ci 534b877906bSopenharmony_ci // Wait for new events 535b877906bSopenharmony_ci glfwWaitEvents(); 536b877906bSopenharmony_ci 537b877906bSopenharmony_ci // Check if the window should be closed 538b877906bSopenharmony_ci if (glfwWindowShouldClose(window)) 539b877906bSopenharmony_ci break; 540b877906bSopenharmony_ci } 541b877906bSopenharmony_ci 542b877906bSopenharmony_ci // Close OpenGL window and terminate GLFW 543b877906bSopenharmony_ci glfwTerminate(); 544b877906bSopenharmony_ci 545b877906bSopenharmony_ci exit(EXIT_SUCCESS); 546b877906bSopenharmony_ci} 547b877906bSopenharmony_ci 548