OpenGL Tiles / Blitting / Clipping

时间:2011-08-17 09:35:35

标签: c++ opengl sdl tiles clipping

在OpenGL中,如何从使用IMG_Load()加载的图像文件中选择区域? (我正在为简单 2D游戏)的tilemap工作

我正在使用以下原则将图像文件加载到纹理中:

GLuint loadTexture( const std::string &fileName ) {

    SDL_Surface *image = IMG_Load(fileName.c_str());

    unsigned object(0);                        
    glGenTextures(1, &object);                 
    glBindTexture(GL_TEXTURE_2D, object);   

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);

    SDL_FreeSurface(image);
    return object;
}

然后我使用以下内容在渲染部分中实际绘制纹理:

glColor4ub(255,255,255,255);                
glBindTexture(GL_TEXTURE_2D, texture);      
glBegin(GL_QUADS);                          
glTexCoord2d(0,0);  glVertex2f(x,y);
glTexCoord2d(1,0);  glVertex2f(x+w,y);
glTexCoord2d(1,1);  glVertex2f(x+w,y+h);
glTexCoord2d(0,1);  glVertex2f(x,y+h);
glEnd(); 

现在我需要的是一个允许我从调用GLuint得到的loadTexture( const std::string &fileName )中选择某些矩形部分的函数,这样我就可以使用上面的代码来绑定这些部分为矩形,然后将它们绘制到屏幕上。类似的东西:

GLuint getTileTexture( GLuint spritesheet, int x, int y, int w, int h )

2 个答案:

答案 0 :(得分:4)

继续并将整个拼贴加载到纹理中。然后在渲染几何体时使用glTexCoord选择它的子集。

glTexSubImage2D无论如何都无济于事。它允许您向单个纹理添加多个文件,而不是从单个文件创建多个纹理。

示例代码:

void RenderSprite( GLuint spritesheet, unsigned spritex, unsigned spritey, unsigned texturew, unsigned textureh, int x, int y, int w, int h )
{
    glColor4ub(255,255,255,255);                
    glBindTexture(GL_TEXTURE_2D, spritesheet);
    glBegin(GL_QUADS);                          
    glTexCoord2d(spritex/(double)texturew,spritey/(double)textureh);
    glVertex2f(x,y);
    glTexCoord2d((spritex+w)/(double)texturew,spritey/(double)textureh);
    glVertex2f(x+w,y);
    glTexCoord2d((spritex+w)/(double)texturew,(spritey+h)/(double)textureh);
    glVertex2f(x+w,y+h);
    glTexCoord2d(spritex/(double)texturew,(spritey+h)/(double)textureh);
    glVertex2f(x,y+h);
    glEnd(); 
}

答案 1 :(得分:2)

虽然Ben Voigt的回答是常用的方法,但如果你真的想要一个额外的纹理(可能有助于边缘过滤),你可以使用glGetTexImage并与{{{1}一起玩。 1}}参数:

glPixelStore

但请记住,此函数始终将整个纹理图集读入CPU内存,然后将子部件复制到新的较小纹理中。因此,一次性创建所有需要的精灵纹理并且只读取一次数据是个好主意。在这种情况下,您还可以完全删除图集纹理,仅使用GLuint getTileTexture(GLuint spritesheet, int x, int y, int w, int h) { glBindTexture(GL_TEXTURE_2D, spritesheet); // first we fetch the complete texture GLint width, height; glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); GLubyte *data = new GLubyte[width*height*4]; glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); // now we take only a sub-rectangle from this data GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, /*filter+wrapping*/, /*whatever*/); glPixelStorei(GL_UNPACK_ROW_LENGTH, width); glTexImage2D(GL_TEXTURE_2D, 0, RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data+4*(y*width+x)); // clean up glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); delete[] data; return texture; } 将图像读入系统内存,以将其分配到各个精灵纹理中。或者,如果你真的需要大纹理,那么至少使用PBO将其数据复制到(使用IMG_Load或类似的东西),所以它不需要留下GPU内存。