'+--------------------------------------------------------------------------+
'|                                TRON3D                                    |
'|                                                                          |
'|                           GDImage animation                              |
'|                                                                          |
'+--------------------------------------------------------------------------+
'|                                                                          |
'|                         Author Patrice TERRIER                           |
'|            8 Domaine de Rochagnon. 38800 Champagnier  FRANCE             |
'|                       http://www.zapsolution.com                         |
'|                    E-mail: pterrier@zapsolution.com                      |
'|                                                                          |
'+--------------------------------------------------------------------------+
'|                  Project started on : 05-30-2011                         |
'|                        Last revised : 10-31-2014                         |
'+--------------------------------------------------------------------------+

#COMPILE EXE "Tron3D.exe"

#INCLUDE "TronWinAPI.inc"
#INCLUDE "GDImage.inc"
#INCLUDE "WinLIFT.inc"
#RESOURCE "Tron.pbr"

declare function zTrace lib "zTrace.DLL" alias "zTrace" (zMessage as asciiz) as long

%NM_FIRST           = 0
%NM_AUDIOCOMPLETION = %NM_FIRST - 80
%NM_MOVIEPLAYING    = %NM_FIRST - 81

%CLIENT_WIDTH       = 780
%CLIENT_HEIGHT      = 440
%CTRL_WIDTH         = 392
%CTRL_HEIGHT        = 392

%IDC_GDImageCTRL    = -1
%IDC_MOTORCYCLE     = -2
%IDC_static         = -3
%IDC_TIMER          = 1


%ID_FIRST           = 1
%ID_Layer1          = %ID_FIRST
%ID_Layer2          = %ID_FIRST + 1
%ID_Layer3          = %ID_FIRST + 2
%ID_Layer4          = %ID_FIRST + 3
%ID_Layer5          = %ID_FIRST + 4
%ID_Layer6          = %ID_FIRST + 5
%ID_LAST            = %ID_Layer6

%ZWP_PARENT         = 1
%ZWP_PLUGIN         = 2
%ZWP_AUDIO          = 3
%ZWP_DESTROY        = 4

type PROP
    hMain           as dword
    hzwp            as dword
    skinactive      as long
    sequence        as long
    ZWPNOTIFICATION as long
end type

type ZWP
    file           as asciiz * %MAX_PATH
end type

global gP as PROP '// Global properties
global gCDS as COPYDATASTRUCT, gZWP as ZWP

function EXEresource() as string
    function = EXE.Path$ + "resource\"
end function

function EXEplugin() as string
    function = EXE.Path$ + "BBplugin\"
end function

sub ZWP_SizeMove()
    local lpw as RECT
    local x, y, w, h as long
    local hPopup as dword

    '// GetWindowRect(gP.hMain, lpw)
    '// Tron3D uses the RECT of the GDImage child control instead of the main window.
    GetWindowRect(GetDlgItem(gP.hMain, %IDC_GDImageCTRL), lpw)
    x = lpw.left       '//+ skGetSystemMetrics(%SK_DWM_LEFT)
    y = lpw.top        '//+ skGetSystemMetrics(%SK_DWM_TOP)
    w = lpw.right - x  '//- skGetSystemMetrics(%SK_DWM_RIGHT)
    h = lpw.bottom - y '//- skGetSystemMetrics(%SK_DWM_BOTTOM)

    '// Use this to move the window in case of AERO shake
    '// because setting the new location with SetWindowPos
    '// may fail!
    if (gP.hzwp) then
        hPopup = skGetDWMregion(gP.hMain)
        if (hPopup = 0) then hPopup = gP.hMain

        SetWindowPos(gP.hzwp, GetWindow(hPopup, %GW_HWNDNEX), 0, 0, 0, 0, %SWP_NOMOVE or %SWP_NOSIZE or %SWP_NOOWNERZORDER or %SWP_NOACTIVATE)
        MoveWindow(gP.hzwp, x, y, w, h, 0)
    end if
end sub

