Code Search for Developers
 
 
  

ex12bit.c from Allegro game programming library at Krugle


Show ex12bit.c syntax highlighted

/*
 *    Example program for the Allegro library, by Richard Mitton.
 *
 *    or "How to get a 12-bit mode on an 8-bit card"
 *
 *    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.
 *
 *    It's quite simple (sort of). 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.
 *
 *    It's all very simple really. Honest.
 *
 *    To start with, you set a normal 256 color VESA 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 al_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:
 *
 *    The horizontal width is halved, so you get resolutions like 320x480,
 *    400x600, and 512x768.
 *
 *    Because each dot is spread over two actual pixels, the display will
 *    be darker than in a normal video mode.
 *
 *    Any bitmap data will obviously need converting to the correct 12
 *    bit format: regular 15 or 16 bit images won't display correctly...
 *
 *    Although this works like a truecolor mode, it is actually using a
 *    256 color palette, so palette fades are still possible!
 *
 *    Note: This code only works in linear al_screen modes (don't try Mode-X).
 */


#include "allegro.h"



/* declare the al_screen size and mask colour we will use */
#define GFXW            320
#define GFXH            480
#define AL_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();
AL_BITMAP *create_bitmap_12(int w, int h);


/* these functions are just for this example */
void blur_12(AL_BITMAP *bmp, AL_BITMAP *back);
void rgb_scales_12(AL_BITMAP *bmp, int ox, int oy, int w, int h);
POINT_T *make_points(int *numpoints, char *msg);
AL_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;
   AL_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;
   }

   al_set_palette(pal);
}



/* the other magic routine - use this to make colours instead of al_make_color */
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 al_create_bitmap, because the vtable needs changing
 * so that the drawing functions will use the 16-bit functions.
 */
AL_BITMAP *create_bitmap_12(int w, int h)
{
   AL_BITMAP *bmp;

   bmp = al_create_bitmap_ex(16, w, h);

   if (bmp) {
      bmp->vtable->color_depth = 12;
      bmp->vtable->mask_color = AL_MASK_COLOR_12;
   }

   return bmp;
}



