Изображение CImg бесцветное

В настоящее время я нахожусь в процессе доработки функции в моей базовой программе редактора уровней, которая позволяет мне сохранять карты, которые я создаю. Он выдает изображение созданной карты в формате .bmp. Он делает это с помощью только что обнаруженной мной библиотеки под названием CImg, о которой я почти ничего не знаю. Кажется, все работает, но результирующее изображение .bmp не цветное, а вместо этого отображается в разных оттенках черного и белого. Как я уже сказал, я практически ничего не знаю о библиотеке, поэтому, если вы знаете, в чем может быть проблема, я был бы признателен за помощь.

Вот функция сохранения:

void Map::Save() {
    Vertex top_left_most, top_right_most, bottom_left_most;
    int img_w = 0, img_h = 0;

    std::vector<std::pair<GLuint, GLuint>>::iterator tl = bufferIDs.begin();            //This little block gives the _most variables valid starting vals
    glBindBuffer(GL_ARRAY_BUFFER, tl->second);
    glGetBufferSubData(GL_ARRAY_BUFFER, sizeof(TextureCoord), sizeof(Vertex), &top_left_most);
    top_right_most = bottom_left_most = top_left_most;


    for (auto i = bufferIDs.begin(); i != bufferIDs.end(); ++i) {   //SEEKS TOP LEFT MOST TILE ON MAP
        Vertex current_coord;
        glBindBuffer(GL_ARRAY_BUFFER, i->second);
        glGetBufferSubData(GL_ARRAY_BUFFER, sizeof(TextureCoord), sizeof(Vertex), &current_coord);

        if ((current_coord.x < top_left_most.x && current_coord.y < top_left_most.y) ||
            (current_coord.x == top_left_most.x && current_coord.y < top_left_most.y) ||
            (current_coord.x < top_left_most.x && current_coord.y == top_left_most.y)) {

            top_left_most = current_coord;
        }
    }

    for (auto i = bufferIDs.begin(); i != bufferIDs.end(); ++i) {   //SEEKS TOP RIGHT MOST TILE ON MAP
        Vertex current_coord;
        glBindBuffer(GL_ARRAY_BUFFER, i->second);
        glGetBufferSubData(GL_ARRAY_BUFFER, sizeof(TextureCoord), sizeof(Vertex), &current_coord);

        if ((current_coord.x > top_right_most.x && current_coord.y < top_right_most.y) ||
            (current_coord.x == top_right_most.x && current_coord.y < top_right_most.y) ||
            (current_coord.x > top_right_most.x && current_coord.y == top_right_most.y)) {

            top_right_most = current_coord;
        }
    }

    for (auto i = bufferIDs.begin(); i != bufferIDs.end(); ++i) {   //SEEKS BOTTOM LEFT MOST TILE ON MAP
        Vertex current_coord;
        glBindBuffer(GL_ARRAY_BUFFER, i->second);
        glGetBufferSubData(GL_ARRAY_BUFFER, sizeof(TextureCoord), sizeof(Vertex), &current_coord);

        if ((current_coord.x < bottom_left_most.x && current_coord.y > bottom_left_most.y) ||
            (current_coord.x == bottom_left_most.x && current_coord.y > bottom_left_most.y) ||
            (current_coord.x < bottom_left_most.x && current_coord.y == bottom_left_most.y)) {

            bottom_left_most = current_coord;
        }
    }

    img_w = (top_right_most.x + 64) - top_left_most.x;      //Calculating image dimensions for the buffer
    img_h = (bottom_left_most.y + 64) - top_left_most.y;

    GLuint *image = new GLuint[img_w * img_h];      //Creating the image buffer

    int int_start_x = 0;        //start_x and y that will be used in buffer pointer positioning computations
    int int_start_y = 0;

    //these nested fors fill the buffer
    for (GLfloat start_y = top_left_most.y; start_y != bottom_left_most.y + 64; start_y += 64) {

        for (GLfloat start_x = top_left_most.x; start_x != top_right_most.x + 64; start_x += 64) {

            bool in_map = false;
            std::vector<std::pair<GLuint, GLuint>>::iterator valid_tile;
            for (auto i = bufferIDs.begin(); i != bufferIDs.end(); ++i) {           //This for checks to see if tile corresponding to start_x & y is present in map
                Vertex current_tile_pos;
                glBindBuffer(GL_ARRAY_BUFFER, i->second);
                glGetBufferSubData(GL_ARRAY_BUFFER, sizeof(TextureCoord), sizeof(Vertex), &current_tile_pos);

                if (current_tile_pos.x == start_x && current_tile_pos.y == start_y) {
                    in_map = true;
                    valid_tile = i;
                    break;
                }
            }

            GLuint *imagepos = image;       //Repositioning the pointer into the final image's buffer
            imagepos += int_start_x + (int_start_y * img_w);

            if (in_map) {       //if in map, that tile's texture is used to fill the corresponding part of the image buffer
                GLuint *texture = new GLuint[64 * 64];
                glBindTexture(GL_TEXTURE_2D, valid_tile->first);
                glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
                GLuint *texturepos = texture;

                for (GLuint ypos = 0; ypos != 64; ++ypos) {
                    std::memcpy(imagepos, texturepos, 64 * 4);
                    texturepos += 64;
                    imagepos += img_w;
                }

                if (texture) 
                    delete[] texture;
            }
            else {              //otherwise, a default all-black array is used to fill the corresponding untiled part of the image buffer
                GLuint *black_buffer = new GLuint[64 * 64];
                GLuint *blackpos = black_buffer;
                GLuint solid_black;
                char *p = (char *)&solid_black;
                p[0] = 0;
                p[1] = 0;
                p[2] = 0;
                p[3] = 255;

                for (GLuint i = 0; i != 64 * 64; ++i) {
                    black_buffer[i] = solid_black;
                }

                for (GLuint ypos = 0; ypos != 64; ++ypos) {
                    std::memcpy(imagepos, blackpos, 64 * 4);
                    blackpos += 64;
                    imagepos += img_w;
                }

                if (black_buffer)
                    delete[] black_buffer;

            }
            int_start_x += 64;
        }
        int_start_x = 0;
        int_start_y += 64;
    }

    cimg_library::CImg<GLuint> final_image(image, img_w, img_h);   //no color!!

    final_image.save_bmp("map.bmp");

    if (image)
        delete[] image;
}

