Just Made an Article.

Pages: 12
closed account (N36fSL3A)
Yeah, well I just made an article on loading .bmp files. It uses OpenGL and C++ (not C!).

I realized there were only tutorials that used crappy C functions instead of C++ ones, so I decided to write one.

It may not be the best, however I'd like your feedback.

http://www.cplusplus.com/articles/GwvU7k9E/

It's not live yet, it's waiting for approval.

Once it passes (if it does), I'll be sure to let y'all know.

ARTICLE:

INTRO

If you clicked on this article, you must want to load a .bmp file into your applications.

Although .bmp files may be large in size, they're still widely used in many applications, and well documented on the internet.

Now there are many tutorials on the internet for doing this, however they mostly use the C way of doing it. This will be a C++ tutorial, NOT a C one.

====================

THINGS TO KNOW

This tutorial assumes you're using windows, but it doesn't use windows specific functions. You can easily write your structures. Wikipedia has a pretty good representation of the bitmap headers.

This also uses OpenGL, but it shouldn't be too hard to port to DirectX.

Also, we have a new type. Uint8's are essentially unsigned chars. We also have to include fstream for this.

====================

TUTORIAL

Alright now let's start. We'll have a function that returns a GLuint for our texture.

The function takes 2 parameters.
int LoadBMP(const char* location, GLuint &texture);

The first is the location of the file. The second is a reference to a texture unsigned int, which is the ID of the texture generated.

Alright now get to actual code. We first start off with four pointers, and we'll set 'em to nullptr (or NULL if you'd like).
1
2
3
4
5
6
	Uint8* datBuff[2] = {nullptr, nullptr}; // Header buffers

	Uint8* pixels = nullptr; // Pixels

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


They're really self explanitory.

We use fstream, and open up a file, then check if it's open.
1
2
3
4
5
6
7
8
	// The file... We open it with it's constructor
	std::ifstream file(location, std::ios::binary);
	if(!file)
	{
		std::cout << "Failure to open bitmap file.\n";

		return 1;
	}


Now, we allocate memory for the headers, get the values with the data buffers.
1
2
3
4
5
6
	// Allocate byte memory that will hold the two headers
	datBuff[0] = new Uint8[sizeof(BITMAPFILEHEADER)];
	datBuff[1] = new Uint8[sizeof(BITMAPINFOHEADER)];

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


Once we have the data loaded, we construct the loaded data into the headers.
1
2
3
	// Construct the values from the buffers
	bmpHeader = (BITMAPFILEHEADER*) datBuff[0];
	bmpInfo   = (BITMAPINFOHEADER*) datBuff[1];


Since we have that loaded, we check if the file is a BMP file.
1
2
3
4
5
6
	// Check if the file is an actual BMP file
	if(bmpHeader->bfType != 0x4D42)
	{
		std::cout << "File \"" << location << "\" isn't a bitmap file\n";
		return 2;
	}


Allocate pixel memory, then jump to where the pixel data starts and read.
1
2
3
4
5
6
	// First allocate pixel memory
	pixels = new Uint8[bmpInfo->biSizeImage];

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


Since bitmaps store pixels as BGR, we convert it to RGB.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
	// We're almost done. We have our image loaded, however it's not in the right format.
	// .bmp files store image data in the BGR format, and we have to convert it to RGB.
	// Since we have the value in bytes, this shouldn't be to hard to accomplish
	Uint8 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;
	}

	// Set width and height to the values loaded from the file
	GLuint w = bmpInfo->biWidth;
	GLuint h = bmpInfo->biHeight;


Now we simply generate the texture with OpenGL. If you're using DirectX, ignore this, and use whatever you do to create textures.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
	/*******************GENERATING TEXTURES*******************/

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

	GLint mode = GL_RGB;                   // Set the mode

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	 
	// Create the texture. We get the offsets from the image, then we use it with the image's
	// pixel data to create it.
	glTexImage2D(GL_TEXTURE_2D, 0, mode, w, h, 0, mode, GL_UNSIGNED_BYTE, pixels);

	// Unbind the texture
	glBindTexture(GL_TEXTURE_2D, NULL);

	// Output a successful message
	std::cout << "Texture \"" << location << "\" successfully loaded.\n";

	// Delete the two buffers.
	delete[] datBuff[0];
	delete[] datBuff[1];
	delete[] pixels;

	return 0; // Return success code 


And that's about it. Please rate this article.

Have fun with your new BMP Texture loader!

====================
Last edited on
ACCESS DENIED
Only the author can access non-public items (art-SA50)
You are logged in as user "Catfish4". That user is not authorized to access this feature.
If you are not this user, please, log out, and log back in with your credentials. 

We'll all have to wait until the article is Approved, before we can comment on it.

So naturally if you want feedback, next time you should post the draft here in the Lounge before you send it for approval.

I realized there were only tutorials that used crappy C functions instead of C++ ones, so I decided to write one.

