Loading a BMP and Mapping to Square with openGL C++

时间:2016-04-04 18:36:35

标签: texture-mapping texture2d

i am simply trying to load a 2D image with openGL and map it to a square. I have looked at many online fourms and tried many different ways to do this, tried loading many different files to load but each attempt gets a different error. I would prefer not to use an external library.

The image loads incorrectly:

program output

Image trying to load:

source image

#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>
#include <math.h>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <iostream>
#include <stdint.h>

using namespace std;

#define size 200
#define other 100

int main()
{
    GLuint _vertexBufferID;

    GLfloat objects[] = {
        other,other,0.0f,
        size, other,0.0f,
        size,size,0.0f,
        other,size,0.0f
    };
    GLfloat texture[] = {
        0.0f,0.0f,
        1.0f,0.0f,
        1.0f,1.0f,
        0.0f,1.0f
    };

    sf::Window window(sf::VideoMode(1000, 800, 32), "SFML OpenGL");//!<        Create the main window

   glEnable(GL_DEPTH_TEST);//!< Enable Z-buffer read and write
   glDepthMask(GL_TRUE);

   glClearColor(1.0f,1.0f,1.0f,1.0f);
   glViewport(0.0f,0.0f,1000,800);

   glMatrixMode(GL_PROJECTION);
   gluOrtho2D(0,1000,0,800);
   glMatrixMode(GL_MODELVIEW);

   glEnable(GL_TEXTURE_2D);

   glEnableClientState(GL_VERTEX_ARRAY);
   glEnableClientState(GL_TEXTURE_COORD_ARRAY);

   glVertexPointer(3,GL_FLOAT,0,objects);
   glTexCoordPointer(2, GL_FLOAT, 0, texture);

   unsigned char* datBuff[2] = {nullptr, nullptr}; // Header buffers

   unsigned char* pixels = nullptr; // Pixels

   BITMAPFILEHEADER* bmpHeader = nullptr; // Header
   BITMAPINFOHEADER* bmpInfo   = nullptr; // Info 

   // The file... We open it with it's constructor
   std::ifstream file("other.bmp", std::ios::binary);

   // Allocate byte memory that will hold the two headers
   datBuff[0] = new unsigned char[sizeof(BITMAPFILEHEADER)];
   datBuff[1] = new unsigned char[sizeof(BITMAPINFOHEADER)];

   file.read((char*)datBuff[0], sizeof(BITMAPFILEHEADER));
   file.read((char*)datBuff[1], sizeof(BITMAPINFOHEADER));

   // Construct the values from the buffers
   bmpHeader = (BITMAPFILEHEADER*) datBuff[0];
   bmpInfo   = (BITMAPINFOHEADER*) datBuff[1];

   // First allocate pixel memory
   pixels = new unsigned char[bmpInfo->biSizeImage];

   // Go to where image data starts, then read in image data
   file.seekg(bmpHeader->bfOffBits);
   file.read((char*)pixels, bmpInfo->biSizeImage);

   unsigned char tmpRGB = 0; // Swap buffer
   for (unsigned long i = 0; i < bmpInfo->biSizeImage; i += 3)
   {
        tmpRGB        = pixels[i];
        pixels[i]     = pixels[i + 2];
        pixels[i + 2] = tmpRGB;
   }

   GLuint textureBuf;
   glGenTextures(1, &textureBuf);             // Generate a texture
   glBindTexture(GL_TEXTURE_2D, textureBuf); // Bind that texture temporarily

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP);

   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bmpInfo->biWidth, bmpInfo->biHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);

   while (window.isOpen())//!< Start game loop
   {

        sf::Event Event;//!< Process events
        while (window.pollEvent(Event))
        {   }

        window.setActive();

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//!< Clear colour and depth buffer
        glClear(GL_COLOR_BUFFER_BIT);

        glDrawArrays(GL_QUADS,0,4);//sizeof(vertexData));

        window.display();
    }

    return EXIT_SUCCESS;
}

1 个答案:

答案 0 :(得分:0)

To follow up on my comment guess, and assuming you can't just use an off-the-shelf BMP loader for some reason, try dumping your current attempt to load the full headers in favour of:

uint32_t data_offset;
file.seekg(10);
file.read((char *)&data_offset, 4);

uint32_t image_width, image_height;
file.seekg(18);
file.read((char *)&image_width, 4);
file.read((char *)&image_height, 4);

uint32_t image_size;
file.seekg(34);
file.read((char *)&image_size, 4);

file.seekg(data_offset);
file.read((char*)pixels, image_size);

Coupled with the rest of your code this still assumes, amongst other sins:

  • the machine you're running on is little endian;
  • the BMP is an uncompressed 24-bit BGR image (per your byte swap later);
  • the info header is one that either is or is an extension of BITMAPINFOHEADER.

... but if it solves the immediate problem then that would confirm that the issue is merely a false assumption about how your compiler will layout structs in memory.