Masking Texture in OpenGL using Class CImage






3.64/5 (13 votes)
Masking Texture in OpenGL from Bitmap Image File using Class CImage (just call the File Name)
Introduction
In my previous article, Image Mapping in OpenGL Using Class CImage, I demonstrated some useful texture handling techology by just calling the name of the image file for texture mapping without a lot of stages with the conditions implementation required. The straight follow-up should be the image masking application provided also arranged as just calling the name of the image bitmap file.
Background
The procedure of masking texture implementation in OpenGL just calling the name of the image bitmap file has been developed with the application of the class CImage
. The demo project MaskTexture
has been derived from my previous article project ImgTexture
derived from the standard MFC Cube Sample project renamed with the CodeProject ProjRename program.
Using the Code
The global procedure LoadMaskTexture(LPCTSTR fName)
and related procedure MakeBWMask(CImage * pImg, CDC *pDC, int w, int h, COLORREF eColor, int BPP)
have been added to the GlobGLTexture.cpp file from the previous article project ImgTexture
. For using the technology provided, you may insert the GlobGLTexture.cpp file into your own project with the menu PROJECT->Add Existing Item... command.
The procedure for masking texture loading:
DWORD LoadMaskTexture(LPCTSTR fName) //Load Mask texture from Bitmap Image file
{
CImage img;
HRESULT hResult = img.Load(fName); //Standard procedure of CImage loading
if (FAILED(hResult)) {
_TCHAR fmt[1028];
_stprintf_s((_TCHAR *)fmt, hResult,
_T("Error %d\n%s\nin file:\n%s"), _com_error(hResult).ErrorMessage(), fName);
MessageBox(NULL, fmt, _T("Error:"), MB_OK | MB_ICONERROR);
return FALSE;
}//if(FAILED(hResult))
if (img.GetBPP() != 24) //if Bitmap format not compatible with
//GL_BGR_EXT
{
CImage tmg;
tmg.Create(img.GetWidth(), img.GetHeight(), 24); //Create CImage compatible
//with GL_BGR_EXT
img.BitBlt(tmg.GetDC(), CPoint(0, 0)); //Copy Original Image to
//the environment created
}
CImage * pSmg = new CImage;
CDC * tDC = CDC::FromHandle(img.GetDC()); //Temporarily graphic context
//Create Black & White mask from original image:
MakeBWMask(pSmg, tDC, img.GetWidth(), img.GetHeight(), tDC->GetPixel(0, 0),
img.GetBPP());
CBitmap * pBmw = GetImgBitmap(pSmg); //Bitmap of the
//Black & White mask
if (pBmw == NULL)
return FALSE;
BITMAP BMPw;
pBmw->GetBitmap(&BMPw);
GLuint nBw = LoadGLTexture(&BMPw); //Create texture of the
//Black & White mask
CDC * pDC = new CDC; //Temporarily graphic context
pDC->CreateCompatibleDC(CDC::FromHandle(img.GetDC()));
CBitmap bmt;
bmt.CreateCompatibleBitmap(CDC::FromHandle(img.GetDC()),
img.GetWidth(), img.GetHeight());
CBitmap * pBm = pDC->SelectObject(&bmt);
//Copy Black & White mask into Temporarily graphic context:
pDC->BitBlt(0, 0, img.GetWidth(), img.GetHeight(),
CDC::FromHandle(pSmg->GetDC()), 0, 0, SRCCOPY);
//Invert colours in Copy Temporarily graphic context mask int
//Temporarily graphic context:
pDC->BitBlt(0, 0, img.GetWidth(),
img.GetHeight(), NULL, 0, 0, DSTINVERT);
//Copy Temporarily graphic context into original image into
//making background color Black:
CDC::FromHandle(img.GetDC())->BitBlt(0, 0, img.GetWidth(),
img.GetHeight(), pDC, 0, 0, SRCAND);
pDC->SelectObject(pBm);
bmt.DeleteObject();
pDC->DeleteDC();
delete pDC; //Remove Temporarily graphic context
CBitmap * pBmi = GetImgBitmap(&img);
BITMAP BMPi;
pBmi->GetBitmap(&BMPi);
delete pBmw; //Clear all Temoparily
delete pSmg;
pSmg = NULL;
GLuint nImg = LoadGLTexture(&BMPi); //Create texture of the mask
//with Black background
delete pBmi;
return MAKELONG(nImg, nBw); //return HIWORD with color texture name
//and LOWORD with Black & White texture name
}
The scheme masking texture has been provided in the table below:
Original masking image Bitmap format and one-ton background color; Top Left pixel GetPixel(0,0) must be of background color | ![]() | Original Background Image; may be of any format | ![]() | |
![]() | ![]() | |||
Black-white masking image provided with MakeBWMask procedure | ![]() | ![]() | Clear to black the masking space 1 1! 1! in the Original Bakground Image | ![]() |
![]() | ![]() | |||
Change background to black with the Black-white masking image inverted: | ![]() | ![]() | Final Masked Image is a result of composition colour mask with the black background to the original background texture with the black space for masking | ![]() |
The left column of the table above demonstrates the LoadMaskTexture
steps of creation two masking textures:
- Black-white masking image provided with MakeBWMask procedure
- Colour masking image with the black background with the Black-white masking the image inverted
The procedure for Black-white masking image creating (change all the background pixels to white, others to black):
void MakeBWMask(CImage * pImg, CDC *pDC, int w, int h, COLORREF eColor, int BPP)
{
pImg->Create(w, h, BPP);
CDC * tDC = CDC::FromHandle(pImg->GetDC());
for (int i = 0; i < w; i++)
for (int j = 0; j < h; j++)
{
COLORREF rgb = pDC->GetPixel(i, j); //get pixel colour
if (rgb == eColor)
tDC->SetPixel(i, j, RGB(255, 255, 255)); //if the colour is a
//background colour
//set pixel white;
else
tDC->SetPixel(i, j, RGB(0, 0, 0)); //if the colour is not
//a background
//colour, set pixel black;
}
}
The variables inserted:
int m_texNum; //Current order number of the name of the texture
int m_maskNum; //Current order number of the name of the mask texture
CWordArray m_globTexture; //Array of the textures' names available
CDWordArray m_globMask; //Array of the bitmap mask textures' names available
enum VIEW_TYPE
{
VIEW_DEFAULT, //Original Cube Sample View
VIEW_TEXTURE, //Texture View
VIEW MASK, //Masking View
};
The original CImgTextureView::Init()
procedure with the procedures related remains unchanged; in CImgTextureView::OnCreate
procedure in demo purposes, the two lines of the texture implementation and three lines of masking implementation from the image files in the Data folder of the root directory located:
int CImgTextureView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
Init(); // initialize OpenGL
m_globTexture.Add((WORD)LoadImgTexture(_T("Data/MSUN.jpg"))); //you may insert
//here any image file
//in any pathway
m_globTexture.Add((WORD)LoadImgTexture(_T("Data/famrt.jpg")));//and as much as
//you like
m_globMask.Add(LoadMaskTexture(_T("Data/vldv.bmp"))); //you may insert here any
//bitmap image file in
//any pathway
m_globMask.Add(LoadMaskTexture(_T("Data/ussr.bmp"))); //and as much as you like;
//just keep in mind that
//the color
m_globMask.Add(LoadMaskTexture(_T("Data/rsfsr.bmp"))); //of the left top pixel
//(GetPixel(0,0)) assumed as
//a background color
return 0;
} ;
You may insert here any image files and any masking bitmap image files from any pathway valid and as much as you like. In the original CMaskTextureView::DrawScene
procedure, the block of masking texture handling inserted:
case VIEW_MASK:
{
//Every face visibility checking required(depth test)
GLdouble model[16]; //MODELVIEW_MATRIX
glGetDoublev(GL_MODELVIEW_MATRIX, model);
GLdouble proj[16]; //PROJECTION_MATRIX
glGetDoublev(GL_PROJECTION_MATRIX, proj);
GLint vw[4]; //VIEWPORT MATRIX
glGetIntegerv(GL_VIEWPORT, vw);
GLdouble xt0, yt0, zt0; //true coord of the cube center
gluProject(0.0, 0.0, 0.0, model,
proj, vw, &xt0, &yt0, &zt0); //calc true coord of the
//cube center
//////////////Front Face
// Front Face Bkg
GLdouble xt, yt, zt;
gluProject(0.0, 0.0, a, model, proj, vw, &xt, &yt, &zt); //calc true coord
//of the face center
if (zt < zt0) //if face is visible
{
glBindTexture(GL_TEXTURE_2D, m_globTexture[m_texNum]);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-a, -a, a);
glTexCoord2f(2.0f, 0.0f); glVertex3f(a, -a, a);
glTexCoord2f(2.0f, 2.0f); glVertex3f(a, a, a);
glTexCoord2f(0.0f, 2.0f); glVertex3f(-a, a, a);
glEnd();
// Front Face BW
glBindTexture(GL_TEXTURE_2D, HIWORD(m_globMask[m_maskNum]));
glEnable(GL_BLEND); // Enable Blending
glDisable(GL_DEPTH_TEST); // Disable Depth Testing
glBlendFunc(GL_DST_COLOR, GL_ZERO); // Blend Screen Color With
// Zero (Black)
glBegin(GL_QUADS);
glTexCoord2f(roll + 0.0f, 0.0f); glVertex3f(-a, -a, a);
glTexCoord2f(roll + 2.0f, 0.0f); glVertex3f(a, -a, a);
glTexCoord2f(roll + 2.0f, 2.0f); glVertex3f(a, a, a);
glTexCoord2f(roll + 0.0f, 2.0f); glVertex3f(-a, a, a);
glEnd();
// Front Face Mask
glBindTexture(GL_TEXTURE_2D, LOWORD(m_globMask[m_maskNum]));
glBlendFunc(GL_ONE, GL_ONE); // Copy Image 2 Color to
// the screen
glBegin(GL_QUADS);
glTexCoord2f(roll + 0.0f, 0.0f); glVertex3f(-a, -a, a);
glTexCoord2f(roll + 2.0f, 0.0f); glVertex3f(a, -a, a);
glTexCoord2f(roll + 2.0f, 2.0f); glVertex3f(a, a, a);
glTexCoord2f(roll + 0.0f, 2.0f); glVertex3f(-a, a, a);
glEnd();
glEnable(GL_DEPTH_TEST); // Enable Depth Testing
glDisable(GL_BLEND); // Disable Blending
}
//////////////Back Face
gluProject(0.0, 0.0, -a, model, proj, vw, &xt, &yt, &zt); //calc true coord
//of the face center
if (zt < zt0) //if face is visible
{
..............................................................................
..............................................................................
///////////////////////////////////////////// Left face
// Left Face bkg
gluProject(-a, 0.0, 0.0,
model, proj, vw, &xt, &yt, &zt); //calc true coord of
//the face center
if (zt < zt0) //if face is visible
{
glBindTexture(GL_TEXTURE_2D,
m_globTexture[m_texNum]);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-a, -a, -a);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-a, -a, a);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-a, a, a);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-a, a, -a);
glEnd();
// Left Face BW
glBindTexture
(GL_TEXTURE_2D, HIWORD(m_globMask[m_maskNum]));
glEnable(GL_BLEND); // Enable Blending
glDisable(GL_DEPTH_TEST); // Disable Depth Testing
glBlendFunc(GL_DST_COLOR, GL_ZERO); // Blend Screen Color
// With Zero (Black)
glBegin(GL_QUADS);
glTexCoord2f(0.0f, roll + 0.0f); glVertex3f(-a, -a, -a);
glTexCoord2f(1.0f, roll + 0.0f); glVertex3f(-a, -a, a);
glTexCoord2f(1.0f, roll + 1.0f); glVertex3f(-a, a, a);
glTexCoord2f(0.0f, roll + 1.0f); glVertex3f(-a, a, -a);
glEnd();
// Left Face Mask
glBindTexture
(GL_TEXTURE_2D, LOWORD(m_globMask[m_maskNum]));
glBlendFunc(GL_ONE, GL_ONE); // Copy Image 2 Color To The Screen
glBegin(GL_QUADS);
glTexCoord2f(0.0f, roll + 0.0f); glVertex3f(-a, -a, -a);
glTexCoord2f(1.0f, roll + 0.0f); glVertex3f(-a, -a, a);
glTexCoord2f(1.0f, roll + 1.0f); glVertex3f(-a, a, a);
glTexCoord2f(0.0f, roll + 1.0f); glVertex3f(-a, a, -a);
glEnd();
glEnable(GL_DEPTH_TEST); // Enable Depth Testing
glDisable(GL_BLEND); // Disable Blending
}
roll += 0.05f; // Increase Our Texture Roll Variable
if (roll>1.0f) // Is Roll Greater Than One
{
roll -= 1.0f; // Subtract 1 From Roll
}
}
break;
In this block, we need to arrange a depth test before every face handling because GL_DEPTH_TEST
is set to disabled for blending. Before every scene drawing, we call standard gluProject
procedure to calc the true coord of the cube center. Before every face drawing, we call standard gluProject
procedure to calc the true coord of the face center. The face is visible if the center of the face is shorter to observe than the center of the cube.
The right column of the table demonstrates the DrawScene
steps of masking texture:
- Original Image Texture mapping performed the same as usual texture mapping procedure
- Clear to black the masking space in the Original Background Image
- Final Masked Image is a result of composition colour mask with the black background to the original background texture with the black space for masking
After masking performance, the scroll factor increased.
All the following Menu and Accelerator Commands have been done with standard AppWizard
technologies.
Application Demo Menu and Keyboard Commands
Some menu and some special Accelerator keys arranged in order to demonstrate the ImgTexture
project implementation:
- Menu File->Open - selecting the file with the image for texture mapping
- Menu File->Open Mask *.bmp - selecting the file with the bitmap image for texture masking
- Menu View->Default - original Cube performance
- Menu View->Texture - current texture performance
- Menu View->Next Texture - next texture performance (also Right Arrow click)
- Menu View->Prev Texture - previous texture performance (also Left Arrow click)
- Menu View->Next Mask - next masking performance (also Page Up click)
- Menu View->Prev Mask - previous masking performance (also Page Down click)
Points of Interest
The technology provided above is an attempt to demonstrate one of the simple masking texture implementation possibilities. You may use the foregoing procedures in your own applications inserting the GlobGLTexture.cpp file into your own project with the menu PROJECT->Add Existing Item... command.
The project has been developed in MFC platform. Nevertheless, the GlobGLTexture.cpp procedures are also valid in Win32 and are acceptable for use in Mobile applications.
History
- 21st November, 2016: Initial version