В случае, если будет полезно какое-то объяснение, Vertex — это простое struct из двух GLfloat (как и TextureCoord), bufferIDs — это std::vector из std::pair из GLuint, первое из которых представляет идентификатор текстуры, а второе представляет идентификатор VBO.

Вот запрошенные образцы изображений:

как должно выглядеть изображение (это монохромное)

То же изображение, что и выше, но созданное с использованием метода reinterpret_cast


person CornOnTheMacabre    schedule 25.07.2016    source источник


Ответы (1)


Ваша линия

cimg_library::CImg<GLuint> final_image(image, img_w, img_h);

неправильно, если вы ожидаете цветное изображение, потому что это создает одноканальное изображение. Вам нужно 3 в конце, чтобы сделать 3 канала - один для красного, один для зеленого и один для синего.

Кроме того, ваши данные хранятся в GLuint, что означает, что изображение размером 4x2 пикселя будет храниться следующим образом, т. е. с чередованием каналов по пикселям:

RGBA RGBA RGBA RGBA
RGBA RGBA RGBA RGBA

тогда как CImg хочет сохранить это в виде чередования каналов по плоскости:

RRRRRRRR
GGGGGGGG
BBBBBBBB
AAAAAAAA

Эта ссылка объясняет расположение буферов памяти CImg.

person Mark Setchell    schedule 12.09.2016