-
Notifications
You must be signed in to change notification settings - Fork 314
Open
Labels
Description
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#include <stdio.h>
#include <math.h>
// Define inline GLSL vertex shader
const char *vertex_shader_source =
"#version 120\n" // OpenGL ES 2.0 / WebGL compatibility
"attribute vec4 al_pos;\n"
"attribute vec4 al_color;\n"
"uniform mat4 al_projview_matrix;\n"
"varying vec4 v_color;\n"
"void main()\n"
"{\n"
" v_color = al_color;\n"
" gl_Position = al_projview_matrix * al_pos;\n"
"}\n";
// Define inline GLSL fragment shader
const char *fragment_shader_source =
"#version 120\n" // OpenGL ES 2.0 / WebGL compatibility
"varying vec4 v_color;\n"
"void main()\n"
"{\n"
" gl_FragColor = v_color;\n"
"}\n";
int main(int argc, char **argv)
{
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
ALLEGRO_TIMER *timer = NULL;
ALLEGRO_SHADER *shader = NULL;
ALLEGRO_VERTEX_BUFFER *vertex_buffer = NULL;
ALLEGRO_INDEX_BUFFER *index_buffer = NULL;
int ret = 0; // Return value for main
// Cube vertices (position and color - RGBA for ALLEGRO_VERTEX)
ALLEGRO_VERTEX vertices[] = {
// Front face (Red)
{.x = -0.5f, .y = -0.5f, .z = 0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(1.0f, 0.0f, 0.0f)},
{.x = 0.5f, .y = -0.5f, .z = 0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(1.0f, 0.0f, 0.0f)},
{.x = 0.5f, .y = 0.5f, .z = 0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(1.0f, 0.0f, 0.0f)},
{.x = -0.5f, .y = 0.5f, .z = 0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(1.0f, 0.0f, 0.0f)},
// Back face (Green)
{.x = -0.5f, .y = -0.5f, .z = -0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(0.0f, 1.0f, 0.0f)},
{.x = 0.5f, .y = -0.5f, .z = -0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(0.0f, 1.0f, 0.0f)},
{.x = 0.5f, .y = 0.5f, .z = -0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(0.0f, 1.0f, 0.0f)},
{.x = -0.5f, .y = 0.5f, .z = -0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(0.0f, 1.0f, 0.0f)},
// Right face (Blue)
{.x = 0.5f, .y = -0.5f, .z = 0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(0.0f, 0.0f, 1.0f)},
{.x = 0.5f, .y = -0.5f, .z = -0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(0.0f, 0.0f, 1.0f)},
{.x = 0.5f, .y = 0.5f, .z = -0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(0.0f, 0.0f, 1.0f)},
{.x = 0.5f, .y = 0.5f, .z = 0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(0.0f, 0.0f, 1.0f)},
// Left face (Yellow)
{.x = -0.5f, .y = -0.5f, .z = 0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(1.0f, 1.0f, 0.0f)},
{.x = -0.5f, .y = -0.5f, .z = -0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(1.0f, 1.0f, 0.0f)},
{.x = -0.5f, .y = 0.5f, .z = -0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(1.0f, 1.0f, 0.0f)},
{.x = -0.5f, .y = 0.5f, .z = 0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(1.0f, 1.0f, 0.0f)},
// Top face (Cyan)
{.x = -0.5f, .y = 0.5f, .z = 0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(0.0f, 1.0f, 1.0f)},
{.x = 0.5f, .y = 0.5f, .z = 0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(0.0f, 1.0f, 1.0f)},
{.x = 0.5f, .y = 0.5f, .z = -0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(0.0f, 1.0f, 1.0f)},
{.x = -0.5f, .y = 0.5f, .z = -0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(0.0f, 1.0f, 1.0f)},
// Bottom face (Magenta)
{.x = -0.5f, .y = -0.5f, .z = 0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(1.0f, 0.0f, 1.0f)},
{.x = 0.5f, .y = -0.5f, .z = 0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(1.0f, 0.0f, 1.0f)},
{.x = 0.5f, .y = -0.5f, .z = -0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(1.0f, 0.0f, 1.0f)},
{.x = -0.5f, .y = -0.5f, .z = -0.5f, .u = 0.0f, .v = 0.0f, .color = al_map_rgb_f(1.0f, 0.0f, 1.0f)},
};
// Indices for drawing the cube (two triangles per face)
unsigned int indices[] = {
// Front
0, 1, 2,
0, 2, 3,
// Back
4, 5, 6,
4, 6, 7,
// Right
8, 9, 10,
8, 10, 11,
// Left
12, 13, 14,
12, 14, 15,
// Top
16, 17, 18,
16, 18, 19,
// Bottom
20, 21, 22,
20, 22, 23,
};
// Initialize Allegro
if (!al_init())
{
fprintf(stderr, "failed to initialize allegro!\n");
ret = -1;
goto cleanup;
}
// Initialize primitives add-on
if (!al_init_primitives_addon())
{
fprintf(stderr, "failed to initialize primitives addon!\n");
ret = -1;
goto cleanup;
}
// Set OpenGL version for Allegro
al_set_new_display_option(ALLEGRO_DEPTH_SIZE, 16, ALLEGRO_SUGGEST); // Enable depth buffer
al_set_new_display_flags(ALLEGRO_WINDOWED | ALLEGRO_RESIZABLE | ALLEGRO_PROGRAMMABLE_PIPELINE | ALLEGRO_OPENGL);
// Create display
display = al_create_display(800, 600);
if (!display)
{
fprintf(stderr, "failed to create display!\n");
ret = -1;
goto cleanup;
}
// Create event queue
event_queue = al_create_event_queue();
if (!event_queue)
{
fprintf(stderr, "failed to create event_queue!\n");
ret = -1;
goto cleanup;
}
// Create timer
timer = al_create_timer(1.0 / 60.0); // 60 FPS
if (!timer)
{
fprintf(stderr, "failed to create timer!\n");
ret = -1;
goto cleanup;
}
// Register event sources
al_register_event_source(event_queue, al_get_display_event_source(display));
al_register_event_source(event_queue, al_get_timer_event_source(timer));
// Create vertex buffer using default ALLEGRO_VERTEX declaration (NULL)
vertex_buffer = al_create_vertex_buffer(
NULL, vertices, sizeof(vertices) / sizeof(vertices[0]), ALLEGRO_PRIM_BUFFER_STATIC);
if (!vertex_buffer)
{
fprintf(stderr, "failed to create vertex buffer!\n");
ret = -1;
goto cleanup;
}
// Create index buffer
index_buffer = al_create_index_buffer(
sizeof(unsigned int), indices, sizeof(indices) / sizeof(indices[0]), ALLEGRO_PRIM_BUFFER_STATIC);
if (!index_buffer)
{
fprintf(stderr, "failed to create index buffer!\n");
ret = -1;
goto cleanup;
}
// Create shader program from inline sources
shader = al_create_shader(ALLEGRO_SHADER_GLSL);
if (!shader)
{
fprintf(stderr, "failed to create shader object!\n");
ret = -1;
goto cleanup;
}
if (!al_attach_shader_source(shader, ALLEGRO_VERTEX_SHADER, vertex_shader_source))
{
fprintf(stderr, "failed to attach vertex shader source: %s\n", al_get_shader_log(shader));
ret = -1;
goto cleanup;
}
if (!al_attach_shader_source(shader, ALLEGRO_PIXEL_SHADER, fragment_shader_source))
{
fprintf(stderr, "failed to attach fragment shader source: %s\n", al_get_shader_log(shader));
ret = -1;
goto cleanup;
}
if (!al_build_shader(shader))
{
fprintf(stderr, "failed to build shader: %s\n", al_get_shader_log(shader));
ret = -1;
goto cleanup;
}
// Activate our custom shader for the backbuffer
al_use_shader(shader);
// Enable depth testing
al_set_render_state(ALLEGRO_DEPTH_TEST, 1);
bool redraw = true;
bool do_exit = false;
float angle = 0.0f;
al_start_timer(timer);
while (!do_exit)
{
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue, &ev);
if (ev.type == ALLEGRO_EVENT_TIMER)
{
angle += 0.02f; // Rotate the cube
redraw = true;
}
else if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
{
do_exit = true;
}
else if (ev.type == ALLEGRO_EVENT_DISPLAY_RESIZE)
{
al_acknowledge_resize(display);
redraw = true;
}
if (redraw && al_is_event_queue_empty(event_queue))
{
redraw = false;
al_clear_to_color(al_map_rgb(0, 0, 128)); // Clear background to blue
al_clear_depth_buffer(1.); // Clear depth to infinitely far away
// Set up projection matrix
ALLEGRO_TRANSFORM projection;
al_identity_transform(&projection);
float aspect_ratio = (float)al_get_display_height(display) / al_get_display_width(display);
al_perspective_transform(&projection, -1, aspect_ratio, 1, 1, -aspect_ratio, 1000);
al_use_projection_transform(&projection);
// Set up modelview matrix
ALLEGRO_TRANSFORM model;
al_identity_transform(&model);
al_rotate_transform_3d(&model, 1.0f, 0.0f, 0.0f, angle * 0.5f); // Rotate around X
al_rotate_transform_3d(&model, 0.0f, 1.0f, 0.0f, angle); // Rotate around Y
al_rotate_transform_3d(&model, 0.0f, 0.0f, 1.0f, angle * 0.3f); // Rotate around Z
al_translate_transform_3d(&model, 0.0f, 0.0f, -3.0f); // Translate
ALLEGRO_TRANSFORM camera;
al_build_camera_transform(&camera,
0.5f * cos(2.0f * angle), 0.0f, 0.0f, // Camera pos, move side to side
0.5f * cos(2.0f * angle), 0.0f, -3.0f, // Look at
0.0f, 1.0f, 0.0f // Up
);
ALLEGRO_TRANSFORM modelview;
al_identity_transform(&modelview);
al_compose_transform(&modelview, &model);
al_compose_transform(&modelview, &camera);
al_use_transform(&modelview);
// Draw the indexed primitive (cube)
al_draw_indexed_buffer(vertex_buffer, NULL, index_buffer, 0, sizeof(indices) / sizeof(indices[0]), ALLEGRO_PRIM_TRIANGLE_LIST);
// Flip display
al_flip_display();
}
}
cleanup:
// Cleanup resources in reverse order of allocation
if (shader)
al_destroy_shader(shader);
if (index_buffer)
al_destroy_index_buffer(index_buffer);
if (vertex_buffer)
al_destroy_vertex_buffer(vertex_buffer);
if (timer)
al_destroy_timer(timer);
if (event_queue)
al_destroy_event_queue(event_queue);
if (display)
al_destroy_display(display);
return ret;
}