使用图像opengl填充多边形

时间:2016-03-29 09:06:39

标签: c++ eclipse image opengl textures

http://coliru.stacked-crooked.com/a/400b648e7442eeb3

你可以阅读一段代码:想法是用纹理填充多边形四边形(图像在四边形内重复)。

我希望图像只重复一次:换句话说,将图像作为多边形的背景。我在一个800x600的窗口,我想放一个台球桌,例如600x400(在glvertex3i定义的四边形)。它可以是glvertex2i并在2D中实现,就像2D游戏一样。

任何帮助都是apreciated

此外,我有一个更好的代码来支持任何jpg文件而不是loadtexture和readjpeg(我认为):

GLuint MyLoadTexture(std::string const filename)
{
    GLuint texname = 0;
    /* this is actually tied to the OpenGL context, so this should
    * actually be a map GLcontext -> std::string -> texturename */
    static std::map<std::string, GLuint> loaded_textures;
    if( loaded_textures.find(filename) != loaded_textures.end() ) {
        texname = loaded_textures[filename];
        glBindTexture(GL_TEXTURE_2D, texname);
        return texname;
    }

    int width,height;
    std::vector<uint8_t> image;
    if( ReadJPEG(filename, &image, &width, &height) ) {
        std::cerr
            << "error reading JPEG"
            << std::endl;
        return 0;
    }

    glGenTextures(1, &texname);
    if( !texname ) {
        std::cerr
            << "error generating OpenGL texture name"
            << std::endl;
        return 0;
    }

    glBindTexture(GL_TEXTURE_2D, texname);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);

   /* glTexImage2D(
        GL_TEXTURE_2D, 0, GL_RGB,
        width, height, 0,
        GL_RGB,
        GL_UNSIGNED_BYTE, buffer );
    */
    glTexImage2D(
           GL_TEXTURE_2D, 0, GL_RGB,
           width, height, 0,
           GL_RGB,
           GL_UNSIGNED_BYTE, &image[0]);

    loaded_textures[filename] = texname;

    return texname;
}

int ReadJPEG(
    std::string const filename,
    std::vector<uint8_t> *image,
    int *width, int *height )
{
     if( !image ) {
            return -1;
        }

        FILE * const infile = fopen(filename.c_str(), "rb");
        if( !infile ) {
            std::cerr
                << "error opening file "
                << filename
                << " : "
                << strerror(errno)
                << std::endl;
            return -2;
        }

        struct jpeg_decompress_struct cinfo;
        struct jpeg_error_mgr jerr;
        cinfo.err = jpeg_std_error(&jerr);

        jpeg_create_decompress(&cinfo);

        jpeg_stdio_src(&cinfo, infile);
        jpeg_read_header(&cinfo, TRUE);
        jpeg_calc_output_dimensions(&cinfo);
        jpeg_start_decompress(&cinfo);

        if( width )  { *width  = cinfo.output_width;  }
        if( height ) { *height = cinfo.output_height; }

        size_t const stride = cinfo.output_width * cinfo.output_components;
        image->resize(cinfo.output_height * stride);

        for(size_t i = 0; i < cinfo.output_height;) {
            uint8_t * const row =  &(*image)[stride * i];
            i += jpeg_read_scanlines(&cinfo, (unsigned char**)&row, 1);
        }
        jpeg_finish_decompress(&cinfo);

        fclose(infile);
        return 0;
    }

1 个答案:

答案 0 :(得分:0)

我注意到您使用的是不推荐使用的OpenGL版本。至于你的情况,如果你关心纹理中的alpha值,对我来说并不明显。每个颜色通道还有多少字节?这一点很重要。

在代码的这一部分中,有一些我认为应该改进的事情:

glGenTextures(1, &texname);
if( !texname ) {
    std::cerr
        << "error generating OpenGL texture name"
        << std::endl;
    return 0;
}

glBindTexture(GL_TEXTURE_2D, texname);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);

/* glTexImage2D(
    GL_TEXTURE_2D, 0, GL_RGB,
    width, height, 0,
    GL_RGB,
    GL_UNSIGNED_BYTE, buffer );
*/
glTexImage2D(
       GL_TEXTURE_2D, 0, GL_RGB,
       width, height, 0,
       GL_RGB,
       GL_UNSIGNED_BYTE, &image[0]);

