Show excamera.c syntax highlighted
/*
* Example program for the Allegro library, by Shawn Hargreaves.
*
* This program demonstrates how to use the al_get_camera_matrix() function
* to view a 3d world from any position and angle.
*/
#include <stdio.h>
#include <math.h>
#include "allegro.h"
#ifndef M_PI
#define M_PI 3.14159
#endif
/* display a nice 8x8 chessboard grid */
#define GRID_SIZE 8
/* convert radians to degrees */
#define DEG(n) ((n) * 180.0 / M_PI)
/* parameters controlling the camera and projection state */
int viewport_w = 320;
int viewport_h = 240;
int fov = 48;
float aspect = 1;
float xpos = 0;
float ypos = -2;
float zpos = -4;
float heading = 0;
float pitch = 0;
float roll = 0;
/* render a tile of the grid */
void draw_square(AL_BITMAP *bmp, AL_MATRIX_F *camera, int x, int z)
{
AL_V3D_F _v[4], _vout[8], _vtmp[8];
AL_V3D_F *v[4], *vout[8], *vtmp[8];
int flags[4], out[8];
int c, vc;
for (c=0; c<4; c++)
v[c] = &_v[c];
for (c=0; c<8; c++) {
vout[c] = &_vout[c];
vtmp[c] = &_vtmp[c];
}
/* set up four vertices with the world-space position of the tile */
v[0]->x = x - GRID_SIZE/2;
v[0]->y = 0;
v[0]->z = z - GRID_SIZE/2;
v[1]->x = x - GRID_SIZE/2 + 1;
v[1]->y = 0;
v[1]->z = z - GRID_SIZE/2;
v[2]->x = x - GRID_SIZE/2 + 1;
v[2]->y = 0;
v[2]->z = z - GRID_SIZE/2 + 1;
v[3]->x = x - GRID_SIZE/2;
v[3]->y = 0;
v[3]->z = z - GRID_SIZE/2 + 1;
/* apply the camera matrix, translating world space -> view space */
for (c=0; c<4; c++) {
al_apply_matrix_f(camera, v[c]->x, v[c]->y, v[c]->z, &v[c]->x, &v[c]->y, &v[c]->z);
flags[c] = 0;
/* set flags if this vertex is off the edge of the al_screen */
if (v[c]->x < -v[c]->z)
flags[c] |= 1;
else if (v[c]->x > v[c]->z)
flags[c] |= 2;
if (v[c]->y < -v[c]->z)
flags[c] |= 4;
else if (v[c]->y > v[c]->z)
flags[c] |= 8;
if (v[c]->z < 0.1)
flags[c] |= 16;
}
/* quit if all vertices are off the same edge of the al_screen */
if (flags[0] & flags[1] & flags[2] & flags[3])
return;
if (flags[0] | flags[1] | flags[2] | flags[3]) {
/* clip if any vertices are off the edge of the al_screen */
vc = al_clip_3d_f(POLYTYPE_FLAT, 0.1, 0.1, 4, (AL_CONST AL_V3D_F **)v, vout, vtmp, out);
if (vc <= 0)
return;
}
else {
/* no need to bother clipping this one */
vout[0] = v[0];
vout[1] = v[1];
vout[2] = v[2];
vout[3] = v[3];
vc = 4;
}
/* project view space -> al_screen space */
for (c=0; c<vc; c++)
al_persp_project_f(vout[c]->x, vout[c]->y, vout[c]->z, &vout[c]->x, &vout[c]->y);
/* set the color */
vout[0]->c = ((x + z) & 1) ? al_make_color(0, 255, 0) : al_make_color(255, 255, 0);
/* render the al_draw_polygon */
al_draw_polygon_3d_f(bmp, POLYTYPE_FLAT, NULL, vc, vout);
}
/* draw everything */
void render(AL_BITMAP *bmp)
{
char buf[80];
AL_MATRIX_F roller, camera;
int x, y, w, h;
float xfront, yfront, zfront;
float xup, yup, zup;
/* clear the background */
al_clear_to_color(bmp, al_make_color(255, 255, 255));
/* set up the viewport region */
x = (AL_SCREEN_W - viewport_w) / 2;
y = (AL_SCREEN_H - viewport_h) / 2;
w = viewport_w;
h = viewport_h;
al_set_projection_viewport(x, y, w, h);
al_draw_rect(bmp, x-1, y-1, x+w, y+h, al_make_color(255, 0, 0));
al_set_clip(bmp, x, y, x+w-1, y+h-1);
/* calculate the in-front vector */
xfront = sin(heading) * cos(pitch);
yfront = sin(pitch);
zfront = cos(heading) * cos(pitch);
/* rotate the up vector around the in-front vector by the roll angle */
al_get_vector_rotation_matrix_f(&roller, xfront, yfront, zfront, roll*128.0/M_PI);
al_apply_matrix_f(&roller, 0, -1, 0, &xup, &yup, &zup);
/* build the camera matrix */
al_get_camera_matrix_f(&camera,
xpos, ypos, zpos, /* camera position */
xfront, yfront, zfront, /* in-front vector */
xup, yup, zup, /* up vector */
fov, /* field of view */
aspect); /* aspect ratio */
/* draw the grid of squares */
for (x=0; x<GRID_SIZE; x++)
for (y=0; y<GRID_SIZE; y++)
draw_square(bmp, &camera, x, y);
/* overlay some text */
al_set_clip(bmp, 0, 0, bmp->w, bmp->h);
al_text_mode(-1);
sprintf(buf, "Viewport width: %d (w/W changes)", viewport_w);
al_put_text(bmp, al_font_8x8, buf, 0, 0, al_make_color(0, 0, 0));
sprintf(buf, "Viewport height: %d (h/H changes)", viewport_h);
al_put_text(bmp, al_font_8x8, buf, 0, 8, al_make_color(0, 0, 0));
sprintf(buf, "Field of view: %d (f/F changes)", fov);
al_put_text(bmp, al_font_8x8, buf, 0, 16, al_make_color(0, 0, 0));
sprintf(buf, "Aspect ratio: %.2f (a/A changes)", aspect);
al_put_text(bmp, al_font_8x8, buf, 0, 24, al_make_color(0, 0, 0));
sprintf(buf, "X position: %.2f (x/X changes)", xpos);
al_put_text(bmp, al_font_8x8, buf, 0, 32, al_make_color(0, 0, 0));
sprintf(buf, "Y position: %.2f (y/Y changes)", ypos);
al_put_text(bmp, al_font_8x8, buf, 0, 40, al_make_color(0, 0, 0));
sprintf(buf, "Z position: %.2f (z/Z changes)", zpos);
al_put_text(bmp, al_font_8x8, buf, 0, 48, al_make_color(0, 0, 0));
sprintf(buf, "Heading: %.2f deg (left/right changes)", DEG(heading));
al_put_text(bmp, al_font_8x8, buf, 0, 56, al_make_color(0, 0, 0));
sprintf(buf, "Pitch: %.2f deg (pgup/pgdn changes)", DEG(pitch));
al_put_text(bmp, al_font_8x8, buf, 0, 64, al_make_color(0, 0, 0));
sprintf(buf, "Roll: %.2f deg (r/R changes)", DEG(roll));
al_put_text(bmp, al_font_8x8, buf, 0, 72, al_make_color(0, 0, 0));
sprintf(buf, "Front vector: %.2f, %.2f, %.2f", xfront, yfront, zfront);
al_put_text(bmp, al_font_8x8, buf, 0, 80, al_make_color(0, 0, 0));
sprintf(buf, "Up vector: %.2f, %.2f, %.2f", xup, yup, zup);
al_put_text(bmp, al_font_8x8, buf, 0, 88, al_make_color(0, 0, 0));
}
/* deal with user input */
void process_input(void)
{
al_poll_keyboard();
if (al_key[AL_KEY_W]) {
if (al_key_shifts & KB_SHIFT_FLAG) {
if (viewport_w < AL_SCREEN_W)
viewport_w += 8;
}
else {
if (viewport_w > 16)
viewport_w -= 8;
}
}
if (al_key[AL_KEY_H]) {
if (al_key_shifts & KB_SHIFT_FLAG) {
if (viewport_h < AL_SCREEN_H)
viewport_h += 8;
}
else {
if (viewport_h > 16)
viewport_h -= 8;
}
}
if (al_key[AL_KEY_F]) {
if (al_key_shifts & KB_SHIFT_FLAG) {
if (fov < 96)
fov++;
}
else {
if (fov > 16)
fov--;
}
}
if (al_key[AL_KEY_A]) {
if (al_key_shifts & KB_SHIFT_FLAG) {
aspect += 0.05;
if (aspect > 2)
aspect = 2;
}
else {
aspect -= 0.05;
if (aspect < .1)
aspect = .1;
}
}
if (al_key[AL_KEY_X]) {
if (al_key_shifts & KB_SHIFT_FLAG)
xpos += 0.05;
else
xpos -= 0.05;
}
if (al_key[AL_KEY_Y]) {
if (al_key_shifts & KB_SHIFT_FLAG)
ypos += 0.05;
else
ypos -= 0.05;
}
if (al_key[AL_KEY_Z]) {
if (al_key_shifts & KB_SHIFT_FLAG)
zpos += 0.05;
else
zpos -= 0.05;
}
if (al_key[AL_KEY_LEFT])
heading -= 0.05;
if (al_key[AL_KEY_RIGHT])
heading += 0.05;
if (al_key[AL_KEY_PGUP])
if (pitch > -M_PI/4)
pitch -= 0.05;
if (al_key[AL_KEY_PGDN])
if (pitch < M_PI/4)
pitch += 0.05;
if (al_key[AL_KEY_R]) {
if (al_key_shifts & KB_SHIFT_FLAG) {
if (roll < M_PI/4)
roll += 0.05;
}
else {
if (roll > -M_PI/4)
roll -= 0.05;
}
}
if (al_key[AL_KEY_UP]) {
xpos += sin(heading) / 4;
zpos += cos(heading) / 4;
}
if (al_key[AL_KEY_DOWN]) {
xpos -= sin(heading) / 4;
zpos -= cos(heading) / 4;
}
}
int main(void)
{
AL_BITMAP *buffer;
allegro_init();
al_install_keyboard();
if (al_set_gfx_mode(AL_GFX_SAFE, 640, 480, 0, 0) != 0) {
al_set_gfx_mode(AL_GFX_NONE, 0, 0, 0, 0);
al_show_message("Unable to set any graphic mode\n%s\n", al_error);
return 1;
}
al_set_palette(al_desktop_palette);
buffer = al_create_bitmap(AL_SCREEN_W, AL_SCREEN_H);
while (!al_key[AL_KEY_ESC]) {
render(buffer);
al_vsync();
al_blit(buffer, al_screen, 0, 0, 0, 0, AL_SCREEN_W, AL_SCREEN_H);
process_input();
}
al_destroy_bitmap(buffer);
return 0;
}
AL_END_OF_MAIN();
See more files for this project here