OpenGL顯示圖片

最近想用C++在windows下實現一個基本的圖像查看器功能,目前只想到了使用GDI或OpenGL兩種方式。因爲實在不想用GDI的API了,就用OpenGL的方式實現了一下基本的顯示功能。ios

用GDAL讀取圖像,這樣就能與圖像格式無關。OpenGL的glDrawPixels()函數也能實現圖像顯示,可是如今高版本的OpenGL都採用glTexImage2D()貼紋理的方式了,也不用考慮圖像大小是不是2的N次方,或者4字節對齊的問題。具體實現以下:windows

// ImageShow.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#include "ImageShow.h"

#include <iostream>
#include <gl\glew.h>            // 包含最新的gl.h,glu.h庫
#include <gl\freeglut.h>            // 包含OpenGL實用庫
#include <gdal_priv.h> 

using namespace std;

unsigned int  texture;    // 紋理對象
unsigned char* imgBuf = nullptr;
int imgWidth;
int imgHeight;

void ReadImage()
{
    GDALAllRegister();

    GDALDataset* img = (GDALDataset *)GDALOpen("lena.bmp", GA_ReadOnly);
    //GDALDataset* img = (GDALDataset *)GDALOpen("dst.tif", GA_ReadOnly);
    if (img == nullptr)
    {
        return;
    }   

    imgWidth = img->GetRasterXSize();   //圖像寬度
    imgHeight = img->GetRasterYSize();  //圖像高度
    int bandNum = img->GetRasterCount();    //波段數   
    int depth = GDALGetDataTypeSize(img->GetRasterBand(1)->GetRasterDataType()) / 8;    //圖像深度

    //申請buf
    size_t imgBufNum = (size_t)imgWidth * imgHeight * bandNum * depth;
    size_t imgBufOffset = (size_t)imgWidth * (imgHeight - 1) * bandNum * depth;
    imgBuf = new GByte[imgBufNum];
    //讀取
    img->RasterIO(GF_Read, 0, 0, imgWidth, imgHeight, imgBuf + imgBufOffset, imgWidth, imgHeight,
        GDT_Byte, bandNum, nullptr, bandNum*depth, -imgWidth*bandNum*depth, depth);

    GDALClose(img);
}

void InitGL()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);

    glShadeModel(GL_SMOOTH);      //平滑着色
    glEnable(GL_DEPTH_TEST);       //深度測試
    glEnable(GL_CULL_FACE);    //只渲染某一面
    glFrontFace(GL_CCW);     //逆時針正面
            
    glEnable(GL_TEXTURE_2D);    //啓用2D紋理映射  

    //載入紋理圖像:
    ReadImage();
    
    //生成紋理對象:
    glGenTextures(1, &texture);         
}

void DrawGLScene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glBindTexture(GL_TEXTURE_2D, texture);    //綁定紋理:
    
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //支持4字節對齊

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);      //S方向上貼圖
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);      //T方向上貼圖
    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, 3, imgWidth, imgHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, imgBuf);  //載入紋理:                                                                                                       

    glMatrixMode(GL_MODELVIEW);                         // 選擇模型觀察矩陣
    glLoadIdentity();                                   // 重置模型觀察矩陣     
    glMatrixMode(GL_PROJECTION);                        // 選擇投影矩陣       
    glLoadIdentity();
        
    glEnable(GL_TEXTURE_2D);    //啓用2D紋理映射
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f);   
    glVertex3f(-0.5f, -0.5f, 0.0f);
    glTexCoord2f(1.0f, 0.0f);   
    glVertex3f(0.5f, -0.5f, 0.0f);
    glTexCoord2f(1.0f, 1.0f);
    glVertex3f(0.5f, 0.5f, 0.0f);
    glTexCoord2f(0.0f, 1.0f);
    glVertex3f(-0.5f, 0.5f, 0.0f);
    glEnd();
    glDisable(GL_TEXTURE_2D);

    glutSwapBuffers();
}

GLvoid ReSizeGLScene(GLsizei width, GLsizei height)    // 重置OpenGL窗口大小
{
    glViewport(0, 0, width, height);
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    
    glutInitContextProfile(GLUT_CORE_PROFILE);
    glutInitWindowSize(600, 600);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("opengl");
    
    InitGL();   
    glutDisplayFunc(DrawGLScene);
    glutReshapeFunc(ReSizeGLScene);
    //glutKeyboardFunc(keyboard);
    //glutMouseWheelFunc(mouse_wheel);
    //glutIdleFunc(idle);

    glutMainLoop(); 
        
    return 0;
}

最後顯示的狀況以下:函數

另外注意最後須要釋放資源:oop

glDeleteTextures(1, &texture);
if (imgBuf)
{
    delete[] imgBuf;
    imgBuf = nullptr;
}
相關文章
相關標籤/搜索