1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
|
/*
* 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 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 screen modes (don't try Mode-X).
*/
#include "allegro.h"
/* 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();
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; y<bmp->h; y++) {
unsigned short *backline = (unsigned short *)(back->line[y]);
unsigned short *bmpline = (unsigned short *)(bmp->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 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; y<h; y++)
for (x=0; x<w; x++)
putpixel(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++)
putpixel(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++)
putpixel(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++)
putpixel(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)
{
BITMAP *bmp;
POINT_T *points;
int n, x, y;
bmp = create_bitmap_ex(8, text_length(font, msg), text_height(font));
clear_bitmap(bmp);
textout(bmp, font, 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 (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; y<bmp->h; y++) {
for (x=0; x<bmp->w; 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 = 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(int argc, char *argv[])
{
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;
allegro_init();
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*sizeof(short), 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*(int)sizeof(short), 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(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 */
text_mode(-1);
textprintf(rgbpic, font, 3, 3, makecol12(255, 255, 255), "%ix%i 12-bit colour on an 8-bit card", GFXW, GFXH);
textprintf(rgbpic, font, 3, 13, makecol12(255, 255, 255), "(3840 colours at once!)");
while (!keypressed()) {
/* first, draw some vector balls moving in a circle round the edge */
for (x=0; x<itofix(256); x += itofix(32)) {
masked_blit(bigball, buffer, 0, 0,
fixtoi(150 * fixcos(xangle+x)) + GFXW/2 - BALLW/2,
fixtoi(200 * fixsin(xangle+x)) + GFXH/2 - BALLH/2,
BIGBALLW, BIGBALLH);
}
/* rotate the vector balls */
get_rotation_matrix(&m, xangle, yangle, zangle);
for (thispoint=0; thispoint<numpoints; thispoint++) {
apply_matrix(&m, points[thispoint].x,
points[thispoint].y,
0,
&newx, &newy, &newz);
masked_blit(ball[points[thispoint].c], buffer, 0,0,
fixtoi(newx) + GFXW/2,
fixtoi(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 screen */
blit(buffer, screen, 0, 0, 0, 0, GFXW,GFXH);
/* rotate it a bit more */
xangle += itofix(1);
yangle += itofix(1);
zangle += itofix(1);
}
clear_keybuf();
/* clean it all up */
for (x=0; x<4; x++)
destroy_bitmap(ball[x]);
destroy_bitmap(bigball);
free(points);
destroy_bitmap(rgbpic);
destroy_bitmap(buffer);
screen->vtable = orig_vtable;
fade_out(4);
return 0;
}
END_OF_MAIN();
|