sub ZWP_Handle()
    if (gP.hzwp = 0) then
        local szFile as asciiz * %MAX_PATH
        local nRet as dword
        szFile = EXE.Path$ + "zwp.exe"
        nRet = ShellExecute(0, "open", szFile, "", EXE.Path$, %SW_SHOWNOACTIVATE)
        apiSleep(400)

        local zClass as asciiz * 16
        zClass = "ZWALLPAPER"
        gP.hzwp = FindWindow(zClass, zClass)
        if (gP.hzwp) then
            ZWP_SizeMove()
            gCDS.dwData = %ZWP_PARENT
            gCDS.cbData = sizeof(gZWP)
            gCDS.lpData = varptr(gZWP)
            SendMessage(gP.hzwp, %WM_COPYDATA, gP.hMain, byval varptr(gCDS))
        end if
    end if
end sub

sub ZWP_Destroy()
    if (gP.hzwp) then
         gCDS.dwData = %ZWP_DESTROY
         gCDS.cbData = sizeof(gZWP)
         gCDS.lpData = varptr (gZWP)
         SendMessage(gP.hzwp, %WM_COPYDATA, gP.hMain, byval varptr(gCDS))
    end if
end sub

sub ZWP_Play(byval sFile as string, byval nFileType as long)
    if (gP.hzwp) then
        ZWP_SizeMove()
        gZWP.file = sFile
        gCDS.dwData = nFileType
        gCDS.cbData = sizeof(gZWP)
        gCDS.lpData = varptr(gZWP)
        SendMessage(gP.hzwp, %WM_COPYDATA, gP.hMain, byval varptr(gCDS))
        ShowWindow(gP.hzwp, %SW_SHOW)
    end if
end sub

sub RenderAnimation(byval hWnd as dword)

    local nX, nY, nW, nH as long, hCtrl as dword, rc as RECT, p as POINTAPI
    static nFlip, nTempo, AnimDone as long

    if (nTempo < GetTickcount()) then

        ZD_GetObjectXY(%ID_Layer2, nX, nY)
        if (nFlip = 0) then
            if (nX > -68) then
                nX -= 2
            else
                nFlip = -1
            end if
        else
            if (nX < 0) then
                nX += 2
            else
                nFlip = 0
            end if
        end if

        ZD_SetObjectRed(%ID_Layer1, 187 + nX, %FALSE)
        ZD_SetObjectBlue(%ID_Layer1, -nX * 2, %FALSE)

        ZD_SetObjectXY(%ID_Layer2,  nX, nY, %FALSE)
        ZD_SetObjectXY(%ID_Layer3, -nX, nY, %FALSE)

        ZD_SetObjectAngle(%ID_Layer5, -nX, %FALSE)

        if (gP.sequence = 1) then
            ZD_SetObjectAlpha(%ID_Layer6, 255 + nX, %FALSE)
            ZD_SetObjectScale(%ID_Layer6, 1 + (-nX * 0.005))
        else
            ZD_SetObjectScale(%ID_Layer6, 3 - (1 + (-nX * 0.005) * 4))
        end if

        ZI_UpdateWindow(GetDlgItem(hWnd, %IDC_GDImageCTRL), 0)

        nTempo = GetTickCount() + 40
    end if

    if (AnimDone = 0) then
        hCtrl = GetDlgItem(hWnd, %IDC_MOTORCYCLE)
        GetWindowRect(hCtrl, rc): p.X = rc.left: p.Y = rc.top: ScreenToClient(GetParent(hCtrl), p)
        if (p.X > 2) then
            p.X -= 2
            nH = rc.bottom - rc.top: GetClientRect(GetParent(hCtrl), rc): nW = rc.right - rc.left
            MoveWindow(hCtrl, p.X, p.Y, nW - p.X, nH, 1)
            ZI_SetAnchorMode(hCtrl, %ANCHOR_WIDTH)
        else
            AnimDone = -1
        end if
    end if

end sub

