Programowanie w języku C/C++ » Artykuły

Bitmapy w C

Tutaj jest krótki kod źrodłowy jak wczytać i wyświetlić bitmape w Borland C...

 * UWAGA! PAMIETAJ ABY USTAWIC "LARGE memory model" !                     *
 * W Borland C: bcc -ml bitmap.c  

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <mem.h>
 
#define VIDEO_INT           0x10      /* przerwanie VIDO dla BIOS */
#define SET_MODE            0x00      /* BIOS funkcja BIOS ustawiająca video */
#define VGA_256_COLOR_MODE  0x13      /* tryb 320 X 200 */
#define TEXT_MODE           0x03      /* 80x25 tryb tekstowy. */
 
#define SCREEN_WIDTH        320       /* szerokosc w pixelach dla trybu 0x13 */
#define SCREEN_HEIGHT       200       /* wysokosc w pixelach dla trybu 0x13 */
#define NUM_COLORS          256       /* liczba kolorow dla trybu 0x13 */
 
typedef unsigned char  byte;
typedef unsigned short word;
typedef unsigned long  dword;
 
byte *VGA=(byte *)0xA0000000L;        /* wskazanie dla adresu pamieci video */
word *my_clock=(word *)0x0000046C;    /* ustawienie zegaru systemowego 18.2hz */
 
typedef struct tagBITMAP              /* struktura bitmapy */
{
  word width;
  word height;
  byte *data;
} BITMAP;
 
/**************************************************************************
 *  fskip                                                                 *
 *     Przeskoki bajtow w pliku                                            *
 **************************************************************************/
 
void fskip(FILE *fp, int num_bytes)
{
   int i;
   for (i=0; i<num_bytes; i++)
      fgetc(fp);
}
 
/**************************************************************************
 *  set_mode                                                              *
 *     Ustaw tryb video                                               *
 **************************************************************************/
 
void set_mode(byte mode)
{
  union REGS regs;
 
  regs.h.ah = SET_MODE;
  regs.h.al = mode;
  int86(VIDEO_INT, &regs, &regs);
}
 
/**************************************************************************
 *  load_bmp                                                              *
 *    Wczytaj bitmape z pliku do pamięci                                  *
 **************************************************************************/
 
void load_bmp(char *file,BITMAP *b)
{
  FILE *fp;
  long index;
  word num_colors;
  int x;
 
  /* otworz plik */
  if ((fp = fopen(file,"rb")) == NULL)
  {
    printf("Blad w otwieraniu pliku %s.\n",file);
    exit(1);
  }
 
  /* zobacz czy to jest poprawny plik bitmapy (kazda bitmapa zaczyna sie od 'BM' wewnatrz pliku */
  if (fgetc(fp)!='B' || fgetc(fp)!='M')
  {
    fclose(fp);
    printf("%s To nie jest plik bitmapy ! \n",file);
    exit(1);
  }
 
  /* przeczytaj szerokosc i wysokosc bitmapy, i liczbe kolorow uzywanych w niej;
  ignoruj reszte ! */
  fskip(fp,16);
  fread(&b->width, sizeof(word), 1, fp);
  fskip(fp,2);
  fread(&b->height,sizeof(word), 1, fp);
  fskip(fp,22);
  fread(&num_colors,sizeof(word), 1, fp);
  fskip(fp,6);
 
  /* zakładamy,że pracujemy na pliku 8 - bitowym */
  if (num_colors==0) num_colors=256;
 
 
  /* alokacja pamięci */
  if ((b->data = (byte *) malloc((word)(b->width*b->height))) == NULL)
  {
    fclose(fp);
    printf("Bład przy alokacji pliku :  %s.\n",file);
    exit(1);
  }
 
  /* Ingoruj informacje na temat palety kolorów.
*/
  fskip(fp,num_colors*4);
 
  /* czytaj bitmape */
  for(index=(b->height-1)*b->width;index>=0;index-=b->width)
    for(x=0;x<b->width;x++)
      b->data[(word)index+x]=(byte)fgetc(fp);
 
  fclose(fp);
}
 
/**************************************************************************
 *  draw_bitmap                                                           *
 *    Draws a bitmap.                                                     *
 **************************************************************************/
 
void draw_bitmap(BITMAP *bmp,int x,int y)
{
  int j;
  word screen_offset = (y<<8)+(y<<6)+x;
  word bitmap_offset = 0;
 
  for(j=0;j<bmp->height;j++)
  {
    memcpy(&VGA[screen_offset],&bmp->data[bitmap_offset],bmp->width);
 
    bitmap_offset+=bmp->width;
    screen_offset+=SCREEN_WIDTH;
  }
}
 
/**************************************************************************
 *  draw_transparent_bitmap                                               *
 *  Rysuje przezroczystą bitmape                                          *
 **************************************************************************/
 
void draw_transparent_bitmap(BITMAP *bmp,int x,int y)
{
  int i,j;
  word screen_offset = (y<<8)+(y<<6);
  word bitmap_offset = 0;
  byte data;
 
  for(j=0;j<bmp->height;j++)
  {
    for(i=0;i<bmp->width;i++,bitmap_offset++)
    {
      data = bmp->data[bitmap_offset];
      if (data) VGA[screen_offset+x+i] = data;
    }
    screen_offset+=SCREEN_WIDTH;
  }
}
 
/**************************************************************************
 *  wait                                                                  *
 *   Oczekuj okreslona liczbe tykniec zegara (18hz).                      *
 **************************************************************************/
 
void wait(int ticks)
{
  word start;
 
  start=*my_clock;
 
  while (*my_clock-start<ticks)
  {
    *my_clock=*my_clock;
  }
}
 
/**************************************************************************
 *  Main                                                                  *
 *    Rysuj nieprzezroczyste i przezroczyste bitmapy                      *
 **************************************************************************/
 
void main()
{
  int i,x,y;
  BITMAP bmp;
 
  load_bmp("BITMAPA1.bmp",&bmp);        /* otwórz plik */
 
  set_mode(VGA_256_COLOR_MODE);       /* ustaw tryb video*/
 
  /* rysuj tło */
  for(i=0;i<200;i++)
    memset(&VGA[320*i],i,SCREEN_WIDTH);
 
  wait(25);
 
  /* rysuj plytke bitmap po lewej stronie*/
  for(y=0;y<=SCREEN_HEIGHT-bmp.height;y+=bmp.height)
    for(x=0;x<=(SCREEN_WIDTH)/2-bmp.width;x+=bmp.width)
      draw_bitmap(&bmp,x,y);
 
  wait(25);
 
  /* rysuj plytke bitmap przezroczysta po prawej stronie */
  for(y=0;y<=SCREEN_HEIGHT-bmp.height;y+=bmp.height)
    for(x=SCREEN_WIDTH-bmp.width;x>=SCREEN_WIDTH/2;x-=bmp.width)
      draw_transparent_bitmap(&bmp,x,y);
 
  wait(100);
 
  free(bmp.data);                     /* zwolnij uzywana pamiec */
 
  set_mode(TEXT_MODE);                /* przywroc z powrotem tryb tekstowy 80X25 */
 
  return;
}

2 komentarze

mario1 2006-09-08 22:18

Trochę dziwne rozwiązanie funkcji pomijania znaków - fskip. Po co po kolei pomijać jeden znak zamiast podaną ilość hurtem za pomocą funkcji ftell/fseek? ;]

Marooned 2005-07-12 01:41

Jest błąd w Coyote i zjada wszelkie znaki < - możesz temu zapobiec póki błąd nie zostanie poprawiony zamieniając wszelkie < na &amp;lt;