OpenGL之讀取Targa圖檔

OpenGL之讀取Targa圖檔

『Targa』是常用於3D紋理的『.tga』圖檔,它與『Bitmap』最大的分別是索引、RGB、灰度均支持RLE編碼,當色彩較單調時壓縮效果明顯. 渲染演示程式下載:

它的文檔結構主要由三部份組成:

Targa圖檔結構 簡介
HEADER header; 頭部
PALETTEENTRY palette[256]; 調色板常用於256色模式,灰度模式和RGB模式均無調色板
PBYTE buffer; 位圖數據

 

頭部結構 簡介
BYTE imageIDLength; 圖像頭部的長度
BYTE colorMayType 調色板類型

0=無

1=使用調色盤

BYTE imageTypeCode 圖像類型

0=無圖像數據

1=索引模式

2= RGB模式

3=灰度模式

9=RLE壓縮索引模式

10=RLE壓縮RGB模式

11=RLE壓縮灰度模式

WORD colorMapOrigin 調色板偏移量
WORD colorMapLength 調色板的長度8bit圖檔這個值為256
BYTE colorMapEntrySize 調色板單個條目的大細

有本書居然寫錯左所占空間大細暈

WORD imageXOrigin 圖像左下角的X軸座標總為0
WORD imageYOrigin 圖像左下角的Y軸座標總為0
WORD imageWidth 圖寬
WORD imageHeight 圖高
BYTE bitCount 像素8BIT,16BIT,24BIT,32BIT
BYTE imageDescriptor 圖像原點的位置

 

調色板結構 簡介
BYTE red; 紅色
BYTE green; 綠色
BYTE blue; 藍色

 

載入並分釋TARGA圖檔

bool Load_Targa(TARGA_FILE_PTR targa, PBYTE data,int size)