/* this merges 'bmp' into 'back'. This is how the trails work */
void blur_12(AL_BITMAP *bmp, AL_BITMAP *back)
{
   int x, y, r1, g1, b1, r2, g2, b2, c1, c2;

   for (y=0; y<bmp->h; y++) {
      unsigned short *backline = (unsigned short *)(back->al_draw_line[y]);
      unsigned short *bmpline = (unsigned short *)(bmp->al_draw_line[y]);

      for (x=0; x<bmp->w; 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 AL_RGB scales onto the specified bitmap */
void rgb_scales_12(AL_BITMAP *bmp, int ox, int oy, int w, int h)
{
   int x, y;

   for (y=0; y<h; y++)
      for (x=0; x<w; x++)
	 al_put_pixel(bmp, ox+x, oy+y, makecol12(x*256/w, y*256/h, 0));

   for (y=0; y<h; y++)
      for (x=0; x<w; x++)
	 al_put_pixel(bmp, ox+x+w, oy+y, makecol12(x*256/w, 0, y*256/h));

   for (y=0; y<h; y++)
      for (x=0; x<w; x++)
	 al_put_pixel(bmp, ox+x, oy+y+h, makecol12(0, x*256/w, y*256/h));

   for (y=0; y<h; y++)
      for (x=0; x<w; x++)
	 al_put_pixel(bmp, ox+x+w, oy+y+h, makecol12(x*128/w+y*128/h,
						 x*128/w+y*128/h,
						 x*128/w+y*128/h));
}



/* turns the string in 'msg' into a series of 2D points. These can then
 * be drawn with the vector balls.
 */
POINT_T *make_points(int *numpoints, char *msg)
{
   AL_BITMAP *bmp;
   POINT_T *points;
   int n, x, y;

   bmp = al_create_bitmap_ex(8, al_text_length(al_font_8x8, msg), al_text_height(al_font_8x8));
   al_clear_bitmap(bmp);
   al_put_text(bmp, al_font_8x8, msg, 0, 0, 1);

   /* first, count how much memory we will need to reserve */
   n = 0;

   for (y=0; y<bmp->h; y++)
      for (x=0; x<bmp->w; x++)
	 if (al_get_pixel(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; y<bmp->h; y++) {
      for (x=0; x<bmp->w; x++) {
	 if (al_get_pixel(bmp, x, y)) {
	    points[n].x = al_int_to_fix(x - bmp->w/2) * 6;
	    points[n].y = al_int_to_fix(y - bmp->h/2) * 12;
	    points[n].c = rand() % 4;
	    n++;
	 }
      }
   }

   *numpoints = n;

   al_destroy_bitmap(bmp);

   return points;
}



/* this draws a vector ball. br/bg/bg is the colour of the brightest spot */
AL_BITMAP *make_ball(int w, int h, int br, int bg, int bb)
{
   AL_BITMAP *bmp;
   int r, rx, ry;
   bmp = create_bitmap_12(w, h); 

   al_clear_to_color(bmp, AL_MASK_COLOR_12);

   for (r=0; r<16; r++) {
      rx = w*(15-r)/32;
      ry = h*(15-r)/32;
      al_draw_ellipse_fill(bmp, w/2, h/2, rx, ry, makecol12(br*r/15, bg*r/15, bb*r/15));
   }

   return bmp;
}



int main(int argc, char *argv[])
{
   AL_BITMAP *rgbpic, *ball[4], *buffer, *bigball;
   int x, r=0, g=0, b=0, numpoints, thispoint;
   fixed xangle, yangle, zangle, newx, newy, newz;
   AL_GFX_VTABLE *orig_vtable;
   POINT_T *points;
   AL_MATRIX m;

   allegro_init();
   al_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 (al_set_gfx_mode(AL_GFX_AUTODETECT, GFXW*sizeof(short), GFXH, 0, 0) != 0) {
      al_set_gfx_mode(AL_GFX_NONE, 0, 0, 0, 0);
      al_show_message("Error setting %ix%ix12 (really %ix%ix8, but we fake it):\n%s\n", GFXW, GFXH, GFXW*(int)sizeof(short), GFXH, al_error);
      return 1;
   }

   /* then set your magic palette. From now on you can't use the al_set_palette_color
    * or al_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 = al_screen->vtable;

   #ifdef ALLEGRO_COLOR16
      al_screen->vtable = &__linear_vtable16;
   #endif

   al_screen->vtable->color_depth = 12;
   al_screen->vtable->mask_color = AL_MASK_COLOR_12;
   al_screen->vtable->unwrite_bank = orig_vtable->unwrite_bank;
   al_screen->w /= sizeof(short);

   /* reset the clip window to it's new parameters */
   al_set_clip(al_screen, 0, 0, al_screen->w-1, al_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-al_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 */
   al_blit(rgbpic, buffer, 0, 0, 0, 0, GFXW, GFXH);

   xangle = yangle = zangle = 0;

   /* put a message in the top-left corner */
   al_text_mode(-1);
   al_printf_text(rgbpic, al_font_8x8, 3, 3, makecol12(255, 255, 255), "%ix%i 12-bit colour on an 8-bit card", GFXW, GFXH);
   al_printf_text(rgbpic, al_font_8x8, 3, 13, makecol12(255, 255, 255), "(3840 colours at once!)");

   while (!al_key_pressed()) {
      /* first, draw some vector balls moving in a al_draw_circle round the edge */
      for (x=0; x<al_int_to_fix(256); x += al_int_to_fix(32)) {
	 al_blit_masked(bigball, buffer, 0, 0,
		     al_fix_to_int(150 * al_fix_cos(xangle+x)) + GFXW/2 - BALLW/2,
		     al_fix_to_int(200 * al_fix_sin(xangle+x)) + GFXH/2 - BALLH/2,
		     BIGBALLW, BIGBALLH);
      }

      /* rotate the vector balls */

      al_get_rotation_matrix(&m, xangle, yangle, zangle);

      for (thispoint=0; thispoint<numpoints; thispoint++) {
	 al_apply_matrix(&m, points[thispoint].x,
			  points[thispoint].y,
			  0,
			  &newx, &newy, &newz);

	 al_blit_masked(ball[points[thispoint].c], buffer, 0,0,
		     al_fix_to_int(newx) + GFXW/2,
		     al_fix_to_int(newy) + GFXH/2, BALLW, BALLH);
      }

      /* then blur the buffer so it fades into the background picture */
      blur_12(buffer, rgbpic);

      /* finally copy everything to the al_screen */
      al_blit(buffer, al_screen, 0, 0, 0, 0, GFXW,GFXH);

      /* rotate it a bit more */
      xangle += al_int_to_fix(1);
      yangle += al_int_to_fix(1);
      zangle += al_int_to_fix(1);
   }

   al_clear_keybuf();

   /* clean it all up */
   for (x=0; x<4; x++)
      al_destroy_bitmap(ball[x]);

   al_destroy_bitmap(bigball);
   free(points);

   al_destroy_bitmap(rgbpic);
   al_destroy_bitmap(buffer);
   
   al_screen->vtable = orig_vtable;
   al_fade_out(4);

   return 0;
}

AL_END_OF_MAIN();




See more files for this project here

Allegro game programming library

Allegro is a cross-platform library intended for use in computer games and other types of multimedia programming.

Project homepage: http://sourceforge.net/projects/alleg
Programming language(s): Assembly,C,Shell Script
License: other

  allegro.pcx
  ex12bit.c
  ex3buf.c
  ex3d.c
  exaccel.c
  exalpha.c
  example.dat
  example.h
  examples.txt
  exbitmap.c
  exblend.c
  excamera.c
  excolmap.c
  excustom.c
  exdata.c
  exdbuf.c
  exdodgy.c
  exexedat.c
  exfixed.c
  exflame.c
  exflip.c
  exgui.c
  exhello.c
  exjoy.c
  exkeys.c
  exlights.c
  exmem.c
  exmidi.c
  exmouse.c
  expal.c
  expat.c
  exquat.c
  exrgbhsv.c
  exsample.c
  exscale.c
  exscn3d.c
  exscroll.c
  exshade.c
  exspline.c
  exsprite.c
  exstars.c
  exstream.c
  exswitch.c
  extimer.c
  extrans.c
  extruec.c
  exunicod.c
  exupdate.c
  exxfade.c
  exzbuf.c
  mysha.pcx
  planet.pcx
  running.dat
  running.h
  unifont.dat