/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Functions for drawing to GDI without using DirectX. * * By Marian Dvorsky. * * See readme.txt for copyright information. */ #include "allegro.h" #include "allegro/internal/aintern.h" #include "allegro/platform/aintwin.h" #ifndef ALLEGRO_WINDOWS #error something is wrong with the makefile #endif static HPALETTE current_hpalette = NULL; /* set_gdi_color_format: * Sets right values for pixel color format to work with GDI. */ void set_gdi_color_format(void) { _rgb_r_shift_15 = 10; _rgb_g_shift_15 = 5; _rgb_b_shift_15 = 0; _rgb_r_shift_16 = 11; _rgb_g_shift_16 = 5; _rgb_b_shift_16 = 0; _rgb_r_shift_24 = 16; _rgb_g_shift_24 = 8; _rgb_b_shift_24 = 0; _rgb_r_shift_32 = 16; _rgb_g_shift_32 = 8; _rgb_b_shift_32 = 0; } /* destroy_current_hpalette: * Destroys the current Windows PALETTE. */ static void destroy_current_hpalette(void) { if (current_hpalette) { DeleteObject(current_hpalette); current_hpalette = NULL; } _remove_exit_func(destroy_current_hpalette); } /* set_palette_to_hdc: * Selects and realizes an Allegro PALETTE to a Windows DC. */ void set_palette_to_hdc(HDC dc, PALETTE pal) { PALETTEENTRY palPalEntry[256]; int i; if (current_hpalette) { for (i = 0; i < 256; i++) { palPalEntry[i].peRed = _rgb_scale_6[pal[i].r]; palPalEntry[i].peGreen = _rgb_scale_6[pal[i].g]; palPalEntry[i].peBlue = _rgb_scale_6[pal[i].b]; palPalEntry[i].peFlags = 0; } SetPaletteEntries(current_hpalette, 0, 256, (LPPALETTEENTRY) & palPalEntry); } else { current_hpalette = convert_palette_to_hpalette(pal); _add_exit_func(destroy_current_hpalette, "destroy_current_hpalette"); } SelectPalette(dc, current_hpalette, FALSE); RealizePalette(dc); select_palette(pal); } /* convert_palette_to_hpalette: * Converts an Allegro PALETTE to a Windows PALETTE. */ HPALETTE convert_palette_to_hpalette(PALETTE pal) { HPALETTE hpal; LOGPALETTE *lp; int i; lp = (LOGPALETTE *) malloc(sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * 256); if (!lp) return NULL; lp->palNumEntries = 256; lp->palVersion = 0x300; for (i = 0; i < 256; i++) { lp->palPalEntry[i].peRed = _rgb_scale_6[pal[i].r]; lp->palPalEntry[i].peGreen = _rgb_scale_6[pal[i].g]; lp->palPalEntry[i].peBlue = _rgb_scale_6[pal[i].b]; lp->palPalEntry[i].peFlags = 0; } hpal = CreatePalette(lp); free(lp); return hpal; } /* convert_hpalette_to_palette: * Converts a Windows PALETTE to an Allegro PALETTE. */ void convert_hpalette_to_palette(HPALETTE hpal, PALETTE pal) { PALETTEENTRY lp[256]; int i; GetPaletteEntries(hpal, 0, 256, (LPPALETTEENTRY) & lp); for (i = 0; i < 256; i++) { pal[i].r = lp[i].peRed >> 2; pal[i].g = lp[i].peGreen >> 2; pal[i].b = lp[i].peBlue >> 2; } } /* get_bitmap_info: * Returns a BITMAPINFO structure suited to an Allegro BITMAP. * You have to free the memory allocated by this function. */ static BITMAPINFO *get_bitmap_info(BITMAP *bitmap, PALETTE pal) { BITMAPINFO *bi; int bpp, i; bi = (BITMAPINFO *) malloc(sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 256); bpp = bitmap_color_depth(bitmap); if (bpp == 15) bpp = 16; ZeroMemory(&bi->bmiHeader, sizeof(BITMAPINFOHEADER)); bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi->bmiHeader.biBitCount = bpp; bi->bmiHeader.biPlanes = 1; bi->bmiHeader.biWidth = bitmap->w; bi->bmiHeader.biHeight = -bitmap->h; bi->bmiHeader.biClrUsed = 256; bi->bmiHeader.biCompression = BI_RGB; if (pal) { for (i = 0; i < 256; i++) { bi->bmiColors[i].rgbRed = _rgb_scale_6[pal[i].r]; bi->bmiColors[i].rgbGreen = _rgb_scale_6[pal[i].g]; bi->bmiColors[i].rgbBlue = _rgb_scale_6[pal[i].b]; bi->bmiColors[i].rgbReserved = 0; } } return bi; } /* get_dib_from_bitmap: * Creates a Windows device-independent bitmap (DIB) from an Allegro BITMAP. * You have to free the memory allocated by this function. */ static BYTE *get_dib_from_bitmap(BITMAP *bitmap) { int bpp; int x, y; int pitch; int col; BYTE *pixels; BYTE *src, *dst; bpp = bitmap_color_depth(bitmap); pitch = bitmap->w * BYTES_PER_PIXEL(bpp); pitch = (pitch + 3) & ~3; /* align on dword */ pixels = (BYTE *) malloc(bitmap->h * pitch); if (!pixels) return NULL; switch (bpp) { case 8: for (y = 0; y < bitmap->h; y++) { memcpy(pixels + y * pitch, bitmap->line[y], bitmap->w); } break; case 15: if ((_rgb_r_shift_15 == 10) && (_rgb_g_shift_15 == 5) && (_rgb_b_shift_15 == 0)) { for (y = 0; y < bitmap->h; y++) memcpy(pixels + y * pitch, bitmap->line[y], bitmap->w * 2); } else { for (y = 0; y < bitmap->h; y++) { src = bitmap->line[y]; dst = pixels + y * pitch; for (x = 0; x < bitmap->w; x++) { col = *(WORD *) (src); *((WORD *) (dst)) = (WORD) ((getb15(col) >> 3) | ((getg15(col) >> 3) << 5) | ((getr15(col) >> 3) << 10)); src += 2; dst += 2; } } } break; case 16: /* the format of a 16-bit DIB is 5-5-5 as above */ for (y = 0; y < bitmap->h; y++) { src = bitmap->line[y]; dst = pixels + y * pitch; for (x = 0; x < bitmap->w; x++) { col = *(WORD *) (src); *((WORD *) (dst)) = (WORD) ((getb16(col) >> 3) | ((getg16(col) >> 3) << 5) | ((getr16(col) >> 3) << 10)); src += 2; dst += 2; } } break; case 24: if ((_rgb_r_shift_24 == 16) && (_rgb_g_shift_24 == 8) && (_rgb_b_shift_24 == 0)) { for (y = 0; y < bitmap->h; y++) memcpy(pixels + y * pitch, bitmap->line[y], bitmap->w * 3); } else { for (y = 0; y < bitmap->h; y++) { src = bitmap->line[y]; dst = pixels + y * pitch; for (x = 0; x < bitmap->w; x++) { col = *(DWORD *) (src); src += 3; *(dst++) = getb24(col); *(dst++) = getg24(col); *(dst++) = getr24(col); } } } break; case 32: if ((_rgb_r_shift_32 == 16) && (_rgb_g_shift_32 == 8) && (_rgb_b_shift_32 == 0)) { for (y = 0; y < bitmap->h; y++) memcpy(pixels + y * pitch, bitmap->line[y], bitmap->w * 4); } else { for (y = 0; y < bitmap->h; y++) { src = bitmap->line[y]; dst = pixels + y * pitch; for (x = 0; x < bitmap->w; x++) { col = *(DWORD *) (src); src += 4; *(dst++) = getb32(col); *(dst++) = getg32(col); *(dst++) = getr32(col); dst++; } } } break; } return pixels; } /* get_dib_from_hbitmap: * Creates a Windows device-independent bitmap (DIB) from a Windows BITMAP. * You have to free the memory allocated by this function. */ static BYTE *get_dib_from_hbitmap(int bpp, HBITMAP hbitmap) { BITMAPINFOHEADER bi; BITMAPINFO *binfo; HDC hdc; HPALETTE hpal, holdpal; int col; WINDOWS_BITMAP bm; int pitch; BYTE *pixels; BYTE *ptr; int x, y; if (!hbitmap) return NULL; if (bpp == 15) bpp = 16; if (!GetObject(hbitmap, sizeof(bm), (LPSTR) & bm)) return NULL; pitch = bm.bmWidth * BYTES_PER_PIXEL(bpp); pitch = (pitch + 3) & ~3; /* align on dword */ pixels = (BYTE *) malloc(bm.bmHeight * pitch); if (!pixels) return NULL; ZeroMemory(&bi, sizeof(BITMAPINFOHEADER)); bi.biSize = sizeof(BITMAPINFOHEADER); bi.biBitCount = bpp; bi.biPlanes = 1; bi.biWidth = bm.bmWidth; bi.biHeight = -abs(bm.bmHeight); bi.biClrUsed = 256; bi.biCompression = BI_RGB; binfo = malloc(sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 256); binfo->bmiHeader = bi; hdc = GetDC(NULL); hpal = convert_palette_to_hpalette(_current_palette); holdpal = SelectPalette(hdc, hpal, TRUE); RealizePalette(hdc); GetDIBits(hdc, hbitmap, 0, bm.bmHeight, pixels, binfo, DIB_RGB_COLORS); ptr = pixels; /* This never occurs, because if screen or memory bitmap is 8-bit, * we ask Windows to convert it to truecolor. It is safer, but a little * bit slower. */ if (bpp == 8) { for (y = 0; y < bm.bmWidth; y++) { for (x = 0; x < bm.bmHeight; x++) { col = *ptr; if ((col < 10) || (col >= 246)) { /* we have to remap colors from system palette */ *(ptr++) = makecol8(binfo->bmiColors[col].rgbRed, binfo->bmiColors[col].rgbGreen, binfo->bmiColors[col].rgbBlue); } else { /* our palette is shifted by 10 */ *(ptr++) = col - 10; } } } } free(binfo); SelectPalette(hdc, holdpal, TRUE); DeleteObject(hpal); ReleaseDC(NULL, hdc); return pixels; } /* get_bitmap_from_dib: * Creates an Allegro BITMAP from a Windows device-independent bitmap (DIB). */ static BITMAP *get_bitmap_from_dib(int bpp, int w, int h, BYTE *pixels) { int x, y; int pitch; int col; int b, g, r; BYTE *src, *dst; BITMAP *bitmap; bitmap = create_bitmap_ex(bpp, w, h); pitch = bitmap->w * BYTES_PER_PIXEL(bpp); pitch = (pitch + 3) & ~3; /* align on dword */ switch (bpp) { case 8: for (y = 0; y < bitmap->h; y++) { memcpy(bitmap->line[y], pixels + y * pitch, bitmap->w); } break; case 15: if ((_rgb_r_shift_15 == 10) && (_rgb_g_shift_15 == 5) && (_rgb_b_shift_15 == 0)) { for (y = 0; y < bitmap->h; y++) memcpy(bitmap->line[y], pixels + y * pitch, bitmap->w * 2); } else { for (y = 0; y < bitmap->h; y++) { dst = bitmap->line[y]; src = pixels + y * pitch; for (x = 0; x < bitmap->w; x++) { col = *(WORD *) (src); *((WORD *) (dst)) = makecol15(_rgb_scale_5[(col >> 10) & 0x1F], _rgb_scale_5[(col >> 5) & 0x1F], _rgb_scale_5[col & 0x1F]); src += 2; dst += 2; } } } break; case 16: /* the format of a 16-bit DIB is 5-5-5 as above */ for (y = 0; y < bitmap->h; y++) { dst = bitmap->line[y]; src = pixels + y * pitch; for (x = 0; x < bitmap->w; x++) { col = *(WORD *) (src); *((WORD *) (dst)) = makecol16(_rgb_scale_5[(col >> 10) & 0x1F], _rgb_scale_5[(col >> 5) & 0x1F], _rgb_scale_5[col & 0x1F]); src += 2; dst += 2; } } break; case 24: if ((_rgb_r_shift_24 == 16) && (_rgb_g_shift_24 == 8) && (_rgb_b_shift_24 == 0)) { for (y = 0; y < bitmap->h; y++) memcpy(bitmap->line[y], pixels + y * pitch, bitmap->w * 3); } else { for (y = 0; y < bitmap->h; y++) { dst = bitmap->line[y]; src = pixels + y * pitch; for (x = 0; x < bitmap->w; x++) { r = *(src++); g = *(src++); b = *(src++); col = makecol24(r, g, b); *((WORD *) dst) = (col & 0xFFFF); dst += 2; *(dst++) = (col >> 16); } } } break; case 32: if ((_rgb_r_shift_32 == 16) && (_rgb_g_shift_32 == 8) && (_rgb_b_shift_32 == 0)) { for (y = 0; y < bitmap->h; y++) memcpy(bitmap->line[y], pixels + y * pitch, bitmap->w * 4); } else { for (y = 0; y < bitmap->h; y++) { dst = bitmap->line[y]; src = pixels + y * pitch; for (x = 0; x < bitmap->w; x++) { b = *(src++); g = *(src++); r = *(src++); col = makecol32(r, g, b); src++; *((DWORD *) dst) = col; dst += 4; } } } break; } return bitmap; } /* convert_bitmap_to_hbitmap: * Converts an Allegro BITMAP to a Windows BITMAP. */ HBITMAP convert_bitmap_to_hbitmap(BITMAP *bitmap) { HDC hdc; HBITMAP hbmp; BITMAPINFO *bi; HPALETTE hpal, holdpal; BYTE *pixels; /* get the DIB first */ bi = get_bitmap_info(bitmap, NULL); pixels = get_dib_from_bitmap(bitmap); hpal = convert_palette_to_hpalette(_current_palette); /* now that we have the DIB, convert it to a DDB */ hdc = GetDC(NULL); holdpal = SelectPalette(hdc, hpal, TRUE); RealizePalette(hdc); hbmp = CreateDIBitmap(hdc, &bi->bmiHeader, CBM_INIT, pixels, bi, DIB_RGB_COLORS); ReleaseDC(NULL, hdc); SelectPalette(hdc, holdpal, TRUE); DeleteObject(hpal); free(pixels); free(bi); return hbmp; } /* convert_hbitmap_to_bitmap: * Converts a Windows BITMAP to an Allegro BITMAP. */ BITMAP *convert_hbitmap_to_bitmap(HBITMAP bitmap) { BYTE *pixels; BITMAP *bmp; WINDOWS_BITMAP bm; int bpp; if (!GetObject(bitmap, sizeof(bm), (LPSTR) & bm)) return NULL; if (bm.bmBitsPixel == 8) { /* ask windows to save truecolor image, then convert to our format */ bpp = 24; } else bpp = bm.bmBitsPixel; /* get the DIB first */ pixels = get_dib_from_hbitmap(bpp, bitmap); /* now that we have the DIB, convert it to a BITMAP */ bmp = get_bitmap_from_dib(bpp, bm.bmWidth, bm.bmHeight, pixels); free(pixels); return bmp; } /* draw_to_hdc: * Draws an entire Allegro BITMAP to a Windows DC. Has a syntax similar to draw_sprite(). */ void draw_to_hdc(HDC dc, BITMAP *bitmap, int x, int y) { stretch_blit_to_hdc(bitmap, dc, 0, 0, bitmap->w, bitmap->h, x, y, bitmap->w, bitmap->h); } /* blit_to_hdc: * Blits an Allegro BITMAP to a Windows DC. Has a syntax similar to blit(). */ void blit_to_hdc(BITMAP *bitmap, HDC dc, int src_x, int src_y, int dest_x, int dest_y, int w, int h) { stretch_blit_to_hdc(bitmap, dc, src_x, src_y, w, h, dest_x, dest_y, w, h); } /* stretch_blit_to_hdc: * Blits an Allegro BITMAP to a Windows DC. Has a syntax similar to stretch_blit(). */ void stretch_blit_to_hdc(BITMAP *bitmap, HDC dc, int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, int dest_w, int dest_h) { BYTE *pixels; BITMAPINFO *bi; bi = get_bitmap_info(bitmap, _current_palette); pixels = get_dib_from_bitmap(bitmap); StretchDIBits(dc, dest_x, dest_y, dest_w, dest_h, src_x, bitmap->h - src_y - src_h, src_w, src_h, pixels, bi, DIB_RGB_COLORS, SRCCOPY); free(pixels); free(bi); } /* blit_from_hdc: * Blits from a Windows DC to an Allegro BITMAP. Has a syntax similar to blit(). */ void blit_from_hdc(HDC dc, BITMAP *bitmap, int src_x, int src_y, int dest_x, int dest_y, int w, int h) { stretch_blit_from_hdc(dc, bitmap, src_x, src_y, w, h, dest_x, dest_y, w, h); } /* stretch_blit_from_hdc: * Blits from a Windows DC to an Allegro BITMAP. Has a syntax similar to stretch_blit(). */ void stretch_blit_from_hdc(HDC dc, BITMAP *bitmap, int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, int dest_w, int dest_h) { HBITMAP hbmp, holdbmp; HDC hmemdc; BITMAP *newbmp; hmemdc = CreateCompatibleDC(dc); hbmp = CreateCompatibleBitmap(dc, dest_w, dest_h); holdbmp = SelectObject(hmemdc, hbmp); StretchBlt(hmemdc, 0, 0, dest_w, dest_h, dc, src_x, src_y, src_w, src_h, SRCCOPY); SelectObject(hmemdc, holdbmp); newbmp = convert_hbitmap_to_bitmap(hbmp); blit(newbmp, bitmap, 0, 0, dest_x, dest_y, dest_w, dest_h); destroy_bitmap(newbmp); DeleteObject(hbmp); DeleteDC(hmemdc); }