I am implementing 2D graphics in WPF using the SharpGL library. I managed to draw some primitive objects on the screen, and I need to detect mouse clicks on these objects.
I reviewed the OpenGL tutorial on how to select and select graphic objects, but I was not able to get it to work. In my test application, I draw three triangles on the screen, and when I click the mouse I draw the same three triangles in GL_SELECT mode, hoping to detect if any of the triangles was pressed. I am not sure if this is the right approach. The Hit test always returns all elements from the selection buffer.
I know that the width and height parameters in PickMatrix are incorrect, and I'm not quite sure that the correct values ββwill be there. Is it the width and height of the whole view?
private void OpenGLControl_OpenGLDraw(object sender, SharpGL.SceneGraph.OpenGLEventArgs args) { //// Get the OpenGL object. OpenGL gl = args.OpenGL; //set background to white gl.ClearColor(1.0f, 1.0f, 1.0f, 1.0f); //// Clear the color and depth buffer. gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); DrawScene(); gl.Flush(); } private void DrawScene() { OpenGL gl = openGLControl.OpenGL; gl.Color(1.0, 0.0, 0.0); DrawTriangle(-0.2, 0.6, 0.0, 0.8, 0.2, 0.6); gl.Color(0.0, 1.0, 0.0); DrawTriangle(-0.2, 0.2, 0.0, 0.4, 0.2, 0.2); gl.Color(0.0, 0.0, 1.0); DrawTriangle(-0.2, -0.2, 0.0, 0.0, 0.2, -0.2); } private void SelectObjects(double mouseDownX, double mouseDownY) { OpenGL gl = openGLControl.OpenGL; int BUFSIZE = 512; uint[] selectBuf = new uint[BUFSIZE]; gl.SelectBuffer(BUFSIZE, selectBuf); gl.RenderMode(OpenGL.GL_SELECT); gl.InitNames(); gl.PushName(0); int[] viewport = new int[4]; gl.GetInteger(OpenGL.GL_VIEWPORT, viewport); //how to define the width and height of an element? gl.PickMatrix(mouseDownX, (double)(viewport[3] - mouseDownY), 50.0, 50.0, viewport); gl.LoadIdentity(); gl.LoadName(1); gl.Color(1.0, 0.0, 0.0); DrawTriangle(-0.2, 0.6, 0.0, 0.8, 0.2, 0.6); gl.LoadName(2); gl.Color(0.0, 1.0, 0.0); DrawTriangle(-0.2, 0.2, 0.0, 0.4, 0.2, 0.2); gl.LoadName(3); gl.Color(0.0, 0.0, 1.0); DrawTriangle(-0.2, -0.2, 0.0, 0.0, 0.2, -0.2); gl.Flush(); int hits = gl.RenderMode(OpenGL.GL_RENDER); processHits(hits, selectBuf); } private void processHits(int hits, uint[] buffer) { uint bufferIterator = 0; for (uint i = 0; i < hits; i++) { uint numberOfNamesInHit = buffer[bufferIterator]; Console.WriteLine("hit: " + i + " number of names in hit " + numberOfNamesInHit); uint lastNameIndex = bufferIterator + 2 + numberOfNamesInHit; for (uint j = bufferIterator + 3; j <= lastNameIndex; j++) { Console.WriteLine("Name is " + buffer[j]); } bufferIterator = bufferIterator + numberOfNamesInHit + 3; } } private void OnMouseClick(object sender, MouseEventArgs e) { System.Windows.Point position = e.GetPosition(this); SelectObjects(position.X, position.Y); }
The output is always the same:
hit: 0 number of names per hit 1
First name 1
hit: 1 number of names per hit 1
Name 2
hit: 2 numbers of names per hit 1
Name 3