基于OpenGL编写一个简易的2D渲染框架-04 绘制图片

摘要:
最后,改用FreeImage库来加载图像了。添加FreeImage库到工程解压FreeImage.rar文件后得到三个文件将其分别拷贝到debug文件夹、External文件夹、Lib文件夹中,再链接上lib库。绘制图片创建一个纹理结构,储存纹理索引、大小以及纹理坐标structDLL_exportTexture{Rectsize;Vec2texcoords[4];GLuinttexture;};创建一个纹理管理器类TextureManager,用于创建和管理纹理。利用FreeImage库加载纹理Texture*TexrureManager::createTexture{GLuinttexture=-1;std::stringfullName=PathHelper::fullPath;unsignedchar*image_data=nullptr;FIBITMAP*bmp=nullptr;/*初始化FreeImage*/FreeImage_Initialise;/*获取图像文件类型*/FREE_IMAGE_FORMATfif=FIF_UNKNOWN;fif=FreeImage_GetFileType;if{fif=FreeImage_GetFIFFromFilename;}/*加载所支持图像类型的图像*/if((fif!

阅读文章前需要了解的知识,纹理:https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/

过程简述:利用 FreeImage 库加载图像数据,再创建 OpenGL 纹理,通过 Canvas2D 画布绘制,最后又 Renderer 渲染器渲染

本来想用 soil 库加载图像数据的,虽然方便,但是加载有些格式的图像文件时会出现一些问题。最后,改用 FreeImage 库来加载图像了。

添加 FreeImage 库到工程

解压 FreeImage.rar 文件后得到三个文件

基于OpenGL编写一个简易的2D渲染框架-04 绘制图片第1张

将其分别拷贝到 debug文件夹、External 文件夹、Lib 文件夹中,再链接上 lib 库。

绘制图片

创建一个纹理结构,储存纹理索引、大小以及纹理坐标

    structDLL_export Texture
    {
        Rect size;
        Vec2 texcoords[4];

        GLuint texture;
    };

创建一个纹理管理器类 TextureManager,用于创建和管理纹理。

利用 FreeImage 库加载纹理

    Texture* TexrureManager::createTexture(const char*filename)
    {
        GLuint texture = -1;
        std::string fullName =PathHelper::fullPath(filename);

        unsigned char* image_data =nullptr;
        FIBITMAP* bmp =nullptr;

        /*初始化 FreeImage */FreeImage_Initialise(TRUE);

        /*获取图像文件类型 */FREE_IMAGE_FORMAT fif =FIF_UNKNOWN;
        fif =FreeImage_GetFileType(fullName.c_str());

        if ( fif ==FIF_UNKNOWN ) {
            fif =FreeImage_GetFIFFromFilename(fullName.c_str());
        }
        /*加载所支持图像类型的图像 */
        if ( (fif != FIF_UNKNOWN) &&FreeImage_FIFSupportsReading(fif) ) {
            bmp =FreeImage_Load(fif, fullName.c_str(), JPEG_DEFAULT);
        }
        if ( !bmp ) returnnullptr;

        int w =FreeImage_GetWidth(bmp);
        int h =FreeImage_GetHeight(bmp);
        int pixel_count = w *h;

        int byte_per_pixel = FreeImage_GetLine(bmp) /w;
        image_data = ( unsigned char* ) malloc(sizeof( unsigned char ) * pixel_count * 4);

        unsigned char* bits =FreeImage_GetBits(bmp);

        int current_pixel = 0;
        if ( byte_per_pixel == 4) {
            for ( int i = 0; i < pixel_count; i++) {
                image_data[i * 4 + 2] = bits[current_pixel++];
                image_data[i * 4 + 1] = bits[current_pixel++];
                image_data[i * 4 + 0] = bits[current_pixel++];
                image_data[i * 4 + 3] = bits[current_pixel++];
            }
        }
        else{
            for ( int i = 0; i < pixel_count; i++) {
                image_data[i * 4 + 2] = bits[current_pixel++];
                image_data[i * 4 + 1] = bits[current_pixel++];
                image_data[i * 4 + 0] = bits[current_pixel++];
                image_data[i * 4 + 3] = 255;
            }
        }

        if( bmp ) FreeImage_Unload(bmp);
        FreeImage_DeInitialise();

        glGenTextures(1, &texture);
        glBindTexture(GL_TEXTURE_2D, texture);

        /*设置纹理选项 */glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
        glBindTexture(GL_TEXTURE_2D, 0);

        free(image_data);

        Texture* tex = newTexture();
        tex->texture =texture;
        tex->size.set(0, 0, w, h);
        tex->texcoords[0].set(0, 0);
        tex->texcoords[1].set(0, 1);
        tex->texcoords[2].set(1, 1);
        tex->texcoords[3].set(1, 0);

        returntex;
    }

在函数中,使用 FreeImage 库加载纹理数据,然后创建 OpenGL 2D纹理,将创建的纹理保存到 Texture 结构中,并设置了纹理坐标。

在 Canvas2D 中绘制纹理

    void Canvas2D::drawTexture(int x, int y, Texture* texture, Color&color)
    {
        int w = texture->size.w;
        int h = texture->size.h;

        this->resizeVector(4, 6);
        vPositions[0].set(x + 0, y + 0, 0);
        vPositions[1].set(x + 0, y + h, 0);
        vPositions[2].set(x + w, y + h, 0);
        vPositions[3].set(x + w, y + 0, 0);

        vIndices[0] = 0;
        vIndices[1] = 2;
        vIndices[2] = 1;
        vIndices[3] = 0;
        vIndices[4] = 3;
        vIndices[5] = 2;

        staticRenderUnit unit;
        unit.pPositions = &vPositions[0];
        unit.nPositionCount = 4;
        unit.pTexcoords = texture->texcoords;
        unit.pIndices = &vIndices[0];
        unit.nIndexCount = 6;
        unit.color =color;
        unit.texture =texture;
        unit.renderType =RENDER_TYPE_TEXTURE;

        pRenderer->pushRenderUnit(unit);
    }

函数很简单,设置了顶点数据并填充了 RenderUnit,再传到 渲染器中渲染。与绘制几何图形相比,多了纹理坐标,并把渲染类型设置为 渲染纹理。

渲染器 Renderer 渲染纹理

添加成员

std::map<Texture*, VertexData*> textureDatas;

每张纹理都有其相应的顶点数据,这样可以把多张相同纹理的顶点数据放到一个缓冲区中渲染,保证了渲染多张相同纹理时只使用使用一个 DrawCall(调用 函数 glDrawElements 进行绘制的次数),提高渲染效率。

在pushRenderUnit 函数中

        else if ( unit.renderType ==RENDER_TYPE_TEXTURE ) {
            auto it =textureDatas.find(unit.texture);
            if ( it ==textureDatas.end() ) {
                vertexData = newVertexData();
                vertexData->bHasTexcoord = true;
                vertexData->renderType =RENDER_TYPE_TEXTURE;
                textureDatas.insert(std::make_pair(unit.texture, vertexData));
            }
            else{
                vertexData = it->second;
            }
        }

索引出纹理对应的 VertexData,然后填充数据。最后的渲染函数中添加填充纹理坐标代码

        /*设置纹理 */
        if ( vertexData->bHasTexcoord ) {
            glBindBuffer(GL_ARRAY_BUFFER, texcoordBuffer);
            glBufferData(GL_ARRAY_BUFFER, sizeof( Vec2 ) * vertexData->nPositionCount, &vertexData->texcoords[0], GL_DYNAMIC_DRAW);

            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, texrure);
            glUniform1i(glGetUniformLocation(shaderProgram, "defaulteTexture"), 0);
        }

为了能够渲染纹理需要更改着色程序

顶点着色器

#version 330core

layout(location = 0) invec3 Position;
layout(location = 1) invec2 Texcoord;
layout(location = 2) invec4 Color;

outvec2 texcoord;
outvec4 color;

uniform intbRenderTexture;

voidmain()
{
    gl_Position = vec4(Position, 1.0f);
    color =Color;

    if( bRenderTexture != 0){
        texcoord =Texcoord;
    }
}

片段着色器

#version 330core

outvec4 Color;

invec2 texcoord;
invec4 color;

uniform sampler2D defaultTexture;
uniform intbRenderTexture;

voidmain()
{
    if( bRenderTexture != 0){
        Color = texture(defaultTexture, texcoord) * color *color.w;
    }
    else{
        Color =color;
    }
}

为了开启 Alpha 效果,设置OpenGL 的混合状态

glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

在主函数中添加绘制图像的代码

    Texture* texture = TexrureManager::instance()->getTexture("image.png");
    Texture* texture1 = TexrureManager::instance()->getTexture("image.jpg");
            canvas.drawTexture(180, 0, texture1, Color(1, 1, 1, 1));
            canvas.drawTexture(120, 100, texture, Color(1, 1, 1, 0.8));

程序的运行结果

基于OpenGL编写一个简易的2D渲染框架-04 绘制图片第2张

这里绘制了 png 和 jpg 格式的图像

源码下载:http://pan.baidu.com/s/1skOmP21

免责声明:文章转载自《基于OpenGL编写一个简易的2D渲染框架-04 绘制图片》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇内核移植和文件系统制作(2):linux内核最小系统和initramfs文件系统u3d中texture2D的Advanced设置解析下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

OpenGL代码学习(22)--绘制通道

注意:需要在配置好OpenGL的编程环境中运行下列代码,环境配置文章可参考: OpenGL在Mac项目上的配置下面的代码,直接放置在main.cpp文件中即可: #include "GLTools.h" #include "GLShaderManager.h" #include "GLFrustum.h" #include "GLBatch.h" #inc...

Qt OpenGL 图形字体的纹理映射

这次教程中,我们将在第14课的基础上创建带有纹理的字体,它真的很简单。也许你想知道如何才能给字体赋予纹理贴图?我们可以使用自动纹理坐标生成器,它会自动为字体上的每一个多边形生成纹理坐标。 这次课中我们还将使用Wingdings字体来显示一个海盗旗(骷髅头和十字骨头)的标志,为此我们需要修改buildFont()函数代码。如果你想显示文字的话,就不用改动第1...

RenderMonkey 练习 第三天 【OpenGL renderToTexture】

渲染到纹理: 1. 新建一个OpenGL 空effect; 2. 添加渲染目标纹理, Add Texture-> Add Render Texture 3. 添加一个渲染pass 4. 将pass0 渲染到纹理上, add Render Target->renderTexture; 5. 在pass1中,引用纹理 Add Tex...

OpenGL编程逐步深入(四)Shaders

OpenGl 中的 Shader在一些中文书籍或资料中都被翻译为“着色器”, 单从字面意思也看不出Shader到底是什么,Shader实际上就是一段代码,用于完成特定功能的一个模块。Shader分为Vertex Shader(顶点着色器)和Pixel Shader(像素着色器)两种,其中Pixel Shader在本文中又被称为Fragment Shade...