OGLplus で画像の描画

OGLplus を使用したテクスチャの描画です。
OGLplus では、libpng で .png の画像ファイルを読み込むことが出来るので、今回はそれを使用します。
使用するためには予め libpng を導入しておく必要があります。


example だと を使っているみたいですが、そんなものは存在しなかったので、直接書いています。
まぁやっていることはそんなに変わらないはず。

[ソース]

#include <vector>
#include <GL/glew.h>

#include <oglplus/gl.hpp>
// OGLplus 0.5.0 以降だと near far を undef しておかないと動かない
#undef near
#undef far

//#include <oglplus/all.hpp>
#include <oglplus/context.hpp>
#include <oglplus/buffer.hpp>
#include <oglplus/vertex_attrib.hpp>
#include <oglplus/vertex_array.hpp>
#include <oglplus/shader.hpp>
#include <oglplus/program.hpp>
#include <oglplus/pixel_data.hpp>
#include <oglplus/texture.hpp>
#include <oglplus/image.hpp>
#include <oglplus/images/load.hpp>
#include <oglplus/shapes/draw.hpp>

#include <GL/Glut.h>

#include <gl/graphics.hpp>
#include <boost/optional.hpp>
#include <fstream>
#include <sstream>

namespace glp = oglplus;
typedef glp::Context glc;


template<typename Shader, typename Char>
boost::optional<std::string>
shader_compile(Shader& shader, Char const* source){
    shader.Source(source);
    try{
        shader.Compile();
        return boost::none;
    }
    catch (glp::CompileError const& error) {
        std::cout << error.what() << std::endl;
        return error.Log();
    }
}

template<typename Shader, typename Char>
boost::optional<std::string>
shader_compile(Shader& shader, std::basic_ifstream<Char> const& file){
    std::stringstream buffer;
    buffer << file.rdbuf();
    return shader_compile(shader, buffer.str().c_str());
}


struct texture : boost::noncopyable{
    
    texture(){

        load_shader();

        // bind the VAO for the texture
        vertex_array.Bind();

        // bind the VBO for the texture vertices
        verts.Bind(glp::Buffer::Target::Array);
        {
            GLfloat data[12] = {
                1.0f, 1.0f,
                1.0f, -1.0f,
                -1.0f, 1.0f,
                -1.0f, 1.0f,
                1.0f, -1.0f,
                -1.0f, -1.0f
            };

            // upload the data
            glp::Buffer::Data(glp::Buffer::Target::Array,
                12,
                data
            );
            // setup the vertex attribs array for the vertices
            glp::VertexAttribArray vert_attr(prog, "Position");
            vert_attr.Setup(2, glp::DataType::Float);
            vert_attr.Enable();
        }
        
        texcoords.Bind(glp::Buffer::Target::Array);
        {
            GLfloat data[12] = {
                1.0f, 1.0f,
                1.0f, 0.0f,
                0.0f, 1.0f,
                0.0f, 1.0f,
                1.0f, 0.0f,
                0.0f, 0.0f
            };
            // upload the data
            glp::Buffer::Data(glp::Buffer::Target::Array,
                12,
                data
            );
            glp::VertexAttribArray attr(prog, "TexCoord");
            attr.Setup(2, glp::DataType::Float);
            attr.Enable();
        }

        // setup the texture
        tex.Bind(glp::Texture::Target::_2D);
        {
            tex.MinFilter(glp::Texture::Target::_2D, glp::TextureMinFilter::Linear);
            tex.MagFilter(glp::Texture::Target::_2D, glp::TextureMagFilter::Linear);
            tex.WrapS(glp::Texture::Target::_2D, glp::TextureWrap::Repeat);
            tex.WrapT(glp::Texture::Target::_2D, glp::TextureWrap::Repeat);

            std::ifstream file("cpplands.png", std::ios::binary);
            tex.Image2D(
                glp::Texture::Target::_2D,
                glp::images::PNG(file)
            );
            // OGLplus で用意されている読み込み処理では
            // std::ios::binary が付いておらず失敗する
//            tex.Image2D(glp::Texture::Target::_2D, glp::images::LoadTexture("cpplands"));
        }
    }
    
