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