#include "GuiImage.h" #include #include int GuiImage::getWidth() { return mWidth; } int GuiImage::getHeight() { return mHeight; } GuiImage::GuiImage(int offsetX, int offsetY, std::string path, unsigned int resizeWidth, unsigned int resizeHeight, bool resizeExact) { mTextureID = 0; mOffsetX = offsetX; mOffsetY = offsetY; //default origin (center of image) mOriginX = 0.5; mOriginY = 0.5; mWidth = 0; mHeight = 0; mTiled = false; mResizeWidth = resizeWidth; mResizeHeight = resizeHeight; mResizeExact = resizeExact; if(!path.empty()) setImage(path); } GuiImage::~GuiImage() { unloadImage(); } void GuiImage::loadImage(std::string path) { //make sure the file *exists* if(!boost::filesystem::exists(path)) { std::cerr << "File \"" << path << "\" not found!\n"; return; } //make sure we don't already have an image unloadImage(); FREE_IMAGE_FORMAT format = FIF_UNKNOWN; FIBITMAP* image = NULL; BYTE* imageData = NULL; unsigned int width, height; //detect the filetype //format = FreeImage_GetFileType(path.c_str(), 0); if(format == FIF_UNKNOWN) format = FreeImage_GetFIFFromFilename(path.c_str()); if(format == FIF_UNKNOWN) { std::cerr << "Error - could not detect filetype for image \"" << path << "\"!\n"; return; } //make sure we can read this filetype first, then load it if(FreeImage_FIFSupportsReading(format)) { image = FreeImage_Load(format, path.c_str()); }else{ std::cerr << "Error - file format reading not supported for image \"" << path << "\"!\n"; return; } //make sure it loaded properly if(!image) { std::cerr << "Error loading image \"" << path << "\"!\n"; return; } //convert to 32bit FIBITMAP* imgConv = FreeImage_ConvertTo32Bits(image); FreeImage_Unload(image); image = imgConv; imageData = FreeImage_GetBits(image); if(!imageData) { std::cerr << "Error retriving bits from image \"" << path << "\"!\n"; return; } width = FreeImage_GetWidth(image); height = FreeImage_GetHeight(image); if(!width || !height) { std::cerr << "Width or height are zero for image \"" << path << "\"!\n"; return; } //convert from BGRA to RGBA GLubyte* imageRGBA = new GLubyte[4*width*height]; for(unsigned int i = 0; i < width*height; i++) { imageRGBA[i*4+0] = imageData[i*4+2]; imageRGBA[i*4+1] = imageData[i*4+1]; imageRGBA[i*4+2] = imageData[i*4+0]; imageRGBA[i*4+3] = imageData[i*4+3]; } //now for the openGL texture stuff glGenTextures(1, &mTextureID); glBindTexture(GL_TEXTURE_2D, mTextureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageRGBA); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); mWidth = width; mHeight = height; //free the image data FreeImage_Unload(image); //free the memory from that pointer delete[] imageRGBA; //a simple way to resize: lie about our real texture size! //(we don't resize tiled images) if(!mTiled) { float resizeScaleX = 0, resizeScaleY = 0; if(mResizeExact) { if(mResizeWidth) resizeScaleX = (float)mResizeWidth / mWidth; if(mResizeHeight) resizeScaleY = (float)mResizeHeight / mHeight; }else{ if(mResizeWidth && mWidth > mResizeWidth) resizeScaleX = (float)mResizeWidth / mWidth; if(mResizeHeight && mHeight > mResizeHeight) resizeScaleY = (float)mResizeHeight / mHeight; } if(resizeScaleX && !resizeScaleY) resizeScaleY = resizeScaleX; if(resizeScaleY && !resizeScaleX) resizeScaleX = resizeScaleY; if(resizeScaleX) mWidth *= resizeScaleX; if(resizeScaleY) mHeight *= resizeScaleY; } //std::cout << "Image load successful, w: " << mWidth << " h: " << mHeight << " texID: " << mTextureID << "\n"; } void GuiImage::unloadImage() { if(mTextureID) { glDeleteTextures(1, &mTextureID); mTextureID = 0; } } void GuiImage::setImage(std::string path) { if(mPath == path) return; mPath = path; unloadImage(); if(!path.empty()) loadImage(path); } void GuiImage::setOrigin(float originX, float originY) { mOriginX = originX; mOriginY = originY; } void GuiImage::setTiling(bool tile) { mTiled = tile; if(mTiled) mResizeExact = false; } void GuiImage::onRender() { if(mTextureID) { if(mTiled) { for(unsigned int x = 0; x < (unsigned int)((float)mResizeWidth/mWidth + 1.5); x++) { for(unsigned int y = 0; y < (unsigned int)((float)mResizeHeight/mHeight + 1.5); y++) { drawImage(mOffsetX + x*mWidth, mOffsetY + y*mHeight); } } }else{ drawImage(mOffsetX, mOffsetY); } } } void GuiImage::drawImage(int posX, int posY) { glBindTexture(GL_TEXTURE_2D, mTextureID); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GLfloat points[12]; points[0] = posX - (mWidth * mOriginX); points[1] = posY - (mHeight * mOriginY); points[2] = posX - (mWidth * mOriginX); points[3] = posY + (mHeight * (1 - mOriginY)); points[4] = posX + (mWidth * (1 - mOriginX)); points[5] = posY - (mHeight * mOriginY); points[6] = posX + (mWidth * (1 - mOriginX)); points[7] = posY - (mHeight * mOriginY); points[8] = posX - (mWidth * mOriginX); points[9] = posY + (mHeight * (1 - mOriginY)); points[10] = posX + (mWidth * (1 -mOriginX)); points[11] = posY + (mHeight * (1 - mOriginY)); //std::cout << "x: " << points[0] << " y: " << points[1] << " to x: " << points[10] << " y: " << points[11] << std::endl; //std::cout << "(w: " << mWidth << " h: " << mHeight << ")" << std::endl; GLfloat texs[12]; texs[0] = 0; texs[1] = 1; texs[2] = 0; texs[3] = 0; texs[4] = 1; texs[5] = 1; texs[6] = 1; texs[7] = 1; texs[8] = 0; texs[9] = 0; texs[10] = 1; texs[11] = 0; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, points); glTexCoordPointer(2, GL_FLOAT, 0, texs); glDrawArrays(GL_TRIANGLES, 0, 6); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); } void GuiImage::onInit() { if(!mPath.empty()) { loadImage(mPath); } } void GuiImage::onDeinit() { unloadImage(); }