function WndProc(byval hWnd as dword, byval uMsg as dword, byval wParam as long, byval lParam as long) as long 
    local nRet as long, szFileName as asciiz * %MAX_PATH

    if (uMsg = gP.ZWPNOTIFICATION) then
         if (wParam = %NM_AUDIOCOMPLETION) then
             incr gP.sequence
             if (gP.sequence > 2) then gP.sequence = 1

             if (gP.sequence = 1) then
                 ZWP_Play(EXEplugin() + "Hud_Ring.dll", %ZWP_PLUGIN)
                 ZWP_Play(EXEresource() + "TronGRID.ogg", %ZWP_AUDIO)
                 ZD_SetObjectBitmapFromFile(EXEresource() + "Layer6.png", %ID_Layer6, %TRUE)
             else
                 ZWP_Play(EXEplugin() + "Hud_Beam.dll", %ZWP_PLUGIN)
                 ZWP_Play(EXEresource() + "TronSOF.ogg", %ZWP_AUDIO)
                 ZD_SetObjectScale(%ID_Layer6, 1)
                 ZD_SetObjectAlpha(%ID_Layer6, 255, %FALSE)
                 ZD_SetObjectBitmapFromFile(EXEresource() + "Layer6_bis.png", %ID_Layer6, %TRUE)
             end if
         end if
         function = 0: exit function
    end if

    select case long uMsg
    case %WM_SIZE, %WM_MOVE, %WM_WINDOWPOSCHANGED, %WM_IME_NOTIFY
         ZWP_SizeMove()

    case %WM_DROPFILES '// Drag & drop
         nRet = DragQueryFile(wParam, -1, "", 0)
         if (nRet > 0) then
             nRet = DragQueryFile(wParam, 0, szFileName, %MAX_PATH)
             if (nRet > 0) then ZWP_Play(szFileName, %ZWP_AUDIO)
         end if
         DragFinish(wParam)

    case %WM_ERASEBKGND
         function = 1: exit function

    case %WM_TIMER
         RenderAnimation(hWnd)
         function = 0: exit function

    case %WM_DESTROY
         ZWP_Destroy()
         PostQuitMessage(0)
         function = 0: exit function
    end select

    function = DefWindowProc(hWnd, uMsg, wParam, lParam)

end function

