How to diplay proportianal correct texture image?

(I’m completely new to OpenGL…)

I’m using orthographic mode
this is (essentially) the code

GLsizei w = {width of view};
GLsizei h = {height of view};

GLsizei iw = {image width};
GLsizei ih = {image height};

TexID1=LoadTexture(“image.tga”);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);

glTranslatef(0.0f,0.0f,0.0f);
glRotatef(0,0.0f,0.0f,1.0f);

glColor3f(1.0f,1.0f,1.0f);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,TexID1);

glBegin(GL_POLYGON);
glTexCoord2f(0.0f,1.0f); glVertex3f (-1.00, -1.00, 0.0);
glTexCoord2f(1.0f,1.0f); glVertex3f (+1.00, -1.00, 0.0);
glTexCoord2f(1.0f,0.0f); glVertex3f (+1.00, +1.00, 0.0);
glTexCoord2f(0.0f,0.0f); glVertex3f (-1.00, +1.00, 0.0);
glEnd();

This will display a texture that stretches and fills the entire screen space.

How do I display the texture so it is proportionally correct?
(based on textures actual width and height)

There are a few things to consider here.

First, you want to make sure your viewport is using square pixels. For that, get the aspect ratio of the viewport and set glOrtho to use it. That gives us a viewport that might be 1.33 wide and will always be 1.0 tall. Next you need to get the image’s aspect ratio:

double viewportAspect = (double)w / h;
glOrtho( 0.0, viewportAspect, 0.0, 1.0 );

double imageAspect = (double)iw / ih;

Now what to do with this? You need to consider all the situations. Your window might be narrow (aspect ratio < 1) or it might be wide (aspect ratio >= 1). Next you need to make the same consideration for your image. Is the image aspect ratio < 1 or >= 1? You can now think of both your viewport and image as simple ratios where one dimension is 1.0 and the other is the ratio whatever it is, rather than the absolute dimensions of the pixels. Okay that was a convoluted explanation, how about some code?

float quadWidth = (float)viewportAspect;
float quadHeight = quadWidth / imageAspect;

This is fine for most cases, except when the image is narrower than the viewport. There’s probably a more efficient way to do it, but for the sake of this let’s just do:

if( quadHeight > 1.0f )
{
    quadWidth /= quadHeight;
    quadHeight = 1.0f;
}

Lastly we need to create the quad with the right dimensions:

glBegin(GL_POLYGON);
glTexCoord2f(0.0f,1.0f); glVertex3f (-quadWidth, -quadHeight, 0.0);
glTexCoord2f(1.0f,1.0f); glVertex3f ( quadWidth, -quadHeight, 0.0);
glTexCoord2f(1.0f,0.0f); glVertex3f ( quadWidth,  quadHeight, 0.0);
glTexCoord2f(0.0f,0.0f); glVertex3f (-quadWidth,  quadHeight, 0.0);
glEnd();

I -think- that’ll work for you. I’m not in a position to test it at the moment. Give it a try and let me know how it works. You might need to divide quadWidth and quadHeight by 2.0f first.

Thanks will try out.
:slight_smile:

Here is project

http://www.mediafire.com/file/btlmi5cez45/OrthoTest.zip

In Render.h is code

void Render(void)
{
GLuint TexID1; // Handles to our textures

double w = 800;
double h = 600;
double iw = 1024;
double ih = 1024;

//glViewport(0,0,w,h);

// Load the textures

TexID1=LoadTexture("penguin.tga");
glViewport(0,0,800,600);




// This loop will run until Esc is pressed
while(RunLevel)
	{
	if(Keys[27]) // Esc Key
		RunLevel=0;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	double viewportAspect = (double)w / h;
	glOrtho( 0.0, viewportAspect, 0.0, 1.0, -1.0, 1.0 );

	double imageAspect = (double)iw / ih;

	float quadWidth = (float)viewportAspect;
	float quadHeight = quadWidth / imageAspect;


	glColor3f(1.0f,1.0f,1.0f);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D,TexID1);

	glBegin(GL_POLYGON);
	glTexCoord2f(0.0f,1.0f); glVertex3f (-quadWidth, -quadHeight, 0.0);
	glTexCoord2f(1.0f,1.0f); glVertex3f ( quadWidth, -quadHeight, 0.0);
	glTexCoord2f(1.0f,0.0f); glVertex3f ( quadWidth,  quadHeight, 0.0);
	glTexCoord2f(0.0f,0.0f); glVertex3f (-quadWidth,  quadHeight, 0.0);
	glEnd();

	SwapBuffers(GLDC);
	}

glDeleteTextures(1,&TexID1);
}

The code looks fine and makes sense, but I’m not getting the results.

Instead of getting whole penguin I get part of it.

It’s 1024x1024 image…(I scale it to that size so the penguin is actually not as fat as he looks in original image, I wanted to test with square image first)

