Really weird error compressing and saving data (c++)

Started by
-1 comments, last by ForeverNoobie 15 years, 3 months ago
Sorry but this is going to be kinda long... So I'm making an application that takes a bitmap and compresses it into a .map file for one of my games. The map data basically consists only of walkable and non walkable area (which is represented by black and white in the bitmap). So I load in a black and white bitmap (which is still 24bpp by the way) and check if tiles of a certain area are white or black, then I bitwise 8 bool values into one byte. I keep going untill the entire thing is encoded. I'm starting with really tiny maps: 128 x 104 pixels.(the game is for cell phones) and each tile is 8x8 (16 tiles across and 13 down). I start with a bitmap thats 39kb and the result is a .map file that is 28 bytes. All of this worked fine untill I decompressed the data on my cell phone emulator and got unexpected results. I searched for the problem for ages but I didn't find it until I opened my .map files in a hex editor (admittedly I'm not great with hex but I figured It might help somehow). For some reason I find that the name of the file is encoded in the map data. For instance for TestMap3.map (made from TestMap3.bmp) this is the hex:

00000000:10 0d 00 00 0c 00 00 00 ff ff ff ff 54 65 73 74  -> ........ÿÿÿÿTest
00000010:4d 61 70 33 2e 62 6d 70 00 00 00 00              ->Map3.bmp....    





Since the file is only just big enough to store the map data, of course it must be obstructed by the name. I can't figure out for the life of me how the name got in my data. All my compression algorithm does is pack 8 bools into a byte depending on whether the tiles are black or white... By the way the file above is made from a bitmap that's totally black, so I expected something to the effect of: 00 00 00 00 00 00... ect. So heres my code. Its rushed and its really nothing fancy... All the cout<< statements are to check values to find errors.

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int* GetBMPData(string,unsigned char**);
int ShrinkData(unsigned char*, int, int, unsigned char**);
void createMap(string, unsigned char* shrunkData, int);
const string FILE_NAME="TestMap3";
const int TILE_DEMENSIONS = 8;
const int WIDTH=0;
const int HEIGHT=1;
int numbytes;

int main()
{
    unsigned char* data;
    unsigned char* compressedData;
    int* demensions = GetBMPData(FILE_NAME.data(), &data);
    int shrankSize=ShrinkData(data, demensions[WIDTH], demensions[HEIGHT], &compressedData);
    createMap(FILE_NAME, compressedData, shrankSize);
    getchar();
}

int* GetBMPData(string bmpFileName, unsigned char** data)
{
    unsigned char offset[4]; //stores the offset to the RGB data
    unsigned char width[4];  //stores the width of the image
    unsigned char height[4]; //stores the height of the image
    bmpFileName+=".bmp";
    ifstream bitstream(bmpFileName.data()); //opens the file passed into the function
    
    bitstream.seekg(10); //seeks to the offset vale
    bitstream.get((char*)offset, 4); 
    
    bitstream.seekg(18); //seek to the width
    bitstream.get((char*)width,4); 
    
    bitstream.seekg(22); //seek to the height
    bitstream.get((char*)height,4); 
  
    numbytes= (*((int*)width)) * (*((int*)height)) * 3; //numbytes equals the width times the height times three (the thre RGB compotents of a pixel) gotta love c++ right?
    
    if((*data)!=NULL)
                 delete (*data);//(this is supposed to prevent memory leaks)
                  
    *data=(unsigned char*) new char[numbytes]; //data equals a new array which is just the right size
    bitstream.seekg(*offset); //seek to the RGB data
    bitstream.get((char*)(*data), numbytes);
    
    bitstream.close(); //close the stream... best to be tidy right?
    cout<<"Offset: "<<*((int*)offset)<<"\nWidth:  "<<*((int*)width)<<"\nHeight: " <<*((int*)height)<<"\n"; //check the values just in case
    
    int* returnVal = new int[2]; // return array for the width and height
    returnVal[WIDTH]=*((int*)width); //put width into first slot 
    returnVal[HEIGHT]=*((int*)height); //and height into second
    
    return returnVal;
}

