Draw rubber-band selection box

Hi, I know this has been asked a number of times, but all the ones I found either referred to the old deprecated pipeline or did not answer the question of how to draw the rectangle.

In the old days it was fairly simple to draw a “rubber-band” selection box:

  1. copy the current front buffer into the back buffer
  2. set the orthographic projection
  3. use glLogicOp(GL_XOR) and Begin(GL_LINES) to draw the box
  4. Swapbuffers

These days I don’t know how it is done. I have listed the code below which does not work on many levels, first glCopyPixels I don’t think exists any more so I have no idea how to copy the front buffer into the back buffer.

Thanks for any advice.

	wglMakeCurrent(m_hDC, m_hRC);

	RECT rc;
	::GetClientRect(m_hWnd, &rc);

	glReadBuffer(GL_FRONT);
	glDrawBuffer(GL_BACK);
	glCopyPixels(rc.left, rc.top, rc.right, rc.bottom, GL_COLOR);

	GLuint pBuffer;
	glGenBuffers(1, &pBuffer);

	Vector3f box[5] = {
		{ m_zoomTracker.Left(), m_zoomTracker.Bottom(), 0.f },
		{ m_zoomTracker.Right(), m_zoomTracker.Bottom(), 0.f },
		{ m_zoomTracker.Right(), m_zoomTracker.Top(), 0.f },
		{ m_zoomTracker.Left(), m_zoomTracker.Top(), 0.f },
		{ m_zoomTracker.Left(), m_zoomTracker.Bottom(), 0.f }
	};

	glBindBuffer(GL_ARRAY_BUFFER, pBuffer);
	glEnableVertexAttribArray(AGL_ATTRIBUTE_VERTEX);
	glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3f)*5, box, GL_STATIC_DRAW);
	glVertexAttribPointer(AGL_ATTRIBUTE_VERTEX, 3, GL_FLOAT, GL_FALSE, 0, 0);

	m_frustum.SetOrthographic(rc.left, rc.right, rc.top, rc.bottom, -1.f, 1.f);

	glDisable(GL_DEPTH_TEST);
	glEnable(GL_COLOR_LOGIC_OP);
	glLogicOp(GL_XOR);
	glColor3f(1.f, 1.f, 1.f);
	glLineWidth(2.f);

	glDrawArrays(GL_LINES, 0, 5);
	//glRectf(m_zoomTracker.Left(), m_zoomTracker.Top(), m_zoomTracker.Right(), m_zoomTracker.Bottom());

	glEnable(GL_DEPTH_TEST);
	glDisable(GL_COLOR_LOGIC_OP);

	glDeleteBuffers(1, &pBuffer);

	m_frustum.SetPerspective(FOV, m_aspectRatio, 1.0, m_sceneDiagonal * 4);

	SwapBuffers(m_hDC);

actually in the good ol’ days people simply did the rubber banding on the front buffer. No need for the copy to back buffer, and then another buffer swap. It was easy to undo as well as you just draw the same again and it’ll disappear.

You can still do this today, but in Vista (onwards I assume) you need to call glflush or glfinish after you’ve finished drawing, otherwise the OS doesn’t know to update the screen. Since everything is rendered through d3d.

[QUOTE=dukey;1245618]actually in the good ol’ days people simply did the rubber banding on the front buffer. No need for the copy to back buffer, and then another buffer swap. It was easy to undo as well as you just draw the same again and it’ll disappear.

You can still do this today, but in Vista (onwards I assume) you need to call glflush or glfinish after you’ve finished drawing, otherwise the OS doesn’t know to update the screen. Since everything is rendered through d3d.[/QUOTE]

I thought glflush and glfinish only complete the gl commands. In a double buffered system you still need to refresh the screen with a swap. The reason I copy the front to back is that

  1. the back buffer is undefined after a swap
  2. I don’t want to redraw the scene, in my case there is no animation so the scene remains the same for duration of the mouse drag.

Anyways, I tried your suggestion and it still doesn’t work. So, assuming you are right, then there must be something wrong with the drawing commands which I can’t figure out.

I don’t know how to refresh the screen in a double-buffered system without a swap, but that’s another issue. I decided to just add this function to the end of my draw scene function (after removing the frame buffer commands) and there is definitely a problem with the drawing code that I cannot figure out. The shader I’m binding to does the following, the mvp matrix is just the orthographic projection matrix, there is no modelview transforms since I am drawing on top of the screen.

uniform mat4 mvpMatrix;
attribute vec4 vVertex;

void main(void)
{
  gl_Position = mvpMatrix * vVertex;
}
void main(void)
{
  gl_FragColor = gl_Color;
}

I don’t know how to refresh the screen in a double-buffered system without a swap,

glDrawBuffer(GL_FRONT);

// draw some stuff

glFlush();

glDrawBuffer(GL_BACK);

I tried that and it didn’t do anything. At least by adding the code to the end of the draw scene code it does something, although what it does is erase the screen.

So it turns out the erasing effect was a bug outside of the opengl code. There is still a problem with this code, that I can’t figure out. Whether I use dukey’s suggestion to draw to the front buffer or just add it to the end of the draw scene function, still nothing happens. I don’t know if it is in the vertex shader or the fragment shader but nothing is happening. Btw, the I edited the fragment shader to correct it.

Thanks to anyone who see the obvious problem with this code.