Announcement

Collapse
No announcement yet.

3D chart

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • 3D chart

    This project, is the exact 32-bit PowerBASIC transcription of a 64-bit project i wrote in C++.

    It is using the José Roca's include files and PB 10.04.

    This is a pure SDK coding style application.
    Using the OpenGL extensions and the 3D primitives that are exposed into the GDImage 6.56 and 7.00 API.
    The whole window is using the Onyx WinLIFT skin theme, altogether with a GDImage spinner animation control provided with several animations.

    Source code:
    Code:
    '+--------------------------------------------------------------------------+
    '|                               SkinChart                                  |
    '|                                                                          |
    '|     Example using the OpenGL 3D chart primitives built into GDImage.     |
    '|                                                                          |
    '+--------------------------------------------------------------------------+
    '|                                                                          |
    '|                         Author Patrice TERRIER                           |
    '|                                                                          |
    '|                           copyright (c) 2013                             |
    '|                                                                          |
    '|                           www.zapsolution.com                            |
    '|                        [email protected]                          |
    '|                                                                          |
    '+--------------------------------------------------------------------------+
    '|                  Project started on : 11-01-2013 (MM-DD-YYYY)            |
    '|                        Last revised : 12-17-2014 (MM-DD-YYYY)            |
    '+--------------------------------------------------------------------------+
    #COMPILE EXE "SkinChart.exe"
    #INCLUDE     "Windows.inc"
    #INCLUDE     "GL.inc"
    #RESOURCE MANIFEST, 1, "SkinChart.xml"
    #RESOURCE ICON, 2, "SkinChart.ico"
    
    #INCLUDE "WINLIFT.INC"
    #INCLUDE "gdimage.inc"
    
    %GL_MULTISAMPLE_ARB = &H809D???
    declare function PathCombine lib "SHLWAPI.DLL" alias "PathCombineA" (byref lpszDest as asciiz, byref lpszDir as asciiz, byref lpszFile as asciiz) as long
    declare function zTrace lib "zTrace.DLL" alias "zTrace" (zMessage as asciiz) as long
    
    type ZCHART
        chartnumber as long
        chartseries as long
        radius      as single
        listIndex   as long
    end type
    
    %ClientW         = 1000
    %ClientH         = 560
    
    %IDC_GDIMAGE     = 101
    %IDC_RESET       = 102
    %IDC_LISTBOX     = 103
    %IDC_STATIC      = 112
    %IDC_SPINNER     = 104
    %IDC_TIMER       = 106
    %IDC_LISTSPINNER = 107
    
    %ID_SPIN01       = 1
    %TIMER_DELAY     = 33
    
    type PROP
         GLwnd         as dword
         SpinnerList   as dword
    
         MinTrackSizeW as long
         MinTrackSizeH as long
    
         ChartCaption  as long
         ChartLegend   as long
         ChartSymbol   as long
         TexSpecular   as long
         TexChrome     as long
         TexBoing      as long
         TexBubble     as long
         rPercent      as single
         nAngle        as long
         nFlip         as long
         UseFont       as ZGLFONT
    
         SpinnerDelay  as dword
    
         R(1 TO 33)    as byte
         G(1 TO 33)    as byte
         B(1 TO 33)    as byte
         A(1 TO 33)    as byte
    end type
    
    global g_Chart as ZCHART
    global g_Graph() as ZCHART_PARAM
    global gP as PROP, g_mt() as ZGLTEXTUREX
    
    function EXEpath() as string
        static zPath as asciiz * %MAX_PATH
        if (len(zPath) = 0) then
            if (GetModuleFileName(byval %NULL, zPath, sizeof(zPath))) then
                local pBits as byte ptr
                local K, nLen as long 
                nLen = len(zPath)
                pBits = varptr(zPath) + nLen
                for K = 1 to nLen
                    if (@pBits[-K] <> 92) then 
                        @pBits[-K] = 0
                    else 
                        exit for
                    end if
                next
            end if
        end if
        function = zPath
    end function
    
    function EXEresource() as string
        static szResource as asciiz * %MAX_PATH
        if (len(szResource) = 0) then PathCombine(szResource, EXEpath(), "resource\")
        function = szResource
    end function
    
    sub List_DeleteAll(byval hList as dword)
        if (IsWindow(hList)) then SendMessage(hList, %LB_RESETCONTENT, 0, 0)
    end sub
    
    sub List_SelectPlus(byval hList as dword, byval nSelected as long)
        if (nSelected > 0) then decr nSelected '// Because ListBox is zero based
        if (IsWindow(hList)) then SendMessage(hList, %LB_SETCURSEL, nSelected, 0)
    end sub
    
    function List_Add(byval hList as dword, zTmp as asciiz) as long
        if (IsWindow(hList)) then
            if (len(zTmp)) then function = SendMessage(hList, %LB_ADDSTRING, 0, varptr(zTmp))
        end if
    end function
    
    function List_GetCount(byval hList as dword) as long
        local nRet as long
        if (IsWindow(hList)) then nRet = SendMessage(hList, %LB_GETCOUNT, 0, 0)
        function = nRet
    end function
    
    function List_GetCursel(byval hList as dword) as long
        local nSelected as long
        if (IsWindow(hList)) then
            nSelected = SendMessage(hList, %LB_GETCURSEL, 0, 0)
            if (nSelected > -1) then incr nSelected '// Because ListBox is zero based
        end if
        function = nSelected
    end function
    
    function List_GetText(byval hList as dword, byval nItem as long) as STRING
        local sItem as STRING, nLen as long
        if (nItem > 0) then
            decr nItem
            nLen = SendMessage(hList, %LB_GETTEXTLEN, nItem, 0)
            sItem = space$(nLen)
            SendMessage(hList, %LB_GETTEXT, nItem, byval STRPTR(sItem))
            function = sItem
        end if
    end function
    
    function DefaultFont() as dword
        static hDefault as long
        if (hDefault = 0) then hDefault = GetStockObject(%DEFAULT_GUI_FONT)
        function = hDefault
    end function
    
    sub SetCTLFont(byval hCtrl as dword, byval hFont as dword)
        SendMessage(hCtrl, %WM_SETFONT, hFont, 0)
    end sub
    
    function StaticCenter(byval sLabel as string, byval x as long, byval y as long, byval w as long, byval h as long, byval hParent as long, byval ID as long) as long
        local hCtl as long
        hCtl = CreateWindowEx(0, "static", (sLabel), %WS_CHILD or %WS_VISIBLE or %WS_BORDER or %SS_CENTER, _
                              x, y, w, h, hParent, ID, zInstance(), byval %NULL)
        if (hCtl) then SetCTLFont(hCtl, DefaultFont())
        function = hCtl
    end function
    
    sub gl_LoadTexture(byval hList as dword)
        if (IsWindow(hList)) then
            local nCount as long
            local fd as WIN32_FIND_DATA
        
            List_DeleteAll(hList)
    
            nCount = 0
            local hFind as dword
            hFind = FindFirstFile(EXEresource() + "Spec*.jpg*", fd)
            if (hFind <> %INVALID_HANDLE_VALUE) then
                local IsOk as long
                IsOk = -1
                while (IsOk)
                    if (NOT (fd.dwFileAttributes and %FILE_ATTRIBUTE_DIRECTORY)) then
                        if (List_Add(hList, fd.cFileName) > -1) then nCount += 1
                    end if
                    if (FindNextFile(hFind, fd) = 0) then IsOk = 0
                wend
                FindClose(hFind)
            end if
            if (nCount > 0) then List_SelectPlus(hList, 1)
        end if
    end sub
    
    function LoadSpinner(byval hMain as dword) as long
        local nCount as long
        gP.SpinnerList = CreateWindowEx(0, "ListBox", "", %WS_CHILD or %LBS_SORT, 0, 0, 0, 0, hMain, %IDC_LISTSPINNER, zInstance(), byval %NULL)
        if (IsWindow(gP.SpinnerList)) then
            local fd as WIN32_FIND_DATA
            local zTmp as asciiz * %MAX_PATH
            PathCombine(zTmp, EXEresource(), "*.ski")
            local nUseSpinner as long
    
            List_DeleteAll(gP.SpinnerList)
    
            local hFind as dword
            hFind = FindFirstFile(zTmp, fd)
            if (hFind <> %INVALID_HANDLE_VALUE) then
                local IsOk as long
                IsOk = -1
                while (IsOk)
                    if (NOT (fd.dwFileAttributes and %FILE_ATTRIBUTE_DIRECTORY)) then
                        if (List_Add(gP.SpinnerList, fd.cFileName) > -1) then
                            nCount += 1
                            if (lcase$(fd.cFileName) = "bawl.ski") then nUseSpinner = nCount
                        end if
                    end if
                    if (FindNextFile(hFind, fd) = 0) then IsOk = 0
                wend
                FindClose(hFind)
            end if
            if (nUseSpinner = 0) then nUseSpinner = 1
            List_SelectPlus(gP.SpinnerList, nUseSpinner)
        end if
        function = nCount
    end function
    
    sub gl_InitGraph()
        local rChartXoff, rChartYoff, rChartZoff, rChartZoom, rChartXrot, rChartYrot as single
        local nChartMax, nChartMin as long
        local nChartSeries, nChartNumber as long
       
        nChartSeries = 7
        nChartNumber = 7  
    
        '// The ChartSeries and ChartNumber maximum are 12 each.
        g_Chart.chartseries = min&(nChartSeries,13)
        g_Chart.chartnumber = min&(nChartNumber,13)
        g_Chart.radius = 1.0
    
        dim tabZ(1 TO 13) as single: ARRAY ASSIGN tabZ() = -24,-26,-28,-30,-34,-38,-42,-47,-50,-53,-57,-60,-62
        dim tabY(1 TO 13) as single: ARRAY ASSIGN tabY() = -3,-2.2,-0.5,0.6,1.5,2.5,3.5,4,5,6.5,7,8.3,9.5
        nChartMax = max&(g_Chart.chartseries,g_Chart.chartnumber)
        nChartMin = min&(g_Chart.chartseries,g_Chart.chartnumber)
    
        rChartXoff = (- g_Chart.chartseries + g_Chart.chartnumber) * 0.8333
        rChartYoff = tabY(nChartMin)
        rChartZoff = tabZ(nChartMax)
        rChartZoom = 1.0
        
        rChartXrot = 45.0
        rChartYrot = -25.0
    
        GL_ChartSetMousing(rChartXoff, rChartYoff, rChartZoff, rChartZoom, rChartXrot, rChartYrot)
        gP.rPercent = 0
    end sub
    
    sub gl_ColorInit()
        gP.R(33) = 032: gP.G(33) = 032: gP.B(33) = 032: gP.A(33) = 255
        gP.R(32) = 000: gP.G(32) = 044: gP.B(32) = 233: gP.A(32) = 255
        gP.R(31) = 000: gP.G(31) = 067: gP.B(31) = 210: gP.A(31) = 255
        gP.R(30) = 000: gP.G(30) = 089: gP.B(30) = 187: gP.A(30) = 255
        gP.R(29) = 000: gP.G(29) = 112: gP.B(29) = 164: gP.A(29) = 255
        gP.R(28) = 000: gP.G(28) = 135: gP.B(28) = 142: gP.A(28) = 255
        gP.R(27) = 000: gP.G(27) = 159: gP.B(27) = 117: gP.A(27) = 255
        gP.R(26) = 000: gP.G(26) = 183: gP.B(26) = 088: gP.A(26) = 255
        gP.R(25) = 000: gP.G(25) = 207: gP.B(25) = 058: gP.A(25) = 255
        gP.R(24) = 000: gP.G(24) = 231: gP.B(24) = 029: gP.A(24) = 255
        gP.R(23) = 026: gP.G(23) = 234: gP.B(23) = 026: gP.A(23) = 255
        gP.R(22) = 052: gP.G(22) = 237: gP.B(22) = 023: gP.A(22) = 255
        gP.R(21) = 079: gP.G(21) = 240: gP.B(21) = 020: gP.A(21) = 255
        gP.R(20) = 105: gP.G(20) = 243: gP.B(20) = 017: gP.A(20) = 255
        gP.R(19) = 126: gP.G(19) = 245: gP.B(19) = 014: gP.A(19) = 255
        gP.R(18) = 147: gP.G(18) = 248: gP.B(18) = 011: gP.A(18) = 255
        gP.R(17) = 168: gP.G(17) = 250: gP.B(17) = 008: gP.A(17) = 255
        gP.R(16) = 189: gP.G(16) = 253: gP.B(16) = 005: gP.A(16) = 255
        gP.R(15) = 210: gP.G(15) = 255: gP.B(15) = 002: gP.A(15) = 255
        gP.R(14) = 233: gP.G(14) = 255: gP.B(14) = 000: gP.A(14) = 255
        gP.R(13) = 255: gP.G(13) = 255: gP.B(13) = 000: gP.A(13) = 255
        gP.R(12) = 255: gP.G(12) = 251: gP.B(12) = 000: gP.A(12) = 255
        gP.R(11) = 255: gP.G(11) = 235: gP.B(11) = 000: gP.A(11) = 255
        gP.R(10) = 255: gP.G(10) = 215: gP.B(10) = 000: gP.A(10) = 255
        gP.R(09) = 255: gP.G(09) = 196: gP.B(09) = 000: gP.A(09) = 255
        gP.R(08) = 255: gP.G(08) = 176: gP.B(08) = 000: gP.A(08) = 255
        gP.R(07) = 255: gP.G(07) = 156: gP.B(07) = 000: gP.A(07) = 255
        gP.R(06) = 253: gP.G(06) = 137: gP.B(06) = 000: gP.A(06) = 255
        gP.R(05) = 255: gP.G(05) = 117: gP.B(05) = 000: gP.A(05) = 255
        gP.R(04) = 255: gP.G(04) = 097: gP.B(04) = 000: gP.A(04) = 255
        gP.R(03) = 255: gP.G(03) = 078: gP.B(03) = 000: gP.A(03) = 255
        gP.R(02) = 255: gP.G(02) = 058: gP.B(02) = 000: gP.A(02) = 255
        gP.R(01) = 255: gP.G(01) = 000: gP.B(01) = 000: gP.A(01) = 255
    end sub
    
    sub gl_Initialize()
    
        Randomize(Timer)
    
        glClearColor(0.5, 0.5, 0.5, 1) '// Grayed background, same as RGB(128,128,128)
        glClearDepth(1)
        glDepthFunc(%GL_LESS)
        glEnable(%GL_DEPTH_TEST)
    
        glHint(%GL_PERSPECTIVE_CORRECTION_HINT, %GL_FASTEST)'%GL_NICEST)
    
        glBlendFunc(%GL_SRC_ALPHA, %GL_ONE_MINUS_SRC_ALPHA)
        glEnable(%GL_BLEND)
        glEnable(%GL_LINE_SMOOTH)
    	  glShadeModel(%GL_SMOOTH)
    
        '// Ambience setting.
        dim LightDiffuse(3) as single:  ARRAY ASSIGN LightDiffuse()  = 0.4, 0.4, 0.4, 1.0
        dim LightAmbient(3) as single:  ARRAY ASSIGN LightAmbient()  = 0.5, 0.5, 0.5, 1.0
        dim LightPosition(3) as single: ARRAY ASSIGN LightPosition() = -100.0,-100.0, 400.0, 1.0
        glLightfv(%GL_LIGHT0, %GL_DIFFUSE, LightDiffuse(0))     '// Setup the Diffuse Light
        glLightfv(%GL_LIGHT0, %GL_AMBIENT, LightAmbient(0))     '// Setup the Ambient Light
        glLightfv(%GL_LIGHT0, %GL_POSITION, LightPosition(0))   '// Position the Light
        glMaterialfv(%GL_FRONT, %GL_SPECULAR, LightDiffuse(0))
        glMaterialfv(%GL_FRONT, %GL_SHININESS, 1)
        glEnable(%GL_LIGHT0)                                    '// Enable Light ONE
        glEnable(%GL_LIGHTING)                                  '// Enable Lighting
        glEnable(%GL_COLOR_MATERIAL)                            '// Enable Coloring Of Material
        glColorMaterial(%GL_FRONT, %GL_AMBIENT_AND_DIFFUSE)
    
        glEnable(%GL_TEXTURE_2D)
    
        local nK, nI, nJ, nC, nT as long
    
        gl_InitGraph()
    
        g_Chart.listIndex = 1
        glGenLists(1)
                  
        '// Draw the XYZ axis grid.   
        glNewList(g_Chart.listIndex, %GL_COMPILE)
           glColor4ub(255, 255, 255, 64)
           GL_ChartAxis(g_Chart.chartseries * (g_Chart.radius * 2.1) + g_Chart.radius, 10, g_Chart.chartnumber * (g_Chart.radius * 2.1) + g_Chart.radius)
        glEndList()
    
        dim g_Graph(1 TO g_Chart.chartnumber * g_Chart.chartseries) as ZCHART_PARAM
    
        gl_ColorInit()
    
        '// Draw g_Chart series.
        nK = 0
        nC = 0
        for nI = 1 TO g_Chart.chartnumber
    
            '// Setup color indice
            nC = (nC + 3) MOD 32 + 1
    
            for nJ = 1 TO g_Chart.chartseries
    
                nK += 1
                g_Graph(nK).nList = g_Chart.ListIndex + nK
                g_Graph(nK).nColor = nC
    
                g_Graph(nK).rValue = rnd(1,8)
    
                glNewList(g_Graph(nK).nList, %GL_COMPILE)
                
                   nT = nI: if (nT > %CHART_MAX) then nT = nI MOD %CHART_MAX
                   select case long (nT)
                   case %CHART_BAR
                        g_Graph(nK).nType = nT
                        g_Graph(nK).nTexture = gP.TexChrome
                        g_Graph(nK).nTexSpec = %TRUE
                        GL_ChartBar(g_Chart.radius * 0.75, g_Chart.radius * 0.75, g_Graph(nK).rValue)
                   case %CHART_CYLINDER
                        g_Graph(nK).nType = nT
                        g_Graph(nK).nTexture = gP.TexChrome
                        g_Graph(nK).nTexSpec = %TRUE
                        GL_ChartCylinder(g_Chart.radius * 0.75, g_Graph(nK).rValue, 32, 1)
                   case %CHART_PYRAMIDE
                        g_Graph(nK).nType = nT
                        g_Graph(nK).nTexture = gP.TexChrome
                        g_Graph(nK).nTexSpec = %TRUE
                        GL_ChartPyramide (g_Chart.radius * 0.75, g_Graph(nK).rValue)
                   case %CHART_SPHERE
                        g_Graph(nK).nType = nT
                        g_Graph(nK).nTexture = gP.TexBoing
                        g_Graph(nK).nTexSpec = %FALSE
                        GL_ChartSphere(g_Chart.radius * 0.75, g_Graph(nK).rValue, %FALSE)
                   case %CHART_CONE                                                  
                        g_Graph(nK).nType = nT                                             
                        g_Graph(nK).nTexture = gP.TexChrome                                
                        g_Graph(nK).nTexSpec = %TRUE                                       
                        GL_ChartCone(g_Chart.radius * 0.75, g_Graph(nK).rValue, 32, 1)
                   case %CHART_POINT
                        g_Graph(nK).nType = nT
                        g_Graph(nK).nTexture = gP.TexBubble
                        g_Graph(nK).nTexSpec = %FALSE
                        '// ChartPoint is 2D surface, thus because of billboarding
                        '// we couldn't compile it with the other 3D objects.                   
                        'GL_ChartPoint(g_Chart.radius * 0.75, g_Graph(nK).rValue)
                   end select
    
                glEndList()
    
            next
        next
    
    end sub
    
    sub gl_DestroyTexture()
        local K, mtCount, OkDelete as long
        mtCount = UBOUND(g_mt()) - LBOUND(g_mt()) + 1
        if (mtCount) then
            dim Texture(mtCount - 1) as long
            for K = 0 TO mtCount - 1
                Texture(K) = g_mt(k).Texture: if (Texture(K)) then OkDelete = -1
            next
            if (OkDelete) then glDeleteTextures(mtCount, Texture(0))
        end if
    end sub
    
    sub gl_DisableAmbience()
        glDisable(%GL_LIGHT0)        '// Disable Light ONE
        glDisable(%GL_LIGHTING)      '// Disable Lighting
        glDisable(%GL_COLOR_MATERIAL)'// Disable Coloring of Material
    end sub
    
    sub gl_EnableAmbience()
        glEnable(%GL_LIGHT0)         '// Enable Light ONE
        glEnable(%GL_LIGHTING)       '// Enable Lighting
        glEnable(%GL_COLOR_MATERIAL) '// Enable Coloring of Material
    end sub
    
    sub AnimateSpinner ()
        local AniCount as dword
        AniCount = GetTickCount()
        if (gP.SpinnerDelay = 0) then gP.SpinnerDelay = AniCount + %TIMER_DELAY
        if (AniCount > gP.SpinnerDelay) then
            gP.SpinnerDelay = 0
            local nFrame as long
            nFrame = ZD_GetObjectFrameToUse(%ID_SPIN01) + 1
            if (nFrame > ZD_GetObjectFrameCount(%ID_SPIN01)) then nFrame = 1
            ZD_SetObjectFrameToUse(%ID_SPIN01, nFrame, %TRUE)
        end if
    end sub
    
    '// This is the place where to customize the charting graph.
    sub gl_DrawScene()
        AnimateSpinner()
    
        local nK, nI, nJ, nC as long, rX, rY, rZ, rHalfRadius as single
        local rChartXoff, rChartYoff, rChartZoff, rChartZoom, rChartXrot, rChartYrot as single
        local zTitle as asciiz * 64
        
        gP.nAngle +=1: gP.nAngle = gP.nAngle MOD 360
        if (gP.rPercent < 1) then gP.rPercent += 0.002
    
        gP.nFlip = NOT gP.nFlip: if (gP.nFlip) then exit sub
    
        '// Turn on antialiasing
        if (GL_MultiSampleARB()) then glEnable(%GL_MULTISAMPLE_ARB)
    
        glClear(%GL_COLOR_BUFFER_BIT or %GL_DEPTH_BUFFER_BIT)
    
        glLoadIdentity()
    
        '// Draw image background
        gl_DisableAmbience()
           glColor4ub(255,255,255,255)
           GL_BindTexture(%GL_TEXTURE_2D, gP.TexSpecular)
           GL_DrawQuad(84, 42,-99.99)
        gl_EnableAmbience()
    
        '// Get Mousing coordinates, zooming, rotation.
        GL_ChartGetMousing(rChartXoff, rChartYoff, rChartZoff, rChartZoom, rChartXrot, rChartYrot)
        glTranslatef(rChartXoff, rChartYoff, rChartZoff)
    
        '// Zooming factor.
        glScalef(rChartZoom, rChartZoom, rChartZoom)
        '// Mousing rotation
        glRotatef(-rChartYrot, 1, 0, 0)
        glRotatef(-rChartXrot, 0, 1, 0)
    
        '// Retrieve current WGL font
        local zTxt as asciiz * 16
    
        '// Draw the chart
        glPushMatrix()
    
           '// Use chrome texture to draw the chart graph.
           GL_BindTexture(%GL_TEXTURE_2D, gP.TexChrome)
           rHalfRadius = g_Chart.radius * 0.5
           glTranslatef(g_Chart.radius + rHalfRadius, 0.0, g_Chart.radius + rHalfRadius)
           nK = 0
           for nI = 1 TO g_Chart.chartnumber
    
               '// Set color for the chart serie
               'ZI_glColor4f(g_Graph(nI).nColor)
               for nJ = 1  TO g_Chart.chartseries
                   nK += 1
                   nC = g_Graph(nK).nColor
                   glColor4ub(gP.R(nC), gP.G(nC), gP.B(nC), gP.A(nC))
                   GL_BindTexture(%GL_TEXTURE_2D, g_Graph(nK).nTexture)
                   GL_TexSpec(g_Graph(nK).nTexSpec)
    
                   '// Draw the matching chart item
                   if (gP.rPercent < 1) then
    
                       select case long (g_Graph(nK).nType)
                       case %CHART_BAR
                            GL_ChartBar(g_Chart.radius * 0.75, g_Chart.radius * 0.75, g_Graph(nK).rValue * gP.rPercent)
                       case %CHART_CYLINDER
                            GL_ChartCylinder(g_Chart.radius * 0.75, g_Graph(nK).rValue * gP.rPercent, 32, 1)
                       case %CHART_PYRAMIDE
                            GL_ChartPyramide(g_Chart.radius * 0.75, g_Graph(nK).rValue * gP.rPercent)
                       case %CHART_SPHERE
                            GL_ChartSphere(g_Chart.radius * 0.75, g_Graph(nK).rValue * gP.rPercent, %FALSE)
                       case %CHART_CONE
                            GL_ChartCone(g_Chart.radius * 0.75, g_Graph(nK).rValue * gP.rPercent, 32, 1)
                       case %CHART_POINT
                            GL_ChartPoint(g_Chart.radius * 0.75, g_Graph(nK).rValue * gP.rPercent)
                       end select
    
                   else
                      if (g_Graph(nK).nType = %CHART_POINT) then
                          GL_ChartPoint(g_Chart.radius * 0.75, g_Graph(nK).rValue)
                      else
                          glCallList(g_Graph(nK).nList)
                      end if 
                   end if
    
                   GL_TexSpec(%FALSE)
                   glTranslatef(2.1 * g_Chart.radius, 0.0, 0.0)
    
               next
               glTranslatef((-2.1 * g_Chart.radius) * g_Chart.chartseries, 0.0, 2.1 * g_Chart.radius)
    
           next
    
        glPopMatrix()
    
    
        '// Restore the default background texture.
        GL_BindTexture(%GL_TEXTURE_2D, gP.TexSpecular)
    
        '// Draw XYZ text.
        for nI = 0 TO 10
            zTxt = str$(nI * 10)
            GL_DrawText (gP.GLwnd, gP.UseFont, g_Chart.chartseries * (g_Chart.radius * 2.1) + g_Chart.radius - 0.1, nI, 0, zTxt, ZD_ARGB(255, 0,255,0))
            GL_DrawText (gP.GLwnd, gP.UseFont, 0.1, nI, g_Chart.chartnumber * (g_Chart.radius * 2.1) + g_Chart.radius + 0.5, zTxt, ZD_ARGB(255, 0,255,0))
        next
    
        '// Draw the XYZ grid
        glLineWidth(1.0)
        glCallList(g_Chart.ListIndex)
    
        '// Draw the podium
        glPushMatrix()
           GL_TexSpec(%TRUE)
              glColor4ub(255,255,255, 128)
              rX = g_Chart.chartseries * (g_Chart.radius * 1.05)
              rY = g_Chart.chartnumber * (g_Chart.radius * 1.05)
              rZ = 0
              glTranslatef(rX + g_Chart.radius * 0.5, -0.1, rY + g_Chart.radius * 0.5)
              GL_ChartBar(rX + g_Chart.radius * 1.5, rY + g_Chart.radius * 1.5, -0.2)
           GL_TexSpec(%FALSE)
        glPopMatrix()
    
        '// Draw XYZ translucent glass panels
        GL_TexSpec(%TRUE)
           rX = g_Chart.chartseries * (g_Chart.radius * 2.1) + g_Chart.radius
           rY = 10
           rZ = g_Chart.chartnumber * (g_Chart.radius * 2.1) + g_Chart.radius
           glColor4ub(240,240,255, 64) '// Transparent light blue color.
           GL_ChartAxisPanel(rX, rY, rZ)
        GL_TexSpec(%FALSE)
    
        '// Draw legend using GDImage bitmapped font. 
        glPushMatrix()
           gl_DisableAmbience()
           glColor4ub(255,255,255,255)
           for nI = 1 TO g_Chart.chartnumber
               glPushMatrix()
                  glTranslatef((2.1 * g_Chart.radius) * g_Chart.chartseries + g_Chart.radius, rHalfRadius * 0.6, g_Chart.radius + rHalfRadius * 1.25)
                  '// Billboard to keep it in front of the camera.
                  GL_Billboard()
    
                  GL_ChartSymbol(gP.GLwnd, gP.ChartSymbol, 0, 0, 0, chr$(128 + nI))
    
               glPopMatrix()
               glTranslatef(0, 0, 2.1 * g_Chart.radius)
           next
           gl_EnableAmbience()
        glPopMatrix()
    
        '// Draw small letters in front of each chart bar.
        glPushMatrix()
           gl_DisableAmbience()
           glColor4ub(255,255,255, 255)
           glTranslatef(g_Chart.radius + rHalfRadius * 0.5, 0.0, 2.1 * g_Chart.radius * g_Chart.chartnumber + rHalfRadius)
           for nJ = 1 TO g_Chart.chartseries
               GL_ChartLabel(gP.GLwnd, gP.ChartLegend, 0, 0, 0, chr$(64 + nJ))
               glTranslatef(2.1 * g_Chart.radius, 0.0, 0.0)
           next
           glTranslatef((-2.1 * g_Chart.radius) * g_Chart.chartseries, 0.0, 2.1 * g_Chart.radius)
           gl_EnableAmbience()
        glPopMatrix()
    
        '// Draw label using GDImage bitmapped font. 
        glPushMatrix()
           glTranslatef(9.2, 0, 2.1 * g_Chart.radius * g_Chart.chartnumber + rHalfRadius * 3 + 0.35)
           glRotatef(-90, 1, 0, 0)
           glColor4ub(255,255,0, 255)
           GL_ChartLabel(gP.GLwnd, gP.ChartCaption, 0, 0, 0, "GDImage " + ZI_Version())
        glPopMatrix()
    
        '// Draw the chart caption using GDImage bitmapped font. 
        glPushMatrix()
           glLoadIdentity()
           gl_DisableAmbience()
           glDisable(%GL_DEPTH_TEST) '// We want to keep it in front.
           zTitle = "The title of the chart"
           glTranslatef(GL_ChartGetTextLength(gP.ChartCaption, zTitle) * -0.5, -8, -20)
           glColor4ub(255,0,0, 255)
           GL_ChartLabel(gP.GLwnd, gP.ChartCaption, 0, 0, 0, zTitle)
           glEnable(%GL_DEPTH_TEST) '// Don't forget to re-enable DEPTH_TEST
           gl_EnableAmbience()
        glPopMatrix()
    
        '// Draw zoom percentage
        ZI_DrawGLText(gP.GLwnd, gP.UseFont, 10, 10 + gP.UseFont.fontHeight * 0, ("Zoom " + str$(CLNG(rChartZoom * 100))) + "%", ZD_ARGB(255, 255,255,0))
    
        glFlush()
    
        '// Turn off antialiasing
        if (GL_MultiSampleARB()) then glDisable(%GL_MULTISAMPLE_ARB)
    
        '// Update display
        ZI_UpdateGLWindow(gP.GLwnd)
    
    end sub
    
    function WndProc(byval hWnd as long, byval uMsg as dword, byval wParam as dword, byval lParam as long) as long
    
        local hCtrl as dword
    
        select case long uMsg
    
        case %WM_GETMINMAXINFO:
             local pMM as MINMAXINFO PTR
             pMM = lParam
             @pMM.ptMinTrackSize.x = gP.MinTrackSizeW '// minimum width size of the window.
             @pMM.ptMinTrackSize.y = gP.MinTrackSizeH '// minimum height size of the window.
    
        case %WM_TIMER
             gl_DrawScene()
             function = 0: exit function
    
        case %WM_MOUSEWHEEL:
             if (GetFocus() <> gP.GLwnd) then SetFocus(gP.GLwnd)
    
        case %WM_SIZE:
             ZI_ResizeGLWindow(gP.GLwnd)
             gl_DrawScene()
    
        case %WM_COMMAND:
             select case long (LO(WORD, wParam))
    
             case %IDC_RESET:
                  gl_InitGraph()
                  ZI_ResizeGLWindow(gP.GLwnd)
                  gl_DrawScene()
       
             case %IDC_LISTBOX:
                  if (HI(WORD, wParam) = %LBN_SELCHANGE) then
                      hCtrl = GetDlgItem(hWnd, %IDC_LISTBOX)
                      PathCombine(g_mt(0).FullName, EXEresource(), List_GetText(hCtrl, List_GetCursel(hCtrl)))
                      ZI_UpdateNamedGLTextureFromFileEx(g_mt(0).FullName, g_mt(0).Texture, g_mt(0).Square)
                  end if
    
             end select
    
        case %WM_DESTROY:
             KillTimer(hWnd, %IDC_TIMER)
             PostQuitMessage(0)
             function = 0: exit function
        end select
        function = DefWindowProc(hWnd, uMsg, wParam, lParam)
    end function
    
    sub InitMainTimer(byval hMain as dword)
        SetTimer(hMain, %IDC_TIMER, 0, 0)
    end sub
    
    function SpinnerCallBack(byval hWnd as DWORD, byval uMsg as DWORD, byval wParam as DWORD, byval lParam as long) as long
    
        local nRet as long '// Do not stop the event processing in GDImage
    
        local nReserved, imgW, imgH, nItem as long
        local hBitmap as dword
        nItem = List_GetCursel(gP.SpinnerList)
        local zTmp as asciiz * %MAX_PATH
    
        select case long (uMsg)
        case %WM_LBUTTONDOWN, %WM_LBUTTONDBLCLK:
             nItem -= 1
             if (nItem < 1) then nItem = List_GetCount(gP.SpinnerList)
             List_SelectPlus(gP.SpinnerList, nItem)
             PathCombine(zTmp, EXEresource(), List_GetText(gP.SpinnerList, nItem))
             hBitmap = skSkiToDib (zTmp, nReserved)
             ZI_GetBitmapSize(hBitmap, imgW, imgH)
             ZD_DrawBitmapToCtrl(hWnd, (128 - imgH) \ 2, (128 - imgH) \ 2, hBitmap, &HFFFFFFFF, %ID_SPIN01, %ZS_VISIBLE)
             ZD_SetObjectFrameCount(%ID_SPIN01, imgW \ imgH)
             ZD_SetObjectFrameToUse(%ID_SPIN01, 1, %FALSE)
    
        case %WM_RBUTTONDOWN, %WM_RBUTTONDBLCLK:
             nItem += 1
             if (nItem > List_GetCount(gP.SpinnerList)) then nItem = 1
             List_SelectPlus(gP.SpinnerList, nItem)
             PathCombine(zTmp, EXEresource(), List_GetText(gP.SpinnerList, nItem))
             hBitmap = skSkiToDib (zTmp, nReserved)
             ZI_GetBitmapSize(hBitmap, imgW, imgH)
             ZD_DrawBitmapToCtrl(hWnd, (128 - imgH) \ 2, (128 - imgH) \ 2, hBitmap, &HFFFFFFFF, %ID_SPIN01, %ZS_VISIBLE)
             ZD_SetObjectFrameCount(%ID_SPIN01, imgW \ imgH)
             ZD_SetObjectFrameToUse(%ID_SPIN01, 1, %FALSE)
        end select
    
        function = nRet
    end function
    
    function WinMain (byval hInstance as DWORD, byval hPrevInstance as DWORD, _
                      byval lpCmdLine as asciiz ptr, byval nCmdShow as long) as long
    
        local msg as tagMSG
        local wcx as WndClassEx
        local rc as RECT
        local nRet, x, y, IsInitialized as long
        local dwStyle, dwExStyle, hMutex as dword
        local hMain, hList, hFound, hCtrl as dword
        local zClass as asciiz * 16, szFile as asciiz * %MAX_PATH
      
        zClass = "ZCHART32"
    
        hMutex = CreateMutex(byval %Null, 0, zClass)
        if (hMutex) then
            if (GetLastError() = %ERROR_ALREADY_EXISTS) then
                do
                   hFound = FindWindow(zClass, ""): if (hFound) then exit do
                   while PeekMessage(msg, %NULL, %NULL, %NULL, %PM_REMOVE): wend
                loop
                if (IsIconic(hFound)) then ShowWindow(hFound, %SW_RESTORE)
                SetForeGroundWindow(hFound)
                function = 0: exit function
            end if
        end if
    
        wcx.cbSize = SIZEOF(wcx)
        IsInitialized = GetClassInfoEx(zInstance, zClass, wcx)
        if (NOT IsInitialized) then
            wcx.style         = %CS_HREDRAW or %CS_VREDRAW
            wcx.lpfnWndProc   = codeptr(WndProc)
            wcx.cbClsExtra    = 0
            wcx.cbWndExtra    = 0
            wcx.hInstance     = hInstance
            wcx.hIcon         = LoadIcon(hInstance, byval 2)
            wcx.hCursor       = LoadCursor(%NULL, byval %IDC_ARROW)
            wcx.hbrBackground = 0 ' %COLOR_BTNSHADOW
            wcx.lpszMenuName  = 0
            wcx.lpszClassName = varptr(zClass)
            wcx.hIconSm       = wcx.hIcon
            if (RegisterClassEx(wcx)) then IsInitialized = -1
        end if
    
        if (IsInitialized) then
    
            '// Window Extended Style
            dwExStyle = %WS_EX_APPWINDOW or %WS_EX_WINDOWEDGE
            '// Window Style
            dwStyle = %WS_OVERLAPPEDWINDOW or %WS_CLIPSIBLINGS or %WS_CLIPCHILDREN
            SetRect(rc, 0, 0, %ClientW, %ClientH)
            AdjustWindowRectEx(rc, dwStyle, %FALSE, dwExStyle) '// Adjust WindowRect to the client size
    
            gP.MinTrackSizeW = rc.nRight - rc.nLeft
            gP.MinTrackSizeH = rc.nBottom - rc.nTop
            x = max&((GetSystemMetrics(%SM_CXSCREEN) - gP.MinTrackSizeW) \ 2, 0)
            y = max&((GetSystemMetrics(%SM_CYSCREEN) - gP.MinTrackSizeH) \ 2, 0)
    
            '// Create The Window
            hMain = CreateWindowEx(dwExStyle, _            '// Extended Style for The Window
                                   zClass, _               '// Class Name
                                   "3D Chart demo", _      '// Window Title
                                   dwStyle, _              '// Defined Window Style
                                   x, y, _                 '// Window Position
                                   gP.MinTrackSizeW, _     '// Calculate Window Width
                                   gP.MinTrackSizeH, _     '// Calculate Window Height
                                   %NULL, _                '// No Parent Window
                                   %NULL, _                '// No Menu
                                   hInstance, _            '// Instance
                                   byval %NULL)            '// Dont Pass Anything To WM_CREATE
    
            if (hMain) then
            
                '// Create button "Reset"
                CreateWindowEx(0, "BUTTON", "Reset", %WS_CHILD or %WS_VISIBLE or %WS_TABSTOP, _
                               %ClientW - (8 + 120 + 8), 10 + (22 + 5) * 2 - 2, 120, 30, hMain, %IDC_RESET, hInstance, byval %NULL)
               
                '// Create static.
                szFile = "|Left mouse button:|change view angle.||Right mouse button:|move graph location.||Mouse wheel: zoom."
                replace "|"  with $crlf in szFile
                StaticCenter(szFile, %ClientW - (8 + 120 + 8), 10 + (22 + 5) * 5 + 5, 120, 120, hMain, %IDC_STATIC)
               
                '// Create ListBox to select texture from.
                hList = CreateWindowEx(0, "ListBox", "", %WS_CHILD or %WS_BORDER or %WS_VISIBLE or %WS_VSCROLL _
                                       or %LBS_SORT or %LBS_NOTIFY or %LBS_HASSTRINGS or %LBS_DISABLENOSCROLL , _
                                       %ClientW - (8 + 120 + 8), 10 + (22 + 5) * 10 + 5, 120, 120, _
                                       hMain, %IDC_LISTBOX, hInstance, byval %NULL)
                SetCTLFont(hList, DefaultFont())
                gl_LoadTexture(hList)
               
                '// *******************************************************************************
                '// Create a GDImage WGL control (OpenGL extensions).
                dwStyle = %WS_CHILD or %WS_VISIBLE
                dwExStyle = 0
                gP.GLwnd = WGL_CreateWindow(dwExStyle, dwStyle, 0, 0, 844, %ClientH, hMain, %IDC_GDIMAGE)
               
                if (gP.GLwnd) then
                    '// Anchor the GDImage WGL control (make it a resizable)
                    ZI_SetAnchorMode(gP.GLwnd, %ANCHOR_HEIGHT_WIDTH)
                   
                    '// Use GDImage OpenGL automatic mousing support.
                    GL_UseMouseManager(gP.GLwnd)
                   
                    '// Create the textures.            
                    dim g_mt(3) as ZGLTEXTUREX
                    g_mt(0).FullName = EXEresource() + List_GetText(hList, List_GetCursel(hList)): g_mt(0).ID = 1: g_mt(0).Square = 0
                    g_mt(1).FullName = EXEresource() + "chrome.jpg": g_mt(1).ID = 2: g_mt(1).Square = 0
                    g_mt(2).FullName = EXEresource() + "boing.png": g_mt(2).ID = 3: g_mt(2).Square = 0
                    g_mt(3).FullName = EXEresource() + "bubble.png": g_mt(3).ID = 4: g_mt(3).Square = 0
                    ZI_MakeMultipleTexture(byval varptr(g_mt(LBOUND(g_mt))), UBOUND(g_mt) - LBOUND(g_mt) + 1)
                    gP.TexSpecular = g_mt(0).texture
                    gP.TexChrome   = g_mt(1).texture
                    gP.TexBoing    = g_mt(2).texture
                    gP.TexBubble   = g_mt(3).texture
                   
                    gl_Initialize()
                       
                    '// Create a WGL font for the XYZ axis.
                    ZI_BuildGLfont(ZI_GetGLDC(gP.GLwnd), gP.UseFont) '// Build OpenGL font for our OpenGL window
                   
                    '// Create a GDImage bitmapped font for the chart labels.
                    '// Valid font size are: 16,32,64
                    PathCombine(szFile, EXEresource(), "HomeRem.ttf")
                    gP.ChartCaption = GL_CreateFontTexture(gP.GLwnd, szFile, 32, &HFFFFFFFF)
                    gP.ChartSymbol  = GL_CreateFontTexture(gP.GLwnd, "WINGDINGS", 32, &HFFFFFFFF)
                    gP.ChartLegend  = GL_CreateFontTexture(gP.GLwnd, "TREBUCHET MS", 16, &HFFFFFFFF)
                   
                    PathCombine(szFile, EXEpath(), "Onyx.sks")
                    if (skInitEngine(szFile, "")) then
                        skSkinWindow(hMain, "Dock|Undock|Minimize|Maximize|Restore|Close")
                        skSetAnchorCtrl(GetDlgItem(hMain, %IDC_RESET), %ANCHOR_RIGHT)
                        skSetAnchorCtrl(GetDlgItem(hMain, %IDC_STATIC), %ANCHOR_RIGHT)
                        skSetAnchorCtrl(GetDlgItem(hMain, %IDC_LISTBOX), %ANCHOR_RIGHT)
                   
                        '// For the fun we add a little GDImage animation
                        hCtrl = CreateWindowEx(0, $GDImageClassName, "", %WS_CHILD or %WS_VISIBLE, _
                                               %ClientW - (128 + 12), %ClientH - (128 + 12), 128, 128, _
                                               hMain, %IDC_SPINNER, hInstance, byval %NULL)
                        local imgW, imgH, nReserved as long
                        if (LoadSpinner(hMain) > 0) then
                            hCtrl = GetDlgItem(hMain, %IDC_LISTSPINNER)
                            PathCombine(szFile, EXEresource(), List_GetText(hCtrl, List_GetCursel(hCtrl)))
                            local hBitmap as dword  
                            hBitmap = skSkiToDib (szFile, nReserved)
                            hCtrl = GetDlgItem(hMain, %IDC_SPINNER)
                            if (hBitmap) then
                                ZI_GetBitmapSize(hBitmap, imgW, imgH)
                                ZD_DrawBitmapToCtrl(hCtrl, (128 - imgH) / 2, (128 - imgH) / 2, hBitmap, ZD_ColorARGB(255, 0), %ID_SPIN01, %ZS_VISIBLE)
                                '// Use the WinLIFT background for better illusion.
                                ZI_UseWinLIFTbackground(hCtrl, %TRUE, %TRUE)
                                ZD_SetObjectFrameCount(%ID_SPIN01, imgW \ imgH)
                                ZD_SetObjectFrameToUse(%ID_SPIN01, 1, %FALSE)
                                skSetAnchorCtrl(GetDlgItem(hMain, %IDC_SPINNER), %ANCHOR_BOTTOM_RIGHT) '// WinLIFT anchor property
                                '// Lock and disable the sprite image.
                                ZD_SetObjectLocked(%ID_SPIN01, %TRUE)
                                skCreateToolTip(hCtrl, "Click to change spinner animation") '// Add tooltip (tooltip must be first enabled with #pragma)
                                '// We use a callback to monitor the GDImage spinner control messages
                                '// Create a WM_LBUTTONDOWN event
                                local cpCallBack as DWORD
                                cpCallBack = codeptr(SpinnerCallBack)
                                ZI_EventMessageEx(hCtrl, cpCallBack, %WM_LBUTTONDOWN, %TRUE)   '// monitor event
                                ZI_EventMessageEx(hCtrl, cpCallBack, %WM_LBUTTONDBLCLK, %TRUE) '// monitor event
                                ZI_EventMessageEx(hCtrl, cpCallBack, %WM_RBUTTONDOWN, %TRUE)   '// monitor event
                                ZI_EventMessageEx(hCtrl, cpCallBack, %WM_RBUTTONDBLCLK, %TRUE) '// monitor event
                            end if
                        end if
                    else
                        '// Anchor child controls if skinning has failed, using GDImage.
                        ZI_SetAnchorMode(GetDlgItem(hMain, %IDC_RESET), %ANCHOR_RIGHT)   '// GDImage anchor property
                        ZI_SetAnchorMode(GetDlgItem(hMain, %IDC_STATIC), %ANCHOR_RIGHT)  '// GDImage anchor property
                        ZI_SetAnchorMode(GetDlgItem(hMain, %IDC_LISTBOX), %ANCHOR_RIGHT) '// GDImage anchor property
                    end if
                   
                    '// Show the main window
                    ShowWindow(hMain, nCmdShow)
                    SetForegroundWindow(hMain)
                    SetFocus(hMain)
                   
                    InitMainTimer(hMain)
    
                    '// Main message pump.
                    while GetMessage(msg, 0, 0, 0)
                          TranslateMessage(msg)
                          DispatchMessage(msg)
                    wend
                    nRet = msg.wParam
                   
                    '// Cleanup texture from memory             
                    gl_DestroyTexture ()
                    '// Delete GLFont.
                    ZI_DeleteGLFont(gP.UseFont)
               
                end if
            end if
        end if
    
        if (hMutex) then CloseHandle(hMutex)
        function = nRet
    end function

    Screen shot:


    Link to download the full project
    SkinChart_PB.zip is here

    ...
    Patrice Terrier
    www.zapsolution.com
    www.objreader.com
    Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).

  • #2
    Very smooth animation!

    Comment


    • #3
      Patrice,

      This is definitely "Academy Award" stuff, genuinely impressive.
      hutch at movsd dot com
      The MASM Forum

      www.masm32.com

      Comment


      • #4
        Thank you Steve.

        I did put a lot of advanced stuffs in this project:
        - GDImage/OpenGL private font (no need to install it first).
        - GDImage/OpenGL bilboarding.
        - GDImage/OpenGL specular effect (glass reflection).
        - GDImage/OpenGL extension support (antialiasing).
        - GDImage spinner animation.
        - GDImage/DWM/GPU reducing the CPU impact down to almost 0%.
        - GDImage/OpenGL 3D primitives (no GLU/GLUT encapsulation).
        - WinLIFT skin theme.

        This is the clear demonstration that nothing could do better than having direct access to the core flat API.

        ...
        Patrice Terrier
        www.zapsolution.com
        www.objreader.com
        Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).

        Comment

        Working...
        X