I'm currently trying to read bitmaps without using an image library.
My current implementation can read bitmaps ,however, issues occur when both the width and height are not of base 2.
To be more specific, when I tired to render a 922x910 bitmap ,the colors didn't come in correctly. Sometimes bitmaps of different resolutions turnout looking "stretched" and without the correct colors.
To get my bitmaps I let microsoft paint convert png's, jpegs and other formats to .bmp.
The ultimate purpose for all of this is to implement the marching squares method so I can generate polygons from sprites.
How do I deal with this?
My bitmap code so far:
#ifndef COLOR_VECTOR
#define COLOR_VECTOR
struct ColorVector{
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
};
#endif
class uBitmap{
public:
uBitmap(std::string path,BYTE redColorKey, BYTE greenColorKey,BYTE blueColorKey);
~uBitmap();
unsigned int getWidth();
unsigned int getHeight();
long int getPixel(int x, int y);
ColorVector getPixelVector(int x, int y);
void resizeBuffer(unsigned int size);
void clearBuffer();
void putPixel(int x, int y, BYTE r, BYTE g, BYTE b);
void saveBitmap(std::string filename);
void renderImage();
private:
BITMAPFILEHEADER bitmapHeader_;
BITMAPINFOHEADER bitmapInfoHeader_;
BYTE* rgbPixelData_;
BYTE* rgbaPixelData_;
ColorVector colorKey_;
};
uBitmap::uBitmap(std::string path,BYTE redColorKey, BYTE greenColorKey,BYTE blueColorKey){
BITMAPFILEHEADER& fileHeader = bitmapHeader_;
BITMAPINFOHEADER& infoHeader = bitmapInfoHeader_;
BYTE*& pixelData = rgbPixelData_;
bitmapInfoHeader_.biWidth = 0;
bitmapInfoHeader_.biHeight = 0;
rgbPixelData_ = NULL;
rgbaPixelData_ = NULL;
std::ifstream file(path.data(),std::ios::binary);
if(file.is_open()){
file.read((char*)&bitmapHeader_ ,sizeof(BITMAPFILEHEADER));
file.read((char*)&bitmapInfoHeader_,sizeof(BITMAPINFOHEADER));
rgbPixelData_ = new BYTE[infoHeader.biSizeImage];
file.read((char*)rgbPixelData_,infoHeader.biSizeImage);
}
file.close();
}
uBitmap::~uBitmap(){
if(rgbPixelData_ != NULL){
delete[] rgbPixelData_;
}
if(rgbaPixelData_ != NULL){
delete[] rgbaPixelData_;
}
}
unsigned int uBitmap::getWidth(){
return bitmapInfoHeader_.biWidth;
}
unsigned int uBitmap::getHeight(){
return bitmapInfoHeader_.biHeight;
}
/*long int uBitmap::getPixel(int x, int y){// attempting to pack color components into an integer
ColorVector pix = getPixelVector(x,y);
return (pix.b << 24) | (pix.g << 16) | (pix.r << 8) ;
}*/
ColorVector uBitmap::getPixelVector(int x, int y){
ColorVector curElement;
unsigned int firstComponent = (y*getWidth()+x)*3;//which is the blue color vector component
curElement.b = *(rgbPixelData_+firstComponent); //reading first component (blue)
curElement.g = *(rgbPixelData_+firstComponent+1);//reading second component (green)
curElement.r = *(rgbPixelData_+firstComponent+2);//reading third component (red)
return curElement;
}
void uBitmap::renderImage(){
glBegin(GL_POINTS);
for(unsigned int y = 0; y < getHeight();y++){
for(unsigned int x = 0; x < getWidth();x++){
ColorVector c = getPixelVector(x,getHeight() - y);
glColor3ub(c.r,c.g ,c.b);
glVertex2i(x,y);
}
}
glEnd();
}
Please note:I realize that using immediate mode to render a bitmap is a horrible idea,however, its more a debugging function than anything else. Just putting that out there.
*EDIT*
I seemed to have fixed the problem. You guys were completely right about the padding. All I did was slightly modify the constructor to fix my problem:
uBitmap::uBitmap(std::string path,BYTE redColorKey, BYTE greenColorKey,BYTE blueColorKey{
BITMAPFILEHEADER& fileHeader = bitmapHeader_;
BITMAPINFOHEADER& infoHeader = bitmapInfoHeader_;
BYTE*& pixelData = rgbPixelData_;
bitmapInfoHeader_.biWidth = 0;
bitmapInfoHeader_.biHeight = 0;
rgbPixelData_ = NULL;
rgbaPixelData_ = NULL;
std::ifstream file(path.data(),std::ios::binary);
if(file.is_open()){
file.read((char*)&bitmapHeader_ ,sizeof(BITMAPFILEHEADER));
file.read((char*)&bitmapInfoHeader_,sizeof(BITMAPINFOHEADER));
int desiredRow = int(ceilf((((float)getWidth())*3.0f) / 4.0f) * 4.0f);
int rowPadding = desiredRow - (getWidth()*3);
rgbPixelData_ = new BYTE[ (getWidth()*getHeight()*3) + (rowPadding*getHeight());
for(unsigned int I = 0; I < getHeight();I++){
file.read(((char*)rgbPixelData_)+(I*getWidth()*3),desiredRow);
}
}
file.close();
}