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