loaded_textures[filename] = texname;

在致电glGenTextures(1, &texname);之前,您应首先致电:

glGetError(); // This will clear errors

在致电glGenTextures(1, &texname);而不是检查texname是否错误之后,首选此方法:

GLenum err = glGetError();
if ( err != GL_NO_ERROR ) {
    // Generate Error Here, either log message to file, console or throw an error
}

接下来是您的glBindTexture( GL_TEXTURE_2D, texname );,这很好。现在,对于生成和绑定纹理的OpenGL函数,第二个参数是OpenGL自动生成的无符号ID,它将它与给定的文件名相关联。机器读取无符号值以检查多个资源比检查和验证字符串更容易。当应用程序处理100s,1000s甚至1,000,000s的资源文件时,性能也会提高。

在此之后,您现在正在设置有关OpenGL如何处理mipmap的参数。如果这是您想要进行mipmapping的行为,那么代码的这一部分似乎没问题。但是,使用纹理的此函数的调用者没有方法来设置mipmap的质量级别。我通常在这里做的是一个枚举,处理mimpmaps的不同质量水平,这是我处理mipmap的方式的片段:

注意:在此函数中未定义或声明枚举值,它将是一个传递给它的参数。

// This enum I usually have it declared or defined in a CommonStructs header.
enum FilterQuality {
    FILTER_NONE = 1,
    FILTER_GOOD,
    FILTER_BETTER,
    FILTER_BEST
 }; // FilterQuality

 // Now as within side of my function for generating texture files I have something like this for mipmaps:     
if ( texture.generateMipMap ) {
    switch ( texture.filterQuality ) {
        case TextureInfo::FILTER_NONE : {
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
            break;
        }
        case TextureInfo::FILTER_GOOD: {
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR );
            break;
        }
        case TextureInfo::FILTER_BEST: {
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
            break;
        }
        default: {
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
        }
    } // Switch

    if ( openglVersion.x < 3 ) {
        // In OpenGL v3 GL_GENERATE_MIPMAP Is Deprecated, And In 3.1+ It Was Removed
        // So For Those Versions We Use glGenerateMipmap below
        static const unsigned int GL_GENERATE_MIPMAP = 0x8191;
        glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
    }
} else { // No MipMaps
    switch( texture.filterQuality ) {
        case TextureInfo::FILTER_NONE:
        case TextureInfo::FILTER_GOOD: {
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
            break;
        }
        default: {
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
            glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
        }
    } 
}

我看到的唯一可能无关紧要的是你对glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);的呼吁因为我从未使用它,现在这可能是你想要的某种行为,而我不知道。

设置mimpmapping信息之后,您可以在此处设置钳位或包装重复的参数,这些参数是代码中缺少的,用于生成纹理。它们看起来像这样:

bool wrapRepeat; // This variable would not be here inside of the function,
// but would come from this function's definition so that the caller can
// set this parameter or flag to the behavior they want for each texture in use.

// What these two lines of code will do depending on the state of wrapRepeat
// is they will cause the last parameter to be either WRAP in S & T coordinates or
// to clamp to edge in both S & T coordinates.
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (wrapRepeat ? GL_REPEAT : GL_CLAMP_TO_EDGE ) );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (wrapRepeat ? GL_REPEAT : GL_CLAMP_TO_EDGE ) );

最后你有你的代码将纹理加载到内存中作为参考,这是我在我的函数中生成纹理的内容:

// Load Texture Into Video Memory
glPixelStorei( GL_UNPACK_ALIGNMENT, texture.hasAlphaChannel ? 4 : 1 );
glTexImage2D( GL_TEXTURE_2D,
    0,
    ( texture.hasAlphaChannel ? GL_RGBA8 : GL_RGB8 ),
    texture.uWidth,
    texture.uHeight,
    0,
    ( texture.hasAlphaChannel ? GL_RGBA : GL_RGB ),
    GL_UNSIGNED_BYTE,
    &texture.vPixelData[0] );

if ( texture.generateMipMap && openglVersion.x >= 3 ) {
    glGenerateMipmap( GL_TEXTURE_2D );
}

