I am exploring the possibility to render a main windows dialog using OpenGL which could have 32-bit per pixel (8-bit alpha, 24-bit color).
So, far I get the render to work and display to work, but the alpha byte stay 0x00. The alpha is working in OpenGL and as well on my main window, as I could get some alpha effect when I process this byte in software. However, this slow down the render and I cannot retrieve what was the exact alpha-value from the OpenGL buffer.
The result currently look like that:
But as you can see, the triangles render in OpenGL is not in transparent but most likely mix in a more like a add-value… where on the black it look nice, on the white, you don’t see the triangle but all white.
Looking to the alpha byte they are all zeroes. If I replace the alpha when 0, to a value related with R,G,B… I get a result that show that the win32 stuff is working.
This code work in windows XP up to windows 8. For a windows size of 800x600 pixels, I get a FPS that is currently not as good as I would like… even for this simple example on a good PC.
I think it would be very interesting if I can first get the alpha byte set in the DIB… then to check how I can improve the FPS for slow end machine.
I have start to look at DirectX stuff, to see what could be done. The code below show nothing using DirectX… as I am looking how to get the render be into buffer which would be render on a windows. I am looking just to see what will be the performance. But, I would prefer OpenGL as it may work on Linux as well.
Here is my code below… type of project win32 c++ in MSVC 2010.
So, if someone has an idea how to modify it to get the alpha byte being copy… let me know!
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include "stdafx.h"
//#include <windowsx.h>
#include <GL/gl.h>
#include <GL/glu.h>
//#include <GL/glaux.h>
#include <mmsystem.h>
#include <stdio.h>
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glu32.lib")
#pragma comment (lib, "winmm.lib")
//#pragma comment (lib, "glaux.lib")
#include <d3d9.h>
// include the Direct3D Library file
#pragma comment (lib, "d3d9.lib")
// global declarations
LPDIRECT3D9 d3d = NULL; // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev = NULL; // the pointer to the device class
#include <assert.h>
#include <tchar.h>
#include <math.h>
#define PI 3.14159265359
#ifdef assert
#define verify(expr) if(!expr) assert(0)
#else verify(expr) expr
#endif
const TCHAR szAppName[]=_T("TransparentGL");
const TCHAR wcWndName[]=_T("WS_EX_LAYERED OpenGL");
HDC hDC;
HGLRC m_hrc;
HWND g_hWnd;
int w(800);
int h(600);
bool g_bSwitchAlpha = false;//false;
bool g_bTryFaster = false;//true;
HDC pdcDIB;
HBITMAP hbmpDIB;
void *bmp_cnt(NULL);
int cxDIB(0);
int cyDIB(0);
BITMAPINFOHEADER BIH;
BITMAPV5HEADER BIHA;
//#define USE_DIRECT_X
BOOL initSC()
{
glEnable(GL_ALPHA_TEST);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glClearColor(0, 0, 0, 0);
return 0;
}
void resizeSC(int width,int height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW );
glLoadIdentity();
}
BOOL renderSC()
{
DWORD dwTime, dwTime2;
static float t = 0.0f;
float a1, a2, a3, x,y;
int i, j;
t=timeGetTime()/1.4f + 350.0f * sin(2.0f * PI * timeGetTime()/1.4f* 1.0f /1000);
#ifndef USE_DIRECT_X
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
glColor3f(0, 1, 1);
glBegin(GL_TRIANGLES); // Drawing Using Triangles
#else
// clear the window to a deep blue
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
d3ddev->BeginScene(); // begins the 3D scene
// do 3D rendering on the back buffer here
#endif
a3 = 0.0f;
for(j=0;j<5;++j)
{
x = 0.3f * sin(2.0f * PI * t* 0.25f /1000);
y = 0.3f * sin(2.0f * PI * t* 0.5f /1000);
for(i=0;i<3;++i)
{
a1 = 0.75f * cos(2.0f * PI * t *0.3f / 1000 + 2.0f * PI * i /3);
a2 = 0.75f * sin(2.0f * PI * t *0.3f / 1000 + 2.0f * PI * i /3);
#ifndef USE_DIRECT_X
if (i==0)
glColor4f(0.8f,0.0f,0.0f,1.0f); // Set The Color To Red
else if (i==1)
glColor4f(1.0f,1.0f,0.0f,1.0f); // Set The Color To Green
else
glColor4f(0.0f,0.0f+j*0.1f,2.0f,0.0f); // Set The Color To Blue
glVertex3f( a1+x, a2+y, a3); // Top
#else
#endif
}
t += (38.0f+30.0f*sin(2.0f*PI*t*0.70f/1000))*(j+1+j*0.1f);
a3-=0.01f;
// a3+=1.5f;
}
#ifndef USE_DIRECT_X
glEnd();
glPopMatrix();
glFlush();
#else
d3ddev->EndScene(); // ends the 3D scene
d3ddev->Present(NULL, NULL, NULL, NULL); // displays the created frame
#endif
/* glColor4f(0.0f,1.0f,0.0f,0.0f); // Set The Color To Green
glVertex3f(-1.0f,-0.0f-a, 0.0f); // Bottom Left
glColor4f(0.0f,0.0f,1.0f,1.0f); // Set The Color To Blue
glVertex3f( 1.0f,0.0f-a, 0.0f); // Bottom Right*/
return 0;
}
// DIB -> hDC
void draw(HDC pdcDest)
{
POINT pptDst, pptSrc;
SIZE pSize;
int i,j;
DWORD dwValue;
DWORD dwTime = timeGetTime();
assert(pdcDIB);
BLENDFUNCTION blendfunc;
blendfunc.AlphaFormat = AC_SRC_ALPHA;
blendfunc.BlendFlags = 0;
blendfunc.SourceConstantAlpha = 255;
blendfunc.BlendOp = AC_SRC_OVER;
// AlphaBlend(pdcDest, 0, 0, w, h, pdcDIB, 0, 0, w, h, blendfunc);
// TransparentBlt(pdcDest, 0, 0, w, h, pdcDIB, 0, 0, w, h, 0);
// verify(BitBlt(pdcDest, 0, 0, w, h, pdcDIB, 0, 0, SRCCOPY));
pptDst.x = 40;
pptDst.y = 30;
pptSrc.x = 0;
pptSrc.y = 0;
pSize.cx = w;
pSize.cy = h;
BOOL bRet;
unsigned char *pBuf;
/* pBuf = new unsigned char[4*w*h];
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biHeight = h;
bmi.bmiHeader.biWidth = w;
bmi.bmiHeader.biCompression = BI_BITFIELDS;
bmi.bmiHeader.biSize = sizeof(BITMAPINFO);*/
HBITMAP hbm;
// hbm = CreateCompatibleBitmap(pdcDIB, w, h);
DWORD *pBmp = (DWORD *) bmp_cnt;
// DWORD dwValue;
int a, b;
if (g_bSwitchAlpha)
{
for(i=0;i<w*h;++i)
{
if ((pBmp[i]&0xFF000000)==0)
{
a = (pBmp[i]&0x00FF00)>>8;
a+= pBmp[i]&0x00FF;
a+= (pBmp[i]&0xFF0000)>>16;
a*=1.0f+0.5f * sin(2.0f * PI * timeGetTime()*0.2f/1000);
if (a>0xFF) a = 0xFF;
pBmp[i]|= (a<<24);
}
}
}
// int nres;
// nres = GetDIBits(pdcDIB, hbm, 0, h, pBuf, &bmi, DIB_RGB_COLORS);
// if ((timeGetTime()%1000)<500)
if (g_bTryFaster)
bRet = UpdateLayeredWindow(g_hWnd, pdcDest, &pptDst, &pSize, pdcDIB, &pptSrc, RGB(0,0,0), &blendfunc, ULW_COLORKEY);
else
bRet = UpdateLayeredWindow(g_hWnd, pdcDest, &pptDst, &pSize, pdcDIB, &pptSrc, RGB(0,0,0), &blendfunc, ULW_ALPHA);
// else
// bRet = UpdateLayeredWindow(g_hWnd, pdcDest, &pptDst, &pSize, pdcDIB, &pptSrc, RGB(0,0,0), &blendfunc, ULW_ALPHA);
/* if (g_bTryFaster)
bRet = UpdateLayeredWindow(g_hWnd, pdcDest, &pptDst, &pSize, pdcDIB, &pptSrc, RGB(0,0,0), &blendfunc, ULW_OPAQUE|ULW_COLORKEY);
else
bRet = UpdateLayeredWindow(g_hWnd, pdcDest, &pptDst, &pSize, pdcDIB, &pptSrc, RGB(0,0,0), &blendfunc, ULW_ALPHA);*/
// else
// bRet = UpdateLayeredWindow(g_hWnd, pdcDest, &pptDst, &pSize, pdcDIB, &pptSrc, RGB(0,0,0), &blendfunc, ULW_ALPHA|ULW_OPAQUE);
// AlphaBlend(pdcDest, 0, 0, w, h, pdcDIB, 0, 0, w, h, blendfunc);
// dwTime = timeGetTime() - dwTime;
// char szDbg[MAX_PATH];
// sprintf(szDbg, "draw: %d ms
", dwTime);
// OutputDebugString(szDbg);
}
void CreateDIB(int cx, int cy)
{
assert(cx > 0);
assert(cy > 0);
cxDIB = cx ;
cyDIB = cy ;
/* int iSize = sizeof(BITMAPINFOHEADER);
memset(&BIH, 0, iSize);
BIH.biSize = iSize;
BIH.biWidth = cx;
BIH.biHeight = cy;
BIH.biPlanes = 1;
BIH.biBitCount = 32;
BIH.biCompression = BI_RGB;*/
int iSize = sizeof(BITMAPV5HEADER);
memset(&BIHA, 0, iSize);
//The following mask specification specifies a supported 32 BPP
//alpha format for Windows XP.
BIHA.bV5Size = sizeof(BITMAPV5HEADER);
BIHA.bV5Width = cx;
BIHA.bV5Height = cy;
BIHA.bV5Planes = 1;
BIHA.bV5BitCount = 32;
BIHA.bV5SizeImage = w*h*4;
BIHA.bV5CSType = LCS_sRGB;
BIHA.bV5Compression = BI_BITFIELDS;
BIHA.bV5RedMask = 0x00FF0000;
BIHA.bV5GreenMask = 0x0000FF00;
BIHA.bV5BlueMask = 0x000000FF;
BIHA.bV5AlphaMask = 0xFF000000;
if(pdcDIB)
verify(DeleteDC(pdcDIB));
pdcDIB = CreateCompatibleDC(NULL);
assert(pdcDIB);
if(hbmpDIB)
verify(DeleteObject(hbmpDIB));
hbmpDIB = CreateDIBSection(
pdcDIB,
(BITMAPINFO*)&BIHA,
DIB_RGB_COLORS,
&bmp_cnt,
NULL,
0);
memset(bmp_cnt, 0x44, 4*w*h);
assert(hbmpDIB);
assert(bmp_cnt);
if(hbmpDIB)
SelectObject(pdcDIB, hbmpDIB);
}
BOOL CreateHGLRC()
{
DWORD dwFlags = PFD_DIRECT3D_ACCELERATED | PFD_DRAW_TO_BITMAP;
// dwFlags = PFD_DRAW_TO_BITMAP|PFD_GENERIC_ACCELERATED;
PIXELFORMATDESCRIPTOR pfd ;
memset(&pfd,0, sizeof(PIXELFORMATDESCRIPTOR)) ;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = dwFlags ;
pfd.iPixelType = PFD_TYPE_RGBA ;
pfd.cColorBits = 32 ;
pfd.cDepthBits = 24 ;
pfd.cStencilBits = 8;
pfd.cAlphaBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
int PixelFormat = ChoosePixelFormat(pdcDIB, &pfd);
if (PixelFormat == 0){
assert(0);
return FALSE ;
}
BOOL bResult = SetPixelFormat(pdcDIB, PixelFormat, &pfd);
if (bResult==FALSE){
assert(0);
return FALSE ;
}
m_hrc = wglCreateContext(pdcDIB);
if (!m_hrc){
assert(0);
return FALSE;
}
return TRUE;
}
BOOL CreateHDXRC(HWND hWnd)
{
D3DPRESENT_PARAMETERS d3dpp; // create a struct to hold various device information
ZeroMemory(&d3dpp, sizeof(d3dpp)); // clear out the struct for use
d3dpp.Windowed = TRUE; // program windowed, not fullscreen
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // discard old frames
d3dpp.hDeviceWindow = hWnd; // set the window to be used by Direct3D
// create a device class using this information and information from the d3dpp stuct
d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);
return TRUE;
}
LRESULT CALLBACK WindowFunc(HWND hWnd,UINT msg, WPARAM wParam, LPARAM lParam)
{
static int s_enter = 0;
PAINTSTRUCT ps;
int i;
char szDbg[MAX_PATH];
char szLastDbg[MAX_PATH];
DWORD dwTime;
static DWORD s_dwTime = 0;
static int s_nTime = 0;
static DWORD s_cumTime = 0;
switch(msg)
{
case WM_ERASEBKGND:
return 0;
break;
case WM_CREATE:
break;
case WM_DESTROY:
#ifndef USE_DIRECT_X
if(m_hrc)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(m_hrc) ;
}
#else
if (d3ddev)
d3ddev->Release(); // close and release the 3D device
if (d3d)
d3d->Release(); // close and release Direct3D
#endif
PostQuitMessage(0) ;
break;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
renderSC(); // OpenGL -> DIB
draw(hDC); // DIB -> hDC
EndPaint(hWnd, &ps);
break;
case WM_TIMER:
if (s_enter!=0) return FALSE;
if (s_dwTime==0) s_dwTime = timeGetTime();
++s_enter;
dwTime = timeGetTime();
//#ifndef USE_DIRECT_X
hDC = GetDC(hWnd);
// hDC = BeginPaint(hWnd, &ps);
renderSC(); // OpenGL -> DIB
draw(hDC); // DIB -> hDC
ReleaseDC(hWnd, hDC);
//#endif
--s_enter;
dwTime = timeGetTime() - dwTime;
s_cumTime+=dwTime;
++s_nTime;
// OutputDebugString(szLastDbg);
s_dwTime = timeGetTime();
// EndPaint(hWnd, &ps);
break;
case WM_SIZE:
w = LOWORD(lParam); h = HIWORD(lParam);
#ifndef USE_DIRECT_X
// --- initialize Open GL ---
wglMakeCurrent(NULL, NULL);
wglDeleteContext(m_hrc);
CreateDIB(w, h);
CreateHGLRC();
verify(wglMakeCurrent(pdcDIB, m_hrc));
initSC();
resizeSC(w, h);
renderSC();
#else
// --- initialize Direct X ---
d3d = Direct3DCreate9(D3D_SDK_VERSION); // create the Direct3D interface
CreateDIB(w, h);
CreateHDXRC(hWnd);
renderSC();
#endif
break;
case WM_KEYDOWN:
if (toupper(LOBYTE(wParam))=='A')
{
sprintf(szLastDbg, "Average: %d ms (cumul. time: %d ms, count: %d)
", s_cumTime/(s_nTime), s_cumTime, s_nTime);
MessageBox(NULL, szLastDbg, "Debug", MB_OK);
}
else if (toupper(LOBYTE(wParam))=='Q')
{
g_bTryFaster = !g_bTryFaster;
s_cumTime = 0;
s_nTime = 0;
}
else
{
g_bSwitchAlpha = !g_bSwitchAlpha;
s_cumTime = 0;
s_nTime = 0;
}
break;
default:
return DefWindowProc(hWnd,msg,wParam,lParam);
}
return 0;
}
int WINAPI _tWinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR str,int nWinMode)
{
WNDCLASSEX wc;
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WindowFunc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hThisInst;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW);
wc.lpszClassName = szAppName;
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, _T("RegisterClassEx - failed"), _T("Error"), MB_OK | MB_ICONERROR);
return FALSE;
}
HWND hWnd = CreateWindowEx(WS_EX_LAYERED, szAppName, wcWndName,
WS_VISIBLE | WS_POPUP, 200, 150, w, h,
NULL, NULL, hThisInst, NULL);
if(!hWnd){
MessageBox(NULL, _T("CreateWindowEx - failed"), _T("Error"), MB_OK | MB_ICONERROR);
return FALSE;
}
// verify(SetLayeredWindowAttributes(hWnd, 0x0, 255, LWA_ALPHA));
g_hWnd = hWnd;
MSG msg;
SetTimer(hWnd, 1, 25, NULL);
while(1)
{
while (PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)){
if (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else return 0;
}
}
return (FALSE);
}