Author Topic: AeroGL (rendering OpenGL on a layered window)  (Read 8524 times)

0 Members and 1 Guest are viewing this topic.

Offline Patrice Terrier

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2193
  • Gender: Male
    • www.zapsolution.com
AeroGL (rendering OpenGL on a layered window)
« on: October 02, 2008, 10:28:33 PM »
The AeroGL is a unique combination of different graphic technologies:
OpenGL + GDI + GDIPLUS + composited layered window.

This project is compatible with XP and VISTA, however you will get the best performance on Dual Core processor running VISTA Premium or higher.

Currently the CPU usage is 27% on VISTA with Dual Core 2 processor, for further CPU reduction you can reduce the size of the layered window and play with the OpenGL setup and the animation you are using.

If you have suggestions to reduce the CPU footprint, please post them here.

Note: This code is for your information, it is not public domain.
« Last Edit: August 10, 2011, 10:24:44 AM by Patrice Terrier »
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Offline Patrice Terrier

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2193
  • Gender: Male
    • www.zapsolution.com
Re: AeroGL (coding insight)
« Reply #1 on: October 03, 2008, 10:59:56 AM »
Here are some insights about the coding being used to display OpenGL on a layered window.

1 - Select the good Window Extended Style
%WS_EX_LAYERED OR %WS_EX_TOPMOST OR %WS_EX_TOOLWINDOW
Code: [Select]
     ' Window Extended Style
       dwExStyle = %WS_EX_LAYERED OR %WS_EX_TOPMOST OR %WS_EX_TOOLWINDOW
     ' Windows Style, avoid using %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN with the Skin Engine
       dwStyle = %WS_POPUP ' OR %WS_CLIPCHILDREN OR %WS_CLIPSIBLINGS
'
       CALL SetRect(rc, 0, 0, %FRAME_SizeX, %FRAME_SizeY)
'      // Note: indeed we don't need AdjustWindowRectEx, because we use do not use a non-client area
'      // but it won't hurt anything to keep it, in case we change our mind ;)
       CALL AdjustWindowRectEx(rc, dwStyle, %FALSE, dwExStyle)  ' Adjust Window To True Requested Size
'
       x = MAX&((GetSystemMetrics(%SM_CXSCREEN) - rc.nRight - rc.nLeft) \ 2, 0)
       y = MAX&((GetSystemMetrics(%SM_CYSCREEN) - rc.nBottom - rc.nTop) \ 2, 0)
'
     ' Create The Window
       MyTitle$ = "AeroGL"
       hMain = CreateWindowEx(dwExStyle, _            ' Extended Style For The Window
                              zClass, _               ' Class Name
                              (MyTitle$), _           ' Window Title
                              dwStyle, _              ' Defined Window Style
                              x, y, _                 ' Window Position
                              rc.nRight - rc.nLeft, _ ' Calculate Window Width
                              rc.nBottom - rc.nTop, _ ' Calculate Window Height
                              %NULL, _                ' No Parent Window
                              %NULL, _                ' No Menu
                              wc.hInstance, _         ' Instance
                              BYVAL %NULL)            ' Dont Pass Anything To WM_CREATE

2 - Create the main message pump with a timer for the purpose of animation
SetTimer(hMain, 1, 50, %NULL)
Code: [Select]
          CALL SetTimer(hMain, 1, 50, %NULL)
          WHILE GetMessage(Msg, %NULL, 0, 0)
                CALL TranslateMessage(Msg)
                CALL DispatchMessage(Msg)
          WEND
          CALL KillTimer(hMain, 1)

3 - Select the good pixel format to use with OpenGL
pfd.dwFlags    = %PFD_SUPPORT_OPENGL OR %PFD_DRAW_TO_BITMAP OR %PFD_SUPPORT_GDI
Code: [Select]
FUNCTION zSetupPixelFormat(BYVAL hDC AS LONG) AS LONG
    LOCAL pfd AS PIXELFORMATDESCRIPTOR
    LOCAL pixelformat AS LONG
    LOCAL lRet AS LONG

    lRet = %TRUE

    pfd.nSize      = SIZEOF(pfd)
    pfd.nVersion   = 1
    pfd.dwFlags    = %PFD_SUPPORT_OPENGL OR %PFD_DRAW_TO_BITMAP OR %PFD_SUPPORT_GDI
    pfd.iPixelType = %PFD_TYPE_RGBA

    pfd.cColorBits = 32
    pfd.cDepthBits = 32

    pixelformat = ChoosePixelFormat(hDC, pfd)

    IF pixelformat THEN
       IF SetPixelFormat(hDC, pixelformat, pfd) = 0 THEN lRet = %FALSE
    ELSE
       lRet = %FALSE
    END IF

    FUNCTION = lRet
