IVideoD3DOSD.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. #include "main.h"
  2. #include "IVideoD3DOSD.h"
  3. #include "resource.h"
  4. extern wchar_t FileTitle[];
  5. static HMODULE d3dx_lib = 0;
  6. // For non-debug builds, comment out DXTraceW debug statements to
  7. // remove them completely
  8. //#ifndef _DEBUG
  9. #define DXTraceW //
  10. //#endif
  11. typedef HRESULT (WINAPI *D3DXCREATESPRITE)(LPDIRECT3DDEVICE9, LPD3DXSPRITE *);
  12. typedef HRESULT (WINAPI *D3DXCREATEFONTW)(LPDIRECT3DDEVICE9, INT, UINT, UINT, UINT, BOOL, DWORD, DWORD, DWORD, DWORD, LPCWSTR, LPD3DXFONT *);
  13. typedef HRESULT (WINAPI *D3DXCREATETEXTUREFROMRESOURCEEXW)(LPDIRECT3DDEVICE9, HMODULE, LPCWSTR, UINT, UINT, UINT, DWORD, D3DFORMAT, D3DPOOL, DWORD, DWORD, D3DCOLOR, D3DXIMAGE_INFO *, PALETTEENTRY *, LPDIRECT3DTEXTURE9 *);
  14. D3DXCREATESPRITE pCreateSprite = NULL;
  15. D3DXCREATEFONTW pCreateFontW = NULL;
  16. D3DXCREATETEXTUREFROMRESOURCEEXW pCreateTextureFromResourceExW = NULL;
  17. HMODULE FindD3DX9()
  18. {
  19. if (d3dx_lib)
  20. return d3dx_lib;
  21. HMODULE d3dx9 = NULL;
  22. HANDLE hFind;
  23. WIN32_FIND_DATAW pfiledata;
  24. wchar_t systemDir[MAX_PATH] = {0};
  25. wchar_t libPath[MAX_PATH] = {0};
  26. GetSystemDirectoryW(systemDir, MAX_PATH);
  27. StringCchCatW(systemDir, MAX_PATH,L"\\d3dx9_");
  28. StringCchCopyW(libPath, MAX_PATH, systemDir);
  29. StringCchCatW(systemDir, MAX_PATH,L"*.dll");
  30. hFind = FindFirstFileW(systemDir,&pfiledata);
  31. if (hFind != INVALID_HANDLE_VALUE)
  32. {
  33. BOOL more = true;
  34. int iHighVersion = 0;
  35. while (more)
  36. {
  37. wchar_t *start = wcsrchr(pfiledata.cFileName,L'_') + 1;
  38. int version = _wtoi(start);
  39. if (version <= 42 && version > iHighVersion)
  40. iHighVersion = version;
  41. more = FindNextFileW(hFind,&pfiledata);
  42. }
  43. FindClose(hFind);
  44. if (iHighVersion >= 24)
  45. {
  46. wchar_t finalD3DX9LibPath[MAX_PATH] = {0};
  47. StringCchPrintfW(finalD3DX9LibPath,MAX_PATH,L"%s%d%s",libPath,iHighVersion,L".dll");
  48. d3dx9 = LoadLibraryW(finalD3DX9LibPath);
  49. }
  50. }
  51. return d3dx9;
  52. }
  53. IVideoD3DOSD::IVideoD3DOSD(void)
  54. {
  55. osdSprite = NULL;
  56. osdAtlasTexture = NULL;
  57. osdTimeFont = NULL;
  58. osdTitleFont = NULL;
  59. streaming = 0;
  60. titleFits = false;
  61. // Texture Src Coordinates for sprite images
  62. // Right and Bottom (last two) excluded from image
  63. SetRect(&osdBkgrndTextSrcCoords, 38, 534, 647, 635);
  64. SetRect(&osdPrevButtonNormalSrcCoords, 41, 17, 63, 31);
  65. SetRect(&osdPlayButtonNormalSrcCoords, 145, 14, 161, 35);
  66. SetRect(&osdPauseButtonNormalSrcCoords, 95, 16, 110, 33);
  67. SetRect(&osdStopButtonNormalSrcCoords, 195, 16, 210, 33);
  68. SetRect(&osdNextButtonNormalSrcCoords, 242, 17, 264, 31);
  69. SetRect(&osdProgressFrameNormalSrcCoords, 41, 226, 606, 235);
  70. SetRect(&osdVolumeFrameNormalSrcCoords, 41, 294, 111, 302);
  71. SetRect(&osdEndFSButtonNormalSrcCoords, 41, 140, 59, 158);
  72. SetRect(&osdMuteButtonNormalSrcCoords, 41, 416, 51, 428);
  73. SetRect(&osdProgressSliderNormalSrcCoords, 41, 343, 57, 361);
  74. SetRect(&osdVolumeSliderNormalSrcCoords, 41, 343, 57, 361);
  75. SetRect(&osdProgressProgressSrcCoords, 41, 274, 606, 282); //hilited progress indicator
  76. SetRect(&osdVolumeProgressSrcCoords, 41, 314, 111, 322); //hilited volume indicator
  77. SetRect(&osdPrevButtonClickSrcCoords, 41, 76, 63, 90);
  78. SetRect(&osdPlayButtonClickSrcCoords, 145, 73, 161, 94);
  79. SetRect(&osdPauseButtonClickSrcCoords, 95, 75, 110, 92);
  80. SetRect(&osdStopButtonClickSrcCoords, 195, 75, 210, 92);
  81. SetRect(&osdNextButtonClickSrcCoords, 242, 76, 264, 90);
  82. SetRect(&osdEndFSButtonClickSrcCoords, 41, 192, 59, 210);
  83. SetRect(&osdProgressSliderClickSrcCoords, 41, 385, 57, 403);
  84. SetRect(&osdVolumeSliderClickSrcCoords, 41, 385, 57, 403);
  85. SetRect(&osdPrevButtonDisabledSrcCoords, 41, 106, 63, 120);
  86. SetRect(&osdNextButtonDisabledSrcCoords, 242, 106, 264, 120);
  87. SetRect(&osdPrevButtonHiliteSrcCoords, 41, 46, 63, 60);
  88. SetRect(&osdPlayButtonHiliteSrcCoords, 145, 43, 161, 64);
  89. SetRect(&osdPauseButtonHiliteSrcCoords, 95, 45, 110, 62);
  90. SetRect(&osdStopButtonHiliteSrcCoords, 195, 45, 210, 62);
  91. SetRect(&osdNextButtonHiliteSrcCoords, 242, 46, 264, 60);
  92. SetRect(&osdEndFSButtonHiliteSrcCoords, 41, 166, 59, 184);
  93. SetRect(&osdProgressSliderHiliteSrcCoords, 41, 363, 57, 381);
  94. SetRect(&osdVolumeSliderHiliteSrcCoords, 41, 363, 57, 381);
  95. xScalingFactor = 1.0f;
  96. yScalingFactor = 1.0f;
  97. for (int i = 0; i < 12; i++)
  98. {
  99. bState[i] = NORMAL;
  100. }
  101. mouseOver = NO_BUTTON;
  102. mouseLastOver = NO_BUTTON;
  103. mousePressed = NO_BUTTON;
  104. mouseLastPressed = NO_BUTTON;
  105. mouseDragging = false;
  106. displayTitle = NULL;
  107. marqueeTitleSrc = NULL;
  108. titleRestart = 0;
  109. dtFormat = 0;
  110. isInited = false;
  111. isReadyToDraw = false;
  112. }
  113. RECT IVideoD3DOSD::BuildHitRect(D3DXVECTOR3 position, RECT size)
  114. {
  115. RECT hitRect;
  116. // casting float to long since I know the position vector will not be too big.
  117. hitRect.left = (long)position.x;
  118. hitRect.top = (long)position.y;
  119. hitRect.right = (long)position.x + size.right - size.left;
  120. hitRect.bottom = (long)position.y + size.bottom - size.top;
  121. return hitRect;
  122. }
  123. IVideoD3DOSD::~IVideoD3DOSD(void)
  124. {
  125. if (osdSprite)
  126. {
  127. osdSprite->Release();
  128. osdSprite = NULL;
  129. }
  130. if (osdAtlasTexture)
  131. {
  132. osdAtlasTexture->Release();
  133. osdAtlasTexture = NULL;
  134. }
  135. if (marqueeTitleSrc)
  136. {
  137. delete [] marqueeTitleSrc;
  138. marqueeTitleSrc = NULL;
  139. }
  140. if (displayTitle)
  141. {
  142. delete [] displayTitle;
  143. displayTitle = NULL;
  144. }
  145. //if (d3dx_lib)
  146. //{
  147. // FreeLibrary(d3dx_lib);
  148. // d3dx_lib = NULL;
  149. //}
  150. }
  151. void IVideoD3DOSD::SetScalingFactor(float fx, float fy)
  152. {
  153. xScalingFactor = fx;
  154. yScalingFactor = fy;
  155. }
  156. void IVideoD3DOSD::CreateOSD(IDirect3DDevice9 * device)
  157. {
  158. HRESULT hr;
  159. d3dx_lib = FindD3DX9();
  160. if (!d3dx_lib)
  161. return;
  162. pCreateFontW = (D3DXCREATEFONTW) GetProcAddress(d3dx_lib,"D3DXCreateFontW");
  163. pCreateSprite = (D3DXCREATESPRITE) GetProcAddress(d3dx_lib,"D3DXCreateSprite");
  164. pCreateTextureFromResourceExW = (D3DXCREATETEXTUREFROMRESOURCEEXW) GetProcAddress(d3dx_lib,"D3DXCreateTextureFromResourceExW");
  165. if (!pCreateFontW || !pCreateSprite || !pCreateTextureFromResourceExW)
  166. return;
  167. hr = pCreateSprite(device,&osdSprite);
  168. if (FAILED(hr))
  169. {
  170. DXTraceW(__FILE__, __LINE__, hr, L"CreateSprite Error", TRUE);
  171. return;
  172. }
  173. int font_size = -12 ;
  174. hr = pCreateFontW(
  175. device,
  176. font_size,
  177. 0,
  178. FW_NORMAL,
  179. 1,
  180. 0,
  181. DEFAULT_CHARSET,
  182. OUT_DEFAULT_PRECIS,
  183. ANTIALIASED_QUALITY, //DEFAULT_QUALITY,
  184. DEFAULT_PITCH,
  185. L"Arial",
  186. &osdTimeFont);
  187. if (FAILED(hr))
  188. {
  189. DXTraceW(__FILE__, __LINE__, hr, L"CreateFont (Time) Error", TRUE);
  190. return;
  191. }
  192. font_size = -16 ;
  193. hr = pCreateFontW(
  194. device,
  195. font_size,
  196. 0,
  197. FW_NORMAL,
  198. 1,
  199. 0,
  200. DEFAULT_CHARSET,
  201. OUT_DEFAULT_PRECIS,
  202. ANTIALIASED_QUALITY,//DEFAULT_QUALITY,
  203. DEFAULT_PITCH,
  204. L"Trebuchet MS",
  205. &osdTitleFont);
  206. if (FAILED(hr))
  207. {
  208. DXTraceW(__FILE__, __LINE__, hr, L"CreateFont (Title) Error", TRUE);
  209. return;
  210. }
  211. ResetOSD(device);
  212. isInited = true;
  213. }
  214. void IVideoD3DOSD::UpdateOSD(HWND hWnd, VideoOutput *adjuster)
  215. {
  216. // Position of sprites in screen coordinates
  217. // Center of sprite (where the position is mapped) is left to default to upper left corner
  218. // Note the Bkgrnd is positioned and then all other sprites are relative to that
  219. RECT clientRect;
  220. GetClientRect(hWnd,&clientRect);
  221. // Need to adjust the client rect to match the video aspect ration to fit the osd on the video.
  222. // adjuster->adjustAspect(clientRect);
  223. // width of the client area - width of the bkgrnd / 2 gives the space on each side
  224. // add that space to the offset of the left side of the client area.
  225. float xPosBkg = clientRect.left +
  226. (((clientRect.right - clientRect.left) - (osdBkgrndTextSrcCoords.right - osdBkgrndTextSrcCoords.left))/2.0f);
  227. // width of the client area * .95 give the location of the bottom of the osd (i.e. 5% from bottom)
  228. // that minus the height of the bkgrnd gives the location of the upper left of background
  229. // add that space to the offset of the top of the client area.
  230. float yPosBkg = clientRect.top +
  231. (((clientRect.bottom - clientRect.top) * 1.0f) - (osdBkgrndTextSrcCoords.bottom - osdBkgrndTextSrcCoords.top));
  232. osdBkgrndPosition = D3DXVECTOR3(floor(xPosBkg), floor(yPosBkg), 0.0f);
  233. osdPrevButtonPosition = osdBkgrndPosition + D3DXVECTOR3(191.0f, 75.0f, 0.0f);
  234. osdPlayButtonPosition = osdBkgrndPosition + D3DXVECTOR3(246.0f, 72.0f, 0.0f);
  235. osdPauseButtonPosition = osdBkgrndPosition + D3DXVECTOR3(296.0f, 74.0f, 0.0f);
  236. osdStopButtonPosition = osdBkgrndPosition + D3DXVECTOR3(345.5f, 74.0f, 0.0f);
  237. osdNextButtonPosition = osdBkgrndPosition + D3DXVECTOR3(392.5f, 75.0f, 0.0f);
  238. osdProgressFramePosition = osdBkgrndPosition + D3DXVECTOR3(22.0f, 49.0f, 0.0f);
  239. osdVolumeFramePosition = osdBkgrndPosition + D3DXVECTOR3(518.0f, 76.0f, 0.0f);
  240. osdEndFSButtonPosition = osdBkgrndPosition + D3DXVECTOR3(583.0f, 19.0f, 0.0f);
  241. osdMuteButtonPosition = osdVolumeFramePosition + D3DXVECTOR3(-15.0f, -1.0f, 0.0f);
  242. osdProgressSliderPosition = osdProgressFramePosition + D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  243. osdVolumeSliderPosition = osdVolumeFramePosition + D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  244. SetRect(&osdTimeRect,
  245. (long)osdBkgrndPosition.x + 26,
  246. (long)osdBkgrndPosition.y + 76,
  247. (long)osdBkgrndPosition.x + 98,
  248. (long)osdBkgrndPosition.y + 85);
  249. SetRect(&osdTitleRect,
  250. (long)osdBkgrndPosition.x + 26,
  251. (long)osdBkgrndPosition.y + 17,
  252. (long)osdBkgrndPosition.x + 503,
  253. (long)osdBkgrndPosition.y + 37);
  254. // Create Hit Test Rects for ui elements that don't move
  255. osdPrevButtonHit = BuildHitRect(osdPrevButtonPosition, osdPrevButtonNormalSrcCoords );
  256. osdPlayButtonHit = BuildHitRect(osdPlayButtonPosition, osdPlayButtonNormalSrcCoords );
  257. osdPauseButtonHit = BuildHitRect(osdPauseButtonPosition, osdPauseButtonNormalSrcCoords );
  258. osdStopButtonHit = BuildHitRect(osdStopButtonPosition, osdStopButtonNormalSrcCoords );
  259. osdNextButtonHit = BuildHitRect(osdNextButtonPosition, osdNextButtonNormalSrcCoords );
  260. osdEndFSButtonHit = BuildHitRect(osdEndFSButtonPosition, osdEndFSButtonNormalSrcCoords);
  261. osdProgressFrameHit = BuildHitRect(osdProgressFramePosition, osdProgressFrameNormalSrcCoords);
  262. osdVolumeFrameHit = BuildHitRect(osdVolumeFramePosition, osdVolumeFrameNormalSrcCoords);
  263. streaming = (in_getlength() < 0) || !in_mod || !in_mod->is_seekable;
  264. if (streaming)
  265. {
  266. bState[PREV_BUTTON] = DISABLED;
  267. bState[NEXT_BUTTON] = DISABLED;
  268. bState[PROGRESS_FRAME] = DISABLED;
  269. bState[PROGRESS_SLIDER] = DISABLED;
  270. }
  271. // Find out if the title will fit in the UI space for it
  272. RECT tempTitleRect = osdTitleRect;
  273. osdTitleFont->DrawTextW(NULL, FileTitle, -1, &tempTitleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP | DT_CALCRECT, D3DCOLOR_XRGB(255,255,255));
  274. if (tempTitleRect.right <= osdTitleRect.right)
  275. {
  276. // The title fits, just use it
  277. titleFits = true;
  278. displayTitle = FileTitle;
  279. dtFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP;
  280. } else
  281. {
  282. // title will not fit, we need to set up a marquee.
  283. //
  284. // a string with two copies of the title makes it easier to process
  285. // sizeNeeded, in chars, includes one space, five dots,
  286. // one space and 1 extra for null.
  287. size_t sizeNeeded = (lstrlenW(FileTitle)*2) + 8;
  288. marqueeTitleSrc = new wchar_t[sizeNeeded];
  289. displayTitle = new wchar_t[sizeNeeded];
  290. titleRestart = lstrlenW(FileTitle);
  291. StringCchPrintfW(marqueeTitleSrc, sizeNeeded, L"%s ..... %s", FileTitle, FileTitle);
  292. titleFits = false;
  293. dtFormat = DT_RIGHT | DT_TOP | DT_SINGLELINE;
  294. }
  295. isReadyToDraw = true;
  296. }
  297. #ifdef _DEBUG
  298. #define DRAW_OSD_SET_ERROR(x) draw_osd_error=x
  299. #else
  300. #define DRAW_OSD_SET_ERROR(x)
  301. #endif
  302. void IVideoD3DOSD::DrawOSD(IDirect3DDevice9 * device)
  303. {
  304. HRESULT hr;
  305. D3DXVECTOR3 sliderCenter(8.0f, 8.0f, 0.0f);
  306. const wchar_t *draw_osd_error;
  307. hr = osdSprite->Begin(D3DXSPRITE_ALPHABLEND);
  308. if (FAILED(hr))
  309. {
  310. DXTraceW(__FILE__, __LINE__, hr, L"Sprite Begin Error", TRUE);
  311. return ;
  312. }
  313. // Doing Scaling of sprites here
  314. // If we do translations and/or rotations we'll have to do a more
  315. // robust hit test (picking) since the current one assumes a rectangular
  316. // shape based on screen coordinates. Only scaling is currently handled
  317. // in the hit test.
  318. //D3DXMATRIX scalingMatrix;
  319. //osdSprite->SetTransform(D3DXMatrixScaling(&scalingMatrix, 1.0f /*xScalingFactor*/, 1.0f /*yScalingFactor*/, 0.0f));
  320. hr = osdSprite->Draw(osdAtlasTexture, &osdBkgrndTextSrcCoords, NULL, &osdBkgrndPosition, D3DCOLOR_XRGB(255,255,255));
  321. if (FAILED(hr))
  322. {
  323. DRAW_OSD_SET_ERROR(L"Background Sprite Draw Error");
  324. goto DrawOSD_Error;
  325. }
  326. hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PREV_BUTTON), NULL, &osdPrevButtonPosition, D3DCOLOR_XRGB(255,255,255));
  327. if (FAILED(hr))
  328. {
  329. DRAW_OSD_SET_ERROR(L"Prev Button Sprite Draw Error");
  330. goto DrawOSD_Error;
  331. }
  332. hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PLAY_BUTTON), NULL, &osdPlayButtonPosition, D3DCOLOR_XRGB(255,255,255));
  333. if (FAILED(hr))
  334. {
  335. DRAW_OSD_SET_ERROR(L"Play Button Sprite Draw Error");
  336. goto DrawOSD_Error;
  337. }
  338. hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PAUSE_BUTTON), NULL, &osdPauseButtonPosition, D3DCOLOR_XRGB(255,255,255));
  339. if (FAILED(hr))
  340. {
  341. DRAW_OSD_SET_ERROR(L"Pause Button Sprite Draw Error");
  342. goto DrawOSD_Error;
  343. }
  344. hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(STOP_BUTTON), NULL, &osdStopButtonPosition, D3DCOLOR_XRGB(255,255,255));
  345. if (FAILED(hr))
  346. {
  347. DRAW_OSD_SET_ERROR(L"Stop Button Sprite Draw Error");
  348. goto DrawOSD_Error;
  349. }
  350. hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(NEXT_BUTTON), NULL, &osdNextButtonPosition, D3DCOLOR_XRGB(255,255,255));
  351. if (FAILED(hr))
  352. {
  353. DRAW_OSD_SET_ERROR(L"Next Button Sprite Draw Error");
  354. goto DrawOSD_Error;
  355. }
  356. hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PROGRESS_FRAME), NULL, &osdProgressFramePosition, D3DCOLOR_XRGB(255,255,255));
  357. if (FAILED(hr))
  358. {
  359. DRAW_OSD_SET_ERROR(L"Progress Frame Sprite Draw Error");
  360. goto DrawOSD_Error;
  361. }
  362. hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(VOLUME_FRAME), NULL, &osdVolumeFramePosition, D3DCOLOR_XRGB(255,255,255));
  363. if (FAILED(hr))
  364. {
  365. DRAW_OSD_SET_ERROR(L"Volume Frame Sprite Draw Error");
  366. goto DrawOSD_Error;
  367. }
  368. hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(ENDFS_BUTTON), NULL, &osdEndFSButtonPosition, D3DCOLOR_XRGB(255,255,255));
  369. if (FAILED(hr))
  370. {
  371. DRAW_OSD_SET_ERROR(L"EndFS Button Sprite Draw Error");
  372. goto DrawOSD_Error;
  373. }
  374. hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(MUTE_BUTTON), NULL, &osdMuteButtonPosition, D3DCOLOR_XRGB(255,255,255));
  375. if (FAILED(hr))
  376. {
  377. DRAW_OSD_SET_ERROR(L"Mute Button Sprite Draw Error");
  378. goto DrawOSD_Error;
  379. }
  380. if (playing && !streaming && !mouseDragging) // if mouseDragging we may be repositioning the slider, don't set it back till Lmouseup
  381. {
  382. // calculate the relative position of the slider
  383. float ppercent = (in_getouttime() / 1000.0f) / in_getlength();
  384. float sizeOfProgFrame = (float)osdProgressFrameHit.right - osdProgressFrameHit.left - 0;
  385. // position the progress slider
  386. osdProgressSliderPosition.x = osdProgressFramePosition.x + (sizeOfProgFrame * ppercent);
  387. // Now build the hit rect based on the new position.
  388. osdProgressSliderHit = BuildHitRect(osdProgressSliderPosition + D3DXVECTOR3(0.0f,0.0f,0.0f), osdProgressSliderNormalSrcCoords);
  389. }
  390. hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(PROGRESS_SLIDER), &sliderCenter, &osdProgressSliderPosition, D3DCOLOR_XRGB(255,255,255));
  391. if (FAILED(hr))
  392. {
  393. DRAW_OSD_SET_ERROR(L"Progress Slider Sprite Draw Error");
  394. goto DrawOSD_Error;
  395. }
  396. // Build the progress hilite line by drawing only a certain amount (width) of the texture.
  397. RECT seekProgress;
  398. // The progress hilite line goes on top of progress frame
  399. seekProgress = osdProgressProgressSrcCoords;
  400. // The width of the progress hilite line is determined by the location of the slider
  401. seekProgress.right = seekProgress.left + (osdProgressSliderHit.left - osdProgressFrameHit.left + 0);
  402. hr = osdSprite->Draw(osdAtlasTexture,
  403. &seekProgress,
  404. NULL,
  405. &osdProgressFramePosition,
  406. D3DCOLOR_XRGB(255,255,255));
  407. if (FAILED(hr))
  408. {
  409. DRAW_OSD_SET_ERROR(L"Seek Progress Sprite Draw Error");
  410. goto DrawOSD_Error;
  411. }
  412. if (!mouseDragging) // if mouseDragging we may be repositioning the slider, don't set it back till Lmouseup
  413. {
  414. // calculate the relative position of the slider
  415. float vpercent = config_volume / 255.0f;
  416. float sizeOfVolFrame = (float)osdVolumeFrameHit.right - osdVolumeFrameHit.left - 0;
  417. // position the volume slider
  418. osdVolumeSliderPosition.x = (osdVolumeFramePosition.x) + (sizeOfVolFrame * vpercent);
  419. // Now build the hit rect based on the new position.
  420. osdVolumeSliderHit = BuildHitRect(osdVolumeSliderPosition + D3DXVECTOR3(0.0f,0.0f,0.0f), osdVolumeSliderNormalSrcCoords);
  421. }
  422. hr = osdSprite->Draw(osdAtlasTexture, GetTextCoords(VOLUME_SLIDER), &sliderCenter, &osdVolumeSliderPosition, D3DCOLOR_XRGB(255,255,255));
  423. if (FAILED(hr))
  424. {
  425. DRAW_OSD_SET_ERROR(L"Volume SLider Sprite Draw Error");
  426. goto DrawOSD_Error;
  427. }
  428. // Build the volume hilite line by drawing only a certain amount (width) of the texture.
  429. RECT volProgress;
  430. // The volume hilite line goes on top of volume frame
  431. volProgress = osdVolumeProgressSrcCoords;
  432. // The width of the volume hilite line is determined by the location of the slider
  433. volProgress.right = volProgress.left + (osdVolumeSliderHit.left - osdVolumeFrameHit.left + 0);
  434. hr = osdSprite->Draw(osdAtlasTexture,
  435. &volProgress,
  436. NULL,
  437. &osdVolumeFramePosition,
  438. D3DCOLOR_XRGB(255,255,255));
  439. if (FAILED(hr))
  440. {
  441. DRAW_OSD_SET_ERROR(L"Volume Progress Sprite Draw Error");
  442. goto DrawOSD_Error;
  443. }
  444. if (osdTimeFont)
  445. {
  446. int seconds_in = in_getouttime() / 1000;
  447. int time_to_go = in_getlength();
  448. wchar_t timerText[256] = {0};
  449. if (streaming)
  450. StringCbPrintfW(timerText,sizeof(timerText),L"%.2u:%.2u",seconds_in /60,seconds_in % 60);
  451. else
  452. StringCbPrintfW(timerText,sizeof(timerText),L"%.2u:%.2u / %.2u:%.2u",seconds_in /60,seconds_in % 60,time_to_go / 60, time_to_go % 60);
  453. osdTimeFont->DrawTextW(osdSprite, timerText, -1, &osdTimeRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP, D3DCOLOR_XRGB(163,164,167)); // #A3A4A7
  454. }
  455. if (osdTitleFont)
  456. {
  457. // found possibility that user can pause in full screen and remove items from playlist
  458. // This prevents a crash by not trying to display a title.
  459. if (lstrlenW(FileTitle) > 0)
  460. {
  461. if (!titleFits)
  462. {
  463. // title does not fit, build marquee
  464. DWORD now = GetTickCount();
  465. static DWORD then;
  466. if (now - then > 250) // slow it down so people can read it.
  467. {
  468. static int charCount = 2; // start with the first char + 1 for null
  469. lstrcpynW(displayTitle,marqueeTitleSrc,charCount);
  470. charCount++;
  471. if (charCount > lstrlenW(marqueeTitleSrc))
  472. charCount = lstrlenW(FileTitle);
  473. then = now;
  474. }
  475. }
  476. osdTitleFont->DrawTextW(osdSprite, displayTitle, -1, &osdTitleRect, dtFormat, D3DCOLOR_XRGB(204,204,204)); // #cccccc
  477. }
  478. }
  479. hr = osdSprite->End();
  480. if (FAILED(hr))
  481. {
  482. DXTraceW(__FILE__, __LINE__, hr, L"Sprite End Error", TRUE);
  483. return;
  484. }
  485. return;
  486. DrawOSD_Error:
  487. DXTraceW(__FILE__, __LINE__, hr, draw_osd_error, TRUE);
  488. osdSprite->End();
  489. }
  490. RECT *IVideoD3DOSD::GetTextCoords(UI_ELEM item)
  491. {
  492. switch (item)
  493. {
  494. case PREV_BUTTON :
  495. switch (bState[item])
  496. {
  497. case NORMAL :
  498. return &osdPrevButtonNormalSrcCoords;
  499. break;
  500. case CLICKED :
  501. return &osdPrevButtonClickSrcCoords;
  502. break;
  503. case HILITE :
  504. return &osdPrevButtonHiliteSrcCoords;
  505. break;
  506. case DISABLED :
  507. return &osdPrevButtonDisabledSrcCoords;
  508. break;
  509. }
  510. break;
  511. case PLAY_BUTTON :
  512. switch (bState[item])
  513. {
  514. case NORMAL :
  515. case DISABLED :
  516. return &osdPlayButtonNormalSrcCoords;
  517. break;
  518. case CLICKED :
  519. return &osdPlayButtonClickSrcCoords;
  520. break;
  521. case HILITE :
  522. return &osdPlayButtonHiliteSrcCoords;
  523. break;
  524. }
  525. break;
  526. case PAUSE_BUTTON :
  527. switch (bState[item])
  528. {
  529. case NORMAL :
  530. case DISABLED :
  531. return &osdPauseButtonNormalSrcCoords;
  532. break;
  533. case CLICKED :
  534. return &osdPauseButtonClickSrcCoords;
  535. break;
  536. case HILITE :
  537. return &osdPauseButtonHiliteSrcCoords;
  538. break;
  539. }
  540. break;
  541. case STOP_BUTTON :
  542. switch (bState[item])
  543. {
  544. case NORMAL :
  545. case DISABLED :
  546. return &osdStopButtonNormalSrcCoords;
  547. break;
  548. case CLICKED :
  549. return &osdStopButtonClickSrcCoords;
  550. break;
  551. case HILITE :
  552. return &osdStopButtonHiliteSrcCoords;
  553. break;
  554. }
  555. break;
  556. case NEXT_BUTTON :
  557. switch (bState[item])
  558. {
  559. case NORMAL :
  560. return &osdNextButtonNormalSrcCoords;
  561. break;
  562. case CLICKED :
  563. return &osdNextButtonClickSrcCoords;
  564. break;
  565. case HILITE :
  566. return &osdNextButtonHiliteSrcCoords;
  567. break;
  568. case DISABLED :
  569. return &osdNextButtonDisabledSrcCoords;
  570. break;
  571. }
  572. break;
  573. case ENDFS_BUTTON :
  574. switch (bState[item])
  575. {
  576. case NORMAL :
  577. case DISABLED :
  578. return &osdEndFSButtonNormalSrcCoords;
  579. break;
  580. case CLICKED :
  581. return &osdEndFSButtonClickSrcCoords;
  582. break;
  583. case HILITE :
  584. return &osdEndFSButtonHiliteSrcCoords;
  585. break;
  586. }
  587. break;
  588. case MUTE_BUTTON :
  589. return &osdMuteButtonNormalSrcCoords;
  590. //switch (bState[item])
  591. //{
  592. //case NORMAL :
  593. //case DISABLED :
  594. // return &osdMuteButtonNormalSrcCoords;
  595. // break;
  596. //case CLICKED :
  597. // return &osdMuteButtonClickSrcCoords;
  598. // break;
  599. //case HILITE :
  600. // return &osdMuteButtonHiliteSrcCoords;
  601. // break;
  602. //}
  603. break;
  604. case PROGRESS_FRAME :
  605. return &osdProgressFrameNormalSrcCoords;
  606. break;
  607. case VOLUME_FRAME :
  608. return &osdVolumeFrameNormalSrcCoords;
  609. break;
  610. case PROGRESS_SLIDER :
  611. switch (bState[item])
  612. {
  613. case NORMAL :
  614. case DISABLED :
  615. return &osdProgressSliderNormalSrcCoords;
  616. break;
  617. case CLICKED :
  618. return &osdProgressSliderClickSrcCoords;
  619. break;
  620. case HILITE :
  621. return &osdProgressSliderHiliteSrcCoords;
  622. break;
  623. }
  624. break;
  625. case VOLUME_SLIDER :
  626. switch (bState[item])
  627. {
  628. case NORMAL :
  629. case DISABLED :
  630. return &osdVolumeSliderNormalSrcCoords;
  631. break;
  632. case CLICKED :
  633. return &osdVolumeSliderClickSrcCoords;
  634. break;
  635. case HILITE :
  636. return &osdVolumeSliderHiliteSrcCoords;
  637. break;
  638. }
  639. break;
  640. }
  641. return NULL;
  642. }
  643. void IVideoD3DOSD::LostOSD()
  644. {
  645. if (osdSprite)
  646. osdSprite->OnLostDevice();
  647. if (osdTimeFont)
  648. osdTimeFont->OnLostDevice();
  649. if (osdTitleFont)
  650. osdTitleFont->OnLostDevice();
  651. if (osdAtlasTexture)
  652. {
  653. osdAtlasTexture->Release();
  654. osdAtlasTexture = 0;
  655. }
  656. }
  657. void IVideoD3DOSD::ResetOSD(IDirect3DDevice9 * device)
  658. {
  659. if (osdSprite)
  660. osdSprite->OnResetDevice();
  661. if (osdTimeFont)
  662. osdTimeFont->OnResetDevice();
  663. if (osdTitleFont)
  664. osdTitleFont->OnResetDevice();
  665. if (device)
  666. {
  667. HRESULT hr;
  668. hr = pCreateTextureFromResourceExW(
  669. device,
  670. NULL, // HMODULE
  671. MAKEINTRESOURCEW(IDB_OSD), // Our texture image atlas
  672. D3DX_DEFAULT, // width
  673. D3DX_DEFAULT, // height
  674. 1, // MIP levels
  675. 0, // usage
  676. D3DFMT_UNKNOWN, // get format from file
  677. D3DPOOL_DEFAULT, // mem pool
  678. D3DX_DEFAULT, // filter
  679. D3DX_DEFAULT, // MIP filter
  680. 0, // transparent color key
  681. NULL, // image info struct
  682. NULL, // palette
  683. &osdAtlasTexture); // the returned texture, if success
  684. if (FAILED(hr))
  685. {
  686. DXTraceW(__FILE__, __LINE__, hr, L"CreateTextureFromFileEx Error", TRUE);
  687. return;
  688. }
  689. }
  690. }
  691. bool IVideoD3DOSD::MouseDown(int xpt, int ypt, WPARAM wParam)
  692. {
  693. Show();
  694. // mouseLastPressed is used during mouse up to verify that the up is on the
  695. // same UI element as the mouse down.
  696. mouseLastPressed = HitTest((float)xpt, (float)ypt);
  697. bState[mouseLastPressed] = CLICKED;
  698. return false;
  699. }
  700. bool IVideoD3DOSD::MouseMove(int ixpt, int iypt, WPARAM wParam)
  701. {
  702. static int saved_ixpt;
  703. static int saved_iypt;
  704. // Need to check whether the mouse cursor is still in the same place.
  705. // Evidently, WM_MOUSEMOVE can get triggered for other reasons than
  706. // actually moving the mouse, per Microsoft blogs
  707. // This code was triggering with IM and EMAIL notifications without
  708. // moving the mouse.
  709. if (ixpt == saved_ixpt && iypt == saved_iypt)
  710. return false;
  711. saved_ixpt = ixpt;
  712. saved_iypt = iypt;
  713. Show();
  714. // Change input ints to floats so later calculations are more precise.
  715. float xpt = (float)ixpt;
  716. float ypt = (float)iypt;
  717. mouseOver = HitTest((float)xpt, (float)ypt);
  718. if (wParam & MK_LBUTTON) //dragging
  719. {
  720. mouseDragging = true;
  721. if (mouseLastPressed == VOLUME_SLIDER)
  722. {
  723. if (xpt < (osdVolumeFrameHit.left)) xpt = (float) osdVolumeFrameHit.left;
  724. else if (xpt > (osdVolumeFrameHit.right) - 0) xpt = (float) osdVolumeFrameHit.right - 0;
  725. //move the volume slider
  726. osdVolumeSliderPosition.x = xpt;
  727. // slider uses center as center
  728. osdVolumeSliderHit = BuildHitRect(osdVolumeSliderPosition + D3DXVECTOR3(0.0f,0.0f,0.0f),osdVolumeSliderNormalSrcCoords);
  729. }
  730. else if (mouseLastPressed == PROGRESS_SLIDER)
  731. {
  732. if (xpt < osdProgressFrameHit.left) xpt = (float)osdProgressFrameHit.left;
  733. else if (xpt > (osdProgressFrameHit.right)) xpt = (float)osdProgressFrameHit.right;
  734. //move the progress slider
  735. osdProgressSliderPosition.x = xpt;
  736. osdProgressSliderHit = BuildHitRect(osdProgressSliderPosition + D3DXVECTOR3(0.0f,0.0f,0.0f),osdProgressSliderNormalSrcCoords);
  737. }
  738. } else // no click, just mousemove
  739. {
  740. mouseDragging = false;
  741. if (mouseLastOver != mouseOver)
  742. {
  743. if (bState[mouseLastOver] == HILITE)
  744. bState[mouseLastOver] = NORMAL;
  745. if (bState[mouseOver] == NORMAL)
  746. bState[mouseOver] = HILITE;
  747. mouseLastOver = mouseOver;
  748. }
  749. }
  750. return false;
  751. }
  752. bool IVideoD3DOSD::MouseUp(int xpt, int ypt, WPARAM wParam)
  753. {
  754. mousePressed = HitTest((float)xpt, (float)ypt);
  755. bState[mouseLastPressed] = NORMAL;
  756. if (bState[mousePressed] == HILITE)
  757. bState[mousePressed] = NORMAL;
  758. mouseDragging = false;
  759. switch (mousePressed)
  760. {
  761. case ENDFS_BUTTON :
  762. if (mouseLastPressed == ENDFS_BUTTON)
  763. return true; // end full screen
  764. break;
  765. case PREV_BUTTON :
  766. if (mouseLastPressed == PREV_BUTTON)
  767. PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON1, 0);
  768. break;
  769. case PLAY_BUTTON :
  770. if (mouseLastPressed == PLAY_BUTTON)
  771. PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON2, 0);
  772. break;
  773. case PAUSE_BUTTON :
  774. if (mouseLastPressed == PAUSE_BUTTON)
  775. PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON3, 0);
  776. break;
  777. case STOP_BUTTON :
  778. if (mouseLastPressed == STOP_BUTTON)
  779. PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON4, 0);
  780. break;
  781. case NEXT_BUTTON :
  782. if (mouseLastPressed == NEXT_BUTTON)
  783. PostMessageW(hMainWindow, WM_COMMAND, WINAMP_BUTTON5, 0);
  784. break;
  785. default :
  786. {
  787. // If not a button, check the sliders
  788. // The successful use of the sliders should not depend on
  789. // releasing the mouse inside the frame, which may be very small.
  790. switch (mouseLastPressed)
  791. {
  792. case PROGRESS_SLIDER :
  793. case PROGRESS_FRAME :
  794. {
  795. float xIntoFrame = (float)xpt - osdProgressFrameHit.left;
  796. // -8 is half the width of the slider
  797. float rightMaxOfFrame = (float)osdProgressFrameHit.right - 0;
  798. float leftMinOfFrame = (float)osdProgressFrameHit.left;
  799. float sizeOfFrame = rightMaxOfFrame - leftMinOfFrame;
  800. float t = xIntoFrame / sizeOfFrame;
  801. if (t < 0)
  802. t = 0;
  803. if (t > 1)
  804. t = 1;
  805. int len = in_getlength();
  806. in_seek((int)(t*len*1000));
  807. }
  808. break;
  809. case VOLUME_SLIDER :
  810. case VOLUME_FRAME :
  811. {
  812. float xIntoFrame = (float)xpt - (osdVolumeFrameHit.left);
  813. // -8 is half the width of the slider
  814. float rightMaxOfFrame = (float)osdVolumeFrameHit.right - 0;
  815. float leftMinOfFrame = (float)osdVolumeFrameHit.left;
  816. float sizeOfFrame = rightMaxOfFrame - leftMinOfFrame;
  817. float t = xIntoFrame / sizeOfFrame;
  818. if (t < 0)
  819. t = 0;
  820. if (t > 1)
  821. t = 1;
  822. unsigned char v = (unsigned char)(t * 255);
  823. config_volume = v;
  824. in_setvol(v);
  825. }
  826. break;
  827. }
  828. }
  829. break;
  830. }
  831. mouseLastPressed = NO_BUTTON;
  832. return false;
  833. }
  834. IVideoD3DOSD::UI_ELEM IVideoD3DOSD::HitTest(float xpt, float ypt)
  835. {
  836. if (PointInRect(xpt, ypt, osdPrevButtonHit))
  837. return PREV_BUTTON;
  838. else if (PointInRect(xpt, ypt, osdPlayButtonHit))
  839. return PLAY_BUTTON;
  840. else if (PointInRect(xpt, ypt, osdPauseButtonHit))
  841. return PAUSE_BUTTON;
  842. else if (PointInRect(xpt, ypt, osdStopButtonHit))
  843. return STOP_BUTTON;
  844. else if (PointInRect(xpt, ypt, osdNextButtonHit))
  845. return NEXT_BUTTON;
  846. else if (PointInRect(xpt, ypt, osdEndFSButtonHit))
  847. return ENDFS_BUTTON;
  848. else if (PointInRect(xpt, ypt, osdVolumeSliderHit))
  849. return VOLUME_SLIDER;
  850. else if (PointInRect(xpt, ypt, osdProgressSliderHit))
  851. return PROGRESS_SLIDER;
  852. else if (PointInRect(xpt, ypt, osdProgressFrameHit))
  853. return PROGRESS_FRAME;
  854. else if (PointInRect(xpt, ypt, osdVolumeFrameHit))
  855. return VOLUME_FRAME;
  856. else
  857. return NO_BUTTON;
  858. }
  859. bool IVideoD3DOSD::PointInRect(float x, float y, RECT testRect)
  860. {
  861. if ((x >= testRect.left) && (x <= testRect.right) &&
  862. (y >= testRect.top) && (y <= testRect.bottom))
  863. return true;
  864. else
  865. return false;
  866. }