locked
Differences between running with f5 and ctrl-f5? (program crashing with ctrl-f5!!) RRS feed

  • Question

  • Hi,
    i'm here because i have a BIG problem, and i have no idea about how to solve it.
    I'm developing a cross-OS (windows/linux) opengl project, using glut and c++.
    In visual c++ 2005 express, i've created the project as an empty project.
    The problem is that under windows, it works only if run with f5 (so the debugger is attached).
    If run with ctrl-f5 (or outside of visual studio), it crashes.. both Debug and Release versions.

    I've backtraced the problem to tga loading, in a malloc or fread call (depends on which files i want to load). The STRANGE things is that those functions are NOT failing, returning the appropriate return value, they are directly CRASHING the program. i've checked the formal parameters and they seem to be ok?!?

    So, i'd like to know all the differences between running with f5 and ctrl-f5...
    or (of course) , if someone already knows, why is it crashing?

    Thanks in advance ;)
    Friday, March 9, 2007 8:30 AM

Answers

  • Don't be sorry, I actually learned some new things through your posts ;)

    edit: looks like i've narrowed down the problem...
    i was adding back in some of the image-flipping functions i used, and just as i put them in it started to crash again. A tga file can have it's origin in all the 4 corners, so if it wasn't in the top left one i flipped the image accordingly, like this:
    switch(origin)
        {
        case TGA_ORIGIN_BOTTOM_LEFT:
            imgFlipVertical(texture);
            break;
        case TGA_ORIGIN_BOTTOM_RIGHT:
            imgFlipVertical(texture);
            imgFlipHorizontal(texture);
            break;
        case TGA_ORIGIN_TOP_LEFT:
            break;
        case TGA_ORIGIN_TOP_RIGHT:
            imgFlipHorizontal(texture);
            break;
        }

    the functons are as follows
    void imgFlipHorizontal(TextureS * pImg)
    {
        unsigned char r, g, b, a;
        unsigned int x, y;

        if (pImg->type == IMG_INDEX)
        {
            // Not supported!
            return;
        }

        for (y=0;y<pImg->height/2;y++)
        {
            for (x=0;x<pImg->width;x++)
            {
                r = GET_R(pImg, x, y);
                g = GET_G(pImg, x, y);
                b = GET_B(pImg, x, y);
                a = GET_A(pImg, x, y);
               
                SET_RGBA(pImg, x, y, GET_R(pImg, x, pImg->height-y),
                    GET_G(pImg, x, pImg->height-y),
                    GET_B(pImg, x, pImg->height-y),
                    GET_A(pImg, x, pImg->height-y));

                SET_RGBA(pImg, x, pImg->height-y, r, g, b, a);
            }
        }

    }

    void imgFlipVertical(TextureS * pImg)
    {
        unsigned char r, g, b, a;
        unsigned int x, y;

        if (pImg->type == IMG_INDEX)
        {
            // Not supported!
            return;
        }

        for (y=0;y<pImg->height;y++)
        {
            for (x=0;x<pImg->width/2;x++)
            {
                r = GET_R(pImg, x, y);
                g = GET_G(pImg, x, y);
                b = GET_B(pImg, x, y);
                a = GET_A(pImg, x, y);
               
                SET_RGBA(pImg, x, y, GET_R(pImg, pImg->width-x, y),
                    GET_G(pImg, pImg->width-x, y),
                    GET_B(pImg, pImg->width-x, y),
                    GET_A(pImg, pImg->width-x, y));

                SET_RGBA(pImg, pImg->width-x, y, r, g, b, a);
            }
        }
    }

    #define GREY(R,G,B)   (unsigned char)(R*0.61f + G*0.29f + B*0.15f)

    #define SET_RGBA(pImg, x, y, r, g, b, a)     \
        switch(pImg->type) \
        {        \
        case IMG_RGB:  \
            pImg->imageData[3*(pImg->width*y+x)] = r; \
            pImg->imageData[3*(pImg->width*y+x)+1] = g; \
            pImg->imageData[3*(pImg->width*y+x)+2] = b; \
            break; \
        case IMG_RGBA: \
            pImg->imageData[4*(pImg->width*y+x)] = r; \
            pImg->imageData[4*(pImg->width*y+x)+1] = g; \
            pImg->imageData[4*(pImg->width*y+x)+2] = b; \
            pImg->imageData[4*(pImg->width*y+x)+3] = a; \
            break; \
        case IMG_GREY: \
            pImg->imageData[pImg->width*y+x] = GREY(r, g, b); \
            break; \
        }

    #define GET_R(pImg, x, y) \
        (pImg->type == IMG_RGB ? pImg->imageData[3*(pImg->width*y+x)] : \
        (pImg->type == IMG_RGBA ? pImg->imageData[4*(pImg->width*y+x)] : \
        (pImg->type == IMG_GREY ? pImg->imageData[pImg->width*y+x] : 0)))

    #define GET_G(pImg, x, y) \
        (pImg->type == IMG_RGB ? pImg->imageData[3*(pImg->width*y+x)+1] : \
        (pImg->type == IMG_RGBA ? pImg->imageData[4*(pImg->width*y+x)+1] : \
        (pImg->type == IMG_GREY ? pImg->imageData[pImg->width*y+x] : 0)))

    #define GET_B(pImg, x, y) \
        (pImg->type == IMG_RGB ? pImg->imageData[3*(pImg->width*y+x)+2] : \
        (pImg->type == IMG_RGBA ? pImg->imageData[4*(pImg->width*y+x)+2] : \
        (pImg->type == IMG_GREY ? pImg->imageData[pImg->width*y+x] : 0)))

    #define GET_A(pImg, x, y) \
        (pImg->type == IMG_RGBA ? pImg->imageData[4*(pImg->width*y+x)] : 255)

    so i converted all of my tga's to have origin in the top left corner, put back my old code in, and it worked flawlessly!
    So the problem lies inside those functions and #defines. Well, now it makes a little more sense, even though i *still* don't know what's the error ;)
    Monday, March 19, 2007 5:33 PM

