1 /* 2 Copyright 2012-2020 David Robillard <d@drobilla.net> 3 4 Permission to use, copy, modify, and/or distribute this software for any 5 purpose with or without fee is hereby granted, provided that the above 6 copyright notice and this permission notice appear in all copies. 7 8 THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "test/test_utils.h" 18 19 #include "pugl/gl.h" 20 #include "pugl/pugl.h" 21 22 #include <stdbool.h> 23 24 static const int N_CURSORS = 7; 25 static const int N_ROWS = 2; 26 static const int N_COLS = 4; 27 28 typedef struct { 29 PuglWorld* world; 30 PuglTestOptions opts; 31 bool quit; 32 } PuglTestApp; 33 34 static void 35 onConfigure(const double width, const double height) 36 { 37 glEnable(GL_DEPTH_TEST); 38 glDepthFunc(GL_LESS); 39 glClearColor(0.2f, 0.2f, 0.2f, 1.0f); 40 41 glMatrixMode(GL_PROJECTION); 42 glLoadIdentity(); 43 glViewport(0, 0, (int)width, (int)height); 44 } 45 46 static void 47 onExpose(void) 48 { 49 glMatrixMode(GL_MODELVIEW); 50 glLoadIdentity(); 51 52 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 53 glColor3f(0.6f, 0.6f, 0.6f); 54 55 for (int row = 1; row < N_ROWS; ++row) { 56 const float y = (float)row * (2.0f / (float)N_ROWS) - 1.0f; 57 glBegin(GL_LINES); 58 glVertex2f(-1.0f, y); 59 glVertex2f(1.0f, y); 60 glEnd(); 61 } 62 63 for (int col = 1; col < N_COLS; ++col) { 64 const float x = (float)col * (2.0f / (float)N_COLS) - 1.0f; 65 glBegin(GL_LINES); 66 glVertex2f(x, -1.0f); 67 glVertex2f(x, 1.0f); 68 glEnd(); 69 } 70 } 71 72 static void 73 onMotion(PuglView* view, double x, double y) 74 { 75 const PuglRect frame = puglGetFrame(view); 76 int row = (int)(y * N_ROWS / frame.height); 77 int col = (int)(x * N_COLS / frame.width); 78 79 row = (row < 0) ? 0 : (row >= N_ROWS) ? (N_ROWS - 1) : row; 80 col = (col < 0) ? 0 : (col >= N_COLS) ? (N_COLS - 1) : col; 81 82 const PuglCursor cursor = (PuglCursor)((row * N_COLS + col) % N_CURSORS); 83 puglSetCursor(view, cursor); 84 } 85 86 static PuglStatus 87 onEvent(PuglView* view, const PuglEvent* event) 88 { 89 PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); 90 91 printEvent(event, "Event: ", app->opts.verbose); 92 93 switch (event->type) { 94 case PUGL_CONFIGURE: 95 onConfigure(event->configure.width, event->configure.height); 96 break; 97 case PUGL_KEY_PRESS: 98 if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { 99 app->quit = 1; 100 } 101 break; 102 case PUGL_MOTION: 103 onMotion(view, event->motion.x, event->motion.y); 104 break; 105 case PUGL_EXPOSE: 106 onExpose(); 107 break; 108 case PUGL_POINTER_OUT: 109 puglSetCursor(view, PUGL_CURSOR_ARROW); 110 break; 111 case PUGL_CLOSE: 112 app->quit = 1; 113 break; 114 default: 115 break; 116 } 117 118 return PUGL_SUCCESS; 119 } 120 121 int 122 main(int argc, char** argv) 123 { 124 PuglTestApp app = {0}; 125 126 app.opts = puglParseTestOptions(&argc, &argv); 127 if (app.opts.help) { 128 puglPrintTestUsage(argv[0], ""); 129 return 1; 130 } 131 132 app.world = puglNewWorld(PUGL_PROGRAM, 0); 133 134 puglSetWorldHandle(app.world, &app); 135 puglSetClassName(app.world, "Pugl Test"); 136 137 PuglView* view = puglNewView(app.world); 138 139 puglSetWindowTitle(view, "Pugl Window Demo"); 140 puglSetDefaultSize(view, 512, 256); 141 puglSetMinSize(view, 128, 64); 142 puglSetMaxSize(view, 512, 256); 143 puglSetBackend(view, puglGlBackend()); 144 145 puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, app.opts.errorChecking); 146 puglSetViewHint(view, PUGL_RESIZABLE, app.opts.resizable); 147 puglSetViewHint(view, PUGL_SAMPLES, app.opts.samples); 148 puglSetViewHint(view, PUGL_DOUBLE_BUFFER, app.opts.doubleBuffer); 149 puglSetViewHint(view, PUGL_SWAP_INTERVAL, app.opts.sync); 150 puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, app.opts.ignoreKeyRepeat); 151 puglSetHandle(view, &app); 152 puglSetEventFunc(view, onEvent); 153 154 const PuglStatus st = puglRealize(view); 155 if (st) { 156 return logError("Failed to create window (%s)\n", puglStrerror(st)); 157 } 158 159 puglShow(view); 160 161 while (!app.quit) { 162 puglUpdate(app.world, -1.0); 163 } 164 165 puglFreeView(view); 166 puglFreeWorld(app.world); 167 168 return 0; 169 } 170