function WinMain (byval hInstance     as long, _
                  byval hPrevInstance as long, _
                  byval lpCmdLine     as asciiz PTR, _
                  byval iCmdShow      as long) as long

    local rc          as RECT
    local Msg         as tagMsg
    local wcx         as WndClassEx
    local zClass      as asciiz * 80
    local IsInitialized, x, y, w, h as long, dwStyleEx, dwStyle, hMutex as dword

    zClass = "ZTRON"

    hMutex = CreateMutex(byval %NULL, 0, zClass)
    if (hMutex) then
       if (GetLastError() = %ERROR_ALREADY_EXISTS) then
          do
             gP.hMain = FindWindow(zClass, ""): if (gP.hMain) then exit do
             while PeekMessage(Msg, 0, 0, 0, %PM_REMOVE): wend
          loop
          if (IsIconic(gP.hMain)) then ShowWindow(gP.hMain, %SW_RESTORE)
          SetForeGroundWindow(gP.hMain)
          function = 0
          exit function
       end if
    end if

    wcx.cbSize = sizeof(wcx)
    IsInitialized = GetClassInfoEx(hInstance, zClass, wcx)
    if (IsInitialized     = 0) then
        wcx.style         = 0 ' %CS_HREDRAW or %CS_VREDRAW
        wcx.lpfnWndProc   = codeptr(WndProc)
        wcx.cbClsExtra    = 0
        wcx.cbWndExtra    = 0
        wcx.hInstance     = hInstance
        wcx.hIcon         = LoadIcon(wcx.hInstance, "PROGRAM")
        wcx.hCursor       = LoadCursor(%NULL, byval %IDC_ARROW)
        wcx.hbrBackground = %NULL
        wcx.lpszMenuName  = %NULL
        wcx.lpszClassName = varptr(zClass)
        wcx.hIconSm       = wcx.hIcon
        if (RegisterClassEx(wcx)) then IsInitialized = %TRUE
    end if

    if (IsInitialized) then

        dwStyleEx = 0
        dwStyle = %WS_POPUP or %WS_CAPTION or %WS_SYSMENU or %WS_MINIMIZEBOX

        SetRect(rc, 0, 0, %CLIENT_WIDTH, %CLIENT_HEIGHT)
        AdjustWindowRectEx(rc, dwStyle, %FALSE, dwStyleEx)
        w = rc.right - rc.left
        h = rc.bottom - rc.top
        x = max&((GetSystemMetrics(%SM_CXSCREEN) - w) \ 2, 0)
        y = max&((GetSystemMetrics(%SM_CYSCREEN) - h) \ 2, 0)

        '// Create The Window
        gP.hMain = CreateWindowEx(dwStyleEx, zClass, "", dwStyle, x, y, w, h, %NULL, %NULL, hInstance, byval %NULL)
        if (gP.hMain) then
            local nID, nW, nH as long, hBitmap, hCtrl as dword

            gP.ZWPNOTIFICATION = RegisterWindowMessage("ZWPnotification")

            dwStyle = %WS_CHILD or %WS_VISIBLE
            x = (%CLIENT_WIDTH - %CTRL_WIDTH) \ 2
            y = (%CLIENT_HEIGHT - %CTRL_HEIGHT) \ 2 + 12
            hCtrl = CreateWindowEx(0, $GDImageClassName, "", dwStyle, x, y, %CTRL_WIDTH, %CTRL_HEIGHT, gP.hMain, %IDC_GDImageCTRL, hInstance, byval %NULL)
            ZI_SetAnchorMode(hCtrl, %ANCHOR_CENTER)
            '// Gradiant color to paint the background
            ZI_SetProperty(hCtrl, %ZI_GradientTop, RGB(1,64,85))
            ZI_SetProperty(hCtrl, %ZI_GradientBottom, 0)

            for nID = %ID_FIRST TO %ID_LAST
                hBitmap = ZI_CreateBitmapFromFile(EXEresource() + "Layer" + LTRIM$(STR$(nID)) + ".png", nW, nH)
                ZD_DrawBitmapToCtrl(hCtrl, 0, 0, hBitmap, ZD_ColorARGB(255, 0), nID, %ZS_VISIBLE)
                ZD_SetObjectLocked(nID, %TRUE)
            next

            if (skInitEngine("Tron.sks", "")) then
                skSkinWindow(gP.hMain, "Dock|Undock|Minimize|Maximize|Restore|Close")
                gP.skinactive = -1
                hCtrl = skPushButtonImage(gP.hMain, EXEresource() + "MotorCycle.png", " ", %CLIENT_WIDTH + 4, 0, %CLIENT_WIDTH + 4, 24, %IDC_MOTORCYCLE, %BS_LEFT)' or %BS_VCENTER)
                EnableWindow(hCtrl, %FALSE)
            end if

            '// To perform audio file drag and drop
            DragAcceptFiles(gP.hMain, %TRUE)

            '// Run ZWP with the default plugin
            ZWP_Handle()
            ZWP_Play(EXEplugin() + "Hud_Ring.dll", %ZWP_PLUGIN)
            ZWP_Play(EXEresource() + "TronGRID.ogg", %ZWP_AUDIO)

            '// Show the main window
            ShowWindow(gP.hMain, %SW_SHOW)
            SetForegroundWindow(gP.hMain) '// Slightly Higher Priority

            gP.sequence = 1

            SetTimer(gP.hMain, %IDC_TIMER, 0, %NULL)
            while GetMessage(Msg, %NULL, 0, 0)
                  TranslateMessage(msg)                ' Translate The Message
                  DispatchMessage(msg)                 ' Dispatch The Message
            wend
            KillTimer(gP.hMain, %IDC_TIMER)

            function = msg.wParam
        end if

    end if

    if (hMutex) then CloseHandle(hMutex)

end function