All replies

  • As you have stated

    running with F5: Automatically attaches the debugger and runs the application from the startup form specified in the <Project> Properties dialog box. Changes to Continue if in Break mode.

    Running with Ctrl + F5:Runs the code without invoking the debugger.

    So basically pretty straightforward, the hard part is why it is crashing, if you can provide more error messages and preferable some sample code here(better without openGL) will helps to approach to the answer.

    Monday, March 12, 2007 7:17 AM
  • this is the function that reads the content of a file, from my .tga loader
    crashing seems to be related to files somehow; if the fclose call is uncommented, it crashes on a file, if it's commented it crashes on fseek some files later in the loading phase.
    unsigned char* GetData(char* lpszFile)
    {
        FILE* pFile = fopen(lpszFile, "rb");
        if(pFile==NULL) {
            perror("error opening file: ");
            exit(-1);
        }
        unsigned char *pData = NULL;
        long nSize = 0;

        fseek(pFile, 0, SEEK_END);
        nSize = ftell(pFile);
        if((pData = (unsigned char*)malloc(nSize)) == NULL) {
            perror("error in malloc: ");
            exit(0);
        }
        fseek(pFile, 0, SEEK_SET);
        int c=fread(pData, 1, nSize, pFile);
        printf("read %u/%u\n",c,nSize);
        fclose(pFile);
        return pData;
    }

    this is another part of the tga loading, on some files it crashes on the malloc in this function instead:
    void imgCreateImage(TextureS * pImg, unsigned int width, unsigned int height, Image_type type)
    {
        int nSize = width * height;
        printf("%d %d %d\n",width,height,nSize);
        switch(type)
        {
        case IMG_RGBA:
            nSize *= 4;
            //printf("IMG_RGBA\n");
            break;
        case IMG_RGB:
            nSize *= 3;
            //printf("IMG_RGB\n");
            break;
        case IMG_GREY:
            //printf("IMG_GREY\n");
        case IMG_INDEX:
            //printf("IMG_INDEX\n");
            // Size should be correct, nothing to do
            break;
        default:
            printf("O_O\n");
            // Unknown image format!!
            nSize = 0;
            break;
        }
        if (nSize) {
           if(pImg->imageData = (GLubyte*)malloc(nSize) == NULL) {
              perror("error in malloc: ");
              exit(0);
            }
        }
        else
            pImg->imageData = NULL;
        pImg->height = height;
        pImg->width = width;
        pImg->type = type;
    }

    TextureS is a struct defined as following:
    typedef struct
    {
        GLubyte    * imageData;                                    /* Image Data (Up To 32 Bits) */
        GLuint    bpp;                                            /* Image Color Depth In Bits Per Pixel */
        GLuint    width;                                            /* Image Width */
        GLuint    height;                                            /* Image Height */
        GLuint    texID;                                            /* Texture ID Used To Select A Texture */
        GLuint    type;                                            /* Image Type (GL_RGB, GL_RGBA) */
    } TextureS;

    The strange things are 2:
    - fseek, fclose, or malloc are NOT failing, they are CRASHING!
    - the function call on which it's crashing is dependant upon the files that have to be loaded.

    It works flawlessly on linux or on windows+visual studio with f5.
    This is driving me insane...
    Monday, March 12, 2007 2:57 PM
  • bump... =((
    Wednesday, March 14, 2007 8:30 AM
  • the function call on which it's crashing is dependant upon the files that have to be loaded.

    Was that depends on the file mode? (binary mode, text mode). This discussion may hints rich. I would use windows API in this file I/O context when platform-independent is not so important:

    long GetFileSize(const TCHAR *fileName)

    {

        BOOL                        fOk;

        WIN32_FILE_ATTRIBUTE_DATA   fileInfo;

     

        if (NULL == fileName)

            return -1;

     

        fOk = GetFileAttributesEx(fileName, GetFileExInfoStandard, (void*)&fileInfo);

        if (!fOk)

            return -1;

        assert(0 == fileInfo.nFileSizeHigh);

        return (long)fileInfo.nFileSizeLow;

    }

    hope it helps

    rico

    Wednesday, March 14, 2007 10:23 AM
  • thx for taking the time to answer.
    I've read the thread you have linked, and tried to use the function you posted, but unfortunately with no success.
    The result is the same as using ftell/fseek (and it makes sense, as i'm reading tga files which i *think* are binary files), the file size returned is the same, the crashing is the same.... =((
    Is writing a separate I/O (and memory allocation -if needed-, too) path for windows worth the effort? Any chance it might work?
    I'm reluctant to do it, because while it wouldn't be a lot of work, i don't know a thing about windows API...
    Wednesday, March 14, 2007 4:21 PM
  • Issues like this usually can ber traced back to memory problems.

    Here's what I would do: I would build my application with debug information - but with usual optimizations that you enable. I would then run the application until it crashes. When it crashes you should get a pop-up I would then attached a debugger and look at the callstack checking that all memory locations point to valid memory - this can take some poking around but hopefully whatever is bad will showup pretty quickly.

    Wednesday, March 14, 2007 9:09 PM
  • I'm sorry, but i'm not getting the point...
    Both Debug and Release versions crash for me if run with ctrl-f5 and both work fine if run with f5;  moreover, Debug version won't let me set  /Zi and  /O1-2-whatever  at the same time... or were you referring to some other stuff??
    Wednesday, March 14, 2007 9:44 PM
  • CTRL-F5 starts without the debugger and so you should have the same behavior as starting the application from the command-line. When it crashes you should get a pop-up: though I have noticed that in some circumstances CTRL-F5 does not produce a popup - which is one reason why I suggest starting from the command-line. When it crashes attach the debugger and start poking around.

    I use /Zi and full optimzations all the time - I know of no reason why these can't be used together.

    Wednesday, March 14, 2007 10:21 PM
  • Ok, i'm starting to get what you mean =)
    And you were right about /Zi and optimizations, i had /ZI enabled.. my bad :|

    So i've tried your suggestion, but when the program crashes i have no option to fire up the debugger..
    here is a screenshot of what i'm getting.. the standard crash report:
    http://img264.imageshack.us/my.php?image=upkg1.jpg

    edit: it looks like i can't enable JIT with Express Edition.... =(
    http://msdn2.microsoft.com/en-us/library/k8kf6y2a.aspx any other idea?
    Wednesday, March 14, 2007 11:10 PM
  • It does indeed look like you can't JIT debug with the Visual C++ Express Edition (this is news to me) so you could try another debugger. You can download and install the Window's debuggers from here - windbg is not as fancy as the Visual Studio debugger but it gets the job done and it is what I always turn to when I have a difficult bug to track down.
    Thursday, March 15, 2007 3:32 PM
  • I installed WinDbg, then it took me ages to install symbols (as i didn't have enough space... i had to start anew a couple of times!!).
    Finally, i launch it inside WinDbg. That's the result:

    CommandLine: D:\GFX_proj\GFX\Debug\GFX.exe
    Symbol search path is: c:\WINDOWS\Symbols\
    Executable search path is:
    ModLoad: 00400000 00469000   GFX.exe
    ModLoad: 7c910000 7c9c6000   ntdll.dll
    ModLoad: 7c800000 7c8ff000   C:\WINDOWS\system32\kernel32.dll
    ModLoad: 10000000 1003c000   C:\WINDOWS\system\glut32.dll
    ModLoad: 77d10000 77da0000   C:\WINDOWS\system32\USER32.dll
    ModLoad: 77e40000 77e87000   C:\WINDOWS\system32\GDI32.dll
    ModLoad: 76b00000 76b2e000   C:\WINDOWS\system32\WINMM.dll
    ModLoad: 77f40000 77feb000   C:\WINDOWS\system32\ADVAPI32.dll
    ModLoad: 77da0000 77e31000   C:\WINDOWS\system32\RPCRT4.dll
    ModLoad: 5c8a0000 5c8c1000   C:\WINDOWS\system32\GLU32.dll
    ModLoad: 77be0000 77c38000   C:\WINDOWS\system32\msvcrt.dll
    ModLoad: 5f140000 5f20c000   C:\WINDOWS\system32\OPENGL32.dll
    ModLoad: 736d0000 73719000   C:\WINDOWS\system32\DDRAW.dll
    ModLoad: 73b30000 73b36000   C:\WINDOWS\system32\DCIMAN32.dll
    ModLoad: 71a30000 71a47000   C:\WINDOWS\system32\WS2_32.dll
    ModLoad: 71a20000 71a28000   C:\WINDOWS\system32\WS2HELP.dll
    (f98.f4c): Break instruction exception - code 80000003 (first chance)
    eax=00251eb4 ebx=7ffd4000 ecx=00000002 edx=00000004 esi=00251f48 edi=00251eb4
    eip=7c911230 esp=0012fb20 ebp=0012fc94 iopl=0         nv up ei pl nz na po nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
    ntdll!DbgBreakPoint:
    7c911230 cc              int     3

    pressing f5 after this just makes it quit with this:
    ModLoad: 76340000 7635d000   C:\WINDOWS\system32\IMM32.DLL
    ModLoad: 746b0000 746fb000   C:\WINDOWS\system32\MSCTF.dll
    ModLoad: 77bd0000 77bd8000   C:\WINDOWS\system32\version.dll
    ModLoad: 752e0000 7530e000   C:\WINDOWS\system32\msctfime.ime
    ModLoad: 774b0000 775ed000   C:\WINDOWS\system32\ole32.dll
    ModLoad: 69000000 692da000   C:\WINDOWS\system32\vticd.dll
    ModLoad: 62250000 62256000   C:\WINDOWS\system32\MCD32.DLL
    Call Into DrvCreateLayerContext
    Call Into DrvCreateLayerContext
    eax=77c0b8c1 ebx=00000000 ecx=00923a38 edx=77c31ae8 esi=7c91e88e edi=ffffffff
    eip=7c91eb94 esp=0012f9f8 ebp=0012faf4 iopl=0         nv up ei pl zr na pe nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
    ntdll!KiFastSystemCallRet:
    7c91eb94 c3              ret

    the only thing i understand is the first-chance expression... but i can't really get a thing out of this... =(
    btw this happens pretty much immediately... i guess this is still in the process initialization phase??
    Thursday, March 15, 2007 10:22 PM
  • It looks like it is running correctly - the first int 3 breakpoint is windbg's way of halting at the entrypoint to your program. There is only one thing left to suggest - the oldest debugging trick in the book: time to start using printf statement to try and track down what is going on.
    Friday, March 16, 2007 4:40 PM
  • if i run it outside of windbg and then attach windbg to it when it crashes, that's what i get:

    Microsoft (R) Windows Debugger  Version 6.6.0007.5
    Copyright (c) Microsoft Corporation. All rights reserved.

    *** wait with pending attach
    Symbol search path is: c:\WINDOWS\Symbols\
    Executable search path is:
    ModLoad: 00400000 00469000   d:\GFX_proj\GFX\Debug\GFX.exe
    ModLoad: 7c910000 7c9c6000   C:\WINDOWS\system32\ntdll.dll
    ModLoad: 7c800000 7c8ff000   C:\WINDOWS\system32\kernel32.dll
    ModLoad: 10000000 1003c000   C:\WINDOWS\system\glut32.dll
    ModLoad: 77d10000 77da0000   C:\WINDOWS\system32\USER32.dll
    ModLoad: 77e40000 77e87000   C:\WINDOWS\system32\GDI32.dll
    ModLoad: 76b00000 76b2e000   C:\WINDOWS\system32\WINMM.dll
    ModLoad: 77f40000 77feb000   C:\WINDOWS\system32\ADVAPI32.dll
    ModLoad: 77da0000 77e31000   C:\WINDOWS\system32\RPCRT4.dll
    ModLoad: 5c8a0000 5c8c1000   C:\WINDOWS\system32\GLU32.dll
    ModLoad: 77be0000 77c38000   C:\WINDOWS\system32\msvcrt.dll
    ModLoad: 5f140000 5f20c000   C:\WINDOWS\system32\OPENGL32.dll
    ModLoad: 736d0000 73719000   C:\WINDOWS\system32\DDRAW.dll
    ModLoad: 73b30000 73b36000   C:\WINDOWS\system32\DCIMAN32.dll
    ModLoad: 71a30000 71a47000   C:\WINDOWS\system32\WS2_32.dll
    ModLoad: 71a20000 71a28000   C:\WINDOWS\system32\WS2HELP.dll
    ModLoad: 76340000 7635d000   C:\WINDOWS\system32\IMM32.DLL
    ModLoad: 746b0000 746fb000   C:\WINDOWS\system32\MSCTF.dll
    ModLoad: 752e0000 7530e000   C:\WINDOWS\system32\msctfime.ime
    ModLoad: 774b0000 775ed000   C:\WINDOWS\system32\ole32.dll
    ModLoad: 69000000 692da000   C:\WINDOWS\system32\vticd.dll
    ModLoad: 719d0000 71a10000   C:\WINDOWS\System32\mswsock.dll
    ModLoad: 76ee0000 76f07000   C:\WINDOWS\system32\DNSAPI.dll
    ModLoad: 76f70000 76f78000   C:\WINDOWS\System32\winrnr.dll
    ModLoad: 76f20000 76f4d000   C:\WINDOWS\system32\WLDAP32.dll
    ModLoad: 76f80000 76f86000   C:\WINDOWS\system32\rasadhlp.dll
    ModLoad: 69940000 69956000   C:\WINDOWS\system32\faultrep.dll
    ModLoad: 77bd0000 77bd8000   C:\WINDOWS\system32\VERSION.dll
    ModLoad: 76980000 76a34000   C:\WINDOWS\system32\USERENV.dll
    ModLoad: 76310000 76320000   C:\WINDOWS\system32\WINSTA.dll
    ModLoad: 5bc70000 5bcc4000   C:\WINDOWS\system32\NETAPI32.dll
    ModLoad: 76f10000 76f18000   C:\WINDOWS\system32\WTSAPI32.dll
    ModLoad: 778f0000 779e7000   C:\WINDOWS\system32\SETUPAPI.dll
    ModLoad: 05660000 056d6000   C:\WINDOWS\system32\SHLWAPI.dll
    ModLoad: 77b10000 77b32000   C:\WINDOWS\system32\Apphelp.dll
    (bd4.f14): Break instruction exception - code 80000003 (first chance)
    eax=7ffd5000 ebx=00000001 ecx=00000002 edx=00000003 esi=00000004 edi=00000005
    eip=7c911230 esp=0570ffcc ebp=0570fff4 iopl=0         nv up ei pl zr na pe nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000246
    ntdll!DbgBreakPoint:
    7c911230 cc              int     3
    0:001> g //i presses f5 here
    (bd4.304): Access violation - code c0000005 (!!! second chance !!!)
    eax=055ffce0 ebx=00009394 ecx=00000200 edx=00ab6a07 esi=055b5038 edi=055b6040
    eip=7c921639 esp=0012f830 ebp=0012fa50 iopl=0         nv up ei pl zr na pe nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
    ntdll!RtlAllocateHeap+0x939:
    7c921639 8a4805          mov     cl,byte ptr [eax+5]        ds:0023:055ffce5=??

    what's a second chance violation!?
    by the way i already used the printf approach, it's what it brought me to create this thread.
    Thanks for taking the time to answer several times =)
    Friday, March 16, 2007 5:30 PM
  • This means that it is an exception that your application does not handle. Whenever an exception is raised by the OS it is known as a first chance exception - i.e. this is your first chance to look at it. But as exceptions can be valid in an application (i.e. they are handled and the application recovers and/or continues) the debugger can be configured to ignore all 1st chance exceptions. A second chance exception occurs when the debugger cannot find any handler for the exception in your applicatio and therefore the OS is going to terminate the application - this is your second (and last!) chance to look at the callstack and see what caused the exception. A dump of the callstack at this point may provide some more information.
    Friday, March 16, 2007 6:26 PM
  • it looks like malloc is having problems with it's paramater..
    http://img490.imageshack.us/my.php?image=upul8.jpg

    I'm passing a long variable to malloc, while malloc takes an int. So i tried using an int (files are small, so there should't be any overflow problem) but had the same result.
    I'm printing that value to screen just the line before, it's 231806 (bytes).
    I'm amazed.... but in a sad way..
    Friday, March 16, 2007 6:57 PM
  • I don't know why I didn't spot this before. I strongly suspect that this line is not doing what you think it should be doing:

    if (pImg->imageData = (GLubyte*)malloc(nSize) == NULL) {

    The operator precedence rules of C and C++ mean that this line is equivalent to

    if (pImg->imageData = ((GLubyte*)malloc(nSize) == NULL)) {

    Because the precedence of '==' is higher than '='

    I suspect you want the line to mean:

    if ((pImg->imageData = (GLubyte*)malloc(nSize)) == NULL) {

    You should change this code, recompile, and see if it makes a difference.

    Friday, March 16, 2007 9:22 PM
  • Unfortunately, that was already alright in my code, must have made a mistake while reporting code on this forum...

    I've made a stripped down version of the project, with only the loading code inside, with the hope it could be simpler to trace the problem. No luck so far, though...

    Once again, it looks like changing the files to be loaded changes the crashing...
    http://img213.imageshack.us/my.php?image=updj0.jpg
    Saturday, March 17, 2007 10:30 AM
  • This sounds like somewhere your overwriting memory that you don't have access to, bugs like this can be the hardest thing to find.
    Can you substitute the TGA loader code your using for another method of doing the same?

    I prefer using new/delete to malloc/free, i hope the code below helps:

    //************************************************************************* //
    // Targa Image class for loading TGA images
    //
    // Authors: Aszdi, Barnabs
    // Czuczor, Szabolcs
    // Created: July, 2004., Budapest, Hungary
    //
    // Budapest University of Technology and Economics,
    // Department of Control Engineering and Information Technology (BME-IIT)
    //************************************************************************* //
    #include <stdio.h>

    #ifndef TGALOADER_H
    #define TGALOADER_H

    struct TGAHeader { // The header of a standard TGA (Targa) image file
    unsigned char ImageIDLength;
    unsigned char ColorMapType;
    unsigned char ImageType;
    unsigned short FirstEntryIndex;
    unsigned short ColorMapLength;
    unsigned char ColorMapEntrySize;
    unsigned short XOrigin;
    unsigned short YOrigin;
    unsigned short Width;
    unsigned short Height;
    unsigned char PixelDepth;
    unsigned char ImageDescriptor;
    };


    //============================================================================
    class TGAImage {
    //============================================================================
    unsigned char * pc; // Pixel components of an image [R, G, B, R, G, B, R, G, B etc.]
    int width, height, pxNum, cmpNum;
    public:

    TGAImage(int w = 1, int h = 1, unsigned char r = 0, unsigned char g = 0, unsigned char b = 0) {
    width = w;
    height = h;
    pxNum = width * height; // Number of pixels
    cmpNum = 3 * pxNum; // Number of RGB components
    pc = new unsigned char[cmpNum];
    for (int i = 0; i < cmpNum; i += 3) {
    pc[ i ] = r;
    pc[i + 1] = g;
    pc[i + 2] = b;
    }
    }

    ~TGAImage() {
    delete [] pc;
    }

    int getWidth() { return width; }
    int getHeight() { return height; }

    unsigned char * getImageDataPointer() { return pc; }

    bool loadFromFile(char * filename) { // Load image from a true color uncompressed TGA file
    FILE * TGAFile = fopen(filename, "rb");
    if (TGAFile == NULL) {
    printf(" Can't open the file \"%s\".\n", TGAFile);
    return false;
    }
    TGAHeader imageHeader;
    unsigned char * imageID;
    unsigned char * colorMapData;
    unsigned char * imageData;
    fread(&imageHeader.ImageIDLength, 1, 1, TGAFile);
    fread(&imageHeader.ColorMapType, 1, 1, TGAFile);
    fread(&imageHeader.ImageType, 1, 1, TGAFile);
    fread(&imageHeader.FirstEntryIndex, 2, 1, TGAFile);
    fread(&imageHeader.ColorMapLength, 2, 1, TGAFile);
    fread(&imageHeader.ColorMapEntrySize, 1, 1, TGAFile);
    fread(&imageHeader.XOrigin, 2, 1, TGAFile);
    fread(&imageHeader.YOrigin, 2, 1, TGAFile);
    fread(&imageHeader.Width, 2, 1, TGAFile);
    fread(&imageHeader.Height, 2, 1, TGAFile);
    fread(&imageHeader.PixelDepth, 1, 1, TGAFile);
    fread(&imageHeader.ImageDescriptor, 1, 1, TGAFile);
    if (imageHeader.ImageIDLength) {
    imageID = new unsigned char[imageHeader.ImageIDLength];
    fread(imageID, 1, imageHeader.ImageIDLength, TGAFile);
    delete [] imageID;
    }
    if (imageHeader.ColorMapType) {
    int numOfBytes = imageHeader.ColorMapLength * (imageHeader.ColorMapEntrySize >> 3);
    colorMapData = new unsigned char[numOfBytes];
    fread(colorMapData, 1, numOfBytes, TGAFile);
    delete [] colorMapData;
    }
    if (imageHeader.ImageType) {
    width = imageHeader.Width;
    height = imageHeader.Height;
    pxNum = width * height;
    cmpNum = 3 * pxNum;
    delete [] pc;
    pc = new unsigned char[cmpNum];
    int numOfBytes = imageHeader.Width * imageHeader.Height * (imageHeader.PixelDepth >> 3);
    imageData = new unsigned char[numOfBytes];
    fread(imageData, 1, numOfBytes, TGAFile);
    if (imageHeader.PixelDepth == 24) {
    int i, j;
    int top2down = (imageHeader.ImageDescriptor >> 5) & 1;
    int left2right = 1 - (imageHeader.ImageDescriptor >> 4) & 1;
    for (int y = 0; y < height; y++)
    for (int x = 0; x < width; x++) {
    i = 3 * ((top2down?(y):(height - 1 - y)) * width + (left2right?(x):(width - 1 - x)));
    j = 3 * (y * width + x);
    pc[ i ] = imageData[j + 2];
    pc[i + 1] = imageData[j + 1];
    pc[i + 2] = imageData[j];
    }
    } else {
    // Here we should process the not 24 bit image data
    }
    delete [] imageData;
    }
    fclose(TGAFile);
    return true;
    }

    bool saveToFile(char * filename) { // Save image into a true color uncompressed TGA file
    FILE * TGAFile = fopen(filename, "wb");
    if (TGAFile == NULL) {
    printf(" Can't open the file \"%s\".\n", TGAFile);
    return false;
    }
    TGAHeader imageHeader;
    unsigned char * imageData;
    imageHeader.ImageIDLength = 0;
    imageHeader.ColorMapType = 0;
    imageHeader.ImageType = 2;
    imageHeader.FirstEntryIndex = 0;
    imageHeader.ColorMapLength = 0;
    imageHeader.ColorMapEntrySize = 24;
    imageHeader.XOrigin = 0;
    imageHeader.YOrigin = 0;
    imageHeader.Width = width;
    imageHeader.Height = height;
    imageHeader.PixelDepth = 24;
    imageHeader.ImageDescriptor = 32;
    fwrite(&imageHeader.ImageIDLength, 1, 1, TGAFile);
    fwrite(&imageHeader.ColorMapType, 1, 1, TGAFile);
    fwrite(&imageHeader.ImageType, 1, 1, TGAFile);
    fwrite(&imageHeader.FirstEntryIndex, 2, 1, TGAFile);
    fwrite(&imageHeader.ColorMapLength, 2, 1, TGAFile);
    fwrite(&imageHeader.ColorMapEntrySize, 1, 1, TGAFile);
    fwrite(&imageHeader.XOrigin, 2, 1, TGAFile);
    fwrite(&imageHeader.YOrigin, 2, 1, TGAFile);
    fwrite(&imageHeader.Width, 2, 1, TGAFile);
    fwrite(&imageHeader.Height, 2, 1, TGAFile);
    fwrite(&imageHeader.PixelDepth, 1, 1, TGAFile);
    fwrite(&imageHeader.ImageDescriptor, 1, 1, TGAFile);
    imageData = new unsigned char[cmpNum];
    for (int i = 0; i < cmpNum; i += 3) {
    imageData[ i ] = pc[i + 2];
    imageData[i + 1] = pc[i + 1];
    imageData[i + 2] = pc[ i ];
    }
    fwrite(imageData, 1, cmpNum, TGAFile);
    fclose(TGAFile);
    delete [] imageData;
    return true;
    }
    };

    #endif
    Sunday, March 18, 2007 7:07 PM
  • I'm feeling stupid, i always wondered how i could replace completely malloc/free in c++. Guess i never thought i could allocate standard types too with "new".

    Going back on topic, this seems to fix my problems, although it doesn't support compressed tga's (not a big problem for my project) and tga with alpha channel (this is a problem). I'll look if i can put alpha support in.

    Thanks a lot, although i still don't know what really caused the crashing... =(
    Sunday, March 18, 2007 10:01 PM
  • actually it looks like alpha channel is supported; so the only thing missing is compressed tga support. But i can live without it ;)
    Monday, March 19, 2007 10:32 AM
  • I'm glad it is working - sorry I couldn't have been more helpful.
    Monday, March 19, 2007 4:08 PM
  • Don't be sorry, I actually learned some new things through your posts ;)

    edit: looks like i've narrowed down the problem...
    i was adding back in some of the image-flipping functions i used, and just as i put them in it started to crash again. A tga file can have it's origin in all the 4 corners, so if it wasn't in the top left one i flipped the image accordingly, like this:
    switch(origin)
        {
        case TGA_ORIGIN_BOTTOM_LEFT:
            imgFlipVertical(texture);
            break;
        case TGA_ORIGIN_BOTTOM_RIGHT:
            imgFlipVertical(texture);
            imgFlipHorizontal(texture);
            break;
        case TGA_ORIGIN_TOP_LEFT:
            break;
        case TGA_ORIGIN_TOP_RIGHT:
            imgFlipHorizontal(texture);
            break;
        }

    the functons are as follows
    void imgFlipHorizontal(TextureS * pImg)
    {
        unsigned char r, g, b, a;
        unsigned int x, y;

        if (pImg->type == IMG_INDEX)
        {
            // Not supported!
            return;
        }

        for (y=0;y<pImg->height/2;y++)
        {
            for (x=0;x<pImg->width;x++)
            {
                r = GET_R(pImg, x, y);
                g = GET_G(pImg, x, y);
                b = GET_B(pImg, x, y);
                a = GET_A(pImg, x, y);
               
                SET_RGBA(pImg, x, y, GET_R(pImg, x, pImg->height-y),
                    GET_G(pImg, x, pImg->height-y),
                    GET_B(pImg, x, pImg->height-y),
                    GET_A(pImg, x, pImg->height-y));

                SET_RGBA(pImg, x, pImg->height-y, r, g, b, a);
            }
        }

    }

    void imgFlipVertical(TextureS * pImg)
    {
        unsigned char r, g, b, a;
        unsigned int x, y;

        if (pImg->type == IMG_INDEX)
        {
            // Not supported!
            return;
        }

        for (y=0;y<pImg->height;y++)
        {
            for (x=0;x<pImg->width/2;x++)
            {
                r = GET_R(pImg, x, y);
                g = GET_G(pImg, x, y);
                b = GET_B(pImg, x, y);
                a = GET_A(pImg, x, y);
               
                SET_RGBA(pImg, x, y, GET_R(pImg, pImg->width-x, y),
                    GET_G(pImg, pImg->width-x, y),
                    GET_B(pImg, pImg->width-x, y),
                    GET_A(pImg, pImg->width-x, y));

                SET_RGBA(pImg, pImg->width-x, y, r, g, b, a);
            }
        }
    }

    #define GREY(R,G,B)   (unsigned char)(R*0.61f + G*0.29f + B*0.15f)

    #define SET_RGBA(pImg, x, y, r, g, b, a)     \
        switch(pImg->type) \
        {        \
        case IMG_RGB:  \
            pImg->imageData[3*(pImg->width*y+x)] = r; \
            pImg->imageData[3*(pImg->width*y+x)+1] = g; \
            pImg->imageData[3*(pImg->width*y+x)+2] = b; \
            break; \
        case IMG_RGBA: \
            pImg->imageData[4*(pImg->width*y+x)] = r; \
            pImg->imageData[4*(pImg->width*y+x)+1] = g; \
            pImg->imageData[4*(pImg->width*y+x)+2] = b; \
            pImg->imageData[4*(pImg->width*y+x)+3] = a; \
            break; \
        case IMG_GREY: \
            pImg->imageData[pImg->width*y+x] = GREY(r, g, b); \
            break; \
        }

    #define GET_R(pImg, x, y) \
        (pImg->type == IMG_RGB ? pImg->imageData[3*(pImg->width*y+x)] : \
        (pImg->type == IMG_RGBA ? pImg->imageData[4*(pImg->width*y+x)] : \
        (pImg->type == IMG_GREY ? pImg->imageData[pImg->width*y+x] : 0)))

    #define GET_G(pImg, x, y) \
        (pImg->type == IMG_RGB ? pImg->imageData[3*(pImg->width*y+x)+1] : \
        (pImg->type == IMG_RGBA ? pImg->imageData[4*(pImg->width*y+x)+1] : \
        (pImg->type == IMG_GREY ? pImg->imageData[pImg->width*y+x] : 0)))

    #define GET_B(pImg, x, y) \
        (pImg->type == IMG_RGB ? pImg->imageData[3*(pImg->width*y+x)+2] : \
        (pImg->type == IMG_RGBA ? pImg->imageData[4*(pImg->width*y+x)+2] : \
        (pImg->type == IMG_GREY ? pImg->imageData[pImg->width*y+x] : 0)))

    #define GET_A(pImg, x, y) \
        (pImg->type == IMG_RGBA ? pImg->imageData[4*(pImg->width*y+x)] : 255)

    so i converted all of my tga's to have origin in the top left corner, put back my old code in, and it worked flawlessly!
    So the problem lies inside those functions and #defines. Well, now it makes a little more sense, even though i *still* don't know what's the error ;)
    Monday, March 19, 2007 5:33 PM
  • Glad to hear your code is getting back on track, if you are intent on finding the exact cause of your previous errors, may i suggest the first thing you do is convert all those nasty macros into inline functions, this will allow you to step through your code and examine the data contents at each step.

    If you need to work with compressed TGA files i suggest you check out NEHE, lesson 33 in particular deals with loading compressed and uncompressed TGA's, i think the code presented also reads alpha values:

    http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=33

    The TGA loader code i presented earlier originally used malloc/free, but i modified it to use new/delete for use as part of a texture manager class i once did, my reason for using new/delete was so i could override those operators so that they allocated memory from a previously allocated shared pool, this helped prevent memory fragmentation and also sped up allocation (compared to the default implementation of new/delete).

    Tuesday, March 20, 2007 12:01 AM