// ============================================================== // This file is part of Glest Shared Library (www.glest.org) // // Copyright (C) 2001-2008 Martio Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published // by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version // ============================================================== #include "math_wrapper.h" #include "pixmap.h" #include #include #include #include "util.h" #include "math_util.h" #include "randomgen.h" #include "FileReader.h" #include "ImageReaders.h" #include "leak_dumper.h" using namespace Shared::Util; using namespace std; namespace Shared{ namespace Graphics{ using namespace Util; // ===================================================== // file structs // ===================================================== #pragma pack(push, 1) struct BitmapFileHeader{ uint8 type1; uint8 type2; uint32 size; uint16 reserved1; uint16 reserved2; uint32 offsetBits; }; struct BitmapInfoHeader{ uint32 size; int32 width; int32 height; uint16 planes; uint16 bitCount; uint32 compression; uint32 sizeImage; int32 xPelsPerMeter; int32 yPelsPerMeter; uint32 clrUsed; uint32 clrImportant; }; struct TargaFileHeader{ int8 idLength; int8 colourMapType; int8 dataTypeCode; int16 colourMapOrigin; int16 colourMapLength; int8 colourMapDepth; int16 xOrigin; int16 yOrigin; int16 width; int16 height; int8 bitsPerPixel; int8 imageDescriptor; }; #pragma pack(pop) const int tgaUncompressedRgb= 2; const int tgaUncompressedBw= 3; // ===================================================== // class PixmapIoTga // ===================================================== PixmapIoTga::PixmapIoTga(){ file= NULL; } PixmapIoTga::~PixmapIoTga(){ if(file!=NULL){ fclose(file); } } void PixmapIoTga::openRead(const string &path){ file= fopen(path.c_str(),"rb"); if (file==NULL){ throw runtime_error("Can't open TGA file: "+ path); } //read header TargaFileHeader fileHeader; size_t readBytes = fread(&fileHeader, sizeof(TargaFileHeader), 1, file); //check that we can load this tga file if(fileHeader.idLength!=0){ throw runtime_error(path + ": id field is not 0"); } if(fileHeader.dataTypeCode!=tgaUncompressedRgb && fileHeader.dataTypeCode!=tgaUncompressedBw){ throw runtime_error(path + ": only uncompressed BW and RGB targa images are supported"); } //check bits per pixel if(fileHeader.bitsPerPixel!=8 && fileHeader.bitsPerPixel!=24 && fileHeader.bitsPerPixel!=32){ throw runtime_error(path + ": only 8, 24 and 32 bit targa images are supported"); } h= fileHeader.height; w= fileHeader.width; components= fileHeader.bitsPerPixel/8; } void PixmapIoTga::read(uint8 *pixels){ read(pixels, components); } void PixmapIoTga::read(uint8 *pixels, int components){ for(int i=0; icomponents==1){ size_t readBytes = fread(&l, 1, 1, file); r= l; g= l; b= l; a= 255; } else{ size_t readBytes = fread(&b, 1, 1, file); readBytes = fread(&g, 1, 1, file); readBytes = fread(&r, 1, 1, file); if(this->components==4){ readBytes = fread(&a, 1, 1, file); } else{ a= 255; } l= (r+g+b)/3; } switch(components){ case 1: pixels[i]= l; break; case 3: pixels[i]= r; pixels[i+1]= g; pixels[i+2]= b; break; case 4: pixels[i]= r; pixels[i+1]= g; pixels[i+2]= b; pixels[i+3]= a; break; } } } void PixmapIoTga::openWrite(const string &path, int w, int h, int components){ this->w= w; this->h= h; this->components= components; file= fopen(path.c_str(),"wb"); if (file==NULL){ throw runtime_error("Can't open TGA file: "+ path); } TargaFileHeader fileHeader; memset(&fileHeader, 0, sizeof(TargaFileHeader)); fileHeader.dataTypeCode= components==1? tgaUncompressedBw: tgaUncompressedRgb; fileHeader.bitsPerPixel= components*8; fileHeader.width= w; fileHeader.height= h; fileHeader.imageDescriptor= components==4? 8: 0; fwrite(&fileHeader, sizeof(TargaFileHeader), 1, file); } void PixmapIoTga::write(uint8 *pixels){ if(components==1){ fwrite(pixels, h*w, 1, file); } else{ for(int i=0; iw= w; this->h= h; this->components= components; file= fopen(path.c_str(),"wb"); if (file==NULL){ throw runtime_error("Can't open BMP file for writting: "+ path); } BitmapFileHeader fileHeader; fileHeader.type1='B'; fileHeader.type2='M'; fileHeader.offsetBits=sizeof(BitmapFileHeader)+sizeof(BitmapInfoHeader); fileHeader.size=sizeof(BitmapFileHeader)+sizeof(BitmapInfoHeader)+3*h*w; fwrite(&fileHeader, sizeof(BitmapFileHeader), 1, file); //info header BitmapInfoHeader infoHeader; infoHeader.bitCount=24; infoHeader.clrImportant=0; infoHeader.clrUsed=0; infoHeader.compression=0; infoHeader.height= h; infoHeader.planes=1; infoHeader.size=sizeof(BitmapInfoHeader); infoHeader.sizeImage=0; infoHeader.width= w; infoHeader.xPelsPerMeter= 0; infoHeader.yPelsPerMeter= 0; fwrite(&infoHeader, sizeof(BitmapInfoHeader), 1, file); } void PixmapIoBmp::write(uint8 *pixels){ for (int i=0; iw= -1; this->components= components; pixels= NULL; } void Pixmap1D::init(int w, int components){ this->w= w; this->components= components; pixels= new uint8[w*components]; } Pixmap1D::~Pixmap1D(){ delete [] pixels; } void Pixmap1D::load(const string &path){ string extension= path.substr(path.find_last_of('.')+1); if(extension=="bmp"){ loadBmp(path); } else if(extension=="tga"){ loadTga(path); } else{ throw runtime_error("Unknown pixmap extension: "+extension); } this->path = path; } void Pixmap1D::loadBmp(const string &path){ this->path = path; PixmapIoBmp plb; plb.openRead(path); //init if(plb.getH()==1){ w= plb.getW(); } else if(plb.getW()==1){ w= plb.getH(); } else{ throw runtime_error("One of the texture dimensions must be 1"); } if(components==-1){ components= 3; } if(pixels==NULL){ pixels= new uint8[w*components]; } //data plb.read(pixels, components); } void Pixmap1D::loadTga(const string &path){ this->path = path; PixmapIoTga plt; plt.openRead(path); //init if(plt.getH()==1){ w= plt.getW(); } else if(plt.getW()==1){ w= plt.getH(); } else{ throw runtime_error("One of the texture dimensions must be 1"); } int fileComponents= plt.getComponents(); if(components==-1){ components= fileComponents; } if(pixels==NULL){ pixels= new uint8[w*components]; } //read data plt.read(pixels, components); } // ===================================================== // class Pixmap2D // ===================================================== // ===================== PUBLIC ======================== Pixmap2D::Pixmap2D(){ h= -1; w= -1; components= -1; pixels= NULL; } Pixmap2D::Pixmap2D(int components){ init(components); } Pixmap2D::Pixmap2D(int w, int h, int components){ init(w, h, components); } void Pixmap2D::init(int components){ this->w= -1; this->h= -1; this->components= components; pixels= NULL; } void Pixmap2D::init(int w, int h, int components){ this->w= w; this->h= h; this->components= components; pixels= new uint8[h*w*components]; } Pixmap2D::~Pixmap2D(){ delete [] pixels; } Pixmap2D* Pixmap2D::loadPath(const string& path) { Pixmap2D *pixmap = FileReader::readPath(path); if(pixmap != NULL) { pixmap->path = path; } return pixmap; } void Pixmap2D::load(const string &path){ FileReader::readPath(path,this); this->path = path; } void Pixmap2D::save(const string &path){ string extension= path.substr(path.find_last_of('.')+1); if(extension=="bmp"){ saveBmp(path); } else if(extension=="tga"){ saveTga(path); } else{ throw runtime_error("Unknown pixmap extension: "+extension); } } void Pixmap2D::saveBmp(const string &path){ PixmapIoBmp psb; psb.openWrite(path, w, h, components); psb.write(pixels); } void Pixmap2D::saveTga(const string &path){ PixmapIoTga pst; pst.openWrite(path, w, h, components); pst.write(pixels); } void Pixmap2D::getPixel(int x, int y, uint8 *value) const{ for(int i=0; i(value[i]*255.f); } } void Pixmap2D::setComponent(int x, int y, int component, uint8 value){ pixels[(w*y+x)*components+component]= value; } void Pixmap2D::setComponent(int x, int y, int component, float32 value){ pixels[(w*y+x)*components+component]= static_cast(value*255.f); } //vector set void Pixmap2D::setPixel(int x, int y, const Vec3f &p){ for(int i=0; i(p.ptr()[i]*255.f); } } void Pixmap2D::setPixel(int x, int y, const Vec4f &p){ for(int i=0; i(p.ptr()[i]*255.f); } } void Pixmap2D::setPixel(int x, int y, float p){ pixels[(w*y+x)*components]= static_cast(p*255.f); } void Pixmap2D::setPixels(const uint8 *value){ for(int i=0; iavg? 0: ((avg-distLu))*random.randRange(0.5f, 1.0f); float ru= distRu>avg? 0: ((avg-distRu))*random.randRange(0.5f, 1.0f); float ld= distLd>avg? 0: ((avg-distLd))*random.randRange(0.5f, 1.0f); float rd= distRd>avg? 0: ((avg-distRd))*random.randRange(0.5f, 1.0f); float total= lu+ru+ld+rd; Vec4f pix= (leftUp->getPixel4f(i, j)*lu+ rightUp->getPixel4f(i, j)*ru+ leftDown->getPixel4f(i, j)*ld+ rightDown->getPixel4f(i, j)*rd)*(1.0f/total); setPixel(i, j, pix); } } } void Pixmap2D::lerp(float t, const Pixmap2D *pixmap1, const Pixmap2D *pixmap2){ if( !doDimensionsAgree(pixmap1) || !doDimensionsAgree(pixmap2)) { throw runtime_error("Pixmap2D::lerp: pixmap dimensions don't agree"); } for(int i=0; igetPixel4f(i, j).lerp(t, pixmap2->getPixel4f(i, j))); } } } void Pixmap2D::copy(const Pixmap2D *sourcePixmap){ assert(components==sourcePixmap->getComponents()); if(w!=sourcePixmap->getW() || h!=sourcePixmap->getH()){ throw runtime_error("Pixmap2D::copy() dimensions must agree"); } memcpy(pixels, sourcePixmap->getPixels(), w*h*sourcePixmap->getComponents()); } void Pixmap2D::subCopy(int x, int y, const Pixmap2D *sourcePixmap){ assert(components==sourcePixmap->getComponents()); if(wgetW() && hgetH()){ throw runtime_error("Pixmap2D::subCopy(), bad dimensions"); } uint8 *pixel= new uint8[components]; for(int i=0; igetW(); ++i){ for(int j=0; jgetH(); ++j){ sourcePixmap->getPixel(i, j, pixel); setPixel(i+x, j+y, pixel); } } delete [] pixel; } bool Pixmap2D::doDimensionsAgree(const Pixmap2D *pixmap){ return pixmap->getW() == w && pixmap->getH() == h; } // ===================================================== // class Pixmap3D // ===================================================== Pixmap3D::Pixmap3D(){ w= -1; h= -1; d= -1; components= -1; } Pixmap3D::Pixmap3D(int w, int h, int d, int components){ init(w, h, d, components); } Pixmap3D::Pixmap3D(int d, int components){ init(d, components); } void Pixmap3D::init(int w, int h, int d, int components){ this->w= w; this->h= h; this->d= d; this->components= components; pixels= new uint8[h*w*d*components];; } void Pixmap3D::init(int d, int components){ this->w= -1; this->h= -1; this->d= d; this->components= components; pixels= NULL; } void Pixmap3D::init(int components){ this->w= -1; this->h= -1; this->d= -1; this->components= components; pixels= NULL; } Pixmap3D::~Pixmap3D(){ delete [] pixels; } void Pixmap3D::loadSlice(const string &path, int slice){ string extension= path.substr(path.find_last_of('.')+1); if(extension=="bmp"){ loadSliceBmp(path, slice); } else if(extension=="tga"){ loadSliceTga(path, slice); } else{ throw runtime_error("Unknown pixmap extension: "+extension); } this->path = path; } void Pixmap3D::loadSliceBmp(const string &path, int slice){ this->path = path; PixmapIoBmp plb; plb.openRead(path); //init w= plb.getW(); h= plb.getH(); if(components==-1){ components= 3; } if(pixels==NULL){ pixels= new uint8[w*h*d*components]; } //data plb.read(&pixels[slice*w*h*components], components); } void Pixmap3D::loadSliceTga(const string &path, int slice){ this->path = path; PixmapIoTga plt; plt.openRead(path); //header int fileComponents= plt.getComponents(); //init w= plt.getW(); h= plt.getH(); if(components==-1){ components= fileComponents; } if(pixels==NULL){ pixels= new uint8[w*h*d*components]; } //read data plt.read(&pixels[slice*w*h*components], components); } // ===================================================== // class PixmapCube // ===================================================== void PixmapCube::init(int w, int h, int components){ for(int i=0; i<6; ++i){ faces[i].init(w, h, components); } } void PixmapCube::init(int components){ for(int i=0; i<6; ++i){ faces[i].init(components); } } //load & save void PixmapCube::loadFace(const string &path, int face){ this->path[face] = path; faces[face].load(path); } }}//end namespace