1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4
5 #define ALLEGRO_UNSTABLE
6 #include "allegro5/allegro.h"
7 #include "allegro5/allegro_primitives.h"
8
9 #include "common.c"
10
11 typedef struct
12 {
13 float x, y;
14 float nx, ny, nz;
15 } CUSTOM_VERTEX;
16
17 #define RING_SIZE 25
18 #define SPHERE_RADIUS 150.1
19 #define SCREEN_WIDTH 640
20 #define SCREEN_HEIGHT 480
21 #define NUM_RINGS (SCREEN_WIDTH / RING_SIZE + 1)
22 #define NUM_SEGMENTS 64
23 #define NUM_VERTICES (NUM_RINGS * NUM_SEGMENTS * 6)
24 #define FIRST_OUTSIDE_RING ((int)(SPHERE_RADIUS / RING_SIZE))
25
setup_vertex(CUSTOM_VERTEX * vtx,int ring,int segment,bool inside)26 static void setup_vertex(CUSTOM_VERTEX* vtx, int ring, int segment, bool inside)
27 {
28 float len;
29 float x, y, z;
30 x = ring * RING_SIZE * cosf(2 * ALLEGRO_PI * segment / NUM_SEGMENTS);
31 y = ring * RING_SIZE * sinf(2 * ALLEGRO_PI * segment / NUM_SEGMENTS);
32 vtx->x = x + SCREEN_WIDTH / 2;
33 vtx->y = y + SCREEN_HEIGHT / 2;
34
35 if (inside) {
36 /* This comes from the definition of the normal vector as the
37 * gradient of the 3D surface. */
38 z = sqrtf(SPHERE_RADIUS * SPHERE_RADIUS - x * x - y * y);
39 vtx->nx = x / z;
40 vtx->ny = y / z;
41 }
42 else {
43 vtx->nx = 0;
44 vtx->ny = 0;
45 }
46 vtx->nz = 1.0;
47
48 len = sqrtf(vtx->nx * vtx->nx + vtx->ny * vtx->ny + vtx->nz * vtx->nz);
49 vtx->nx /= len;
50 vtx->ny /= len;
51 vtx->nz /= len;
52 }
53
main(int argc,char ** argv)54 int main(int argc, char **argv)
55 {
56 ALLEGRO_DISPLAY *display;
57 ALLEGRO_TIMER *timer;
58 ALLEGRO_EVENT_QUEUE *queue;
59 bool redraw = true;
60 ALLEGRO_SHADER *shader;
61 ALLEGRO_VERTEX_DECL *vertex_decl;
62 ALLEGRO_VERTEX_ELEMENT vertex_elems[] = {
63 {ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, offsetof(CUSTOM_VERTEX, x)},
64 {ALLEGRO_PRIM_USER_ATTR, ALLEGRO_PRIM_FLOAT_3, offsetof(CUSTOM_VERTEX, nx)},
65 {0, 0, 0}
66 };
67 CUSTOM_VERTEX vertices[NUM_VERTICES];
68 bool quit = false;
69 const char* vertex_shader_file;
70 const char* pixel_shader_file;
71 int vertex_idx = 0;
72 int ring, segment;
73 float diffuse_color[4] = {0.1, 0.1, 0.7, 1.0};
74 float light_position[3] = {0, 0, 100};
75
76 (void)argc;
77 (void)argv;
78
79 if (!al_init()) {
80 abort_example("Could not init Allegro.\n");
81 }
82
83 al_install_mouse();
84 al_install_keyboard();
85 al_install_touch_input();
86 if (!al_init_primitives_addon()) {
87 abort_example("Could not init primitives addon.\n");
88 }
89 init_platform_specific();
90 al_set_new_display_flags(ALLEGRO_PROGRAMMABLE_PIPELINE);
91 display = al_create_display(SCREEN_WIDTH, SCREEN_HEIGHT);
92 if (!display) {
93 abort_example("Error creating display.\n");
94 }
95
96 vertex_decl = al_create_vertex_decl(vertex_elems, sizeof(CUSTOM_VERTEX));
97 if (!vertex_decl) {
98 abort_example("Error creating vertex declaration.\n");
99 }
100
101 /* Computes a "spherical" bump ring. The z coordinate is not actually set
102 * appropriately as this is a 2D example, but the normal vectors are computed
103 * correctly for the light shading effect. */
104 for (ring = 0; ring < NUM_RINGS; ring++) {
105 for (segment = 0; segment < NUM_SEGMENTS; segment++) {
106 bool inside = ring < FIRST_OUTSIDE_RING;
107 setup_vertex(&vertices[vertex_idx + 0], ring + 0, segment + 0, inside);
108 setup_vertex(&vertices[vertex_idx + 1], ring + 0, segment + 1, inside);
109 setup_vertex(&vertices[vertex_idx + 2], ring + 1, segment + 0, inside);
110 setup_vertex(&vertices[vertex_idx + 3], ring + 1, segment + 0, inside);
111 setup_vertex(&vertices[vertex_idx + 4], ring + 0, segment + 1, inside);
112 setup_vertex(&vertices[vertex_idx + 5], ring + 1, segment + 1, inside);
113 vertex_idx += 6;
114 }
115 }
116
117 shader = al_create_shader(ALLEGRO_SHADER_AUTO);
118
119 if (!shader) {
120 abort_example("Failed to create shader.");
121 }
122
123 if (al_get_shader_platform(shader) == ALLEGRO_SHADER_GLSL) {
124 vertex_shader_file = "data/ex_prim_shader_vertex.glsl";
125 pixel_shader_file = "data/ex_prim_shader_pixel.glsl";
126 }
127 else {
128 vertex_shader_file = "data/ex_prim_shader_vertex.hlsl";
129 pixel_shader_file = "data/ex_prim_shader_pixel.hlsl";
130 }
131
132 if (!al_attach_shader_source_file(shader, ALLEGRO_VERTEX_SHADER, vertex_shader_file)) {
133 abort_example("al_attach_shader_source_file for vertex shader failed: %s\n",
134 al_get_shader_log(shader));
135 }
136 if (!al_attach_shader_source_file(shader, ALLEGRO_PIXEL_SHADER, pixel_shader_file)) {
137 abort_example("al_attach_shader_source_file for pixel shader failed: %s\n",
138 al_get_shader_log(shader));
139 }
140
141 if (!al_build_shader(shader)) {
142 abort_example("al_build_shader for link failed: %s\n", al_get_shader_log(shader));
143 }
144
145 al_use_shader(shader);
146 al_set_shader_float_vector("diffuse_color", 4, diffuse_color, 1);
147 /* alpha controls shininess, and 25 is very shiny */
148 al_set_shader_float("alpha", 25);
149
150 timer = al_create_timer(1.0 / 60);
151 queue = al_create_event_queue();
152 al_register_event_source(queue, al_get_keyboard_event_source());
153 al_register_event_source(queue, al_get_mouse_event_source());
154 if (al_is_touch_input_installed()) {
155 al_register_event_source(queue,
156 al_get_touch_input_mouse_emulation_event_source());
157 }
158 al_register_event_source(queue, al_get_display_event_source(display));
159 al_register_event_source(queue, al_get_timer_event_source(timer));
160 al_start_timer(timer);
161
162 while (!quit) {
163 ALLEGRO_EVENT event;
164 al_wait_for_event(queue, &event);
165
166 switch (event.type) {
167 case ALLEGRO_EVENT_DISPLAY_CLOSE:
168 quit = true;
169 break;
170 case ALLEGRO_EVENT_MOUSE_AXES:
171 light_position[0] = event.mouse.x;
172 light_position[1] = event.mouse.y;
173 break;
174 case ALLEGRO_EVENT_KEY_CHAR:
175 if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
176 quit = true;
177 break;
178 case ALLEGRO_EVENT_TIMER:
179 redraw = true;
180 break;
181 }
182
183 if (redraw && al_is_event_queue_empty(queue)) {
184 al_clear_to_color(al_map_rgb_f(0, 0, 0));
185
186 al_set_shader_float_vector("light_position", 3, light_position, 1);
187 al_draw_prim(vertices, vertex_decl, NULL, 0, NUM_VERTICES, ALLEGRO_PRIM_TRIANGLE_LIST);
188
189 al_flip_display();
190 redraw = false;
191 }
192 }
193
194 al_use_shader(NULL);
195 al_destroy_shader(shader);
196 al_destroy_vertex_decl(vertex_decl);
197
198 return 0;
199 }
200
201
202 /* vim: set sts=3 sw=3 et: */
203