END FUNCTION

4 - Create the OpenGL context INTO A 32-BIT MEMORY BITMAP
hGLBMP = zCreateDIBSection(DesktopDC, nWidth, nHeight, 32)
Code: [Select]
FUNCTION CreateGLcontext(BYVAL nWidth AS LONG, BYVAL nHeight AS LONG, BYREF hGLDC AS LONG, BYREF hGLRC AS LONG) AS LONG
    LOCAL nRet, DesktopDC, hGLBMP AS LONG
    IF nWidth > 0 AND nHeight > 0 THEN
       DesktopDC = GetDC(0)
       hGLDC = CreateCompatibleDC(DesktopDC)
       hGLBMP = zCreateDIBSection(DesktopDC, nWidth, nHeight, 32)
       CALL SelectObject(hGLDC, hGLBMP)
       CALL ReleaseDC(0, DesktopDC)
       IF hGLBMP THEN
          IF zSetupPixelFormat(hGLDC) THEN
            hGLRC = wglCreateContext(hGLDC)
            IF hGLRC THEN
               IF wglMakeCurrent(hGLDC, hGLRC) THEN
   
                  CALL glClearColor(0.0, 0.0, 0.0, 0.0)
                  CALL glClearDepth(1.0)
                  CALL glDepthFunc(%GL_LESS)
                  CALL glEnable(%GL_DEPTH_TEST)
                  CALL glShadeModel(%GL_SMOOTH)

                  CALL glMatrixMode(%GL_PROJECTION)

                  CALL glViewport(0, 0, nWidth, nHeight)
                 
                  CALL glEnable(%GL_TEXTURE_2D)

                  nRet = -1
                 
               END IF
            END IF
          END IF
       END IF
    END IF
    FUNCTION = nRet
END FUNCTION

5 - The rendering section.
'   // Draw the OpenGL scene
    CALL DrawTheScene()
    CALL DrawAndSetupAlphaChannel(hMemDC, 60, 109)

Code: [Select]
SUB SetImage(BYVAL hWnd AS LONG)
    LOCAL DesktopDC, hMemDC, hBmp LONG
    LOCAL rw AS RECT
    LOCAL bf AS BLENDFUNCTION
    LOCAL lp, ptSrc AS POINTAPI
    LOCAL lpSize AS SIZEL
     
    CALL GetWindowRect(hWnd, rw)
    lpSize.Cx = rw.nRight - rw.nLeft: lpSize.Cy = rw.nBottom - rw.nTop
    lp.X = rw.nLeft: lp.Y = rw.nTop

    DesktopDC = GetDC(0)
   
    '// Draw active frame to new memory DC
    hMemDC = CreateCompatibleDC(DesktopDC)
    hBmp = zCreateDIBSection(DesktopDC, lpSize.Cx, lpSize.CY, 32)
    CALL SelectObject(hMemDC, hBmp)

'   // Draw the OpenGL scene
    CALL DrawTheScene()
    CALL DrawAndSetupAlphaChannel(hMemDC, 60, 109)
   
    bf.BlendOp             = %AC_SRC_OVER
    bf.BlendFlags          = 0
    bf.AlphaFormat         = %AC_SRC_ALPHA '// Use source alpha
    bf.SourceConstantAlpha = 255 '//alpha
 
    CALL UpdateLayeredWindow (hWnd, DesktopDC, lp, lpSize, hMemDC, ptSrc, 0, bf, %ULW_ALPHA)
   
    CALL DeleteObject(hBmp)
    CALL DeleteDC(hMemDC)
    CALL ReleaseDC(0, DesktopDC)
