1 /* 2 * PROJECT: ReactOS Picture and Fax Viewer 3 * LICENSE: GPL-2.0 (https://spdx.org/licenses/GPL-2.0) 4 * PURPOSE: Animation of shimgvw.dll 5 * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 6 */ 7 8 #include "shimgvw.h" 9 10 #define ANIME_TIMER_ID 9999 11 12 void Anime_FreeInfo(PANIME pAnime) 13 { 14 if (pAnime->m_pDelayItem) 15 { 16 QuickFree(pAnime->m_pDelayItem); 17 pAnime->m_pDelayItem = NULL; 18 } 19 pAnime->m_nFrameIndex = 0; 20 pAnime->m_nFrameCount = 0; 21 pAnime->m_nLoopIndex = 0; 22 pAnime->m_nLoopCount = (UINT)-1; 23 } 24 25 void Anime_SetTimerWnd(PANIME pAnime, HWND hwndTimer) 26 { 27 pAnime->m_hwndTimer = hwndTimer; 28 } 29 30 void Anime_Pause(PANIME pAnime) 31 { 32 KillTimer(pAnime->m_hwndTimer, ANIME_TIMER_ID); 33 } 34 35 void Anime_Start(PANIME pAnime, DWORD dwDelay) 36 { 37 if (pAnime->m_pDelayItem) 38 SetTimer(pAnime->m_hwndTimer, ANIME_TIMER_ID, dwDelay, NULL); 39 } 40 41 DWORD Anime_GetFrameDelay(PANIME pAnime, UINT nFrameIndex) 42 { 43 if (nFrameIndex < pAnime->m_nFrameCount && pAnime->m_pDelayItem) 44 { 45 return ((DWORD *)pAnime->m_pDelayItem->value)[pAnime->m_nFrameIndex] * 10; 46 } 47 return 0; 48 } 49 50 BOOL Anime_Step(PANIME pAnime, DWORD *pdwDelay) 51 { 52 *pdwDelay = INFINITE; 53 if (pAnime->m_nLoopCount == (UINT)-1) 54 return FALSE; 55 56 if (pAnime->m_nFrameIndex + 1 < pAnime->m_nFrameCount) 57 { 58 *pdwDelay = Anime_GetFrameDelay(pAnime, pAnime->m_nFrameIndex); 59 Anime_SetFrameIndex(pAnime, pAnime->m_nFrameIndex); 60 ++pAnime->m_nFrameIndex; 61 return TRUE; 62 } 63 64 if (pAnime->m_nLoopCount == 0 || pAnime->m_nLoopIndex < pAnime->m_nLoopCount) 65 { 66 *pdwDelay = Anime_GetFrameDelay(pAnime, pAnime->m_nFrameIndex); 67 Anime_SetFrameIndex(pAnime, pAnime->m_nFrameIndex); 68 pAnime->m_nFrameIndex = 0; 69 ++pAnime->m_nLoopIndex; 70 return TRUE; 71 } 72 73 return FALSE; 74 } 75 76 BOOL Anime_OnTimer(PANIME pAnime, WPARAM wParam) 77 { 78 DWORD dwDelay; 79 80 if (wParam != ANIME_TIMER_ID) 81 return FALSE; 82 83 Anime_Pause(pAnime); 84 if (Anime_Step(pAnime, &dwDelay)) 85 Anime_Start(pAnime, dwDelay); 86 return TRUE; 87 } 88 89 BOOL Anime_LoadInfo(PANIME pAnime) 90 { 91 UINT nDimCount = 0; 92 UINT cbItem; 93 UINT result; 94 95 Anime_Pause(pAnime); 96 Anime_FreeInfo(pAnime); 97 98 if (!g_pImage) 99 return FALSE; 100 101 GdipImageGetFrameDimensionsCount(g_pImage, &nDimCount); 102 if (nDimCount) 103 { 104 GUID *dims = (GUID *)QuickAlloc(nDimCount * sizeof(GUID), TRUE); 105 if (dims) 106 { 107 GdipImageGetFrameDimensionsList(g_pImage, dims, nDimCount); 108 GdipImageGetFrameCount(g_pImage, dims, &result); 109 pAnime->m_nFrameCount = result; 110 QuickFree(dims); 111 } 112 } 113 114 result = 0; 115 GdipGetPropertyItemSize(g_pImage, PropertyTagFrameDelay, &result); 116 cbItem = result; 117 if (cbItem) 118 { 119 pAnime->m_pDelayItem = (PropertyItem *)QuickAlloc(cbItem, FALSE); 120 GdipGetPropertyItem(g_pImage, PropertyTagFrameDelay, cbItem, pAnime->m_pDelayItem); 121 } 122 123 result = 0; 124 GdipGetPropertyItemSize(g_pImage, PropertyTagLoopCount, &result); 125 cbItem = result; 126 if (cbItem) 127 { 128 PropertyItem *pItem = (PropertyItem *)QuickAlloc(cbItem, FALSE); 129 if (pItem) 130 { 131 if (GdipGetPropertyItem(g_pImage, PropertyTagLoopCount, cbItem, pItem) == Ok) 132 { 133 pAnime->m_nLoopCount = *(WORD *)pItem->value; 134 } 135 QuickFree(pItem); 136 } 137 } 138 139 Anime_Start(pAnime, 0); 140 141 return pAnime->m_pDelayItem != NULL; 142 } 143 144 void Anime_SetFrameIndex(PANIME pAnime, UINT nFrameIndex) 145 { 146 if (nFrameIndex < pAnime->m_nFrameCount) 147 { 148 GUID guid = FrameDimensionTime; 149 if (Ok != GdipImageSelectActiveFrame(g_pImage, &guid, nFrameIndex)) 150 { 151 guid = FrameDimensionPage; 152 GdipImageSelectActiveFrame(g_pImage, &guid, nFrameIndex); 153 } 154 } 155 pAnime->m_nFrameIndex = nFrameIndex; 156 } 157