/* * Example program for the Allegro library, by Richard Mitton. * * This program sets up a 12-bit mode on any 8-bit card, by * setting up a 256-colour palette that will fool the eye into * grouping two 8-bit pixels into one 12-bit pixel. In order * to do this, you make your 256-colour palette with all the * combinations of blue and green, assuming green ranges from 0-15 * and blue from 0-14. This takes up 16x15=240 colours. This * leaves 16 colours to use as red (red ranges from 0-15). * Then you put your green/blue in one pixel, and your red in * the pixel next to it. The eye gets fooled into thinking it's * all one pixel. * * The example starts setting a normal 256 color mode, and * construct a special palette for it. But then comes the trick: * you need to write to a set of two adjacent pixels to form a * single 12 bit dot. Two eight bit pixels is the same as one 16 * bit pixel, so after setting the video mode you need to hack * the screen bitmap about, halving the width and changing it * to use the 16 bit drawing code. Then, once you have packed a * color into the correct format (using the makecol12() function * below), any of the normal Allegro drawing functions can be * used with this 12 bit display! * * Things to note: * * */ #include /* declare the screen size and mask colour we will use */ #define GFXW 320 #define GFXH 480 #define MASK_COLOR_12 0xFFE0 /* these are specific to this example. They say how big the balls are */ #define BALLW 12 #define BALLH 24 #define BIGBALLW 20 #define BIGBALLH 40 #define MESSAGE_STR "Allegro" typedef struct { fixed x, y; int c; } POINT_T; /* these functions can be used in any 12-bit program */ int makecol12(int r, int g, int b); void set_12bit_palette(void); BITMAP *create_bitmap_12(int w, int h); /* these functions are just for this example */ void blur_12(BITMAP *bmp, BITMAP *back); void rgb_scales_12(BITMAP *bmp, int ox, int oy, int w, int h); POINT_T *make_points(int *numpoints, char *msg); BITMAP *make_ball(int w, int h, int br, int bg, int bb); /* construct the magic palette that makes it all work */ void set_12bit_palette(void) { int r, g, b; PALETTE pal; for (b=0; b<15; b++) { for (g=0; g<16; g++) { pal[b*16+g].r = 0; pal[b*16+g].g = g*63/15; pal[b*16+g].b = b*63/15; } } for (r=0; r<16; r++) { pal[r+240].r = r*63/15; pal[r+240].g = 0; pal[r+240].b = 0; } set_palette(pal); } /* the other magic routine - use this to make colours instead of makecol */ int makecol12(int r, int g, int b) { /* returns a 16-bit integer - here's the format: * * 0xARBG - where A=0xf (reserved, if you like), * R=red (0-15) * B=blue (0-14) * G=green (0-15) */ r = r*16/256; g = g*16/256; b = b*16/256 - 1; if (b < 0) b = 0; return (r << 8) | (b << 4) | g | 0xF000; } /* extract red component from color */ int getr12(int color) { return (color >> 4) & 0xF0; } /* extract green component from color */ int getg12(int color) { return (color << 4) & 0xF0; } /* extract blue component from color */ int getb12(int color) { return (color & 0xF0); } /* use this instead of create_bitmap, because the vtable needs changing * so that the drawing functions will use the 16-bit functions. */ BITMAP *create_bitmap_12(int w, int h) { BITMAP *bmp; bmp = create_bitmap_ex(16, w, h); if (bmp) { bmp->vtable->color_depth = 12; bmp->vtable->mask_color = MASK_COLOR_12; } return bmp; } /* this merges 'bmp' into 'back'. This is how the trails work */ void blur_12(BITMAP *bmp, BITMAP *back) { int x, y, r1, g1, b1, r2, g2, b2, c1, c2; for (y=0; yh; y++) { unsigned short *backline = (unsigned short *)(back->line[y]); unsigned short *bmpline = (unsigned short *)(bmp->line[y]); for (x=0; xw; x++) { /* first get the pixel from each bitmap, then move the first * colour value slightly towards the second. */ c1 = bmpline[x]; c2 = backline[x]; r1 = c1 & 0xF00; r2 = c2 & 0xF00; if (r1 < r2) c1 += 0x100; else if (r1 > r2) c1 -= 0x100; b1 = c1 & 0xF0; b2 = c2 & 0xF0; if (b1 < b2) c1 += 0x10; else if (b1 > b2) c1 -= 0x10; g1 = c1 & 0x0F; g2 = c2 & 0x0F; if (g1 < g2) c1 += 0x01; else if (g1 > g2) c1 -= 0x01; /* then put it back in the bitmap */ bmpline[x] = c1; } } } /* generates some nice RGB scales onto the specified bitmap */ void rgb_scales_12(BITMAP *bmp, int ox, int oy, int w, int h) { int x, y; for (y=0; yh; y++) for (x=0; xw; x++) if (getpixel(bmp, x, y)) n++; points = malloc(n * sizeof(POINT_T)); /* then redo it all, but actually store the points this time */ n = 0; for (y=0; yh; y++) { for (x=0; xw; x++) { if (getpixel(bmp, x, y)) { points[n].x = itofix(x - bmp->w/2) * 6; points[n].y = itofix(y - bmp->h/2) * 12; points[n].c = AL_RAND() % 4; n++; } } } *numpoints = n; destroy_bitmap(bmp); return points; } /* this draws a vector ball. br/bg/bg is the colour of the brightest spot */ BITMAP *make_ball(int w, int h, int br, int bg, int bb) { BITMAP *bmp; int r, rx, ry; bmp = create_bitmap_12(w, h); clear_to_color(bmp, MASK_COLOR_12); for (r=0; r<16; r++) { rx = w*(15-r)/32; ry = h*(15-r)/32; ellipsefill(bmp, w/2, h/2, rx, ry, makecol12(br*r/15, bg*r/15, bb*r/15)); } return bmp; } int main(void) { BITMAP *rgbpic, *ball[4], *buffer, *bigball; int x, r=0, g=0, b=0, numpoints, thispoint; fixed xangle, yangle, zangle, newx, newy, newz; GFX_VTABLE *orig_vtable; POINT_T *points; MATRIX m; if (allegro_init() != 0) return 1; install_keyboard(); /* first set your graphics mode as normal, except twice as wide because * we are using 2-bytes per pixel, but the graphics card doesn't know this. */ if (set_gfx_mode(GFX_AUTODETECT, GFXW * 2, GFXH, 0, 0) != 0) { set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); allegro_message("Error setting %ix%ix12 (really %ix%ix8, but we fake " "it):\n%s\n", GFXW, GFXH, GFXW* 2, GFXH, allegro_error); return 1; } /* then set your magic palette. From now on you can't use the set_color * or set_palette functions or they will mess up this palette. You can * still use the fade routines, if you make sure you fade back into this * palette. */ set_12bit_palette(); /* then hack the vtable so it uses the 16-bit functions */ orig_vtable = screen->vtable; #ifdef ALLEGRO_COLOR16 screen->vtable = &__linear_vtable16; #endif screen->vtable->color_depth = 12; screen->vtable->mask_color = MASK_COLOR_12; screen->vtable->unwrite_bank = orig_vtable->unwrite_bank; screen->w /= sizeof(short); /* reset the clip window to it's new parameters */ set_clip_rect(screen, 0, 0, screen->w-1, screen->h-1); /* then generate 4 vector balls of different colours */ for (x=0; x<4; x++) { switch (x) { case 0: r = 255; g = 0; b = 0; break; case 1: r = 0; g = 255; b = 0; break; case 2: r = 0; g = 0; b = 255; break; case 3: r = 255; g = 255; b = 0; break; } ball[x] = make_ball(BALLW, BALLH, r, g, b); } /* also make one big red vector ball */ bigball = make_ball(BIGBALLW, BIGBALLH, 255, 0, 0); /* make the off-screen buffer that everything will be drawn onto */ buffer = create_bitmap_12(GFXW, GFXH); /* convert the text message into the coordinates of the vector balls */ points = make_points(&numpoints, MESSAGE_STR); /* create the background picture */ rgbpic = create_bitmap_12(GFXW, GFXH); rgb_scales_12(rgbpic, 0, 0, GFXW/2, GFXH/2); /* copy the background into the buffer */ blit(rgbpic, buffer, 0, 0, 0, 0, GFXW, GFXH); xangle = yangle = zangle = 0; /* put a message in the top-left corner */ textprintf_ex(rgbpic, font, 3, 3, makecol12(255, 255, 255), -1, "%ix%i 12-bit colour on an 8-bit card", GFXW, GFXH); textprintf_ex(rgbpic, font, 3, 13, makecol12(255, 255, 255), -1, "(3840 colours at once!)"); while (!keypressed()) { /* first, draw some vector balls moving in a circle round the edge */ for (x=0; xvtable = orig_vtable; fade_out(4); return 0; } END_OF_MAIN()