Drawing Image RGB Color Distribution Using OpenGL
Posted
by Pierre Alliez and Magali Mazihre
on October 18th, 2000
This article allows ones to:
- draw an image RGB color distribution using OpenGL in a dialog,
- use OpenGL display lists,
- draw antialiased smooth colored lines,
- implement mouse interaction (rotation),
- store and load an image from resource.
We assume that our aim is to display the RGB color distribution of the following image (Figure 1) in an interactive way. In particular, it would be nice to display the RGB cube and the image color cloud.




Initialization of the Rendering Engine
Following lines make the rendering engine to be initialized in a dialog.//********************************* // OnCreate //********************************* int CColorDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { // Init OpenGL engine HWND hWnd = GetSafeHwnd(); HDC hDC = ::GetDC(hWnd); if(SetWindowPixelFormat(hDC)==FALSE) return 0; if(CreateViewGLContext(hDC)==FALSE) return 0; // The lines are antialiased glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glHint(GL_LINE_SMOOTH_HINT,GL_NICEST); glLineWidth(1.5); // required glPointSize(1.0); glPolygonMode(GL_FRONT,GL_LINE); glPolygonMode(GL_BACK,GL_LINE); glShadeModel(GL_SMOOTH); // Precalculate display lists BuildListCube(); BuildListCloud(); return 0; }
//********************************************** // OpenGL //********************************************** BOOL CColorDlg::SetWindowPixelFormat(HDC hDC) { PIXELFORMATDESCRIPTOR pixelDesc; pixelDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR); pixelDesc.nVersion = 1; pixelDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_STEREO_DONTCARE; pixelDesc.iPixelType = PFD_TYPE_RGBA; pixelDesc.cColorBits = 32; pixelDesc.cRedBits = 8; pixelDesc.cRedShift = 16; pixelDesc.cGreenBits = 8; pixelDesc.cGreenShift = 8; pixelDesc.cBlueBits = 8; pixelDesc.cBlueShift = 0; pixelDesc.cAlphaBits = 0; pixelDesc.cAlphaShift = 0; pixelDesc.cAccumBits = 64; pixelDesc.cAccumRedBits = 16; pixelDesc.cAccumGreenBits = 16; pixelDesc.cAccumBlueBits = 16; pixelDesc.cAccumAlphaBits = 0; pixelDesc.cDepthBits = 32; pixelDesc.cStencilBits = 8; pixelDesc.cAuxBuffers = 0; pixelDesc.iLayerType = PFD_MAIN_PLANE; pixelDesc.bReserved = 0; pixelDesc.dwLayerMask = 0; pixelDesc.dwVisibleMask = 0; pixelDesc.dwDamageMask = 0; m_GLPixelIndex = ChoosePixelFormat(hDC,&pixelDesc); if(m_GLPixelIndex==0) // Choose default { m_GLPixelIndex = 1; if(!DescribePixelFormat(hDC,m_GLPixelIndex, sizeof(PIXELFORMATDESCRIPTOR),&pixelDesc)) return FALSE; } if(!SetPixelFormat(hDC,m_GLPixelIndex,&pixelDesc)) return FALSE; return TRUE; } //********************************* // CreateViewGLContext //********************************* BOOL CColorDlg::CreateViewGLContext(HDC hDC) { m_hGLContext = wglCreateContext(hDC); if(m_hGLContext==NULL) return FALSE; if(wglMakeCurrent(hDC,m_hGLContext)==FALSE) return FALSE; return TRUE; }
//********************************* // OnDestroy //********************************* void CColorDlg::OnDestroy() { CDialog::OnDestroy(); if(wglGetCurrentContext() != NULL) wglMakeCurrent(NULL,NULL); if(m_hGLContext != NULL) { wglDeleteContext(m_hGLContext); m_hGLContext = NULL; } glDeleteLists(1,2); }
RENDERING
The RGB cube and the cloud are rendered in two distinct display lists. The cube is a fixed part, while the color cloud is rebuild each time a new image is loaded.//********************************* // OnPaint //********************************* void CColorDlg::OnPaint() { // ** Draw scene ** CPaintDC dc(this); RenderScene(); SwapBuffers(dc.m_ps.hdc); // double buffer }
//********************************* // RenderScene //********************************* void CColorDlg::RenderScene() { ::glClearColor((float)GetRValue(m_BackColor)/255.0f, (float)GetGValue(m_BackColor)/255.0f, (float)GetBValue(m_BackColor)/255.0f,1.0f); ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ::glPushMatrix(); ::glTranslated(0.0,0.0,-8.0); ::glRotated(m_xRotate, 1.0, 0.0, 0.0); ::glRotated(m_yRotate, 0.0, 1.0, 0.0); ::glCallList(1); // cube ::glCallList(2); // clouds ::glPopMatrix(); } //*********************************************** // BuildList //*********************************************** void CColorDlg::BuildListCube(BOOL list) { GLUquadricObj* pQuadric = gluNewQuadric(); if(list) ::glNewList(1,GL_COMPILE_AND_EXECUTE); float x = m_Size; // RGB cube glBegin(GL_LINE_LOOP); glColor3ub(0,0,0); glVertex3d(-x,-x,-x); glColor3ub(255,0,0); glVertex3d(x,-x,-x); glColor3ub(255,255,0); glVertex3d(x,x,-x); glColor3ub(0,255,0); glVertex3d(-x,x,-x); glEnd(); glBegin(GL_LINE_LOOP); glColor3ub(0,0,255); glVertex3d(-x,-x,x); glColor3ub(255,0,255); glVertex3d(x,-x,x); glColor3ub(255,255,255); glVertex3d(x,x,x); glColor3ub(0,255,255); glVertex3d(-x,x,x); glEnd(); glBegin(GL_LINES); glColor3ub(0,0,0); glVertex3d(-x,-x,-x); glColor3ub(0,0,255); glVertex3d(-x,-x,x); glColor3ub(255,0,0); glVertex3d(x,-x,-x); glColor3ub(255,0,255); glVertex3d(x,-x,x); glColor3ub(255,255,0); glVertex3d(x,x,-x); glColor3ub(255,255,255); glVertex3d(x,x,x); glColor3ub(0,255,0); glVertex3d(-x,x,-x); glColor3ub(0,255,255); glVertex3d(-x,x,x); glEnd(); // Spheres glPolygonMode(GL_FRONT,GL_FILL); glPolygonMode(GL_BACK,GL_FILL); float radius = 0.1f; glPushMatrix(); glTranslated(-m_Size,-m_Size,-m_Size); glColor3ub(0,0,0); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(m_Size,-m_Size,-m_Size); glColor3ub(255,0,0); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(-m_Size,m_Size,-m_Size); glColor3ub(0,255,0); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(-m_Size,-m_Size,m_Size); glColor3ub(0,0,255); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(m_Size,m_Size,-m_Size); glColor3ub(255,255,0); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(-m_Size,m_Size,m_Size); glColor3ub(0,255,255); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(m_Size,-m_Size,m_Size); glColor3ub(255,0,255); gluSphere(pQuadric,radius,12,12); glPopMatrix(); glPushMatrix(); glTranslated(m_Size,m_Size,m_Size); glColor3ub(255,255,255); gluSphere(pQuadric,radius,12,12); glPopMatrix(); if(list) ::glEndList(); gluDeleteQuadric(pQuadric); } //*********************************************** // BuildListCloud //*********************************************** void CColorDlg::BuildListCloud() { TRACE("Build list cloud..."); // Image area unsigned int area = m_Image.GetWidth() * m_Image.GetHeight(); TRACE("area : %d...",area); // Need valid image (24 bits) if(area == 0 || m_Image.GetDepth() != 24) return; // Maximum -> area distinct colors / 2^24 // This table is memory expansive, but short lived TRACE("alloc..."); unsigned char *pTable = new unsigned char[16777216]; memset(pTable,0,16777216); // init 0 // Image data unsigned int wb32 = m_Image.GetWidthByte32(); unsigned char *pData = m_Image.GetData(); // Build a new list TRACE("build list..."); int nb = 0; ::glNewList(2,GL_COMPILE_AND_EXECUTE); glBegin(GL_POINTS); float tmp = 2.0f/255.0f*m_Size; for(unsigned int j=0;j<m_Image.GetHeight();j++) for(unsigned int i=0;i<m_Image.GetWidth();i++) { unsigned char b = pData[wb32*j+3*i]; unsigned char g = pData[wb32*j+3*i+1]; unsigned char r = pData[wb32*j+3*i+2]; if(!pTable[b*65536+g*256+r]) { glColor3ub(r,g,b); float x = -m_Size+(float)r*tmp; float y = -m_Size+(float)g*tmp; float z = -m_Size+(float)b*tmp; glVertex3d(x,y,z); pTable[b*65536+g*256+r] = 1; nb++; } } glEnd(); ::glEndList(); TRACE("%d points...",nb); TRACE("cleanup..."); delete [] pTable; TRACE("ok\n"); }
Downloads
Download source - 10 KbDownload (built) demo project - 530 Kb

Comments
wglDeleteContext error
Posted by Legacy on 05/08/2001 12:00amOriginally posted by: de Halleux Jonathan
I tried to run your code in debug mode but when wglDeleteContext is called in void " CColorDlg::OnDestroy " an error occur ("user break point from code blablabla").
I have the same problem for another application. Do you have any clue about this ?
Reply