这可以帮助您解决当前的问题,即纹理被包裹而不是被夹住。

现在,就我的项目而言,我有一个派生的文件处理程序类,它专门读取纹理文件并加载到TGA或PNG文件中,并且它的设计方式可以加载到任何其他纹理或图像文件中只要向该类添加一个函数来解析文件类型。我在渲染中使用的实际图像类型与文件阅读器是分开的。它们与此代码分开。此代码属于AssetStorage类。我的这一类负责存储所有资产并管理它们的内存,就是这样。这个类不会渲染任何东西,但它会将对象加载到ram和video ram中。我的批处理类和批处理管理器类处理所有对象的渲染。现在我的对象都是使用GLSL着色器构建的。但是要完整地向您展示这个功能可以作为我的框架设计的参考。

// ----------------------------------------------------------------------------
// add()
// Creates An OpenGL Texture And Returns It's ID Value
// This Can Only Be Called From The Main OpenGL Thread
TextureInfo AssetStorage::add( const Texture& texture, const std::string& strFilename ) {
    if ( INVALID_UNSIGNED != getTextureInfo( strFilename ).uTextureId ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " can not store " << strFilename << " multiple times";
        throw ExceptionHandler( strStream );
    }

    TextureInfo textureInfo;
    textureInfo.hasTransparency = texture.hasAlphaChannel;
    textureInfo.size = glm::uvec2( texture.uWidth, texture.uHeight );

    glGetError(); // Clear Errors

    glGenTextures( 1, &textureInfo.uTextureId );

    GLenum err = glGetError();
    if ( err != GL_NO_ERROR ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " failed glGenTextures with error code 0x" << std::hex << err;
        throw ExceptionHandler( strStream );
    }

    glBindTexture( GL_TEXTURE_2D, textureInfo.uTextureId );

    // Wrap Textures
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ( texture.wrapRepeat ? GL_REPEAT : GL_CLAMP_TO_EDGE ) );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ( texture.wrapRepeat ? GL_REPEAT : GL_CLAMP_TO_EDGE ) );

    const glm::uvec2& openglVersion = s_pSettings->getOpenglVersion();

    if ( texture.generateMipMap ) {
        switch ( texture.filterQuality ) {
            case TextureInfo::FILTER_NONE : {
                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
                break;
            }
            case TextureInfo::FILTER_GOOD: {
                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR );
                break;
            }
            case TextureInfo::FILTER_BEST: {
                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
                break;
            }
            default: {
                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
            }
        } // Switch

        if ( openglVersion.x < 3 ) {
            // In OpenGL v3 GL_GENERATE_MIPMAP Is Deprecated, And In 3.1+ It Was Removed
            // So For Those Versions We Use glGenerateMipmap below
            static const unsigned int GL_GENERATE_MIPMAP = 0x8191;
            glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
        }
    } else { // No MipMaps
        switch( texture.filterQuality ) {
            case TextureInfo::FILTER_NONE:
            case TextureInfo::FILTER_GOOD: {
                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
                break;
            }
            default: {
                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
            }
        } 
    }

    // Load Texture Into Video Memory
    glPixelStorei( GL_UNPACK_ALIGNMENT, texture.hasAlphaChannel ? 4 : 1 );
    glTexImage2D( GL_TEXTURE_2D,
        0,
        ( texture.hasAlphaChannel ? GL_RGBA8 : GL_RGB8 ),
        texture.uWidth,
        texture.uHeight,
        0,
        ( texture.hasAlphaChannel ? GL_RGBA : GL_RGB ),
        GL_UNSIGNED_BYTE,
        &texture.vPixelData[0] );

    if ( texture.generateMipMap && openglVersion.x >= 3 ) {
        glGenerateMipmap( GL_TEXTURE_2D );
    }

    // Store TextureId
    BlockThread blockThread( s_criticalSection );
    m_textureInfos.insert( MapTextureInfos::value_type( strFilename, textureInfo ) );

    if ( s_pSettings->isDebugLoggingEnabled( Settings::DEBUG_MEMORY ) ) {
        Logger::log( std::string( "Created " ) + strFilename );
    }

    return textureInfo;
} // add
相关问题