int ShrinkData(unsigned char* data, int width, int height, unsigned char** shrunk)
{
     int numOfBlack=0;
     int numOfWhite=0;
     int numMapXTiles = width/TILE_DEMENSIONS;
     cout<<width/TILE_DEMENSIONS<<"\n";
     cout<<height/TILE_DEMENSIONS<<"\n";
     int numMapYTiles = height/TILE_DEMENSIONS;
     int eightcount=0;
     int shrunkSize=((numMapXTiles*numMapYTiles)/8) + 2;
     *shrunk = new unsigned char[shrunkSize];
     int offset=2; //offsets the firs two initial values
     (*shrunk)[0]=numMapXTiles;
     (*shrunk)[1]=numMapYTiles;

     for(int i=0; i<numMapYTiles; i++)
     {
             for(int j=0; j<numMapXTiles; j++)
             {
                     int bitPlace= eightcount%8; //this variable is how many places I shift the bits for compression
                     int dataOffset=(i*numMapXTiles*TILE_DEMENSIONS*TILE_DEMENSIONS*3) + (j*TILE_DEMENSIONS*3);
                     unsigned char* shrunkByte=((*shrunk)+(eightcount/8)+ offset);
                     unsigned char bitWiser;
                     unsigned char tileColor=*(data+dataOffset);
                     if( tileColor == 255)
                     {
                         bitWiser=1;
                         numOfWhite++;
                     }
                     else if( tileColor == 0)
                     {
                          bitWiser=0;
                          numOfBlack++;
                     }
                     else
                     {
                         cout<<"Fatal Error: "<<"\n";
                     }
                     //cout<<(i*16)+j<<": "<<(int)tileColor<<"\n";
                     //cout<<(i*16)+j<<": "<<(i*numMapXTiles*TILE_DEMENSIONS*TILE_DEMENSIONS*3) +(j*TILE_DEMENSIONS*3)<<"\n";
                     bitWiser<<bitPlace;
                     *shrunkByte=(*shrunkByte) | bitWiser;
                     eightcount++;
             }
     }

     cout<<"Number of white tiles: "<<numOfWhite<<"\nNumber of black tiles: "<<numOfBlack;
//Note the white and black values are correct here but not after I decompress
     return shrunkSize;
}

void createMap(string fileName, unsigned char* shrankData, int shrankSize)
{
     fileName+=".map";
     ofstream mapFile(fileName.data(), ios::binary);
     mapFile.write((const char*)shrankData,shrankSize);
     mapFile.close();
}





Sorry if thats hard to understand. Like I said its rushed. It was my goal to make the entire map system in one day. I thought it'd be simple enough. I did loads of debugging and cout-ing and I'm certain that all the data is correct when its loaded. The numOfBlack and numOfWhite variables are always right so I figure the compression is working well. For some reason though the .map file only contains the bitmap file name and a bit of useless data. In order for the code to work a white and black bitmap (24bpp) must be in the same path. Best to make it 128x104 if you run it yourself. I'm not sure how flexible it is. I should also tell you that when I used more white tiles (int the example near the top there were 0 white tiles) the name of file begins to get messed up in the hex file. For instance TestMap1 used half white tiles and half black and here's the hex:
00000000:10 0d 00 00 0d 01 00 00 ff ff ff ff 55 65 73 74    ........ÿÿÿÿUest
00000010:4d 61 70 31 2f 63 6d 70 01 01 00 00                Map1/cmp....


if anyone could help me with this I would greatly appreciate it. I'm really eager to get on with development. I'll elaborate on any part of the code that doesn't make sense to anyone. [Edited by - ForeverNoobie on December 26, 2008 6:38:40 PM]
Simplicity is the ultimate sophistication. – Leonardo da Vinci

This topic is closed to new replies.

Advertisement