1 /*
2 Copyright 2012-2016 David Robillard <http://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 /**
18 @file pugl_test.c A simple Pugl test that creates a top-level window.
19 */
20
21 #include <locale.h>
22 #include <math.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "pugl/gl.h"
27 #include "pugl/pugl.h"
28
29 static int quit = 0;
30 static float xAngle = 0.0f;
31 static float yAngle = 0.0f;
32 static float dist = 10.0f;
33
34 static const float cubeVertices[] = {
35 -1.0f, -1.0f, -1.0f,
36 -1.0f, -1.0f, 1.0f,
37 -1.0f, 1.0f, 1.0f,
38
39 1.0f, 1.0f, -1.0f,
40 -1.0f, -1.0f, -1.0f,
41 -1.0f, 1.0f, -1.0f,
42
43 1.0f, -1.0f, 1.0f,
44 -1.0f, -1.0f, -1.0f,
45 1.0f, -1.0f, -1.0f,
46
47 1.0f, 1.0f, -1.0f,
48 1.0f, -1.0f, -1.0f,
49 -1.0f, -1.0f, -1.0f,
50
51 -1.0f, -1.0f, -1.0f,
52 -1.0f, 1.0f, 1.0f,
53 -1.0f, 1.0f, -1.0f,
54
55 1.0f, -1.0f, 1.0f,
56 -1.0f, -1.0f, 1.0f,
57 -1.0f, -1.0f, -1.0f,
58
59 -1.0f, 1.0f, 1.0f,
60 -1.0f, -1.0f, 1.0f,
61 1.0f, -1.0f, 1.0f,
62
63 1.0f, 1.0f, 1.0f,
64 1.0f, -1.0f, -1.0f,
65 1.0f, 1.0f, -1.0f,
66
67 1.0f, -1.0f, -1.0f,
68 1.0f, 1.0f, 1.0f,
69 1.0f, -1.0f, 1.0f,
70
71 1.0f, 1.0f, 1.0f,
72 1.0f, 1.0f, -1.0f,
73 -1.0f, 1.0f, -1.0f,
74
75 1.0f, 1.0f, 1.0f,
76 -1.0f, 1.0f, -1.0f,
77 -1.0f, 1.0f, 1.0f,
78
79 1.0f, 1.0f, 1.0f,
80 -1.0f, 1.0f, 1.0f,
81 1.0f, -1.0f, 1.0f
82 };
83
84 /** Calculate a projection matrix for a given perspective. */
85 static void
perspective(float * m,float fov,float aspect,float zNear,float zFar)86 perspective(float* m, float fov, float aspect, float zNear, float zFar)
87 {
88 const float h = tan(fov);
89 const float w = h / aspect;
90 const float depth = zNear - zFar;
91 const float q = (zFar + zNear) / depth;
92 const float qn = 2 * zFar * zNear / depth;
93
94 m[0] = w; m[1] = 0; m[2] = 0; m[3] = 0;
95 m[4] = 0; m[5] = h; m[6] = 0; m[7] = 0;
96 m[8] = 0; m[9] = 0; m[10] = q; m[11] = -1;
97 m[12] = 0; m[13] = 0; m[14] = qn; m[15] = 0;
98 }
99
100 static void
onReshape(PuglView * view,int width,int height)101 onReshape(PuglView* view, int width, int height)
102 {
103 glMatrixMode(GL_PROJECTION);
104 glLoadIdentity();
105 glViewport(0, 0, width, height);
106
107 float projection[16];
108 perspective(projection, 1.8f, width / (float)height, 1.0, 100.0f);
109 glLoadMatrixf(projection);
110 }
111
112 static void
onDisplay(PuglView * view)113 onDisplay(PuglView* view)
114 {
115 glMatrixMode(GL_MODELVIEW);
116 glLoadIdentity();
117 glTranslatef(0.0f, 0.0f, dist * -1);
118 glRotatef(xAngle, 0.0f, 1.0f, 0.0f);
119 glRotatef(yAngle, 1.0f, 0.0f, 0.0f);
120
121 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
122 glEnableClientState(GL_VERTEX_ARRAY);
123 glEnableClientState(GL_COLOR_ARRAY);
124
125 glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
126 glColorPointer(3, GL_FLOAT, 0, cubeVertices);
127 glDrawArrays(GL_TRIANGLES, 0, 12 * 3);
128
129 glDisableClientState(GL_VERTEX_ARRAY);
130 glDisableClientState(GL_COLOR_ARRAY);
131 }
132
133 static void
printModifiers(PuglView * view,unsigned mods)134 printModifiers(PuglView* view, unsigned mods)
135 {
136 fprintf(stderr, "Modifiers:%s%s%s%s\n",
137 (mods & PUGL_MOD_SHIFT) ? " Shift" : "",
138 (mods & PUGL_MOD_CTRL) ? " Ctrl" : "",
139 (mods & PUGL_MOD_ALT) ? " Alt" : "",
140 (mods & PUGL_MOD_SUPER) ? " Super" : "");
141 }
142
143 static void
onEvent(PuglView * view,const PuglEvent * event)144 onEvent(PuglView* view, const PuglEvent* event)
145 {
146 switch (event->type) {
147 case PUGL_NOTHING:
148 break;
149 case PUGL_CONFIGURE:
150 onReshape(view, event->configure.width, event->configure.height);
151 break;
152 case PUGL_EXPOSE:
153 onDisplay(view);
154 break;
155 case PUGL_CLOSE:
156 quit = 1;
157 break;
158 case PUGL_KEY_PRESS:
159 fprintf(stderr, "Key %u (char %u) press (%s)%s\n",
160 event->key.keycode, event->key.character, event->key.utf8,
161 event->key.filter ? " (filtered)" : "");
162 if (event->key.character == 'q' ||
163 event->key.character == 'Q' ||
164 event->key.character == PUGL_CHAR_ESCAPE) {
165 quit = 1;
166 }
167 break;
168 case PUGL_KEY_RELEASE:
169 fprintf(stderr, "Key %u (char %u) release (%s)%s\n",
170 event->key.keycode, event->key.character, event->key.utf8,
171 event->key.filter ? " (filtered)" : "");
172 break;
173 case PUGL_MOTION_NOTIFY:
174 xAngle = -(int)event->motion.x % 360;
175 yAngle = (int)event->motion.y % 360;
176 puglPostRedisplay(view);
177 break;
178 case PUGL_BUTTON_PRESS:
179 case PUGL_BUTTON_RELEASE:
180 fprintf(stderr, "Mouse %d %s at %f,%f ",
181 event->button.button,
182 (event->type == PUGL_BUTTON_PRESS) ? "down" : "up",
183 event->button.x,
184 event->button.y);
185 printModifiers(view, event->scroll.state);
186 break;
187 case PUGL_SCROLL:
188 fprintf(stderr, "Scroll %f %f %f %f ",
189 event->scroll.x, event->scroll.y, event->scroll.dx, event->scroll.dy);
190 printModifiers(view, event->scroll.state);
191 dist += event->scroll.dy;
192 if (dist < 10.0f) {
193 dist = 10.0f;
194 }
195 puglPostRedisplay(view);
196 break;
197 case PUGL_ENTER_NOTIFY:
198 fprintf(stderr, "Entered\n");
199 break;
200 case PUGL_LEAVE_NOTIFY:
201 fprintf(stderr, "Exited\n");
202 break;
203 case PUGL_FOCUS_IN:
204 fprintf(stderr, "Focus in\n");
205 break;
206 case PUGL_FOCUS_OUT:
207 fprintf(stderr, "Focus out\n");
208 break;
209 }
210 }
211
212 int
main(int argc,char ** argv)213 main(int argc, char** argv)
214 {
215 bool ignoreKeyRepeat = false;
216 bool resizable = false;
217 for (int i = 1; i < argc; ++i) {
218 if (!strcmp(argv[i], "-h")) {
219 printf("USAGE: %s [OPTIONS]...\n\n"
220 " -h Display this help\n"
221 " -i Ignore key repeat\n"
222 " -r Resizable window\n", argv[0]);
223 return 0;
224 } else if (!strcmp(argv[i], "-i")) {
225 ignoreKeyRepeat = true;
226 } else if (!strcmp(argv[i], "-r")) {
227 resizable = true;
228 } else {
229 fprintf(stderr, "Unknown option: %s\n", argv[i]);
230 }
231 }
232
233 setlocale(LC_CTYPE, "");
234
235 PuglView* view = puglInit(NULL, NULL);
236 puglInitWindowClass(view, "PuglTest");
237 puglInitWindowSize(view, 512, 512);
238 puglInitWindowMinSize(view, 256, 256);
239 puglInitResizable(view, resizable);
240
241 puglIgnoreKeyRepeat(view, ignoreKeyRepeat);
242 puglSetEventFunc(view, onEvent);
243
244 puglCreateWindow(view, "Pugl Test");
245
246 puglEnterContext(view);
247 glEnable(GL_DEPTH_TEST);
248 glDepthFunc(GL_LESS);
249 glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
250 puglLeaveContext(view, false);
251
252 puglShowWindow(view);
253
254 while (!quit) {
255 puglWaitForEvent(view);
256 puglProcessEvents(view);
257 }
258
259 puglDestroy(view);
260 return 0;
261 }
262