Page 1 of 2 12 LastLast
Results 1 to 10 of 20

Thread: TGA fliped out

  1. #1
    Join Date
    Oct 2003
    Location
    My little corner of the world
    Posts
    1,460

    TGA fliped out

    Ok,
    after more than 5 hours trying to figure out why the heck SOME of my TGA files were upside down i finally figured it out

    This all began when i tried to implement the drawing text functionality following the VTM specifications. The thing was that i was getting VERY weird text as output (trying to output "OpenGL" i'd get something like "Z~34!" (at the best case)).

    After a LOT of trial and error, i figured out that my image was being parsed upside down AND mirrored (weird huh?).
    I tried looking at my code, inverting normals, pixel drawing order, texture coordinates, etc. All to no vail (well, actually now i know exactly how to think about texture coordinates).

    In despair i googled for some code around the web to try to figure out WHAT i was doing wrong. So i find a quick tut on textures, that had the exact same things i was doing, BUT was working.
    In despair i copied the texture i was using in my program to replace the one the program i downloaded was using, and, to my surprise IT WAS UPSIDE DOWN!

    Good news: my code was good (i tested with the texture the demo came with)
    Bad news: what the heck is the problem with textures?!

    Back to google!
    So... after half an hour or so i discovered that TGA files CAN be stored upside down (and apparently thats what my editing programs were doing (including the Bitmap Font Builder Joel was using)). So... how to fix it?!

    More google
    with the help of google, wotsit.org and the TGA specification i discovered a field that Joel didn't mentioned (or at least i didn't saw he mentioning), where is stored if the image is upside down/mirrored (for those who cares, i'm talking about the Image Descriptor field under the Image Specification field, bits 4 and 5 to be precise. For the lazy ones, bottom of page 8 of the TGA specification).

    Any way, after fighting with some pointers and doing some calculations on how to point to the right pixels that needed to be swapped i got it working (weeeeeeeeeeeeee).

    Basically what i did was:
    1) add another byte at the end of the TGAHeader type defined by Joel
    Code:
    GLubyte ImageDescriptor;
    2) figure out if the image was flipped Horizontally or Vertically
    Code:
        bool flipH = ((header.ImageDescriptor & 0x10) == 0x10);
        bool flipV = ((header.ImageDescriptor & 0x20) == 0x20);
    3) flip the image when appropriated
    Code:
    void Texture::flipImage(unsigned char * image, bool flipHorizontal, bool flipVertical, GLushort width, GLushort height, GLbyte bpp){
        GLbyte Bpp = bpp / 8;        
    
        if (flipHorizontal){
            for (int h = 0; h < height; h++) {
                for (int w = 0; w < width / 2; w++){                
                    swap(image + (h * width + w) * Bpp, image + (h * width + width - w - 1)* Bpp, Bpp);
                }
            }
        }
    
        if (flipVertical){
            for (int w = 0; w < width; w++){
                for (int h = 0; h < height / 2; h++) {
                    swap(image + (h * width + w) * Bpp, image + ((height - h - 1) * width + w)* Bpp, Bpp);
                }
            }
        }
    }
    
    void swap(unsigned char * ori, unsigned char * dest, GLint size){
        GLubyte * temp = new unsigned char[size];
    
        memcpy(temp, ori, size);
        memcpy(ori, dest, size);
        memcpy(dest, temp, size);
    
       delete [] temp;
    }
    after all this i can load any TGA i want and it'll display at the right orientation. Thats sweet or what?!
    Attached i'll send two versions of the program: one with flipping enabled and other with it disabled, and a bunch of textures: font.tga (the font used to show the FPSs, its stored upside down), surface_ME_Fliped.tga (a picture of me, stored upside down), and two versions of the texture that came with the tut i got one upside down(surface_Fliped.tga) and other normal (surface_Normal.tga).
    All you have to do is change the names of the .tga files to surface.tga and it will be used by the program. Run both programs with the same textures and see how all pics are upside down, or mirrored.

    Hope this helps somebody out there

    OW yeah...
    I also think the absence of the ImageDescriptor field on the TGAHeader can be the cause of the problem reported by Zecster in this thread: http://3dbuzz.com/vbforum/showthread.php?t=110839

    Cheers,
    KM
    Attached Files Attached Files
    Last edited by KhaoticMind; 10-04-2005 at 12:15 PM.
    "Things are like they are because thats how they are suposed to be"

  2. #2
    Join Date
    Feb 2005
    Location
    Bellevue, WA
    Posts
    3,251
    Hey KM,

    Good job on finding out the problem!

    A couple of suggestions though: if you're leave the method of getting the flipH and the flipV the way you have it, you should make constants for 0x10 and 0x20.

    Also, to improve performance of loading your TGA textures, you might want to look into reading in the texture "backwards" and/or "mirrored" instead of looping through the entire texture again to flip it. Make sense?

    Great job though!

    David

    "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." ~Rich Cook

  3. #3
    Join Date
    Oct 2003
    Location
    My little corner of the world
    Posts
    1,460
    hey owen
    thanks a lot for you words

    yeah, i was thinking about making the 0x10 and 0x20 constants, but i didn't had the time for it (had to clean the house and do some laundry). This was the kind of thing that goes by the saying "make it work, then make it work efficiently"

    About reading the file backwards/mirrored dunno if this is possible/would solve the problem, but i'll do some more testings tomorrow.
    Any ways, i think of leaving the flip function "just in case", ya know


    KM
    "Things are like they are because thats how they are suposed to be"

  4. #4
    Join Date
    Feb 2005
    Location
    Bellevue, WA
    Posts
    3,251
    I don't mean to read the file backwards/mirrored, but rather read in the data into the array (assuming it's an array, could be way off here though) backwards. Does that make sense?

    But yes, definately keep the flip() function around until/if you get the "optimized" way working.

    David (Owens)

    "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." ~Rich Cook

  5. #5
    Join Date
    Jan 2003
    Posts
    536
    If I recall, there is some way of knowing which programs export TGA in reverse order, but I have no idea what it was. Bitmaps can be the same way, also.

    Loading image files is pretty cool, though, heh.

  6. #6
    Join Date
    Nov 2003
    Location
    Michigan
    Posts
    661
    I know this is 2 months old but I just ran into this problem myself and knew it was the TGA file. I guess I'm still too new to understand where you are putting your code to fix this issue. I can use a non flipped TGA but I'd rather have the ability to read any TGA, flipped or not.

    If you still have the code for this could you maybe explain where you are adding this at? I know where the GLubyte ImageDescriptor; needs to go but I'm lost on the rest. Damn I hate being a noob sometimes

  7. #7
    Join Date
    Jan 2003
    Posts
    536
    Man do I not remember this thread, lol. From what I read from KM's post, he is doing his code inside the function that handles copying the bits from the file to your memory buffer. In n00b terms, when you copy from the file to your array, you flip them. How do you know when to flip them? Again, according to KM's post, you can check this:

    Code:
        bool flipH = ((header.ImageDescriptor & 0x10) == 0x10);
        bool flipV = ((header.ImageDescriptor & 0x20) == 0x20);
    Which says that if flipH is true (dont worry about the code if you dont understand it), then flip the horizontal, and the same for veritical iff flipV. Since all files (or most, anyway) have headers (hence the "header."), you check this by reading the header. If you dont know what the header is, read on.

    Files, like any data, are ...well, data. Bytes and so forth, 0s and 1s. There is no real difference between image data and anything else you would find stored in your computer. Because of this, we, as programmers, need a way to tell our "dumb" computers, and other programmers (technically, a program is talking with the programmer, if you think about it), how to read our data (the image), and where it is. To do this, we create "headers" which are just data themselves. The type of data determines its size, and size of the data determines where the next part of the data starts, right? To you and I, a clump of 0s and 1s is just that, a clump. But when you know that a byte is 8 bits, and an int is 4 bytes, you have something to start from. If the header consists of 4 ints, then it must be 16 bytes (4 * 4 bytes). All you have to do then is know the order (which is complicated, but simple, heh), and you can read the data.

    So why botehr with a header? Well, in my crappy example, a header is simple and pointless. But if the header of an image file contains the starting position of the image data, you have somethign useful! You need to know where the header (and other possible info) stops, and where the image begins. After that, the bit depth (32bit, 24, 16) determines the "stride" of a pixel. Since each pixel is, for example, 24 bits, thats 3 bytes. Thus, an array of 3 * width * height can hold the entire image. Once the "stride" is known, then all that is left to do is fill your array. Most people use char arrays (or byte arrays, same thing, data is data afterall!) to hold the independant channel data. Thus your R, G and B data is easily seperated. But, when you copy this over to the buffer, it doesnt necessarily matter what data type it is, since its just copied as one whole block anyway. How the API (OGL or D3D) handles it internally is irrelevant to us, as long as we can tell it where to go find it, and how big it is.

    If I'm not telling you anything new, good. If I'm wrong about something, correct me, otherwise, dinner is ready, good day.

  8. #8
    Join Date
    Mar 2005
    Location
    Ontario, Canada
    Posts
    1,750
    KhaoticMind, I think you have a memory leak in your swap function

    Quote Originally Posted by KhaoticMind
    Code:
    void swap(unsigned char * ori, unsigned char * dest, GLint size){
        GLubyte * temp = new unsigned char[size];
    
        memcpy(temp, ori, size);
        memcpy(ori, dest, size);
        memcpy(dest, temp, size);
    }
    you create a new temp pointer but you never delete it.
    C++, 3D OpenGL and Game Programming video tutorials:
    www.MarekKnows.com
    Play my free games: Ghost Toast, Zing, Jewel Thief

  9. #9
    Join Date
    Oct 2003
    Location
    My little corner of the world
    Posts
    1,460
    yeap,
    leak, leak!
    very ugly leak by the way

    thanks for pointing that out


    KM
    Last edited by KhaoticMind; 10-04-2005 at 03:00 PM.
    "Things are like they are because thats how they are suposed to be"

  10. #10
    Join Date
    Jan 2003
    Posts
    536
    I've leaked 1 bitmap per frame before, lol. Only once, though...

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •