Advertisement

Zoom issue

Started by July 04, 2024 06:35 PM
2 comments, last by taby 5 months, 3 weeks ago

I've got some OpenGL code:

void draw_textured_quad(vector<quad> &quads, GLuint shader_program, long signed int x, long signed int y, long signed int tile_size, long signed int win_width, long signed int win_height, GLuint tex_handle, ImVec2 uv_min, ImVec2 uv_max)
{
	static GLuint vao = 0, vbo = 0, ibo = 0;

	if (!glIsVertexArray(vao))
	{
		glGenVertexArrays(1, &vao);
		glGenBuffers(1, &vbo);
		glGenBuffers(1, &ibo);
	}

	glDisable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	complex<float> v0w(static_cast<float>(x), static_cast<float>(y));
	complex<float> v1w(static_cast<float>(x), static_cast<float>(y + tile_size));
	complex<float> v2w(static_cast<float>(x + tile_size), static_cast<float>(y + tile_size));
	complex<float> v3w(static_cast<float>(x + tile_size), static_cast<float>(y));

	v0w.real(v0w.real() * zoom_factor);
	v0w.imag(v0w.imag() * zoom_factor);
	v1w.real(v1w.real() * zoom_factor);
	v1w.imag(v1w.imag() * zoom_factor);
	v2w.real(v2w.real() * zoom_factor);
	v2w.imag(v2w.imag() * zoom_factor);
	v3w.real(v3w.real() * zoom_factor);
	v3w.imag(v3w.imag() * zoom_factor);

	quad q;
	q.vertices[0].x = v0w.real();
	q.vertices[0].y = v0w.imag();
	q.vertices[1].x = v1w.real();
	q.vertices[1].y = v1w.imag();
	q.vertices[2].x = v2w.real();
	q.vertices[2].y = v2w.imag();
	q.vertices[3].x = v3w.real();
	q.vertices[3].y = v3w.imag();
	quads.push_back(q);

	complex<float> v0ndc = get_ndc_coords_from_window_coords(win_width, win_height, v0w);
	complex<float> v1ndc = get_ndc_coords_from_window_coords(win_width, win_height, v1w);
	complex<float> v2ndc = get_ndc_coords_from_window_coords(win_width, win_height, v2w);
	complex<float> v3ndc = get_ndc_coords_from_window_coords(win_width, win_height, v3w);

	const GLfloat vertexData[] = {
		//	  X             Y             Z		  U         V     
			  v0ndc.real(), v0ndc.imag(), 0,      uv_min.x, uv_max.y,
			  v1ndc.real(), v1ndc.imag(), 0,      uv_min.x, uv_min.y,
			  v2ndc.real(), v2ndc.imag(), 0,      uv_max.x, uv_min.y,
			  v3ndc.real(), v3ndc.imag(), 0,      uv_max.x, uv_max.y,
	};

	// https://raw.githubusercontent.com/progschj/OpenGL-Examples/master/03texture.cpp

	glBindVertexArray(vao);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);

	glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4 * 5, vertexData, GL_STATIC_DRAW);

	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (char*)0 + 0 * sizeof(GLfloat));
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (char*)0 + 3 * sizeof(GLfloat));

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

	static const GLuint indexData[] = {
		3,1,0,
		2,1,3,
	};

	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * 2 * 3, indexData, GL_STATIC_DRAW);

	glBindVertexArray(0);

	glUseProgram(ortho_shader.get_program());

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, tex_handle);

	glUniform1i(uniforms.ortho_shader_uniforms.tex, 0);
	glUniform1i(uniforms.ortho_shader_uniforms.viewport_width, win_width);
	glUniform1i(uniforms.ortho_shader_uniforms.viewport_height, win_height);

	glBindVertexArray(vao);

	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}

which is called by this code:

		for (size_t i = 0; i < tiles_per_dimension; i++)
		{
			for (size_t j = 0; j < tiles_per_dimension; j++)
			{
				size_t index = i * tiles_per_dimension + j;

				vector<quad> quads;

				draw_textured_quad(quads, ortho_shader.get_program(), int(image_anchor.x) + int(i) * background_tiles[index].tile_size, int(image_anchor.y) + int(j) * background_tiles[index].tile_size, background_tiles[index].tile_size, (int)io.DisplaySize.x, (int)io.DisplaySize.y, my_image_texture, background_tiles[index].uv_min, background_tiles[index].uv_max);
			
				if (quads.size() == 1)
				{
					int x, y;
					SDL_GetMouseState(&x, &y);

					quad q = quads[0];

					float min_x = FLT_MAX;
					float min_y = FLT_MAX;
					float max_x = -FLT_MAX;
					float max_y = -FLT_MAX;

					if (q.vertices[0].x < min_x)
						min_x = q.vertices[0].x;
					else if (q.vertices[0].x > max_x)
						max_x = q.vertices[0].x;

					if (q.vertices[1].x < min_x)
						min_x = q.vertices[1].x;
					else if (q.vertices[1].x > max_x)
						max_x = q.vertices[1].x;

					if (q.vertices[2].x < min_x)
						min_x = q.vertices[2].x;
					else if (q.vertices[2].x > max_x)
						max_x = q.vertices[2].x;

					if (q.vertices[3].x < min_x)
						min_x = q.vertices[3].x;
					else if (q.vertices[3].x > max_x)
						max_x = q.vertices[3].x;

					if (q.vertices[0].y < min_y)
						min_y = q.vertices[0].y;
					else if (q.vertices[0].y > max_y)
						max_y = q.vertices[0].y;

					if (q.vertices[1].y < min_y)
						min_y = q.vertices[1].y;
					else if (q.vertices[1].y > max_y)
						max_y = q.vertices[1].y;

					if (q.vertices[2].y < min_y)
						min_y = q.vertices[2].y;
					else if (q.vertices[2].y > max_y)
						max_y = q.vertices[2].y;

					if (q.vertices[3].y < min_y)
						min_y = q.vertices[3].y;
					else if (q.vertices[3].y > max_y)
						max_y = q.vertices[3].y;

					if (x >= min_x && x <= max_x && y >= min_y && y <= max_y)
					{
						cout << i << " " << j << endl;
					}
				}
			}
		}

It works perfectly fine when zoom_factor is 1.0. But for other zoom levels, it does not work. Any ideas?

The full source – which requires SDL 2 and OpenCV – is at https://github.com/sjhalayka/tiles

taby said:
It works perfectly fine when zoom_factor is 1.0. But for other zoom levels, it does not work. Any ideas?

Well, saying just ‘it does not work’ is not really helpful to tell us what we should look for. What do you expect, and what happens instead?

However, this seems strange:

	complex<float> v0w(static_cast<float>(x), static_cast<float>(y));
	complex<float> v1w(static_cast<float>(x), static_cast<float>(y + tile_size));
	complex<float> v2w(static_cast<float>(x + tile_size), static_cast<float>(y + tile_size));
	complex<float> v3w(static_cast<float>(x + tile_size), static_cast<float>(y));

	v0w.real(v0w.real() * zoom_factor);
	v0w.imag(v0w.imag() * zoom_factor);
	v1w.real(v1w.real() * zoom_factor);
	v1w.imag(v1w.imag() * zoom_factor);
	v2w.real(v2w.real() * zoom_factor);
	v2w.imag(v2w.imag() * zoom_factor);
	v3w.real(v3w.real() * zoom_factor);
	v3w.imag(v3w.imag() * zoom_factor);

I would expect this instead:

complex<float> v0w(x, y);
complex<float> v1w(x, y+1);
complex<float> v2w(x+1, y+1);
complex<float> v3w(x+1, y);

v0w *= tile_size * zoom_factor;
v1w *= tile_size * zoom_factor;
v2w *= tile_size * zoom_factor;
v3w *= tile_size * zoom_factor;






(Too lazy for the casting)

With this convention, tiles have indices independent from their size, so each tile is just one cell in the grid.

Maybe that's not what you want for a reason. But if so, it follows that both tilesize and zoomfactor are ust a value for scale, so one of the two is redundant.

Advertisement

@JoeJ Thank you, sir. I found a solution… use win_height:

	quad q;
	q.vertices[0].x = v0w.real();
	q.vertices[0].y = win_height - v0w.imag();
	q.vertices[1].x = v1w.real();
	q.vertices[1].y = win_height - v1w.imag();
	q.vertices[2].x = v2w.real();
	q.vertices[2].y = win_height - v2w.imag();
	q.vertices[3].x = v3w.real();
	q.vertices[3].y = win_height - v3w.imag();
	quads.push_back(q);

This topic is closed to new replies.

Advertisement