END SUB
The very important DrawAndSetupAlphaChannel
I am using a personnal trick there, for the alpha channel compatibility between OpenGL and GDI:
Code: [Select]
SUB DrawAndSetupAlphaChannel(BYVAL hMemDC AS LONG, BYVAL x AS LONG, BYVAL y AS LONG)
'   // We must do this to be compatible with BitBlt
'   // We compute a fake alpha channel based on color convertion to shade of gray
    LOCAL pBits AS BYTE PTR, bm AS BITMAP, P AS LONG
    CALL GetObject(GetCurrentObject(hGLDC, 7), SIZEOF(bm), bm)
    pBits = bm.bmBits
    FOR P = (bm.bmWidth * bm.bmHeight) TO 1 STEP - 1
        Alpha& = Rgb2Gray(RGB(@pBits[2],@pBits[1],@pBits[0])) AND &H000000FF???
        @pBits[3] = MIN&(Alpha& * 255, 255)
        pBits = pBits + 4
    NEXT
    CALL BitBlt(hMemDC, x, y, bm.bmWidth, bm.bmHeight, hGLDC, 0, 0, %SRCCOPY)
END SUB

Next step, i shall use a permanent buffer to reduce the CPU footprint.
:)

...
« Last Edit: October 03, 2008, 11:04:03 AM by Patrice Terrier »
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Offline Petr Schreiber

  • Sr. Member
  • ****
  • Posts: 412
Re: AeroGL (rendering OpenGL on a layered window)
« Reply #2 on: October 03, 2008, 11:43:24 AM »
Hi Patrice,

very impressive, I thought you left this idea but you just finished it :o
Runs good. Only problem is it is not smooth ( maybe just on my PC - GeForce 6150LE ) even with timer set to 1ms, but that is probably related to your notice on reducing CPU footprint.


Thanks,
Petr
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

Offline Patrice Terrier

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2193
  • Gender: Male
    • www.zapsolution.com
Re: AeroGL (The BareBone)
« Reply #3 on: October 03, 2008, 02:47:55 PM »
This is a BareBone version of the AeroGL, to let you check what is going on.

This version uses 0% CPU on my Dual Core 2 runnning VISTA Premium with NVIDIA GeForce Go 7600

It seems that the Windows Layered API is very CPU intensive, this is the reason why most of the layered window (Destop icons for example, or drag and drop) are using only small size.

Anyway to make your own test, in the source code, play with these parameters:
%FRAME_SizeX = 200 '// The animation frame width
%FRAME_SizeY = 200 '// The animation frame height
%TIMER_DELAY = 50  '// The timer delay (animation speed)

Also notice the changes i have done to the SetImage subroutine to focus only on the OpenGL drawing

Code: [Select]
SUB SetImage(BYVAL hWnd AS LONG)
    LOCAL graphics, DesktopDC, Img, imgW, imgH, ImgAttr, x, y AS LONG
    LOCAL rw AS RECT
    LOCAL bf AS BLENDFUNCTION
    LOCAL lp, ptSrc AS POINTAPI
    LOCAL lpSize AS SIZEL
   
    STATIC xMove3, FlipMove3 AS LONG   
   
    CALL GetWindowRect(hWnd, rw)
    lpSize.Cx = rw.nRight - rw.nLeft: lpSize.Cy = rw.nBottom - rw.nTop
    lp.X = rw.nLeft: lp.Y = rw.nTop

    DesktopDC = GetDC(0)
   
    '// Draw active frame to new memory DC
    IF ghBmp = 0 THEN
       ghMemDC = CreateCompatibleDC(DesktopDC)
       ghBmp = zCreateDIBSection(DesktopDC, lpSize.Cx, lpSize.CY, 32)
       CALL SelectObject(ghMemDC, ghBmp)
    END IF
   
'   // Draw the OpenGL scene
    CALL DrawTheScene()
    CALL wglMakeCurrent(hGLDC, hGLRC)
    CALL wglSwapBuffers(hGLDC)
    CALL DrawAndSetupAlphaChannel(ghMemDC, 0, 0)

'   // Update the layered window   
    bf.BlendOp             = %AC_SRC_OVER
    bf.BlendFlags          = 0
    bf.AlphaFormat         = %AC_SRC_ALPHA '// Use source alpha
    bf.SourceConstantAlpha = 255 '//alpha
    CALL UpdateLayeredWindow (hWnd, DesktopDC, lp, lpSize, ghMemDC, ptSrc, 0, bf, %ULW_ALPHA)

    CALL ReleaseDC(0, DesktopDC)
END SUB

Note: This version uses alphablending and culing mode.

Added:
Possible enhancement to play with opacity