{

int index;

PBYTE image;

int   image_size;// 圖像字節的長度

int   pixel_size;// 像素大小

int   pixel_count;// 像素個數(寬*高)

memcpy(&targa->header, data, sizeof(TARGA_HEADER));// 讀取頭部數據

image_size = targa->header.imageWidth * targa->header.imageHeight * targa->header.bitCount / 8;

pixel_size = targa->header.bitCount / 8;

pixel_count = targa->header.imageWidth * targa->header.imageHeight;

targa->buffer = (PBYTE)malloc(image_size);// 根據位圖影像的大小申請空間

if (targa->buffer == NULL)

return false;//出錯返回

if (targa->header.imageTypeCode == TARGA_TYPE_INDEXED ||

targa->header.imageTypeCode == TARGA_TYPE_INDEXED_RLE )// 壓縮索引

image = data + sizeof(TARGA_HEADER) + targa->header.imageIDLength + targa->header.colorMapOrigin + (targa->header.colorMapEntrySize / 8) * targa->header.colorMapLength;

else

image = data + sizeof(TARGA_HEADER) + targa->header.imageIDLength ;

if( targa->header.imageTypeCode == TARGA_TYPE_INDEXED ||// 索引

targa->header.imageTypeCode == TARGA_TYPE_RGB     ||// RGB

targa->header.imageTypeCode == TARGA_TYPE_GRAYSCALE)// 灰度

{   // 讀取位圖的圖像

memcpy(targa->buffer, image, image_size);

}

else

if (targa->header.imageTypeCode == TARGA_TYPE_INDEXED_RLE  ||// 壓縮索引

targa->header.imageTypeCode == TARGA_TYPE_RGB_RLE      ||// 壓縮RGB

targa->header.imageTypeCode == TARGA_TYPE_GRAYSCALE_RLE )// 壓縮灰度

{ // RLE解碼

Load_RLE_Targa(targa->buffer, image, image_size, pixel_size);

}

if (targa->header.bitCount == 8)

{   // 計算調色板的入口地址

PBYTE  palette = data + sizeof(TARGA_HEADER) + targa->header.imageIDLength + targa->header.colorMapOrigin;

// RGBQUAD結構與PALETTEENTRY結構的順序調轉了

for (index = 0; index < targa->header.colorMapLength; index++)

{//掉轉調色板的紅色和綠色

targa->palette[index].red   = palette[index *targa->header.colorMapEntrySize/8 + 2];

targa->palette[index].green = palette[index *targa->header.colorMapEntrySize/8 + 1];

targa->palette[index].blue  = palette[index *targa->header.colorMapEntrySize/8 + 0];

targa->palette[index].flags = PC_NOCOLLAPSE;

}

PBYTE temp_buffer = targa->buffer;

//根據圖像的寬高計算記憶體空間(24BIT)

targa->buffer = (UCHAR *)malloc(targa->header.imageWidth * targa->header.imageHeight * 3);

if (targa->buffer == NULL)

return false;//出錯返回

for (index = 0; index < image_size; index++)

{ // 現在將索引值轉為24位值

int color = temp_buffer[index];

if (targa->header.imageTypeCode == TARGA_TYPE_GRAYSCALE ||

targa->header.imageTypeCode == TARGA_TYPE_GRAYSCALE_RLE)

{// 處理灰度圖像

targa->buffer[index * 3 + 0] = color;

targa->buffer[index * 3 + 1] = color;

targa->buffer[index * 3 + 2] = color;

}

else

{

targa->buffer[index * 3 + 0] = targa->palette[color].red;

targa->buffer[index * 3 + 1] = targa->palette[color].green;

targa->buffer[index * 3 + 2] = targa->palette[color].blue;

}

}

targa->header.bitCount = 24;//最後將位圖位數變為24位

}

else

if (targa->header.bitCount == 16)//RGB555

{   // 根據位圖影像的大小申請空間

PBYTE temp_buffer = targa->buffer;

// 根據位圖影像的大小生請空間(位圖為16位但要生成24位空間來保存)

targa->buffer = (UCHAR *)malloc(targa->header.imageWidth * targa->header.imageHeight * 3);

if (targa->buffer == NULL)

{//分配內存空間失敗

free(temp_buffer); // 釋放資源

return false;//出錯返回

}

for (index = 0; index < pixel_count; ++index)

{

WORD color = (temp_buffer[index2 + 1] << 8) | temp_buffer[index2 + 0];

UCHAR red = (((color) >> 10) & 0x1f);

UCHAR green = (((color) >> 5) & 0x1f);

UCHAR blue = ((color) & 0x1f);

targa->buffer[index * 3 + 0] = (red << 3);

targa->buffer[index * 3 + 1] = (green << 3);

targa->buffer[index * 3 + 2] = (blue << 3);

}

targa->header.bitCount = 24;//最後將位圖位數變為24位

free(temp_buffer); // 釋放資源

}

else

if (targa->header.bitCount == 24)

{

for (index = 0; index < image_size; index = index + 3)

{

UCHAR blue = targa->buffer[index + 0];

UCHAR green = targa->buffer[index + 1];

UCHAR red = targa->buffer[index + 2];

targa->buffer[index + 0] = red ;

targa->buffer[index + 2] = blue;

}

}

else

if (targa->header.bitCount == 32)

{

for (index = 0; index < image_size; index = index + 4)

{

//DWORD color;//32的顏色

UCHAR blue = targa->buffer[index + 0];

UCHAR green = targa->buffer[index + 1];

UCHAR red = targa->buffer[index + 2];

targa->buffer[index + 0] = red;

targa->buffer[index + 2] = blue;

}

}

// 判斷圖像原點是否左下角,否則翻轉圖像

if ((targa->header.imageDescriptor & TARGA_ORIGIN_TOP_LEFT) == TARGA_ORIGIN_TOP_LEFT)

Flip_Targa(targa->buffer, targa->header.imageWidth * pixel_size, targa->header.imageHeight);

return true;//

}

 

將顛倒的圖像翻轉過來

image:指向位圖數據

bytes_per_line:圖像每行所占的字節數

height:圖像的高度

bool Flip_Targa(UCHAR *image, int bytes_per_line, int height)

{

UCHAR *buffer; //用於臨時保存位圖數據.

int index;     //循環計數

//根據位圖影像的大小生請空間

buffer = (UCHAR )malloc(bytes_per_lineheight);

if (buffer == NULL)

return false;

// 位圖拷貝

memcpy(buffer, image, bytes_per_line*height);

// 垂直顛倒圖片

for (index = 0; index < height; index++)

memcpy(&image[((height – 1) – index)bytes_per_line], &buffer[indexbytes_per_line], bytes_per_line);

//釋放臨時空間

free(buffer);

return true;//返回

}

評論