Cool, I didn't know OpenGL had a C++ API.
closed account (N36fSL3A)
Cool, I didn't know OpenGL had a C++ API.
You knew what I meant ;)
closed account (z05DSL3A)
Lumpkin wrote:
that used crappy C functions instead of C++ ones, so I decided to write one
hmm...write your own crappy C++ functions? ;-)
Last edited on
closed account (N36fSL3A)
:p No.

But I converted the a forum post. I posted it in the OP.
Last edited on
But I converted the a forum post. I posted it in the OP.

And what an unpalatable move this was! Anyway!

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

First, where is Uint8 from?
If it's from Windows.h could you give me a reason why it's any better than the standard std::uint8_t from cstdint (since you're using elements of C++11 anyway)?

Second, dynamic memory allocation using dumb pointers? Which come from good old C? Really?

Why not use an std::vector or even smart pointers from C++11 like std::unique_ptr?

Third, I can't help but notice this is incomplete code, as in you must have written a Texture class, no? Where is it?
Almost everything in the text of the article is repeated in the code blocks (begging the question, "Why split up the code block?")

What does a comment on the lines:

1
2
3
4
	glGenTextures(1, texture);             // Generate a texture
	glBindTexture(GL_TEXTURE_2D, texture); // Bind that texture temporarily

	GLint mode = GL_RGB;                   // Set the mode 


buy you? The code already says what it does.

Why do you use dynamic memory for the headers?

Why is the loading of the image not separated from the generation of an OpenGL texture?

Why is the function: int Texture::LoadBMP(const char* location, GLuint &texture); with no explanation of what Texture is? Is it a class? A namespace? Why introduce it at all?

Why are you returning magic numbers from the function?
closed account (N36fSL3A)
I'm returning error codes.

That was a typo, I meant to delete the Texture:: thing.

I did the dynamic memory thing because I thought I was supposed to.

@Catfish
I wrote:
Also, we have a new type. Uint8's are essentially unsigned chars
(Under things to know)

Catfish wrote:
Why not use an std::vector or even smart pointers from C++11 like std::unique_ptr?
But how would I feed the pixel data to OpenGL?

And yes, I took this from my game's Texture class and modified it a bit.
Last edited on
But how would I feed the pixel data to OpenGL?

http://www.cplusplus.com/reference/vector/vector/data/
http://www.cplusplus.com/reference/memory/unique_ptr/get/

Edit:
1
2
3
		tmpRGB        = pixels[i];
		pixels[i]     = pixels[i + 2];
		pixels[i + 2] = tmpRGB;


Is there any reason why you couldn't use std::swap() instead?
http://www.cplusplus.com/reference/algorithm/swap/

In fact is there any reason why you couldn't let OpenGL know you wish to use BGR encoding instead of RGB? Hint: glext.h.
Last edited on
> I did the dynamic memory thing because I thought I was supposed to.
... you weren't.
While it is an interesting article, I don't think it is beneficially helpful to programmers. I don't think it will be approved at this time.
closed account (N36fSL3A)
Eh, okay. It was worth a try anyway.
closed account (o1vk4iN6)
Since bitmaps store pixels as BGR, we convert it to RGB.

You can just change some of the parameters in glTexImage2D() and you won't have to do any conversion.

Already a memory leak in your program as well, you didn't delete your "pixels" variable.

1
2
GLint mode = GL_RGB;                   // Set the mod
glTexImage2D(GL_TEXTURE_2D, 0, mode, w, h, 0, mode, GL_UNSIGNED_BYTE, pixels);


This line is also :\, why does this comment even exist. iirc this actually affects the internal representation of the pixels, so using GL_RGB is 4 floats, you are essentially using x4 the space of the texture without increasing quality.
Last edited on
closed account (N36fSL3A)
There is a memory leak. My bad, I forgot to add it as it was originally a function in my texture class. pixels was a class variable that was deleted in the destructor.

I could have done the GL_BGR thing, but it was for my engine's convenience.
Last edited on
closed account (o1vk4iN6)
Why would you keep the pixels loaded in memory for the entire duration of the texture class (which I assume the class would also be used for binding the texture) ? That's a lot of wasted memory keeping the texture in GPU memory but also in main memory.

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, w, h, 0, GL_BGR, GL_UNSIGNED_BYTE, pixels);

It's not jsut setting mode to GL_BGR, one parameter affects how the pixel data is read and the other affects how it is stored on the GPU.
Last edited on
closed account (N36fSL3A)
I'm keeping it in memory so I can directly access the data.

EDIT: Woah, I just realized how stupid that sounded.
Last edited on
http://scientificninja.com/blog/dont-write-tutorials

The larger problem with tutorials is that there are just so many of them, and most of them are written by people who at best have only a passing understanding of the subject. Frequently the author lacks even that basic foundation, and just thinks he or she understands the material
@Abramus
I don't know which I like more: 1) the quote from the link or 2) the name of the url 'scientificninja'.
closed account (3qX21hU5)
scientificninja has a collection of great articles and would definitely recommend anyone to read some of them :).

I especially love this one which I link all the time http://scientificninja.com/blog/write-games-not-engines
closed account (N36fSL3A)
What if I WANT to write an engine?
Pages: 12