OpenGL Tiles / Blitting / Clipping - PullRequest
       25

OpenGL Tiles / Blitting / Clipping

1 голос
/ 17 августа 2011

Как в OpenGL выбрать область из файла изображения, который был загружен с помощью IMG_Load()? (Я работаю над картой тайлов для простой 2D игры)

Я использую следующий принцип для загрузки файла изображения в текстуру:

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 ]

4 голосов
/ 17 августа 2011

Идите и загрузите весь коллаж в текстуру.Затем выберите его подмножество, используя 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(); 
}
2 голосов
/ 17 августа 2011

Хотя ответ Бена Фойгта - обычный путь, если вам действительно нужна дополнительная текстура для плиток (которая может помочь с фильтрацией по краям), вы можете использовать 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;
}

Но имейте в виду, что эта функция всегда читает весь текстурный атлас в память процессора, а затем копирует часть в новую меньшую текстуру. Поэтому было бы неплохо создать все необходимые текстуры спрайта за один раз и считывать данные только один раз. В этом случае вы также можете просто полностью удалить текстуру атласа и только прочитать изображение в системную память с помощью IMG_Load, чтобы распределить его по отдельным текстурам спрайта. Или, если вам действительно нужна большая текстура, тогда, по крайней мере, используйте PBO для копирования своих данных (с использованием GL_DYNAMIC_COPY или чего-то подобного), поэтому не нужно оставлять память GPU.

...