Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ OpenGL分幅/分幅/剪辑_C++_Opengl_Sdl_Tiles_Clipping - Fatal编程技术网

C++ OpenGL分幅/分幅/剪辑

C++ OpenGL分幅/分幅/剪辑,c++,opengl,sdl,tiles,clipping,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); glGe

在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(); 
现在我需要的是一个函数,它允许我从调用
loadTexture(const std::string&fileName)
得到的
GLuint
中选择某些矩形部分,这样我就可以使用上面的代码将这些部分绑定到矩形,然后将它们绘制到屏幕上。比如:


继续并将整个拼贴加载到纹理中。然后,在渲染几何体时,使用
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(); 
}

继续并将整个拼贴加载到纹理中。然后,在渲染几何体时,使用
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(); 
}

尽管Ben Voigt的答案是通常的做法,但如果您真的想要为瓷砖添加额外的纹理(这可能有助于在边缘进行过滤),您可以使用
glGetTexImage
并使用
glPixelStore
参数:

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;
}

但请记住,此函数始终将整个纹理图集读取到CPU内存中,然后将子部分复制到新的较小纹理中。因此,一次创建所有需要的sprite纹理并只读取一次数据是一个好主意。在这种情况下,您也可以完全删除atlas纹理,仅使用
IMG_Load
将图像读取到系统内存中,以将其分配到各个sprite纹理中。或者,如果你真的需要大纹理,那么至少使用PBO将其数据复制到(使用
GL\u DYNAMIC\u copy
usage或类似的东西),这样它就不需要离开GPU内存。

尽管Ben Voigt的答案是通常的做法,如果你真的想为瓷砖添加额外的纹理(这可能有助于边缘的过滤)您可以使用
glGetTexImage
并使用
glPixelStore
参数播放:

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;
}

但请记住,此函数始终将整个纹理图集读取到CPU内存中,然后将子部分复制到新的较小纹理中。因此,一次创建所有需要的sprite纹理并只读取一次数据是一个好主意。在这种情况下,您也可以完全删除atlas纹理,仅使用
IMG_Load
将图像读取到系统内存中,以将其分配到各个sprite纹理中。或者,如果您真的需要大纹理,那么至少使用PBO将其数据复制到(使用
GL\u DYNAMIC\u copy
usage或类似工具),这样它就不需要离开GPU内存。

谢谢。在我的案例中,我需要把什么作为最后的论点<代码>glTexSubImage2D(GL_纹理_2D,0,x,y,w,h,GL_RGBA,GL_无符号_字节,常量GLvoid*数据)我没有SDL_曲面了,我只有调用
loadTexture()
得到的胶水。请你写一个简短的例子好吗?谢谢。在我的案例中,我需要把什么作为最后的论点<代码>glTexSubImage2D(GL_纹理_2D,0,x,y,w,h,GL_RGBA,GL_无符号_字节,常量GLvoid*数据)我没有SDL_曲面了,我只有调用
loadTexture()
得到的胶水。你能写一个简短的例子吗?非常感谢!这是可行的:)不过,只有一个问题,既然
unsigned texturew,unsigned textureh
指的是精灵表的尺寸,那么有可能从
GLuint精灵表本身获取这些尺寸吗?那会舒服得多吗?@Ben:你可以打电话传递
GL\u TEXTURE\u WIDTH
GL\u TEXTURE\u HEIGHT
。但是,只在CPU上跟踪这些数据,而不是每次都从GPU取回数据,效率要高得多。您可能需要创建一个小结构,它将纹理ID(
GLuint
)与宽度和高度结合起来,这样您就可以将它们一起传递。非常感谢!这是可行的:)不过,只有一个问题,既然
unsigned texturew,unsigned textureh
指的是精灵表的尺寸,那么有可能从
GLuint精灵表本身获取这些尺寸吗?那会舒服得多吗?@Ben:你可以打电话传递
GL\u TEXTURE\u WIDTH
GL\u TEXTURE\u HEIGHT
。但是,只在CPU上跟踪这些数据,而不是每次都从GPU取回数据,效率要高得多。您可能需要创建一个结合纹理ID(
GLuint
)和宽度和高度的小结构,这样您就可以将它们一起传递。老实说,我不太确定我是否“真的想要为瓷砖添加额外的纹理”。到目前为止,我已经在一个单独的图像文件中的每个纹理。我现在所做的是将多个纹理组合到一个图像文件(spritesheet),例如,每个角色或级别一张图片。我希望返回
GLuint
的唯一原因是因为我的逻辑是这样构造的(来自单独的图像版本)。但我现在改变了。那么你会推荐我使用哪个版本呢?与你的版本相比,本的版本表现如何?有什么值得注意的吗?@Ben我认为本的版本更高级(你可能会接受这个版本,尽管你仍然可以投票给我:)。这样你就不必一直切换纹理。如果纹理太大(虽然高达4096x4096,您应该可以,或者在较新的硬件上更大),您可能会遇到问题,或者您可能会遇到瑕疵