Advertisement

Tutorial Object Picking Problem

Started by August 07, 2004 05:42 PM
4 comments, last by Adawyn 20 years, 4 months ago
I have open gl rendering in a static window within my form. The code to pick the objects seems to work, but it is offset from where it should be on the y axis being an inch above where the objects are actually drawn. If anyone can see where my problem is I would really appreciate it. I am adjusting the mouse coordinates in the following way:

case WM_LBUTTONDOWN:
        if (wParam==MK_LBUTTON)
	{			
	maininterface.handle_mouse_click((int)LOWORD(lParam), (int)HIWORD(lParam));
	}
	else
	return DefWindowProc(hwnd, msg, wParam, lParam);
break;
then maininterface.handle_mouse_click(..) looks like this I subtrack 390 from the x position because that is the offset of the static window on the main form.

void windowsinterface::handle_mouse_click(int x, int y)
{
	char valc[100]="";
	// adjust for window shift (from main)
	x = x - 390;
	if (x < 0)
		return;
	itoa(renderwindow.check_collision(x,y),valc, 100);
	MessageBox(NULL, valc, "test", MB_OK);
}
Then finally my opengl class (renderwindow object) looks like this.

#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>

struct line
{
	float x1;
	float y1;
	float x2;
	float y2;
	int ID;
	float r;
	float g;
	float b;
};

struct quad
{
	RECT box;
	int ID;
	float r;
	float g;
	float b;
};

class OpenGL
{
public:
	OpenGL()
	{
		m_RC=NULL;
		m_DC=NULL;
		m_hwnd=NULL;
		m_hinstance=NULL;
		m_clear_c=0;
		m_linecount=0;
		m_quadcount=0;
		lines=NULL;
		quads=NULL;
		m_width=0;
		m_height=0;
	};
	~OpenGL();
	GLvoid resize_scene(GLsizei width, GLsizei height);
	int init(HWND hwnd, int width, int height);
	int drawscene(GLvoid);
	void render();
	void set_clear_color(int val);
	void add_line(float x1, float y1, float x2, float y2, int val, float r, float g, float b);
	int remove_line(int ID);
	void add_quad(quad toadd);
	int remove_quad(int ID);
	int check_collision(int x, int y);
private:
	HGLRC m_RC;
	HDC m_DC;
	HWND m_hwnd;
	HINSTANCE m_hinstance;
	int m_clear_c;
	int m_linecount;
	int m_quadcount;
	struct line* lines;
	struct quad* quads;
	int m_width;
	int m_height;
};

OpenGL::~OpenGL()
{
	if (m_RC)
	{
		if (!wglMakeCurrent(NULL, NULL))
		{
			MessageBox(NULL, "DC and RC release Failed", "SHUTDOWN ERROR", MB_OK | MB_ICONEXCLAMATION);
		}
		if (!wglDeleteContext(m_RC))
		{
			MessageBox(NULL, "Rendering Context Release Failed", "SHUTDOWN ERROR", MB_OK | MB_ICONEXCLAMATION);
		}
		
		m_RC = NULL;	
	}
	if (m_DC && (!ReleaseDC(m_hwnd, m_DC)))
	{
		MessageBox(NULL, "Device Context Release Failed", "SHUTDOWN ERROR", MB_OK | MB_ICONEXCLAMATION);
		m_DC=NULL;
	}
	if (m_hwnd)
	{
		m_hwnd=NULL;
	}
}


GLvoid OpenGL::resize_scene(GLsizei width, GLsizei height)
{
	if (height==0)
		height=1;
	glViewport(0, 0, width, height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

int OpenGL::init(HWND hwnd, int width, int height)
{
	m_hwnd = hwnd;
	m_width = width;
	m_height = height;
	glShadeModel(GL_SMOOTH);
	// set background color to black
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClearDepth(1.0f);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	// set nice perspective calculations
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	

	// variable for pixle format
	GLuint PixelFormat;

	// set up pixle format descriptor
	static PIXELFORMATDESCRIPTOR pfd=
	{
		sizeof(PIXELFORMATDESCRIPTOR),
		1,
		PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA,
		32, // number of bits
		0, 0, 0, 0, 0, 0,
		0,
		0,
		0,
		0, 0, 0, 0,
		16,
		0,
		0,
		PFD_MAIN_PLANE,
		0,
		0, 0, 0
	};

	// get the device context
	if (!(m_DC = GetDC(hwnd)))
	{
		MessageBox(NULL, "Can't Create a GL Device Context", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		delete this;
		return 0;
	}

	// get the pixel format
	if (!(PixelFormat=ChoosePixelFormat(m_DC, &pfd)))
	{
		MessageBox(NULL, "Can't find a Suitable Pixel Format Check that 32 bit color is enabled", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		delete this;
		return 0;
	}

	// set the pixel format
	if (!SetPixelFormat(m_DC, PixelFormat, &pfd))
	{
		MessageBox(NULL, "Can't Set the Pixel Format", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		delete this;
		return 0;
	}

	// get the render context
	if (!(m_RC=wglCreateContext(m_DC)))
	{
		MessageBox(NULL, "Can't Create a GL Rendering Context", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		delete this;
		return 0;
	}

	// activate render context
	if (!(wglMakeCurrent(m_DC, m_RC)))
	{
		MessageBox(NULL, "Can't Activate GL Rendering Context", "ERROR", MB_OK | MB_ICONEXCLAMATION);
		delete this;
		return 0;
	}
	resize_scene(width, height);
	drawscene();

	return 1;
}

int OpenGL::drawscene(GLvoid)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	glPushMatrix();
	gluLookAt(0,0,3, 0,0,0, 0,1,0);
	glInitNames();
	if (m_quadcount)
	{
		for (int i=0; i<m_quadcount+1;i++)
		{
			glLoadName(quads.ID);
			glBegin(GL_QUADS);
				glColor3f(quads.r, quads.g, quads.b);
				glVertex3d(quads.box.left, quads.box.top,0);
				glVertex3d(quads.box.right, quads.box.top,0);
				glVertex3d(quads.box.right, quads.box.bottom,0);
				glVertex3d(quads.box.left, quads.box.bottom,0);
			glEnd();
		}
	}
	if (m_linecount)
	{
		for (int i=0; i<m_linecount+1;i++)
		{
			glLoadName(lines.ID);
			glBegin(GL_LINES);
				glColor3f(lines.r, lines.g, lines.b);
				glVertex2d(lines.x1, lines.y1);
				glVertex2d(lines.x2, lines.y2);
			glEnd();
		}
	}
	glPopMatrix();
	glFlush();

	return 1;
}

void OpenGL::render()
{
	drawscene();
	SwapBuffers(m_DC);
}

void OpenGL::set_clear_color(int val)
{
	m_clear_c = val;
	if (val==0)
	{
		glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		glColor3f(1.0f, 1.0f, 1.0f);
	}
	else if (val==1)
	{
		glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
		glColor3f(0.0f, 0.0f, 0.0f);
	}
}		

void OpenGL::add_line(float x1, float y1, float x2, float y2, int val, float r=0, float g=0, float b=0)
{
	lines = (struct line*)realloc(lines, sizeof(line)*(m_linecount+1));
	lines[m_linecount].ID = val;
	lines[m_linecount].x1 = x1;
	lines[m_linecount].y1 = y1;
	lines[m_linecount].x2 = x2;
	lines[m_linecount].y2 = y2;
	lines[m_linecount].r = r;
	lines[m_linecount].g = g;
	lines[m_linecount].b = b;
	m_linecount++;
}

int OpenGL::remove_line(int ID)
{
	int remove_count=0;

	for (int i=0; i<m_linecount+1;i++)
	{
		if (lines.ID == ID)
		{
			for (int j=i;j<m_linecount+1;j++)
			{
				lines[j] = lines[j+1];
			}
			remove_count++;
			m_linecount--;
			if (m_linecount)
				lines = (struct line*)realloc(lines, sizeof(line)*m_linecount);
		}
	}
	return remove_count;
}

void OpenGL::add_quad(quad toadd)
{
	quads = (struct quad*)realloc(quads, sizeof(quad)*(m_quadcount+1));
	quads[m_quadcount].box = toadd.box;
	quads[m_quadcount].ID = toadd.ID;
	quads[m_quadcount].r = toadd.r;
	quads[m_quadcount].g = toadd.g;
	quads[m_quadcount].b = toadd.b;
	m_quadcount++;
}

int OpenGL::remove_quad(int ID)
{
	int remove_count=0;
	for (int i=0;i<m_quadcount+1;i++)
	{
		if (quads.ID == ID)
		{
			for (int j=i;j<m_quadcount+1;j++)
			{
				quads = quads[i+1];
			}
			remove_count++;
			m_quadcount--;
			if (m_quadcount)
				quads = (struct quad*)realloc(quads, sizeof(quad)*m_quadcount);
		}
	}
	return remove_count;
}
#include <stdio.h>

int OpenGL::check_collision(int x, int y)
{
	int objectcount=0;
	int viewportcoords[4]= {0};
	
	unsigned int selectbuffer[32] = {0};

	// set the select buffer
	glSelectBuffer(32, selectbuffer);

	// get the coordinates for the viewport
	glGetIntegerv(GL_VIEWPORT, viewportcoords);

	// switch to project matrix mode
	glMatrixMode(GL_PROJECTION);

	// push on a new matrix so I don't effect the back buffer
	glPushMatrix();
		// set the render mode so that what we render isn't actually drawn to screen
		glRenderMode(GL_SELECT);
		// reset the projection matrix
		glLoadIdentity();
		// get the projection matrix for the pick region
		gluPickMatrix(x, viewportcoords[3]-y, 2, 2, viewportcoords);
		// reset the aspect ratio
		gluPerspective(45.0f, (GLfloat)(viewportcoords[2]-viewportcoords[0])/(GLfloat)(viewportcoords[3]-viewportcoords[1]), 0.1f, 100.0f);
		// change to modelview mode
		glMatrixMode(GL_MODELVIEW);
		// render
		drawscene();
		// get the number of objects in the clicked region
		objectcount = glRenderMode(GL_RENDER);
		// change back to projection matrix
		glMatrixMode(GL_PROJECTION);
	// pop the projection matrix
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	return objectcount;
}

Didn't read the code, are you doing this in windowed mode or full screen?
Advertisement
windowed
though it is a windowed form and then I have a static window that is within the form that I am rendering to, the statics position is 0, 390 that is why I have a 390 adjust to the x coordinate. The code seems to pick objects but the picking is offset by about an inch on the screen to high. IE If I click an inch above where the object is visible it picks otherwise it doesn't
I just looked over it real quickly....I need to get to work. Does it have to do with the fact that the Y coordinates in OpenGL are inverted from the windows Y coordinate?

YOpenGL = YWindow.Left + YWindow.Height - YOpenGL;
I thought I was accounting for that with this :

gluPickMatrix(x, viewportcoords[3]-y, 2, 2, viewportcoords);

This topic is closed to new replies.

Advertisement