pluginshell.cpp 118 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693
  1. /*
  2. LICENSE
  3. -------
  4. Copyright 2005-2013 Nullsoft, Inc.
  5. All rights reserved.
  6. Redistribution and use in source and binary forms, with or without modification,
  7. are permitted provided that the following conditions are met:
  8. * Redistributions of source code must retain the above copyright notice,
  9. this list of conditions and the following disclaimer.
  10. * Redistributions in binary form must reproduce the above copyright notice,
  11. this list of conditions and the following disclaimer in the documentation
  12. and/or other materials provided with the distribution.
  13. * Neither the name of Nullsoft nor the names of its contributors may be used to
  14. endorse or promote products derived from this software without specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  16. IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  18. CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  21. IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  22. OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. */
  24. /*
  25. TO DO
  26. -----
  27. -done/v1.06:
  28. -(nothing yet)
  29. -
  30. -
  31. -to do/v1.06:
  32. -FFT: high freq. data kinda sucks because of the 8-bit samples we get in;
  33. look for justin to put 16-bit vis data into wa5.
  34. -make an 'advanced view' button on config panel; hide complicated stuff
  35. til they click that.
  36. -put an asterisk(*) next to the 'max framerate' values that
  37. are ideal (given the current windows display mode or selected FS dispmode).
  38. -or add checkbox: "smart sync"
  39. -> matches FPS limit to nearest integer divisor of refresh rate.
  40. -debug.txt/logging support!
  41. -audio: make it a DSP plugin? then we could get the complete, continuous waveform
  42. and overlap our waveform windows, so we'd never miss a brief high note.
  43. -bugs:
  44. -vms plugins sometimes freeze after a several-minute pause; I've seen it
  45. with most of them. hard to repro, though.
  46. -running FS on monitor 2, hit ALT-TAB -> minimizes!!!
  47. -but only if you let go of TAB first. Let go of ALT first and it's fine!
  48. -> means it's related to the keyup...
  49. -fix delayloadhelper leak; one for each launch to config panel/plugin.
  50. -also, delayload(d3d9.dll) still leaks, if plugin has error initializing and
  51. quits by returning false from PluginInitialize().
  52. -add config panel option to ignore fake-fullscreen tips
  53. -"tip" boxes in dxcontext.cpp
  54. -"notice" box on WM_ACTIVATEAPP?
  55. -desktop mode:
  56. -icon context menus: 'send to', 'cut', and 'copy' links do nothing.
  57. -http://netez.com/2xExplorer/shellFAQ/bas_context.html
  58. -create a 2nd texture to render all icon text labels into
  59. (they're the sole reason that desktop mode is slow)
  60. -in UpdateIconBitmaps, don't read the whole bitmap and THEN
  61. realize it's a dupe; try to compare icon filename+index or somethign?
  62. -DRAG AND DROP. COMPLICATED; MANY DETAILS.
  63. -http://netez.com/2xExplorer/shellFAQ/adv_drag.html
  64. -http://www.codeproject.com/shell/explorerdragdrop.asp
  65. -hmm... you can't drag icons between the 2 desktops (ugh)
  66. -multiple delete/open/props/etc
  67. -delete + enter + arrow keys.
  68. -try to solve mysteries w/ShellExecuteEx() and desktop *shortcuts* (*.lnk).
  69. -(notice that when icons are selected, they get modulated by the
  70. highlight color, when they should be blended 50% with that color.)
  71. ---------------------------
  72. final touches:
  73. -Tests:
  74. -make sure desktop still functions/responds properly when winamp paused
  75. -desktop mode + multimon:
  76. -try desktop mode on all monitors
  77. -try moving taskbar around; make sure icons are in the
  78. right place, that context menus (general & for
  79. specific icons) pop up in the right place, and that
  80. text-off-left-edge is ok.
  81. -try setting the 2 monitors to different/same resolutions
  82. -check tab order of config panel controls!
  83. -Clean All
  84. -build in release mode to include in the ZIP
  85. -leave only one file open in workspace: README.TXT.
  86. -TEMPORARILY "ATTRIB -R" ALL FILES BEFORE ZIPPING THEM!
  87. ---------------------------
  88. KEEP IN VIEW:
  89. -EMBEDWND:
  90. -kiv: on resize of embedwnd, it's out of our control; winamp
  91. resizes the child every time the mouse position changes,
  92. and we have to cleanup & reallocate everything, b/c we
  93. can't tell when the resize begins & ends.
  94. [justin said he'd fix in wa5, though]
  95. -kiv: with embedded windows of any type (plugin, playlist, etc.)
  96. you can't place the winamp main wnd over them.
  97. -kiv: embedded windows are child windows and don't get the
  98. WM_SETFOCUS or WM_KILLFOCUS messages when they get or lose
  99. the focus. (For a workaround, see milkdrop & scroll lock key.)
  100. -kiv: tiny bug (IGNORE): when switching between embedwnd &
  101. no-embedding, the window gets scooted a tiny tiny bit.
  102. -kiv: fake fullscreen mode w/multiple monitors: there is no way
  103. to keep the taskbar from popping up [potentially overtop of
  104. the plugin] when you click on something besides the plugin.
  105. To get around this, use true fullscreen mode.
  106. -kiv: max_fps implementation assumptions:
  107. -that most computers support high-precision timer
  108. -that no computers [regularly] sleep for more than 1-2 ms
  109. when you call Sleep(1) after timeBeginPeriod(1).
  110. -reminder: if vms_desktop.dll's interface needs changed,
  111. it will have to be renamed! (version # upgrades are ok
  112. as long as it won't break on an old version; if the
  113. new functionality is essential, rename the DLL.)
  114. ---------------------------
  115. REMEMBER:
  116. -GF2MX + GF4 have icon scooting probs in desktop mode
  117. (when taskbar is on upper or left edge of screen)
  118. -Radeon is the one w/super slow text probs @ 1280x1024.
  119. (it goes unstable after you show playlist AND helpscr; -> ~1 fps)
  120. -Mark's win98 machine has hidden cursor (in all modes),
  121. but no one else seems to have this problem.
  122. -links:
  123. -win2k-only-style desktop mode: (uses VirtualAllocEx, vs. DLL Injection)
  124. http://www.digiwar.com/scripts/renderpage.php?section=2&subsection=2
  125. -http://www.experts-exchange.com/Programming/Programming_Platforms/Win_Prog/Q_20096218.html
  126. */
  127. #include "api__vis_milk2.h"
  128. #include "pluginshell.h"
  129. #include "utility.h"
  130. #include "defines.h"
  131. #include "shell_defines.h"
  132. #include "resource.h"
  133. #include "vis.h"
  134. #include <multimon.h>
  135. #include "../Winamp/wa_ipc.h"
  136. #include "../nu/AutoCharFn.h"
  137. #include <mmsystem.h>
  138. #pragma comment(lib,"winmm.lib") // for timeGetTime
  139. // STATE VALUES & VERTEX FORMATS FOR HELP SCREEN TEXTURE:
  140. #define TEXT_SURFACE_NOT_READY 0
  141. #define TEXT_SURFACE_REQUESTED 1
  142. #define TEXT_SURFACE_READY 2
  143. #define TEXT_SURFACE_ERROR 3
  144. typedef struct _HELPVERTEX
  145. {
  146. float x, y; // screen position
  147. float z; // Z-buffer depth
  148. DWORD Diffuse; // diffuse color. also acts as filler; aligns struct to 16 bytes (good for random access/indexed prims)
  149. float tu, tv; // texture coordinates for texture #0
  150. } HELPVERTEX, *LPHELPVERTEX;
  151. #define HELP_VERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
  152. typedef struct _SIMPLEVERTEX
  153. {
  154. float x, y; // screen position
  155. float z; // Z-buffer depth
  156. DWORD Diffuse; // diffuse color. also acts as filler; aligns struct to 16 bytes (good for random access/indexed prims)
  157. } SIMPLEVERTEX, *LPSIMPLEVERTEX;
  158. #define SIMPLE_VERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE)
  159. extern wchar_t* g_szHelp;
  160. extern int g_szHelp_W;
  161. extern winampVisModule mod1;
  162. // resides in vms_desktop.dll/lib:
  163. void getItemData(int x);
  164. CPluginShell::CPluginShell()
  165. {
  166. // this should remain empty!
  167. }
  168. CPluginShell::~CPluginShell()
  169. {
  170. // this should remain empty!
  171. }
  172. eScrMode CPluginShell::GetScreenMode()
  173. {
  174. return m_screenmode;
  175. }
  176. int CPluginShell::GetFrame()
  177. {
  178. return m_frame;
  179. }
  180. float CPluginShell::GetTime()
  181. {
  182. return m_time;
  183. }
  184. float CPluginShell::GetFps()
  185. {
  186. return m_fps;
  187. }
  188. HWND CPluginShell::GetPluginWindow()
  189. {
  190. if (m_lpDX) return m_lpDX->GetHwnd(); else return NULL;
  191. }
  192. int CPluginShell::GetWidth()
  193. {
  194. if (m_lpDX) return m_lpDX->m_client_width; else return 0;
  195. }
  196. int CPluginShell::GetHeight()
  197. {
  198. if (m_lpDX) return m_lpDX->m_client_height; else return 0;
  199. }
  200. int CPluginShell::GetCanvasMarginX()
  201. {
  202. if (m_lpDX && m_screenmode==WINDOWED) return (m_lpDX->m_client_width - m_lpDX->m_REAL_client_width)/2; else return 0;
  203. }
  204. int CPluginShell::GetCanvasMarginY()
  205. {
  206. if (m_lpDX && m_screenmode==WINDOWED) return (m_lpDX->m_client_height - m_lpDX->m_REAL_client_height)/2; else return 0;
  207. }
  208. HWND CPluginShell::GetWinampWindow()
  209. {
  210. return m_hWndWinamp;
  211. }
  212. HINSTANCE CPluginShell::GetInstance()
  213. {
  214. return m_hInstance;
  215. }
  216. wchar_t* CPluginShell::GetPluginsDirPath()
  217. {
  218. return m_szPluginsDirPath;
  219. }
  220. wchar_t* CPluginShell::GetConfigIniFile()
  221. {
  222. return m_szConfigIniFile;
  223. }
  224. char* CPluginShell::GetConfigIniFileA()
  225. {
  226. return m_szConfigIniFileA;
  227. }
  228. int CPluginShell::GetFontHeight(eFontIndex idx)
  229. {
  230. if (idx >= 0 && idx < NUM_BASIC_FONTS + NUM_EXTRA_FONTS) return m_fontinfo[idx].nSize; else return 0;
  231. }
  232. int CPluginShell::GetBitDepth()
  233. {
  234. return m_lpDX->GetBitDepth();
  235. }
  236. LPDIRECT3DDEVICE9 CPluginShell::GetDevice()
  237. {
  238. if (m_lpDX) return m_lpDX->m_lpDevice; else return NULL;
  239. }
  240. D3DCAPS9* CPluginShell::GetCaps()
  241. {
  242. if (m_lpDX) return &(m_lpDX->m_caps); else return NULL;
  243. }
  244. D3DFORMAT CPluginShell::GetBackBufFormat()
  245. {
  246. if (m_lpDX) return m_lpDX->m_current_mode.display_mode.Format; else return D3DFMT_UNKNOWN;
  247. }
  248. D3DFORMAT CPluginShell::GetBackBufZFormat()
  249. {
  250. if (m_lpDX) return m_lpDX->GetZFormat(); else return D3DFMT_UNKNOWN;
  251. }
  252. LPD3DXFONT CPluginShell::GetFont(eFontIndex idx)
  253. {
  254. if (idx >= 0 && idx < NUM_BASIC_FONTS + NUM_EXTRA_FONTS) return m_d3dx_font[idx]; else return NULL;
  255. }
  256. char* CPluginShell::GetDriverFilename()
  257. {
  258. if (m_lpDX) return m_lpDX->GetDriver(); else return NULL;
  259. }
  260. char* CPluginShell::GetDriverDescription()
  261. {
  262. if (m_lpDX) return m_lpDX->GetDesc(); else return NULL;
  263. }
  264. int CPluginShell::InitNondx9Stuff()
  265. {
  266. timeBeginPeriod(1);
  267. m_fftobj.Init(576, NUM_FREQUENCIES);
  268. if (!InitGDIStuff()) return false;
  269. return AllocateMyNonDx9Stuff();
  270. }
  271. void CPluginShell::CleanUpNondx9Stuff()
  272. {
  273. timeEndPeriod(1);
  274. CleanUpMyNonDx9Stuff();
  275. CleanUpGDIStuff();
  276. m_fftobj.CleanUp();
  277. }
  278. int CPluginShell::InitGDIStuff()
  279. {
  280. wchar_t title[64];
  281. // note: messagebox parent window should be NULL here, because lpDX is still NULL!
  282. for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++)
  283. {
  284. if (!(m_font[i] = CreateFontW(m_fontinfo[i].nSize, 0, 0, 0, m_fontinfo[i].bBold ? 900 : 400, m_fontinfo[i].bItalic, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, m_fontinfo[i].bAntiAliased ? ANTIALIASED_QUALITY : DEFAULT_QUALITY, DEFAULT_PITCH, m_fontinfo[i].szFace)))
  285. {
  286. MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_GDI_FONTS),
  287. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
  288. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  289. return false;
  290. }
  291. }
  292. if (!(m_main_menu = WASABI_API_LOADMENU(IDR_WINDOWED_CONTEXT_MENU)))
  293. {
  294. MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_LOADING_MAIN_MENU),
  295. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
  296. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  297. return false;
  298. }
  299. if (!(m_context_menu = GetSubMenu(m_main_menu, 0)))
  300. {
  301. MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_LOADING_CONTEXT_MENU),
  302. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
  303. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  304. return false;
  305. }
  306. return true;
  307. }
  308. void CPluginShell::CleanUpGDIStuff()
  309. {
  310. for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++)
  311. {
  312. if (m_font[i])
  313. {
  314. DeleteObject(m_font[i]);
  315. m_font[i] = NULL;
  316. }
  317. }
  318. /*if (m_context_menu)
  319. {
  320. DestroyMenu(m_context_menu);
  321. m_context_menu = NULL;
  322. }*/
  323. if (m_main_menu)
  324. {
  325. DestroyMenu(m_main_menu);
  326. m_main_menu = NULL;
  327. }
  328. //CleanUpMyGDIStuff();
  329. }
  330. int CPluginShell::InitVJStuff(RECT* pClientRect)
  331. {
  332. wchar_t title[64];
  333. // Init VJ mode (second window for text):
  334. if (m_vj_mode)
  335. {
  336. DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_SYSMENU;
  337. POINT upper_left_corner;
  338. upper_left_corner.x = 0;
  339. upper_left_corner.y = 0;
  340. // Create direct 3d & get some infos
  341. if (!(m_vjd3d9 = Direct3DCreate9(D3D_SDK_VERSION)))
  342. {
  343. MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_DIRECT3D_DEVICE_FOR_VJ_MODE),
  344. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  345. return false;
  346. }
  347. // Get ordinal adapter # for the currently-selected Windowed Mode display adapter
  348. int ordinal_adapter = D3DADAPTER_DEFAULT;
  349. int nAdapters = m_vjd3d9->GetAdapterCount();
  350. for (int i=0; i<nAdapters; i++)
  351. {
  352. D3DADAPTER_IDENTIFIER9 temp;
  353. if ((m_vjd3d9->GetAdapterIdentifier(i, /*D3DENUM_NO_WHQL_LEVEL*/ 0, &temp) == D3D_OK) &&
  354. (memcmp(&temp.DeviceIdentifier, &m_adapter_guid_windowed, sizeof(GUID))==0))
  355. {
  356. ordinal_adapter = i;
  357. break;
  358. }
  359. }
  360. // Get current display mode for windowed-mode adapter:
  361. D3DDISPLAYMODE dm;
  362. if (D3D_OK != m_vjd3d9->GetAdapterDisplayMode(ordinal_adapter, &dm))
  363. {
  364. MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_VJ_MODE_INIT_ERROR),
  365. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
  366. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  367. return false;
  368. }
  369. // And get the upper-left corner of the monitor for it:
  370. HMONITOR hMon = m_vjd3d9->GetAdapterMonitor(ordinal_adapter);
  371. if (hMon)
  372. {
  373. MONITORINFO mi;
  374. mi.cbSize = sizeof(mi);
  375. if (GetMonitorInfo(hMon, &mi))
  376. {
  377. upper_left_corner.x = mi.rcWork.left;
  378. upper_left_corner.y = mi.rcWork.top;
  379. }
  380. }
  381. // CREATE THE WINDOW
  382. RECT rect;
  383. if (pClientRect)
  384. {
  385. rect = *pClientRect;
  386. AdjustWindowRect(&rect, dwStyle, 0); // convert client->wnd
  387. }
  388. else
  389. {
  390. SetRect(&rect, 0, 0, 384, 384);
  391. AdjustWindowRect(&rect, dwStyle, 0); // convert client->wnd
  392. rect.right -= rect.left;
  393. rect.left = 0;
  394. rect.bottom -= rect.top;
  395. rect.top = 0;
  396. rect.top += upper_left_corner.y+32;
  397. rect.left += upper_left_corner.x+32;
  398. rect.right += upper_left_corner.x+32;
  399. rect.bottom += upper_left_corner.y+32;
  400. }
  401. WNDCLASS wc = {0};
  402. wc.lpfnWndProc = VJModeWndProc; // our window procedure
  403. wc.hInstance = GetInstance(); // hInstance of DLL
  404. wc.hIcon = LoadIcon(GetInstance(), MAKEINTRESOURCE(IDI_PLUGIN_ICON));
  405. wc.lpszClassName = TEXT_WINDOW_CLASSNAME; // our window class name
  406. wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; // CS_DBLCLKS lets the window receive WM_LBUTTONDBLCLK, for toggling fullscreen mode...
  407. wc.cbWndExtra = sizeof(DWORD);
  408. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  409. wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
  410. if (!RegisterClass(&wc))
  411. {
  412. MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_REGISTERING_WINDOW_CLASS_FOR_TEXT_WINDOW),
  413. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
  414. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  415. return false;
  416. }
  417. m_bTextWindowClassRegistered = true;
  418. //DWORD nThreadID;
  419. //CreateThread(NULL, 0, TextWindowThread, &rect, 0, &nThreadID);
  420. // Create the text window
  421. m_hTextWnd = CreateWindowEx(
  422. 0,
  423. TEXT_WINDOW_CLASSNAME, // our window class name
  424. TEXT_WINDOW_CLASSNAME, // use description for a window title
  425. dwStyle,
  426. rect.left, rect.top, // screen position (read from config)
  427. rect.right - rect.left, rect.bottom - rect.top, // width & height of window (need to adjust client area later)
  428. NULL, // parent window (winamp main window)
  429. NULL, // no menu
  430. GetInstance(), // hInstance of DLL
  431. NULL
  432. ); // no window creation data
  433. if (!m_hTextWnd)
  434. {
  435. MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_VJ_WINDOW),
  436. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
  437. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  438. return false;
  439. }
  440. SetWindowLongPtr(m_hTextWnd, GWLP_USERDATA, (LONG_PTR)this);
  441. GetClientRect(m_hTextWnd, &rect);
  442. m_nTextWndWidth = rect.right-rect.left;
  443. m_nTextWndHeight = rect.bottom-rect.top;
  444. // Create the device
  445. D3DPRESENT_PARAMETERS pres_param;
  446. ZeroMemory(&pres_param,sizeof(pres_param));
  447. pres_param.BackBufferCount = 0;
  448. pres_param.BackBufferFormat = dm.Format;
  449. pres_param.BackBufferWidth = rect.right - rect.left;
  450. pres_param.BackBufferHeight = rect.bottom - rect.top;
  451. pres_param.hDeviceWindow = m_hTextWnd;
  452. pres_param.AutoDepthStencilFormat = D3DFMT_D16;
  453. pres_param.EnableAutoDepthStencil = FALSE;
  454. pres_param.SwapEffect = D3DSWAPEFFECT_DISCARD;
  455. pres_param.MultiSampleType = D3DMULTISAMPLE_NONE;
  456. pres_param.Flags = 0;
  457. pres_param.FullScreen_RefreshRateInHz = 0;
  458. pres_param.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;//D3DPRESENT_INTERVAL_ONE;//D3DPRESENT_INTERVAL_IMMEDIATE;//m_current_mode.allow_page_tearing ? D3DPRESENT_INTERVAL_IMMEDIATE : D3DPRESENT_INTERVAL_ONE;//D3DPRESENT_INTERVAL_IMMEDIATE;//D3DPRESENT_INTERVAL_ONE;
  459. //pres_param.FullScreen_PresentationInterval = 0;
  460. pres_param.Windowed = TRUE;
  461. HRESULT hr;
  462. if (D3D_OK != (hr = m_vjd3d9->CreateDevice(ordinal_adapter,//D3DADAPTER_DEFAULT,
  463. D3DDEVTYPE_HAL,
  464. m_hTextWnd,
  465. D3DCREATE_SOFTWARE_VERTEXPROCESSING,
  466. &pres_param,
  467. &m_vjd3d9_device)))
  468. {
  469. m_vjd3d9_device = NULL;
  470. MessageBoxW(m_lpDX->GetHwnd(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_D3D_DEVICE_FOR_VJ_MODE),
  471. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
  472. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  473. return false;
  474. }
  475. if (!AllocateFonts(m_vjd3d9_device))
  476. return false;
  477. if (m_fix_slow_text) // note that when not doing vj mode, m_lpDDSText is allocated in AllocateDX9Stuff
  478. AllocateTextSurface();
  479. m_text.Finish();
  480. m_text.Init(m_vjd3d9_device, m_lpDDSText, 0);
  481. m_bClearVJWindow = true;
  482. }
  483. return true;
  484. }
  485. void CPluginShell::CleanUpVJStuff()
  486. {
  487. // ALWAYS set the textures to NULL before releasing textures,
  488. // otherwise they might still have a hanging reference!
  489. if (m_lpDX && m_lpDX->m_lpDevice)
  490. {
  491. for (int i=0; i<16; i++)
  492. m_lpDX->m_lpDevice->SetTexture(i, NULL);
  493. }
  494. if (m_vjd3d9_device)
  495. {
  496. for (int i=0; i<16; i++)
  497. m_vjd3d9_device->SetTexture(i, NULL);
  498. }
  499. if (!m_vj_mode)
  500. return;
  501. // clean up VJ mode
  502. {
  503. CleanUpFonts();
  504. SafeRelease(m_lpDDSText);
  505. SafeRelease(m_vjd3d9_device);
  506. SafeRelease(m_vjd3d9);
  507. if (m_hTextWnd)
  508. {
  509. //dumpmsg("Finish: destroying text window");
  510. DestroyWindow(m_hTextWnd);
  511. m_hTextWnd = NULL;
  512. //dumpmsg("Finish: text window destroyed");
  513. }
  514. if (m_bTextWindowClassRegistered)
  515. {
  516. //dumpmsg("Finish: unregistering text window class");
  517. UnregisterClass(TEXT_WINDOW_CLASSNAME,GetInstance()); // unregister window class
  518. m_bTextWindowClassRegistered = false;
  519. //dumpmsg("Finish: text window class unregistered");
  520. }
  521. }
  522. }
  523. int CPluginShell::AllocateFonts(IDirect3DDevice9* pDevice)
  524. {
  525. // Create D3DX system font:
  526. for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++)
  527. if (pCreateFontW(pDevice, //m_font[i],
  528. m_fontinfo[i].nSize,
  529. m_fontinfo[i].nSize*4/10,
  530. m_fontinfo[i].bBold ? 900 : 400,
  531. 1, // mip levels
  532. m_fontinfo[i].bItalic,
  533. DEFAULT_CHARSET,
  534. OUT_DEFAULT_PRECIS,
  535. m_fontinfo[i].bAntiAliased ? ANTIALIASED_QUALITY : DEFAULT_QUALITY,
  536. DEFAULT_PITCH,
  537. m_fontinfo[i].szFace,
  538. &m_d3dx_font[i]
  539. ) != D3D_OK)
  540. {
  541. wchar_t title[64];
  542. MessageBoxW(m_lpDX ? m_lpDX->GetHwnd() : NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_D3DX_FONTS),
  543. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
  544. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  545. return false;
  546. }
  547. // get actual font heights
  548. for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++)
  549. {
  550. RECT r;
  551. SetRect(&r, 0, 0, 1024, 1024);
  552. int h = m_d3dx_font[i]->DrawText(NULL, "M", -1, &r, DT_CALCRECT, 0xFFFFFFFF);
  553. if (h>0) m_fontinfo[i].nSize = h;
  554. }
  555. return true;
  556. }
  557. void CPluginShell::CleanUpFonts()
  558. {
  559. for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++)
  560. SafeRelease(m_d3dx_font[i]);
  561. }
  562. void CPluginShell::AllocateTextSurface()
  563. {
  564. IDirect3DDevice9 *pDevice = m_vjd3d9_device ? m_vjd3d9_device : GetDevice();
  565. int w = m_vjd3d9_device ? m_nTextWndWidth : GetWidth() ;
  566. int h = m_vjd3d9_device ? m_nTextWndHeight : GetHeight();
  567. if (D3D_OK != pCreateTexture(pDevice, w, h, 1, D3DUSAGE_RENDERTARGET, GetBackBufFormat(), D3DPOOL_DEFAULT, &m_lpDDSText))
  568. m_lpDDSText = NULL; // OK if there's not enough mem for it!
  569. else
  570. {
  571. // if m_lpDDSText doesn't cover enough of screen, cancel it.
  572. D3DSURFACE_DESC desc;
  573. if (D3D_OK == m_lpDDSText->GetLevelDesc(0, &desc))
  574. {
  575. if ((desc.Width < 256 && w >= 256) ||
  576. (desc.Height < 256 && h >= 256) ||
  577. (desc.Width /(float)w < 0.74f) ||
  578. (desc.Height/(float)h < 0.74f)
  579. )
  580. {
  581. m_lpDDSText->Release();
  582. m_lpDDSText = NULL;
  583. }
  584. }
  585. }
  586. }
  587. int CPluginShell::AllocateDX9Stuff()
  588. {
  589. if (!m_vj_mode)
  590. {
  591. AllocateFonts(m_lpDX->m_lpDevice);
  592. if (m_fix_slow_text) // note that when not doing vj mode, m_lpDDSText is allocated in AllocateDX9Stuff
  593. AllocateTextSurface();
  594. }
  595. /*
  596. // Create D3DX system font:
  597. for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++)
  598. if (pCreateFontW(m_lpDX->m_lpDevice,
  599. m_fontinfo[i].nSize,
  600. m_fontinfo[i].nSize*4/10,
  601. m_fontinfo[i].bBold ? 900 : 400,
  602. 0, // mip levels
  603. m_fontinfo[i].bItalic,
  604. DEFAULT_CHARSET,
  605. OUT_DEFAULT_PRECIS,
  606. m_fontinfo[i].bAntiAliased ? ANTIALIASED_QUALITY : DEFAULT_QUALITY,
  607. DEFAULT_PITCH,
  608. m_fontinfo[i].szFace,
  609. &m_d3dx_font[i]
  610. ) != D3D_OK)
  611. {
  612. MessageBox(m_lpDX->GetHwnd(), "Error creating D3DX fonts", "ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  613. return false;
  614. }
  615. // get actual font heights
  616. for (i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++)
  617. {
  618. RECT r;
  619. SetRect(&r, 0, 0, 1024, 1024);
  620. int h = m_d3dx_font[i]->DrawText(NULL, "M", -1, &r, DT_CALCRECT, 0xFFFFFFFF);
  621. if (h>0) m_fontinfo[i].nSize = h;
  622. }
  623. */
  624. if (m_screenmode == DESKTOP)
  625. if (!InitDesktopMode())
  626. return false;
  627. int ret = AllocateMyDX9Stuff();
  628. // invalidate various 'caches' here:
  629. m_playlist_top_idx = -1; // invalidating playlist cache forces recompute of playlist width
  630. //m_icon_list.clear(); // clear desktop mode icon list, so it has to read the bitmaps back in
  631. if (!m_vj_mode)
  632. {
  633. m_text.Finish();
  634. m_text.Init(GetDevice(), m_lpDDSText, 1);
  635. }
  636. return ret;
  637. }
  638. void CPluginShell::CleanUpDX9Stuff(int final_cleanup)
  639. {
  640. // ALWAYS unbind the textures before releasing textures,
  641. // otherwise they might still have a hanging reference!
  642. if (m_lpDX && m_lpDX->m_lpDevice)
  643. {
  644. for (int i=0; i<16; i++)
  645. m_lpDX->m_lpDevice->SetTexture(i, NULL);
  646. }
  647. if (m_screenmode == DESKTOP)
  648. CleanUpDesktopMode();
  649. if (!m_vj_mode)
  650. {
  651. for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++)
  652. SafeRelease(m_d3dx_font[i]);
  653. SafeRelease(m_lpDDSText);
  654. }
  655. CleanUpMyDX9Stuff(final_cleanup);
  656. }
  657. void CPluginShell::OnUserResizeTextWindow()
  658. {
  659. // Update window properties
  660. RECT w, c;
  661. GetWindowRect(m_hTextWnd, &w);
  662. GetClientRect(m_hTextWnd, &c);
  663. WINDOWPLACEMENT wp;
  664. ZeroMemory(&wp, sizeof(wp));
  665. wp.length = sizeof(wp);
  666. GetWindowPlacement(m_hTextWnd, &wp);
  667. // convert client rect from client coords to screen coords:
  668. // (window rect is already in screen coords...)
  669. POINT p;
  670. p.x = c.left;
  671. p.y = c.top;
  672. if (ClientToScreen(m_hTextWnd, &p))
  673. {
  674. c.left += p.x;
  675. c.right += p.x;
  676. c.top += p.y;
  677. c.bottom += p.y;
  678. }
  679. if (wp.showCmd != SW_SHOWMINIMIZED)
  680. {
  681. if (m_nTextWndWidth != c.right-c.left ||
  682. m_nTextWndHeight != c.bottom-c.top)
  683. {
  684. CleanUpVJStuff();
  685. if (!InitVJStuff(&c))
  686. {
  687. SuggestHowToFreeSomeMem();
  688. m_lpDX->m_ready = false; // flag to exit
  689. return;
  690. }
  691. }
  692. // save the new window position:
  693. //if (wp.showCmd==SW_SHOWNORMAL)
  694. // SaveTextWindowPos();
  695. }
  696. }
  697. void CPluginShell::OnUserResizeWindow()
  698. {
  699. // Update window properties
  700. RECT w, c;
  701. GetWindowRect(m_lpDX->GetHwnd(), &w);
  702. GetClientRect(m_lpDX->GetHwnd(), &c);
  703. WINDOWPLACEMENT wp;
  704. ZeroMemory(&wp, sizeof(wp));
  705. wp.length = sizeof(wp);
  706. GetWindowPlacement(m_lpDX->GetHwnd(), &wp);
  707. // convert client rect from client coords to screen coords:
  708. // (window rect is already in screen coords...)
  709. POINT p;
  710. p.x = c.left;
  711. p.y = c.top;
  712. if (ClientToScreen(m_lpDX->GetHwnd(), &p))
  713. {
  714. c.left += p.x;
  715. c.right += p.x;
  716. c.top += p.y;
  717. c.bottom += p.y;
  718. }
  719. if (wp.showCmd != SW_SHOWMINIMIZED)
  720. {
  721. int new_REAL_client_w = c.right-c.left;
  722. int new_REAL_client_h = c.bottom-c.top;
  723. // kiv: could we just resize when the *snapped* w/h changes? slightly more ideal...
  724. if (m_lpDX->m_REAL_client_width != new_REAL_client_w ||
  725. m_lpDX->m_REAL_client_height != new_REAL_client_h)
  726. {
  727. //CleanUpVJStuff();
  728. CleanUpDX9Stuff(0);
  729. if (!m_lpDX->OnUserResizeWindow(&w, &c))
  730. {
  731. // note: a basic warning messagebox will have already been given.
  732. // now suggest specific advice on how to regain more video memory:
  733. SuggestHowToFreeSomeMem();
  734. return;
  735. }
  736. if (!AllocateDX9Stuff())
  737. {
  738. m_lpDX->m_ready = false; // flag to exit
  739. return;
  740. }
  741. /*if (!InitVJStuff())
  742. {
  743. m_lpDX->m_ready = false; // flag to exit
  744. return;
  745. }*/
  746. }
  747. // save the new window position:
  748. if (wp.showCmd==SW_SHOWNORMAL)
  749. m_lpDX->SaveWindow();
  750. }
  751. }
  752. void CPluginShell::StuffParams(DXCONTEXT_PARAMS *pParams)
  753. {
  754. pParams->screenmode = m_screenmode;
  755. pParams->display_mode = m_disp_mode_fs;
  756. pParams->nbackbuf = 1;
  757. pParams->m_dualhead_horz = m_dualhead_horz;
  758. pParams->m_dualhead_vert = m_dualhead_vert;
  759. pParams->m_skin = (m_screenmode==WINDOWED) ? m_skin : 0;
  760. switch (m_screenmode)
  761. {
  762. case WINDOWED:
  763. pParams->allow_page_tearing = m_allow_page_tearing_w;
  764. pParams->adapter_guid = m_adapter_guid_windowed;
  765. pParams->multisamp = m_multisample_windowed;
  766. strcpy(pParams->adapter_devicename, m_adapter_devicename_windowed);
  767. break;
  768. case FULLSCREEN:
  769. case FAKE_FULLSCREEN:
  770. pParams->allow_page_tearing = m_allow_page_tearing_fs;
  771. pParams->adapter_guid = m_adapter_guid_fullscreen;
  772. pParams->multisamp = m_multisample_fullscreen;
  773. strcpy(pParams->adapter_devicename, m_adapter_devicename_fullscreen);
  774. break;
  775. case DESKTOP:
  776. pParams->allow_page_tearing = m_allow_page_tearing_dm;
  777. pParams->adapter_guid = m_adapter_guid_desktop;
  778. pParams->multisamp = m_multisample_desktop;
  779. strcpy(pParams->adapter_devicename, m_adapter_devicename_desktop);
  780. break;
  781. }
  782. pParams->parent_window = (m_screenmode==DESKTOP) ? m_hWndDesktopListView : NULL;
  783. }
  784. void CPluginShell::ToggleDesktop()
  785. {
  786. CleanUpDX9Stuff(0);
  787. switch (m_screenmode)
  788. {
  789. case WINDOWED:
  790. case FULLSCREEN:
  791. case FAKE_FULLSCREEN:
  792. m_screenmode = DESKTOP;
  793. break;
  794. case DESKTOP:
  795. m_screenmode = WINDOWED;
  796. break;
  797. }
  798. DXCONTEXT_PARAMS params;
  799. StuffParams(&params);
  800. if (!m_lpDX->StartOrRestartDevice(&params))
  801. {
  802. // note: a basic warning messagebox will have already been given.
  803. if (m_lpDX->m_lastErr == DXC_ERR_CREATEDEV_PROBABLY_OUTOFVIDEOMEMORY)
  804. SuggestHowToFreeSomeMem();
  805. return;
  806. }
  807. if (!AllocateDX9Stuff())
  808. {
  809. m_lpDX->m_ready = false; // flag to exit
  810. return;
  811. }
  812. SetForegroundWindow(m_lpDX->GetHwnd());
  813. SetActiveWindow(m_lpDX->GetHwnd());
  814. SetFocus(m_lpDX->GetHwnd());
  815. }
  816. #define IPC_IS_PLAYING_VIDEO 501 // from wa_ipc.h
  817. #define IPC_SET_VIS_FS_FLAG 631 // a vis should send this message with 1/as param to notify winamp that it has gone to or has come back from fullscreen mode
  818. void CPluginShell::ToggleFullScreen()
  819. {
  820. CleanUpDX9Stuff(0);
  821. switch (m_screenmode)
  822. {
  823. case DESKTOP:
  824. case WINDOWED:
  825. m_screenmode = m_fake_fullscreen_mode ? FAKE_FULLSCREEN : FULLSCREEN;
  826. if (m_screenmode == FULLSCREEN && SendMessage(GetWinampWindow(), WM_WA_IPC, 0, IPC_IS_PLAYING_VIDEO) > 1)
  827. {
  828. m_screenmode = FAKE_FULLSCREEN;
  829. }
  830. SendMessage(GetWinampWindow(), WM_WA_IPC, 1, IPC_SET_VIS_FS_FLAG);
  831. break;
  832. case FULLSCREEN:
  833. case FAKE_FULLSCREEN:
  834. m_screenmode = WINDOWED;
  835. SendMessage(GetWinampWindow(), WM_WA_IPC, 0, IPC_SET_VIS_FS_FLAG);
  836. break;
  837. }
  838. DXCONTEXT_PARAMS params;
  839. StuffParams(&params);
  840. if (!m_lpDX->StartOrRestartDevice(&params))
  841. {
  842. // note: a basic warning messagebox will have already been given.
  843. if (m_lpDX->m_lastErr == DXC_ERR_CREATEDEV_PROBABLY_OUTOFVIDEOMEMORY)
  844. SuggestHowToFreeSomeMem();
  845. return;
  846. }
  847. if (!AllocateDX9Stuff())
  848. {
  849. m_lpDX->m_ready = false; // flag to exit
  850. return;
  851. }
  852. SetForegroundWindow(m_lpDX->GetHwnd());
  853. SetActiveWindow(m_lpDX->GetHwnd());
  854. SetFocus(m_lpDX->GetHwnd());
  855. }
  856. void CPluginShell::ToggleHelp()
  857. {
  858. m_show_help = 1-m_show_help;
  859. int ret = CheckMenuItem(m_context_menu, ID_SHOWHELP, MF_BYCOMMAND | (m_show_help ? MF_CHECKED : MF_UNCHECKED));
  860. }
  861. void CPluginShell::TogglePlaylist()
  862. {
  863. m_show_playlist = 1-m_show_playlist;
  864. m_playlist_top_idx = -1; // <- invalidates playlist cache
  865. int ret = CheckMenuItem(m_context_menu, ID_SHOWPLAYLIST, MF_BYCOMMAND | (m_show_playlist ? MF_CHECKED : MF_UNCHECKED));
  866. }
  867. int CPluginShell::InitDirectX()
  868. {
  869. m_lpDX = new DXContext(m_hWndWinamp,m_hInstance,CLASSNAME,WINDOWCAPTION,CPluginShell::WindowProc,(LONG_PTR)this, m_minimize_winamp, m_szConfigIniFile);
  870. if (!m_lpDX)
  871. {
  872. wchar_t title[64];
  873. MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_INIT_DXCONTEXT),
  874. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR, title, 64),
  875. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  876. return FALSE;
  877. }
  878. if (m_lpDX->m_lastErr != S_OK)
  879. {
  880. // warning messagebox will have already been given
  881. delete m_lpDX;
  882. return FALSE;
  883. }
  884. // initialize graphics
  885. DXCONTEXT_PARAMS params;
  886. StuffParams(&params);
  887. if (!m_lpDX->StartOrRestartDevice(&params))
  888. {
  889. // note: a basic warning messagebox will have already been given.
  890. if (m_lpDX->m_lastErr == DXC_ERR_CREATEDEV_PROBABLY_OUTOFVIDEOMEMORY)
  891. {
  892. // suggest specific advice on how to regain more video memory:
  893. SuggestHowToFreeSomeMem();
  894. }
  895. delete m_lpDX;
  896. m_lpDX = NULL;
  897. return FALSE;
  898. }
  899. return TRUE;
  900. }
  901. void CPluginShell::CleanUpDirectX()
  902. {
  903. SafeDelete(m_lpDX);
  904. }
  905. int CPluginShell::PluginPreInitialize(HWND hWinampWnd, HINSTANCE hWinampInstance)
  906. {
  907. // PROTECTED CONFIG PANEL SETTINGS (also see 'private' settings, below)
  908. m_start_fullscreen = 0;
  909. m_start_desktop = 0;
  910. m_fake_fullscreen_mode = 0;
  911. m_max_fps_fs = 30;
  912. m_max_fps_dm = 30;
  913. m_max_fps_w = 30;
  914. m_show_press_f1_msg = 1;
  915. m_allow_page_tearing_w = 1;
  916. m_allow_page_tearing_fs = 0;
  917. m_allow_page_tearing_dm = 0;
  918. m_minimize_winamp = 1;
  919. m_desktop_show_icons = 1;
  920. m_desktop_textlabel_boxes = 1;
  921. m_desktop_manual_icon_scoot = 0;
  922. m_desktop_555_fix = 2;
  923. m_dualhead_horz = 2;
  924. m_dualhead_vert = 1;
  925. m_save_cpu = 1;
  926. m_skin = 1;
  927. m_fix_slow_text = 0;
  928. // initialize font settings:
  929. wcscpy(m_fontinfo[SIMPLE_FONT ].szFace, SIMPLE_FONT_DEFAULT_FACE);
  930. m_fontinfo[SIMPLE_FONT ].nSize = SIMPLE_FONT_DEFAULT_SIZE ;
  931. m_fontinfo[SIMPLE_FONT ].bBold = SIMPLE_FONT_DEFAULT_BOLD ;
  932. m_fontinfo[SIMPLE_FONT ].bItalic = SIMPLE_FONT_DEFAULT_ITAL ;
  933. m_fontinfo[SIMPLE_FONT ].bAntiAliased = SIMPLE_FONT_DEFAULT_AA ;
  934. wcscpy(m_fontinfo[DECORATIVE_FONT].szFace, DECORATIVE_FONT_DEFAULT_FACE);
  935. m_fontinfo[DECORATIVE_FONT].nSize = DECORATIVE_FONT_DEFAULT_SIZE;
  936. m_fontinfo[DECORATIVE_FONT].bBold = DECORATIVE_FONT_DEFAULT_BOLD;
  937. m_fontinfo[DECORATIVE_FONT].bItalic = DECORATIVE_FONT_DEFAULT_ITAL;
  938. m_fontinfo[DECORATIVE_FONT].bAntiAliased = DECORATIVE_FONT_DEFAULT_AA ;
  939. wcscpy(m_fontinfo[HELPSCREEN_FONT].szFace, HELPSCREEN_FONT_DEFAULT_FACE);
  940. m_fontinfo[HELPSCREEN_FONT].nSize = HELPSCREEN_FONT_DEFAULT_SIZE;
  941. m_fontinfo[HELPSCREEN_FONT].bBold = HELPSCREEN_FONT_DEFAULT_BOLD;
  942. m_fontinfo[HELPSCREEN_FONT].bItalic = HELPSCREEN_FONT_DEFAULT_ITAL;
  943. m_fontinfo[HELPSCREEN_FONT].bAntiAliased = HELPSCREEN_FONT_DEFAULT_AA ;
  944. wcscpy(m_fontinfo[PLAYLIST_FONT ].szFace, PLAYLIST_FONT_DEFAULT_FACE);
  945. m_fontinfo[PLAYLIST_FONT ].nSize = PLAYLIST_FONT_DEFAULT_SIZE;
  946. m_fontinfo[PLAYLIST_FONT ].bBold = PLAYLIST_FONT_DEFAULT_BOLD;
  947. m_fontinfo[PLAYLIST_FONT ].bItalic = PLAYLIST_FONT_DEFAULT_ITAL;
  948. m_fontinfo[PLAYLIST_FONT ].bAntiAliased = PLAYLIST_FONT_DEFAULT_AA ;
  949. #if (NUM_EXTRA_FONTS >= 1)
  950. wcscpy(m_fontinfo[NUM_BASIC_FONTS + 0].szFace, EXTRA_FONT_1_DEFAULT_FACE);
  951. m_fontinfo[NUM_BASIC_FONTS + 0].nSize = EXTRA_FONT_1_DEFAULT_SIZE;
  952. m_fontinfo[NUM_BASIC_FONTS + 0].bBold = EXTRA_FONT_1_DEFAULT_BOLD;
  953. m_fontinfo[NUM_BASIC_FONTS + 0].bItalic = EXTRA_FONT_1_DEFAULT_ITAL;
  954. m_fontinfo[NUM_BASIC_FONTS + 0].bAntiAliased = EXTRA_FONT_1_DEFAULT_AA;
  955. #endif
  956. #if (NUM_EXTRA_FONTS >= 2)
  957. wcscpy(m_fontinfo[NUM_BASIC_FONTS + 1].szFace, EXTRA_FONT_2_DEFAULT_FACE);
  958. m_fontinfo[NUM_BASIC_FONTS + 1].nSize = EXTRA_FONT_2_DEFAULT_SIZE;
  959. m_fontinfo[NUM_BASIC_FONTS + 1].bBold = EXTRA_FONT_2_DEFAULT_BOLD;
  960. m_fontinfo[NUM_BASIC_FONTS + 1].bItalic = EXTRA_FONT_2_DEFAULT_ITAL;
  961. m_fontinfo[NUM_BASIC_FONTS + 1].bAntiAliased = EXTRA_FONT_2_DEFAULT_AA;
  962. #endif
  963. #if (NUM_EXTRA_FONTS >= 3)
  964. strcpy(m_fontinfo[NUM_BASIC_FONTS + 2].szFace, EXTRA_FONT_3_DEFAULT_FACE);
  965. m_fontinfo[NUM_BASIC_FONTS + 2].nSize = EXTRA_FONT_3_DEFAULT_SIZE;
  966. m_fontinfo[NUM_BASIC_FONTS + 2].bBold = EXTRA_FONT_3_DEFAULT_BOLD;
  967. m_fontinfo[NUM_BASIC_FONTS + 2].bItalic = EXTRA_FONT_3_DEFAULT_ITAL;
  968. m_fontinfo[NUM_BASIC_FONTS + 2].bAntiAliased = EXTRA_FONT_3_DEFAULT_AA;
  969. #endif
  970. #if (NUM_EXTRA_FONTS >= 4)
  971. strcpy(m_fontinfo[NUM_BASIC_FONTS + 3].szFace, EXTRA_FONT_4_DEFAULT_FACE);
  972. m_fontinfo[NUM_BASIC_FONTS + 3].nSize = EXTRA_FONT_4_DEFAULT_SIZE;
  973. m_fontinfo[NUM_BASIC_FONTS + 3].bBold = EXTRA_FONT_4_DEFAULT_BOLD;
  974. m_fontinfo[NUM_BASIC_FONTS + 3].bItalic = EXTRA_FONT_4_DEFAULT_ITAL;
  975. m_fontinfo[NUM_BASIC_FONTS + 3].bAntiAliased = EXTRA_FONT_4_DEFAULT_AA;
  976. #endif
  977. #if (NUM_EXTRA_FONTS >= 5)
  978. strcpy(m_fontinfo[NUM_BASIC_FONTS + 4].szFace, EXTRA_FONT_5_DEFAULT_FACE);
  979. m_fontinfo[NUM_BASIC_FONTS + 4].nSize = EXTRA_FONT_5_DEFAULT_SIZE;
  980. m_fontinfo[NUM_BASIC_FONTS + 4].bBold = EXTRA_FONT_5_DEFAULT_BOLD;
  981. m_fontinfo[NUM_BASIC_FONTS + 4].bItalic = EXTRA_FONT_5_DEFAULT_ITAL;
  982. m_fontinfo[NUM_BASIC_FONTS + 4].bAntiAliased = EXTRA_FONT_5_DEFAULT_AA;
  983. #endif
  984. m_disp_mode_fs.Width = DEFAULT_FULLSCREEN_WIDTH;
  985. m_disp_mode_fs.Height = DEFAULT_FULLSCREEN_HEIGHT;
  986. m_disp_mode_fs.Format = D3DFMT_UNKNOWN;
  987. m_disp_mode_fs.RefreshRate = 60;
  988. // better yet - in case there is no config INI file saved yet, use the current display mode (if detectable) as the default fullscreen res:
  989. DEVMODE dm;
  990. dm.dmSize = sizeof(dm);
  991. dm.dmDriverExtra = 0;
  992. if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm))
  993. {
  994. m_disp_mode_fs.Width = dm.dmPelsWidth;
  995. m_disp_mode_fs.Height = dm.dmPelsHeight;
  996. m_disp_mode_fs.RefreshRate = dm.dmDisplayFrequency;
  997. m_disp_mode_fs.Format = (dm.dmBitsPerPel==16) ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8;
  998. }
  999. // PROTECTED STRUCTURES/POINTERS
  1000. int i = 0;
  1001. for (int i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++)
  1002. m_d3dx_font[i] = NULL;
  1003. m_d3dx_desktop_font = NULL;
  1004. m_lpDDSText = NULL;
  1005. ZeroMemory(&m_sound, sizeof(td_soundinfo));
  1006. for (int ch=0; ch<2; ch++)
  1007. for (i=0; i<3; i++)
  1008. {
  1009. m_sound.infinite_avg[ch][i] = m_sound.avg[ch][i] = m_sound.med_avg[ch][i] = m_sound.long_avg[ch][i] = 1.0f;
  1010. }
  1011. // GENERAL PRIVATE STUFF
  1012. //m_screenmode: set at end (derived setting)
  1013. m_frame = 0;
  1014. m_time = 0;
  1015. m_fps = 30;
  1016. m_hWndWinamp = hWinampWnd;
  1017. m_hInstance = hWinampInstance;
  1018. m_lpDX = NULL;
  1019. m_szPluginsDirPath[0] = 0; // will be set further down
  1020. m_szConfigIniFile[0] = 0; // will be set further down
  1021. // m_szPluginsDirPath:
  1022. wchar_t *p;
  1023. if (hWinampWnd
  1024. && (p = (wchar_t *)SendMessage(hWinampWnd, WM_WA_IPC, 0, IPC_GETPLUGINDIRECTORYW))
  1025. && p != (wchar_t *)1)
  1026. {
  1027. swprintf(m_szPluginsDirPath, L"%s\\", p);
  1028. }
  1029. else
  1030. {
  1031. // get path to INI file & read in prefs/settings right away, so DumpMsg works!
  1032. GetModuleFileNameW(m_hInstance, m_szPluginsDirPath, MAX_PATH);
  1033. wchar_t *p = m_szPluginsDirPath + wcslen(m_szPluginsDirPath);
  1034. while (p >= m_szPluginsDirPath && *p != L'\\') p--;
  1035. if (++p >= m_szPluginsDirPath) *p = 0;
  1036. }
  1037. if (hWinampWnd
  1038. && (p = (wchar_t *)SendMessage(hWinampWnd, WM_WA_IPC, 0, IPC_GETINIDIRECTORYW))
  1039. && p != (wchar_t *)1)
  1040. {
  1041. // load settings as well as coping with moving old settings to a contained folder
  1042. wchar_t m_szOldConfigIniFile[MAX_PATH] = {0}, temp[MAX_PATH] = {0}, temp2[MAX_PATH] = {0};
  1043. swprintf(m_szOldConfigIniFile, L"%s\\Plugins\\%s", p, INIFILE);
  1044. swprintf(m_szConfigIniFile, L"%s\\Plugins\\%s%s", p, SUBDIR, INIFILE);
  1045. swprintf(temp, L"%s\\Plugins\\%s", p, SUBDIR);
  1046. swprintf(temp2, L"%s\\Plugins\\", p);
  1047. CreateDirectoryW(temp, NULL);
  1048. if (PathFileExistsW(m_szOldConfigIniFile) && !PathFileExistsW(m_szConfigIniFile))
  1049. {
  1050. MoveFileW(m_szOldConfigIniFile, m_szConfigIniFile);
  1051. wchar_t m_szMsgIniFile[MAX_PATH] = {0}, m_szNewMsgIniFile[MAX_PATH] = {0},
  1052. m_szImgIniFile[MAX_PATH] = {0}, m_szNewImgIniFile[MAX_PATH] = {0},
  1053. m_szAdaptersFile[MAX_PATH] = {0}, m_szNewAdaptersFile[MAX_PATH] = {0};
  1054. swprintf(m_szMsgIniFile, L"%s%s", temp2, MSG_INIFILE);
  1055. swprintf(m_szNewMsgIniFile, L"%s%s", temp, MSG_INIFILE);
  1056. swprintf(m_szImgIniFile, L"%s%s", temp2, IMG_INIFILE);
  1057. swprintf(m_szNewImgIniFile, L"%s%s", temp, IMG_INIFILE);
  1058. swprintf(m_szAdaptersFile, L"%s%s", temp2, ADAPTERSFILE);
  1059. swprintf(m_szNewAdaptersFile, L"%s%s", temp, ADAPTERSFILE);
  1060. MoveFileW(m_szImgIniFile, m_szNewImgIniFile);
  1061. MoveFileW(m_szMsgIniFile, m_szNewMsgIniFile);
  1062. MoveFileW(m_szAdaptersFile, m_szNewAdaptersFile);
  1063. }
  1064. }
  1065. else
  1066. {
  1067. swprintf(m_szConfigIniFile, L"%s%s", m_szPluginsDirPath, INIFILE);
  1068. }
  1069. lstrcpyn(m_szConfigIniFileA,AutoCharFn(m_szConfigIniFile),MAX_PATH);
  1070. // PRIVATE CONFIG PANEL SETTINGS
  1071. m_multisample_fullscreen = D3DMULTISAMPLE_NONE;
  1072. m_multisample_desktop = D3DMULTISAMPLE_NONE;
  1073. m_multisample_windowed = D3DMULTISAMPLE_NONE;
  1074. ZeroMemory(&m_adapter_guid_fullscreen, sizeof(GUID));
  1075. ZeroMemory(&m_adapter_guid_desktop , sizeof(GUID));
  1076. ZeroMemory(&m_adapter_guid_windowed , sizeof(GUID));
  1077. m_adapter_devicename_windowed[0] = 0;
  1078. m_adapter_devicename_fullscreen[0] = 0;
  1079. m_adapter_devicename_desktop[0] = 0;
  1080. // PRIVATE RUNTIME SETTINGS
  1081. m_lost_focus = 0;
  1082. m_hidden = 0;
  1083. m_resizing = 0;
  1084. m_show_help = 0;
  1085. m_show_playlist = 0;
  1086. m_playlist_pos = 0;
  1087. m_playlist_pageups = 0;
  1088. m_playlist_top_idx = -1;
  1089. m_playlist_btm_idx = -1;
  1090. // m_playlist_width_pixels will be considered invalid whenever 'm_playlist_top_idx' is -1.
  1091. // m_playlist[256][256] will be considered invalid whenever 'm_playlist_top_idx' is -1.
  1092. m_exiting = 0;
  1093. m_upper_left_corner_y = 0;
  1094. m_lower_left_corner_y = 0;
  1095. m_upper_right_corner_y = 0;
  1096. m_lower_right_corner_y = 0;
  1097. m_left_edge = 0;
  1098. m_right_edge = 0;
  1099. m_force_accept_WM_WINDOWPOSCHANGING = 0;
  1100. // PRIVATE - GDI STUFF
  1101. m_main_menu = NULL;
  1102. m_context_menu = NULL;
  1103. for (i=0; i<NUM_BASIC_FONTS + NUM_EXTRA_FONTS; i++)
  1104. m_font[i] = NULL;
  1105. m_font_desktop = NULL;
  1106. // PRIVATE - DESKTOP MODE STUFF
  1107. m_icon_list.clear();
  1108. for (i=0; i<MAX_ICON_TEXTURES; i++)
  1109. m_desktop_icons_texture[i] = NULL;
  1110. FindDesktopWindows(&m_hWndProgMan, &m_hWndDesktop, &m_hWndDesktopListView);
  1111. GetDesktopFolder(m_szDesktopFolder);
  1112. m_desktop_icon_size = 32;
  1113. m_desktop_dragging = 0; // '1' when user is dragging icons around
  1114. m_desktop_box = 0; // '1' when user is drawing a box
  1115. m_desktop_wc_registered = 0;
  1116. m_desktop_bk_color = 0xFF000000 | BGR2RGB(::GetSysColor(COLOR_BACKGROUND));
  1117. m_desktop_text_color = 0xFF000000 | BGR2RGB(SendMessage(m_hWndDesktopListView, LVM_GETTEXTCOLOR, 0, 0));
  1118. m_desktop_sel_color = 0xFF000000 | BGR2RGB(::GetSysColor(COLOR_HIGHLIGHT));
  1119. m_desktop_sel_text_color = 0xFF000000 | BGR2RGB(::GetSysColor(COLOR_HIGHLIGHTTEXT));
  1120. m_desktop_icon_state = 0;
  1121. m_desktop_icon_count = 0;
  1122. m_desktop_icon_update_frame = 0;
  1123. m_desktop_icons_disabled = 0;
  1124. m_vms_desktop_loaded = 0;
  1125. m_desktop_hook_set = 0;
  1126. // PRIVATE - MORE TIMEKEEPING
  1127. m_last_raw_time = 0;
  1128. memset(m_time_hist, 0, sizeof(m_time_hist));
  1129. m_time_hist_pos = 0;
  1130. if (!QueryPerformanceFrequency(&m_high_perf_timer_freq))
  1131. m_high_perf_timer_freq.QuadPart = 0;
  1132. m_prev_end_of_frame.QuadPart = 0;
  1133. // PRIVATE AUDIO PROCESSING DATA
  1134. //(m_fftobj needs no init)
  1135. memset(m_oldwave[0], 0, sizeof(float)*576);
  1136. memset(m_oldwave[1], 0, sizeof(float)*576);
  1137. m_prev_align_offset[0] = 0;
  1138. m_prev_align_offset[1] = 0;
  1139. m_align_weights_ready = 0;
  1140. // SEPARATE TEXT WINDOW (FOR VJ MODE)
  1141. m_vj_mode = 0;
  1142. m_hidden_textwnd = 0;
  1143. m_resizing_textwnd = 0;
  1144. m_hTextWnd = NULL;
  1145. m_nTextWndWidth = 0;
  1146. m_nTextWndHeight = 0;
  1147. m_bTextWindowClassRegistered = false;
  1148. m_vjd3d9 = NULL;
  1149. m_vjd3d9_device = NULL;
  1150. //-----
  1151. m_screenmode = NOT_YET_KNOWN;
  1152. OverrideDefaults();
  1153. ReadConfig();
  1154. if (m_start_fullscreen)
  1155. {
  1156. m_screenmode = m_fake_fullscreen_mode ? FAKE_FULLSCREEN : FULLSCREEN;
  1157. if (m_screenmode == FULLSCREEN && SendMessage(GetWinampWindow(), WM_WA_IPC, 0, IPC_IS_PLAYING_VIDEO) > 1)
  1158. {
  1159. m_screenmode = FAKE_FULLSCREEN;
  1160. }
  1161. }
  1162. else if (m_start_desktop)
  1163. m_screenmode = DESKTOP;
  1164. else
  1165. m_screenmode = WINDOWED;
  1166. MyPreInitialize();
  1167. MyReadConfig();
  1168. //-----
  1169. return TRUE;
  1170. }
  1171. int CPluginShell::PluginInitialize()
  1172. {
  1173. // note: initialize GDI before DirectX. Also separate them because
  1174. // when we change windowed<->fullscreen, or lose the device and restore it,
  1175. // we don't want to mess with any (persistent) GDI stuff.
  1176. if (!InitDirectX()) return FALSE; // gives its own error messages
  1177. if (!InitNondx9Stuff()) return FALSE; // gives its own error messages
  1178. if (!AllocateDX9Stuff()) return FALSE; // gives its own error messages
  1179. if (!InitVJStuff()) return FALSE;
  1180. return TRUE;
  1181. }
  1182. void CPluginShell::PluginQuit()
  1183. {
  1184. CleanUpVJStuff();
  1185. CleanUpDX9Stuff(1);
  1186. CleanUpNondx9Stuff();
  1187. CleanUpDirectX();
  1188. SetFocus(m_hWndWinamp);
  1189. SetActiveWindow(m_hWndWinamp);
  1190. SetForegroundWindow(m_hWndWinamp);
  1191. }
  1192. wchar_t* BuildSettingName(wchar_t* name, int number){
  1193. static wchar_t temp[64];
  1194. swprintf(temp, L"%s%d", name, number);
  1195. return temp;
  1196. }
  1197. void CPluginShell::READ_FONT(int n){
  1198. GetPrivateProfileStringW(L"settings",BuildSettingName(L"szFontFace",n),m_fontinfo[n].szFace,m_fontinfo[n].szFace,sizeof(m_fontinfo[n].szFace), m_szConfigIniFile);
  1199. m_fontinfo[n].nSize = GetPrivateProfileIntW(L"settings",BuildSettingName(L"nFontSize",n),m_fontinfo[n].nSize ,m_szConfigIniFile);
  1200. m_fontinfo[n].bBold = GetPrivateProfileIntW(L"settings",BuildSettingName(L"bFontBold",n),m_fontinfo[n].bBold ,m_szConfigIniFile);
  1201. m_fontinfo[n].bItalic = GetPrivateProfileIntW(L"settings",BuildSettingName(L"bFontItalic",n),m_fontinfo[n].bItalic,m_szConfigIniFile);
  1202. m_fontinfo[n].bAntiAliased = GetPrivateProfileIntW(L"settings",BuildSettingName(L"bFontAA",n),m_fontinfo[n].bItalic,m_szConfigIniFile);
  1203. }
  1204. void CPluginShell::ReadConfig()
  1205. {
  1206. int old_ver = GetPrivateProfileIntW(L"settings",L"version" ,-1,m_szConfigIniFile);
  1207. int old_subver = GetPrivateProfileIntW(L"settings",L"subversion",-1,m_szConfigIniFile);
  1208. // nuke old settings from prev. version:
  1209. if (old_ver < INT_VERSION)
  1210. return;
  1211. else if (old_subver < INT_SUBVERSION)
  1212. return;
  1213. //D3DMULTISAMPLE_TYPE m_multisample_fullscreen;
  1214. //D3DMULTISAMPLE_TYPE m_multisample_desktop;
  1215. //D3DMULTISAMPLE_TYPE m_multisample_windowed;
  1216. m_multisample_fullscreen = (D3DMULTISAMPLE_TYPE)GetPrivateProfileIntW(L"settings",L"multisample_fullscreen",m_multisample_fullscreen,m_szConfigIniFile);
  1217. m_multisample_desktop = (D3DMULTISAMPLE_TYPE)GetPrivateProfileIntW(L"settings",L"multisample_desktop",m_multisample_desktop,m_szConfigIniFile);
  1218. m_multisample_windowed = (D3DMULTISAMPLE_TYPE)GetPrivateProfileIntW(L"settings",L"multisample_windowed" ,m_multisample_windowed ,m_szConfigIniFile);
  1219. //GUID m_adapter_guid_fullscreen
  1220. //GUID m_adapter_guid_desktop
  1221. //GUID m_adapter_guid_windowed
  1222. char str[256];
  1223. GetPrivateProfileString("settings","adapter_guid_fullscreen","",str,sizeof(str)-1,m_szConfigIniFileA);
  1224. TextToGuid(str, &m_adapter_guid_fullscreen);
  1225. GetPrivateProfileString("settings","adapter_guid_desktop","",str,sizeof(str)-1,m_szConfigIniFileA);
  1226. TextToGuid(str, &m_adapter_guid_desktop);
  1227. GetPrivateProfileString("settings","adapter_guid_windowed","",str,sizeof(str)-1,m_szConfigIniFileA);
  1228. TextToGuid(str, &m_adapter_guid_windowed);
  1229. GetPrivateProfileString("settings","adapter_devicename_fullscreen","",m_adapter_devicename_fullscreen,sizeof(m_adapter_devicename_fullscreen)-1,m_szConfigIniFileA);
  1230. GetPrivateProfileString("settings","adapter_devicename_desktop", "",m_adapter_devicename_desktop ,sizeof(m_adapter_devicename_desktop)-1,m_szConfigIniFileA);
  1231. GetPrivateProfileString("settings","adapter_devicename_windowed", "",m_adapter_devicename_windowed ,sizeof(m_adapter_devicename_windowed)-1,m_szConfigIniFileA);
  1232. // FONTS
  1233. READ_FONT(0);
  1234. READ_FONT(1);
  1235. READ_FONT(2);
  1236. READ_FONT(3);
  1237. #if (NUM_EXTRA_FONTS >= 1)
  1238. READ_FONT(4);
  1239. #endif
  1240. #if (NUM_EXTRA_FONTS >= 2)
  1241. READ_FONT(5);
  1242. #endif
  1243. #if (NUM_EXTRA_FONTS >= 3)
  1244. READ_FONT(6);
  1245. #endif
  1246. #if (NUM_EXTRA_FONTS >= 4)
  1247. READ_FONT(7);
  1248. #endif
  1249. #if (NUM_EXTRA_FONTS >= 5)
  1250. READ_FONT(8);
  1251. #endif
  1252. m_start_fullscreen = GetPrivateProfileIntW(L"settings",L"start_fullscreen",m_start_fullscreen,m_szConfigIniFile);
  1253. m_start_desktop = GetPrivateProfileIntW(L"settings",L"start_desktop" ,m_start_desktop ,m_szConfigIniFile);
  1254. m_fake_fullscreen_mode = GetPrivateProfileIntW(L"settings",L"fake_fullscreen_mode",m_fake_fullscreen_mode,m_szConfigIniFile);
  1255. m_max_fps_fs = GetPrivateProfileIntW(L"settings",L"max_fps_fs",m_max_fps_fs,m_szConfigIniFile);
  1256. m_max_fps_dm = GetPrivateProfileIntW(L"settings",L"max_fps_dm",m_max_fps_dm,m_szConfigIniFile);
  1257. m_max_fps_w = GetPrivateProfileIntW(L"settings",L"max_fps_w" ,m_max_fps_w ,m_szConfigIniFile);
  1258. m_show_press_f1_msg = GetPrivateProfileIntW(L"settings",L"show_press_f1_msg",m_show_press_f1_msg,m_szConfigIniFile);
  1259. m_allow_page_tearing_w = GetPrivateProfileIntW(L"settings",L"allow_page_tearing_w",m_allow_page_tearing_w,m_szConfigIniFile);
  1260. m_allow_page_tearing_fs= GetPrivateProfileIntW(L"settings",L"allow_page_tearing_fs",m_allow_page_tearing_fs,m_szConfigIniFile);
  1261. m_allow_page_tearing_dm= GetPrivateProfileIntW(L"settings",L"allow_page_tearing_dm",m_allow_page_tearing_dm,m_szConfigIniFile);
  1262. m_minimize_winamp = GetPrivateProfileIntW(L"settings",L"minimize_winamp",m_minimize_winamp,m_szConfigIniFile);
  1263. m_desktop_show_icons = GetPrivateProfileIntW(L"settings",L"desktop_show_icons",m_desktop_show_icons,m_szConfigIniFile);
  1264. m_desktop_textlabel_boxes = GetPrivateProfileIntW(L"settings",L"desktop_textlabel_boxes",m_desktop_textlabel_boxes,m_szConfigIniFile);
  1265. m_desktop_manual_icon_scoot = GetPrivateProfileIntW(L"settings",L"desktop_manual_icon_scoot",m_desktop_manual_icon_scoot,m_szConfigIniFile);
  1266. m_desktop_555_fix = GetPrivateProfileIntW(L"settings",L"desktop_555_fix",m_desktop_555_fix,m_szConfigIniFile);
  1267. m_dualhead_horz = GetPrivateProfileIntW(L"settings",L"dualhead_horz",m_dualhead_horz,m_szConfigIniFile);
  1268. m_dualhead_vert = GetPrivateProfileIntW(L"settings",L"dualhead_vert",m_dualhead_vert,m_szConfigIniFile);
  1269. m_save_cpu = GetPrivateProfileIntW(L"settings",L"save_cpu",m_save_cpu,m_szConfigIniFile);
  1270. m_skin = GetPrivateProfileIntW(L"settings",L"skin",m_skin,m_szConfigIniFile);
  1271. m_fix_slow_text = GetPrivateProfileIntW(L"settings",L"fix_slow_text",m_fix_slow_text,m_szConfigIniFile);
  1272. m_vj_mode = GetPrivateProfileBoolW(L"settings",L"vj_mode",m_vj_mode,m_szConfigIniFile);
  1273. //D3DDISPLAYMODE m_fs_disp_mode
  1274. m_disp_mode_fs.Width = GetPrivateProfileIntW(L"settings",L"disp_mode_fs_w", m_disp_mode_fs.Width ,m_szConfigIniFile);
  1275. m_disp_mode_fs.Height = GetPrivateProfileIntW(L"settings",L"disp_mode_fs_h",m_disp_mode_fs.Height ,m_szConfigIniFile);
  1276. m_disp_mode_fs.RefreshRate = GetPrivateProfileIntW(L"settings",L"disp_mode_fs_r",m_disp_mode_fs.RefreshRate,m_szConfigIniFile);
  1277. m_disp_mode_fs.Format = (D3DFORMAT)GetPrivateProfileIntW(L"settings",L"disp_mode_fs_f",m_disp_mode_fs.Format ,m_szConfigIniFile);
  1278. // note: we don't call MyReadConfig() yet, because we
  1279. // want to completely finish CPluginShell's preinit (and ReadConfig)
  1280. // before calling CPlugin's preinit and ReadConfig.
  1281. }
  1282. void CPluginShell::WRITE_FONT(int n){
  1283. WritePrivateProfileStringW(L"settings",BuildSettingName(L"szFontFace",n),m_fontinfo[n].szFace,m_szConfigIniFile);
  1284. WritePrivateProfileIntW(m_fontinfo[n].bBold, BuildSettingName(L"bFontBold",n), m_szConfigIniFile, L"settings");
  1285. WritePrivateProfileIntW(m_fontinfo[n].bItalic,BuildSettingName(L"bFontItalic",n), m_szConfigIniFile, L"settings");
  1286. WritePrivateProfileIntW(m_fontinfo[n].nSize, BuildSettingName(L"nFontSize",n), m_szConfigIniFile, L"settings");
  1287. WritePrivateProfileIntW(m_fontinfo[n].bAntiAliased, BuildSettingName(L"bFontAA",n),m_szConfigIniFile, L"settings");
  1288. }
  1289. void CPluginShell::WriteConfig()
  1290. {
  1291. //D3DMULTISAMPLE_TYPE m_multisample_fullscreen;
  1292. //D3DMULTISAMPLE_TYPE m_multisample_desktop;
  1293. //D3DMULTISAMPLE_TYPE m_multisample_windowed;
  1294. WritePrivateProfileIntW((int)m_multisample_fullscreen,L"multisample_fullscreen",m_szConfigIniFile,L"settings");
  1295. WritePrivateProfileIntW((int)m_multisample_desktop ,L"multisample_desktop" ,m_szConfigIniFile,L"settings");
  1296. WritePrivateProfileIntW((int)m_multisample_windowed ,L"multisample_windowed" ,m_szConfigIniFile,L"settings");
  1297. //GUID m_adapter_guid_fullscreen
  1298. //GUID m_adapter_guid_desktop
  1299. //GUID m_adapter_guid_windowed
  1300. char str[256];
  1301. GuidToText(&m_adapter_guid_fullscreen, str, sizeof(str));
  1302. WritePrivateProfileString("settings","adapter_guid_fullscreen",str,m_szConfigIniFileA);
  1303. GuidToText(&m_adapter_guid_desktop, str, sizeof(str));
  1304. WritePrivateProfileString("settings","adapter_guid_desktop",str,m_szConfigIniFileA);
  1305. GuidToText(&m_adapter_guid_windowed, str, sizeof(str));
  1306. WritePrivateProfileString("settings","adapter_guid_windowed" ,str,m_szConfigIniFileA);
  1307. WritePrivateProfileString("settings","adapter_devicename_fullscreen",m_adapter_devicename_fullscreen,m_szConfigIniFileA);
  1308. WritePrivateProfileString("settings","adapter_devicename_desktop" ,m_adapter_devicename_desktop ,m_szConfigIniFileA);
  1309. WritePrivateProfileString("settings","adapter_devicename_windowed" ,m_adapter_devicename_windowed ,m_szConfigIniFileA);
  1310. // FONTS
  1311. WRITE_FONT(0);
  1312. WRITE_FONT(1);
  1313. WRITE_FONT(2);
  1314. WRITE_FONT(3);
  1315. #if (NUM_EXTRA_FONTS >= 1)
  1316. WRITE_FONT(4);
  1317. #endif
  1318. #if (NUM_EXTRA_FONTS >= 2)
  1319. WRITE_FONT(5);
  1320. #endif
  1321. #if (NUM_EXTRA_FONTS >= 3)
  1322. WRITE_FONT(6);
  1323. #endif
  1324. #if (NUM_EXTRA_FONTS >= 4)
  1325. WRITE_FONT(7);
  1326. #endif
  1327. #if (NUM_EXTRA_FONTS >= 5)
  1328. WRITE_FONT(8);
  1329. #endif
  1330. WritePrivateProfileIntW(m_start_fullscreen,L"start_fullscreen",m_szConfigIniFile,L"settings");
  1331. WritePrivateProfileIntW(m_start_desktop ,L"start_desktop" ,m_szConfigIniFile,L"settings");
  1332. WritePrivateProfileIntW(m_fake_fullscreen_mode,L"fake_fullscreen_mode",m_szConfigIniFile,L"settings");
  1333. WritePrivateProfileIntW(m_max_fps_fs,L"max_fps_fs",m_szConfigIniFile,L"settings");
  1334. WritePrivateProfileIntW(m_max_fps_dm,L"max_fps_dm",m_szConfigIniFile,L"settings");
  1335. WritePrivateProfileIntW(m_max_fps_w ,L"max_fps_w" ,m_szConfigIniFile,L"settings");
  1336. WritePrivateProfileIntW(m_show_press_f1_msg,L"show_press_f1_msg",m_szConfigIniFile,L"settings");
  1337. WritePrivateProfileIntW(m_allow_page_tearing_w,L"allow_page_tearing_w",m_szConfigIniFile,L"settings");
  1338. WritePrivateProfileIntW(m_allow_page_tearing_fs,L"allow_page_tearing_fs",m_szConfigIniFile,L"settings");
  1339. WritePrivateProfileIntW(m_allow_page_tearing_dm,L"allow_page_tearing_dm",m_szConfigIniFile,L"settings");
  1340. WritePrivateProfileIntW(m_minimize_winamp,L"minimize_winamp",m_szConfigIniFile,L"settings");
  1341. WritePrivateProfileIntW(m_desktop_show_icons,L"desktop_show_icons",m_szConfigIniFile,L"settings");
  1342. WritePrivateProfileIntW(m_desktop_textlabel_boxes,L"desktop_textlabel_boxes",m_szConfigIniFile,L"settings");
  1343. WritePrivateProfileIntW(m_desktop_manual_icon_scoot,L"desktop_manual_icon_scoot",m_szConfigIniFile,L"settings");
  1344. WritePrivateProfileIntW(m_desktop_555_fix,L"desktop_555_fix",m_szConfigIniFile,L"settings");
  1345. WritePrivateProfileIntW(m_dualhead_horz,L"dualhead_horz",m_szConfigIniFile,L"settings");
  1346. WritePrivateProfileIntW(m_dualhead_vert,L"dualhead_vert",m_szConfigIniFile,L"settings");
  1347. WritePrivateProfileIntW(m_save_cpu,L"save_cpu",m_szConfigIniFile,L"settings");
  1348. WritePrivateProfileIntW(m_skin,L"skin",m_szConfigIniFile,L"settings");
  1349. WritePrivateProfileIntW(m_fix_slow_text,L"fix_slow_text",m_szConfigIniFile,L"settings");
  1350. WritePrivateProfileIntW(m_vj_mode,L"vj_mode",m_szConfigIniFile,L"settings");
  1351. //D3DDISPLAYMODE m_fs_disp_mode
  1352. WritePrivateProfileIntW(m_disp_mode_fs.Width ,L"disp_mode_fs_w",m_szConfigIniFile,L"settings");
  1353. WritePrivateProfileIntW(m_disp_mode_fs.Height ,L"disp_mode_fs_h",m_szConfigIniFile,L"settings");
  1354. WritePrivateProfileIntW(m_disp_mode_fs.RefreshRate,L"disp_mode_fs_r",m_szConfigIniFile,L"settings");
  1355. WritePrivateProfileIntW(m_disp_mode_fs.Format ,L"disp_mode_fs_f",m_szConfigIniFile,L"settings");
  1356. WritePrivateProfileIntW(INT_VERSION ,L"version" ,m_szConfigIniFile,L"settings");
  1357. WritePrivateProfileIntW(INT_SUBVERSION ,L"subversion" ,m_szConfigIniFile,L"settings");
  1358. // finally, save the plugin's unique settings:
  1359. MyWriteConfig();
  1360. }
  1361. //----------------------------------------------------------------------
  1362. //----------------------------------------------------------------------
  1363. //----------------------------------------------------------------------
  1364. int CPluginShell::PluginRender(unsigned char *pWaveL, unsigned char *pWaveR)//, unsigned char *pSpecL, unsigned char *pSpecR)
  1365. {
  1366. // return FALSE here to tell Winamp to terminate the plugin
  1367. if (!m_lpDX || !m_lpDX->m_ready)
  1368. {
  1369. // note: 'm_ready' will go false when a device reset fatally fails
  1370. // (for example, when user resizes window, or toggles fullscreen.)
  1371. m_exiting = 1;
  1372. return false; // EXIT THE PLUGIN
  1373. }
  1374. if (m_hTextWnd)
  1375. m_lost_focus = ((GetFocus() != GetPluginWindow()) && (GetFocus() != m_hTextWnd));
  1376. else
  1377. m_lost_focus = (GetFocus() != GetPluginWindow());
  1378. if ((m_screenmode==WINDOWED && m_hidden) ||
  1379. (m_screenmode==FULLSCREEN && m_lost_focus) ||
  1380. (m_screenmode==WINDOWED && m_resizing)
  1381. )
  1382. {
  1383. Sleep(30);
  1384. return true;
  1385. }
  1386. // test for lost device
  1387. // (this happens when device is fullscreen & user alt-tabs away,
  1388. // or when monitor power-saving kicks in)
  1389. HRESULT hr = m_lpDX->m_lpDevice->TestCooperativeLevel();
  1390. if (hr == D3DERR_DEVICENOTRESET)
  1391. {
  1392. // device WAS lost, and is now ready to be reset (and come back online):
  1393. CleanUpDX9Stuff(0);
  1394. if (m_lpDX->m_lpDevice->Reset(&m_lpDX->m_d3dpp) != D3D_OK)
  1395. {
  1396. // note: a basic warning messagebox will have already been given.
  1397. // now suggest specific advice on how to regain more video memory:
  1398. if (m_lpDX->m_lastErr == DXC_ERR_CREATEDEV_PROBABLY_OUTOFVIDEOMEMORY)
  1399. SuggestHowToFreeSomeMem();
  1400. return false; // EXIT THE PLUGIN
  1401. }
  1402. if (!AllocateDX9Stuff())
  1403. return false; // EXIT THE PLUGIN
  1404. }
  1405. else if (hr != D3D_OK)
  1406. {
  1407. // device is lost, and not yet ready to come back; sleep.
  1408. Sleep(30);
  1409. return true;
  1410. }
  1411. if (m_vjd3d9_device)
  1412. {
  1413. HRESULT hr = m_vjd3d9_device->TestCooperativeLevel();
  1414. if (hr == D3DERR_DEVICENOTRESET)
  1415. {
  1416. RECT c;
  1417. GetClientRect(m_hTextWnd, &c);
  1418. POINT p;
  1419. p.x = c.left;
  1420. p.y = c.top;
  1421. if (ClientToScreen(m_hTextWnd, &p))
  1422. {
  1423. c.left += p.x;
  1424. c.right += p.x;
  1425. c.top += p.y;
  1426. c.bottom += p.y;
  1427. }
  1428. CleanUpVJStuff();
  1429. if (!InitVJStuff(&c))
  1430. return false; // EXIT THE PLUGIN
  1431. }
  1432. }
  1433. if (m_screenmode==DESKTOP)
  1434. {
  1435. PushWindowToJustBeforeDesktop(GetPluginWindow());
  1436. }
  1437. DoTime();
  1438. AnalyzeNewSound(pWaveL, pWaveR);
  1439. AlignWaves();
  1440. DrawAndDisplay(0);
  1441. EnforceMaxFPS();
  1442. m_frame++;
  1443. return true;
  1444. }
  1445. void CPluginShell::PushWindowToJustBeforeDesktop(HWND h)
  1446. {
  1447. // if our window isn't already at the bottom of the Z order,
  1448. // freshly send it to HWND_BOTTOM.
  1449. // this usually gives us the Program Manager window:
  1450. HWND hWndBottom = GetWindow(h, GW_HWNDLAST);
  1451. // then, bottommost 'normal' window is usually the one just in front of it:
  1452. if (hWndBottom == m_hWndProgMan)
  1453. hWndBottom = GetWindow(hWndBottom, GW_HWNDPREV);
  1454. if (hWndBottom != h)
  1455. {
  1456. m_force_accept_WM_WINDOWPOSCHANGING = 1;
  1457. SetWindowPos(h, HWND_BOTTOM, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE);
  1458. m_force_accept_WM_WINDOWPOSCHANGING = 0;
  1459. }
  1460. /*
  1461. HWND hDesktopBkgWnd = FindWindow("SHELLDLL_DefView", "");
  1462. if (hDesktopBkgWnd)
  1463. {
  1464. HWND hWndInFrontOfIcons = GetWindow(h, GW_HWNDPREV);
  1465. if (hWndInFrontOfIcons != h)
  1466. {
  1467. m_force_accept_WM_WINDOWPOSCHANGING = 1;
  1468. SetWindowPos(hDesktopBkgWnd, h, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE);
  1469. m_force_accept_WM_WINDOWPOSCHANGING = 0;
  1470. }
  1471. }
  1472. */
  1473. }
  1474. void CPluginShell::DrawAndDisplay(int redraw)
  1475. {
  1476. int cx = m_vjd3d9_device ? m_nTextWndWidth : m_lpDX->m_client_width;
  1477. int cy = m_vjd3d9_device ? m_nTextWndHeight : m_lpDX->m_client_height;
  1478. if (m_lpDDSText)
  1479. {
  1480. D3DSURFACE_DESC desc;
  1481. if (D3D_OK == m_lpDDSText->GetLevelDesc(0, &desc))
  1482. {
  1483. cx = min(cx, (int)desc.Width);
  1484. cy = min(cy, (int)desc.Height);
  1485. }
  1486. }
  1487. m_upper_left_corner_y = TEXT_MARGIN + GetCanvasMarginY();
  1488. m_upper_right_corner_y = TEXT_MARGIN + GetCanvasMarginY();
  1489. m_lower_left_corner_y = cy - TEXT_MARGIN - GetCanvasMarginY();
  1490. m_lower_right_corner_y = cy - TEXT_MARGIN - GetCanvasMarginY();
  1491. m_left_edge = TEXT_MARGIN + GetCanvasMarginX();
  1492. m_right_edge = cx - TEXT_MARGIN - GetCanvasMarginX();
  1493. /*if (m_screenmode == DESKTOP || m_screenmode == FAKE_FULLSCREEN)
  1494. {
  1495. // check if taskbar is above plugin window;
  1496. // if so, scoot text & icons out of the way.
  1497. // [...should always be true for Desktop Mode,
  1498. // but it's like this for code simplicity.]
  1499. int taskbar_is_above_plugin_window = 1;
  1500. HWND h = FindWindow("Shell_TrayWnd", NULL);
  1501. while (h) //(..shouldn't be very many windows to iterate through here)
  1502. {
  1503. h = GetWindow(h, GW_HWNDPREV);
  1504. if (h == GetPluginWindow())
  1505. {
  1506. taskbar_is_above_plugin_window = 0;
  1507. break;
  1508. }
  1509. }
  1510. if (taskbar_is_above_plugin_window)
  1511. {
  1512. // respect the taskbar area; make sure the text, desktop icons, etc.
  1513. // don't appear underneath it.
  1514. //m_upper_left_corner_y += m_lpDX->m_monitor_work_rect.top - m_lpDX->m_monitor_rect.top;
  1515. //m_upper_right_corner_y += m_lpDX->m_monitor_work_rect.top - m_lpDX->m_monitor_rect.top;
  1516. //m_lower_left_corner_y -= m_lpDX->m_monitor_rect.bottom - m_lpDX->m_monitor_work_rect.bottom;
  1517. //m_lower_right_corner_y -= m_lpDX->m_monitor_rect.bottom - m_lpDX->m_monitor_work_rect.bottom;
  1518. //m_left_edge += m_lpDX->m_monitor_work_rect.left - m_lpDX->m_monitor_rect.left;
  1519. //m_right_edge -= m_lpDX->m_monitor_rect.right - m_lpDX->m_monitor_work_rect.right;
  1520. m_lpDX->UpdateMonitorWorkRect();
  1521. m_upper_left_corner_y = max(m_upper_left_corner_y , m_lpDX->m_monitor_work_rect.top - m_lpDX->m_monitor_rect.top + TEXT_MARGIN + GetCanvasMarginY());
  1522. m_upper_right_corner_y = max(m_upper_right_corner_y, m_lpDX->m_monitor_work_rect.top - m_lpDX->m_monitor_rect.top + TEXT_MARGIN + GetCanvasMarginY());
  1523. m_lower_left_corner_y = min(m_lower_left_corner_y , m_lpDX->m_client_height - (m_lpDX->m_monitor_rect.bottom - m_lpDX->m_monitor_work_rect.bottom) - TEXT_MARGIN - GetCanvasMarginY());
  1524. m_lower_right_corner_y = min(m_lower_right_corner_y, m_lpDX->m_client_height - (m_lpDX->m_monitor_rect.bottom - m_lpDX->m_monitor_work_rect.bottom) - TEXT_MARGIN - GetCanvasMarginY());
  1525. m_left_edge = max(m_left_edge , m_lpDX->m_monitor_work_rect.left - m_lpDX->m_monitor_rect.left + TEXT_MARGIN + GetCanvasMarginX() );
  1526. m_right_edge = min(m_right_edge, m_lpDX->m_client_width - (m_lpDX->m_monitor_rect.right - m_lpDX->m_monitor_work_rect.right) - TEXT_MARGIN + GetCanvasMarginX());
  1527. }
  1528. }*/
  1529. if (D3D_OK==m_lpDX->m_lpDevice->BeginScene())
  1530. {
  1531. MyRenderFn(redraw);
  1532. PrepareFor2DDrawing_B(GetDevice(), GetWidth(), GetHeight());
  1533. RenderDesktop();
  1534. if (!m_vjd3d9_device) // in VJ mode, this renders to different context, so do it after BeginScene() on 2nd device.
  1535. RenderBuiltInTextMsgs(); // to m_lpDDSText?
  1536. MyRenderUI(&m_upper_left_corner_y, &m_upper_right_corner_y, &m_lower_left_corner_y, &m_lower_right_corner_y, m_left_edge, m_right_edge);
  1537. RenderPlaylist();
  1538. if (!m_vjd3d9_device)
  1539. m_text.DrawNow();
  1540. m_lpDX->m_lpDevice->EndScene();
  1541. }
  1542. // VJ Mode:
  1543. if (m_vj_mode && m_vjd3d9_device && !m_hidden_textwnd && D3D_OK==m_vjd3d9_device->BeginScene())
  1544. {
  1545. if (!m_lpDDSText || m_bClearVJWindow)
  1546. m_vjd3d9_device->Clear(0, 0, D3DCLEAR_TARGET, 0xFF000000, 1.0f, 0);
  1547. m_bClearVJWindow = false;
  1548. // note: when using debug DX runtime, textwnd will flash red/green after frame 4, if no text is drawn on a frame!
  1549. RenderBuiltInTextMsgs();
  1550. PrepareFor2DDrawing_B(m_vjd3d9_device, m_nTextWndWidth, m_nTextWndHeight);
  1551. m_text.DrawNow();
  1552. m_vjd3d9_device->EndScene();
  1553. }
  1554. if (m_screenmode == DESKTOP)
  1555. {
  1556. // window is hidden after creation, until 1st frame is ready to go;
  1557. // now that it's ready, we show it.
  1558. // see dxcontext::Internal_Init()'s call to SetWindowPos() for the DESKTOP case.
  1559. if (!IsWindowVisible(GetPluginWindow()))
  1560. ShowWindow(GetPluginWindow(), SW_SHOWNORMAL);
  1561. }
  1562. if (m_screenmode == WINDOWED && (m_lpDX->m_client_width != m_lpDX->m_REAL_client_width || m_lpDX->m_client_height != m_lpDX->m_REAL_client_height))
  1563. {
  1564. int real_w = m_lpDX->m_REAL_client_width; // real client size, in pixels
  1565. int real_h = m_lpDX->m_REAL_client_height;
  1566. int fat_w = m_lpDX->m_client_width; // oversized VS canvas size, in pixels
  1567. int fat_h = m_lpDX->m_client_height;
  1568. int extra_w = fat_w - real_w;
  1569. int extra_h = fat_h - real_h;
  1570. RECT src, dst;
  1571. SetRect(&src, extra_w/2, extra_h/2, extra_w/2 + real_w, extra_h/2 + real_h);
  1572. SetRect(&dst, 0, 0, real_w, real_h);
  1573. m_lpDX->m_lpDevice->Present(&src, &dst,NULL,NULL);
  1574. }
  1575. else
  1576. m_lpDX->m_lpDevice->Present(NULL,NULL,NULL,NULL);
  1577. if (m_vjd3d9_device && !m_hidden_textwnd)
  1578. m_vjd3d9_device->Present(NULL,NULL,NULL,NULL);
  1579. }
  1580. void CPluginShell::EnforceMaxFPS()
  1581. {
  1582. int max_fps;
  1583. switch (m_screenmode)
  1584. {
  1585. case WINDOWED: max_fps = m_max_fps_w; break;
  1586. case FULLSCREEN: max_fps = m_max_fps_fs; break;
  1587. case FAKE_FULLSCREEN: max_fps = m_max_fps_fs; break;
  1588. case DESKTOP: max_fps = m_max_fps_dm; break;
  1589. }
  1590. if (max_fps <= 0)
  1591. return;
  1592. float fps_lo = (float)max_fps;
  1593. float fps_hi = (float)max_fps;
  1594. if (m_save_cpu)
  1595. {
  1596. // Find the optimal lo/hi bounds for the fps
  1597. // that will result in a maximum difference,
  1598. // in the time for a single frame, of 0.003 seconds -
  1599. // the assumed granularity for Sleep(1) -
  1600. // Using this range of acceptable fps
  1601. // will allow us to do (sloppy) fps limiting
  1602. // using only Sleep(1), and never the
  1603. // second half of it: Sleep(0) in a tight loop,
  1604. // which sucks up the CPU (whereas Sleep(1)
  1605. // leaves it idle).
  1606. // The original equation:
  1607. // 1/(max_fps*t1) = 1/(max*fps/t1) - 0.003
  1608. // where:
  1609. // t1 > 0
  1610. // max_fps*t1 is the upper range for fps
  1611. // max_fps/t1 is the lower range for fps
  1612. float a = 1;
  1613. float b = -0.003f * max_fps;
  1614. float c = -1.0f;
  1615. float det = b*b - 4*a*c;
  1616. if (det>0)
  1617. {
  1618. float t1 = (-b + sqrtf(det)) / (2*a);
  1619. //float t2 = (-b - sqrtf(det)) / (2*a);
  1620. if (t1 > 1.0f)
  1621. {
  1622. fps_lo = max_fps / t1;
  1623. fps_hi = max_fps * t1;
  1624. // verify: now [1.0f/fps_lo - 1.0f/fps_hi] should equal 0.003 seconds.
  1625. // note: allowing tolerance to go beyond these values for
  1626. // fps_lo and fps_hi would gain nothing.
  1627. }
  1628. }
  1629. }
  1630. if (m_high_perf_timer_freq.QuadPart > 0)
  1631. {
  1632. LARGE_INTEGER t;
  1633. QueryPerformanceCounter(&t);
  1634. if (m_prev_end_of_frame.QuadPart != 0)
  1635. {
  1636. int ticks_to_wait_lo = (int)((float)m_high_perf_timer_freq.QuadPart / (float)fps_hi);
  1637. int ticks_to_wait_hi = (int)((float)m_high_perf_timer_freq.QuadPart / (float)fps_lo);
  1638. int done = 0;
  1639. int loops = 0;
  1640. do
  1641. {
  1642. QueryPerformanceCounter(&t);
  1643. __int64 t2 = t.QuadPart - m_prev_end_of_frame.QuadPart;
  1644. if (t2 > 2147483000)
  1645. done = 1;
  1646. if (t.QuadPart < m_prev_end_of_frame.QuadPart) // time wrap
  1647. done = 1;
  1648. // this is sloppy - if your freq. is high, this can overflow (to a (-) int) in just a few minutes
  1649. // but it's ok, we have protection for that above.
  1650. int ticks_passed = (int)(t.QuadPart - m_prev_end_of_frame.QuadPart);
  1651. if (ticks_passed >= ticks_to_wait_lo)
  1652. done = 1;
  1653. if (!done)
  1654. {
  1655. // if > 0.01s left, do Sleep(1), which will actually sleep some
  1656. // steady amount of up to 3 ms (depending on the OS),
  1657. // and do so in a nice way (cpu meter drops; laptop battery spared).
  1658. // otherwise, do a few Sleep(0)'s, which just give up the timeslice,
  1659. // but don't really save cpu or battery, but do pass a tiny
  1660. // amount of time.
  1661. //if (ticks_left > (int)m_high_perf_timer_freq.QuadPart/500)
  1662. if (ticks_to_wait_hi - ticks_passed > (int)m_high_perf_timer_freq.QuadPart/100)
  1663. Sleep(5);
  1664. else if (ticks_to_wait_hi - ticks_passed > (int)m_high_perf_timer_freq.QuadPart/1000)
  1665. Sleep(1);
  1666. else
  1667. for (int i=0; i<10; i++)
  1668. Sleep(0); // causes thread to give up its timeslice
  1669. }
  1670. }
  1671. while (!done);
  1672. }
  1673. m_prev_end_of_frame = t;
  1674. }
  1675. else
  1676. {
  1677. Sleep(1000/max_fps);
  1678. }
  1679. }
  1680. void CPluginShell::DoTime()
  1681. {
  1682. if (m_frame==0)
  1683. {
  1684. m_fps = 30;
  1685. m_time = 0;
  1686. m_time_hist_pos = 0;
  1687. }
  1688. double new_raw_time;
  1689. float elapsed;
  1690. if (m_high_perf_timer_freq.QuadPart != 0)
  1691. {
  1692. // get high-precision time
  1693. // precision: usually from 1..6 us (MICROseconds), depending on the cpu speed.
  1694. // (higher cpu speeds tend to have better precision here)
  1695. LARGE_INTEGER t;
  1696. if (!QueryPerformanceCounter(&t))
  1697. {
  1698. m_high_perf_timer_freq.QuadPart = 0; // something went wrong (exception thrown) -> revert to crappy timer
  1699. }
  1700. else
  1701. {
  1702. new_raw_time = (double)t.QuadPart;
  1703. elapsed = (float)((new_raw_time - m_last_raw_time)/(double)m_high_perf_timer_freq.QuadPart);
  1704. }
  1705. }
  1706. if (m_high_perf_timer_freq.QuadPart == 0)
  1707. {
  1708. // get low-precision time
  1709. // precision: usually 1 ms (MILLIsecond) for win98, and 10 ms for win2k.
  1710. new_raw_time = (double)(timeGetTime()*0.001);
  1711. elapsed = (float)(new_raw_time - m_last_raw_time);
  1712. }
  1713. m_last_raw_time = new_raw_time;
  1714. int slots_to_look_back = (m_high_perf_timer_freq.QuadPart==0) ? TIME_HIST_SLOTS : TIME_HIST_SLOTS/2;
  1715. m_time += 1.0f/m_fps;
  1716. // timekeeping goals:
  1717. // 1. keep 'm_time' increasing SMOOTHLY: (smooth animation depends on it)
  1718. // m_time += 1.0f/m_fps; // where m_fps is a bit damped
  1719. // 2. keep m_time_hist[] 100% accurate (except for filtering out pauses),
  1720. // so that when we look take the difference between two entries,
  1721. // we get the real amount of time that passed between those 2 frames.
  1722. // m_time_hist[i] = m_last_raw_time + elapsed_corrected;
  1723. if (m_frame > TIME_HIST_SLOTS)
  1724. {
  1725. if (m_fps < 60.0f)
  1726. slots_to_look_back = (int)(slots_to_look_back*(0.1f + 0.9f*(m_fps/60.0f)));
  1727. if (elapsed > 5.0f/m_fps || elapsed > 1.0f || elapsed < 0)
  1728. elapsed = 1.0f / 30.0f;
  1729. float old_hist_time = m_time_hist[(m_time_hist_pos - slots_to_look_back + TIME_HIST_SLOTS) % TIME_HIST_SLOTS];
  1730. float new_hist_time = m_time_hist[(m_time_hist_pos - 1 + TIME_HIST_SLOTS) % TIME_HIST_SLOTS]
  1731. + elapsed;
  1732. m_time_hist[m_time_hist_pos] = new_hist_time;
  1733. m_time_hist_pos = (m_time_hist_pos+1) % TIME_HIST_SLOTS;
  1734. float new_fps = slots_to_look_back / (float)(new_hist_time - old_hist_time);
  1735. float damping = (m_high_perf_timer_freq.QuadPart==0) ? 0.93f : 0.87f;
  1736. // damp heavily, so that crappy timer precision doesn't make animation jerky
  1737. if (fabsf(m_fps - new_fps) > 3.0f)
  1738. m_fps = new_fps;
  1739. else
  1740. m_fps = damping*m_fps + (1-damping)*new_fps;
  1741. }
  1742. else
  1743. {
  1744. float damping = (m_high_perf_timer_freq.QuadPart==0) ? 0.8f : 0.6f;
  1745. if (m_frame < 2)
  1746. elapsed = 1.0f / 30.0f;
  1747. else if (elapsed > 1.0f || elapsed < 0)
  1748. elapsed = 1.0f / m_fps;
  1749. float old_hist_time = m_time_hist[0];
  1750. float new_hist_time = m_time_hist[(m_time_hist_pos - 1 + TIME_HIST_SLOTS) % TIME_HIST_SLOTS]
  1751. + elapsed;
  1752. m_time_hist[m_time_hist_pos] = new_hist_time;
  1753. m_time_hist_pos = (m_time_hist_pos+1) % TIME_HIST_SLOTS;
  1754. if (m_frame > 0)
  1755. {
  1756. float new_fps = (m_frame) / (new_hist_time - old_hist_time);
  1757. m_fps = damping*m_fps + (1-damping)*new_fps;
  1758. }
  1759. }
  1760. // Synchronize the audio and video by telling Winamp how many milliseconds we want the audio data,
  1761. // before it's actually audible. If we set this to the amount of time it takes to display 1 frame
  1762. // (1/fps), the video and audio should be perfectly synchronized.
  1763. if (m_fps < 2.0f)
  1764. mod1.latencyMs = 500;
  1765. else if (m_fps > 125.0f)
  1766. mod1.latencyMs = 8;
  1767. else
  1768. mod1.latencyMs = (int)(1000.0f/m_fps*m_lpDX->m_frame_delay + 0.5f);
  1769. }
  1770. void CPluginShell::AnalyzeNewSound(unsigned char *pWaveL, unsigned char *pWaveR)
  1771. {
  1772. // we get 576 samples in from winamp.
  1773. // the output of the fft has 'num_frequencies' samples,
  1774. // and represents the frequency range 0 hz - 22,050 hz.
  1775. // usually, plugins only use half of this output (the range 0 hz - 11,025 hz),
  1776. // since >10 khz doesn't usually contribute much.
  1777. int i;
  1778. float temp_wave[2][576];
  1779. int old_i = 0;
  1780. for (i=0; i<576; i++)
  1781. {
  1782. m_sound.fWaveform[0][i] = (float)((pWaveL[i] ^ 128) - 128);
  1783. m_sound.fWaveform[1][i] = (float)((pWaveR[i] ^ 128) - 128);
  1784. // simulating single frequencies from 200 to 11,025 Hz:
  1785. //float freq = 1.0f + 11050*(GetFrame() % 100)*0.01f;
  1786. //m_sound.fWaveform[0][i] = 10*sinf(i*freq*6.28f/44100.0f);
  1787. // damp the input into the FFT a bit, to reduce high-frequency noise:
  1788. temp_wave[0][i] = 0.5f*(m_sound.fWaveform[0][i] + m_sound.fWaveform[0][old_i]);
  1789. temp_wave[1][i] = 0.5f*(m_sound.fWaveform[1][i] + m_sound.fWaveform[1][old_i]);
  1790. old_i = i;
  1791. }
  1792. m_fftobj.time_to_frequency_domain(temp_wave[0], m_sound.fSpectrum[0]);
  1793. m_fftobj.time_to_frequency_domain(temp_wave[1], m_sound.fSpectrum[1]);
  1794. // sum (left channel) spectrum up into 3 bands
  1795. // [note: the new ranges do it so that the 3 bands are equally spaced, pitch-wise]
  1796. float min_freq = 200.0f;
  1797. float max_freq = 11025.0f;
  1798. float net_octaves = (logf(max_freq/min_freq) / logf(2.0f)); // 5.7846348455575205777914165223593
  1799. float octaves_per_band = net_octaves / 3.0f; // 1.9282116151858401925971388407864
  1800. float mult = powf(2.0f, octaves_per_band); // each band's highest freq. divided by its lowest freq.; 3.805831305510122517035102576162
  1801. // [to verify: min_freq * mult * mult * mult should equal max_freq.]
  1802. for (int ch=0; ch<2; ch++)
  1803. {
  1804. for (i=0; i<3; i++)
  1805. {
  1806. // old guesswork code for this:
  1807. // float exp = 2.1f;
  1808. // int start = (int)(NUM_FREQUENCIES*0.5f*powf(i/3.0f, exp));
  1809. // int end = (int)(NUM_FREQUENCIES*0.5f*powf((i+1)/3.0f, exp));
  1810. // results:
  1811. // old range: new range (ideal):
  1812. // bass: 0-1097 200-761
  1813. // mids: 1097-4705 761-2897
  1814. // treb: 4705-11025 2897-11025
  1815. int start = (int)(NUM_FREQUENCIES * min_freq*powf(mult, (float)i)/11025.0f);
  1816. int end = (int)(NUM_FREQUENCIES * min_freq*powf(mult, (float)(i+1))/11025.0f);
  1817. if (start < 0) start = 0;
  1818. if (end > NUM_FREQUENCIES) end = NUM_FREQUENCIES;
  1819. m_sound.imm[ch][i] = 0;
  1820. for (int j=start; j<end; j++)
  1821. m_sound.imm[ch][i] += m_sound.fSpectrum[ch][j];
  1822. m_sound.imm[ch][i] /= (float)(end-start);
  1823. }
  1824. }
  1825. // some code to find empirical long-term averages for imm[0..2]:
  1826. /*{
  1827. static float sum[3];
  1828. static int count = 0;
  1829. #define FRAMES_PER_SONG 300 // should be at least 200!
  1830. if (m_frame < FRAMES_PER_SONG)
  1831. {
  1832. sum[0] = sum[1] = sum[2] = 0;
  1833. count = 0;
  1834. }
  1835. else
  1836. {
  1837. if (m_frame%FRAMES_PER_SONG == 0)
  1838. {
  1839. char buf[256];
  1840. sprintf(buf, "%.4f, %.4f, %.4f (%d samples / ~%d songs)\n",
  1841. sum[0]/(float)(count),
  1842. sum[1]/(float)(count),
  1843. sum[2]/(float)(count),
  1844. count,
  1845. count/(FRAMES_PER_SONG-10)
  1846. );
  1847. OutputDebugString(buf);
  1848. // skip to next song
  1849. PostMessage(m_hWndWinamp,WM_COMMAND,40048,0);
  1850. }
  1851. else if (m_frame%FRAMES_PER_SONG == 5)
  1852. {
  1853. // then advance to 0-2 minutes into the song:
  1854. PostMessage(m_hWndWinamp,WM_USER,(20 + (warand()%65) + (rand()%65))*1000,106);
  1855. }
  1856. else if (m_frame%FRAMES_PER_SONG >= 10)
  1857. {
  1858. sum[0] += m_sound.imm[0];
  1859. sum[1] += m_sound.imm[1];
  1860. sum[2] += m_sound.imm[2];
  1861. count++;
  1862. }
  1863. }
  1864. }*/
  1865. // multiply by long-term, empirically-determined inverse averages:
  1866. // (for a trial of 244 songs, 10 seconds each, somewhere in the 2nd or 3rd minute,
  1867. // the average levels were: 0.326781557 0.38087377 0.199888934
  1868. for (int ch=0; ch<2; ch++)
  1869. {
  1870. m_sound.imm[ch][0] /= 0.326781557f;//0.270f;
  1871. m_sound.imm[ch][1] /= 0.380873770f;//0.343f;
  1872. m_sound.imm[ch][2] /= 0.199888934f;//0.295f;
  1873. }
  1874. // do temporal blending to create attenuated and super-attenuated versions
  1875. for (int ch=0; ch<2; ch++)
  1876. {
  1877. for (i=0; i<3; i++)
  1878. {
  1879. // m_sound.avg[i]
  1880. {
  1881. float avg_mix;
  1882. if (m_sound.imm[ch][i] > m_sound.avg[ch][i])
  1883. avg_mix = AdjustRateToFPS(0.2f, 14.0f, m_fps);
  1884. else
  1885. avg_mix = AdjustRateToFPS(0.5f, 14.0f, m_fps);
  1886. m_sound.avg[ch][i] = m_sound.avg[ch][i]*avg_mix + m_sound.imm[ch][i]*(1-avg_mix);
  1887. }
  1888. // m_sound.med_avg[i]
  1889. // m_sound.long_avg[i]
  1890. {
  1891. float med_mix = 0.91f;//0.800f + 0.11f*powf(t, 0.4f); // primarily used for velocity_damping
  1892. float long_mix = 0.96f;//0.800f + 0.16f*powf(t, 0.2f); // primarily used for smoke plumes
  1893. med_mix = AdjustRateToFPS(med_mix, 14.0f, m_fps);
  1894. long_mix = AdjustRateToFPS(long_mix, 14.0f, m_fps);
  1895. m_sound.med_avg[ch][i] = m_sound.med_avg[ch][i]*(med_mix) + m_sound.imm[ch][i]*(1-med_mix);
  1896. m_sound.long_avg[ch][i] = m_sound.long_avg[ch][i]*(long_mix) + m_sound.imm[ch][i]*(1-long_mix);
  1897. }
  1898. }
  1899. }
  1900. }
  1901. void CPluginShell::PrepareFor2DDrawing_B(IDirect3DDevice9 *pDevice, int w, int h)
  1902. {
  1903. // New 2D drawing area will have x,y coords in the range <-1,-1> .. <1,1>
  1904. // +--------+ Y=-1
  1905. // | |
  1906. // | screen | Z=0: front of scene
  1907. // | | Z=1: back of scene
  1908. // +--------+ Y=1
  1909. // X=-1 X=1
  1910. // NOTE: After calling this, be sure to then call (at least):
  1911. // 1. SetVertexShader()
  1912. // 2. SetTexture(), if you need it
  1913. // before rendering primitives!
  1914. // Also, be sure your sprites have a z coordinate of 0.
  1915. pDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
  1916. pDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
  1917. pDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
  1918. pDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
  1919. pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
  1920. pDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
  1921. pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
  1922. pDevice->SetRenderState(D3DRS_CLIPPING, TRUE);
  1923. pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
  1924. pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
  1925. pDevice->SetRenderState(D3DRS_LOCALVIEWER, FALSE);
  1926. pDevice->SetRenderState(D3DRS_COLORVERTEX, TRUE);
  1927. pDevice->SetTexture(0, NULL);
  1928. pDevice->SetTexture(1, NULL);
  1929. pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);//D3DTEXF_LINEAR);
  1930. pDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_POINT);//D3DTEXF_LINEAR);
  1931. pDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
  1932. pDevice->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
  1933. pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
  1934. pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  1935. pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
  1936. pDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
  1937. pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
  1938. pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
  1939. pDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
  1940. pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
  1941. // set up for 2D drawing:
  1942. {
  1943. D3DXMATRIX Ortho2D;
  1944. D3DXMATRIX Identity;
  1945. pMatrixOrthoLH(&Ortho2D, (float)w, (float)h, 0.0f, 1.0f);
  1946. D3DXMatrixIdentity(&Identity);
  1947. pDevice->SetTransform(D3DTS_PROJECTION, &Ortho2D);
  1948. pDevice->SetTransform(D3DTS_WORLD, &Identity);
  1949. pDevice->SetTransform(D3DTS_VIEW, &Identity);
  1950. }
  1951. }
  1952. void CPluginShell::DrawDarkTranslucentBox(RECT* pr)
  1953. {
  1954. // 'pr' is the rectangle that some text will occupy;
  1955. // a black box will be drawn around it, plus a bit of extra margin space.
  1956. if (m_vjd3d9_device)
  1957. return;
  1958. m_lpDX->m_lpDevice->SetVertexShader(NULL);
  1959. m_lpDX->m_lpDevice->SetPixelShader(NULL);
  1960. m_lpDX->m_lpDevice->SetFVF(SIMPLE_VERTEX_FORMAT);
  1961. m_lpDX->m_lpDevice->SetTexture(0, NULL);
  1962. m_lpDX->m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
  1963. m_lpDX->m_lpDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  1964. m_lpDX->m_lpDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  1965. m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
  1966. m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
  1967. m_lpDX->m_lpDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
  1968. m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
  1969. m_lpDX->m_lpDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
  1970. // set up a quad
  1971. SIMPLEVERTEX verts[4];
  1972. for (int i=0; i<4; i++)
  1973. {
  1974. verts[i].x = (i%2==0) ? (float)(-m_lpDX->m_client_width /2 + pr->left) :
  1975. (float)(-m_lpDX->m_client_width /2 + pr->right);
  1976. verts[i].y = (i/2==0) ? (float)-(-m_lpDX->m_client_height/2 + pr->bottom) :
  1977. (float)-(-m_lpDX->m_client_height/2 + pr->top);
  1978. verts[i].z = 0;
  1979. verts[i].Diffuse = (m_screenmode==DESKTOP) ? 0xE0000000 : 0xD0000000;
  1980. }
  1981. m_lpDX->m_lpDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, verts, sizeof(SIMPLEVERTEX));
  1982. // undo unusual state changes:
  1983. m_lpDX->m_lpDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
  1984. m_lpDX->m_lpDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
  1985. }
  1986. void CPluginShell::RenderBuiltInTextMsgs()
  1987. {
  1988. int _show_press_f1_NOW = (m_show_press_f1_msg && m_time < PRESS_F1_DUR);
  1989. {
  1990. RECT r;
  1991. if (m_show_help)
  1992. {
  1993. int y = m_upper_left_corner_y;
  1994. SetRect(&r, 0, 0, GetWidth(), GetHeight());
  1995. if(!g_szHelp_W)
  1996. m_d3dx_font[HELPSCREEN_FONT]->DrawTextA(NULL, (char*)g_szHelp, -1, &r, DT_CALCRECT, 0xFFFFFFFF);
  1997. else
  1998. m_d3dx_font[HELPSCREEN_FONT]->DrawTextW(NULL, g_szHelp, -1, &r, DT_CALCRECT, 0xFFFFFFFF);
  1999. r.top += m_upper_left_corner_y;
  2000. r.left += m_left_edge;
  2001. r.right += m_left_edge + PLAYLIST_INNER_MARGIN*2;
  2002. r.bottom += m_upper_left_corner_y + PLAYLIST_INNER_MARGIN*2;
  2003. DrawDarkTranslucentBox(&r);
  2004. r.top += PLAYLIST_INNER_MARGIN;
  2005. r.left += PLAYLIST_INNER_MARGIN;
  2006. r.right -= PLAYLIST_INNER_MARGIN;
  2007. r.bottom -= PLAYLIST_INNER_MARGIN;
  2008. if(!g_szHelp_W)
  2009. m_d3dx_font[HELPSCREEN_FONT]->DrawTextA(NULL, (char*)g_szHelp, -1, &r, 0, 0xFFFFFFFF);
  2010. else
  2011. m_d3dx_font[HELPSCREEN_FONT]->DrawTextW(NULL, g_szHelp, -1, &r, 0, 0xFFFFFFFF);
  2012. m_upper_left_corner_y += r.bottom-r.top + PLAYLIST_INNER_MARGIN*3;
  2013. }
  2014. // render 'Press F1 for Help' message in lower-right corner:
  2015. if (_show_press_f1_NOW)
  2016. {
  2017. int dx = (int)(160.0f * powf(m_time/(float)(PRESS_F1_DUR), (float)(PRESS_F1_EXP)));
  2018. SetRect(&r, m_left_edge, m_lower_right_corner_y - GetFontHeight(DECORATIVE_FONT), m_right_edge + dx, m_lower_right_corner_y);
  2019. m_lower_right_corner_y -= m_d3dx_font[DECORATIVE_FONT]->DrawTextW(NULL, WASABI_API_LNGSTRINGW(IDS_PRESS_F1_MSG), -1, &r, DT_RIGHT, 0xFFFFFFFF);
  2020. }
  2021. }
  2022. }
  2023. void CPluginShell::RenderPlaylist()
  2024. {
  2025. // draw playlist:
  2026. if (m_show_playlist)
  2027. {
  2028. RECT r;
  2029. int nSongs = SendMessage(m_hWndWinamp,WM_USER, 0, 124);
  2030. int now_playing = SendMessage(m_hWndWinamp,WM_USER, 0, 125);
  2031. if (nSongs <= 0)
  2032. {
  2033. m_show_playlist = 0;
  2034. }
  2035. else
  2036. {
  2037. int playlist_vert_pixels = m_lower_left_corner_y - m_upper_left_corner_y;
  2038. int disp_lines = min(MAX_SONGS_PER_PAGE, (playlist_vert_pixels - PLAYLIST_INNER_MARGIN*2) / GetFontHeight(PLAYLIST_FONT));
  2039. int total_pages = (nSongs) / disp_lines;
  2040. if (disp_lines<=0)
  2041. return;
  2042. // apply PgUp/PgDn keypresses since last time
  2043. m_playlist_pos -= m_playlist_pageups * disp_lines;
  2044. m_playlist_pageups = 0;
  2045. if (m_playlist_pos < 0)
  2046. m_playlist_pos = 0;
  2047. if (m_playlist_pos >= nSongs)
  2048. m_playlist_pos = nSongs-1;
  2049. // NOTE: 'dwFlags' is used for both DDRAW and DX9
  2050. DWORD dwFlags = DT_SINGLELINE;// | DT_NOPREFIX | DT_WORD_ELLIPSIS;
  2051. DWORD color;
  2052. int cur_page = (m_playlist_pos) / disp_lines;
  2053. int cur_line = (m_playlist_pos + disp_lines - 1) % disp_lines;
  2054. int new_top_idx = cur_page * disp_lines;
  2055. int new_btm_idx = new_top_idx + disp_lines;
  2056. wchar_t buf[1024] = {0};
  2057. // ask winamp for the song names, but DO IT BEFORE getting the DC,
  2058. // otherwise vaio will crash (~DDRAW port).
  2059. if (m_playlist_top_idx != new_top_idx ||
  2060. m_playlist_btm_idx != new_btm_idx)
  2061. {
  2062. for (int i=0; i<disp_lines; i++)
  2063. {
  2064. int j = new_top_idx + i;
  2065. if (j < nSongs)
  2066. {
  2067. // clip max len. of song name to 240 chars, to prevent overflows
  2068. lstrcpynW(buf, (wchar_t*)SendMessage(m_hWndWinamp, WM_USER, j, IPC_GETPLAYLISTTITLEW), 240);
  2069. wsprintfW(m_playlist[i], L"%d. %s ", j+1, buf); // leave an extra space @ end, so italicized fonts don't get clipped
  2070. }
  2071. }
  2072. }
  2073. // update playlist cache, if necessary:
  2074. if (m_playlist_top_idx != new_top_idx ||
  2075. m_playlist_btm_idx != new_btm_idx)
  2076. {
  2077. m_playlist_top_idx = new_top_idx;
  2078. m_playlist_btm_idx = new_btm_idx;
  2079. m_playlist_width_pixels = 0;
  2080. int max_w = min(m_right_edge - m_left_edge, m_lpDX->m_client_width - TEXT_MARGIN*2 - PLAYLIST_INNER_MARGIN*2);
  2081. for (int i=0; i<disp_lines; i++)
  2082. {
  2083. int j = new_top_idx + i;
  2084. if (j < nSongs)
  2085. {
  2086. // clip max len. of song name to 240 chars, to prevent overflows
  2087. //strcpy(buf, (char*)SendMessage(m_hWndWinamp, WM_USER, j, 212));
  2088. //buf[240] = 0;
  2089. //sprintf(m_playlist[i], "%d. %s ", j+1, buf); // leave an extra space @ end, so italicized fonts don't get clipped
  2090. SetRect(&r, 0, 0, max_w, 1024);
  2091. m_d3dx_font[PLAYLIST_FONT]->DrawTextW(NULL, m_playlist[i], -1, &r, dwFlags | DT_CALCRECT, 0xFFFFFFFF);
  2092. int w = r.right-r.left;
  2093. if (w>0)
  2094. m_playlist_width_pixels = max(m_playlist_width_pixels, w);
  2095. }
  2096. else
  2097. {
  2098. m_playlist[i][0] = 0;
  2099. }
  2100. }
  2101. if (m_playlist_width_pixels == 0 ||
  2102. m_playlist_width_pixels > max_w)
  2103. m_playlist_width_pixels = max_w;
  2104. }
  2105. int start = max(0, (cur_page)*disp_lines);
  2106. int end = min(nSongs, (cur_page+1)*disp_lines);
  2107. // draw dark box around where the playlist will go:
  2108. RECT r;
  2109. r.top = m_upper_left_corner_y;
  2110. r.left = m_left_edge;
  2111. r.right = m_left_edge + m_playlist_width_pixels + PLAYLIST_INNER_MARGIN*2;
  2112. r.bottom = m_upper_left_corner_y + (end-start)*GetFontHeight(PLAYLIST_FONT) + PLAYLIST_INNER_MARGIN*2;
  2113. DrawDarkTranslucentBox(&r);
  2114. //m_d3dx_font[PLAYLIST_FONT]->Begin();
  2115. // draw playlist text
  2116. int y = m_upper_left_corner_y + PLAYLIST_INNER_MARGIN;
  2117. for (int i=start; i<end; i++)
  2118. {
  2119. SetRect(&r, m_left_edge + PLAYLIST_INNER_MARGIN, y, m_left_edge + PLAYLIST_INNER_MARGIN + m_playlist_width_pixels, y + GetFontHeight(PLAYLIST_FONT));
  2120. if (m_lpDX->GetBitDepth() == 8)
  2121. color = (i==m_playlist_pos) ?
  2122. (i==now_playing ? 0xFFFFFFFF : 0xFFFFFFFF) :
  2123. (i==now_playing ? 0xFFFFFFFF : 0xFF707070);
  2124. else
  2125. color = (i==m_playlist_pos) ?
  2126. (i==now_playing ? PLAYLIST_COLOR_BOTH : PLAYLIST_COLOR_HILITE_TRACK) :
  2127. (i==now_playing ? PLAYLIST_COLOR_PLAYING_TRACK : PLAYLIST_COLOR_NORMAL);
  2128. y += m_d3dx_font[PLAYLIST_FONT]->DrawTextW(NULL, m_playlist[i-start], -1, &r, dwFlags, color);
  2129. }
  2130. //m_d3dx_font[PLAYLIST_FONT]->End();
  2131. }
  2132. }
  2133. }
  2134. void CPluginShell::SuggestHowToFreeSomeMem()
  2135. {
  2136. // This function is called when the plugin runs out of video memory;
  2137. // it lets you show a messagebox to the user so you can (intelligently)
  2138. // suggest how to free up some video memory, based on what settings
  2139. // they've chosen.
  2140. wchar_t str[1024];
  2141. if (m_lpDX->m_current_mode.multisamp != D3DMULTISAMPLE_NONE)
  2142. {
  2143. if (m_lpDX->m_current_mode.screenmode == WINDOWED)
  2144. WASABI_API_LNGSTRINGW_BUF(IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG, str, 2048);
  2145. else if (m_lpDX->m_current_mode.screenmode == FAKE_FULLSCREEN)
  2146. WASABI_API_LNGSTRINGW_BUF(IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG_2, str, 2048);
  2147. else
  2148. WASABI_API_LNGSTRINGW_BUF(IDS_TO_FREE_UP_SOME_MEMORY_RESTART_WINAMP_THEN_GO_TO_CONFIG_3, str, 2048);
  2149. }
  2150. else
  2151. if (m_lpDX->m_current_mode.screenmode == FULLSCREEN) // true fullscreen
  2152. WASABI_API_LNGSTRINGW_BUF(IDS_TO_FREE_UP_VIDEO_MEMORY, str, 2048);
  2153. else // windowed, desktop mode, or fake fullscreen
  2154. WASABI_API_LNGSTRINGW_BUF(IDS_TO_FREE_UP_VIDEO_MEMORY, str, 2048);
  2155. MessageBoxW(m_lpDX->GetHwnd(), str, WASABI_API_LNGSTRINGW(IDS_MILKDROP_SUGGESTION), MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  2156. }
  2157. LRESULT CALLBACK CPluginShell::WindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam)
  2158. {
  2159. //if (uMsg==WM_GETDLGCODE)
  2160. // return DLGC_WANTALLKEYS|DLGC_WANTCHARS|DLGC_WANTMESSAGE; // this tells the embedwnd that we want keypresses to flow through to our client wnd.
  2161. if (uMsg == WM_CREATE)
  2162. {
  2163. CREATESTRUCT *create = (CREATESTRUCT *)lParam;
  2164. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)create->lpCreateParams);
  2165. }
  2166. CPluginShell* p = (CPluginShell*)GetWindowLongPtr(hWnd,GWLP_USERDATA);
  2167. if (p)
  2168. return p->PluginShellWindowProc(hWnd, uMsg, wParam, lParam);
  2169. else
  2170. return DefWindowProcW(hWnd, uMsg, wParam, lParam);
  2171. }
  2172. LRESULT CPluginShell::PluginShellWindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam)
  2173. {
  2174. USHORT mask = 1 << (sizeof(SHORT)*8 - 1);
  2175. //bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0;
  2176. bool bCtrlHeldDown = (GetKeyState(VK_CONTROL) & mask) != 0;
  2177. //bool bAltHeldDown: most keys come in under WM_SYSKEYDOWN when ALT is depressed.
  2178. int i;
  2179. #ifdef _DEBUG
  2180. char caption[256] = "WndProc: frame 0, ";
  2181. if (m_frame > 0)
  2182. {
  2183. float time = m_time;
  2184. int hours = (int)(time/3600);
  2185. time -= hours*3600;
  2186. int minutes = (int)(time/60);
  2187. time -= minutes*60;
  2188. int seconds = (int)time;
  2189. time -= seconds;
  2190. int dsec = (int)(time*100);
  2191. sprintf(caption, "WndProc: frame %d, t=%dh:%02dm:%02d.%02ds, ", m_frame, hours, minutes, seconds, dsec);
  2192. }
  2193. if (uMsg != WM_MOUSEMOVE &&
  2194. uMsg != WM_NCHITTEST &&
  2195. uMsg != WM_SETCURSOR &&
  2196. uMsg != WM_COPYDATA &&
  2197. uMsg != WM_USER)
  2198. OutputDebugMessage(caption, hWnd, uMsg, wParam, lParam);
  2199. #endif
  2200. switch (uMsg)
  2201. {
  2202. case WM_USER:
  2203. if (m_screenmode == DESKTOP)
  2204. {
  2205. // this function resides in vms_desktop.dll;
  2206. // its response will come later, via the WM_COPYDATA
  2207. // message (See below).
  2208. //KIV: **THIS CALL CRASHES EXPLORER IN VISTA**
  2209. getItemData(wParam);
  2210. return 0;
  2211. }
  2212. break;
  2213. case WM_COPYDATA:
  2214. if (m_screenmode == DESKTOP)
  2215. {
  2216. // this message is vms_desktop.dll's response to
  2217. // our call to getItemData().
  2218. PCOPYDATASTRUCT c = (PCOPYDATASTRUCT)lParam;
  2219. if (c && (c->cbData % sizeof(icon_t) == 0))
  2220. {
  2221. icon_t *pNewIcons = (icon_t*)c->lpData;
  2222. EnterCriticalSection(&m_desktop_cs);
  2223. if (m_desktop_icon_state == 1 && (c->dwData & 0x80000000)) // if doing a total refresh...
  2224. {
  2225. // ...we build the list from zero
  2226. int len = c->dwData & 0xFFFF;
  2227. for (int i=0; i<len; i++)
  2228. m_icon_list.push_back(pNewIcons[i]);
  2229. }
  2230. else if (m_desktop_icon_state == 3 && !(c->dwData & 0x80000000))
  2231. {
  2232. // otherwise, we alter existing things in the list:
  2233. IconList::iterator p;
  2234. int start = c->dwData & 0xFFFF;
  2235. int len = c->dwData >> 16;
  2236. int i = 0;
  2237. for (p = m_icon_list.begin(); p != m_icon_list.end() && i<start; p++)
  2238. i++;
  2239. for (; p != m_icon_list.end() && i<start+len; p++)
  2240. {
  2241. p->x = pNewIcons[i-start].x;
  2242. p->y = pNewIcons[i-start].y;
  2243. memcpy(p->name, pNewIcons[i-start].name, sizeof(p->name));
  2244. memcpy(p->pidl, pNewIcons[i-start].pidl, sizeof(p->pidl));
  2245. i++;
  2246. }
  2247. m_desktop_icon_state = 2;
  2248. m_desktop_icon_update_frame = GetFrame();
  2249. }
  2250. LeaveCriticalSection(&m_desktop_cs);
  2251. }
  2252. return 0;
  2253. }
  2254. break;
  2255. case WM_ERASEBKGND:
  2256. // Repaint window when song is paused and image needs to be repainted:
  2257. if (SendMessage(m_hWndWinamp,WM_USER,0,104)!=1 && m_lpDX && m_lpDX->m_lpDevice && GetFrame() > 0) // WM_USER/104 return codes: 1=playing, 3=paused, other=stopped
  2258. {
  2259. m_lpDX->m_lpDevice->Present(NULL,NULL,NULL,NULL);
  2260. return 0;
  2261. }
  2262. break;
  2263. case WM_WINDOWPOSCHANGING:
  2264. if (
  2265. m_screenmode == DESKTOP
  2266. && (!m_force_accept_WM_WINDOWPOSCHANGING)
  2267. && m_lpDX && m_lpDX->m_ready
  2268. )
  2269. {
  2270. // unless we requested it ourselves or it's init time,
  2271. // prevent the fake desktop window from moving around
  2272. // in the Z order! (i.e., keep it on the bottom)
  2273. // without this code, when you click on the 'real' desktop
  2274. // in a multimon setup, any windows that are overtop of the
  2275. // 'fake' desktop will flash, since they'll be covered
  2276. // up by the fake desktop window (but then shown again on
  2277. // the next frame, when we detect that the fake desktop
  2278. // window isn't on bottom & send it back to the bottom).
  2279. LPWINDOWPOS pwp = (LPWINDOWPOS)lParam;
  2280. if (pwp)
  2281. pwp->flags |= SWP_NOOWNERZORDER | SWP_NOZORDER;
  2282. }
  2283. if (m_screenmode==WINDOWED && m_lpDX && m_lpDX->m_ready && m_lpDX->m_current_mode.m_skin)
  2284. m_lpDX->SaveWindow();
  2285. break;
  2286. case WM_NCACTIVATE:
  2287. // *Very Important Handler!*
  2288. // -Without this code, the app would not work properly when running in true
  2289. // fullscreen mode on multiple monitors; it would auto-minimize whenever the
  2290. // user clicked on a window in another display.
  2291. if (wParam == 0 &&
  2292. m_screenmode == FULLSCREEN &&
  2293. m_frame > 0 &&
  2294. !m_exiting &&
  2295. m_lpDX &&
  2296. m_lpDX->m_ready
  2297. && m_lpDX->m_lpD3D &&
  2298. m_lpDX->m_lpD3D->GetAdapterCount() > 1
  2299. )
  2300. {
  2301. return 0;
  2302. }
  2303. break;
  2304. case WM_DESTROY:
  2305. // note: don't post quit message here if the window is being destroyed
  2306. // and re-created on a switch between windowed & FAKE fullscreen modes.
  2307. if (!m_lpDX->TempIgnoreDestroyMessages())
  2308. {
  2309. // this is a final exit, and not just destroy-then-recreate-the-window.
  2310. // so, flag DXContext so it knows that someone else
  2311. // will take care of destroying the window!
  2312. m_lpDX->OnTrulyExiting();
  2313. PostQuitMessage(0);
  2314. }
  2315. return FALSE;
  2316. break;
  2317. // benski> a little hack to get the window size correct. it seems to work
  2318. case WM_USER+555:
  2319. if (m_lpDX && m_lpDX->m_ready && m_screenmode==WINDOWED && !m_resizing)
  2320. {
  2321. OnUserResizeWindow();
  2322. m_lpDX->SaveWindow();
  2323. }
  2324. break;
  2325. case WM_MOVE:
  2326. m_lpDX->SaveWindow();
  2327. break;
  2328. case WM_SIZE:
  2329. // clear or set activity flag to reflect focus
  2330. if (m_lpDX && m_lpDX->m_ready && m_screenmode==WINDOWED && !m_resizing)
  2331. {
  2332. m_hidden = (SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam) ? TRUE : FALSE;
  2333. if (SIZE_MAXIMIZED==wParam || SIZE_RESTORED==wParam) // the window has been maximized or restored
  2334. OnUserResizeWindow();
  2335. }
  2336. break;
  2337. case WM_ENTERSIZEMOVE:
  2338. m_resizing = 1;
  2339. break;
  2340. case WM_EXITSIZEMOVE:
  2341. if (m_lpDX && m_lpDX->m_ready && m_screenmode==WINDOWED)
  2342. OnUserResizeWindow();
  2343. m_lpDX->SaveWindow();
  2344. m_resizing = 0;
  2345. break;
  2346. case WM_GETMINMAXINFO:
  2347. {
  2348. // don't let the window get too small
  2349. MINMAXINFO* p = (MINMAXINFO*)lParam;
  2350. if (p->ptMinTrackSize.x < 64)
  2351. p->ptMinTrackSize.x = 64;
  2352. p->ptMinTrackSize.y = p->ptMinTrackSize.x*3/4;
  2353. }
  2354. return 0;
  2355. case WM_MOUSEMOVE:
  2356. if (m_screenmode==DESKTOP && (m_desktop_dragging==1 || m_desktop_box==1))
  2357. {
  2358. m_desktop_drag_curpos.x = LOWORD(lParam);
  2359. m_desktop_drag_curpos.y = HIWORD(lParam);
  2360. if (m_desktop_box==1)
  2361. {
  2362. // update selection based on box coords
  2363. RECT box, temp;
  2364. box.left = min(m_desktop_drag_curpos.x, m_desktop_drag_startpos.x);
  2365. box.right = max(m_desktop_drag_curpos.x, m_desktop_drag_startpos.x);
  2366. box.top = min(m_desktop_drag_curpos.y, m_desktop_drag_startpos.y);
  2367. box.bottom = max(m_desktop_drag_curpos.y, m_desktop_drag_startpos.y);
  2368. IconList::iterator p;
  2369. for (p = m_icon_list.begin(); p != m_icon_list.end(); p++)
  2370. {
  2371. p->selected = 0;
  2372. if (IntersectRect(&temp, &box, &p->label_rect))
  2373. p->selected = 1;
  2374. else if (IntersectRect(&temp, &box, &p->icon_rect))
  2375. p->selected = 1;
  2376. }
  2377. }
  2378. // repaint window manually, if winamp is paused
  2379. if (SendMessage(m_hWndWinamp,WM_USER,0,104) != 1)
  2380. {
  2381. PushWindowToJustBeforeDesktop(GetPluginWindow());
  2382. DrawAndDisplay(1);
  2383. }
  2384. //return 0;
  2385. }
  2386. m_lpDX->SaveWindow();
  2387. break;
  2388. case WM_LBUTTONUP:
  2389. if (m_screenmode==DESKTOP)
  2390. {
  2391. if (m_desktop_dragging)
  2392. {
  2393. m_desktop_dragging = 0;
  2394. // move selected item(s) to new cursor position
  2395. int dx = LOWORD(lParam) - m_desktop_drag_startpos.x;
  2396. int dy = HIWORD(lParam) - m_desktop_drag_startpos.y;
  2397. if (dx!=0 || dy!=0)
  2398. {
  2399. int idx=0;
  2400. IconList::iterator p;
  2401. for (p = m_icon_list.begin(); p != m_icon_list.end(); p++)
  2402. {
  2403. if (p->selected)
  2404. {
  2405. SendMessage(m_hWndDesktopListView, LVM_SETITEMPOSITION, idx, MAKELPARAM(p->x + dx, p->y + dy));
  2406. p->x += dx;
  2407. p->y += dy;
  2408. }
  2409. idx++;
  2410. }
  2411. }
  2412. // repaint window manually, if winamp is paused
  2413. if (SendMessage(m_hWndWinamp,WM_USER,0,104) != 1)
  2414. {
  2415. PushWindowToJustBeforeDesktop(GetPluginWindow());
  2416. DrawAndDisplay(1);
  2417. }
  2418. }
  2419. if (m_desktop_box)
  2420. {
  2421. m_desktop_box = 0;
  2422. // repaint window manually, if winamp is paused
  2423. if (SendMessage(m_hWndWinamp,WM_USER,0,104) != 1)
  2424. {
  2425. PushWindowToJustBeforeDesktop(GetPluginWindow());
  2426. DrawAndDisplay(1);
  2427. }
  2428. }
  2429. //return 0;
  2430. }
  2431. break;
  2432. case WM_USER + 1666:
  2433. if (wParam == 1 && lParam == 15)
  2434. {
  2435. if (m_screenmode == FULLSCREEN || m_screenmode == FAKE_FULLSCREEN)
  2436. ToggleFullScreen();
  2437. }
  2438. return 0;
  2439. case WM_LBUTTONDOWN:
  2440. case WM_LBUTTONDBLCLK:
  2441. case WM_RBUTTONDOWN:
  2442. case WM_RBUTTONUP:
  2443. // Toggle between Fullscreen and Windowed modes on double-click
  2444. // note: this requires the 'CS_DBLCLKS' windowclass style!
  2445. if (m_screenmode != DESKTOP)
  2446. {
  2447. SetFocus(hWnd);
  2448. if (uMsg==WM_LBUTTONDBLCLK && m_frame>0)
  2449. {
  2450. ToggleFullScreen();
  2451. return 0;
  2452. }
  2453. }
  2454. else
  2455. {
  2456. POINT pt;
  2457. pt.x = LOWORD(lParam);
  2458. pt.y = HIWORD(lParam);
  2459. int done = 0;
  2460. for (int pass=0; pass<2 && !done; pass++)
  2461. {
  2462. IconList::iterator p;
  2463. for (p = m_icon_list.begin(); p != m_icon_list.end(); p++)
  2464. {
  2465. RECT *pr = (pass==0) ? &p->icon_rect : &p->label_rect;
  2466. int bottom_extend = (pass==0) ? 3 : 0; // accepts clicks in the 3-pixel gap between the icon and the text label.
  2467. if (pt.x >= pr->left &&
  2468. pt.x <= pr->right &&
  2469. pt.y >= pr->top &&
  2470. pt.y <= pr->bottom + bottom_extend)
  2471. {
  2472. switch (uMsg)
  2473. {
  2474. case WM_RBUTTONUP:
  2475. //pt.x += m_lpDX->m_monitor_rect.left;
  2476. //pt.y += m_lpDX->m_monitor_rect.top;
  2477. DoExplorerMenu(GetPluginWindow(), (LPITEMIDLIST)p->pidl, pt);
  2478. break;
  2479. case WM_LBUTTONDBLCLK:
  2480. {
  2481. char buf[MAX_PATH];
  2482. sprintf(buf, "%s\\%s", m_szDesktopFolder, p->name);
  2483. ExecutePidl((LPITEMIDLIST)p->pidl, buf, m_szDesktopFolder, GetPluginWindow());
  2484. }
  2485. break;
  2486. case WM_LBUTTONDOWN:
  2487. m_desktop_dragging = 1;
  2488. memcpy(m_desktop_drag_pidl, p->pidl, sizeof(m_desktop_drag_pidl));
  2489. m_desktop_drag_startpos.x = LOWORD(lParam);
  2490. m_desktop_drag_startpos.y = HIWORD(lParam);
  2491. m_desktop_drag_curpos.x = LOWORD(lParam);
  2492. m_desktop_drag_curpos.y = HIWORD(lParam);
  2493. if (!(wParam & MK_CONTROL)) // if CTRL not held down
  2494. {
  2495. if (!p->selected)
  2496. {
  2497. DeselectDesktop();
  2498. p->selected = 1;
  2499. }
  2500. }
  2501. else
  2502. {
  2503. p->selected = 1-p->selected;
  2504. }
  2505. break;
  2506. case WM_RBUTTONDOWN:
  2507. DeselectDesktop();
  2508. p->selected = 1;
  2509. break;
  2510. }
  2511. done = 1;
  2512. break;
  2513. }
  2514. }
  2515. }
  2516. if (!done)
  2517. {
  2518. // deselect all, unless they're CTRL+clicking and missed an icon.
  2519. if (uMsg!=WM_LBUTTONDOWN || !(wParam & MK_CONTROL))
  2520. DeselectDesktop();
  2521. if (uMsg==WM_RBUTTONUP)// || uMsg==WM_RBUTTONDOWN)
  2522. {
  2523. // note: can't use GetMenu and TrackPopupMenu here because the hwnd param to TrackPopupMenu must belong to current application.
  2524. // (before sending coords to desktop window, xform them into its client coords:)
  2525. POINT pt;
  2526. pt.x = LOWORD(lParam);
  2527. pt.y = HIWORD(lParam);
  2528. ScreenToClient(m_hWndDesktopListView, &pt);
  2529. lParam = MAKELPARAM(pt.x + m_lpDX->m_monitor_rect.left, pt.y + m_lpDX->m_monitor_rect.top);
  2530. PostMessage(m_hWndDesktopListView, uMsg, wParam, lParam);
  2531. //PostMessage(m_hWndDesktopListView, WM_CONTEXTMENU, (WPARAM)m_hWndDesktopListView, lParam);
  2532. }
  2533. else if (uMsg==WM_LBUTTONDOWN)
  2534. {
  2535. m_desktop_box = 1;
  2536. m_desktop_drag_startpos.x = LOWORD(lParam);
  2537. m_desktop_drag_startpos.y = HIWORD(lParam);
  2538. m_desktop_drag_curpos.x = LOWORD(lParam);
  2539. m_desktop_drag_curpos.y = HIWORD(lParam);
  2540. }
  2541. }
  2542. // repaint window manually, if winamp is paused
  2543. if (SendMessage(m_hWndWinamp,WM_USER,0,104) != 1)
  2544. {
  2545. PushWindowToJustBeforeDesktop(GetPluginWindow());
  2546. DrawAndDisplay(1);
  2547. }
  2548. //return 0;
  2549. }
  2550. break;
  2551. case WM_SETFOCUS:
  2552. // note: this msg never comes in when embedwnd is used, but that's ok, because that's only
  2553. // in Windowed mode, and m_lost_focus only makes us sleep when fullscreen.
  2554. m_lost_focus = 0;
  2555. break;
  2556. case WM_KILLFOCUS:
  2557. // note: this msg never comes in when embedwnd is used, but that's ok, because that's only
  2558. // in Windowed mode, and m_lost_focus only makes us sleep when fullscreen.
  2559. m_lost_focus = 1;
  2560. break;
  2561. case WM_SETCURSOR:
  2562. if (
  2563. (m_screenmode == FULLSCREEN) ||
  2564. (m_screenmode == FAKE_FULLSCREEN && m_lpDX->m_fake_fs_covers_all)
  2565. )
  2566. {
  2567. // hide the cursor
  2568. SetCursor(NULL);
  2569. return TRUE; // prevent Windows from setting cursor to window class cursor
  2570. }
  2571. break;
  2572. case WM_NCHITTEST:
  2573. // Prevent the user from selecting the menu in fullscreen mode
  2574. if (m_screenmode != WINDOWED)
  2575. return HTCLIENT;
  2576. break;
  2577. case WM_SYSCOMMAND:
  2578. // Prevent *moving/sizing* and *entering standby mode* when in fullscreen mode
  2579. switch (wParam)
  2580. {
  2581. case SC_MOVE:
  2582. case SC_SIZE:
  2583. case SC_MAXIMIZE:
  2584. case SC_KEYMENU:
  2585. if (m_screenmode != WINDOWED)
  2586. return 1;
  2587. break;
  2588. case SC_MONITORPOWER:
  2589. if (m_screenmode == FULLSCREEN || m_screenmode == FAKE_FULLSCREEN)
  2590. return 1;
  2591. break;
  2592. }
  2593. break;
  2594. case WM_CONTEXTMENU:
  2595. // launch popup context menu. see handler for WM_COMMAND also.
  2596. if (m_screenmode == DESKTOP)
  2597. {
  2598. // note: execution should never reach this point,
  2599. // because we don't pass WM_RBUTTONUP to DefWindowProc
  2600. // when in desktop mode!
  2601. return 0;
  2602. }
  2603. else if (m_screenmode == WINDOWED) // context menus only allowed in ~windowed modes
  2604. {
  2605. TrackPopupMenuEx(m_context_menu, TPM_VERTICAL, LOWORD(lParam), HIWORD(lParam), hWnd, NULL);
  2606. return 0;
  2607. }
  2608. break;
  2609. case WM_COMMAND:
  2610. // handle clicks on items on context menu.
  2611. if (m_screenmode == WINDOWED)
  2612. {
  2613. switch (LOWORD(wParam))
  2614. {
  2615. case ID_QUIT:
  2616. m_exiting = 1;
  2617. PostMessage(hWnd, WM_CLOSE, 0, 0);
  2618. return 0;
  2619. case ID_GO_FS:
  2620. if (m_frame > 0)
  2621. ToggleFullScreen();
  2622. return 0;
  2623. case ID_DESKTOP_MODE:
  2624. if (m_frame > 0)
  2625. ToggleDesktop();
  2626. return 0;
  2627. case ID_SHOWHELP:
  2628. ToggleHelp();
  2629. return 0;
  2630. case ID_SHOWPLAYLIST:
  2631. TogglePlaylist();
  2632. return 0;
  2633. }
  2634. // then allow the plugin to override any command:
  2635. if (MyWindowProc(hWnd, uMsg, wParam, lParam) == 0)
  2636. return 0;
  2637. }
  2638. break;
  2639. /*
  2640. KEY HANDLING: the basic idea:
  2641. -in all cases, handle or capture:
  2642. -ZXCVBRS, zxcvbrs
  2643. -also make sure it's case-insensitive! (lowercase come through only as WM_CHAR; uppercase come in as both)
  2644. -(ALT+ENTER)
  2645. -(F1, ESC, UP, DN, Left, Right, SHIFT+l/r)
  2646. -(P for playlist)
  2647. -when playlist showing: steal J, HOME, END, PGUP, PGDN, UP, DOWN, ESC
  2648. -(BLOCK J, L)
  2649. -when integrated with winamp (using embedwnd), also handle these keys:
  2650. -j, l, L, CTRL+L [windowed mode only!]
  2651. -CTRL+P, CTRL+D
  2652. -CTRL+TAB
  2653. -ALT-E
  2654. -ALT+F (main menu)
  2655. -ALT+3 (id3)
  2656. */
  2657. case WM_SYSKEYDOWN:
  2658. if (wParam==VK_RETURN && m_frame > 0)
  2659. {
  2660. ToggleFullScreen();
  2661. return 0;
  2662. }
  2663. // if in embedded mode (using winamp skin), pass ALT+ keys on to winamp
  2664. // ex: ALT+E, ALT+F, ALT+3...
  2665. if (m_screenmode==WINDOWED && m_lpDX->m_current_mode.m_skin)
  2666. return PostMessage(m_hWndWinamp, uMsg, wParam, lParam); // force-pass to winamp; required for embedwnd
  2667. break;
  2668. case WM_SYSKEYUP:
  2669. if (m_screenmode==WINDOWED && m_lpDX->m_current_mode.m_skin)
  2670. return PostMessage(m_hWndWinamp, uMsg, wParam, lParam); // force-pass to winamp; required for embedwnd
  2671. break;
  2672. case WM_SYSCHAR:
  2673. if ((wParam=='k' || wParam=='K'))
  2674. {
  2675. OnAltK();
  2676. return 0;
  2677. }
  2678. if ((wParam=='d' || wParam=='D') && m_frame > 0)
  2679. {
  2680. ToggleDesktop();
  2681. return 0;
  2682. }
  2683. break;
  2684. case WM_CHAR:
  2685. // if playlist is showing, steal p/j keys from the plugin:
  2686. if (m_show_playlist)
  2687. {
  2688. switch (wParam)
  2689. {
  2690. case 'j':
  2691. case 'J':
  2692. m_playlist_pos = SendMessage(m_hWndWinamp,WM_USER, 0, 125);
  2693. return 0;
  2694. default:
  2695. {
  2696. int nSongs = SendMessage(m_hWndWinamp,WM_USER, 0, 124);
  2697. int found = 0;
  2698. int orig_pos = m_playlist_pos;
  2699. int inc = (wParam>='A' && wParam<='Z') ? -1 : 1;
  2700. while (1)
  2701. {
  2702. if (inc==1 && m_playlist_pos >= nSongs-1)
  2703. break;
  2704. if (inc==-1 && m_playlist_pos <= 0)
  2705. break;
  2706. m_playlist_pos += inc;
  2707. char buf[32];
  2708. strncpy(buf, (char*)SendMessage(m_hWndWinamp, WM_USER, m_playlist_pos, 212), 31);
  2709. buf[31] = 0;
  2710. // remove song # and period from beginning
  2711. char *p = buf;
  2712. while (*p >= '0' && *p <= '9') p++;
  2713. if (*p == '.' && *(p+1) == ' ')
  2714. {
  2715. p += 2;
  2716. int pos = 0;
  2717. while (*p != 0)
  2718. {
  2719. buf[pos++] = *p;
  2720. p++;
  2721. }
  2722. buf[pos++] = 0;
  2723. }
  2724. int wParam2 = (wParam>='A' && wParam<='Z') ? (wParam + 'a'-'A') : (wParam + 'A'-'a');
  2725. if (buf[0]==wParam || buf[0]==wParam2)
  2726. {
  2727. found = 1;
  2728. break;
  2729. }
  2730. }
  2731. if (!found)
  2732. m_playlist_pos = orig_pos;
  2733. }
  2734. return 0;
  2735. }
  2736. }
  2737. // then allow the plugin to override any keys:
  2738. if (MyWindowProc(hWnd, uMsg, wParam, lParam) == 0)
  2739. return 0;
  2740. // finally, default key actions:
  2741. if (wParam == keyMappings[5] || wParam == keyMappings[6]) // 'z' or 'Z'
  2742. {
  2743. PostMessage(m_hWndWinamp,WM_COMMAND,40044,0);
  2744. return 0;
  2745. }
  2746. else
  2747. {
  2748. switch (wParam)
  2749. {
  2750. // WINAMP PLAYBACK CONTROL KEYS:
  2751. case 'x':
  2752. case 'X':
  2753. PostMessage(m_hWndWinamp,WM_COMMAND,40045,0);
  2754. return 0;
  2755. case 'c':
  2756. case 'C':
  2757. PostMessage(m_hWndWinamp,WM_COMMAND,40046,0);
  2758. return 0;
  2759. case 'v':
  2760. case 'V':
  2761. PostMessage(m_hWndWinamp,WM_COMMAND,40047,0);
  2762. return 0;
  2763. case 'b':
  2764. case 'B':
  2765. PostMessage(m_hWndWinamp,WM_COMMAND,40048,0);
  2766. return 0;
  2767. case 's':
  2768. case 'S':
  2769. //if (SendMessage(m_hWndWinamp,WM_USER,0,250))
  2770. // sprintf(m_szUserMessage, "shuffle is now OFF"); // shuffle was on
  2771. //else
  2772. // sprintf(m_szUserMessage, "shuffle is now ON"); // shuffle was off
  2773. // toggle shuffle
  2774. PostMessage(m_hWndWinamp,WM_COMMAND,40023,0);
  2775. return 0;
  2776. case 'r':
  2777. case 'R':
  2778. // toggle repeat
  2779. PostMessage(m_hWndWinamp,WM_COMMAND,40022,0);
  2780. return 0;
  2781. case 'p':
  2782. case 'P':
  2783. TogglePlaylist();
  2784. return 0;
  2785. case 'l':
  2786. // note that this is actually correct; when you hit 'l' from the
  2787. // MAIN winamp window, you get an "open files" dialog; when you hit
  2788. // 'l' from the playlist editor, you get an "add files to playlist" dialog.
  2789. // (that sends IDC_PLAYLIST_ADDMP3==1032 to the playlist, which we can't
  2790. // do from here.)
  2791. PostMessage(m_hWndWinamp,WM_COMMAND,40029,0);
  2792. return 0;
  2793. case 'L':
  2794. PostMessage(m_hWndWinamp,WM_COMMAND,40187,0);
  2795. return 0;
  2796. case 'j':
  2797. PostMessage(m_hWndWinamp,WM_COMMAND,40194,0);
  2798. return 0;
  2799. }
  2800. return 0;//DefWindowProc(hWnd,uMsg,wParam,lParam);
  2801. }
  2802. break; // end case WM_CHAR
  2803. case WM_KEYUP:
  2804. // allow the plugin to override any keys:
  2805. if (MyWindowProc(hWnd, uMsg, wParam, lParam) == 0)
  2806. return 0;
  2807. /*
  2808. switch(wParam)
  2809. {
  2810. case VK_SOMETHING:
  2811. ...
  2812. break;
  2813. }
  2814. */
  2815. return 0;
  2816. break;
  2817. case WM_KEYDOWN:
  2818. if (m_show_playlist)
  2819. {
  2820. switch (wParam)
  2821. {
  2822. case VK_ESCAPE:
  2823. if(m_show_playlist)
  2824. TogglePlaylist();
  2825. //m_show_playlist = 0;
  2826. return 0;
  2827. case VK_UP:
  2828. {
  2829. int nRepeat = lParam & 0xFFFF;
  2830. if (GetKeyState(VK_SHIFT) & mask)
  2831. m_playlist_pos -= 10*nRepeat;
  2832. else
  2833. m_playlist_pos -= nRepeat;
  2834. }
  2835. return 0;
  2836. case VK_DOWN:
  2837. {
  2838. int nRepeat = lParam & 0xFFFF;
  2839. if (GetKeyState(VK_SHIFT) & mask)
  2840. m_playlist_pos += 10*nRepeat;
  2841. else
  2842. m_playlist_pos += nRepeat;
  2843. }
  2844. return 0;
  2845. case VK_HOME:
  2846. m_playlist_pos = 0;
  2847. return 0;
  2848. case VK_END:
  2849. m_playlist_pos = SendMessage(m_hWndWinamp,WM_USER, 0, 124) - 1;
  2850. return 0;
  2851. case VK_PRIOR:
  2852. if (GetKeyState(VK_SHIFT) & mask)
  2853. m_playlist_pageups += 10;
  2854. else
  2855. m_playlist_pageups++;
  2856. return 0;
  2857. case VK_NEXT:
  2858. if (GetKeyState(VK_SHIFT) & mask)
  2859. m_playlist_pageups -= 10;
  2860. else
  2861. m_playlist_pageups--;
  2862. return 0;
  2863. case VK_RETURN:
  2864. SendMessage(m_hWndWinamp,WM_USER, m_playlist_pos, 121); // set sel
  2865. SendMessage(m_hWndWinamp,WM_COMMAND, 40045, 0); // play it
  2866. return 0;
  2867. }
  2868. }
  2869. // allow the plugin to override any keys:
  2870. if (MyWindowProc(hWnd, uMsg, wParam, lParam) == 0)
  2871. return 0;
  2872. switch (wParam)
  2873. {
  2874. case VK_F1:
  2875. m_show_press_f1_msg = 0;
  2876. ToggleHelp();
  2877. return 0;
  2878. case VK_ESCAPE:
  2879. if (m_show_help)
  2880. ToggleHelp();
  2881. else
  2882. {
  2883. if (m_screenmode == FAKE_FULLSCREEN || m_screenmode == FULLSCREEN)
  2884. {
  2885. ToggleFullScreen();
  2886. }
  2887. else if (m_screenmode == DESKTOP)
  2888. {
  2889. ToggleDesktop();
  2890. }
  2891. // exit the program on escape
  2892. //m_exiting = 1;
  2893. //PostMessage(hWnd, WM_CLOSE, 0, 0);
  2894. }
  2895. return 0;
  2896. case VK_UP:
  2897. // increase volume
  2898. {
  2899. int nRepeat = lParam & 0xFFFF;
  2900. for (i=0; i<nRepeat*2; i++) PostMessage(m_hWndWinamp,WM_COMMAND,40058,0);
  2901. }
  2902. return 0;
  2903. case VK_DOWN:
  2904. // decrease volume
  2905. {
  2906. int nRepeat = lParam & 0xFFFF;
  2907. for (i=0; i<nRepeat*2; i++) PostMessage(m_hWndWinamp,WM_COMMAND,40059,0);
  2908. }
  2909. return 0;
  2910. case VK_LEFT:
  2911. case VK_RIGHT:
  2912. {
  2913. bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0;
  2914. int cmd = (wParam == VK_LEFT) ? 40144 : 40148;
  2915. int nRepeat = lParam & 0xFFFF;
  2916. int reps = (bShiftHeldDown) ? 6*nRepeat : 1*nRepeat;
  2917. for (int i=0; i<reps; i++)
  2918. PostMessage(m_hWndWinamp,WM_COMMAND,cmd,0);
  2919. }
  2920. return 0;
  2921. default:
  2922. // pass CTRL+A thru CTRL+Z, and also CTRL+TAB, to winamp, *if we're in windowed mode* and using an embedded window.
  2923. // be careful though; uppercase chars come both here AND to WM_CHAR handler,
  2924. // so we have to eat some of them here, to avoid them from acting twice.
  2925. if (m_screenmode==WINDOWED && m_lpDX && m_lpDX->m_current_mode.m_skin)
  2926. {
  2927. if (bCtrlHeldDown && ((wParam >= 'A' && wParam <= 'Z') || wParam==VK_TAB))
  2928. {
  2929. PostMessage(m_hWndWinamp, uMsg, wParam, lParam);
  2930. return 0;
  2931. }
  2932. }
  2933. return 0;
  2934. }
  2935. return 0;
  2936. break;
  2937. }
  2938. return MyWindowProc(hWnd, uMsg, wParam, lParam);//DefWindowProc(hWnd, uMsg, wParam, lParam);
  2939. //return 0L;
  2940. }
  2941. LRESULT CALLBACK CPluginShell::DesktopWndProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam)
  2942. {
  2943. CPluginShell* p = (CPluginShell*)GetWindowLongPtr(hWnd,GWLP_USERDATA);
  2944. if (p)
  2945. return p->PluginShellDesktopWndProc(hWnd, uMsg, wParam, lParam);
  2946. else
  2947. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  2948. }
  2949. LRESULT CPluginShell::PluginShellDesktopWndProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam)
  2950. {
  2951. //#ifdef _DEBUG
  2952. // OutputDebugMessage("kbfocus", hWnd, uMsg, wParam, lParam);
  2953. //#endif
  2954. switch (uMsg)
  2955. {
  2956. case WM_KEYDOWN:
  2957. case WM_KEYUP:
  2958. case WM_CHAR:
  2959. case WM_SYSCHAR:
  2960. case WM_SYSKEYDOWN:
  2961. case WM_SYSKEYUP:
  2962. //PostMessage(GetPluginWindow(), uMsg, wParam, lParam);
  2963. PluginShellWindowProc(GetPluginWindow(), uMsg, wParam, lParam);
  2964. return 0;
  2965. break;
  2966. }
  2967. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  2968. }
  2969. void CPluginShell::AlignWaves()
  2970. {
  2971. // align waves, using recursive (mipmap-style) least-error matching
  2972. // note: NUM_WAVEFORM_SAMPLES must be between 32 and 576.
  2973. int align_offset[2] = { 0, 0 };
  2974. #if (NUM_WAVEFORM_SAMPLES < 576) // [don't let this code bloat our DLL size if it's not going to be used]
  2975. int nSamples = NUM_WAVEFORM_SAMPLES;
  2976. #define MAX_OCTAVES 10
  2977. int octaves = (int)floorf(logf((float)(576-nSamples))/logf(2.0f));
  2978. if (octaves < 4)
  2979. return;
  2980. if (octaves > MAX_OCTAVES)
  2981. octaves = MAX_OCTAVES;
  2982. for (int ch=0; ch<2; ch++)
  2983. {
  2984. // only worry about matching the lower 'nSamples' samples
  2985. float temp_new[MAX_OCTAVES][576];
  2986. float temp_old[MAX_OCTAVES][576];
  2987. static float temp_weight[MAX_OCTAVES][576];
  2988. static int first_nonzero_weight[MAX_OCTAVES];
  2989. static int last_nonzero_weight[MAX_OCTAVES];
  2990. int spls[MAX_OCTAVES];
  2991. int space[MAX_OCTAVES];
  2992. memcpy(temp_new[0], m_sound.fWaveform[ch], sizeof(float)*576);
  2993. memcpy(temp_old[0], &m_oldwave[ch][m_prev_align_offset[ch]], sizeof(float)*nSamples);
  2994. spls[0] = 576;
  2995. space[0] = 576 - nSamples;
  2996. // potential optimization: could reuse (instead of recompute) mip levels for m_oldwave[2][]?
  2997. int octave = 0;
  2998. for (octave=1; octave<octaves; octave++)
  2999. {
  3000. spls[octave] = spls[octave-1]/2;
  3001. space[octave] = space[octave-1]/2;
  3002. for (int n=0; n<spls[octave]; n++)
  3003. {
  3004. temp_new[octave][n] = 0.5f*(temp_new[octave-1][n*2] + temp_new[octave-1][n*2+1]);
  3005. temp_old[octave][n] = 0.5f*(temp_old[octave-1][n*2] + temp_old[octave-1][n*2+1]);
  3006. }
  3007. }
  3008. if (!m_align_weights_ready)
  3009. {
  3010. m_align_weights_ready = 1;
  3011. for (octave=0; octave<octaves; octave++)
  3012. {
  3013. int compare_samples = spls[octave] - space[octave];
  3014. int n = 0;
  3015. for (n=0; n<compare_samples; n++)
  3016. {
  3017. // start with pyramid-shaped pdf, from 0..1..0
  3018. if (n < compare_samples/2)
  3019. temp_weight[octave][n] = n*2/(float)compare_samples;
  3020. else
  3021. temp_weight[octave][n] = (compare_samples-1 - n)*2/(float)compare_samples;
  3022. // TWEAK how much the center matters, vs. the edges:
  3023. temp_weight[octave][n] = (temp_weight[octave][n] - 0.8f)*5.0f + 0.8f;
  3024. // clip:
  3025. if (temp_weight[octave][n]>1) temp_weight[octave][n] = 1;
  3026. if (temp_weight[octave][n]<0) temp_weight[octave][n] = 0;
  3027. }
  3028. n = 0;
  3029. while (temp_weight[octave][n] == 0 && n < compare_samples)
  3030. n++;
  3031. first_nonzero_weight[octave] = n;
  3032. n = compare_samples-1;
  3033. while (temp_weight[octave][n] == 0 && n >= 0)
  3034. n--;
  3035. last_nonzero_weight[octave] = n;
  3036. }
  3037. }
  3038. int n1 = 0;
  3039. int n2 = space[octaves-1];
  3040. for (octave = octaves-1; octave>=0; octave--)
  3041. {
  3042. // for example:
  3043. // space[octave] == 4
  3044. // spls[octave] == 36
  3045. // (so we test 32 samples, w/4 offsets)
  3046. int compare_samples = spls[octave]-space[octave];
  3047. int lowest_err_offset = -1;
  3048. float lowest_err_amount = 0;
  3049. for (int n=n1; n<n2; n++)
  3050. {
  3051. float err_sum = 0;
  3052. //for (int i=0; i<compare_samples; i++)
  3053. for (int i=first_nonzero_weight[octave]; i<=last_nonzero_weight[octave]; i++)
  3054. {
  3055. float x = (temp_new[octave][i+n] - temp_old[octave][i]) * temp_weight[octave][i];
  3056. if (x>0)
  3057. err_sum += x;
  3058. else
  3059. err_sum -= x;
  3060. }
  3061. if (lowest_err_offset == -1 || err_sum < lowest_err_amount)
  3062. {
  3063. lowest_err_offset = n;
  3064. lowest_err_amount = err_sum;
  3065. }
  3066. }
  3067. // now use 'lowest_err_offset' to guide bounds of search in next octave:
  3068. // space[octave] == 8
  3069. // spls[octave] == 72
  3070. // -say 'lowest_err_offset' was 2
  3071. // -that corresponds to samples 4 & 5 of the next octave
  3072. // -also, expand about this by 2 samples? YES.
  3073. // (so we'd test 64 samples, w/8->4 offsets)
  3074. if (octave > 0)
  3075. {
  3076. n1 = lowest_err_offset*2 -1;
  3077. n2 = lowest_err_offset*2+2+1;
  3078. if (n1 < 0) n1=0;
  3079. if (n2 > space[octave-1]) n2 = space[octave-1];
  3080. }
  3081. else
  3082. align_offset[ch] = lowest_err_offset;
  3083. }
  3084. }
  3085. #endif
  3086. memcpy(m_oldwave[0], m_sound.fWaveform[0], sizeof(float)*576);
  3087. memcpy(m_oldwave[1], m_sound.fWaveform[1], sizeof(float)*576);
  3088. m_prev_align_offset[0] = align_offset[0];
  3089. m_prev_align_offset[1] = align_offset[1];
  3090. // finally, apply the results: modify m_sound.fWaveform[2][0..576]
  3091. // by scooting the aligned samples so that they start at m_sound.fWaveform[2][0].
  3092. for (int ch=0; ch<2; ch++)
  3093. if (align_offset[ch]>0)
  3094. {
  3095. for (int i=0; i<nSamples; i++)
  3096. m_sound.fWaveform[ch][i] = m_sound.fWaveform[ch][i+align_offset[ch]];
  3097. // zero the rest out, so it's visually evident that these samples are now bogus:
  3098. memset(&m_sound.fWaveform[ch][nSamples], 0, (576-nSamples)*sizeof(float));
  3099. }
  3100. }
  3101. LRESULT CALLBACK CPluginShell::VJModeWndProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam)
  3102. {
  3103. CPluginShell* p = (CPluginShell*)GetWindowLongPtr(hWnd,GWLP_USERDATA);
  3104. if (p)
  3105. return p->PluginShellVJModeWndProc(hWnd, uMsg, wParam, lParam);
  3106. else
  3107. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  3108. }
  3109. LRESULT CPluginShell::PluginShellVJModeWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  3110. {
  3111. #ifdef _DEBUG
  3112. if (message != WM_MOUSEMOVE &&
  3113. message != WM_NCHITTEST &&
  3114. message != WM_SETCURSOR &&
  3115. message != WM_COPYDATA &&
  3116. message != WM_USER)
  3117. {
  3118. char caption[256] = "VJWndProc: frame 0, ";
  3119. if (m_frame > 0)
  3120. {
  3121. float time = m_time;
  3122. int hours = (int)(time/3600);
  3123. time -= hours*3600;
  3124. int minutes = (int)(time/60);
  3125. time -= minutes*60;
  3126. int seconds = (int)time;
  3127. time -= seconds;
  3128. int dsec = (int)(time*100);
  3129. sprintf(caption, "VJWndProc: frame %d, t=%dh:%02dm:%02d.%02ds, ", m_frame, hours, minutes, seconds, dsec);
  3130. }
  3131. OutputDebugMessage(caption, hwnd, message, wParam, lParam);
  3132. }
  3133. #endif
  3134. switch (message)
  3135. {
  3136. case WM_KEYDOWN:
  3137. case WM_KEYUP:
  3138. case WM_CHAR:
  3139. case WM_SYSKEYDOWN:
  3140. case WM_SYSKEYUP:
  3141. case WM_SYSCHAR:
  3142. // pass keystrokes on to plugin!
  3143. return PluginShellWindowProc(GetPluginWindow(),message,wParam,lParam);
  3144. case WM_ERASEBKGND:
  3145. // Repaint window when song is paused and image needs to be repainted:
  3146. if (SendMessage(m_hWndWinamp,WM_USER,0,104)!=1 && m_vjd3d9_device && GetFrame() > 0) // WM_USER/104 return codes: 1=playing, 3=paused, other=stopped
  3147. {
  3148. m_vjd3d9_device->Present(NULL,NULL,NULL,NULL);
  3149. return 0;
  3150. }
  3151. break;
  3152. /*
  3153. case WM_WINDOWPOSCHANGING:
  3154. if (m_screenmode == DESKTOP)
  3155. {
  3156. LPWINDOWPOS pwp = (LPWINDOWPOS)lParam;
  3157. if (pwp)
  3158. pwp->flags |= SWP_NOOWNERZORDER | SWP_NOZORDER;
  3159. }
  3160. break;
  3161. case WM_ACTIVATEAPP:
  3162. // *Very Important Handler!*
  3163. // -Without this code, the app would not work properly when running in true
  3164. // fullscreen mode on multiple monitors; it would auto-minimize whenever the
  3165. // user clicked on a window in another display.
  3166. if (wParam == 1 &&
  3167. m_screenmode == DESKTOP &&
  3168. m_frame > 0 &&
  3169. !m_exiting
  3170. )
  3171. {
  3172. return 0;
  3173. }
  3174. break;
  3175. /*
  3176. case WM_NCACTIVATE:
  3177. // *Very Important Handler!*
  3178. // -Without this code, the app would not work properly when running in true
  3179. // fullscreen mode on multiple monitors; it would auto-minimize whenever the
  3180. // user clicked on a window in another display.
  3181. // (NOTE: main window also handles this message this way)
  3182. if (wParam == 0 &&
  3183. m_screenmode == FULLSCREEN &&
  3184. m_frame > 0 &&
  3185. !m_exiting &&
  3186. m_lpDX &&
  3187. m_lpDX->m_ready
  3188. && m_lpDX->m_lpD3D &&
  3189. m_lpDX->m_lpD3D->GetAdapterCount() > 1
  3190. )
  3191. {
  3192. return 0;
  3193. }
  3194. break;
  3195. */
  3196. /*
  3197. case WM_ACTIVATEAPP:
  3198. if (wParam == 1 &&
  3199. m_screenmode == DESKTOP &&
  3200. m_frame > 0 &&
  3201. !m_exiting &&
  3202. m_vjd3d9_device
  3203. )
  3204. {
  3205. return 0;
  3206. }
  3207. break;
  3208. */
  3209. /*
  3210. case WM_WINDOWPOSCHANGING:
  3211. if (
  3212. m_screenmode == DESKTOP
  3213. && (!m_force_accept_WM_WINDOWPOSCHANGING)
  3214. && m_lpDX && m_lpDX->m_ready
  3215. )
  3216. {
  3217. // unless we requested it ourselves or it's init time,
  3218. // prevent the fake desktop window from moving around
  3219. // in the Z order! (i.e., keep it on the bottom)
  3220. // without this code, when you click on the 'real' desktop
  3221. // in a multimon setup, any windows that are overtop of the
  3222. // 'fake' desktop will flash, since they'll be covered
  3223. // up by the fake desktop window (but then shown again on
  3224. // the next frame, when we detect that the fake desktop
  3225. // window isn't on bottom & send it back to the bottom).
  3226. LPWINDOWPOS pwp = (LPWINDOWPOS)lParam;
  3227. if (pwp)
  3228. pwp->flags |= SWP_NOOWNERZORDER | SWP_NOZORDER;
  3229. }
  3230. break;
  3231. */
  3232. case WM_CLOSE:
  3233. // if they close the VJ window (by some means other than ESC key),
  3234. // this will make the graphics window close, too.
  3235. m_exiting = 1;
  3236. if (GetPluginWindow())
  3237. PostMessage(GetPluginWindow(), WM_CLOSE, 0, 0);
  3238. break;
  3239. case WM_GETMINMAXINFO:
  3240. {
  3241. // don't let the window get too small
  3242. MINMAXINFO* p = (MINMAXINFO*)lParam;
  3243. if (p->ptMinTrackSize.x < 64)
  3244. p->ptMinTrackSize.x = 64;
  3245. p->ptMinTrackSize.y = p->ptMinTrackSize.x*3/4;
  3246. }
  3247. return 0;
  3248. case WM_SIZE:
  3249. // clear or set activity flag to reflect focus
  3250. if (m_vjd3d9_device && !m_resizing_textwnd)
  3251. {
  3252. m_hidden_textwnd = (SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam) ? TRUE : FALSE;
  3253. if (SIZE_MAXIMIZED==wParam || SIZE_RESTORED==wParam) // the window has been maximized or restored
  3254. OnUserResizeTextWindow();
  3255. }
  3256. break;
  3257. case WM_ENTERSIZEMOVE:
  3258. m_resizing_textwnd = 1;
  3259. break;
  3260. case WM_EXITSIZEMOVE:
  3261. if (m_vjd3d9_device)
  3262. OnUserResizeTextWindow();
  3263. m_resizing_textwnd = 0;
  3264. break;
  3265. }
  3266. return DefWindowProc(hwnd, message, wParam, lParam);
  3267. }