SUB DrawAndSetupAlphaChannel(BYVAL hMemDC AS LONG, BYVAL x AS LONG, BYVAL y AS LONG)
'   // We must do this to be compatible with BitBlt
'   // We compute a fake alpha channel based on color conversion to shade of gray
    LOCAL pBits AS BYTE PTR, bm AS BITMAP, P AS LONG
    CALL GetObject(GetCurrentObject(hGLDC, 7), SIZEOF(bm), bm)
    pBits = bm.bmBits
    FOR P = (bm.bmWidth * bm.bmHeight) TO 1 STEP - 1
        Alpha& = Rgb2Gray(RGB(@pBits[2],@pBits[1],@pBits[0])) AND &H000000FF???

        '@pBits[3] = MIN&(Alpha& * 255, 255)
        IF Alpha& = 0 THEN
           @pBits[3] = 0
        ELSE

           @pBits[3] = 200
        END IF
        pBits = pBits + 4
    NEXT
    CALL BitBlt(hMemDC, x, y, bm.bmWidth, bm.bmHeight, hGLDC, 0, 0, %SRCCOPY)
END SUB

...

« Last Edit: August 10, 2011, 10:41:22 AM by Patrice Terrier »
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Offline Patrice Terrier

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2193
  • Gender: Male
    • www.zapsolution.com
Re: AeroGL (rendering OpenGL on a layered window)
« Reply #4 on: October 03, 2008, 07:10:14 PM »
Petr

Quote
I thought you left this idea but you just finished it
It was on my back burner  :)

By the way i think to another solution (the same i have used in "XP AERO Glass") to create my own layered GL window to save CPU resource and use larger frame...

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Offline Eros Olmi

  • Sr. Member
  • ****
  • Posts: 360
  • Gender: Male
    • thinBasic
Re: AeroGL (rendering OpenGL on a layered window)
« Reply #5 on: October 03, 2008, 07:17:21 PM »
Here it works smoothly.
About 2% to 6% CPU usage
thinBasic Script Interpreter - www.thinbasic.com | www.thinbasic.com/community
Win7Pro 64bit - 8GB Ram - Intel i7 M620 2.67GHz - NVIDIA Quadro FX1800M 1GB

Offline Patrice Terrier

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2193
  • Gender: Male
    • www.zapsolution.com
Re: AeroGL (rendering OpenGL on a layered window)
« Reply #6 on: August 10, 2011, 10:43:05 AM »
The first post of this thread has been updated, to fix the ZIP file corruption caused by the "Server Collapse".

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Offline Jürgen Huhn

  • Full Member
  • ***
  • Posts: 105
  • Gender: Male
Re: AeroGL (rendering OpenGL on a layered window)
« Reply #7 on: July 12, 2012, 11:50:42 AM »
I`ve modyfied your BareBone Code and made most changes in your SetImage SUBFunction.
Work`s fine on my ICore7.. Full source Code is in the .zip.

SUB SetImage(BYVAL hWnd AS LONG)
    LOCAL x, y, DIS_IC, ImgAttr AS LONG
    LOCAL rw AS RECT
    LOCAL bf AS BLENDFUNCTION
    LOCAL lp, ptSrc AS POINTAPI
    LOCAL lpSize AS SIZEL

    CALL GetWindowRect(hWnd, rw)
    lpSize.Cx = rw.nRight - rw.nLeft: lpSize.Cy = rw.nBottom - rw.nTop
    lp.X = rw.nLeft: lp.Y = rw.nTop

'   // Draw the OpenGL scene
    CALL DrawTheScene()
    CALL wglMakeCurrent(hGLDC, hGLRC)
'    CALL wglSwapBuffers(hGLDC)                                                     
    CALL SetupAlphaChannel(hGLDC)
'   // Update the layered window
    bf.BlendOp             = %AC_SRC_OVER
    bf.BlendFlags          = 0
    bf.AlphaFormat         = %AC_SRC_ALPHA       '// Use source alpha
    bf.SourceConstantAlpha = JH_AlphaLevel(0,0) '// Setup the alpha level

    DIS_IC = CreateIC("DISPLAY", BYVAL 0, BYVAL 0, BYVAL 0)
    CALL UpdateLayeredWindow (hWnd, DIS_IC, lp, lpSize, hGLDC, ptSrc, 0, bf, &H00000002) '
    CALL DeleteDC(DIS_IC)
    CALL glFlush()
END SUB
« Last Edit: July 12, 2012, 11:54:59 AM by Jürgen Huhn »
.¸.•’´¯)¸.•’´¯)¸.•’´¯)¸.•’´¯)
¤ª“˜¨¨¯¯¨¨˜“ª¤....¤ ª“˜¨