TAPAKAHATOP,
я как-то переделал загрузку под себя, в принципе тут тоже самое. Надеюсь пригодиться
А вот и код:
cTexture.h
Код:
namespace {
//Converts a four-character array to an integer, using little-endian form
int toInt(const char* bytes) {
return (int)(((unsigned char)bytes[3] << 24) |
((unsigned char)bytes[2] << 16) |
((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
//Converts a two-character array to a short, using little-endian form
short toShort(const char* bytes) {
return (short)(((unsigned char)bytes[1] << 8) |
(unsigned char)bytes[0]);
}
//Reads the next four bytes as an integer, using little-endian form
int readInt(ifstream &input) {
char buffer[4];
input.read(buffer, 4);
return toInt(buffer);
}
//Reads the next two bytes as a short, using little-endian form
short readShort(ifstream &input) {
char buffer[2];
input.read(buffer, 2);
return toShort(buffer);
}
//Just like auto_ptr, but for arrays
template<class T>
class auto_array {
private:
T* array;
mutable bool isReleased;
public:
explicit auto_array(T* array_ = NULL) :
array(array_), isReleased(false) {
}
auto_array(const auto_array<T> &aarray) {
array = aarray.array;
isReleased = aarray.isReleased;
aarray.isReleased = true;
}
~auto_array() {
if (!isReleased && array != NULL) {
delete[] array;
}
}
T* get() const {
return array;
}
T &operator*() const {
return *array;
}
void operator=(const auto_array<T> &aarray) {
if (!isReleased && array != NULL) {
delete[] array;
}
array = aarray.array;
isReleased = aarray.isReleased;
aarray.isReleased = true;
}
T* operator->() const {
return array;
}
T* release() {
isReleased = true;
return array;
}
void reset(T* array_ = NULL) {
if (!isReleased && array != NULL) {
delete[] array;
}
array = array_;
}
T* operator+(int i) {
return array + i;
}
T &operator[](int i) {
return array[i];
}
};
}
//------------------------------------------------------------------------------
// Класс текстуры
class cTexture
{
public:
cTexture(); // конструктор
~cTexture(); // деструктор
// Загрузка TGA файла
bool LoadTGA(char* filename, char* textureName, unsigned int id);
// Загрузка BMP файла
bool LoadBMP(const char* filename);
void Free(bool all = true); // очистка
// Установка параметров текстуры
inline void SetName(char* name) { m_Name = name; } // имя текстуры
inline void SetID(unsigned int id) { m_ID = id; } // идентификатор текстуры
// Установка параметров фильтрации
inline void SetParameterMagFilter(int param)
{
glBindTexture(GL_TEXTURE_2D, m_ID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param);
}
inline void SetParameterMimFilter(int param)
{
glBindTexture(GL_TEXTURE_2D, m_ID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param);
}
// Получаем параметры текстуры
inline bool IsLoaded() { return (m_Data == NULL ? false : true); } // загружена ли текстура
inline unsigned char* GetTexture() { return m_Data; } // текстура
inline unsigned int GetID() { return m_ID; } // идентификатор текстуры
inline char* GetName() { return m_Name; } // имя текстуры
inline char* GetFilename() { return m_Filename; } // имя файла
inline unsigned int GetWidth() { return m_Width; } // ширина
inline unsigned int GetHeight() { return m_Height; } // высота
inline unsigned int GetSize() { return m_Size; } // размер картинки
inline bool IsCompessed() { return m_Compessed; } // сжатый файл или нет
inline unsigned int GetType() { return m_Type; } // тип информация хранимая в *m_Data (GL_RGB или GL_RGBA)
inline bool GetRGBA() { return (m_Bpp == 32 ? true : false); } // тип RGBA?
inline unsigned int GetBytesPerPixel() { return m_BytesPerPixel; } // количество байт на пиксель (3 или 4)
unsigned int m_ID; // идентификатор текстуры для использования совместно с glBindTexture
private:
// Загрузка несжатый файл TGA
bool LoadUncompressedTGA();
// Загрузка сжатого файла TGA
bool LoadCompressedTGA();
char* m_Filename; // имя файла
char* m_Name; // имя текстуры
unsigned char* m_Data; // содержит всю информацию о цвете изображения
unsigned char m_Header[12]; // заголовок файла определяющий его тип (сжатый или несжатый)
unsigned char m_First6Byte[6]; // содержит первые полезные 6 байт файла
bool m_Compessed; // сжатый файл или нет
unsigned int m_Bpp; // содержит кол-во бит на пиксель (24 или 32)
unsigned int m_Width; // ширина изображения
unsigned int m_Height; // высота изображения
unsigned int m_Type; // информация хранимая в *m_Data (GL_RGB или GL_RGBA)
unsigned int m_BytesPerPixel; // количество байт на пиксель (3 или 4)
unsigned int m_Size; // размер памяти необходимый для хранения изображения
int m_ParameterMagFilter; //
int m_ParameterMinFilter; //
// Временные переменные
FILE *m_tempFile;
unsigned int i; // для алгоритмов
short counter; // для цикла
unsigned int pixelcount; // количество пикселей в изображении
unsigned int currentpixel; // пиксель с который мы сейчас считываем
unsigned int currentbyte; // байт который мы зарисуем в Imagedata
unsigned char* colorbuffer; // хранилище для одного пикселя
unsigned int chunkheader; // значение для хранения идентификатора секции
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#endif // cTexture_h
cTexture.cpp
Код:
// Desc: Необходимые постоянные
//------------------------------------------------------------------------------
unsigned char uTGAcompare[12] = {0, 0, 2,0,0,0,0,0,0,0,0,0}; // заголовок несжатого TGA
unsigned char cTGAcompare[12] = {0, 0,10,0,0,0,0,0,0,0,0,0}; // заголовок сжатого TGA
//------------------------------------------------------------------------------
// Name: cTexture() (Constructor)
// Desc: Конструктор
//------------------------------------------------------------------------------
cTexture::cTexture()
{
Free(false); // очищаем
}
//------------------------------------------------------------------------------
// Name: ~cTexture() (Destructor)
// Desc: Деструктор
//------------------------------------------------------------------------------
cTexture::~cTexture()
{
Free(); // очищаем
}
//-----------------------------------------------------------------------------
// Name: LoadTGA() (Public)
// Desc: Загрузка TGA файла
//-----------------------------------------------------------------------------
bool cTexture::LoadTGA(char* filename, char* textureName, unsigned int id)
{
Free(); // очищаем перед загрузкой
m_tempFile = fopen(filename, "rb"); // открываем файл на чтение
if(m_tempFile == NULL) // проверка, если была ошибка
return false; // ошибка, возвращаем
// Попытка прочитать заголовок файла
if(fread(&m_Header, sizeof(m_Header), 1, m_tempFile) == 0)
{
fclose(m_tempFile); // закрываем файл
return false; // ошибка, возвращаем
}
m_Filename = filename; // сохраняем имя файла
m_Name = textureName; // сохраняем имя текстуры
m_ID = id; // установка идентификатора текстуры
// Если заголовок файла соответствует заголовку несжатого файла
if(memcmp(uTGAcompare, &m_Header, sizeof(m_Header)) == 0)
{
if(LoadUncompressedTGA()) // загружаем несжатый TGA, возвращаем
{
glBindTexture(GL_TEXTURE_2D, m_ID); // установка текстуры
// Установка фильтрация
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_ParameterMagFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_ParameterMinFilter);
// Создания текстур
glTexImage2D(GL_TEXTURE_2D,
0,
m_Type,
m_Height,
m_Width,
0,
m_Type,
GL_UNSIGNED_BYTE,
m_Data);
return true; // возвращаем
}
return false; // ошибка, возвращаем
}
// Если заголовок файла соответствует заголовку сжатого файла
else if(memcmp(cTGAcompare, &m_Header, sizeof(m_Header)) == 0)
{
if(LoadCompressedTGA()) // загружаем сжатый TGA, возвращаем
{
glBindTexture(GL_TEXTURE_2D, m_ID); // установка текстуры
// Установка фильтрация
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_ParameterMagFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_ParameterMinFilter);
// Создания текстур
glTexImage2D(GL_TEXTURE_2D,
0,
m_Type,
m_Height,
m_Width,
0,
m_Type,
GL_UNSIGNED_BYTE,
m_Data);
return true; // возвращаем
}
return false; // ошибка, возвращаем
}
else // если не соответствует никакому
{
fclose(m_tempFile); // закрываем файл
return false; // ошибка, возвращаем
}
}
//-----------------------------------------------------------------------------
// Name: LoadUncompressedTGA() (Public)
// Desc: Загрузка несжатого TGA файла
//-----------------------------------------------------------------------------
bool cTexture::LoadUncompressedTGA()
{
m_Compessed = false; // несжатый файл
// Пытаемся прочитать следующие 6 байт
if(fread(m_First6Byte, sizeof(m_First6Byte), 1, m_tempFile) == 0)
{
fclose(m_tempFile); // закрываем файл
return false; // ошибка, возвращаем
}
m_Width = m_First6Byte[1] * 256 + m_First6Byte[0]; // вычисляем высоту
m_Height = m_First6Byte[3] * 256 + m_First6Byte[2];// вычисляем ширину
m_Bpp = m_First6Byte[4]; // вычисляем количество бит на пиксель
// Убеждаемся что вся информация корректна
if((m_Width <= 0) || (m_Height <= 0) || ((m_Bpp != 24) && (m_Bpp != 32)))
{
fclose(m_tempFile); // закрываем файл
Free(); // очищаем всё
return false; // ошибка, возвращаем
}
// Устанавливаем тип изображения
if(m_Bpp == 24)
m_Type = GL_RGB; // установка значения GL_RGB
else
m_Type = GL_RGBA; // установка значения GL_RGBA
m_BytesPerPixel = m_Bpp / 8; // высчитываем количество байт на пиксель (3 или 4)
// Считаем размер памяти необходимый для хранения изображения
m_Size = m_BytesPerPixel * m_Width * m_Height;
// Выделяем память
m_Data = (unsigned char*)malloc(m_Size);
if(m_Data == NULL) // проверка, что память была выделена
{
fclose(m_tempFile); // закрываем файл
return false; // ошибка, возвращаем
}
// Пытаемся считать всё изображение
if(fread(m_Data, 1, m_Size, m_tempFile) != m_Size)
{
fclose(m_tempFile); // закрываем файл
return false; // ошибка, возвращаем
}
// Начинаем цикл перевода данных хранения цвета в файлу TGA (BGR) в формат RGB
for(i = 0; i < (int)m_Size; i += m_BytesPerPixel)
{
// Первый байт XOR третий байт XOR первый байт XOR третий байт
m_Data[i] ^= m_Data[i + 2] ^= m_Data[i] ^= m_Data[i + 2];
}
fclose(m_tempFile); // закрываем файл
return true; // возвращаем
}
//-----------------------------------------------------------------------------
// Name: LoadCompressedTGA() (Public)
// Desc: Загрузка сжатого TGA файла
//-----------------------------------------------------------------------------
bool cTexture::LoadCompressedTGA()
{
m_Compessed = true; // сжатый файл
// Пытаемся прочитать следующие 6 байт
if(fread(m_First6Byte, sizeof(m_First6Byte), 1, m_tempFile) == 0)
{
fclose(m_tempFile); // закрываем файл
return false; // ошибка, возвращаем
}
m_Width = m_First6Byte[1] * 256 + m_First6Byte[0]; // вычисляем высоту
m_Height = m_First6Byte[3] * 256 + m_First6Byte[2];// вычисляем ширину
m_Bpp = m_First6Byte[4]; // вычисляем количество бит на пиксель
// Убеждаемся что вся информация корректна
if((m_Width <= 0) || (m_Height <= 0) || ((m_Bpp != 24) && (m_Bpp != 32)))
{
fclose(m_tempFile); // закрываем файл
Free(); // очищаем всё
return false; // ошибка, возвращаем
}
// Устанавливаем тип изображения
if(m_Bpp == 24)
m_Type = GL_RGB; // установка значения GL_RGB
else
m_Type = GL_RGBA; // установка значения GL_RGBA
m_BytesPerPixel = m_Bpp / 8; // высчитываем количество байт на пиксель (3 или 4)
// Считаем размер памяти необходимый для хранения изображения
m_Size = m_BytesPerPixel * m_Width * m_Height;
// Выделяем память
m_Data = (unsigned char*)malloc(m_Size);
if(m_Data == NULL) // проверка, что память была выделена
{
fclose(m_tempFile); // закрываем файл
return false; // ошибка, возвращаем
}
pixelcount = m_Height * m_Width; // количество пикселей в изображении
currentpixel = 0; // пиксель с который мы сейчас считываем
currentbyte = 0; // байт который мы зарисуем в Imagedata
// Хранилище для одного пикселя
colorbuffer = (unsigned char*)malloc(m_BytesPerPixel);
// Цикл обработки данных
do
{
// Сначала мы читаем заголовок в один байт.
chunkheader = 0; // значение для хранения идентификатора секции
// Пытаемся считать идентификатора секции
if(fread(&chunkheader, sizeof(unsigned char), 1, m_tempFile) == 0)
{
fclose(m_tempFile); // закрываем файл
return false; // ошибка, возвращаем
}
if(chunkheader < 128) // проверка, если секция является 'RAW' секцией
{
chunkheader++; // добавляем единицу для получения кол-ва RAW пикселей
// Цикл чтения пикселей, заполняем данные
for(counter = 0; counter < chunkheader; counter++)
{
// Пытаемся прочитать 1 пиксель
if(fread(colorbuffer, 1, m_BytesPerPixel, m_tempFile) != m_BytesPerPixel)
{
fclose(m_tempFile); // закрываем файл
return false; // ошибка, возвращаем
}
// Заполняем данные, переводя ABGR в RGBA
m_Data[currentbyte] = colorbuffer[2]; // записываем байт 'R'
m_Data[currentbyte + 1] = colorbuffer[1]; // записываем байт 'G'
m_Data[currentbyte + 2] = colorbuffer[0]; // записываем байт 'B'
if(m_BytesPerPixel == 4) // проверка, это 32bpp или 24bpp (есть 'A')
m_Data[currentbyte + 3] = colorbuffer[3]; // записываем байт 'A'
// Увеличиваем счётчик байтов на значение равное кол-ву байт на пиксель
currentbyte += m_BytesPerPixel;
currentpixel++; // увеличиваем кол-во пикселей на 1
}
}
else // если это RLE секция
{
chunkheader -= 127; // вычитаем 127 для получения кол-ва повторений
// Считываем значения следующего цвета, читаем следующий пиксель
if(fread(colorbuffer, 1, m_BytesPerPixel, m_tempFile) != m_BytesPerPixel)
return false; // ошибка, возвращаем
// Цикл чтения пикселей, заполняем данные
for(counter = 0; counter < chunkheader; counter++)
{
// Заполняем данные, переводя ABGR в RGBA
m_Data[currentbyte] = colorbuffer[2]; // записываем байт 'R'
m_Data[currentbyte + 1] = colorbuffer[1]; // записываем байт 'G'
m_Data[currentbyte + 2] = colorbuffer[0]; // записываем байт 'B'
if(m_BytesPerPixel == 4) // проверка, это 32bpp или 24bpp (есть 'A')
m_Data[currentbyte + 3] = colorbuffer[3]; // записываем байт 'A'
// Увеличиваем счётчик байтов на значение равное кол-ву байт на пиксель
currentbyte += m_BytesPerPixel;
currentpixel++; // увеличиваем кол-во пикселей на 1
}
}
} while(currentpixel < pixelcount); // прверка, есть пиксели для чтения
fclose(m_tempFile); // закрываем файл
return true; // возвращаем
}
//------------------------------------------------------------------------------
// Name: Free() (public)
// Desc: Очищаем всё
//------------------------------------------------------------------------------
void cTexture::Free(bool all)
{
//glDeleteTextures(m_Size, &m_ID); // удаляем текстуру из OpenGL
m_Filename = m_Name = NULL; // очищаем имя файла, имя текстуры
if(m_Data != NULL)
delete[] m_Data;
m_Data = NULL; // очищаем информацию о цвете изображения
for(int i = 0; i < 12; i++)
m_Header[i] = NULL; // заголовок файла определяющий его тип (сжатый или нет)
m_Compessed = false; // несжатый файл
m_ParameterMagFilter = m_ParameterMinFilter = GL_LINEAR; //линейная фильтрация
// Идентификатор текстуры,содержит кол-во бит на пиксель (24 или 32), размеры,
// информация хранимая в *m_Data (GL_RGB или GL_RGBA), количество байт на пиксель (3 или 4)
// размер памяти необходимый для хранения изображения
m_ID = m_Bpp = m_Width = m_Height =
m_Type = m_BytesPerPixel = m_Size = -1; // очищаем
// Очищаем временные переменные
m_tempFile = NULL;
i = 0;
counter = 0;
pixelcount = 0; // количество пикселей в изображении
currentpixel = 0; // пиксель с который мы сейчас считываем
currentbyte = 0; // байт который мы зарисуем в Imagedata
colorbuffer = 0; // хранилище для одного пикселя
chunkheader = 0; // значение для хранения идентификатора секции
}
//-----------------------------------------------------------------------------
// Name: LoadBMP() (Public)
// Desc: Загрузка файла BMP
//-----------------------------------------------------------------------------
bool cTexture::LoadBMP(const char* filename)
{
ifstream input;
input.open(filename, ifstream::binary);
//assert(!input.fail() || !"Could not find file");
char buffer[2];
input.read(buffer, 2);
//assert(buffer[0] == 'B' && buffer[1] == 'M' || !"Not a bitmap file");
input.ignore(8);
int dataOffset = readInt(input);
//Read the header
int headerSize = readInt(input);
int width;
int height;
switch(headerSize) {
case 40:
//V3
width = readInt(input);
height = readInt(input);
input.ignore(2);
//assert(readShort(input) == 24 || !"Image is not 24 bits per pixel");
//assert(readShort(input) == 0 || !"Image is compressed");
break;
case 12:
//OS/2 V1
width = readShort(input);
height = readShort(input);
input.ignore(2);
//assert(readShort(input) == 24 || !"Image is not 24 bits per pixel");
break;
case 64:
//OS/2 V2
//assert(!"Can't load OS/2 V2 bitmaps");
break;
case 108:
//Windows V4
//assert(!"Can't load Windows V4 bitmaps");
break;
case 124:
//Windows V5
//assert(!"Can't load Windows V5 bitmaps");
break;
default:
break;
//assert(!"Unknown bitmap format");
}
//Read the data
int bytesPerRow = ((width * 3 + 3) / 4) * 4 - (width * 3 % 4);
int size = bytesPerRow * height;
auto_array<char> pixels(new char[size]);
input.seekg(dataOffset, ios_base::beg);
input.read(pixels.get(), size);
//Get the data into the right format
auto_array<unsigned char> pixels2(new unsigned char[width * height * 3]);
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
for(int c = 0; c < 3; c++) {
pixels2[3 * (width * y + x) + c] =
pixels[bytesPerRow * y + 3 * x + (2 - c)];
}
}
}
input.close();
m_Data = pixels2.release();
m_Width = width;
m_Height = height;
return true;
}