00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "Image.h"
00026
00027 #include <iostream>
00028 #include <fstream>
00029 #include <cstdlib>
00030
00031 #include "Constants.h"
00032
00033 int Image::readInt(std::ifstream &input) {
00034 char buffer[4];
00035 input.read(buffer, 4);
00036 return (int) (((unsigned char) buffer[3] << 24) |
00037 ((unsigned char) buffer[2] << 16) |
00038 ((unsigned char) buffer[1] << 8) |
00039 (unsigned char) buffer[0]);
00040 }
00041
00042 short Image::readShort(std::ifstream &input) {
00043 char buffer[2];
00044 input.read(buffer, 2);
00045 return (short) (((unsigned char)buffer[1] << 8) |
00046 (unsigned char)buffer[0]);
00047 }
00048
00049 void Image::readBMPFileHeader(std::ifstream &input, BITMAPFILEHEADER *bfh) {
00050 bfh->bfType = readShort(input);
00051 bfh->bfSize = readInt(input);
00052 bfh->bfReserved1 = readShort(input);
00053 bfh->bfReserved2 = readShort(input);
00054 bfh->bfOffBits = readInt(input);
00055 }
00056
00057 void Image::readBMPInfoHeader(std::ifstream &input, BITMAPINFOHEADER *bih) {
00058 bih->biSize = readInt(input);
00059 bih->biWidth = readInt(input);
00060 bih->biHeight = readInt(input);
00061 bih->biPlanes = readShort(input);
00062 bih->biBitCount = readShort(input);
00063 bih->biCompression = readInt(input);
00064 bih->biSizeImage = readInt(input);
00065 bih->biXPelsPerMeter = readInt(input);
00066 bih->biYPelsPerMeter = readInt(input);
00067 bih->biClrUsed = readInt(input);
00068 bih->biClrImportant = readInt(input);
00069 }
00070
00071 void Image::readBMPColorTable(std::ifstream &input, int end, RGBQUAD *table) {
00072 int i, size = (end - input.tellg()) / 4;
00073
00074 for(i = 0; i < size; i++) {
00075 input.read(&(table[i].rgbBlue), 1);
00076 input.read(&(table[i].rgbGreen), 1);
00077 input.read(&(table[i].rgbRed), 1);
00078 input.read(&(table[i].rgbReserved), 1);
00079 }
00080 }
00081
00082 void Image::loadBMP(const char* filename) {
00083 std::ifstream input;
00084 BITMAPFILEHEADER *bfh;
00085 BITMAPINFOHEADER *bih;
00086 RGBQUAD *colorTable;
00087 int bytesPerRow, size, i, j, k, l;
00088 float factor;
00089 char *datas;
00090 char c;
00091
00092
00093 input.open(filename, std::ios::in | std::ifstream::binary);
00094 if(input.fail()) {
00095 std::cerr << filename << " : could not find file" << std::endl;
00096 exit(EXIT_FAILURE);
00097 }
00098
00099
00100 bfh = new BITMAPFILEHEADER;
00101 readBMPFileHeader(input, bfh);
00102
00103
00104 if(bfh->bfType != 0x4D42) {
00105 std::cerr << filename << " : not a bitmap file" << std::endl;
00106 exit(EXIT_FAILURE);
00107 }
00108
00109
00110 bih = new BITMAPINFOHEADER;
00111 readBMPInfoHeader(input, bih);
00112
00113
00114 if(bih->biCompression != 0) {
00115 std::cerr << filename << " : image is compressed" << std::endl;
00116 exit(EXIT_FAILURE);
00117 }
00118
00119
00120 _width = bih->biWidth;
00121 _height = bih->biHeight;
00122
00123
00124
00125
00126 switch(bih->biBitCount) {
00127 case 24:
00128 factor = 3.0;
00129 break;
00130 case 8:
00131 factor = 1.0;
00132 break;
00133 case 4:
00134 factor = 1.0 / 2.0;
00135 break;
00136 case 1:
00137 factor = 1.0 / 8.0;
00138 break;
00139 default:
00140 std::cerr << filename << " : invalid color depth" << std::endl;
00141 exit(EXIT_FAILURE);
00142 }
00143 float x = factor * (float) _width;
00144 int bytesToRead = ((int) x) + (((float) ((int) x)) != x);
00145 bytesPerRow = ((int) (((float) bytesToRead + 3.0) / 4.0)) * 4;
00146 int bytesToSkip = bytesPerRow - bytesToRead;
00147 size = bytesPerRow * _height;
00148
00149
00150 datas = new char[size];
00151
00152 _pixels = new GLubyte[4 * _width * _height];
00153
00154
00155
00156 switch(bih->biBitCount) {
00157 case 24:
00158
00159 input.seekg(bfh->bfOffBits, std::ios::beg);
00160 input.read(datas, size);
00161
00162
00163
00164
00165 for(i = 0; i < _height; i++) {
00166 for(j = 0; j < _width; j++) {
00167 _pixels[4 * (i * _width + j)] = datas[i * bytesPerRow + 3 * j + 2];
00168 _pixels[4 * (i * _width + j) + 1] = datas[i * bytesPerRow + 3 * j + 1];
00169 _pixels[4 * (i * _width + j) + 2] = datas[i * bytesPerRow + 3 * j];
00170 _pixels[4 * (i * _width + j) + 3] = COLOR_MAX;
00171 }
00172 }
00173 break;
00174 case 8:
00175
00176 colorTable = new RGBQUAD[256];
00177 readBMPColorTable(input, bfh->bfOffBits, colorTable);
00178
00179 input.seekg(bfh->bfOffBits, std::ios::beg);
00180 for(i = 0; i < _height; i++) {
00181 for(j = 0; j < _width; j++) {
00182
00183 input.read(&c, 1);
00184
00185
00186 _pixels[4 * (i * _width + j)] = colorTable[c].rgbRed;
00187 _pixels[4 * (i * _width + j) + 1] = colorTable[c].rgbGreen;
00188 _pixels[4 * (i * _width + j) + 2] = colorTable[c].rgbBlue;
00189 _pixels[4 * (i * _width + j) + 3] = COLOR_MAX;
00190 }
00191 input.seekg(bytesToSkip, std::ios::cur);
00192 }
00193 delete colorTable;
00194 break;
00195 case 4:
00196
00197 colorTable = new RGBQUAD[16];
00198 readBMPColorTable(input, bfh->bfOffBits, colorTable);
00199
00200 input.seekg(bfh->bfOffBits, std::ios::beg);
00201 for(i = 0; i < _height; i++) {
00202 for(j = 0; j < _width; j++) {
00203
00204
00205 if((j % 2) == 0) {
00206
00207 input.read(&c, 1);
00208
00209 k = c / 16;
00210 } else {
00211
00212
00213 k = c % 16;
00214 }
00215 _pixels[4 * (i * _width + j)] = colorTable[k].rgbRed;
00216 _pixels[4 * (i * _width + j) + 1] = colorTable[k].rgbGreen;
00217 _pixels[4 * (i * _width + j) + 2] = colorTable[k].rgbBlue;
00218 _pixels[4 * (i * _width + j) + 3] = COLOR_MAX;
00219 }
00220 input.seekg(bytesToSkip, std::ios::cur);
00221 }
00222 delete colorTable;
00223 break;
00224 case 1:
00225
00226 colorTable = new RGBQUAD[2];
00227 readBMPColorTable(input, bfh->bfOffBits, colorTable);
00228
00229 input.seekg(bfh->bfOffBits, std::ios::beg);
00230 for(i = 0; i < _height; i++) {
00231 for(j = 0; j < _width; j += 8) {
00232
00233
00234
00235 input.read(&c, 1);
00236 for(k = 0; k < 8 && 8 * j + k < _width; k++) {
00237
00238 l = (((1 << (7 - k)) & (((int) c) & 0xff)) > 0);
00239 _pixels[4 * (i * _width + j + k)] = colorTable[l].rgbRed;
00240 _pixels[4 * (i * _width + j + k) + 1] = colorTable[l].rgbGreen;
00241 _pixels[4 * (i * _width + j + k) + 2] = colorTable[l].rgbBlue;
00242 _pixels[4 * (i * _width + j + k) + 3] = COLOR_MAX;
00243 }
00244 }
00245 input.seekg(bytesToSkip, std::ios::cur);
00246 }
00247 delete colorTable;
00248 break;
00249 default:
00250 std::cerr << filename << " : invalid color depth" << std::endl;
00251 exit(EXIT_FAILURE);
00252 }
00253
00254
00255 delete bfh;
00256 delete bih;
00257 delete datas;
00258 input.close();
00259 }
00260
00261 Image::Image(const char* filename) {
00262 loadBMP(filename);
00263 }
00264
00265 Image::Image(GLuint width, GLuint height) : _width(width), _height(height) {
00266 int i, size = _width * _height;
00267
00268 _pixels = new GLubyte[4 * size];
00269 for(i = 0; i < size; i++) {
00270 _pixels[i] = COLOR_MIN;
00271 _pixels[i + 1] = COLOR_MIN;
00272 _pixels[i + 2] = COLOR_MIN;
00273 _pixels[i + 3] = COLOR_MAX;
00274 }
00275 }
00276
00277 Image::~Image() {
00278 delete _pixels;
00279 }
00280
00281 GLuint Image::genTexture1D() {
00282 GLuint tex_name;
00283
00284 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00285
00286 glGenTextures(1, &tex_name);
00287
00288 glBindTexture(GL_TEXTURE_1D, tex_name);
00289
00290 glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, _width * _height, 0,
00291 GL_RGBA, GL_UNSIGNED_BYTE, _pixels);
00292
00293
00294 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00295 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00296 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00297
00298 return tex_name;
00299 }
00300
00301 GLuint Image::genTexture2D() {
00302 GLuint tex_name;
00303
00304 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00305
00306 glGenTextures(1, &tex_name);
00307
00308 glBindTexture(GL_TEXTURE_2D, tex_name);
00309
00310 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _width, _height, 0,
00311 GL_RGBA, GL_UNSIGNED_BYTE, _pixels);
00312
00313
00314 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00316 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00317 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00318
00319 return tex_name;
00320 }