//*********************************************************** // // Name: Bitmap.Cpp // Author: Poya Manouchehri // // Description: CBitmap operates on a bitmap. Currently it // can load BMPs and TGAs. All bitmaps (even 8-bit // ones) are converted into full RGBAs. // //*********************************************************** #include "Bitmap.H" #include "RenderPrims.H" CBitmap::CBitmap () { //everthing is 0 m_pBits = NULL; m_Height = m_Width = 0; } CBitmap::~CBitmap () { //destroy the data DestroyData (); } //Load the image from a file FRESULT CBitmap::LoadBitmap (char *path, RESOURCETYPE type) { FILE *ImageFile = NULL; int ImageType; FRESULT Result; CFileResource::SetupParams (path, type); //clean up DestroyData (); ImageFile = fopen (path, "rb"); if (!ImageFile) { return R_FILE_NOOPEN; } ImageType = GetImageType (ImageFile); switch (ImageType) { case FILE_TYPE_BMP: //try to load as a BMP Result = LoadBMP (ImageFile); break; case FILE_TYPE_TGA: //try to load as a TGA Result = LoadTGA (ImageFile); break; default: return R_BADPARAMS; break; } if (Result != R_OK) return R_FAIL; return R_OK; } FRESULT CBitmap::CreateBitmap (RESOURCETYPE type, char *name, int width, int height) { //clean any old data DestroyData (); strcpy (m_Name, name); m_Type = type; m_Width = width; m_Height = height; m_pBits = new unsigned char [m_Width*m_Height*4]; if (!m_pBits) return R_NOMEMORY; return R_OK; } //Get the file format int CBitmap::GetImageType (FILE *file) { short int type; //is the file valid ? if (!file) { fclose(file); return FILE_TYPE_NOSUPPORT; } // Read the first 2 bytes of the file if (fread (&type, 2, 1, file) != 1) { fclose(file); return FILE_TYPE_NOSUPPORT; } rewind(file); // Is it a bitmap ? if (type == 0x4d42) { rewind (file); return FILE_TYPE_BMP; } // TGA's don't have a header ID, so just take a guess rewind(file); return FILE_TYPE_TGA; } //Load a bmp file FRESULT CBitmap::LoadBMP (FILE *file) { BITMAPFILEHEADER bmfileh; BITMAPINFOHEADER bminfoh; RGBQUAD bmColors[256]; //Note: the file format of a BMP file is: // BITMAPFILEHEADER // BITMAPINFOHEADER // RGBQUAD[2^bitcount] // the actual bits (indices in case of an 8 bit bitmap) fread (&bmfileh, sizeof (BITMAPFILEHEADER), 1, file); //read the file header fread (&bminfoh, sizeof (BITMAPINFOHEADER), 1, file); //read the bitmap header m_Width = bminfoh.biWidth; m_Height = abs(bminfoh.biHeight); //read the color table if indexed if (bminfoh.biBitCount < 24) fread (&bmColors, sizeof (RGBQUAD), 256, file); //move to the point where the actual bit data start fseek (file, bmfileh.bfOffBits, SEEK_SET); //load the data return LoadData (file, bminfoh.biBitCount, bmColors); } //Load a TGA file FRESULT CBitmap::LoadTGA (FILE *file) { TGAHeader tgaHeader; int loadedOK = 1; int i, temp; // We have to load the header explicitly, due to some time // weird memory aligning thing that goes on at compile loadedOK &= fread(&tgaHeader.IDLength, 1, 1, file); loadedOK &= fread(&tgaHeader.MapType, 1, 1, file); loadedOK &= fread(&tgaHeader.ImageType, 1, 1, file); loadedOK &= fread(&tgaHeader.MapOrigin, 2, 1, file); loadedOK &= fread(&tgaHeader.MapLength, 2, 1, file); loadedOK &= fread(&tgaHeader.MapEntrySize, 1, 1, file); loadedOK &= fread(&tgaHeader.XOrigin, 2, 1, file); loadedOK &= fread(&tgaHeader.YOrigin, 2, 1, file); loadedOK &= fread(&tgaHeader.Width, 2, 1, file); loadedOK &= fread(&tgaHeader.Height, 2, 1, file); loadedOK &= fread(&tgaHeader.BPP, 1, 1, file); loadedOK &= fread(&tgaHeader.Descriptor, 1, 1, file); // Ensure all elements of the file header were loaded if (!loadedOK) { fclose(file); return R_FAIL; } // Check the image type if (tgaHeader.ImageType != 1 && tgaHeader.ImageType != 2 && tgaHeader.ImageType != 3) { fclose(file); return R_FAIL; } if (tgaHeader.BPP != 24 && tgaHeader.BPP != 32) { fclose(file); return R_FAIL; } // Skip any identification data in the header (we're not interested in that) for (i=0; i>3); i++) fread(&temp, sizeof(unsigned char), 1, file); m_Width = tgaHeader.Width; m_Height = tgaHeader.Height; return LoadData (file, tgaHeader.BPP, NULL); } //Load the actual bits from a file. the table is NULL //unless the image is 8-bit FRESULT CBitmap::LoadData (FILE *file, int bpp, RGBQUAD *table) { unsigned char *TempBits = NULL; //temporary bits which are read straight from the file m_pBits = new unsigned char[m_Width*m_Height*4]; //allocate memory for the bits //this is rather bad: no memory if (!m_pBits) { fclose (file); return R_NOMEMORY; } //read the bits switch (bpp) { case 8: { TempBits = new unsigned char[m_Width*m_Height]; //allocate some memory for temporary bits break; } case 24: { TempBits = new unsigned char[m_Width*m_Height*3]; //allocate some memory for temporary bits break; } case 32: { TempBits = new unsigned char[m_Width*m_Height*4]; //allocate some memory for temporary bits break; } default: { fclose (file); return R_FILE_INVALID; break; } } //no memory if (!TempBits) { fclose (file); return R_NOMEMORY; } //now lets actually read the bits from the file and copy them into //Bits in the proper fashion switch (bpp) { case 8: { //only one channel (8-bit) so there are Width*Height values to read if (fread (TempBits, sizeof (unsigned char), m_Width*m_Height, file) != (unsigned int)(m_Width*m_Height)) { fclose (file); return R_FILE_NOREAD; } //the following loop converts the index data of TempBits, //into actual color data (read from the color table) and //stores it to Bits int i; for (int index=0;index