The code looks correct, I should have gotten this…
What did I do wrong?

Guess it should be this:
glTexCoord2f(0.0f,1.0f); glVertex3f (0.0f, 0.0f, 0.0);
glTexCoord2f(1.0f,1.0f); glVertex3f ( quadWidth, 0.0f, 0.0);
glTexCoord2f(1.0f,0.0f); glVertex3f ( quadWidth, quadHeight, 0.0);
glTexCoord2f(0.0f,0.0f); glVertex3f (0.0f, quadHeight, 0.0);

I get the penguin moved to lower left quadrant…still not working.

I’m also new to OpenGL but you seem to be using glOrtho not correctly.

Also, you create a window of 1280X1024 but specify the viewport as 800X600.

Here, I took your project and made it work :

This is the first part of your render function. Only replacing yours by this one should make this work.


GLuint TexID1;      // Handles to our textures

	double w = 1280;
	double h = 1024;
	double iw = 1024;
	double ih = 1024;

	//glViewport(0,0,w,h);

	// Load the textures

	TexID1=LoadTexture("penguin.tga");
	glViewport(0,0,1280,1024);


	// This loop will run until Esc is pressed
	while(RunLevel)
		{
		if(Keys[27]) // Esc Key
			RunLevel=0;

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();

		double viewportAspect = (double)w / h;
		//glOrtho( 0.0, viewportAspect, 0.0, 1.0, -5.0, 5.0 );
		glOrtho(0, w, 0, h, -5, 1);

		double imageAspect = (double)iw / ih;

		float quadWidth = (float)viewportAspect;
		float quadHeight = quadWidth / imageAspect;


		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		glColor3f(1.0f,1.0f,1.0f);
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D,TexID1);

		glBegin(GL_POLYGON);
		glTexCoord2f(0.0f,1.0f); glVertex3f (0.0f, 0.0f, 0.0f);
		glTexCoord2f(1.0f,1.0f); glVertex3f (iw, 0.0f, 0.0f);
		glTexCoord2f(1.0f,0.0f); glVertex3f (iw, ih, 0.0f);
		glTexCoord2f(0.0f,0.0f); glVertex3f (0.0f, ih, 0.0f);
		glEnd();

		SwapBuffers(GLDC);
		}

	glDeleteTextures(1,&TexID1);
	}

If you want to do this in a 800X600 viewport, you might want to change this : if(!StartGL(1280,1024,32)) and then the render code.

Hope this helps.

Thanks, it seems to be working…will try different images…
:slight_smile:

Ack…

It “works”, but is not generic enough if you use different sized (width / height) non-square images.

This is harder than I thought.

:stuck_out_tongue:

It is very possible that when you load a 50 X 64 image (for example), it considers it as a 64X64 texture. This is because a lot of videocard deals with power of 2 texture data.

So with my example of 50X64 texture, its possible that the data is loaded in a 64X64 so you have to compensate the texture UV to reflect your image correctly.

I don’t know if this is your problem but I saw that happen before.

This seems to work for the general case
(when iw > ih)

Will modify to handle both case of iw>ih and ih>iw

void Render(void)
{
GLuint TexID1; // Handles to our textures

int screenWidth = GetSystemMetrics(SM_CXSCREEN); 
int screenHeight = GetSystemMetrics(SM_CYSCREEN);



double w = screenWidth;
double h = screenHeight;

double iw = 832;
double ih = 308;


// Load the textures

//TexID1=LoadTexture("square.tga");
TexID1=LoadTexture("eyes2.tga");



// This loop will run until Esc is pressed
while(RunLevel)
	{
	if(Keys[27]) // Esc Key
		RunLevel=0;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	double viewportAspect = (double)w / h;
	glOrtho( -viewportAspect, viewportAspect, -1.0, 1.0, -1.0, 1.0  );

	double imageAspect = (double)ih / iw;

	float quadWidth = viewportAspect;
	float quadHeight = viewportAspect*imageAspect;

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glColor3f(1.0f,1.0f,1.0f);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D,TexID1);

	glBegin(GL_POLYGON);
	glTexCoord2f(0.0f,1.0f); glVertex3f (-quadWidth, -quadHeight, 0.0);
	glTexCoord2f(1.0f,1.0f); glVertex3f ( quadWidth, -quadHeight, 0.0);
	glTexCoord2f(1.0f,0.0f); glVertex3f ( quadWidth,  quadHeight, 0.0);
	glTexCoord2f(0.0f,0.0f); glVertex3f (-quadWidth,  quadHeight, 0.0);
	glEnd();
	SwapBuffers(GLDC);
	}

glDeleteTextures(1,&TexID1);
}

I was also wondering about this kind of case.

Does anybody know if there is a way to tell if this is what has happened?

I was purposefully testing with powers of 2 sized images, because I was not sure of this.