1#include <stdio.h>
2#include <math.h>
3
4#include <allegro.h>
5#include <alleggl.h>
6#ifdef ALLEGRO_MACOSX
7#include <OpenGL/glu.h>
8#else
9#include <GL/glu.h>
10#endif
11
12
13/* Define M_PI in case the compiler doesn't */
14#ifndef M_PI
15 #define M_PI 3.1415926535897932384626433832795
16#endif
17
18GLuint SlateTex
;
19
20
21/* Define a 3D vector type */
22typedef struct VECTOR
{
23 float x, y, z
;
24} VECTOR
;
25
26
27/* display a nice 12x12 chessboard grid */
28#define GRID_SIZE 12
29
30
31
32/* Parameters controlling the camera and projection state */
33int viewport_w
= 320; /* Viewport Width (pixels) */
34int viewport_h
= 240; /* Viewport Height (pixels) */
35int fov
= 48; /* Field of view (degrees) */
36float aspect
= 1; /* Aspect ratio */
37
38/* Define the camera
39 * We need: One position vector, and one orientation QUAT
40 */
41struct CAMERA
{
42 VECTOR position
;
43 QUAT orientation
;
44} camera
;
45
46
47
48/* A simple font to display some info on screen */
49FONT *agl_font
;
50
51
52
53/* Sets up the viewport to designated values */
54void set_viewport
() {
55 glViewport
((SCREEN_W - viewport_w
) / 2,
(SCREEN_H - viewport_h
) / 2,
56 viewport_w, viewport_h
);
57}
58
59
60
61/* Sets up the camera for displaying the world */
62void set_camera
() {
63 float theta
;
64
65 /* First, we set up the projection matrix.
66 * Note that SCREEN_W / SCREEN_H = 1.333333, so we need to multiply the
67 * aspect ratio by that value so that the display doesn't get distorted.
68 */
69 glMatrixMode
(GL_PROJECTION
);
70 glLoadIdentity
();
71 gluPerspective
((float)fov, aspect
* 1.
333333,
1.
0,
120.
0);
72 glMatrixMode
(GL_MODELVIEW
);
73 glLoadIdentity
();
74
75 /* Macro to convert radians to degrees */
76 #define RAD_2_DEG(x) ((x) * 180 / M_PI)
77
78 /* Convert the QUAT to something OpenGL can understand
79 * We can use allegro_gl_apply_quat() here, but I'd just like
80 * to show how it can be done with regular GL code.
81 *
82 * Since we're working with the camera, we have to rotate first,
83 * and then translate. Objects are done the other way around.
84 */
85 theta
= RAD_2_DEG
(2 * acos(camera.orientation.w
));
86 if (camera.orientation.w
< 1.
0f && camera.orientation.w
> -1.
0f) {
87 glRotatef
(theta, camera.orientation.x, camera.orientation.y,
88 camera.orientation.z
);
89 }
90
91 glTranslatef
(-camera.position.x,
-camera.position.y,
-camera.position.z
);
92
93 #undef RAD_2_DEG
94}
95
96
97
98/* Draw the (simple) world
99 * Notice how the camera doesn't affect the positioning.
100 */
101void draw_field
() {
102
103 int i, j
;
104
105 for (j
= 0; j
< GRID_SIZE
; j
++) {
106 for (i
= 0; i
< GRID_SIZE
; i
++) {
107 glPushMatrix
();
108 glTranslatef
(i
* 2 - GRID_SIZE
+ 1,
-2, j
* 2 - GRID_SIZE
+ 1);
109
110 glBindTexture
(GL_TEXTURE_2D,SlateTex
);
111
112 glClear
(GL_COLOR_BUFFER_BIT
);
113
114 glBegin
(GL_QUADS
);
115
116
117
118 glVertex3f
(-1,
0,
-1);
119 glVertex3f
(-1,
0,
1);
120 glVertex3f
( 1,
0,
1);
121 glVertex3f
( 1,
0,
-1);
122
123 glEnd
();
124 glPopMatrix
();
125 }
126 }
127}
128
129
130
131/* For display, we'd like to convert the QUAT back to heading, pitch and roll
132 * These don't serve any purpose but to make it look human readable.
133 * Note: Produces incorrect results.
134 */
135void convert_quat
(QUAT *q,
float *heading,
float *pitch,
float *roll
) {
136 MATRIX_f matrix
;
137 quat_to_matrix(q,
&matrix
);
138
139 *heading
= atan2(matrix.v
[0][2], matrix.v
[0][0]);
140 *pitch
= asin(matrix.v
[0][1]);
141 *roll
= atan2(matrix.v
[2][1], matrix.v
[2][0]);
142}
143
144
145
146/* Draws the overlay over the field. The position of the overlay is
147 * independent of the camera.
148 */
149void draw_overlay
() {
150 float heading, pitch, roll
;
151 int color
;
152 VECTOR v
;
153
154 /* Set up the viewport so that it takes up the whole screen */
155 glViewport
(0,
0,
SCREEN_W,
SCREEN_H);
156
157 /* Draw a line around the viewport */
158 allegro_gl_set_projection
();
159
160 glColor3ub
(255,
0,
0);
161 glDisable
(GL_DEPTH_TEST
);
162
163 glBegin
(GL_LINE_LOOP
);
164 glVertex2i
((SCREEN_W - viewport_w
) / 2,
(SCREEN_H - viewport_h
) / 2);
165 glVertex2i
((SCREEN_W + viewport_w
) / 2 - 1,
166 (SCREEN_H - viewport_h
) / 2);
167 glVertex2i
((SCREEN_W + viewport_w
) / 2 - 1,
168 (SCREEN_H + viewport_h
) / 2 - 1);
169 glVertex2i
((SCREEN_W - viewport_w
) / 2,
170 (SCREEN_H + viewport_h
) / 2 - 1);
171 glEnd
();
172
173 /* Overlay some text describing the current situation */
174 glBlendFunc
(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
);
175 color
= 0;
176 glTranslatef
(-0.
375,
-0.
375,
0);
177 allegro_gl_printf
(agl_font,
0,
0,
0, color,
178 "Viewport width: %03d pix (w/W changes)", viewport_w
);
179 allegro_gl_printf
(agl_font,
0,
8,
0, color,
180 "Viewport height: %03d pix (h/H changes)", viewport_h
);
181 allegro_gl_printf
(agl_font,
0,
16,
0, color,
182 "Field Of View: %02d deg (f/F changes)", fov
);
183 allegro_gl_printf
(agl_font,
0,
24,
0, color,
184 "Aspect Ratio: %.2f (a/A changes)", aspect
);
185 allegro_gl_printf
(agl_font,
0,
32,
0, color,
186 "X position: %+.2f (x/X changes)", camera.position.x
);
187 allegro_gl_printf
(agl_font,
0,
40,
0, color,
188 "Y position: %+.2f (y/Y changes)", camera.position.y
);
189 allegro_gl_printf
(agl_font,
0,
48,
0, color,
190 "Z position: %+.2f (z/Z changes)", camera.position.z
);
191
192 /* Convert the orientation QUAT into heading, pitch and roll to display */
193 convert_quat
(&camera.orientation,
&heading,
&pitch,
&roll
);
194
195 allegro_gl_printf
(agl_font,
0,
56,
0, color,
196 "Heading: %+.2f deg (left/right changes)", heading
* 180 / M_PI
);
197 allegro_gl_printf
(agl_font,
0,
64,
0, color,
198 "Pitch: %+.2f deg (pgup/pgdn changes)", pitch
* 180 / M_PI
);
199 allegro_gl_printf
(agl_font,
0,
72,
0, color,
200 "Roll: %+.2f deg (r/R changes)", roll
* 180 / M_PI
);
201
202 apply_quat(&camera.orientation,
0,
0,
-1,
&v.x,
&v.y,
&v.z
);
203
204 allegro_gl_printf
(agl_font,
0,
80,
0, color,
205 "Front Vector: %.2f, %.2f, %.2f", v.x, v.y, v.z
);
206
207 apply_quat(&camera.orientation,
0,
1,
0,
&v.x,
&v.y,
&v.z
);
208
209 allegro_gl_printf
(agl_font,
0,
88,
0, color,
210 "Up Vector: %.2f, %.2f, %.2f", v.x, v.y, v.z
);
211 allegro_gl_printf
(agl_font,
0,
96,
0, color,
212 "QUAT: %f, %f, %f, %f ", camera.orientation.w,
213 camera.orientation.x, camera.orientation.y, camera.orientation.z
);
214
215 allegro_gl_unset_projection
();
216
217 glBlendFunc
(GL_ONE, GL_ZERO
);
218 glEnable
(GL_DEPTH_TEST
);
219}
220
221
222
223/* draw everything */
224void render
()
225{
226 set_viewport
();
227
228 glClearColor
(1.
0,
1.
0,
1.
0,
0.
0);
229 glClear
(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
230
231 set_camera
();
232
233 draw_field
();
234
235 draw_overlay
();
236
237 glFlush
();
238
239 allegro_gl_flip
();
240}
241
242
243
244/* deal with user input */
245void process_input
(void) {
246
247 QUAT q
;
248
249 poll_keyboard();
250
251 if (key[KEY_W
]) {
252 if (key_shifts & KB_SHIFT_FLAG
) {
253 if (viewport_w
< SCREEN_W)
254 viewport_w
+= 8;
255 }
256 else {
257 if (viewport_w
> 16)
258 viewport_w
-= 8;
259 }
260 }
261
262 if (key[KEY_H
]) {
263 if (key_shifts & KB_SHIFT_FLAG
) {
264 if (viewport_h
< SCREEN_H)
265 viewport_h
+= 8;
266 }
267 else {
268 if (viewport_h
> 16)
269 viewport_h
-= 8;
270 }
271 }
272
273 if (key[KEY_X
]) {
274 if (key_shifts & KB_SHIFT_FLAG
)
275 camera.position.x
+= 0.
05;
276 else
277 camera.position.x
-= 0.
05;
278 }
279
280 if (key[KEY_Y
]) {
281 if (key_shifts & KB_SHIFT_FLAG
)
282 camera.position.y
+= 0.
05;
283 else
284 camera.position.y
-= 0.
05;
285 }
286
287 if (key[KEY_Z
]) {
288 if (key_shifts & KB_SHIFT_FLAG
)
289 camera.position.z
+= 0.
05;
290 else
291 camera.position.z
-= 0.
05;
292 }
293
294 if (key[KEY_UP
]) {
295 VECTOR front
;
296 /* Note: We use -1 here because Allegro's coordinate system
297 * is slightly different than OpenGL's.
298 */
299 apply_quat(&camera.orientation,
0,
0,
-1,
&front.x,
&front.y,
&front.z
);
300 camera.position.x
+= front.x
/ 10;
301 camera.position.y
+= front.y
/ 10;
302 camera.position.z
+= front.z
/ 10;
303 }
304 if (key[KEY_DOWN
]) {
305 VECTOR front
;
306 apply_quat(&camera.orientation,
0,
0,
-1,
&front.x,
&front.y,
&front.z
);
307 camera.position.x
-= front.x
/ 10;
308 camera.position.y
-= front.y
/ 10;
309 camera.position.z
-= front.z
/ 10;
310 }
311
312
313 /* When turning right or left, we only want to change the heading.
314 * That is, we only want to rotate around the absolute Y axis
315 */
316 if (key[KEY_LEFT
]) {
317 get_y_rotate_quat(&q,
-1);
318 quat_mul(&camera.orientation,
&q,
&camera.orientation
);
319 }
320 if (key[KEY_RIGHT
]) {
321 get_y_rotate_quat(&q,
1);
322 quat_mul(&camera.orientation,
&q,
&camera.orientation
);
323 }
324
325 /* However, when rolling or changing pitch, we do a rotation relative to
326 * the current orientation of the camera. This is why we extract the
327 * 'right' and 'front' vectors of the camera and apply a rotation on
328 * those.
329 */
330 if (key[KEY_PGUP
]) {
331 VECTOR right
;
332 apply_quat(&camera.orientation,
1,
0,
0,
&right.x,
&right.y,
&right.z
);
333 get_vector_rotation_quat(&q, right.x, right.y, right.z,
-1);
334 quat_mul(&camera.orientation,
&q,
&camera.orientation
);
335 }
336 if (key[KEY_PGDN
]) {
337 VECTOR right
;
338 apply_quat(&camera.orientation,
1,
0,
0,
&right.x,
&right.y,
&right.z
);
339 get_vector_rotation_quat(&q, right.x, right.y, right.z,
1);
340 quat_mul(&camera.orientation,
&q,
&camera.orientation
);
341 }
342
343 if (key[KEY_R
]) {
344 VECTOR front
;
345 apply_quat(&camera.orientation,
0,
0,
1,
&front.x,
&front.y,
&front.z
);
346
347 if (key_shifts & KB_SHIFT_FLAG
)
348 get_vector_rotation_quat(&q, front.x, front.y, front.z,
-1);
349 else
350 get_vector_rotation_quat(&q, front.x, front.y, front.z,
1);
351
352 quat_mul(&camera.orientation,
&q,
&camera.orientation
);
353 }
354
355 if (key[KEY_F
]) {
356 if (key_shifts & KB_SHIFT_FLAG
) {
357 if (fov
< 96)
358 fov
++;
359 }
360 else {
361 if (fov
> 16)
362 fov--
;
363 }
364 }
365
366 if (key[KEY_A
]) {
367 if (key_shifts & KB_SHIFT_FLAG
) {
368 aspect
+= 0.
05;
369 if (aspect
> 2)
370 aspect
= 2;
371 }
372 else {
373 aspect
-= 0.
05;
374 if (aspect
< .
1)
375 aspect
= .
1;
376 }
377 }
378}
379
380
381
382int main
(void) {
383
384 allegro_init();
385 install_allegro_gl
();
386 install_keyboard();
387
388 /* Initialise the camera */
389 camera.orientation
= identity_quat;
390 camera.position.x
= 0;
391 camera.position.y
= 0;
392 camera.position.z
= 4;
393
394 /* Set up AllegroGL */
395 allegro_gl_clear_settings
();
396 allegro_gl_set
(AGL_COLOR_DEPTH,
16);
397 allegro_gl_set
(AGL_Z_DEPTH,
16);
398 allegro_gl_set
(AGL_DOUBLEBUFFER,
1);
399 allegro_gl_set
(AGL_RENDERMETHOD,
1);
400 allegro_gl_set
(AGL_WINDOWED, TRUE
);
401 allegro_gl_set
(AGL_SUGGEST, AGL_Z_DEPTH
| AGL_DOUBLEBUFFER
402 | AGL_RENDERMETHOD
| AGL_WINDOWED
| AGL_COLOR_DEPTH
);
403
404 if (set_gfx_mode(GFX_OPENGL,
640,
480,
0,
0) != 0) {
405 set_gfx_mode(GFX_TEXT,
0,
0,
0,
0);
406 allegro_message ("Error setting OpenGL graphics mode:\n%s\n"
407 "Allegro GL error : %s\n",
408 allegro_error, allegro_gl_error
);
409 return 1;
410 }
411
412 allegro_gl_set_texture_format
(GL_RGB8
);
413
414 BITMAP* slate_bmp
= load_bitmap("imagem.bmp",
0);
415 SlateTex
= allegro_gl_make_texture
(slate_bmp
);
416 destroy_bitmap(slate_bmp
);
417
418
419 /* Set up OpenGL */
420 glEnable
(GL_DEPTH_TEST
);
421 glCullFace
(GL_BACK
);
422 glEnable
(GL_CULL_FACE
);
423 glEnable
(GL_TEXTURE_2D
);
424 glEnable
(GL_BLEND
);
425
426 glShadeModel
(GL_SMOOTH
);
427
428 /* Build the font we'll use to display info */
429 agl_font
= allegro_gl_convert_allegro_font_ex
(font,
430 AGL_FONT_TYPE_TEXTURED,
-1.
0, GL_ALPHA8
);
431 glEnable
(GL_TEXTURE_2D
);
432
433
434
435 /* Run the example program */
436 while (!key[KEY_ESC
]) {
437 render
();
438
439 process_input
();
440 }
441
442 allegro_gl_destroy_font
(agl_font
);
443
444 return 0;
445}
446END_OF_MAIN();