Click here to Skip to main content
13,256,716 members (51,519 online)
Click here to Skip to main content
Add your own
alternative version


49 bookmarked
Posted 8 Feb 2006

Rubber-Banding with OpenGL

, 7 Jan 2012
Rate this:
Please Sign up or sign in to vote.
Rubber-banding with OpenGL - A utility class


This article shows how we can perform rubber-banding in an OpenGL application.


Rubber-banding is frequently used by drawing programs. The objective is to draw something such as a rectangle, then erase it without disturbing what has already been rendered. The rubber-banding rectangle can then be used for selecting objects. For an OpenGL application, rubber-banding can be achieved by rendering with the logic op enabled and set to XOR mode.

The source code here includes a simple C++ class called jxglTracker. The two main member functions in the class are DrawTrackRect() and Track(). In the DrawTrackRect() function, the logic op is enabled by calling glEnable(GL_COLOR_LOGIC_OP) and the XOR mode is set by calling glLogicOp(GL_XOR). The rubber-banding rectangle is drawn using glRecti().

void jxglTracker::DrawTrackRect(int x1, int y1, int x2, int y2)
    CRect rectClient;
    // drawing different rubber-banding rectangle
    // depending on the mouse movement x-direction
    if(x1 < x2)
        glColor4f(0.0, 0.0, 1.0, 0.5);
        glColor4f(1.0, 0.0, 0.0, 0.5);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    // OpenGL window coordinates are different from GDI's
    glRecti(x1, rectClient.Height() - y1, x2, 
                rectClient.Height() - y2);
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glFlush(); // must flush here

In the Track() function, we first set the drawing buffer to the front-buffer instead of the default back-buffer. This is needed because we do not want to disturb what has already been drawn (which could be expensive to redraw) while the rubber-banding rectangle is constantly being drawn and erased. Here, we also set up a convenient projection matrix so the pixels on the window client rectangle corresponds to the OpenGL model coordinate system. The DrawTrackRect() is called in an infinite for loop until WM_LBUTTONUP, WM_RBUTTONDOWN or the ESC WM_KEYDOWN message is received. The Track() function takes CWnd* pWnd and CPoint point as parameters, and is generally called from the WM_LBUTTONDOWN message handler of the client window pWnd.

BOOL jxglTracker::Track(CWnd* pWnd, CPoint point)
    m_pWnd = pWnd;
    ASSERT(m_pWnd != 0);
    CRect rectClient;

    // set drawing mode to front-buffer

    // set up a convenient projection matrix
    glOrtho(0, rectClient.Width(), 0, 
               rectClient.Height(), -1, 1);
    glViewport(-1, -1, rectClient.Width() + 2, 
                       rectClient.Height() + 2);

    if (::GetCapture() != NULL)
        return FALSE;

    // set mouse capture because we
    // are going to work on this window
    ASSERT(pWnd == CWnd::GetCapture());

    BOOL bMoved = FALSE;
    CPoint ptOld = point;
    CRect rectOld = CRect(ptOld, ptOld);
    CPoint ptNew;

    BOOL bStop = FALSE;
    for (;;)
        // loop forever until LButtonUp,
        // RButtonDown or ESC keyDown
        MSG msg;
        VERIFY(::GetMessage(&msg, NULL, 0, 0));
        if (CWnd::GetCapture() != pWnd)

        if(msg.message == WM_LBUTTONUP || msg.message == WM_MOUSEMOVE)
            ptNew.x = (int)(short)LOWORD(msg.lParam);
            ptNew.y = (int)(short)HIWORD(msg.lParam);
            m_rect = CRect(ptOld, ptNew);
            if (bMoved)
                m_bErased = TRUE;
            rectOld = m_rect;
            if (msg.message != WM_LBUTTONUP)
                bMoved = TRUE;
            if (msg.message == WM_MOUSEMOVE)
                m_bErased = FALSE;
                bStop = TRUE;
                ASSERT(msg.message == WM_LBUTTONUP);
        else if(msg.message == WM_KEYDOWN)
            if (msg.wParam == VK_ESCAPE)
                bStop = TRUE;
        else if(msg.message == WM_RBUTTONDOWN)
            bStop = TRUE;

    } // for (;;)

    // release mouse capture
        // do a final erase if needed

    // restore drawing mode to back-buffer

    return TRUE;

Using the Code

The jxglTracker class can be simply used inside the WM_LBUTTONDOWN message handler like shown below:

void COglRubberBandView::OnLButtonDown(UINT nFlags, CPoint point) 
    CPaintDC dc(this); // device context for painting
    wglMakeCurrent(dc.m_hDC, m_hRC);

    jxglTracker tracker;
    tracker.Track(this, point);

    CView::OnLButtonDown(nFlags, point);

Points of Interest

An MDI MFC-OpenGL application (oglRubberBand) is used to test the jxglTracker rubber-banding class. This application is generated by the MFC AppWizard (accepting default settings) using VC++ 6.0. It is beyond the scope of this article to explain the details of setting up OpenGL. The main logic is contained in the view class (COglRubberBandView) and should be pretty easy to follow. Of course, the jxglTracker.h and jxglTracker.cpp files are added to the project. OpenGL libraries are linked through #pragma comment(lib,"opengl32.lib") etc. in the stdafx.h file.

Depending on the graphics card speed of your system, you can change the number of geometry entities to draw, as shown below. Notice that the drawing speed of the rubber-banding should not be affected by the number of entities already drawn.

void COglRubberBandView::OnPaint() 
    const int nLines = 10000; // let's draw quite a few lines

Happy coding!


  • 8th February, 2006: Initial post
  • 16th November, 2009: Article updated - code change that fixed a display bug in Windows 7 environment
  • 6th January, 2012: Article updated - code change that fixed a bug on Vista and Windows 7


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Junlin Xu
President Computations & Graphics, Inc.
United States United States
Junlin Xu is the founder of Computations & Graphics, Inc. ( He is the author of Real3D-Analysis (finite element package), SolverBlaze (finite element SDK), OpenGraph Library (OpenGL-based visualization and charting SDK for native and .NET environment), double128 SDK (quad precision floating point math for C++ and .NET).

Junlin has 19+ years software development experiences in various industries. He has skills in Windows desktop and web application development using C++, C++/CLI, C#, Objective C, Win32 and Win64, MFC, STL, OpenGL,GLSL,COM/COM+, WinForm, MS SQL, MySLQ, ASP.NET, MVC4, CSS, jQuery and jQuery UI, WCF, WPF, HL7, Mirth Connect, Autodesk Revit API, FEM, Inno Setup. He is also an expert in mathematical, CAD and algorithmic software development.

You may also be interested in...

Comments and Discussions

GeneralRe: Couple of issues with this code Pin
baoyibao12-Aug-09 18:12
memberbaoyibao12-Aug-09 18:12 
GeneralRe: Couple of issues with this code Pin
Junlin Xu4-Nov-09 15:47
memberJunlin Xu4-Nov-09 15:47 
GeneralRe: Couple of issues with this code Pin
Le Roy9-Nov-11 3:28
memberLe Roy9-Nov-11 3:28 
GeneralRe: Couple of issues with this code Pin
Junlin Xu10-Nov-11 14:37
memberJunlin Xu10-Nov-11 14:37 
GL_LOGIC_OP is supported on OpenGL 1.1 or higher. It is not supported on OpenGL ES.
GeneralDo you have this sample in VB6? Pin
Member 839378011-Nov-11 4:09
memberMember 839378011-Nov-11 4:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.171114.1 | Last Updated 7 Jan 2012
Article Copyright 2006 by Junlin Xu
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid