Code snippet only works correctly when headed by Ofstream opening a file.

This is the strangest thing I've encountered because I can't really find any noticeable patterns or any reason why it might be doing this. Tried searching but all the results were related to Ofstream itself not working. Came across it when using it to debug my code that decompresses run-length encoded 32 bit TARGA images for use in OpenGL/GLUT, and it works... But only if it is headed by Ofstream opening a file to output to. The only thing I think could possibly be related is the "Ifstream" used earlier to open the image file and read it, which goes under the handle "input." However, I don't think that makes sense because it can read the uncompressed version just fine (without having to open any external file.)

Please excuse the formatting/inefficiency of the code in general, I'm still new.

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
      int runTime = 0;
      int red;
      int grn;
      int blu;
      int alpha;

                
      auto_array<char> pixels(new char[width * height * 4]); // cant be declared before here
      
    ofstream myfile;
    myfile.open ("example.txt"); // code wont run without this being declared/opened exactly here




      for(int i = 0; i <= width * height; i += 0)
      {
          int runLength = readByte(input);
          if(runLength < 128)
          {
              runLength += 1;
              for(int j = 0; j < runLength; j++)
              {
              blu = readByte(input);
              grn = readByte(input);
              red = readByte(input);
              alpha = readByte(input);

              pixels[runTime + (j*4)] = red;
              pixels[runTime + (j*4) + 1] = grn;
              pixels[runTime + (j*4) + 2] = blu;
              pixels[runTime + (j*4) + 3] = alpha;
              }
          }
          else if(runLength > 128)
          {
              runLength -= 127;
              blu = readByte(input);
              grn = readByte(input);
              red = readByte(input);
              alpha = readByte(input);


              for(int j = 0; j <= runLength * 4; j += 4)
              {
                  pixels[runTime + j] = red;
                  pixels[runTime + j + 1] = grn;
                  pixels[runTime + j + 2] = blu;
                  pixels[runTime + j + 3] = alpha;

              }
          }
          runTime += runLength * 4;
                    i += runLength;


      }
        // doesnt work if declared here, also doesnt matter if myfile is closed or not
      	input.close();

      return new Image(pixels.release(), width, height);


I tried messing around with it, doing myfile.close() right after opening doesn't work, strangely enough it won't work if myfile is opened before declaring the char array of pixels, only right after, and it does not work if myfile is opened after the decompression. By "doesn't work," the program just automatically closes and doesn't even reach the line where it returns the pixel data (return new Image(pixels.release(), width, height);) When it does work, it loads a cube and the vertices correctly, and maps the texture to the side correctly with no performance issues or anything.

The code that makes an array for uncompressed image data (commented out at the bottom and admittedly not my own):

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
    ifstream input;
    input.open(filename, ifstream::binary);

    assert(!input.fail() || !"Could not find file or compatible TARGA.");

    assert(readByte(input) == 0 || !"Image has an ID and is not suitable for this method of loading.");
    assert(readByte(input) != 1 || !"Image has a color map and is not suitable for this method of loading.");

    int width;
    int height;
    int imageType = readByte(input);
    cout << "Image type: " << imageType << " (2 = uncompressed, 10 = compressed) \n" << endl;

    switch(imageType)
    {
        default:
            cout << "No image data found." << endl;
            return false;
        break;

        case 2:
            cout << "Uncompressed image data found. Not optimal, but will load regardless.\n" << endl;
            input.ignore(9);
            width = readShort(input);
            height = readShort(input);
        break;

        case 10:
            cout << "Compressed image data found. Congratulations!\n" << endl;
            input.ignore(9);
            width = readShort(input);
            height = readShort(input);
        break;
    }


    cout << "W: " << width << "\n" << endl;
    cout << "H: " << height << "\n" << endl;

    int bytesPp = readByte(input);

    cout << "BPP: " << bytesPp << "\n" << endl;

    input.ignore(1);

    int fields;

    switch(imageType)
    {
    case 2:
        {
        fields = (bytesPp / 8);
        cout << "Byte Fields: " << fields  << "\n" << endl;
        }
    break;

    case 10:
        {
        fields = (bytesPp / 8) + 1;
        cout << "Byte Fields: " << fields  << "\n" << endl;
        }
    break;
    }
/*
    int bytesPerRow = width * fields;
    cout << "Bytes Per Row: " << bytesPerRow  << "\n" << endl;
	int size = bytesPerRow * height;
    cout << "Byte Amount: " << size  << "\n" << endl;
	auto_array<char> pixels(new char[size]);
	input.read(pixels.get(), size);
/*
	//Get the data into the right format
	auto_array<char> pixels2(new char[width * height * fields]);
	for(int y = 0; y < height; y++) {
		for(int x = 0; x < width; x++) {
			for(int c = 0; c < fields; c++) {
				pixels2[fields * (width * y + x) + c ] = pixels[bytesPerRow * y + fields * x + (2 - c)];
                                            }
                                    }
                            }
	input.close();


      return new Image(pixels2.release(), width, height); */