    void
    render() const{
        vertex_array.Bind();
        glc::DrawArrays(glp::PrimitiveType::Triangles, 0, 6);
    }
    void
    reload_shader(std::string name = "basic"){
        prog.DetachShader(vs);
        prog.DetachShader(fs);
        load_shader(name);
        std::cout << "reloaded shader" << std::endl;
    }

private:
    void
    load_shader(std::string name = "basic"){
        if(auto error = shader_compile(vs, std::ifstream(name + ".vert"))){
            std::cout << "==== VertexShader Compile Error ====" << std::endl;
            std::cout << *error << std::endl;
            return;
        }

        if(auto error = shader_compile(fs, std::ifstream(name + ".frag"))){
            std::cout << "==== FragmentShader Compile Error ====" << std::endl;
            std::cout << *error << std::endl;
            return;
        }
        // attach the shaders to the program
        prog.AttachShader(vs);
        prog.AttachShader(fs);
        // link and use it
        prog.Link();
        prog.Use();
    }

    // Vertex shader
    glp::VertexShader vs;

    // Fragment shader
    glp::FragmentShader fs;

    // Program
    glp::Program prog;

    // A vertex array object for the rendered texture
    glp::VertexArray vertex_array;
    // VBO for the texture's vertices
    glp::Buffer verts;
    
    glp::Buffer texcoords;

    // The stained glass texture
    glp::Texture tex;
};


int
main(int argc, char *argv[]) try{
    namespace glp = oglplus;
    typedef glp::Context glc;
    
    gl::graphics g(argc, argv, 800, 600, "test");
    
    // glew の初期化
    auto err = glewInit();
    if (err != GLEW_OK)
    {
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
    }
    
    glc::ClearColor(0.5f, 0.7f, 0.9f, 1.0f);
    glc::ClearDepth(1.0f);

    // テクスチャポリゴンの生成
    texture tex;

    //----------------------------------------------------------------------    
    
    gl::displayfunc(g, [&](){
        glc::Clear().ColorBuffer().DepthBuffer();
        tex.render();
    });
    
    gl::reshapefunc(g, [&](int width, int height){
        glc::Viewport(width, height);
    });

    // キー入力イベント
    gl::keyboardfunc(g, [&tex](unsigned char key, int x, int y){
        if(key == 'q') return exit(0);
        if(key == 'u') return tex.reload_shader(), glutPostRedisplay();
    });

    g.run();
    return 0;
}
catch(glp::Error const& error){
    std::cout << error.what() << std::endl;
    std::cout << "GLSymbol          " << error.GLSymbol          () << std::endl;
    std::cout << "File              " << error.File              () << std::endl;
    std::cout << "Func              " << error.Func              () << std::endl;
    std::cout << "Line              " << error.Line              () << std::endl;
    std::cout << "ClassName         " << error.ClassName         () << std::endl;
    std::cout << "ObjectDescription " << error.ObjectDescription () << std::endl;
}

[basic.vert]

#version 330
in vec4 Position;
in vec2 TexCoord;
out vec2 vertTexCoord;

void main(void){
    vertTexCoord = TexCoord;
    gl_Position = Position;
}

[basic.frag]

#version 330
uniform sampler2D TexUnit;
in vec2 vertTexCoord;
out vec4 fragColor;

void main(void){
    fragColor = texture(TexUnit, vertTexCoord);
    vec4 t  = texture(TexUnit, vertTexCoord);
    fragColor = vec4(t.rgb, 1.0);
}

[出力]

[注意]

oglplus::images::LoadTexture を使用して画像ファイルを読み込む場合、std::ios::binary オプションが付いておらずに読み込みに失敗してしまいます。
これを防ぐためには、OGLplus のコードを直接書き換えるか、ユーザコードで、std::ifstream で読み込む必要があります。

[OGLplus]

  • 0.7.0