1 /*
2 * Example program for the Allegro library, by Grzegorz Adam Hankiewicz.
3 *
4 * This program demonstrates how to create custom graphic effects
5 * with the create_color_table function. Allegro drawing routines
6 * are affected by any color table you might have set up. In
7 * the first part of this example, a greyscale color table is
8 * set. The result is that a simple rectfill call, instead of
9 * drawing a rectangle with color zero, uses the already drawn
10 * pixels to determine the pixel to be drawn (read the comment
11 * of return_grey_color() for a precise description of the
12 * algorithm). In the second part of the test, the color table
13 * is changed to be an inverse table, meaning that any pixel
14 * drawn will be shown as its color values had been inverted.
15 */
16
17
18 #include <allegro.h>
19
20
21
22 /* RGB -> color mapping table. Not needed, but speeds things up */
23 RGB_MAP rgb_table;
24
25 /* greyscale & negative color mapping table */
26 COLOR_MAP greyscale_table, negative_table;
27
28 PALETTE pal;
29 BITMAP *background;
30 BITMAP *temp;
31
32
33
34 /* Here comes our custom function. It's designed to take the input colors
35 * (red, green & blue) and return a greyscale color for it. This way, when
36 * any drawing function draws say over green, it draws the greyscale color
37 * for green.
38 * 'pal' is the palette we are looking in to find the colors.
39 * Now, imagine we want to draw a pixel with color A, over color B.
40 * Once the table is created, set, and the drawing mode is TRANSLUCENT, then
41 * A is the 'x' color passed to the function and B is the 'y' color passed
42 * to the function.
43 * Since we want a greyscale effect with no matter what A (or 'x') color, we
44 * ignore it and use y to look at the palette.
45 * NOTE:
46 * When you return the rgb value, you don't need to search the palette for
47 * the nearest color, Allegro does this automatically.
48 */
49
return_grey_color(AL_CONST PALETTE pal,int x,int y,RGB * rgb)50 void return_grey_color(AL_CONST PALETTE pal, int x, int y, RGB *rgb)
51 {
52 int c;
53
54 /* first create the greyscale color */
55 c = (pal[y].r*0.3 + pal[y].g*0.5 + pal[y].b*0.2);
56
57 /* now assign to our rgb triplet the palette greyscale color... */
58 rgb->r = rgb->g = rgb->b = c;
59 }
60
61
62
63 /* The negative_color function is quite the same like the grayscale one,
64 * since we are ignoring the value of the drawn color (aka x).
65 */
66
return_negative_color(AL_CONST PALETTE pal,int x,int y,RGB * rgb)67 void return_negative_color(AL_CONST PALETTE pal, int x, int y, RGB *rgb)
68 {
69 /* To get the negative color, subtract the color values of red, green
70 * and blue from the full (63) color value.
71 */
72 rgb->r = 63-pal[y].r;
73 rgb->g = 63-pal[y].g;
74 rgb->b = 63-pal[y].b;
75 }
76
77
78
generate_background(void)79 void generate_background(void)
80 {
81 int i;
82
83 /* First get some usual colors. */
84 generate_332_palette(pal);
85
86 /* Now remap the first 64 for a perfect greyscale gradient. */
87 for (i=0; i<64; i++) {
88 pal[i].r = i;
89 pal[i].g = i;
90 pal[i].b = i;
91 }
92
93 /* Draws some things on the screen using not-greyscale colors. */
94 for (i=0; i<3000; i++)
95 circlefill(background, AL_RAND() % 320, AL_RAND() % 200,
96 AL_RAND() % 25, 64 + AL_RAND() % 192);
97 }
98
99
100
main(void)101 int main(void)
102 {
103 int x, y, deltax=1, deltay=1;
104
105 if (allegro_init() != 0)
106 return 1;
107 install_keyboard();
108
109 temp = create_bitmap(320, 200);
110 background = create_bitmap(320, 200);
111
112 generate_background();
113
114 /* This isn't needed, but it speeds up the color table calculations. */
115 create_rgb_table(&rgb_table, pal, NULL);
116 rgb_map = &rgb_table;
117
118 /* Build a color lookup table for greyscale effect. */
119 create_color_table(&greyscale_table, pal, return_grey_color, NULL);
120
121 /* Build a color lookup table for negative effect. */
122 create_color_table(&negative_table, pal, return_negative_color, NULL);
123
124 if (set_gfx_mode(GFX_AUTODETECT, 320, 200, 0, 0) != 0) {
125 if (set_gfx_mode(GFX_SAFE, 320, 200, 0, 0) != 0) {
126 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
127 allegro_message("Unable to set any graphic mode\n%s\n",
128 allegro_error);
129 return 1;
130 }
131 }
132
133 set_palette(pal);
134
135 /* We have set the drawing mode to TRANS. This makes all the drawing
136 * functions use the general color_map table, which is _NOT_ translucent,
137 * since we are using a custom color_map table.
138 */
139 drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);
140
141 /* select the greyscale table */
142 color_map = &greyscale_table;
143
144 x = y = 50;
145 blit(background, temp, 0, 0, 0, 0, 320, 200);
146 rectfill(temp, x, y, x+50, y+50, 0);
147
148 blit(temp, screen, 0, 0, 0, 0, 320, 200);
149
150 while (!keypressed()) {
151 x += deltax;
152 y += deltay;
153
154 if ((x < 1) || (x > 320-50))
155 deltax *= -1;
156
157 if ((y < 1) || (y > 200-50))
158 deltay *= -1;
159
160 blit(background, temp, 0, 0, 0, 0, 320, 200);
161 textout_centre_ex(temp, font, "Greyscale effect",
162 SCREEN_W/2, SCREEN_H/2, makecol(0, 0, 255), -1);
163 rectfill(temp, x, y, x+50, y+50, 0);
164 vsync();
165 blit(temp, screen, 0, 0, 0, 0, 320, 200);
166
167 /* slow down the animation for modern machines */
168 rest(1);
169 }
170
171 clear_keybuf();
172
173 /* Now it's time for the negative part. The negative example is easier to
174 * see with greyscale colors. Therefore we will change the color of the
175 * background to a greyscale one, but only in a restricted area...
176 */
177
178 rectfill(background, SCREEN_H/4, SCREEN_H/4,
179 background->w-SCREEN_H/4, background->h-SCREEN_H/4, 0);
180
181 /* this should go inside the next loop, but since we won't use the
182 * background image any more, we can optimize it's speed printing the
183 * text now.
184 */
185 textout_centre_ex(background, font, "Negative effect",
186 SCREEN_W/2, SCREEN_H/2, makecol(0, 0, 0), -1);
187
188 /* switch the active color table... */
189 color_map = &negative_table;
190
191 blit(background, temp, 0, 0, 0, 0, 320, 200);
192 rectfill(temp, x, y, x+50, y+50, 0);
193
194 blit(temp, screen, 0, 0, 0, 0, 320, 200);
195
196 while (!keypressed()) {
197 x += deltax;
198 y += deltay;
199
200 if ((x < 1) || (x > 320-50))
201 deltax *= -1;
202
203 if ((y < 1) || (y > 200-50))
204 deltay *= -1;
205
206 blit(background, temp, 0, 0, 0, 0, 320, 200);
207 rectfill(temp, x, y, x+50, y+50, 0);
208 vsync();
209 blit(temp, screen, 0, 0, 0, 0, 320, 200);
210
211 /* slow down the animation for modern machines */
212 rest(1);
213 }
214
215 destroy_bitmap(background);
216 destroy_bitmap(temp);
217
218 return 0;
219 }
220
221 END_OF_MAIN()
222