I just can't wrap my head around it, it's probably something very simple and I'm just too sleepy to see it. Thank you if you do happen to respond and I can provide the rest of the source code or explanation of it if need be.
Last edited on
Hello helpmeimnotthesmartest,

When you defined "myFile" as an "ofstream" the "o" implies an output stream just as the "i" in "ifstream" implies input.

You could just as easily written the code as:
1
2
fstream myfile;
myfile.open ("example.txt", std::ios::out);

When using the "fatream" in the open statement you have to tell it if the stream is for "input", "output", or both, i.e., myfile.open ("example.txt", std::ios::in | std::ios::out);
Notice when combining more than one item you use the bit wise "|". Not the logical "||".

Done properly it should not make any difference if you open the file stream before or after you define the array.

There is not enough code there to load and test you program and right now I can only guess at what is missing and that is likely to be wrong.

Personally I like using the "ifstream" and "ofstream" to define a file stream along with the variable names "inFile" and "outFile". I find it easier to keep everything straight when working with the code.

Hope that helps,

Andy
Thanks for the reply Andy! I'm not sure if I misunderstood, but I don't want the output fstream at all in my code, I only used it for a short while while trying to debug it, but it breaks for some reason without it. This part specifically breaks without it:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
      for(int i = 0; i <= width * height; i += 0)
      {
          int runLength = readByte(input);
          if(runLength < 128)
          {
              runLength += 1;
              for(int j = 0; j < runLength; j++)
              {
              blu = readByte(input);
              grn = readByte(input);
              red = readByte(input);
              alpha = readByte(input);

              pixels[runTime + (j*4)] = red;
              pixels[runTime + (j*4) + 1] = grn;
              pixels[runTime + (j*4) + 2] = blu;
              pixels[runTime + (j*4) + 3] = alpha;
              }
          }
          else if(runLength > 128)
          {
              runLength -= 127;
              blu = readByte(input);
              grn = readByte(input);
              red = readByte(input);
              alpha = readByte(input);


              for(int j = 0; j < runLength * 4; j += 4)
              {
                  pixels[runTime + j] = red;
                  pixels[runTime + j + 1] = grn;
                  pixels[runTime + j + 2] = blu;
                  pixels[runTime + j + 3] = alpha;

              }
          }
          runTime += runLength * 4;
                    i += runLength;


      }


Once it reaches the end of the amount of pixels it has to read, the program just exits and doesn't even read these lines after it:

1
2
3
      	input.close();

      return new Image(pixels.release(), width, height);


If I remove or move these lines at all:

1
2
    ofstream myfile;
    myfile.open ("example.txt");


It just seems to stop working completely. If I keep the defined fstream, it works perfectly, but I don't really want it to create/modify a new file every time I load a new texture.
Last edited on
Hello helpmeimnotthesmartest,

Alas I am not that familiar working with image files that your program uses.

The main point of my last post is that
1
2
fstream myfile;
myfile.open ("example.txt");

This only opens the file, but does not say if it is for input or output.

I see that you edited your OP and now the above bit of code now says ofstream. I do not recall if it was that way to begin with or not, but if you changed that code, do not do that. It only confuses people that read what you have posted and can not find anything wrong with the code.

It is also a good idea to put "Edit:" at the end and say what you changed, so that everyone will know.

Something I noticed in the OP the first switch the default case comes first. I do not know if it makes any difference, but I have always seen the default case as being last. Also the "return" statement will never allow the case to reach the "break" as it will leave the switch before that.

In the second post the for loop can be written as: for(int i = 0; i <= width * height;). Since you are changing the value of "i" inside the for loop you do not need the third part, but you do need the second ";" for it to work properly.

The for loop looks like it will process the image data, but what do you do after this for loop to read what is left. Do not look to this for loop to read the entire file.

You say that you need to open an output file for the program to work, but you also say that yo do not need an output file. This says to me that something is wrong and most likely in code that you have not shown.

I have found that problems and errors do not always start where you think they do. Errors can start several lines above where the compiler says it is and problems can start in functions that may come before you you see a problem or from functions that are called from where the is being seen.

Even though I do not understand what the program is doing. Having code that will compile and run along with the file that you are testing I can usually figure out what is going wrong.

Someone who is use to working with image file may see something I do not or have an idea that I do not know about.

Sorry I could not be of more help,

Andy
I have not figured out the problem with fstream, however, I did find a workaround using an old tutorial that makes use fopen/fread from stdio.h. It works similarly to my code but looks significantly more elegant and doesn't have weird bugs.

Thank you to everyone who tried to help.

Tutorial for anyone in case they have a similar problem: http://nehe.gamedev.net/tutorial/loading_compressed_and_uncompressed_tga%27s/22001/
Topic archived. No new replies allowed.