Textures, some work and some doesn't???

Started by
24 comments, last by babaliaris 5 years, 4 months ago

I gave you working code today using a switch statement to handle 1-4 channel bitmaps...Even if you don't want to support 1 & 2 channel bitmaps, it does not hurt to include the switch statement and handle it with a proper message there instead of the code you have now.  Not just UNSUPPORTEWD (typo in there :) ?


I'm going to say it, I don't have time to correct it now, but your code scares me.  I will come back tomorrow and take a stab at it.  I know you're just learning, but seeing someone else's code might help?  I just got a new PC so will have to dig up my old code.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Advertisement
6 hours ago, CrazyCdn said:

I gave you working code today using a switch statement to handle 1-4 channel bitmaps...Even if you don't want to support 1 & 2 channel bitmaps, it does not hurt to include the switch statement and handle it with a proper message there instead of the code you have now.  Not just UNSUPPORTEWD (typo in there :) ?


I'm going to say it, I don't have time to correct it now, but your code scares me.  I will come back tomorrow and take a stab at it.  I know you're just learning, but seeing someone else's code might help?  I just got a new PC so will have to dig up my old code.

That's the problem, I've learned all these stuff by seeing code from others. It seems they didn't know about all these stuff since they weren't also explaining all these things about channels, memory alignment that the driver does. Check this Texture uploading common mistakes . All the details and the advanced stuff about these operations where taught to me by you guys and I'm really thankful.

So, what I was trying to do was to solve that Alignment Problem In the common mistakes. If the width of the image multiplied by the channels is a number that can not be divided perfectly with 4, then it means that the default alignment of openGL (4) will not read the pixel data correctly, so I need to change the alignment to 1 in order to read them byte by byte. This didn't work here.

But forcing load_image to use 4 channels, because 4 channels = 4 bytes no matter what the width of the image is the number width*channels will always be divisible by 4, so the default alignment of openGL will read the data correctly.

The person who mentioned this to me told me that like 99% I will always be safe if I'm always forcing 4 channels no matter the input file. But if for example I'm uploading a greyscale image you can imagine the loose in VRAM while I'm adding 3 more channels to the greyscale data per pixel which are not needed, only and only because the driver will read them correctly.


void life()
{
  while (!succeed())
    try_again();

  die_happily();
}

 

I'm going to show you the tests I run now that I know more stuff about textures.

Notice that I'm uploading 5 Textures but using (binding) only the first one (a.jpg)!

Divisible by 4 is yes if (width * channels) / 4.0f is an integer number.

Texture Max Size is the return value of glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size)

Test 1 (Without forcing 4 channels.)

9e0Yu28.png

If you see the log, all files are divisible by 4 ( (width * height) / 4) so the alignment is not a problem.

 

Test 2 (Without forcing 4 channels and Uploading only one texture)

MrlYDbr.png

I'm getting what I expected. This seems so weird. How can the upload of the other textures in the first test can impact to that weird result since I'm not even using them?

 

Test 3 (Forcing 4 channels):

Peq3FUe.png

As you can see by forcing 4 channels I'm getting what I expected.

 

Code:

Notice that in the first and second test stbi_load(path.c_str(), &m_width, &m_height, &m_channels, 0); and also the line m_channels = 4; does not exist.


	//Reverse the pixels.
	stbi_set_flip_vertically_on_load(1);

	//Try to load the image.
	//FORCE 4 CHANNELS.
	unsigned char *data = stbi_load(path.c_str(), &m_width, &m_height, &m_channels, 4);
	m_channels = 4;

	//Debug.
	float check = (m_width * m_channels) / 4.0f;
	printf("file: %20s \tchannels: %d, Divisible by 4: %s, width: %d,  height: %d,  widthXheight: %d\n", 
		path.c_str(), m_channels, check == ceilf(check) ? "yes" : "no", m_width, m_height, m_width * m_height);


	//Image loaded successfully.
	if (data)
	{

		//Generate the texture and bind it.
		GLCall(glGenTextures(1, &m_id));
		GLCall(glActiveTexture(GL_TEXTURE0 + unit));
		GLCall(glBindTexture(GL_TEXTURE_2D, m_id));

		//Not Transparent texture.
		if (m_channels == 3)
		{
			GLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_width, m_height, 0, GL_RGB, GL_UNSIGNED_BYTE, data));
		}

		//Transparent texture.
		else if (m_channels == 4)
		{
			GLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data));
		}

		else
		{
			throw EngineError("UNSUPPORTEWD");
		}

		//Texture Filters.
		GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
		GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
		GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST));
		GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));

		//Generate mipmaps.
		GLCall(glGenerateMipmap(GL_TEXTURE_2D));
	}

 

a.jpg

brick2.jpg

brick3.jpg

container.jpg

container2.png


void life()
{
  while (!succeed())
    try_again();

  die_happily();
}

 

Then I will save my time and not write the code :)  I would highly recommend not forcing it to 4 channels as you are though.  What happens when you try and load an actual 3 channel bitmap?  You're going to be attempting to have OpenGL read a 4 channel bitmap that is only actually 3.  Have fun tracking down that bug later.  The size difference on a PC doesn't much matter but if you force every image in your game to have a 4th channel when it has no need what-so-ever for that channel, then on a mobile platform you're wasting resources.  Write code that can handle all different situations it could encounter.  It's good overall programming practice.  If you do not want to support them, you can then notify the user and gracefully handle the situation.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

9 minutes ago, CrazyCdn said:

Then I will save my time and not write the code :)  I would highly recommend not forcing it to 4 channels as you are though.  What happens when you try and load an actual 3 channel bitmap?  You're going to be attempting to have OpenGL read a 4 channel bitmap that is only actually 3.  Have fun tracking down that bug later.  The size difference on a PC doesn't much matter but if you force every image in your game to have a 4th channel when it has no need what-so-ever for that channel, then on a mobile platform you're wasting resources.  Write code that can handle all different situations it could encounter.  It's good overall programming practice.  If you do not want to support them, you can then notify the user and gracefully handle the situation.

I would do that if I could find what the problem is in this post. It seems that forcing 4 channels does the trick.

Quote

You're going to be attempting to have OpenGL read a 4 channel bitmap that is only actually 3.  Have fun tracking down that bug later.

I don't thing this will ever happen. Since load_image when it load's an image with 3 channels and you are saying to force 4 channels, it reconstructs the data to have 4 channels per pixel and initialise the Alpha channel to 1 (no transparency). If you have only one channel, it will also initialise all the other 3 to 0 0 1.So openGL will successfully read RGBA data. If what you are saying is true, in my tests i would see an unexpected rendering, something that is not happening.

But yeah, wasting resources is a thing with this method, but if I find what causes this problem I will use the best solution for performance too,


void life()
{
  while (!succeed())
    try_again();

  die_happily();
}

 

This topic is closed to new replies.

Advertisement