| KyleMiles (83) | |||
|
Okay, so yesterday I posted to this thread, and someone help me out a lot with a few problems I had, however, I am still having issues with a BMP loader I have made. I will post the code for it, and what I see. Thank you for your time!! Code:
What I see (Both pictures are supposed to look like the one on the right): http://tinypic.com/r/15kc41/6 - Kyle | |||
|
|
|||
| Disch (8349) | |
|
Pretty much most of the stuff I mentioned in the other thread still applies. 1) You still are ignoring the bitmap pitch (rows are padded to 4-byte boundaries) 2) You still are ignoring the OpenGL limitation where textures must have a power-of-2 size. 3) biBitCount is the depth of pixels in bits.... not bytes. Divide it by 8 to get the number of bytes per pixel. 4) You still are not taking into consideration that bitmaps are stored bottom row first. #2 is probably your biggest problem here. EDIT: Also, I think biOffBits might not be the offset from the start of the file, but might be the offset from after the BITMAPFILEHEADER. Don't know for sure -- you'll have to check the documentation. | |
|
Last edited on
|
|
| KyleMiles (83) | |
|
I don't know how to solve any of these (Except 3).... Sorry, I'm relativity new to OpenGL (and it doesn't help that I'm 14). - Kyle | |
|
Last edited on
|
|
| Disch (8349) | |||
|
These are not really OpenGL problems as much as they're data manipulation problems. Anyways.... Bitmap pitch The pitch is the number of bytes between rows. This has to be calculated, as it is not stored directly in the bitmap header. The pitch of the bitmap is equal to round_up_to_4byte_boundary( bytes_per_pixel * pixel_width ) So if there are 3 bytes per pixel, and you have a width of 150... this means there are actually 452 bytes per row... not 450. Your code will need to account for this by either making the rows wider... or skip bytes in the file between reading each row. Bitmaps are upside-down Normal bitmaps are stored with the bottom row first and the top row last. OpenGL textures (and pretty much every other kind of imaging standard everywhere) does it the exact opposite, with the top row first. This means you will need to flip the image somehow. Either after it's loaded, or do it while you're loading. Note that this isn't always the case. You can tell if an image is upside-down or not by looking at the biHeight value in the header. If it's positive, the bitmap is upside-down. If it's negative, the bitmap is rightside-up. OpenGL needs power of 2 sizes The buffer you give to openGL might have to be larger than the image data you have. For example if your image is 160 x 100 pixels... this means the smallest texture that image will fit on is 256 x 128 (unless you break the image up and rearrange it -- but that's another topic I won't get into). What you need to do Basically... this code is wrong.
I would recommend you do several things differently: 1) Get the width, height, and bytes-per-pixel (bpp) value from the header 2) Use the width and bpp values to calculate the pitch 3) Use the width and height to calculate how big of an OpenGL texture you'll need. Remember the texture dims must be >= the image dims... and the texture dims must each be an exact power of 2 (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024) 4) Allocate a buffer big enough to hold the entire texture (ie: power of 2 texture dims). Probably a good idea to wipe it to transparent black as well because you probably will not set every pixel according to the bmp file contents, due to the necessary power-of-2 padding. 5) Start reading rows individually from the file, rather than trying to read the entire image in one read. 6) If the image needs to be vertically flipped (positive height), then you can flip it by reading rows into different areas in the buffer. For example if the image is 10 pixels tall, you can read the first row in the file into row 9 of your texture buffer. 2nd row in the file goes in row 8 of your texture, etc, etc. | |||
|
|
|||
| KyleMiles (83) | |
|
Okay... Thanks, but I still have a few questions, that I'll match to your numbers: 1. Don't I already do this? 2. Once I calculate the pitch, what do I do with it? 3. The OpenGL dimensions being the shape I apply the picture to to? 4. Huh? 5. How? (Obviously a while/for loop, but still...) 6. Store the image data in a multi-dimensional list? - Kyle | |
|
|
|
| Disch (8349) | |||
|
1. Yes you do. Sorry for the confusion. 2. Then you know how many bytes you have to read from the file in order to get 1 row of pixel data. 3 & 4. There are 2 different images here. One is the source image (the bitmap file). This has its own width/height. The other image is the destination image (the OpenGL texture). This image must have dims that are a power of 2. You will be creating a buffer (a chunk of memory: ie, that chunk you are malloc'ing). This buffer will be the OpenGL texture. This means you must create that buffer with the power-of-2 dimensions. After you malloc the buffer, you will want to zero it. Since it will be larger than the source image, not all pixels will be drawn to it, and you don't want garbage pixels hanging around. So filling the buffer with zero up front ensures that everything is wiped clean to black. 5 & 6. You need to know how to get to any individual row in your malloc'd buffer. This is very easy:
As you are loading the file, do a for loop and read 1 row's worth of data (ie: read 'pitch' bytes) into the desired row number (use above math to get the buffer to the desired row) There is no mulitdimentional list. You're just working with a big buffer. | |||
|
|
|||
| KyleMiles (83) | |||
|
Sorry. School has prevented me from doing much coding, at all. Okay, so does the memory I allocate to the heap have to be a power of two, or the shape I apply them to have to be? And would I detect how big it is by reading the width and height, then having a bunch of if statements comparing the texture to larger and larger, and use the first one that is larger? Or could I just make a HUGE (2048) memory block? - Lazy As for reading in row by row, how do I know where to start reading in the file? After that, I could do a
Correct? Plus a random question, I currently read the texture every loop. Can I just save the texture number that it is (the one I bind to) and just do it that way? And one last thing, how do I make the picture so that around the image it is see through, such as not seeing white corners around a red ball? Thank you again, - Kyle | |||
|
Last edited on
|
|||
| Disch (8349) | |||||||
When you create an OpenGL texture -- the width/height you specify must be powers of 2. So I guess that means "the shape you apply them to".
Try to keep your textures under 1024x1024 as iirc that is a maximum texture size on some systems.... but I don't know if that has changed or not. Anyway finding the nearest power-of-2 size is pretty simple... just have a loop where you keep multiplying a value by 2 until it's >= the necessary size.
Not sure I understand this question. You start reading the file where the pixel data starts in the file. I thought you had already figured this part out? IIRC there's an 'offset' in the file header that tells you where the pixel data starts... but I don't recall where it is or how to use it. I'd have to look up the bmp file specs again.
This is one way to do it. Personally I would fill the buffer with 0 all at once before you start reading pixel data. Then you start with a fully transparent buffer and can just read the pixel data on top of it, not worrying about the parts that the pixel data doesn't fill. If that makes sense...
This is very bad. You probably should be loading the texture exactly once. Once it's loaded it stays in memory until you destroy it. Therefore you do not have to keep loading it over and over (and you shouldn't!). Loading is a very slow process, so you don't want to do it repeatedly. Once the texture is loaded the first time, you can just bind to it and use it for drawing as many times as you need.
You will need to do a few things: 1) Enable alpha blending (this requires 2 or 3 function calls in OpenGL, but I can't remember exactly what they are... glEnable(GL_ALPHA_BLEND); I think... and glBlendFunc( xx, xx ); is the other one maybe... look it up) 2) Your texture will need to have an alpha channel. This means you'll probably want to create a 32-bit ARGB texture instead of a 24-bit RGB texture. The alpha channel specifies the 'opacity' of a pixel. 0=transparent, FF=fully opaque. 3) Your loader will have to read individual pixels from the file and convert them from 24-bit (as stored in your bitmap) to 32-bit (as needed by your OpenGL texture), assigning an appropriate alpha value to them. This means you can no longer load the image row at a time, but instead must load it pixel at a time. It makes it more complicated for sure. I would recommend not worrying about adding the alpha channel until you have non-alpha texture loading working first. | |||||||
|
|
|||||||
| KyleMiles (83) | |||
Okay, I finally got some time to code. However, I don't know if it's pure exhaustion, or idiocy, but I don't know what to do. I have the size of the buffer as a ^2, or whatever you said it needs to be, and not reading in the texture every frame, but now I'm confused about how I read the individual bytes/bits (it's all turning to mush in my mind)... However, I'm going to post my current texture loader, and I would love for some more help. As always, thank you.
- Kyle | |||
|
|
|||
| Disch (8349) | |||
|
I don't think I can explain it in any more detail than I already have. The only thing I could really do is write the code and show it to you, but I'm hesitant to do that because I don't think that's what you want. (am I wrong?) Do you have a hex editor? Try opening a simple bmp file in the hex editor and examining it that way. That way you can see how the image is stored... which might give you an idea of how to manipulate it. PS: you're calculating the pitch incorrectly. A 24-bit bitmap with a width of 10 will have a pitch of 32 (3 bytes per pixel * 10 pixels = 30, pad to 32). But by your formula: Pitch = ((BiBitCount * 8) * (Width));Bitcount * 8 * Width = 24 * 8 * 10 = 1920 which is crazy wrong. EDIT: I was bored... so here is some completely untested code. You'll have to plug in some details, but it's mostly commented. Feel free to ask questions if parts of it aren't clear:
| |||
|
Last edited on
|
|||
| naraku9333 (923) | |
| I had an assignment a few semesters back where I needed to read in a bmp file. Maybe reding the source will help you out a bit http://home.comcast.net/~svogel76/Projects/Console_app/bitmap.cpp It just reads in a bmp file and saves it to a different file. | |
|
|
|