/** ******************************************************************************* * @file ewolTexture.cpp * @brief ewol Texture loading system (sources) * @author Edouard DUPIN * @date 28/10/2011 * @par Project * ewol * * @par Copyright * Copyright 2011 Edouard DUPIN, all right reserved * * This software is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY. * * Licence summary : * You can modify and redistribute the sources code and binaries. * You can send me the bug-fix * * Term of the licence in in the file licence.txt. * ******************************************************************************* */ #include <ewolTexture.h> extern "C" { #pragma pack(push,1) typedef struct { int16_t bfType; int32_t bfSize; int32_t bfReserved; int32_t bfOffBits; } bitmapFileHeader_ts; typedef struct { int32_t biSize; int32_t biWidth; int32_t biHeight; int16_t biPlanes; int16_t biBitCount; int32_t biCompression; int32_t biSizeImage; int32_t biXPelsPerMeter; int32_t biYPelsPerMeter; int32_t biClrUsed; int32_t biClrImportant; } bitmapInfoHeader_ts; #pragma pack(pop) typedef enum { BITS_16_R5G6B5, BITS_16_X1R5G5B5, BITS_24_R8G8B8, BITS_32_X8R8G8B8, BITS_32_A8R8G8B8 } modeBitmap_te; }; #undef __class__ #define __class__ "ewol::Bitmap" class Bitmap { private: modeBitmap_te m_dataMode; int32_t m_width; int32_t m_height; int32_t m_size; uint8_t * m_data; uint8_t * m_dataGenerate; bitmapFileHeader_ts m_FileHeader; bitmapInfoHeader_ts m_InfoHeader; public: Bitmap(etk::File & fileName) : m_data(NULL), m_dataGenerate(NULL) { m_dataMode = BITS_16_R5G6B5; m_width = 0; m_height = 0; m_size = 0; FILE *File=NULL; // Get the fileSize ... if (fileName.Size() < (int32_t)(sizeof(bitmapFileHeader_ts) + sizeof(bitmapInfoHeader_ts) ) ) { EWOL_ERROR("not enought data in the file named=\"" << fileName << "\""); return; } File=fopen(fileName.GetCompleateName().c_str(),"rb"); if(NULL == File) { EWOL_ERROR("Can not find the file name=\"" << fileName << "\""); return; } // get the data : if (fread(&m_FileHeader,sizeof(bitmapFileHeader_ts),1,File) != 1) { EWOL_ERROR("error loading file header"); fclose(File); return; } if (fread(&m_InfoHeader,sizeof(bitmapInfoHeader_ts),1,File) != 1) { EWOL_ERROR("error loading file header"); fclose(File); return; } // TODO : do otherwise ... fseek(File,m_FileHeader.bfOffBits,SEEK_SET); if(ferror(File)) { EWOL_ERROR("error with the 'bfOffBits' in the file named=\"" << fileName << "\""); fclose(File); return; } // Check the header error : if (m_FileHeader.bfType != 0x4D42) { EWOL_ERROR("the file=\"" << fileName << "\" is not a bitmap file ..."); fclose(File); return; } if (m_FileHeader.bfReserved != 0x00000000) { EWOL_ERROR("the bfReserved feald is not at 0 ==> not supported format ..."); fclose(File); return; } if( m_InfoHeader.biBitCount == 16 && m_InfoHeader.biCompression == 0) { m_dataMode = BITS_16_X1R5G5B5; } else if( m_InfoHeader.biBitCount == 16 && m_InfoHeader.biCompression == 3) { m_dataMode = BITS_16_R5G6B5; } else if( m_InfoHeader.biBitCount == 24 && m_InfoHeader.biCompression == 0) { m_dataMode = BITS_24_R8G8B8; } else if( m_InfoHeader.biBitCount == 32 && m_InfoHeader.biCompression == 3) { m_dataMode = BITS_32_X8R8G8B8; } else if( m_InfoHeader.biBitCount == 32 && m_InfoHeader.biCompression == 0) { m_dataMode = BITS_32_A8R8G8B8; } else { EWOL_ERROR("the biBitCount & biCompression fealds are unknow ==> not supported format ..."); fclose(File); return; } m_width = m_InfoHeader.biWidth; m_height = m_InfoHeader.biHeight; if(0 != m_InfoHeader.biSizeImage) { m_data=new uint8_t[m_InfoHeader.biSizeImage]; if (fread(m_data,m_InfoHeader.biSizeImage,1,File) != 1){ EWOL_CRITICAL("Can not read the file with the good size..."); } // allocate the destination data ... m_dataGenerate=new uint8_t[m_width*m_height*4]; } fclose(File); // need now to generate RGBA data ... switch(m_dataMode) { case BITS_16_R5G6B5: { uint16_t * pointer = (uint16_t*)m_data; for(int32_t yyy=0; yyy<m_height; yyy++) { for(int32_t xxx=0; xxx<m_width; xxx++) { m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 0] = (int8_t)((*pointer & 0xF800) >> 8); m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 1] = (int8_t)((*pointer & 0x07E0) >> 3); m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 2] = (int8_t)(*pointer << 3); m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 3] = 0xFF; pointer++; } } } break; case BITS_16_X1R5G5B5: { uint16_t * pointer = (uint16_t*)m_data; for(int32_t yyy=0; yyy<m_height; yyy++) { for(int32_t xxx=0; xxx<m_width; xxx++) { m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 0] = (int8_t)((*pointer & 0x7C00) >> 7); m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 1] = (int8_t)((*pointer & 0x03E0) >> 2); m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 2] = (int8_t)(*pointer << 3); m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 3] = 0xFF; pointer++; } } } break; case BITS_24_R8G8B8: { uint8_t * pointer = m_data; for(int32_t yyy=0; yyy<m_height; yyy++) { for(int32_t xxx=0; xxx<m_width; xxx++) { m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 0] = *pointer++; m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 1] = *pointer++; m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 2] = *pointer++; m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 3] = 0xFF; } } } break; case BITS_32_X8R8G8B8: { uint8_t * pointer = m_data; for(int32_t yyy=0; yyy<m_height; yyy++) { for(int32_t xxx=0; xxx<m_width; xxx++) { pointer++; m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 0] = *pointer++; m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 1] = *pointer++; m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 2] = *pointer++; m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 3] = 0xFF; } } } break; case BITS_32_A8R8G8B8: { uint8_t * pointer = m_data; for(int32_t yyy=0; yyy<m_height; yyy++) { for(int32_t xxx=0; xxx<m_width; xxx++) { m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 0] = *pointer++; m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 1] = *pointer++; m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 2] = *pointer++; m_dataGenerate[4*((m_height-yyy-1) * m_width + xxx ) + 3] = *pointer++; } } } break; default: EWOL_DEBUG(" mode = ERROR"); break; } } ~Bitmap(void) { if (NULL != m_data) { delete(m_data); } if (NULL != m_dataGenerate) { delete(m_dataGenerate); } } bool LoadOK(void) { if (NULL != m_dataGenerate) { return true; } else { return false; } }; int32_t Width(void) { return m_width; }; int32_t Height(void) { return m_height; }; uint8_t * Data(void) { return m_dataGenerate; }; void Display(void) { if (NULL == m_data) { EWOL_ERROR("Might loading error of this Bitmap ..."); return; } EWOL_DEBUG(" -----------------------------------------------------------"); if (false) { EWOL_DEBUG("Display caracteristic of the bitmap : "); EWOL_DEBUG(" Header of file :"); EWOL_DEBUG(" bfType =" << m_FileHeader.bfType << " 19778 : must always be set to 'BM' to declare that this is a .bmp-file."); EWOL_DEBUG(" bfSize =" << m_FileHeader.bfSize << " specifies the size of the file in bytes."); EWOL_DEBUG(" bfReserved=" << m_FileHeader.bfReserved << " must always be set to zero."); EWOL_DEBUG(" bfOffBits =" << m_FileHeader.bfOffBits << " 1078 : specifies the offset from the beginning of the file to the bitmap data."); EWOL_DEBUG(" info header of file :"); EWOL_DEBUG(" biSize =" << m_InfoHeader.biSize << " specifies the size of the BITMAPINFOHEADER structure, in bytes."); EWOL_DEBUG(" biWidth =" << m_InfoHeader.biWidth << " specifies the width of the image, in pixels."); EWOL_DEBUG(" biHeight =" << m_InfoHeader.biHeight << " specifies the height of the image, in pixels."); EWOL_DEBUG(" biPlanes =" << m_InfoHeader.biPlanes << " specifies the number of planes of the target device, must be set to zero."); EWOL_DEBUG(" biBitCount =" << m_InfoHeader.biBitCount << " specifies the number of bits per pixel."); EWOL_DEBUG(" biCompression =" << m_InfoHeader.biCompression << " Specifies the type of compression, usually set to zero (no compression)."); EWOL_DEBUG(" biSizeImage =" << m_InfoHeader.biSizeImage << " specifies the size of the image data, in bytes. If there is no compression, it is valid to set this member to zero."); EWOL_DEBUG(" biXPelsPerMeter=" << m_InfoHeader.biXPelsPerMeter << " specifies the the horizontal pixels per meter on the designated targer device, usually set to zero."); EWOL_DEBUG(" biYPelsPerMeter=" << m_InfoHeader.biYPelsPerMeter << " specifies the the vertical pixels per meter on the designated targer device, usually set to zero."); EWOL_DEBUG(" biClrUsed =" << m_InfoHeader.biClrUsed << " speglTexImage2Dcifies the number of colors used in the bitmap, if set to zero the number of colors is calculated using the biBitCount member."); EWOL_DEBUG(" biClrImportant =" << m_InfoHeader.biClrImportant << " specifies the number of color that are 'important' for the bitmap, if set to zero, all colors are important."); } EWOL_DEBUG("Bitmap : " << m_width << "x" << m_height); switch(m_dataMode) { case BITS_16_R5G6B5: EWOL_DEBUG(" mode = 16 bits R5G6B5"); break; case BITS_16_X1R5G5B5: EWOL_DEBUG(" mode = 16 bits X1R5G5B5"); break; case BITS_24_R8G8B8: EWOL_DEBUG(" mode = 24 bits R8G8B8"); break; case BITS_32_X8R8G8B8: EWOL_DEBUG(" mode = 32 bits X8R8G8B8"); break; case BITS_32_A8R8G8B8: EWOL_DEBUG(" mode = 32 bits A8R8G8B8"); break; default: EWOL_DEBUG(" mode = ERROR"); break; } } }; #include <GL/gl.h> #include <GL/glu.h> class LoadedTexture { public: etk::File m_filename; int32_t m_nbTimeLoaded; int32_t m_imageSize; // must be x=y ... uint32_t m_openGlTextureID; }; etk::VectorType<LoadedTexture*> listLoadedTexture; #undef __class__ #define __class__ "ewol" int32_t ewol::LoadTexture(etk::File fileName) { if (listLoadedTexture.Size()!=0) { for (int32_t iii=0; iii<listLoadedTexture.Size(); iii++) { if (listLoadedTexture[iii]->m_filename == fileName) { listLoadedTexture[iii]->m_nbTimeLoaded++; return listLoadedTexture[iii]->m_openGlTextureID; } } } etk::String fileExtention = fileName.GetExtention(); if (fileExtention == "bmp") { if (false == fileName.Exist()) { EWOL_ERROR("File does not Exist ... " << fileName); return -1; } Bitmap myBitmap(fileName); myBitmap.Display(); if (myBitmap.LoadOK() == true) { if (myBitmap.Width()!= myBitmap.Height()) { EWOL_ERROR("Texture can not have Width=" << myBitmap.Width() << "px different of height=" << myBitmap.Height() << "px in file:" << fileName); return -1; } GLuint textureid; glGenTextures(1, &textureid); glBindTexture(GL_TEXTURE_2D, textureid); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //--- mode nearest //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); //--- Mode linear glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myBitmap.Width(), myBitmap.Height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, myBitmap.Data()); LoadedTexture *tmpTex = new LoadedTexture(); if (NULL != tmpTex) { tmpTex->m_filename = fileName; tmpTex->m_nbTimeLoaded = 1; tmpTex->m_imageSize = myBitmap.Width(); tmpTex->m_openGlTextureID = textureid; listLoadedTexture.PushBack(tmpTex); } else { EWOL_ERROR("Allocation ERROR... "); } return textureid; } else { return -1; } } else { EWOL_ERROR("Extention not managed " << fileName << " Sopported extention : .bmp"); return -1; } } void ewol::UnLoadTexture(uint32_t textureID) { for (int32_t iii=0; iii<listLoadedTexture.Size(); iii++) { if (listLoadedTexture[iii]->m_openGlTextureID == textureID) { listLoadedTexture[iii]->m_nbTimeLoaded--; if (0 == listLoadedTexture[iii]->m_nbTimeLoaded) { EWOL_DEBUG("Remove openGL texture ID=" << textureID << " file:" << listLoadedTexture[iii]->m_filename); glDeleteTextures(1,&listLoadedTexture[iii]->m_openGlTextureID); delete(listLoadedTexture[iii]); listLoadedTexture[iii] = NULL; listLoadedTexture.Erase(iii); } return; } } EWOL_CRITICAL("Can not find TextureId=" << textureID << " in the list of texture loaded...==> to remove it ..."); } int32_t ewol::GetTextureSize(uint32_t textureID) { for (int32_t iii=0; iii<listLoadedTexture.Size(); iii++) { if (listLoadedTexture[iii]->m_openGlTextureID == textureID) { return listLoadedTexture[iii]->m_imageSize; } } EWOL_ERROR("Can not find TextureId=" << textureID << " in the list of texture loaded..."); return -1; }