C ++ 11中的cstr文字,如何将(char * [])传递给函数

约翰尼斯

在包装OpenGL着色器时,我发现了其中一个必需参数的问题。标准顶点着色器的源由OpenGL复制到内部表示中。一个简单的例子可能是这样的:

static const GLchar * vertex_shader_source[] =
{
    "#version 430 core\n",
    "void main(void)\n"
    "{",
    "    gl_Position = vec4(0.0, 0.0, 0.5, 1.0):\n",
    "}"
};

GLchar定义为char,因此本质上是cstr。我编写了一个包装器对象,该对象可以帮助我创建和销毁着色器(GLuint是OpenGL句柄)。我的问题可以分解为以下函数调用:

GLuint shader_ptr = helper(GL_VERTEX_SHADER, vertex_shader_source);

我只需要vertex_shader_source即可使用。我想写一些使用数组初始化程序创建具有自动作用域的内存的东西。我不想使用C99的转换方式,因为我想使用C ++ 11的方式进行转换。

helper 定义如下:

GLuint helper(GLenum type, const GLchar * source[])
{
    GLuint shader_ptr = glCreateShader(type);
    glShaderSource(shader_ptr, 1, source, NULL);
    glCompileShader(shader_ptr);
    return shader_ptr;
}

删除对于这个问题并不重要,可以使用来在析构函数中进行处理glDeleteShader

我尝试了以下操作,但无法编译:

GLuint shader_ptr = helper(GL_VERTEX_SHADER,
{
    "#version 430 core\n",
    "void main(void)\n"
    "{",
    "    gl_Position = vec4(0.0, 0.0, 0.5, 1.0):\n",
    "}"
}
);

我怎么称呼它helper为“一个班轮”?

数据狼

如果您的着色器是单个字符串(而不是字符串列表,在某些地方实际上是非常有益的),则使您的助手仅接受achar const *而不是a char const * const *这样,您将拥有一个本地符号,可以使用以下地址:

GLuint helper(GLenum type, GLchar const * source)
{
    GLuint shader_name = glCreateShader(type);
    glShaderSource(shader_ptr, 1, &source, NULL);
    glCompileShader(shader_ptr);
    return shader_name;
}

您可以仅使用字符串作为参数来调用它:

GLuint shader_name = helper(GL_VERTEX_SHADER,
    "#version 430 core\n"
    "void main() {"
    "    gl_Position = vec4(0.0, 0.0, 0.5, 1.0);"
    "}"
);

请注意,由于没有逗号(因此缺少围棋符{}并且这是一个长字符串文字,

顺便说一句:OpenGL不给您指针,但是不透明的对象


关于编程风格的几句话:

诸如着色器源文本之类的字符串文字是编译时间常数。像任何类型的常数值一样,就地编写它们是不好的方式:如果是数字,这是没有意义的“魔术值”。对于某些字符串,在读取源代码(宿主程序与着色器代码交错)时,您现在必须在头脑中保持两个解析器状态。这在很大程度上降低了可读性并降低了可维护性。

另外,您的助手也缺少错误检查代码。

在我的项目中,使用编译到程序中的着色器源时,我使用此帮助器(请注意,它实际上将数组提取为C字符串):

https://gist.github.com/datenwolf/f108f2ed4085f3840457

GLuint load_gl_shader_from_sources(
    GLenum shader_unit,
    char const * const * const sources )
{
    GLuint shader = glCreateShader(shader_unit);
    if( !shader ) {
        goto failed_shader;
    }

    size_t n_sources = 0;
    for(; sources[n_sources]; n_sources++);

    GLint * const lengths = alloca(sizeof(GLint)*(n_sources+1));
    if( !lengths ) {
        goto failed_lengths;
    }
    lengths[n_sources] = 0;

    for(size_t i = 0; i < n_sources; i++) {
        lengths[i] = strlen(sources[i]);
    }

    glShaderSource(shader, n_sources, sources, lengths);

    glCompileShader(shader);

    GLint shader_status;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_status);
    if( shader_status == GL_FALSE ) {
        GLint log_length, returned_length;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);

        char *shader_infolog = alloca(log_length);
        if(shader_infolog) {
            glGetShaderInfoLog(
                shader,
                log_length,
                &returned_length,
                shader_infolog );
            char const * shader_unit_str = NULL;
            switch(shader_unit) {
            case GL_VERTEX_SHADER:   shader_unit_str = "vertex";   break;
            case GL_FRAGMENT_SHADER: shader_unit_str = "fragment"; break;
            }
            fprintf(stderr,
                "\n %s shader compilation failed;\n%*s",
                shader_unit_str,
                returned_length, shader_infolog );
        }
        goto failed_compile;
    }

    return shader;

failed_compile:

failed_lengths:

    glDeleteShader(shader); 
failed_shader:

    return 0;
}

GLuint load_gl_program_from_sources(
    char const * const * const sources_vs,
    char const * const * const sources_fs )
{
    GLuint program = glCreateProgram();
    if( !program ) {
        goto failed_program;
    }

    GLuint vert_shader = 0;
    if( sources_vs ) {
        vert_shader = load_gl_shader_from_sources(
            GL_VERTEX_SHADER,
            sources_vs );

        if( !vert_shader ) {
            goto failed_vert_shader;
        }
    }
    
    GLuint frag_shader = 0;
    if( sources_fs ) {
        frag_shader = load_gl_shader_from_sources(
            GL_FRAGMENT_SHADER,
            sources_fs );

        if( !frag_shader ) {
            goto failed_frag_shader;
        }
    }

    glAttachShader(program, vert_shader);
    glAttachShader(program, frag_shader);

    glLinkProgram(program);
    GLint linkStatus;
    glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
    if( GL_FALSE == linkStatus ) {
        GLint log_length, returned_length;
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);

        char *program_infolog= alloca(log_length);
        if(program_infolog) {
            glGetProgramInfoLog(
                program,
                log_length,
                &returned_length,
                program_infolog );
            fwrite(program_infolog, returned_length, 1, stderr);
        }

        goto failed_link;
    }

    /* shaders will get actually deleted only after the rogram gets deleted */
    glDeleteShader(vert_shader);
    glDeleteShader(frag_shader);

    return program;

failed_link:

    if(frag_shader)
        glDeleteShader(frag_shader);
failed_frag_shader:

    if(vert_shader)
        glDeleteShader(vert_shader);
failed_vert_shader:

    glDeleteProgram(program);
failed_program:

    return 0;
}

您可以像这样使用它:

void renderBoundingBox(mat4x4 mv, mat4x4 proj)
{
    char const * vs_sources[] = {
"#version 120\n",
"uniform mat4x4 mv; uniform mat4x4 proj;"
"attribute vec3 position;",
"void main() { gl_Position = proj * mv * vec4(position*2.-1., 1.0); }",
NULL };

    char const * fs_sources[] = {
"#version 120\n",
"void main() { gl_FragColor = vec4(1.0f); }",
NULL };

    static GLuint program = 0;
    static GLint attrib_position, uniform_mv, uniform_proj;
    if( !program ) {
        program = load_gl_program_from_sources(
            vs_sources,
            fs_sources );
        uniform_mv      = voglr_glGetUniformLocation(program, "mv");
        uniform_proj    = voglr_glGetUniformLocation(program, "proj");
        attrib_position = voglr_glGetAttribLocation(program,  "position");
    }

    if( !program ) {
        return;
    }

/* … */

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章