plugin.cpp 383 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653
  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. ##########################################################################################
  26. NOTE:
  27. The DX9 SDK include & lib files for building MilkDrop 2 are right here, in the subdirectory:
  28. .\dx9sdk_summer04\
  29. The summer 2004 SDK statically links you to d3dx9.lib (5,820 kb). It bloats vis_milk2.dll
  30. a bit, but we (Ben Allison / Ryan Geiss) decided it's worth the stability. We tinkered
  31. with using the February 2005 sdk, which lets you dynamically link to d3dx9_31.dll (?),
  32. but decided to skip it because it would cause too much hassle/confusion among users.
  33. Summer 2004 sdk: http://www.microsoft.com/downloads/details.aspx?FamilyID=fd044a42-9912-42a3-9a9e-d857199f888e&DisplayLang=en
  34. Feb 2005 sdk: http://www.microsoft.com/downloads/details.aspx?FamilyId=77960733-06E9-47BA-914A-844575031B81&displaylang=en
  35. ##########################################################################################
  36. */
  37. /*
  38. Order of Function Calls
  39. -----------------------
  40. The only code that will be called by the plugin framework are the
  41. 12 virtual functions in plugin.h. But in what order are they called?
  42. A breakdown follows. A function name in { } means that it is only
  43. called under certain conditions.
  44. Order of function calls...
  45. When the PLUGIN launches
  46. ------------------------
  47. INITIALIZATION
  48. OverrideDefaults
  49. MyPreInitialize
  50. MyReadConfig
  51. << DirectX gets initialized at this point >>
  52. AllocateMyNonDx9Stuff
  53. AllocateMyDX9Stuff
  54. RUNNING
  55. +--> { CleanUpMyDX9Stuff + AllocateMyDX9Stuff } // called together when user resizes window or toggles fullscreen<->windowed.
  56. | MyRenderFn
  57. | MyRenderUI
  58. | { MyWindowProc } // called, between frames, on mouse/keyboard/system events. 100% threadsafe.
  59. +----<< repeat >>
  60. CLEANUP
  61. CleanUpMyDX9Stuff
  62. CleanUpMyNonDx9Stuff
  63. << DirectX gets uninitialized at this point >>
  64. When the CONFIG PANEL launches
  65. ------------------------------
  66. INITIALIZATION
  67. OverrideDefaults
  68. MyPreInitialize
  69. MyReadConfig
  70. << DirectX gets initialized at this point >>
  71. RUNNING
  72. { MyConfigTabProc } // called on startup & on keyboard events
  73. CLEANUP
  74. [ MyWriteConfig ] // only called if user clicked 'OK' to exit
  75. << DirectX gets uninitialized at this point >>
  76. */
  77. /*
  78. NOTES
  79. -----
  80. To do
  81. -----
  82. -VMS VERSION:
  83. -based on vms 1.05, but the 'fix slow text' option has been added.
  84. that includes m_lpDDSText, CTextManager (m_text), changes to
  85. DrawDarkTranslucentBox, the replacement of all DrawText calls
  86. (now routed through m_text), and adding the 'fix slow text' cb
  87. to the config panel.
  88. -KILLED FEATURES:
  89. -vj mode
  90. -NEW FEATURES FOR 1.04:
  91. -added the following variables for per-frame scripting: (all booleans, except 'gamma')
  92. wave_usedots, wave_thick, wave_additive, wave_brighten
  93. gamma, darken_center, wrap, invert, brighten, darken, solarize
  94. (also, note that echo_zoom, echo_alpha, and echo_orient were already in there,
  95. but weren't covered in the documentation!)
  96. d -fixed: spectrum w/512 samples + 256 separation -> infinite spike
  97. d -reverted dumb changes to aspect ratio stuff
  98. d -reverted wave_y fix; now it's backwards, just like it's always been
  99. (i.e. for wave's y position, 0=bottom and 1=top, which is opposite
  100. to the convention in the rest of milkdrop. decided to keep the
  101. 'bug' so presets don't need modified.)
  102. d -fixed: Krash: Inconsistency bug - pressing Escape while in the code windows
  103. for custom waves completely takes you out of the editing menus,
  104. rather than back to the custom wave menu
  105. d -when editing code: fix display of '&' character
  106. d -internal texture size now has a little more bias toward a finer texture,
  107. based on the window size, when set to 'Auto'. (Before, for example,
  108. to reach 1024x1024, the window had to be 768x768 or greater; now, it
  109. only has to be 640x640 (25% of the way there). I adjusted it because
  110. before, at in-between resolutions like 767x767, it looked very grainy;
  111. now it will always look nice and crisp, at any window size, but still
  112. won't cause too much aliasing (due to downsampling for display).
  113. d -fixed: rova:
  114. When creating presets have commented code // in the per_pixel section when cause error in preset.
  115. Example nothing in per_frame and just comments in the per_pixel. EXamples on repuest I have a few.
  116. d -added kill keys:
  117. -CTRL+K kills all running sprites
  118. -CTRL+T kills current song title anim
  119. -CTRL+Y kills current custom message
  120. d -notice to sprite users:
  121. -in milk_img.ini, color key can't be a range anymore; it's
  122. now limited to just a single color. 'colorkey_lo' and
  123. 'colorkey_hi' have been replaced with just one setting,
  124. 'colorkey'.
  125. d -song titles + custom messages are working again
  126. ? -fixed?: crashes on window resize [out of mem]
  127. -Rova: BTW the same bug as krash with the window resizing.
  128. -NOT due to the 'integrate w/winamp' option.
  129. -> might be fixed now (had forgotten to release m_lpDDSText)
  130. <AFTER BETA 3..>
  131. d -added checkbox to config screen to automatically turn SCROLL LOCK on @ startup
  132. d -added alphanumeric seeking to the playlist; while playlist is up,
  133. you can now press A-Z and 0-9 to seek to the next song in the playlist
  134. that starts with that character.
  135. d -<fixed major bug w/illegal mem access on song title launches;
  136. could have been causing crashing madness @ startup on many systems>
  137. d -<fixed bug w/saving 64x48 mesh size>
  138. d -<fixed squashed shapes>
  139. d -<fixed 'invert' variable>
  140. d -<fixed squashed song titles + custom msgs>
  141. ? -<might have fixed scroll lock stuff>
  142. ? -<might have fixed crashing; could have been due to null ptr for failed creation of song title texture.>
  143. ? -<also might have solved any remaining resize or exit bugs by callign SetTexture(NULL)
  144. in DX8 cleanup.>
  145. d -<fixed sizing issues with songtitle font.>
  146. d -<fixed a potentially bogus call to deallocate memory on exit, when it was cleaning up the menus.>
  147. d -<fixed more scroll lock issues>
  148. d -<fixed broken Noughts & Crosses presets; max # of per-frame vars was one too few, after the additions of the new built-in variables.>
  149. d -<hopefully fixed waveforms>
  150. <AFTER BETA 4>
  151. -now when playlist is up, SHIFT+A-Z seeks upward (while lowercase/regular a-z seeks downward).
  152. -custom shapes:
  153. -OH MY GOD
  154. -increased max. # of custom shapes (and waves) from 3 to 4
  155. -added 'texture' option, which allows you to use the last frame as a texture on the shape
  156. -added "tex_ang" and "tex_zoom" params to control the texture coords
  157. -each frame, custom shapes now draw BEFORE regular waveform + custom waves
  158. -added init + per-frame vars: "texture", "additive", "thick", "tex_ang", "tex_zoom"
  159. -fixed valid characters for filenames when importing/exporting custom shapes/waves;
  160. also, it now gives error messages on error in import/export.
  161. -cranked max. meshsize up to 96x72
  162. -Krash, Rova: now the 'q' variables, as modified by the preset per-frame equations, are again
  163. readable by the custom waves + custom shapes. Sorry about that. Should be the end of the
  164. 'q' confusion.
  165. -added 'meshx' and 'meshy' [read-only] variables to the preset init, per-frame, and per-pixel
  166. equations (...and inc'd the size of the global variable pool by 2).
  167. -removed t1-t8 vars for Custom Shapes; they were unnecessary (since there's no per-point code there).
  168. -protected custom waves from trying to draw when # of sample minus the separation is < 2
  169. (or 1 if drawing with dots)
  170. -fixed some [minor] preset-blending bugs in the custom wave code
  171. -created a visual map for the flow of values for the q1-q8 and t1-t8 variables:
  172. q_and_t_vars.gif (or something).
  173. -fixed clipping of onscreen text in low-video-memory situations. Now, if there isn't enough
  174. video memory to create an offscreen texture that is at least 75% of the size of the
  175. screen (or to create at least a 256x256 one), it won't bother using one, and will instead draw text directly to the screen.
  176. Otherwise, if the texture is from 75%-99% of the screen size, text will now at least
  177. appear in the correct position on the screen so that it will be visible; this will mean
  178. that the right- and bottom-aligned text will no longer be fully right/bottom-aligned
  179. to the edge of the screen.
  180. -fixed blurry text
  181. -VJ mode is partially restored; the rest will come with beta 7 or the final release. At the time of beta 6, VJ mode still has some glitches in it, but I'm working on them. Most notably, it doesn't resize the text image when you resize the window; that's next on my list.
  182. <AFTER BETA 6:>
  183. -now sprites can burn-in on any frame, not just on the last frame.
  184. set 'burn' to one (in the sprite code) on any frame to make it burn in.
  185. this will break some older sprites, but it's super easy to fix, and
  186. I think it's worth it. =) thanks to papaw00dy for the suggestion!
  187. -fixed the asymptotic-value bug with custom waves using spectral data & having < 512 samples (thanks to telek's example!)
  188. -fixed motion vectors' reversed Y positioning.
  189. -fixed truncation ("...") of long custom messages
  190. -fixed that pesky bug w/the last line of code on a page
  191. -fixed the x-positioning of custom waves & shapes. Before, if you were
  192. saving some coordinates from the preset's per-frame equations (say in q1 and q2)
  193. and then you set "x = q1; y = q2;" in a custom shape's per-frame code
  194. (or in a custom wave's per-point code), the x position wouldn't really be
  195. in the right place, because of aspect ratio multiplications. Before, you had
  196. to actually write "x = (q1-0.5)*0.75 + 0.5; y = q2;" to get it to line up;
  197. now it's fixed, though, and you can just write "x = q1; y = q2;".
  198. -fixed some bugs where the plugin start up, in windowed mode, on the wrong window
  199. (and hence run super slow).
  200. -fixed some bugs w/a munged window frame when the "integrate with winamp" option
  201. was checked.
  202. <AFTER BETA 7:>
  203. -preset ratings are no longer read in all at once; instead, they are scanned in
  204. 1 per frame until they're all in. This fixes the long pauses when you switch
  205. to a directory that has many hundreds of presets. If you want to switch
  206. back to the old way (read them all in at once), there is an option for it
  207. in the config panel.
  208. -cranked max. mesh size up to 128x96
  209. -fixed bug in custom shape per-frame code, where t1-t8 vars were not
  210. resetting, at the beginning of each frame, to the values that they had
  211. @ the end of the custom shape init code's execution.
  212. -
  213. -
  214. -
  215. beta 2 thread: http://forums.winamp.com/showthread.php?threadid=142635
  216. beta 3 thread: http://forums.winamp.com/showthread.php?threadid=142760
  217. beta 4 thread: http://forums.winamp.com/showthread.php?threadid=143500
  218. beta 6 thread: http://forums.winamp.com/showthread.php?threadid=143974
  219. (+read about beat det: http://forums.winamp.com/showthread.php?threadid=102205)
  220. @ -code editing: when cursor is on 1st posn. in line, wrong line is highlighted!?
  221. -requests:
  222. -random sprites (...they can just write a prog for this, tho)
  223. -Text-entry mode.
  224. -Like your favorite online game, hit T or something to enter 'text entry' mode. Type a message, then either hit ESC to clear and cancel text-entry mode, or ENTER to display the text on top of the vis. Easier for custom messages than editing the INI file (and probably stopping or minimizing milkdrop to do it) and reloading.
  225. -OR SKIP IT; EASY TO JUST EDIT, RELOAD, AND HIT 00.
  226. -add 'AA' parameter to custom message text file?
  227. -when mem is low, fonts get kicked out -> white boxes
  228. -probably happening b/c ID3DXFont can't create a
  229. temp surface to use to draw text, since all the
  230. video memory is gobbled up.
  231. * -add to installer: q_and_t_vars.gif
  232. * -presets:
  233. 1. pick final set
  234. a. OK-do a pass weeding out slow presets (crank mesh size up)
  235. b. OK-do 2nd pass; rate them & delete crappies
  236. c. OK-merge w/set from 1.03; check for dupes; delete more suckies
  237. 2. OK-check for cpu-guzzlers
  238. 3. OK-check for big ones (>= 8kb)
  239. 4. check for ultra-spastic-when-audio-quiet ones
  240. 5. update all ratings
  241. 6. zip 'em up for safekeeping
  242. * -docs:
  243. -link to milkdrop.co.uk
  244. -preset authoring:
  245. -there are 11 variable pools:
  246. preset:
  247. a) preset init & per-frame code
  248. b) preset per-pixel code
  249. custom wave 1:
  250. c) init & per-frame code
  251. d) per-point code
  252. custom wave 2:
  253. e) init & per-frame code
  254. f) per-point code
  255. custom wave 3:
  256. g) init & per-frame code
  257. h) per-point code
  258. i) custom shape 1: init & per-frame code
  259. j) custom shape 2: init & per-frame code
  260. k) custom shape 3: init & per-frame code
  261. -all of these have predefined variables, the values of many of which
  262. trickle down from init code, to per-frame code, to per-pixel code,
  263. when the same variable is defined for each of these.
  264. -however, variables that you define ("my_var = 5;") do NOT trickle down.
  265. To allow you to pass custom values from, say, your per-frame code
  266. to your per-pixel code, the variables q1 through q8 were created.
  267. For custom waves and custom shapes, t1 through t8 work similarly.
  268. -q1-q8:
  269. -purpose: to allow [custom] values to carry from {the preset init
  270. and/or per-frame equations}, TO: {the per-pixel equations},
  271. {custom waves}, and {custom shapes}.
  272. -are first set in preset init code.
  273. -are reset, at the beginning of each frame, to the values that
  274. they had at the end of the preset init code.
  275. -can be modified in per-frame code...
  276. -changes WILL be passed on to the per-pixel code
  277. -changes WILL pass on to the q1-q8 vars in the custom waves
  278. & custom shapes code
  279. -changes will NOT pass on to the next frame, though;
  280. use your own (custom) variables for that.
  281. -can be modified in per-pixel code...
  282. -changes will pass on to the next *pixel*, but no further
  283. -changes will NOT pass on to the q1-q8 vars in the custom
  284. waves or custom shapes code.
  285. -changes will NOT pass on to the next frame, after the
  286. last pixel, though.
  287. -CUSTOM SHAPES: q1-q8...
  288. -are readable in both the custom shape init & per-frame code
  289. -start with the same values as q1-q8 had at the end of the *preset*
  290. per-frame code, this frame
  291. -can be modified in the init code, but only for a one-time
  292. pass-on to the per-frame code. For all subsequent frames
  293. (after the first), the per-frame code will get the q1-q8
  294. values as described above.
  295. -can be modified in the custom shape per-frame code, but only
  296. as temporary variables; the changes will not pass on anywhere.
  297. -CUSTOM WAVES: q1-q8...
  298. -are readable in the custom wave init, per-frame, and per-point code
  299. -start with the same values as q1-q8 had at the end of the *preset*
  300. per-frame code, this frame
  301. -can be modified in the init code, but only for a one-time
  302. pass-on to the per-frame code. For all subsequent frames
  303. (after the first), the per-frame code will get the q1-q8
  304. values as described above.
  305. -can be modified in the custom wave per-frame code; changes will
  306. pass on to the per-point code, but that's it.
  307. -can be modified in the per-point code, and the modified values
  308. will pass on from point to point, but won't carry beyond that.
  309. -CUSTOM WAVES: t1-t8...
  310. -allow you to generate & save values in the custom wave init code,
  311. that can pass on to the per-frame and, more sigificantly,
  312. per-point code (since it's in a different variable pool).
  313. -...
  314. !-whatever the values of q1-q8 were at the end of the per-frame and per-pixel
  315. code, these are copied to the q1-q8 variables in the custom wave & custom
  316. shape code, for that frame. However, those values are separate.
  317. For example, if you modify q1-q8 in the custom wave #1 code, those changes
  318. will not be visible anywhere else; if you modify q1-q8 in the custom shape
  319. #2 code, same thing. However, if you modify q1-q8 in the per-frame custom
  320. wave code, those modified values WILL be visible to the per-point custom
  321. wave code, and can be modified within it; but after the last point,
  322. the values q1-q8 will be discarded; on the next frame, in custom wave #1
  323. per-frame code, the values will be freshly copied from the values of the
  324. main q1-q8 after the preset's per-frame and per-point code have both been
  325. executed.
  326. -monitor:
  327. -can be read/written in preset init code & preset per-frame code.
  328. -not accessible from per-pixel code.
  329. -if you write it on one frame, then that value persists to the next frame.
  330. -t1-t8:
  331. -
  332. -
  333. -
  334. -regular docs:
  335. -put in the stuff recommended by VMS (vidcap, etc.)
  336. -add to troubleshooting:
  337. 1) desktop mode icons not appearing? or
  338. onscreen text looking like colored boxes?
  339. -> try freeing up some video memory. lower your res; drop to 16 bit;
  340. etc. TURN OFF AUTO SONGTITLES.
  341. 1) slow desktop/fullscr mode? -> try disabling auto songtitles + desktop icons.
  342. also try reducing texsize to 256x256, since that eats memory that the text surface could claim.
  343. 2)
  344. 3)
  345. * -presets:
  346. -add new
  347. -fix 3d presets (bring gammas back down to ~1.0)
  348. -check old ones, make sure they're ok
  349. -"Rovastar - Bytes"
  350. -check wave_y
  351. * -document custom waves & shapes
  352. * -slow text is mostly fixed... =(
  353. -desktop icons + playlist both have begin/end around them now, but in desktop mode,
  354. if you bring up playlist or Load menu, fps drops in half; press Esc, and fps doesn't go back up.
  355. -
  356. -
  357. -
  358. -DONE / v1.04:
  359. -updated to VMS 1.05
  360. -[list benefits...]
  361. -
  362. -
  363. -3d mode:
  364. a) SWAPPED DEFAULT L/R LENS COLORS! All images on the web are left=red, right=blue!
  365. b) fixed image display when viewing a 3D preset in a non-4:3 aspect ratio window
  366. c) gamma now works for 3d presets! (note: you might have to update your old presets.
  367. if they were 3D presets, the gamma was ignored and 1.0 was used; now,
  368. if gamma was >1.0 in the old preset, it will probably appear extremely bright.)
  369. d) added SHIFT+F9 and CTRL+C9 to inc/dec stereo separation
  370. e) added default stereo separation to config panel
  371. -cranked up the max. mesh size (was 48x36, now 64x48) and the default mesh size
  372. (was 24x18, now 32x24)
  373. -fixed aspect ratio for final display
  374. -auto-texsize is now computed slightly differently; for vertically or horizontally-stretched
  375. windows, the texsize is now biased more toward the larger dimension (vs. just the
  376. average).
  377. -added anisotropic filtering (for machines that support it)
  378. -fixed bug where the values of many variables in the preset init code were not set prior
  379. to execution of the init code (e.g. time, bass, etc. were all broken!)
  380. -added various preset blend effects. In addition to the old uniform fade, there is
  381. now a directional wipe, radial wipe, and plasma fade.
  382. -FIXED SLOW TEXT for DX8 (at least, on the geforce 4).
  383. Not using DT_RIGHT or DT_BOTTOM was the key.
  384. -why does text kill it in desktop mode?
  385. -text is SLOOW
  386. -to do: add (and use) song title font + tooltip font
  387. -re-test: menus, text, boxes, etc.
  388. -re-test: TIME
  389. -testing:
  390. -make sure sound works perfectly. (had to repro old pre-vms sound analysis!)
  391. -autogamma: currently assumes/requires that GetFrame() resets to 0 on a mode change
  392. (i.e. windowed -> fullscreen)... is that the case?
  393. -restore motion vectors
  394. -
  395. -
  396. -restore lost surfaces
  397. -test bRedraw flag (desktop mode/paused)
  398. -search for //? in milkdropfs.cpp and fix things
  399. problem: no good soln for VJ mode
  400. problem: D3DX won't give you solid background for your text.
  401. soln: (for later-) create wrapper fn that draws w/solid bkg.
  402. SOLN?: use D3DX to draw all text (plugin.cpp stuff AND playlist);
  403. then, for VJ mode, create a 2nd DxContext
  404. w/its own window + windowproc + fonts. (YUCK)
  405. 1) config panel: test, and add WM_HELP's (copy from tooltips)
  406. 2) keyboard input: test; and...
  407. -need to reset UI_MODE when playlist is turned on, and
  408. -need to reset m_show_playlist when UI_MODE is changed. (?)
  409. -(otherwise they can both show @ same time and will fight
  410. for keys and draw over each other)
  411. 3) comment out most of D3D stuff in milkdropfs.cpp, and then
  412. get it running w/o any milkdrop, but with text, etc.
  413. 4) sound
  414. Issues / To Do Later
  415. --------------------
  416. 1) sprites: color keying stuff probably won't work any more...
  417. 2) scroll lock: pull code from Monkey
  418. 3) m_nGridY should not always be m_nGridX*3/4!
  419. 4) get solid backgrounds for menus, waitstring code, etc.
  420. (make a wrapper function!)
  421. 99) at end: update help screen
  422. Things that will be different
  423. -----------------------------
  424. 1) font sizes are no longer relative to size of window; they are absolute.
  425. 2) 'don't clear screen at startup' option is gone
  426. 3) 'always on top' option is gone
  427. 4) text will not be black-on-white when an inverted-color preset is showing
  428. -VJ mode:
  429. -notes
  430. 1. (remember window size/pos, and save it from session to session? nah.)
  431. 2. (kiv: scroll lock)
  432. 3. (VJ window + desktop mode:)
  433. -ok w/o VJ mode
  434. -w/VJ mode, regardless of 'fix slow text' option, probs w/focus;
  435. click on vj window, and plugin window flashes to top of Z order!
  436. -goes away if you comment out 1st call to PushWindowToJustBeforeDesktop()...
  437. -when you disable PushWindowToJustBeforeDesktop:
  438. -..and click on EITHER window, milkdrop jumps in front of the taskbar.
  439. -..and click on a non-MD window, nothing happens.
  440. d-FIXED somehow, magically, while fixing bugs w/true fullscreen mode!
  441. 4. (VJ window + true fullscreen mode:)
  442. d-make sure VJ window gets placed on the right monitor, at startup,
  443. and respects taskbar posn.
  444. d-bug - start in windowed mode, then dbl-clk to go [true] fullscreen
  445. on 2nd monitor, all with VJ mode on, and it excepts somewhere
  446. in m_text.DrawNow() in a call to DrawPrimitive()!
  447. FIXED - had to check m_vjd3d8_device->TestCooperativeLevel
  448. each frame, and destroy/reinit if device needed reset.
  449. d-can't resize VJ window when grfx window is running true fullscreen!
  450. -FIXED, by dropping the Sleep(30)/return when m_lost_focus
  451. was true, and by not consuming WM_NCACTIVATE in true fullscreen
  452. mode when m_hTextWnd was present, since DX8 doesn't do its
  453. auto-minimize thing in that case.
  454. */
  455. #include "api__vis_milk2.h"
  456. #include "plugin.h"
  457. #include "utility.h"
  458. #include "support.h"
  459. #include "resource.h"
  460. #include "defines.h"
  461. #include "shell_defines.h"
  462. #include <assert.h>
  463. #include <locale.h>
  464. #include <process.h> // for beginthread, etc.
  465. #include <shellapi.h>
  466. #include <strsafe.h>
  467. #include "../nu/AutoCharFn.h"
  468. #define FRAND ((warand() % 7381)/7380.0f)
  469. void NSEEL_HOSTSTUB_EnterMutex(){}
  470. void NSEEL_HOSTSTUB_LeaveMutex(){}
  471. // note: these must match layouts in support.h!!
  472. D3DVERTEXELEMENT9 g_MyVertDecl[] =
  473. {
  474. { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
  475. { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
  476. { 0, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
  477. { 0, 32, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },
  478. D3DDECL_END()
  479. };
  480. D3DVERTEXELEMENT9 g_WfVertDecl[] =
  481. {
  482. { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
  483. { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
  484. D3DDECL_END()
  485. };
  486. D3DVERTEXELEMENT9 g_SpriteVertDecl[] =
  487. {
  488. // matches D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1
  489. { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
  490. { 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
  491. { 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
  492. D3DDECL_END()
  493. };
  494. //extern CSoundData* pg_sound; // declared in main.cpp
  495. extern CPlugin g_plugin; // declared in main.cpp (note: was 'pg')
  496. // from support.cpp:
  497. extern bool g_bDebugOutput;
  498. extern bool g_bDumpFileCleared;
  499. // for __UpdatePresetList:
  500. volatile HANDLE g_hThread; // only r/w from our MAIN thread
  501. volatile bool g_bThreadAlive; // set true by MAIN thread, and set false upon exit from 2nd thread.
  502. volatile int g_bThreadShouldQuit; // set by MAIN thread to flag 2nd thread that it wants it to exit.
  503. static CRITICAL_SECTION g_cs;
  504. #define IsAlphabetChar(x) ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z'))
  505. #define IsAlphanumericChar(x) ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || (x >= '0' && x <= '9') || x == '.')
  506. #define IsNumericChar(x) (x >= '0' && x <= '9')
  507. const unsigned char LC2UC[256] = {
  508. 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
  509. 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,255,
  510. 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
  511. 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
  512. 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
  513. 113,114,115,116,117,118,119,120,121,122,91,92,93,94,95,96,
  514. 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
  515. 113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
  516. 129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,
  517. 145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,
  518. 161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,
  519. 177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,
  520. 193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,
  521. 209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,
  522. 225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,
  523. 241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
  524. };
  525. /*
  526. * Copies the given string TO the clipboard.
  527. */
  528. void copyStringToClipboardA(const char * source)
  529. {
  530. int ok = OpenClipboard(NULL);
  531. if (!ok)
  532. return;
  533. HGLOBAL clipbuffer;
  534. EmptyClipboard();
  535. clipbuffer = GlobalAlloc(GMEM_DDESHARE, (lstrlenA(source)+1)*sizeof(char));
  536. char* buffer = (char*)GlobalLock(clipbuffer);
  537. lstrcpyA(buffer, source);
  538. GlobalUnlock(clipbuffer);
  539. SetClipboardData(CF_TEXT, clipbuffer);
  540. CloseClipboard();
  541. }
  542. void copyStringToClipboardW(const wchar_t * source)
  543. {
  544. int ok = OpenClipboard(NULL);
  545. if (!ok)
  546. return;
  547. HGLOBAL clipbuffer;
  548. EmptyClipboard();
  549. clipbuffer = GlobalAlloc(GMEM_DDESHARE, (lstrlenW(source)+1)*sizeof(wchar_t));
  550. wchar_t* buffer = (wchar_t*)GlobalLock(clipbuffer);
  551. lstrcpyW(buffer, source);
  552. GlobalUnlock(clipbuffer);
  553. SetClipboardData(CF_UNICODETEXT, clipbuffer);
  554. CloseClipboard();
  555. }
  556. /*
  557. * Suppose there is a string on the clipboard.
  558. * This function copies it FROM there.
  559. */
  560. char * getStringFromClipboardA()
  561. {
  562. int ok = OpenClipboard(NULL);
  563. if (!ok)
  564. return NULL;
  565. HANDLE hData = GetClipboardData(CF_TEXT);
  566. char* buffer = (char*)GlobalLock(hData);
  567. GlobalUnlock(hData);
  568. CloseClipboard();
  569. return buffer;
  570. }
  571. wchar_t * getStringFromClipboardW()
  572. {
  573. int ok = OpenClipboard(NULL);
  574. if (!ok)
  575. return NULL;
  576. HANDLE hData = GetClipboardData(CF_UNICODETEXT);
  577. wchar_t* buffer = (wchar_t*)GlobalLock(hData);
  578. GlobalUnlock(hData);
  579. CloseClipboard();
  580. return buffer;
  581. }
  582. void ConvertCRsToLFCA(const char* src, char* dst)
  583. {
  584. while (*src)
  585. {
  586. char ch = *src;
  587. if (*src==13 && *(src+1)==10)
  588. {
  589. *dst++ = LINEFEED_CONTROL_CHAR;
  590. src += 2;
  591. }
  592. else
  593. {
  594. *dst++ = *src++;
  595. }
  596. }
  597. *dst = 0;
  598. }
  599. void ConvertCRsToLFCW(const wchar_t* src, wchar_t* dst)
  600. {
  601. while (*src)
  602. {
  603. wchar_t ch = *src;
  604. if (*src==13 && *(src+1)==10)
  605. {
  606. *dst++ = LINEFEED_CONTROL_CHAR;
  607. src += 2;
  608. }
  609. else
  610. {
  611. *dst++ = *src++;
  612. }
  613. }
  614. *dst = 0;
  615. }
  616. void ConvertLFCToCRsA(const char* src, char* dst)
  617. {
  618. while (*src)
  619. {
  620. char ch = *src;
  621. if (*src==LINEFEED_CONTROL_CHAR)
  622. {
  623. *dst++ = 13;
  624. *dst++ = 10;
  625. src++;
  626. }
  627. else
  628. {
  629. *dst++ = *src++;
  630. }
  631. }
  632. *dst = 0;
  633. }
  634. void ConvertLFCToCRsW(const wchar_t* src, wchar_t* dst)
  635. {
  636. while (*src)
  637. {
  638. wchar_t ch = *src;
  639. if (*src==LINEFEED_CONTROL_CHAR)
  640. {
  641. *dst++ = 13;
  642. *dst++ = 10;
  643. src++;
  644. }
  645. else
  646. {
  647. *dst++ = *src++;
  648. }
  649. }
  650. *dst = 0;
  651. }
  652. int mystrcmpiW(const wchar_t *s1, const wchar_t *s2)
  653. {
  654. // returns 1 if s1 comes before s2
  655. // returns 0 if equal
  656. // returns -1 if s1 comes after s2
  657. // treats all characters/symbols by their ASCII values,
  658. // except that it DOES ignore case.
  659. int i=0;
  660. while (LC2UC[s1[i]] == LC2UC[s2[i]] && s1[i] != 0)
  661. i++;
  662. //FIX THIS!
  663. if (s1[i]==0 && s2[i]==0)
  664. return 0;
  665. else if (s1[i]==0)
  666. return -1;
  667. else if (s2[i]==0)
  668. return 1;
  669. else
  670. return (LC2UC[s1[i]] < LC2UC[s2[i]]) ? -1 : 1;
  671. }
  672. bool ReadFileToString(const wchar_t* szBaseFilename, char* szDestText, int nMaxBytes, bool bConvertLFsToSpecialChar)
  673. {
  674. wchar_t szFile[MAX_PATH];
  675. swprintf(szFile, L"%s%s", g_plugin.m_szMilkdrop2Path, szBaseFilename);
  676. // read in all chars. Replace char combos: { 13; 13+10; 10 } with LINEFEED_CONTROL_CHAR, if bConvertLFsToSpecialChar is true.
  677. FILE* f = _wfopen(szFile, L"rb");
  678. if (!f)
  679. {
  680. wchar_t buf[1024], title[64];
  681. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_READ_DATA_FILE_X), szFile);
  682. g_plugin.dumpmsg(buf);
  683. MessageBoxW(NULL, buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  684. return false;
  685. }
  686. int len = 0;
  687. int x;
  688. char prev_ch = 0;
  689. while ( (x = fgetc(f)) >= 0 && len < nMaxBytes-4 )
  690. {
  691. char orig_ch = (char)x;
  692. char ch = orig_ch;
  693. bool bSkipChar = false;
  694. if (bConvertLFsToSpecialChar)
  695. {
  696. if (ch==10)
  697. {
  698. if (prev_ch==13)
  699. bSkipChar = true;
  700. else
  701. ch = LINEFEED_CONTROL_CHAR;
  702. }
  703. else if (ch==13)
  704. ch = LINEFEED_CONTROL_CHAR;
  705. }
  706. if (!bSkipChar)
  707. szDestText[len++] = ch;
  708. prev_ch = orig_ch;
  709. }
  710. szDestText[len] = 0;
  711. szDestText[len++] = ' '; // make sure there is some whitespace after
  712. fclose(f);
  713. return true;
  714. }
  715. // these callback functions are called by menu.cpp whenever the user finishes editing an eval_ expression.
  716. void OnUserEditedPerFrame(LPARAM param1, LPARAM param2)
  717. {
  718. g_plugin.m_pState->RecompileExpressions(RECOMPILE_PRESET_CODE, 0);
  719. }
  720. void OnUserEditedPerPixel(LPARAM param1, LPARAM param2)
  721. {
  722. g_plugin.m_pState->RecompileExpressions(RECOMPILE_PRESET_CODE, 0);
  723. }
  724. void OnUserEditedPresetInit(LPARAM param1, LPARAM param2)
  725. {
  726. g_plugin.m_pState->RecompileExpressions(RECOMPILE_PRESET_CODE, 1);
  727. }
  728. void OnUserEditedWavecode(LPARAM param1, LPARAM param2)
  729. {
  730. g_plugin.m_pState->RecompileExpressions(RECOMPILE_WAVE_CODE, 0);
  731. }
  732. void OnUserEditedWavecodeInit(LPARAM param1, LPARAM param2)
  733. {
  734. g_plugin.m_pState->RecompileExpressions(RECOMPILE_WAVE_CODE, 1);
  735. }
  736. void OnUserEditedShapecode(LPARAM param1, LPARAM param2)
  737. {
  738. g_plugin.m_pState->RecompileExpressions(RECOMPILE_SHAPE_CODE, 0);
  739. }
  740. void OnUserEditedShapecodeInit(LPARAM param1, LPARAM param2)
  741. {
  742. g_plugin.m_pState->RecompileExpressions(RECOMPILE_SHAPE_CODE, 1);
  743. }
  744. void OnUserEditedWarpShaders(LPARAM param1, LPARAM param2)
  745. {
  746. g_plugin.m_bNeedRescanTexturesDir = true;
  747. g_plugin.ClearErrors(ERR_PRESET);
  748. if (g_plugin.m_nMaxPSVersion == 0)
  749. return;
  750. if (!g_plugin.RecompilePShader(g_plugin.m_pState->m_szWarpShadersText, &g_plugin.m_shaders.warp, SHADER_WARP, false, g_plugin.m_pState->m_nWarpPSVersion))
  751. {
  752. // switch to fallback
  753. g_plugin.m_fallbackShaders_ps.warp.ptr->AddRef();
  754. g_plugin.m_fallbackShaders_ps.warp.CT->AddRef();
  755. g_plugin.m_shaders.warp = g_plugin.m_fallbackShaders_ps.warp;
  756. }
  757. }
  758. void OnUserEditedCompShaders(LPARAM param1, LPARAM param2)
  759. {
  760. g_plugin.m_bNeedRescanTexturesDir = true;
  761. g_plugin.ClearErrors(ERR_PRESET);
  762. if (g_plugin.m_nMaxPSVersion == 0)
  763. return;
  764. if (!g_plugin.RecompilePShader(g_plugin.m_pState->m_szCompShadersText, &g_plugin.m_shaders.comp, SHADER_COMP, false, g_plugin.m_pState->m_nCompPSVersion))
  765. {
  766. // switch to fallback
  767. g_plugin.m_fallbackShaders_ps.comp.ptr->AddRef();
  768. g_plugin.m_fallbackShaders_ps.comp.CT->AddRef();
  769. g_plugin.m_shaders.comp = g_plugin.m_fallbackShaders_ps.comp;
  770. }
  771. }
  772. // Modify the help screen text here.
  773. // Watch the # of lines, though; if there are too many, they will get cut off;
  774. // and watch the length of the lines, since there is no wordwrap.
  775. // A good guideline: your entire help screen should be visible when fullscreen
  776. // @ 640x480 and using the default help screen font.
  777. wchar_t* g_szHelp = 0;
  778. int g_szHelp_W = 0;
  779. // this is for integrating modern skins (with their Random button)
  780. // and having it match our Scroll Lock (preset lock) state...
  781. #define IPC_CB_VISRANDOM 628
  782. //----------------------------------------------------------------------
  783. void CPlugin::OverrideDefaults()
  784. {
  785. // Here, you have the option of overriding the "default defaults"
  786. // for the stuff on tab 1 of the config panel, replacing them
  787. // with custom defaults for your plugin.
  788. // To override any of the defaults, just uncomment the line
  789. // and change the value.
  790. // DO NOT modify these values from any function but this one!
  791. // This example plugin only changes the default width/height
  792. // for fullscreen mode; the "default defaults" are just
  793. // 640 x 480.
  794. // If your plugin is very dependent on smooth animation and you
  795. // wanted it plugin to have the 'save cpu' option OFF by default,
  796. // for example, you could set 'm_save_cpu' to 0 here.
  797. // m_start_fullscreen = 0; // 0 or 1
  798. // m_start_desktop = 0; // 0 or 1
  799. // m_fake_fullscreen_mode = 0; // 0 or 1
  800. // m_max_fps_fs = 30; // 1-120, or 0 for 'unlimited'
  801. // m_max_fps_dm = 30; // 1-120, or 0 for 'unlimited'
  802. // m_max_fps_w = 30; // 1-120, or 0 for 'unlimited'
  803. // m_show_press_f1_msg = 1; // 0 or 1
  804. m_allow_page_tearing_w = 0; // 0 or 1
  805. // m_allow_page_tearing_fs = 0; // 0 or 1
  806. // m_allow_page_tearing_dm = 1; // 0 or 1
  807. // m_minimize_winamp = 1; // 0 or 1
  808. // m_desktop_textlabel_boxes = 1; // 0 or 1
  809. // m_save_cpu = 0; // 0 or 1
  810. // lstrcpy(m_fontinfo[0].szFace, "Trebuchet MS"); // system font
  811. // m_fontinfo[0].nSize = 18;
  812. // m_fontinfo[0].bBold = 0;
  813. // m_fontinfo[0].bItalic = 0;
  814. // lstrcpy(m_fontinfo[1].szFace, "Times New Roman"); // decorative font
  815. // m_fontinfo[1].nSize = 24;
  816. // m_fontinfo[1].bBold = 0;
  817. // m_fontinfo[1].bItalic = 1;
  818. // Don't override default FS mode here; shell is now smart and sets it to match
  819. // the current desktop display mode, by default.
  820. //m_disp_mode_fs.Width = 1024; // normally 640
  821. //m_disp_mode_fs.Height = 768; // normally 480
  822. // use either D3DFMT_X8R8G8B8 or D3DFMT_R5G6B5.
  823. // The former will match to any 32-bit color format available,
  824. // and the latter will match to any 16-bit color available,
  825. // if that exact format can't be found.
  826. //m_disp_mode_fs.Format = D3DFMT_UNKNOWN; //<- this tells config panel & visualizer to use current display mode as a default!! //D3DFMT_X8R8G8B8;
  827. // m_disp_mode_fs.RefreshRate = 60;
  828. }
  829. //----------------------------------------------------------------------
  830. void CPlugin::MyPreInitialize()
  831. {
  832. // Initialize EVERY data member you've added to CPlugin here;
  833. // these will be the default values.
  834. // If you want to initialize any of your variables with random values
  835. // (using rand()), be sure to seed the random number generator first!
  836. // (If you want to change the default values for settings that are part of
  837. // the plugin shell (framework), do so from OverrideDefaults() above.)
  838. // seed the system's random number generator w/the current system time:
  839. //srand((unsigned)time(NULL)); -don't - let winamp do it
  840. // attempt to load a unicode F1 help message otherwise revert to the ansi version
  841. g_szHelp = (wchar_t*)GetTextResource(IDR_TEXT2,1);
  842. if(!g_szHelp) g_szHelp = (wchar_t*)GetTextResource(IDR_TEXT1,0);
  843. else g_szHelp_W = 1;
  844. // CONFIG PANEL SETTINGS THAT WE'VE ADDED (TAB #2)
  845. m_bFirstRun = true;
  846. m_bInitialPresetSelected = false;
  847. m_fBlendTimeUser = 1.7f;
  848. m_fBlendTimeAuto = 2.7f;
  849. m_fTimeBetweenPresets = 16.0f;
  850. m_fTimeBetweenPresetsRand = 10.0f;
  851. m_bSequentialPresetOrder = false;
  852. m_bHardCutsDisabled = true;
  853. m_fHardCutLoudnessThresh = 2.5f;
  854. m_fHardCutHalflife = 60.0f;
  855. //m_nWidth = 1024;
  856. //m_nHeight = 768;
  857. //m_nDispBits = 16;
  858. m_nCanvasStretch = 0;
  859. m_nTexSizeX = -1; // -1 means "auto"
  860. m_nTexSizeY = -1; // -1 means "auto"
  861. m_nTexBitsPerCh = 8;
  862. m_nGridX = 48;//32;
  863. m_nGridY = 36;//24;
  864. m_bShowPressF1ForHelp = true;
  865. //lstrcpy(m_szMonitorName, "[don't use multimon]");
  866. m_bShowMenuToolTips = true; // NOTE: THIS IS CURRENTLY HARDWIRED TO TRUE - NO OPTION TO CHANGE
  867. m_n16BitGamma = 2;
  868. m_bAutoGamma = true;
  869. //m_nFpsLimit = -1;
  870. m_bEnableRating = true;
  871. //m_bInstaScan = false;
  872. m_bSongTitleAnims = true;
  873. m_fSongTitleAnimDuration = 1.7f;
  874. m_fTimeBetweenRandomSongTitles = -1.0f;
  875. m_fTimeBetweenRandomCustomMsgs = -1.0f;
  876. m_nSongTitlesSpawned = 0;
  877. m_nCustMsgsSpawned = 0;
  878. m_nFramesSinceResize = 0;
  879. //m_bAlways3D = false;
  880. //m_fStereoSep = 1.0f;
  881. //m_bAlwaysOnTop = false;
  882. //m_bFixSlowText = true;
  883. //m_bWarningsDisabled = false;
  884. m_bWarningsDisabled2 = true;
  885. //m_bAnisotropicFiltering = true;
  886. m_bPresetLockOnAtStartup = false;
  887. m_bPreventScollLockHandling = false;
  888. m_nMaxPSVersion_ConfigPanel = -1; // -1 = auto, 0 = disable shaders, 2 = ps_2_0, 3 = ps_3_0
  889. m_nMaxPSVersion_DX9 = -1; // 0 = no shader support, 2 = ps_2_0, 3 = ps_3_0
  890. m_nMaxPSVersion = -1; // this one will be the ~min of the other two. 0/2/3.
  891. m_nMaxImages = 32;
  892. m_nMaxBytes = 16000000;
  893. #ifdef _DEBUG
  894. m_dwShaderFlags = D3DXSHADER_DEBUG|(1<<16);
  895. #else
  896. m_dwShaderFlags = (1<<16);//D3DXSHADER_SKIPOPTIMIZATION|D3DXSHADER_NO_PRESHADER;
  897. #endif
  898. //m_pFragmentLinker = NULL;
  899. //m_pCompiledFragments = NULL;
  900. m_pShaderCompileErrors = NULL;
  901. //m_vs_warp = NULL;
  902. //m_ps_warp = NULL;
  903. //m_vs_comp = NULL;
  904. //m_ps_comp = NULL;
  905. ZeroMemory(&m_shaders, sizeof(PShaderSet));
  906. ZeroMemory(&m_OldShaders, sizeof(PShaderSet));
  907. ZeroMemory(&m_NewShaders, sizeof(PShaderSet));
  908. ZeroMemory(&m_fallbackShaders_vs, sizeof(VShaderSet));
  909. ZeroMemory(&m_fallbackShaders_ps, sizeof(PShaderSet));
  910. ZeroMemory(m_BlurShaders, sizeof(m_BlurShaders));
  911. m_bWarpShaderLock = false;
  912. m_bCompShaderLock = false;
  913. m_bNeedRescanTexturesDir = true;
  914. // vertex declarations:
  915. m_pSpriteVertDecl = NULL;
  916. m_pWfVertDecl = NULL;
  917. m_pMyVertDecl = NULL;
  918. m_gdi_title_font_doublesize = NULL;
  919. m_d3dx_title_font_doublesize = NULL;
  920. // RUNTIME SETTINGS THAT WE'VE ADDED
  921. m_prev_time = GetTime() - 0.0333f; // note: this will be updated each frame, at bottom of MyRenderFn.
  922. m_bTexSizeWasAutoPow2 = false;
  923. m_bTexSizeWasAutoExact = false;
  924. //m_bPresetLockedByUser = false; NOW SET IN DERIVED SETTINGS
  925. m_bPresetLockedByCode = false;
  926. m_fStartTime = 0.0f;
  927. m_fPresetStartTime = 0.0f;
  928. m_fNextPresetTime = -1.0f; // negative value means no time set (...it will be auto-set on first call to UpdateTime)
  929. m_nLoadingPreset = 0;
  930. m_nPresetsLoadedTotal = 0;
  931. m_fSnapPoint = 0.5f;
  932. m_pState = &m_state_DO_NOT_USE[0];
  933. m_pOldState = &m_state_DO_NOT_USE[1];
  934. m_pNewState = &m_state_DO_NOT_USE[2];
  935. m_UI_mode = UI_REGULAR;
  936. m_bShowShaderHelp = false;
  937. m_nMashSlot = 0; //0..MASH_SLOTS-1
  938. for (int mash=0; mash<MASH_SLOTS; mash++)
  939. m_nLastMashChangeFrame[mash] = 0;
  940. //m_nTrackPlaying = 0;
  941. //m_nSongPosMS = 0;
  942. //m_nSongLenMS = 0;
  943. m_bUserPagedUp = false;
  944. m_bUserPagedDown = false;
  945. m_fMotionVectorsTempDx = 0.0f;
  946. m_fMotionVectorsTempDy = 0.0f;
  947. m_waitstring.bActive = false;
  948. m_waitstring.bOvertypeMode = false;
  949. m_waitstring.szClipboard[0] = 0;
  950. m_nPresets = 0;
  951. m_nDirs = 0;
  952. m_nPresetListCurPos = 0;
  953. m_nCurrentPreset = -1;
  954. m_szCurrentPresetFile[0] = 0;
  955. m_szLoadingPreset[0] = 0;
  956. //m_szPresetDir[0] = 0; // will be set @ end of this function
  957. m_bPresetListReady = false;
  958. m_szUpdatePresetMask[0] = 0;
  959. //m_nRatingReadProgress = -1;
  960. myfft.Init(576, MY_FFT_SAMPLES, -1);
  961. memset(&mysound, 0, sizeof(mysound));
  962. int i = 0;
  963. for (i=0; i<PRESET_HIST_LEN; i++)
  964. m_presetHistory[i] = L"";
  965. m_presetHistoryPos = 0;
  966. m_presetHistoryBackFence = 0;
  967. m_presetHistoryFwdFence = 0;
  968. //m_nTextHeightPixels = -1;
  969. //m_nTextHeightPixels_Fancy = -1;
  970. m_bShowFPS = false;
  971. m_bShowRating = false;
  972. m_bShowPresetInfo = false;
  973. m_bShowDebugInfo = false;
  974. m_bShowSongTitle = false;
  975. m_bShowSongTime = false;
  976. m_bShowSongLen = false;
  977. m_fShowRatingUntilThisTime = -1.0f;
  978. ClearErrors();
  979. m_szDebugMessage[0] = 0;
  980. m_szSongTitle[0] = 0;
  981. m_szSongTitlePrev[0] = 0;
  982. m_lpVS[0] = NULL;
  983. m_lpVS[1] = NULL;
  984. #if (NUM_BLUR_TEX>0)
  985. for (i=0; i<NUM_BLUR_TEX; i++)
  986. m_lpBlur[i] = NULL;
  987. #endif
  988. m_lpDDSTitle = NULL;
  989. m_nTitleTexSizeX = 0;
  990. m_nTitleTexSizeY = 0;
  991. m_verts = NULL;
  992. m_verts_temp = NULL;
  993. m_vertinfo = NULL;
  994. m_indices_list = NULL;
  995. m_indices_strip = NULL;
  996. m_bMMX = false;
  997. m_bHasFocus = true;
  998. m_bHadFocus = false;
  999. m_bOrigScrollLockState = GetKeyState(VK_SCROLL) & 1;
  1000. // m_bMilkdropScrollLockState is derived at end of MyReadConfig()
  1001. m_nNumericInputMode = NUMERIC_INPUT_MODE_CUST_MSG;
  1002. m_nNumericInputNum = 0;
  1003. m_nNumericInputDigits = 0;
  1004. //td_custom_msg_font m_CustomMessageFont[MAX_CUSTOM_MESSAGE_FONTS];
  1005. //td_custom_msg m_CustomMessage[MAX_CUSTOM_MESSAGES];
  1006. //texmgr m_texmgr; // for user sprites
  1007. m_supertext.bRedrawSuperText = false;
  1008. m_supertext.fStartTime = -1.0f;
  1009. // --------------------other init--------------------
  1010. g_bDebugOutput = false;
  1011. g_bDumpFileCleared = false;
  1012. swprintf(m_szMilkdrop2Path, L"%s%s", GetPluginsDirPath(), SUBDIR);
  1013. swprintf(m_szPresetDir, L"%spresets\\", m_szMilkdrop2Path );
  1014. // note that the config dir can be under Program Files or Application Data!!
  1015. wchar_t szConfigDir[MAX_PATH] = {0};
  1016. lstrcpyW(szConfigDir, GetConfigIniFile());
  1017. wchar_t* p = wcsrchr(szConfigDir, L'\\');
  1018. if (p) *(p+1) = 0;
  1019. swprintf(m_szMsgIniFile, L"%s%s", szConfigDir, MSG_INIFILE );
  1020. swprintf(m_szImgIniFile, L"%s%s", szConfigDir, IMG_INIFILE );
  1021. }
  1022. //----------------------------------------------------------------------
  1023. void CPlugin::MyReadConfig()
  1024. {
  1025. // Read the user's settings from the .INI file.
  1026. // If you've added any controls to the config panel, read their value in
  1027. // from the .INI file here.
  1028. // use this function declared in to read a value of this type:
  1029. // ----------------- ----------- ----------------------------
  1030. // GetPrivateProfileInt Win32 API int
  1031. // GetPrivateProfileBool utility.h bool
  1032. // GetPrivateProfileBOOL utility.h BOOL
  1033. // GetPrivateProfileFloat utility.h float
  1034. // GetPrivateProfileString Win32 API string
  1035. //ex: m_fog_enabled = GetPrivateProfileInt("settings","fog_enabled" ,m_fog_enabled ,GetConfigIniFile());
  1036. int n=0;
  1037. wchar_t *pIni = GetConfigIniFile();
  1038. m_bFirstRun = !GetPrivateProfileBoolW(L"settings",L"bConfigured" ,false,pIni);
  1039. m_bEnableRating = GetPrivateProfileBoolW(L"settings",L"bEnableRating",m_bEnableRating,pIni);
  1040. //m_bInstaScan = GetPrivateProfileBool("settings","bInstaScan",m_bInstaScan,pIni);
  1041. m_bHardCutsDisabled = GetPrivateProfileBoolW(L"settings",L"bHardCutsDisabled",m_bHardCutsDisabled,pIni);
  1042. g_bDebugOutput = GetPrivateProfileBoolW(L"settings",L"bDebugOutput",g_bDebugOutput,pIni);
  1043. //m_bShowSongInfo = GetPrivateProfileBool("settings","bShowSongInfo",m_bShowSongInfo,pIni);
  1044. //m_bShowPresetInfo=GetPrivateProfileBool("settings","bShowPresetInfo",m_bShowPresetInfo,pIni);
  1045. m_bShowPressF1ForHelp = GetPrivateProfileBoolW(L"settings",L"bShowPressF1ForHelp",m_bShowPressF1ForHelp,pIni);
  1046. //m_bShowMenuToolTips = GetPrivateProfileBool("settings","bShowMenuToolTips",m_bShowMenuToolTips,pIni);
  1047. m_bSongTitleAnims = GetPrivateProfileBoolW(L"settings",L"bSongTitleAnims",m_bSongTitleAnims,pIni);
  1048. m_bShowFPS = GetPrivateProfileBoolW(L"settings",L"bShowFPS", m_bShowFPS ,pIni);
  1049. m_bShowRating = GetPrivateProfileBoolW(L"settings",L"bShowRating", m_bShowRating ,pIni);
  1050. m_bShowPresetInfo = GetPrivateProfileBoolW(L"settings",L"bShowPresetInfo",m_bShowPresetInfo ,pIni);
  1051. //m_bShowDebugInfo = GetPrivateProfileBool("settings","bShowDebugInfo", m_bShowDebugInfo ,pIni);
  1052. m_bShowSongTitle = GetPrivateProfileBoolW(L"settings",L"bShowSongTitle", m_bShowSongTitle ,pIni);
  1053. m_bShowSongTime = GetPrivateProfileBoolW(L"settings",L"bShowSongTime", m_bShowSongTime ,pIni);
  1054. m_bShowSongLen = GetPrivateProfileBoolW(L"settings",L"bShowSongLen", m_bShowSongLen ,pIni);
  1055. //m_bFixPinkBug = GetPrivateProfileBool("settings","bFixPinkBug",m_bFixPinkBug,pIni);
  1056. int nTemp = GetPrivateProfileBoolW(L"settings",L"bFixPinkBug",-1,pIni);
  1057. if (nTemp == 0)
  1058. m_n16BitGamma = 0;
  1059. else if (nTemp == 1)
  1060. m_n16BitGamma = 2;
  1061. m_n16BitGamma = GetPrivateProfileIntW(L"settings",L"n16BitGamma",m_n16BitGamma,pIni);
  1062. m_bAutoGamma = GetPrivateProfileBoolW(L"settings",L"bAutoGamma",m_bAutoGamma,pIni);
  1063. //m_bAlways3D = GetPrivateProfileBool("settings","bAlways3D",m_bAlways3D,pIni);
  1064. //m_fStereoSep = GetPrivateProfileFloat("settings","fStereoSep",m_fStereoSep,pIni);
  1065. //m_bFixSlowText = GetPrivateProfileBool("settings","bFixSlowText",m_bFixSlowText,pIni);
  1066. //m_bAlwaysOnTop = GetPrivateProfileBool("settings","bAlwaysOnTop",m_bAlwaysOnTop,pIni);
  1067. //m_bWarningsDisabled = GetPrivateProfileBool("settings","bWarningsDisabled",m_bWarningsDisabled,pIni);
  1068. m_bWarningsDisabled2 = GetPrivateProfileBoolW(L"settings",L"bWarningsDisabled2",m_bWarningsDisabled2,pIni);
  1069. //m_bAnisotropicFiltering = GetPrivateProfileBool("settings","bAnisotropicFiltering",m_bAnisotropicFiltering,pIni);
  1070. m_bPresetLockOnAtStartup = GetPrivateProfileBoolW(L"settings",L"bPresetLockOnAtStartup",m_bPresetLockOnAtStartup,pIni);
  1071. m_bPreventScollLockHandling = GetPrivateProfileBoolW(L"settings",L"m_bPreventScollLockHandling",m_bPreventScollLockHandling,pIni);
  1072. m_nCanvasStretch = GetPrivateProfileIntW(L"settings",L"nCanvasStretch" ,m_nCanvasStretch,pIni);
  1073. m_nTexSizeX = GetPrivateProfileIntW(L"settings",L"nTexSize" ,m_nTexSizeX ,pIni);
  1074. m_nTexSizeY = m_nTexSizeX;
  1075. m_bTexSizeWasAutoPow2 = (m_nTexSizeX == -2);
  1076. m_bTexSizeWasAutoExact = (m_nTexSizeX == -1);
  1077. m_nTexBitsPerCh = GetPrivateProfileIntW(L"settings", L"nTexBitsPerCh", m_nTexBitsPerCh, pIni);
  1078. m_nGridX = GetPrivateProfileIntW(L"settings",L"nMeshSize" ,m_nGridX ,pIni);
  1079. m_nGridY = m_nGridX*3/4;
  1080. m_nMaxPSVersion_ConfigPanel = GetPrivateProfileIntW(L"settings",L"MaxPSVersion",m_nMaxPSVersion_ConfigPanel,pIni);
  1081. m_nMaxImages = GetPrivateProfileIntW(L"settings",L"MaxImages",m_nMaxImages,pIni);
  1082. m_nMaxBytes = GetPrivateProfileIntW(L"settings",L"MaxBytes" ,m_nMaxBytes ,pIni);
  1083. m_fBlendTimeUser = GetPrivateProfileFloatW(L"settings",L"fBlendTimeUser" ,m_fBlendTimeUser ,pIni);
  1084. m_fBlendTimeAuto = GetPrivateProfileFloatW(L"settings",L"fBlendTimeAuto" ,m_fBlendTimeAuto ,pIni);
  1085. m_fTimeBetweenPresets = GetPrivateProfileFloatW(L"settings",L"fTimeBetweenPresets" ,m_fTimeBetweenPresets ,pIni);
  1086. m_fTimeBetweenPresetsRand = GetPrivateProfileFloatW(L"settings",L"fTimeBetweenPresetsRand",m_fTimeBetweenPresetsRand,pIni);
  1087. m_fHardCutLoudnessThresh = GetPrivateProfileFloatW(L"settings",L"fHardCutLoudnessThresh" ,m_fHardCutLoudnessThresh ,pIni);
  1088. m_fHardCutHalflife = GetPrivateProfileFloatW(L"settings",L"fHardCutHalflife" ,m_fHardCutHalflife ,pIni);
  1089. m_fSongTitleAnimDuration = GetPrivateProfileFloatW(L"settings",L"fSongTitleAnimDuration" ,m_fSongTitleAnimDuration ,pIni);
  1090. m_fTimeBetweenRandomSongTitles = GetPrivateProfileFloatW(L"settings",L"fTimeBetweenRandomSongTitles" ,m_fTimeBetweenRandomSongTitles,pIni);
  1091. m_fTimeBetweenRandomCustomMsgs = GetPrivateProfileFloatW(L"settings",L"fTimeBetweenRandomCustomMsgs" ,m_fTimeBetweenRandomCustomMsgs,pIni);
  1092. // --------
  1093. GetPrivateProfileStringW(L"settings",L"szPresetDir",m_szPresetDir,m_szPresetDir,sizeof(m_szPresetDir),pIni);
  1094. ReadCustomMessages();
  1095. // bounds-checking:
  1096. if (m_nGridX > MAX_GRID_X)
  1097. m_nGridX = MAX_GRID_X;
  1098. if (m_nGridY > MAX_GRID_Y)
  1099. m_nGridY = MAX_GRID_Y;
  1100. if (m_fTimeBetweenPresetsRand < 0)
  1101. m_fTimeBetweenPresetsRand = 0;
  1102. if (m_fTimeBetweenPresets < 0.1f)
  1103. m_fTimeBetweenPresets = 0.1f;
  1104. // DERIVED SETTINGS
  1105. m_bPresetLockedByUser = m_bPresetLockOnAtStartup;
  1106. //m_bMilkdropScrollLockState = m_bPresetLockOnAtStartup;
  1107. }
  1108. //----------------------------------------------------------------------
  1109. void CPlugin::MyWriteConfig()
  1110. {
  1111. // Write the user's settings to the .INI file.
  1112. // This gets called only when the user runs the config panel and hits OK.
  1113. // If you've added any controls to the config panel, write their value out
  1114. // to the .INI file here.
  1115. // use this function declared in to write a value of this type:
  1116. // ----------------- ----------- ----------------------------
  1117. // WritePrivateProfileInt Win32 API int
  1118. // WritePrivateProfileInt utility.h bool
  1119. // WritePrivateProfileInt utility.h BOOL
  1120. // WritePrivateProfileFloat utility.h float
  1121. // WritePrivateProfileString Win32 API string
  1122. // ex: WritePrivateProfileInt(m_fog_enabled ,"fog_enabled" ,GetConfigIniFile(),"settings");
  1123. wchar_t *pIni = GetConfigIniFile();
  1124. // constants:
  1125. WritePrivateProfileStringW(L"settings",L"bConfigured",L"1",pIni);
  1126. //note: m_szPresetDir is not written here; it is written manually, whenever it changes.
  1127. wchar_t szSectionName[] = L"settings";
  1128. WritePrivateProfileIntW(m_bSongTitleAnims, L"bSongTitleAnims", pIni, L"settings");
  1129. WritePrivateProfileIntW(m_bHardCutsDisabled, L"bHardCutsDisabled", pIni, L"settings");
  1130. WritePrivateProfileIntW(m_bEnableRating, L"bEnableRating", pIni, L"settings");
  1131. //WritePrivateProfileIntW(m_bInstaScan, "bInstaScan", pIni, "settings");
  1132. WritePrivateProfileIntW(g_bDebugOutput, L"bDebugOutput", pIni, L"settings");
  1133. //itePrivateProfileInt(m_bShowPresetInfo, "bShowPresetInfo", pIni, "settings");
  1134. //itePrivateProfileInt(m_bShowSongInfo, "bShowSongInfo", pIni, "settings");
  1135. //itePrivateProfileInt(m_bFixPinkBug, "bFixPinkBug", pIni, "settings");
  1136. WritePrivateProfileIntW(m_bShowPressF1ForHelp, L"bShowPressF1ForHelp", pIni, L"settings");
  1137. //itePrivateProfileInt(m_bShowMenuToolTips, "bShowMenuToolTips", pIni, "settings");
  1138. WritePrivateProfileIntW(m_n16BitGamma, L"n16BitGamma", pIni, L"settings");
  1139. WritePrivateProfileIntW(m_bAutoGamma, L"bAutoGamma", pIni, L"settings");
  1140. //WritePrivateProfileIntW(m_bAlways3D, "bAlways3D", pIni, "settings");
  1141. //WritePrivateProfileFloat(m_fStereoSep, "fStereoSep", pIni, "settings");
  1142. //WritePrivateProfileIntW(m_bFixSlowText, "bFixSlowText", pIni, "settings");
  1143. //itePrivateProfileInt(m_bAlwaysOnTop, "bAlwaysOnTop", pIni, "settings");
  1144. //WritePrivateProfileIntW(m_bWarningsDisabled, "bWarningsDisabled", pIni, "settings");
  1145. WritePrivateProfileIntW(m_bWarningsDisabled2, L"bWarningsDisabled2", pIni, L"settings");
  1146. //WritePrivateProfileIntW(m_bAnisotropicFiltering, "bAnisotropicFiltering",pIni, "settings");
  1147. WritePrivateProfileIntW(m_bPresetLockOnAtStartup,L"bPresetLockOnAtStartup",pIni,L"settings");
  1148. WritePrivateProfileIntW(m_bPreventScollLockHandling,L"m_bPreventScollLockHandling",pIni,L"settings");
  1149. // note: this is also written @ exit of the visualizer
  1150. WritePrivateProfileIntW(m_nCanvasStretch, L"nCanvasStretch", pIni, L"settings");
  1151. WritePrivateProfileIntW(m_nTexSizeX, L"nTexSize", pIni, L"settings");
  1152. WritePrivateProfileIntW(m_nTexBitsPerCh, L"nTexBitsPerCh", pIni, L"settings");
  1153. WritePrivateProfileIntW(m_nGridX, L"nMeshSize", pIni, L"settings");
  1154. WritePrivateProfileIntW(m_nMaxPSVersion_ConfigPanel, L"MaxPSVersion", pIni, L"settings");
  1155. WritePrivateProfileIntW(m_nMaxImages, L"MaxImages", pIni, L"settings");
  1156. WritePrivateProfileIntW(m_nMaxBytes , L"MaxBytes", pIni, L"settings");
  1157. WritePrivateProfileFloatW(m_fBlendTimeAuto, L"fBlendTimeAuto", pIni, L"settings");
  1158. WritePrivateProfileFloatW(m_fBlendTimeUser, L"fBlendTimeUser", pIni, L"settings");
  1159. WritePrivateProfileFloatW(m_fTimeBetweenPresets, L"fTimeBetweenPresets", pIni, L"settings");
  1160. WritePrivateProfileFloatW(m_fTimeBetweenPresetsRand, L"fTimeBetweenPresetsRand", pIni, L"settings");
  1161. WritePrivateProfileFloatW(m_fHardCutLoudnessThresh, L"fHardCutLoudnessThresh", pIni, L"settings");
  1162. WritePrivateProfileFloatW(m_fHardCutHalflife, L"fHardCutHalflife", pIni, L"settings");
  1163. WritePrivateProfileFloatW(m_fSongTitleAnimDuration, L"fSongTitleAnimDuration", pIni, L"settings");
  1164. WritePrivateProfileFloatW(m_fTimeBetweenRandomSongTitles,L"fTimeBetweenRandomSongTitles",pIni, L"settings");
  1165. WritePrivateProfileFloatW(m_fTimeBetweenRandomCustomMsgs,L"fTimeBetweenRandomCustomMsgs",pIni, L"settings");
  1166. }
  1167. //----------------------------------------------------------------------
  1168. void ConvertLLCto1310(char* d, const char *s)
  1169. {
  1170. // src and dest can NOT be the same pointer.
  1171. assert(s != d);
  1172. while (*s)
  1173. {
  1174. if (*s == LINEFEED_CONTROL_CHAR)
  1175. {
  1176. *d++ = 13;
  1177. *d++ = 10;
  1178. }
  1179. else
  1180. {
  1181. *d++ = *s;
  1182. }
  1183. s++;
  1184. };
  1185. *d = 0;
  1186. }
  1187. void StripComments(char* str)
  1188. {
  1189. if (!str || !str[0] || !str[1])
  1190. return;
  1191. char c0 = str[0];
  1192. char c1 = str[1];
  1193. char* dest = str;
  1194. char* p = &str[1];
  1195. bool bIgnoreTilEndOfLine = false;
  1196. bool bIgnoreTilCloseComment = false; //this one takes precedence
  1197. int nCharsToSkip = 0;
  1198. while (1)
  1199. {
  1200. // handle '//' comments
  1201. if (!bIgnoreTilCloseComment && c0=='/' && c1=='/')
  1202. bIgnoreTilEndOfLine = true;
  1203. if (bIgnoreTilEndOfLine && (c0==10 || c0==13))
  1204. {
  1205. bIgnoreTilEndOfLine = false;
  1206. nCharsToSkip = 0;
  1207. }
  1208. // handle /* */ comments
  1209. if (!bIgnoreTilEndOfLine && c0=='/' && c1=='*')
  1210. bIgnoreTilCloseComment = true;
  1211. if (bIgnoreTilCloseComment && c0=='*' && c1=='/')
  1212. {
  1213. bIgnoreTilCloseComment = false;
  1214. nCharsToSkip = 2;
  1215. }
  1216. if (!bIgnoreTilEndOfLine && !bIgnoreTilCloseComment)
  1217. {
  1218. if (nCharsToSkip > 0)
  1219. nCharsToSkip--;
  1220. else
  1221. *dest++ = c0;
  1222. }
  1223. if (c1==0)
  1224. break;
  1225. p++;
  1226. c0 = c1;
  1227. c1 = *p;
  1228. }
  1229. *dest++ = 0;
  1230. }
  1231. int CPlugin::AllocateMyNonDx9Stuff()
  1232. {
  1233. // This gets called only once, when your plugin is actually launched.
  1234. // If only the config panel is launched, this does NOT get called.
  1235. // (whereas MyPreInitialize() still does).
  1236. // If anything fails here, return FALSE to safely exit the plugin,
  1237. // but only after displaying a messagebox giving the user some information
  1238. // about what went wrong.
  1239. /*
  1240. if (!m_hBlackBrush)
  1241. m_hBlackBrush = CreateSolidBrush(RGB(0,0,0));
  1242. */
  1243. g_hThread = INVALID_HANDLE_VALUE;
  1244. g_bThreadAlive = false;
  1245. g_bThreadShouldQuit = false;
  1246. InitializeCriticalSection(&g_cs);
  1247. // read in 'm_szShaderIncludeText'
  1248. bool bSuccess = true;
  1249. bSuccess = ReadFileToString(L"data\\include.fx", m_szShaderIncludeText, sizeof(m_szShaderIncludeText)-4, false);
  1250. if (!bSuccess) return false;
  1251. StripComments(m_szShaderIncludeText);
  1252. m_nShaderIncludeTextLen = lstrlen(m_szShaderIncludeText);
  1253. bSuccess |= ReadFileToString(L"data\\warp_vs.fx", m_szDefaultWarpVShaderText, sizeof(m_szDefaultWarpVShaderText), true);
  1254. if (!bSuccess) return false;
  1255. bSuccess |= ReadFileToString(L"data\\warp_ps.fx", m_szDefaultWarpPShaderText, sizeof(m_szDefaultWarpPShaderText), true);
  1256. if (!bSuccess) return false;
  1257. bSuccess |= ReadFileToString(L"data\\comp_vs.fx", m_szDefaultCompVShaderText, sizeof(m_szDefaultCompVShaderText), true);
  1258. if (!bSuccess) return false;
  1259. bSuccess |= ReadFileToString(L"data\\comp_ps.fx", m_szDefaultCompPShaderText, sizeof(m_szDefaultCompPShaderText), true);
  1260. if (!bSuccess) return false;
  1261. bSuccess |= ReadFileToString(L"data\\blur_vs.fx", m_szBlurVS, sizeof(m_szBlurVS), true);
  1262. if (!bSuccess) return false;
  1263. bSuccess |= ReadFileToString(L"data\\blur1_ps.fx", m_szBlurPSX, sizeof(m_szBlurPSX), true);
  1264. if (!bSuccess) return false;
  1265. bSuccess |= ReadFileToString(L"data\\blur2_ps.fx", m_szBlurPSY, sizeof(m_szBlurPSY), true);
  1266. if (!bSuccess) return false;
  1267. BuildMenus();
  1268. m_bMMX = CheckForMMX();
  1269. //m_bSSE = CheckForSSE();
  1270. m_pState->Default();
  1271. m_pOldState->Default();
  1272. m_pNewState->Default();
  1273. //LoadRandomPreset(0.0f); -avoid this here; causes some DX9 stuff to happen.
  1274. return true;
  1275. }
  1276. //----------------------------------------------------------------------
  1277. void CancelThread(int max_wait_time_ms)
  1278. {
  1279. g_bThreadShouldQuit = true;
  1280. int waited = 0;
  1281. while (g_bThreadAlive && waited < max_wait_time_ms)
  1282. {
  1283. Sleep(30);
  1284. waited += 30;
  1285. }
  1286. if (g_bThreadAlive)
  1287. {
  1288. TerminateThread(g_hThread,0);
  1289. g_bThreadAlive = false;
  1290. }
  1291. if (g_hThread != INVALID_HANDLE_VALUE)
  1292. CloseHandle(g_hThread);
  1293. g_hThread = INVALID_HANDLE_VALUE;
  1294. }
  1295. void CPlugin::CleanUpMyNonDx9Stuff()
  1296. {
  1297. // This gets called only once, when your plugin exits.
  1298. // Be sure to clean up any objects here that were
  1299. // created/initialized in AllocateMyNonDx9Stuff.
  1300. //sound.Finish();
  1301. // NOTE: DO NOT DELETE m_gdi_titlefont_doublesize HERE!!!
  1302. DeleteCriticalSection(&g_cs);
  1303. CancelThread(0);
  1304. m_menuPreset .Finish();
  1305. m_menuWave .Finish();
  1306. m_menuAugment .Finish();
  1307. m_menuCustomWave.Finish();
  1308. m_menuCustomShape.Finish();
  1309. m_menuMotion .Finish();
  1310. m_menuPost .Finish();
  1311. int i = 0;
  1312. for (i=0; i<MAX_CUSTOM_WAVES; i++)
  1313. m_menuWavecode[i].Finish();
  1314. for (i=0; i<MAX_CUSTOM_SHAPES; i++)
  1315. m_menuShapecode[i].Finish();
  1316. SetScrollLock(m_bOrigScrollLockState, m_bPreventScollLockHandling);
  1317. //dumpmsg("Finish: cleanup complete.");
  1318. }
  1319. //----------------------------------------------------------------------
  1320. float SquishToCenter(float x, float fExp)
  1321. {
  1322. if (x > 0.5f)
  1323. return powf(x*2-1, fExp)*0.5f + 0.5f;
  1324. return (1-powf(1-x*2, fExp))*0.5f;
  1325. }
  1326. int GetNearestPow2Size(int w, int h)
  1327. {
  1328. float fExp = logf( max(w,h)*0.75f + 0.25f*min(w,h) ) / logf(2.0f);
  1329. float bias = 0.55f;
  1330. if (fExp + bias >= 11.0f) // ..don't jump to 2048x2048 quite as readily
  1331. bias = 0.5f;
  1332. int nExp = (int)(fExp + bias);
  1333. int log2size = (int)powf(2.0f, (float)nExp);
  1334. return log2size;
  1335. }
  1336. int CPlugin::AllocateMyDX9Stuff()
  1337. {
  1338. // (...aka OnUserResizeWindow)
  1339. // (...aka OnToggleFullscreen)
  1340. // Allocate and initialize all your DX9 and D3DX stuff here: textures,
  1341. // surfaces, vertex/index buffers, D3DX fonts, and so on.
  1342. // If anything fails here, return FALSE to safely exit the plugin,
  1343. // but only after displaying a messagebox giving the user some information
  1344. // about what went wrong. If the error is NON-CRITICAL, you don't *have*
  1345. // to return; just make sure that the rest of the code will be still safely
  1346. // run (albeit with degraded features).
  1347. // If you run out of video memory, you might want to show a short messagebox
  1348. // saying what failed to allocate and that the reason is a lack of video
  1349. // memory, and then call SuggestHowToFreeSomeMem(), which will show them
  1350. // a *second* messagebox that (intelligently) suggests how they can free up
  1351. // some video memory.
  1352. // Don't forget to account for each object you create/allocate here by cleaning
  1353. // it up in CleanUpMyDX9Stuff!
  1354. // IMPORTANT:
  1355. // Note that the code here isn't just run at program startup!
  1356. // When the user toggles between fullscreen and windowed modes
  1357. // or resizes the window, the base class calls this function before
  1358. // destroying & recreating the plugin window and DirectX object, and then
  1359. // calls AllocateMyDX9Stuff afterwards, to get your plugin running again.
  1360. wchar_t buf[32768], title[64];
  1361. m_nFramesSinceResize = 0;
  1362. int nNewCanvasStretch = (m_nCanvasStretch == 0) ? 100 : m_nCanvasStretch;
  1363. DWORD PSVersion = GetCaps()->PixelShaderVersion & 0xFFFF; // 0x0300, etc.
  1364. if (PSVersion >= 0x0300)
  1365. m_nMaxPSVersion_DX9 = MD2_PS_3_0;
  1366. else if (PSVersion > 0x0200)
  1367. m_nMaxPSVersion_DX9 = MD2_PS_2_X;
  1368. else if (PSVersion >= 0x0200)
  1369. m_nMaxPSVersion_DX9 = MD2_PS_2_0;
  1370. else
  1371. m_nMaxPSVersion_DX9 = MD2_PS_NONE;
  1372. if (m_nMaxPSVersion_ConfigPanel == -1)
  1373. m_nMaxPSVersion = m_nMaxPSVersion_DX9;
  1374. else
  1375. {
  1376. // to still limit their choice by what HW reports:
  1377. //m_nMaxPSVersion = min(m_nMaxPSVersion_DX9, m_nMaxPSVersion_ConfigPanel);
  1378. // to allow them to override:
  1379. m_nMaxPSVersion = m_nMaxPSVersion_ConfigPanel;
  1380. }
  1381. /*
  1382. Auto mode: do a check against a few known, *SLOW* DX9/ps_2_0 cards to see
  1383. if we should run them without pixel shaders instead.
  1384. Here is valve's list of the cards they run DX8 on (mostly because they're too slow under DX9 + ps_2_0):
  1385. NVIDIA GeForce FX 5200� 31.12%
  1386. ATI Radeon 9200�������� 21.29%
  1387. NVIDIA GeForce FX 5500� 11.27%
  1388. NVIDIA GeForce4��������� 7.74%
  1389. NVIDIA GeForce FX 5700�� 7.12%
  1390. NVIDIA GeForce FX 5600�� 5.16%
  1391. SiS 661FX_760_741������� 3.34%
  1392. NVIDIA GeForce FX 5900�� 3.24%
  1393. NVIDIA GeForce3��������� 2.09%
  1394. ATI Radeon 9000��������� 1.98%
  1395. other������������������� 5.66%
  1396. [ from http://www.steampowered.com/status/survey.html ]
  1397. see also:
  1398. http://en.wikipedia.org/wiki/Radeon
  1399. http://en.wikipedia.org/wiki/Geforce_fx
  1400. */
  1401. const char* szGPU = GetDriverDescription();
  1402. /* known examples of this string:
  1403. "ATI MOBILITY RADEON X600"
  1404. "RADEON X800 Series " <- note the spaces at the end
  1405. "Sapphire RADEON X700"
  1406. "NVIDIA GeForce Go 6200 " <- note the spaces at the end
  1407. "NVIDIA GeForce 6800 GT"
  1408. "Intel(R) 82865G Graphics Controller"
  1409. "Mobile Intel(R) 915GM/GMS,910GML Express Chipset Family"
  1410. might want to consider adding these to the list: [from http://www.intel.com/support/graphics/sb/cs-014257.htm ]
  1411. (...they should support PS2.0, but not sure if they're fast...)
  1412. "Mobile Intel(R) 945GM Express Chipset Family"
  1413. "Mobile Intel(R) 915GM/GMS,910GML Express Chipset"
  1414. "Intel(R) 945G Express Chipset"
  1415. "Intel(R) 82915G/82910GL Express Chipset Family"
  1416. or these, if they seem to be reporting that they do support ps_2_0, which would be very bogus info:
  1417. "Intel(R) 82865G Graphics Controller"
  1418. "Intel(R) 82852/82855 Graphics Controller Family"
  1419. "Intel(R) 82845G Graphics Controller"
  1420. "Intel(R) 82830M Graphics Controller"
  1421. "Intel(R) 82815 Graphics Controller"
  1422. "Intel(R) 82810 Graphics Controller"
  1423. */
  1424. // GREY LIST - slow ps_2_0 cards
  1425. // In Canvas Stretch==Auto mode, for these cards, if they (claim to) run ps_2_0,
  1426. // we run at half-res (cuz they're slow).
  1427. // THE GENERAL GUIDELINE HERE:
  1428. // It should be at least as fast as a GeForce FX 5700 or my GeForce 6200 (TC)
  1429. // if it's to run without stretch.
  1430. if (m_nCanvasStretch==0)// && m_nMaxPSVersion_DX9 > 0)
  1431. {
  1432. // put cards on this list if you see them successfully run ps_2_0 (using override)
  1433. // and they run well at a low resolution (512x512 or less).
  1434. if (
  1435. strstr(szGPU, "GeForce 4" ) || // probably not even ps_2_0
  1436. strstr(szGPU, "GeForce FX 52" ) || // chip's computer (FX 5200) - does do ps_2_0, but slow
  1437. strstr(szGPU, "GeForce FX 53" ) ||
  1438. strstr(szGPU, "GeForce FX 54" ) ||
  1439. strstr(szGPU, "GeForce FX 55" ) || //GeForce FX 5600 is 13 GB/s - 2.5x as fast as my 6200!
  1440. strstr(szGPU, "GeForce FX 56" ) ||
  1441. //...GeForce FX 5700 and up, we let those run at full-res on ps_2_0...
  1442. strstr(szGPU, "GeForce FX 56" ) ||
  1443. strstr(szGPU, "GeForce FX 56" ) ||
  1444. strstr(szGPU, "SiS 300/305/630/540/730") || // mom's computer - just slow.
  1445. strstr(szGPU, "Radeon 8" ) || // no shader model 2.
  1446. strstr(szGPU, "Radeon 90" ) || // from Valve. no shader model 2.
  1447. strstr(szGPU, "Radeon 91" ) || // no shader model 2.
  1448. strstr(szGPU, "Radeon 92" ) || // from Valve. no shader model 2.
  1449. strstr(szGPU, "Radeon 93" ) || // no shader model 2.
  1450. strstr(szGPU, "Radeon 94" ) || // no shader model 2.
  1451. // guessing that 9500+ are ok - they're all ps_2_0 and the 9600 is like an FX 5900.
  1452. strstr(szGPU, "Radeon 9550") || // *maybe* - kiv - super budget R200 chip. def. ps_2_0 but possibly very slow.
  1453. strstr(szGPU, "Radeon X300") || // *maybe* - kiv - super budget R200 chip def. ps_2_0 but possibly very slow.
  1454. 0)
  1455. {
  1456. nNewCanvasStretch = 200;
  1457. }
  1458. }
  1459. /* pix pipes
  1460. core Fill(G) membw(GB/s)
  1461. Radeon 9600 Pro 400 4 1.6 9.6
  1462. Radeon 9600 XT 500 4 2.0 9.6
  1463. GeForce FX 5600 Ultra 400 4 1.6 12.8
  1464. GeForce FX 5700 Ultra 475 4 1.9 14.4
  1465. GeForce FX 5900 XT 400 4 1.6 22.4
  1466. GeForce FX 5900 450 4 1.8 27.2
  1467. GeForce FX 5950 Ultra 475 4 2.9 30
  1468. GeForce 6200 TC-32 350 4 1.1 5.6 (TurboDonkey)
  1469. GeForce 6600 GT 500 8 2.0 16
  1470. GeForce 6800 Ultra 400 16 6.4 35
  1471. ATI Radeon X800 XT PE 520 16 8.3 36
  1472. ATI Radeon X850 XT PE 540 16 8.6 38
  1473. Entry-level GPU 5200, 5300, 5500
  1474. Mid-Range GPU 5600, 5700
  1475. High-end GPU 5800, 5900, 5950
  1476. Entry-level GPU 6200, 6500
  1477. Mid-Range GPU 6600
  1478. High-end GPU 6800
  1479. Entry-level GPU
  1480. Mid-Range GPU
  1481. High-end GPU
  1482. R200: only ps_1_4. Radeon 8500-9250.
  1483. R300: ps_2_0. Radeon 9500-9800, X300-X600, X1050. 9600 fast enough (~FX5900). 9500/9700 ~ GeForce 4 Ti.
  1484. R420: ps_2_0 Radeon X700-8750 - ALL FAST ENOUGH. X700 is same speed as a GeForce 6600.
  1485. 6600 ~ X700
  1486. GeForce 4 < X300 / X600 / 9600
  1487. GeForce 4 Ti > Radeon 8500
  1488. FX 5900 = Radeon 9600
  1489. FX 5900 Ultra << [half] Radeon 9800 Pro
  1490. GeForce FX < Radeon 9700/9800
  1491. */
  1492. // BLACK LIST
  1493. // In Pixel Shaders==Auto mode, for these cards, we avoid ps_2_0 completely.
  1494. // There shouldn't be much on this list... feel free to put anything you KNOW doesn't do ps_2_0 (why not),
  1495. // and to put anything that is slow to begin with, and HAS BUGGY DRIVERS (INTEL).
  1496. if (m_nMaxPSVersion_ConfigPanel==-1)
  1497. {
  1498. if (strstr(szGPU, "GeForce2" ) || // from Valve
  1499. strstr(szGPU, "GeForce3" ) || // from Valve
  1500. strstr(szGPU, "GeForce4" ) || // from Valve
  1501. strstr(szGPU, "Radeon 7" ) || // from Valve
  1502. strstr(szGPU, "Radeon 8" ) ||
  1503. strstr(szGPU, "SiS 661FX_760_741") || // from Valve
  1504. //FOR NOW, FOR THESE, ASSUME INTEL EITHER DOESN'T DO PS_2_0,
  1505. //OR DRIVERS SUCK AND IT WOULDN'T WORK ANYWAY!
  1506. (strstr(szGPU,"Intel") && strstr(szGPU,"945G")) ||
  1507. (strstr(szGPU,"Intel") && strstr(szGPU,"915G")) || // ben allison's laptop - snow, freezing when you try ps_2_0
  1508. (strstr(szGPU,"Intel") && strstr(szGPU,"910G")) ||
  1509. (strstr(szGPU,"Intel") && strstr(szGPU,"8291")) || // gonna guess that this supports ps_2_0 but is SLOW
  1510. (strstr(szGPU,"Intel") && strstr(szGPU,"8281")) || // definitely DOESN'T support pixel shaders
  1511. (strstr(szGPU,"Intel") && strstr(szGPU,"8283")) || // definitely DOESN'T support pixel shaders
  1512. (strstr(szGPU,"Intel") && strstr(szGPU,"8284")) || // definitely DOESN'T support pixel shaders
  1513. (strstr(szGPU,"Intel") && strstr(szGPU,"8285")) || // definitely DOESN'T support pixel shaders
  1514. (strstr(szGPU,"Intel") && strstr(szGPU,"8286")) || // definitely DOESN'T support pixel shaders. Ben Allison's desktop (865) - no image w/ps_2_0. Plus Nes's desktop - no ps_2_0.
  1515. 0)
  1516. {
  1517. m_nMaxPSVersion = MD2_PS_NONE;
  1518. //if (m_nCanvasStretch==0)
  1519. // nNewCanvasStretch = 100;
  1520. }
  1521. }
  1522. /*char fname[512];
  1523. sprintf(fname, "%s%s", GetPluginsDirPath(), TEXTURE_NAME);
  1524. if (D3DXCreateTextureFromFile(GetDevice(), fname, &m_object_tex) != S_OK)
  1525. {
  1526. // just give a warning, and move on
  1527. m_object_tex = NULL; // (make sure pointer wasn't mangled by some bad driver)
  1528. char msg[1024];
  1529. sprintf(msg, "Unable to load texture:\r%s", fname);
  1530. MessageBox(GetPluginWindow(), msg, "WARNING", MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  1531. //return false;
  1532. }*/
  1533. // Note: this code used to be in OnResizeGraphicsWindow().
  1534. // SHADERS
  1535. //-------------------------------------
  1536. if (m_nMaxPSVersion > MD2_PS_NONE)
  1537. {
  1538. // Create vertex declarations (since we're not using FVF anymore)
  1539. if (D3D_OK != GetDevice()->CreateVertexDeclaration( g_MyVertDecl, &m_pMyVertDecl ))
  1540. {
  1541. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_CREATE_MY_VERTEX_DECLARATION,buf,sizeof(buf));
  1542. dumpmsg(buf);
  1543. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,sizeof(title)), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  1544. return false;
  1545. }
  1546. if (D3D_OK != GetDevice()->CreateVertexDeclaration( g_WfVertDecl, &m_pWfVertDecl ))
  1547. {
  1548. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_CREATE_WF_VERTEX_DECLARATION,buf,sizeof(buf));
  1549. dumpmsg(buf);
  1550. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,sizeof(title)), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  1551. return false;
  1552. }
  1553. if (D3D_OK != GetDevice()->CreateVertexDeclaration( g_SpriteVertDecl, &m_pSpriteVertDecl ))
  1554. {
  1555. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_CREATE_SPRITE_VERTEX_DECLARATION,buf,sizeof(buf));
  1556. dumpmsg(buf);
  1557. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,sizeof(title)), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  1558. return false;
  1559. }
  1560. // Load the FALLBACK shaders...
  1561. if (!RecompilePShader(m_szDefaultWarpPShaderText, &m_fallbackShaders_ps.warp, SHADER_WARP, true, 2))
  1562. {
  1563. wchar_t szSM[64];
  1564. switch(m_nMaxPSVersion_DX9)
  1565. {
  1566. case MD2_PS_2_0:
  1567. case MD2_PS_2_X:
  1568. WASABI_API_LNGSTRINGW_BUF(IDS_SHADER_MODEL_2,szSM,64); break;
  1569. case MD2_PS_3_0: WASABI_API_LNGSTRINGW_BUF(IDS_SHADER_MODEL_3,szSM,64); break;
  1570. case MD2_PS_4_0: WASABI_API_LNGSTRINGW_BUF(IDS_SHADER_MODEL_4,szSM,64); break;
  1571. default:
  1572. swprintf(szSM, WASABI_API_LNGSTRINGW(IDS_UKNOWN_CASE_X), m_nMaxPSVersion_DX9);
  1573. break;
  1574. }
  1575. if (m_nMaxPSVersion_ConfigPanel >= MD2_PS_NONE && m_nMaxPSVersion_DX9 < m_nMaxPSVersion_ConfigPanel)
  1576. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_FAILED_TO_COMPILE_PIXEL_SHADERS_USING_X),szSM,PSVersion);
  1577. else
  1578. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_FAILED_TO_COMPILE_PIXEL_SHADERS_HARDWARE_MIS_REPORT),szSM,PSVersion);
  1579. dumpmsg(buf);
  1580. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  1581. return false;
  1582. }
  1583. if (!RecompileVShader(m_szDefaultWarpVShaderText, &m_fallbackShaders_vs.warp, SHADER_WARP, true))
  1584. {
  1585. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_FALLBACK_WV_SHADER,buf,sizeof(buf));
  1586. dumpmsg(buf);
  1587. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  1588. return false;
  1589. }
  1590. if (!RecompileVShader(m_szDefaultCompVShaderText, &m_fallbackShaders_vs.comp, SHADER_COMP, true))
  1591. {
  1592. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_FALLBACK_CV_SHADER,buf,sizeof(buf));
  1593. dumpmsg(buf);
  1594. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  1595. return false;
  1596. }
  1597. if (!RecompilePShader(m_szDefaultCompPShaderText, &m_fallbackShaders_ps.comp, SHADER_COMP, true, 2))
  1598. {
  1599. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_FALLBACK_CP_SHADER,buf,sizeof(buf));
  1600. dumpmsg(buf);
  1601. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  1602. return false;
  1603. }
  1604. // Load the BLUR shaders...
  1605. if (!RecompileVShader(m_szBlurVS, &m_BlurShaders[0].vs, SHADER_BLUR, true))
  1606. {
  1607. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_BLUR1_VERTEX_SHADER,buf,sizeof(buf));
  1608. dumpmsg(buf);
  1609. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  1610. return false;
  1611. }
  1612. if (!RecompilePShader(m_szBlurPSX, &m_BlurShaders[0].ps, SHADER_BLUR, true, 2))
  1613. {
  1614. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_BLUR1_PIXEL_SHADER,buf,sizeof(buf));
  1615. dumpmsg(buf);
  1616. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  1617. return false;
  1618. }
  1619. if (!RecompileVShader(m_szBlurVS, &m_BlurShaders[1].vs, SHADER_BLUR, true))
  1620. {
  1621. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_BLUR2_VERTEX_SHADER,buf,sizeof(buf));
  1622. dumpmsg(buf);
  1623. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  1624. return false;
  1625. }
  1626. if (!RecompilePShader(m_szBlurPSY, &m_BlurShaders[1].ps, SHADER_BLUR, true, 2))
  1627. {
  1628. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_COMPILE_BLUR2_PIXEL_SHADER,buf,sizeof(buf));
  1629. dumpmsg(buf);
  1630. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  1631. return false;
  1632. }
  1633. }
  1634. // create m_lpVS[2]
  1635. {
  1636. int log2texsize = GetNearestPow2Size(GetWidth(), GetHeight());
  1637. // auto-guess texsize
  1638. if (m_bTexSizeWasAutoExact)
  1639. {
  1640. // note: in windowed mode, the winamp window could be weird sizes,
  1641. // so the plugin shell now gives us a slightly enlarged size,
  1642. // which pads it out to the nearest 32x32 block size,
  1643. // and then on display, it intelligently crops the image.
  1644. // This is pretty likely to work on non-shitty GPUs.
  1645. // but some shitty ones will still only do powers of 2!
  1646. // So if we are running out of video memory here or experience
  1647. // other problems, though, we can make our VS's smaller;
  1648. // which will work, although it will lead to stretching.
  1649. m_nTexSizeX = GetWidth();
  1650. m_nTexSizeY = GetHeight();
  1651. }
  1652. else if (m_bTexSizeWasAutoPow2)
  1653. {
  1654. m_nTexSizeX = log2texsize;
  1655. m_nTexSizeY = log2texsize;
  1656. }
  1657. // clip texsize by max. from caps
  1658. if ((DWORD)m_nTexSizeX > GetCaps()->MaxTextureWidth && GetCaps()->MaxTextureWidth>0)
  1659. m_nTexSizeX = GetCaps()->MaxTextureWidth;
  1660. if ((DWORD)m_nTexSizeY > GetCaps()->MaxTextureHeight && GetCaps()->MaxTextureHeight>0)
  1661. m_nTexSizeY = GetCaps()->MaxTextureHeight;
  1662. // apply canvas stretch
  1663. m_nTexSizeX = (m_nTexSizeX * 100)/nNewCanvasStretch;
  1664. m_nTexSizeY = (m_nTexSizeY * 100)/nNewCanvasStretch;
  1665. // re-compute closest power-of-2 size, now that we've factored in the stretching...
  1666. log2texsize = GetNearestPow2Size(m_nTexSizeX, m_nTexSizeY);
  1667. if (m_bTexSizeWasAutoPow2)
  1668. {
  1669. m_nTexSizeX = log2texsize;
  1670. m_nTexSizeY = log2texsize;
  1671. }
  1672. // snap to 16x16 blocks
  1673. m_nTexSizeX = ((m_nTexSizeX+15)/16)*16;
  1674. m_nTexSizeY = ((m_nTexSizeY+15)/16)*16;
  1675. // determine format for VS1/VS2
  1676. D3DFORMAT fmt;
  1677. switch(m_nTexBitsPerCh) {
  1678. case 5: fmt = D3DFMT_R5G6B5 ; break;
  1679. case 8: fmt = D3DFMT_X8R8G8B8 ; break;
  1680. case 10: fmt = D3DFMT_A2R10G10B10; break; // D3DFMT_A2W10V10U10 or D3DFMT_A2R10G10B10 or D3DFMT_A2B10G10R10
  1681. case 16: fmt = D3DFMT_A16B16G16R16F; break;
  1682. case 32: fmt = D3DFMT_A32B32G32R32F; break; //FIXME
  1683. default: fmt = D3DFMT_X8R8G8B8 ; break;
  1684. }
  1685. // reallocate
  1686. bool bSuccess = false;
  1687. DWORD vs_flags = D3DUSAGE_RENDERTARGET;// | D3DUSAGE_AUTOGENMIPMAP;//FIXME! (make automipgen optional)
  1688. bool bRevertedBitDepth = false;
  1689. do
  1690. {
  1691. SafeRelease(m_lpVS[0]);
  1692. SafeRelease(m_lpVS[1]);
  1693. // create VS1
  1694. bSuccess = (GetDevice()->CreateTexture(m_nTexSizeX, m_nTexSizeY, 1, vs_flags, fmt, D3DPOOL_DEFAULT, &m_lpVS[0], NULL) == D3D_OK);
  1695. if (!bSuccess)
  1696. {
  1697. bSuccess = (GetDevice()->CreateTexture(m_nTexSizeX, m_nTexSizeY, 1, vs_flags, GetBackBufFormat(), D3DPOOL_DEFAULT, &m_lpVS[0], NULL) == D3D_OK);
  1698. if (bSuccess)
  1699. fmt = GetBackBufFormat();
  1700. }
  1701. // create VS2
  1702. if (bSuccess)
  1703. bSuccess = (GetDevice()->CreateTexture(m_nTexSizeX, m_nTexSizeY, 1, vs_flags, fmt, D3DPOOL_DEFAULT, &m_lpVS[1], NULL) == D3D_OK);
  1704. if (!bSuccess)
  1705. {
  1706. if (m_bTexSizeWasAutoExact)
  1707. {
  1708. if (m_nTexSizeX > 256 || m_nTexSizeY > 256)
  1709. {
  1710. m_nTexSizeX /= 2;
  1711. m_nTexSizeY /= 2;
  1712. m_nTexSizeX = ((m_nTexSizeX+15)/16)*16;
  1713. m_nTexSizeY = ((m_nTexSizeY+15)/16)*16;
  1714. }
  1715. else
  1716. {
  1717. m_nTexSizeX = log2texsize;
  1718. m_nTexSizeY = log2texsize;
  1719. m_bTexSizeWasAutoExact = false;
  1720. m_bTexSizeWasAutoPow2 = true;
  1721. }
  1722. }
  1723. else if (m_bTexSizeWasAutoPow2)
  1724. {
  1725. if (m_nTexSizeX > 256)
  1726. {
  1727. m_nTexSizeX /= 2;
  1728. m_nTexSizeY /= 2;
  1729. }
  1730. else
  1731. break;
  1732. }
  1733. }
  1734. }
  1735. while (!bSuccess);// && m_nTexSizeX >= 256 && (m_bTexSizeWasAutoExact || m_bTexSizeWasAutoPow2));
  1736. if (!bSuccess)
  1737. {
  1738. wchar_t buf[2048];
  1739. UINT err_id = IDS_COULD_NOT_CREATE_INTERNAL_CANVAS_TEXTURE_NOT_ENOUGH_VID_MEM;
  1740. if (GetScreenMode() == FULLSCREEN)
  1741. err_id = IDS_COULD_NOT_CREATE_INTERNAL_CANVAS_TEXTURE_SMALLER_DISPLAY;
  1742. else if (!(m_bTexSizeWasAutoExact || m_bTexSizeWasAutoPow2))
  1743. err_id = IDS_COULD_NOT_CREATE_INTERNAL_CANVAS_TEXTURE_NOT_ENOUGH_VID_MEM_RECOMMENDATION;
  1744. WASABI_API_LNGSTRINGW_BUF(err_id,buf,sizeof(buf));
  1745. dumpmsg(buf);
  1746. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  1747. return false;
  1748. }
  1749. else
  1750. {
  1751. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SUCCESSFULLY_CREATED_VS0_VS1), m_nTexSizeX, m_nTexSizeY, GetWidth(), GetHeight());
  1752. dumpmsg(buf);
  1753. }
  1754. /*
  1755. if (m_nTexSizeX != GetWidth() || m_nTexSizeY != GetHeight())
  1756. {
  1757. char buf[2048];
  1758. sprintf(buf, "warning - canvas size adjusted from %dx%d to %dx%d.", GetWidth(), GetHeight(), m_nTexSizeX, m_nTexSizeY);
  1759. dumpmsg(buf);
  1760. AddError(buf, 3.2f, ERR_INIT, true);
  1761. }/**/
  1762. // create blur textures w/same format. A complete mip chain costs 33% more video mem then 1 full-sized VS.
  1763. #if (NUM_BLUR_TEX>0)
  1764. int w = m_nTexSizeX;
  1765. int h = m_nTexSizeY;
  1766. DWORD blurtex_flags = D3DUSAGE_RENDERTARGET;// | D3DUSAGE_AUTOGENMIPMAP;//FIXME! (make automipgen optional)
  1767. for (int i=0; i<NUM_BLUR_TEX; i++)
  1768. {
  1769. // main VS = 1024
  1770. // blur0 = 512
  1771. // blur1 = 256 <- user sees this as "blur1"
  1772. // blur2 = 128
  1773. // blur3 = 128 <- user sees this as "blur2"
  1774. // blur4 = 64
  1775. // blur5 = 64 <- user sees this as "blur3"
  1776. if (!(i&1) || (i<2))
  1777. {
  1778. w = max(16, w/2);
  1779. h = max(16, h/2);
  1780. }
  1781. int w2 = ((w+3)/16)*16;
  1782. int h2 = ((h+3)/4)*4;
  1783. bSuccess = (GetDevice()->CreateTexture(w2, h2, 1, blurtex_flags, fmt, D3DPOOL_DEFAULT, &m_lpBlur[i], NULL) == D3D_OK);
  1784. m_nBlurTexW[i] = w2;
  1785. m_nBlurTexH[i] = h2;
  1786. if (!bSuccess)
  1787. {
  1788. m_nBlurTexW[i] = 1;
  1789. m_nBlurTexH[i] = 1;
  1790. MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_CREATING_BLUR_TEXTURES,buf,sizeof(buf)),
  1791. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_WARNING,title,sizeof(title)), MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  1792. break;
  1793. }
  1794. // add it to m_textures[].
  1795. TexInfo x;
  1796. swprintf(x.texname, L"blur%d%s", i/2+1, (i%2) ? L"" : L"doNOTuseME");
  1797. x.texptr = m_lpBlur[i];
  1798. //x.texsize_param = NULL;
  1799. x.w = w2;
  1800. x.h = h2;
  1801. x.d = 1;
  1802. x.bEvictable = false;
  1803. x.nAge = m_nPresetsLoadedTotal;
  1804. x.nSizeInBytes = 0;
  1805. m_textures.push_back(x);
  1806. }
  1807. #endif
  1808. }
  1809. m_fAspectX = (m_nTexSizeY > m_nTexSizeX) ? m_nTexSizeX/(float)m_nTexSizeY : 1.0f;
  1810. m_fAspectY = (m_nTexSizeX > m_nTexSizeY) ? m_nTexSizeY/(float)m_nTexSizeX : 1.0f;
  1811. m_fInvAspectX = 1.0f/m_fAspectX;
  1812. m_fInvAspectY = 1.0f/m_fAspectY;
  1813. // BUILD VERTEX LIST for final composite blit
  1814. // note the +0.5-texel offset!
  1815. // (otherwise, a 1-pixel-wide line of the image would wrap at the top and left edges).
  1816. ZeroMemory(m_comp_verts, sizeof(MYVERTEX)*FCGSX*FCGSY);
  1817. //float fOnePlusInvWidth = 1.0f + 1.0f/(float)GetWidth();
  1818. //float fOnePlusInvHeight = 1.0f + 1.0f/(float)GetHeight();
  1819. float fHalfTexelW = 0.5f / (float)GetWidth(); // 2.5: 2 pixels bad @ bottom right
  1820. float fHalfTexelH = 0.5f / (float)GetHeight();
  1821. float fDivX = 1.0f / (float)(FCGSX-2);
  1822. float fDivY = 1.0f / (float)(FCGSY-2);
  1823. for (int j=0; j<FCGSY; j++)
  1824. {
  1825. int j2 = j - j/(FCGSY/2);
  1826. float v = j2*fDivY;
  1827. v = SquishToCenter(v, 3.0f);
  1828. float sy = -((v-fHalfTexelH)*2-1);//fOnePlusInvHeight*v*2-1;
  1829. for (int i=0; i<FCGSX; i++)
  1830. {
  1831. int i2 = i - i/(FCGSX/2);
  1832. float u = i2*fDivX;
  1833. u = SquishToCenter(u, 3.0f);
  1834. float sx = (u-fHalfTexelW)*2-1;//fOnePlusInvWidth*u*2-1;
  1835. MYVERTEX* p = &m_comp_verts[i + j*FCGSX];
  1836. p->x = sx;
  1837. p->y = sy;
  1838. p->z = 0;
  1839. float rad, ang;
  1840. UvToMathSpace( u, v, &rad, &ang );
  1841. // fix-ups:
  1842. if (i==FCGSX/2-1) {
  1843. if (j < FCGSY/2-1)
  1844. ang = 3.1415926535898f*1.5f;
  1845. else if (j == FCGSY/2-1)
  1846. ang = 3.1415926535898f*1.25f;
  1847. else if (j == FCGSY/2)
  1848. ang = 3.1415926535898f*0.75f;
  1849. else
  1850. ang = 3.1415926535898f*0.5f;
  1851. }
  1852. else if (i==FCGSX/2) {
  1853. if (j < FCGSY/2-1)
  1854. ang = 3.1415926535898f*1.5f;
  1855. else if (j == FCGSY/2-1)
  1856. ang = 3.1415926535898f*1.75f;
  1857. else if (j == FCGSY/2)
  1858. ang = 3.1415926535898f*0.25f;
  1859. else
  1860. ang = 3.1415926535898f*0.5f;
  1861. }
  1862. else if (j==FCGSY/2-1) {
  1863. if (i < FCGSX/2-1)
  1864. ang = 3.1415926535898f*1.0f;
  1865. else if (i == FCGSX/2-1)
  1866. ang = 3.1415926535898f*1.25f;
  1867. else if (i == FCGSX/2)
  1868. ang = 3.1415926535898f*1.75f;
  1869. else
  1870. ang = 3.1415926535898f*2.0f;
  1871. }
  1872. else if (j==FCGSY/2) {
  1873. if (i < FCGSX/2-1)
  1874. ang = 3.1415926535898f*1.0f;
  1875. else if (i == FCGSX/2-1)
  1876. ang = 3.1415926535898f*0.75f;
  1877. else if (i == FCGSX/2)
  1878. ang = 3.1415926535898f*0.25f;
  1879. else
  1880. ang = 3.1415926535898f*0.0f;
  1881. }
  1882. p->tu = u;
  1883. p->tv = v;
  1884. //p->tu_orig = u;
  1885. //p->tv_orig = v;
  1886. p->rad = rad;
  1887. p->ang = ang;
  1888. p->Diffuse = 0xFFFFFFFF;
  1889. }
  1890. }
  1891. // build index list for final composite blit -
  1892. // order should be friendly for interpolation of 'ang' value!
  1893. int* cur_index = &m_comp_indices[0];
  1894. int y = 0;
  1895. for (y=0; y<FCGSY-1; y++)
  1896. {
  1897. if (y==FCGSY/2-1)
  1898. continue;
  1899. for (int x=0; x<FCGSX-1; x++)
  1900. {
  1901. if (x==FCGSX/2-1)
  1902. continue;
  1903. bool left_half = (x < FCGSX/2);
  1904. bool top_half = (y < FCGSY/2);
  1905. bool center_4 = ((x==FCGSX/2 || x==FCGSX/2-1) && (y==FCGSY/2 || y==FCGSY/2-1));
  1906. if ( ((int)left_half + (int)top_half + (int)center_4) % 2 )
  1907. {
  1908. *(cur_index+0) = (y )*FCGSX + (x );
  1909. *(cur_index+1) = (y )*FCGSX + (x+1);
  1910. *(cur_index+2) = (y+1)*FCGSX + (x+1);
  1911. *(cur_index+3) = (y+1)*FCGSX + (x+1);
  1912. *(cur_index+4) = (y+1)*FCGSX + (x );
  1913. *(cur_index+5) = (y )*FCGSX + (x );
  1914. }
  1915. else
  1916. {
  1917. *(cur_index+0) = (y+1)*FCGSX + (x );
  1918. *(cur_index+1) = (y )*FCGSX + (x );
  1919. *(cur_index+2) = (y )*FCGSX + (x+1);
  1920. *(cur_index+3) = (y )*FCGSX + (x+1);
  1921. *(cur_index+4) = (y+1)*FCGSX + (x+1);
  1922. *(cur_index+5) = (y+1)*FCGSX + (x );
  1923. }
  1924. cur_index += 6;
  1925. }
  1926. }
  1927. // -----------------
  1928. /*if (m_bFixSlowText && !m_bSeparateTextWindow)
  1929. {
  1930. if (pCreateTexture(GetDevice(), GetWidth(), GetHeight(), 1, D3DUSAGE_RENDERTARGET, GetBackBufFormat(), D3DPOOL_DEFAULT, &m_lpDDSText) != D3D_OK)
  1931. {
  1932. char buf[2048];
  1933. dumpmsg("Init: -WARNING-:");
  1934. sprintf(buf, "WARNING: Not enough video memory to make a dedicated text surface; \rtext will still be drawn directly to the back buffer.\r\rTo avoid seeing this error again, uncheck the 'fix slow text' option.");
  1935. dumpmsg(buf);
  1936. if (!m_bWarningsDisabled)
  1937. MessageBox(GetPluginWindow(), buf, "WARNING", MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  1938. m_lpDDSText = NULL;
  1939. }
  1940. }*/
  1941. // -----------------
  1942. // reallocate the texture for font titles + custom msgs (m_lpDDSTitle)
  1943. {
  1944. m_nTitleTexSizeX = max(m_nTexSizeX, m_nTexSizeY);
  1945. m_nTitleTexSizeY = m_nTitleTexSizeX/4;
  1946. //dumpmsg("Init: [re]allocating title surface");
  1947. // [DEPRECATED as of transition to dx9:]
  1948. // We could just create one title surface, but this is a problem because many
  1949. // systems can only call DrawText on DDSCAPS_OFFSCREENPLAIN surfaces, and can NOT
  1950. // draw text on a DDSCAPS_TEXTURE surface (it comes out garbled).
  1951. // So, we create one of each; we draw the text to the DDSCAPS_OFFSCREENPLAIN surface
  1952. // (m_lpDDSTitle[1]), then we blit that (once) to the DDSCAPS_TEXTURE surface
  1953. // (m_lpDDSTitle[0]), which can then be drawn onto the screen on polys.
  1954. HRESULT hr;
  1955. do
  1956. {
  1957. hr = pCreateTexture(GetDevice(), m_nTitleTexSizeX, m_nTitleTexSizeY, 1, D3DUSAGE_RENDERTARGET, GetBackBufFormat(), D3DPOOL_DEFAULT, &m_lpDDSTitle);
  1958. if (hr != D3D_OK)
  1959. {
  1960. if (m_nTitleTexSizeY < m_nTitleTexSizeX)
  1961. {
  1962. m_nTitleTexSizeY *= 2;
  1963. }
  1964. else
  1965. {
  1966. m_nTitleTexSizeX /= 2;
  1967. m_nTitleTexSizeY /= 2;
  1968. }
  1969. }
  1970. }
  1971. while (hr != D3D_OK && m_nTitleTexSizeX > 16);
  1972. if (hr != D3D_OK)
  1973. {
  1974. //dumpmsg("Init: -WARNING-: Title texture could not be created!");
  1975. m_lpDDSTitle = NULL;
  1976. //SafeRelease(m_lpDDSTitle);
  1977. //return true;
  1978. }
  1979. else
  1980. {
  1981. //sprintf(buf, "Init: title texture size is %dx%d (ideal size was %dx%d)", m_nTitleTexSizeX, m_nTitleTexSizeY, m_nTexSize, m_nTexSize/4);
  1982. //dumpmsg(buf);
  1983. m_supertext.bRedrawSuperText = true;
  1984. }
  1985. }
  1986. // -----------------
  1987. // create 'm_gdi_title_font_doublesize'
  1988. int songtitle_font_size = m_fontinfo[SONGTITLE_FONT].nSize * m_nTitleTexSizeX/256;
  1989. if (songtitle_font_size<6) songtitle_font_size=6;
  1990. if (!(m_gdi_title_font_doublesize = CreateFontW(songtitle_font_size, 0, 0, 0, m_fontinfo[SONGTITLE_FONT].bBold ? 900 : 400,
  1991. m_fontinfo[SONGTITLE_FONT].bItalic, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, m_fontinfo[SONGTITLE_FONT].bAntiAliased ? ANTIALIASED_QUALITY : DEFAULT_QUALITY, DEFAULT_PITCH, m_fontinfo[SONGTITLE_FONT].szFace)))
  1992. {
  1993. MessageBoxW(NULL, WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_DOUBLE_SIZED_GDI_TITLE_FONT),
  1994. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,sizeof(title)),
  1995. MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  1996. return false;
  1997. }
  1998. if (pCreateFontW( GetDevice(),
  1999. songtitle_font_size,
  2000. 0,
  2001. m_fontinfo[SONGTITLE_FONT].bBold ? 900 : 400,
  2002. 1,
  2003. m_fontinfo[SONGTITLE_FONT].bItalic,
  2004. DEFAULT_CHARSET,
  2005. OUT_DEFAULT_PRECIS,
  2006. ANTIALIASED_QUALITY,//DEFAULT_QUALITY,
  2007. DEFAULT_PITCH,
  2008. m_fontinfo[SONGTITLE_FONT].szFace,
  2009. &m_d3dx_title_font_doublesize
  2010. ) != D3D_OK)
  2011. {
  2012. MessageBoxW(GetPluginWindow(), WASABI_API_LNGSTRINGW(IDS_ERROR_CREATING_DOUBLE_SIZED_D3DX_TITLE_FONT),
  2013. WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,sizeof(title)), MB_OK|MB_SETFOREGROUND|MB_TOPMOST);
  2014. return false;
  2015. }
  2016. // -----------------
  2017. m_texmgr.Init(GetDevice());
  2018. //dumpmsg("Init: mesh allocation");
  2019. m_verts = new MYVERTEX[(m_nGridX+1)*(m_nGridY+1)];
  2020. m_verts_temp = new MYVERTEX[(m_nGridX+2) * 4];
  2021. m_vertinfo = new td_vertinfo[(m_nGridX+1)*(m_nGridY+1)];
  2022. m_indices_strip = new int[(m_nGridX+2)*(m_nGridY*2)];
  2023. m_indices_list = new int[m_nGridX*m_nGridY*6];
  2024. if (!m_verts || !m_vertinfo)
  2025. {
  2026. swprintf(buf, L"couldn't allocate mesh - out of memory");
  2027. dumpmsg(buf);
  2028. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  2029. return false;
  2030. }
  2031. int nVert = 0;
  2032. float texel_offset_x = 0.5f / (float)m_nTexSizeX;
  2033. float texel_offset_y = 0.5f / (float)m_nTexSizeY;
  2034. for (y=0; y<=m_nGridY; y++)
  2035. {
  2036. for (int x=0; x<=m_nGridX; x++)
  2037. {
  2038. // precompute x,y,z
  2039. m_verts[nVert].x = x/(float)m_nGridX*2.0f - 1.0f;
  2040. m_verts[nVert].y = y/(float)m_nGridY*2.0f - 1.0f;
  2041. m_verts[nVert].z = 0.0f;
  2042. // precompute rad, ang, being conscious of aspect ratio
  2043. m_vertinfo[nVert].rad = sqrtf(m_verts[nVert].x*m_verts[nVert].x*m_fAspectX*m_fAspectX + m_verts[nVert].y*m_verts[nVert].y*m_fAspectY*m_fAspectY);
  2044. if (y==m_nGridY/2 && x==m_nGridX/2)
  2045. m_vertinfo[nVert].ang = 0.0f;
  2046. else
  2047. m_vertinfo[nVert].ang = atan2f(m_verts[nVert].y*m_fAspectY, m_verts[nVert].x*m_fAspectX);
  2048. m_vertinfo[nVert].a = 1;
  2049. m_vertinfo[nVert].c = 0;
  2050. m_verts[nVert].rad = m_vertinfo[nVert].rad;
  2051. m_verts[nVert].ang = m_vertinfo[nVert].ang;
  2052. m_verts[nVert].tu_orig = m_verts[nVert].x*0.5f + 0.5f + texel_offset_x;
  2053. m_verts[nVert].tv_orig = -m_verts[nVert].y*0.5f + 0.5f + texel_offset_y;
  2054. nVert++;
  2055. }
  2056. }
  2057. // generate triangle strips for the 4 quadrants.
  2058. // each quadrant has m_nGridY/2 strips.
  2059. // each strip has m_nGridX+2 *points* in it, or m_nGridX/2 polygons.
  2060. int xref, yref;
  2061. int nVert_strip = 0;
  2062. for (int quadrant=0; quadrant<4; quadrant++)
  2063. {
  2064. for (int slice=0; slice < m_nGridY/2; slice++)
  2065. {
  2066. for (int i=0; i < m_nGridX + 2; i++)
  2067. {
  2068. // quadrants: 2 3
  2069. // 0 1
  2070. xref = i/2;
  2071. yref = (i%2) + slice;
  2072. if (quadrant & 1)
  2073. xref = m_nGridX - xref;
  2074. if (quadrant & 2)
  2075. yref = m_nGridY - yref;
  2076. int v = xref + (yref)*(m_nGridX+1);
  2077. m_indices_strip[nVert_strip++] = v;
  2078. }
  2079. }
  2080. }
  2081. // also generate triangle lists for drawing the main warp mesh.
  2082. int nVert_list = 0;
  2083. for (int quadrant=0; quadrant<4; quadrant++)
  2084. {
  2085. for (int slice=0; slice < m_nGridY/2; slice++)
  2086. {
  2087. for (int i=0; i < m_nGridX/2; i++)
  2088. {
  2089. // quadrants: 2 3
  2090. // 0 1
  2091. xref = i;
  2092. yref = slice;
  2093. if (quadrant & 1)
  2094. xref = m_nGridX-1 - xref;
  2095. if (quadrant & 2)
  2096. yref = m_nGridY-1 - yref;
  2097. int v = xref + (yref)*(m_nGridX+1);
  2098. m_indices_list[nVert_list++] = v;
  2099. m_indices_list[nVert_list++] = v +1;
  2100. m_indices_list[nVert_list++] = v+m_nGridX+1 ;
  2101. m_indices_list[nVert_list++] = v +1;
  2102. m_indices_list[nVert_list++] = v+m_nGridX+1 ;
  2103. m_indices_list[nVert_list++] = v+m_nGridX+1+1;
  2104. }
  2105. }
  2106. }
  2107. // GENERATED TEXTURES FOR SHADERS
  2108. //-------------------------------------
  2109. if (m_nMaxPSVersion > 0)
  2110. {
  2111. // Generate noise textures
  2112. if (!AddNoiseTex(L"noise_lq", 256, 1)) return false;
  2113. if (!AddNoiseTex(L"noise_lq_lite", 32, 1)) return false;
  2114. if (!AddNoiseTex(L"noise_mq", 256, 4)) return false;
  2115. if (!AddNoiseTex(L"noise_hq", 256, 8)) return false;
  2116. if (!AddNoiseVol(L"noisevol_lq", 32, 1)) return false;
  2117. if (!AddNoiseVol(L"noisevol_hq", 32, 4)) return false;
  2118. }
  2119. if (!m_bInitialPresetSelected)
  2120. {
  2121. UpdatePresetList(true); //...just does its initial burst!
  2122. LoadRandomPreset(0.0f);
  2123. m_bInitialPresetSelected = true;
  2124. }
  2125. else
  2126. LoadShaders(&m_shaders, m_pState, false); // Also force-load the shaders - otherwise they'd only get compiled on a preset switch.
  2127. return true;
  2128. }
  2129. float fCubicInterpolate(float y0, float y1, float y2, float y3, float t)
  2130. {
  2131. float a0,a1,a2,a3,t2;
  2132. t2 = t*t;
  2133. a0 = y3 - y2 - y0 + y1;
  2134. a1 = y0 - y1 - a0;
  2135. a2 = y2 - y0;
  2136. a3 = y1;
  2137. return(a0*t*t2+a1*t2+a2*t+a3);
  2138. }
  2139. DWORD dwCubicInterpolate(DWORD y0, DWORD y1, DWORD y2, DWORD y3, float t)
  2140. {
  2141. // performs cubic interpolation on a D3DCOLOR value.
  2142. DWORD ret = 0;
  2143. DWORD shift = 0;
  2144. for (int i=0; i<4; i++)
  2145. {
  2146. float f = fCubicInterpolate(
  2147. ((y0 >> shift) & 0xFF)/255.0f,
  2148. ((y1 >> shift) & 0xFF)/255.0f,
  2149. ((y2 >> shift) & 0xFF)/255.0f,
  2150. ((y3 >> shift) & 0xFF)/255.0f,
  2151. t
  2152. );
  2153. if (f<0)
  2154. f = 0;
  2155. if (f>1)
  2156. f = 1;
  2157. ret |= ((DWORD)(f*255)) << shift;
  2158. shift += 8;
  2159. }
  2160. return ret;
  2161. }
  2162. bool CPlugin::AddNoiseTex(const wchar_t* szTexName, int size, int zoom_factor)
  2163. {
  2164. // size = width & height of the texture;
  2165. // zoom_factor = how zoomed-in the texture features should be.
  2166. // 1 = random noise
  2167. // 2 = smoothed (interp)
  2168. // 4/8/16... = cubic interp.
  2169. wchar_t buf[2048], title[64];
  2170. // Synthesize noise texture(s)
  2171. LPDIRECT3DTEXTURE9 pNoiseTex = NULL;
  2172. // try twice - once with mips, once without.
  2173. for (int i=0; i<2; i++)
  2174. {
  2175. if (D3D_OK != GetDevice()->CreateTexture(size, size, i, D3DUSAGE_DYNAMIC | (i ? 0 : D3DUSAGE_AUTOGENMIPMAP), D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pNoiseTex, NULL))
  2176. {
  2177. if (i==1)
  2178. {
  2179. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_CREATE_NOISE_TEXTURE,buf,sizeof(buf));
  2180. dumpmsg(buf);
  2181. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  2182. return false;
  2183. }
  2184. }
  2185. else
  2186. break;
  2187. }
  2188. D3DLOCKED_RECT r;
  2189. if (D3D_OK != pNoiseTex->LockRect(0, &r, NULL, D3DLOCK_DISCARD))
  2190. {
  2191. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_LOCK_NOISE_TEXTURE,buf,sizeof(buf));
  2192. dumpmsg(buf);
  2193. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  2194. return false;
  2195. }
  2196. if (r.Pitch < size*4)
  2197. {
  2198. WASABI_API_LNGSTRINGW_BUF(IDS_NOISE_TEXTURE_BYTE_LAYOUT_NOT_RECOGNISED,buf,sizeof(buf));
  2199. dumpmsg(buf);
  2200. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  2201. return false;
  2202. }
  2203. // write to the bits...
  2204. DWORD* dst = (DWORD*)r.pBits;
  2205. int dwords_per_line = r.Pitch / sizeof(DWORD);
  2206. int RANGE = (zoom_factor > 1) ? 216 : 256;
  2207. for (int y=0; y<size; y++) {
  2208. LARGE_INTEGER q;
  2209. QueryPerformanceCounter(&q);
  2210. srand(q.LowPart ^ q.HighPart ^ warand());
  2211. int x = 0;
  2212. for (x=0; x<size; x++) {
  2213. dst[x] = (((DWORD)(warand() % RANGE)+RANGE/2) << 24) |
  2214. (((DWORD)(warand() % RANGE)+RANGE/2) << 16) |
  2215. (((DWORD)(warand() % RANGE)+RANGE/2) << 8) |
  2216. (((DWORD)(warand() % RANGE)+RANGE/2) );
  2217. }
  2218. // swap some pixels randomly, to improve 'randomness'
  2219. for (x=0; x<size; x++)
  2220. {
  2221. int x1 = (warand() ^ q.LowPart ) % size;
  2222. int x2 = (warand() ^ q.HighPart) % size;
  2223. DWORD temp = dst[x2];
  2224. dst[x2] = dst[x1];
  2225. dst[x1] = temp;
  2226. }
  2227. dst += dwords_per_line;
  2228. }
  2229. // smoothing
  2230. if (zoom_factor > 1)
  2231. {
  2232. // first go ACROSS, blending cubically on X, but only on the main lines.
  2233. DWORD* dst = (DWORD*)r.pBits;
  2234. for (int y=0; y<size; y+=zoom_factor)
  2235. for (int x=0; x<size; x++)
  2236. if (x % zoom_factor)
  2237. {
  2238. int base_x = (x/zoom_factor)*zoom_factor + size;
  2239. int base_y = y*dwords_per_line;
  2240. DWORD y0 = dst[ base_y + ((base_x - zoom_factor ) % size) ];
  2241. DWORD y1 = dst[ base_y + ((base_x ) % size) ];
  2242. DWORD y2 = dst[ base_y + ((base_x + zoom_factor ) % size) ];
  2243. DWORD y3 = dst[ base_y + ((base_x + zoom_factor*2) % size) ];
  2244. float t = (x % zoom_factor)/(float)zoom_factor;
  2245. DWORD result = dwCubicInterpolate(y0, y1, y2, y3, t);
  2246. dst[ y*dwords_per_line + x ] = result;
  2247. }
  2248. // next go down, doing cubic interp along Y, on every line.
  2249. for (int x=0; x<size; x++)
  2250. for (int y=0; y<size; y++)
  2251. if (y % zoom_factor)
  2252. {
  2253. int base_y = (y/zoom_factor)*zoom_factor + size;
  2254. DWORD y0 = dst[ ((base_y - zoom_factor ) % size)*dwords_per_line + x ];
  2255. DWORD y1 = dst[ ((base_y ) % size)*dwords_per_line + x ];
  2256. DWORD y2 = dst[ ((base_y + zoom_factor ) % size)*dwords_per_line + x ];
  2257. DWORD y3 = dst[ ((base_y + zoom_factor*2) % size)*dwords_per_line + x ];
  2258. float t = (y % zoom_factor)/(float)zoom_factor;
  2259. DWORD result = dwCubicInterpolate(y0, y1, y2, y3, t);
  2260. dst[ y*dwords_per_line + x ] = result;
  2261. }
  2262. }
  2263. // unlock texture
  2264. pNoiseTex->UnlockRect(0);
  2265. // add it to m_textures[].
  2266. TexInfo x;
  2267. lstrcpyW(x.texname, szTexName);
  2268. x.texptr = pNoiseTex;
  2269. //x.texsize_param = NULL;
  2270. x.w = size;
  2271. x.h = size;
  2272. x.d = 1;
  2273. x.bEvictable = false;
  2274. x.nAge = m_nPresetsLoadedTotal;
  2275. x.nSizeInBytes = 0;
  2276. m_textures.push_back(x);
  2277. return true;
  2278. }
  2279. bool CPlugin::AddNoiseVol(const wchar_t* szTexName, int size, int zoom_factor)
  2280. {
  2281. // size = width & height & depth of the texture;
  2282. // zoom_factor = how zoomed-in the texture features should be.
  2283. // 1 = random noise
  2284. // 2 = smoothed (interp)
  2285. // 4/8/16... = cubic interp.
  2286. wchar_t buf[2048], title[64];
  2287. // Synthesize noise texture(s)
  2288. LPDIRECT3DVOLUMETEXTURE9 pNoiseTex = NULL;
  2289. // try twice - once with mips, once without.
  2290. // NO, TRY JUST ONCE - DX9 doesn't do auto mipgen w/volume textures. (Debug runtime complains.)
  2291. for (int i=1; i<2; i++)
  2292. {
  2293. if (D3D_OK != GetDevice()->CreateVolumeTexture(size, size, size, i, D3DUSAGE_DYNAMIC | (i ? 0 : D3DUSAGE_AUTOGENMIPMAP), D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pNoiseTex, NULL))
  2294. {
  2295. if (i==1)
  2296. {
  2297. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_CREATE_3D_NOISE_TEXTURE,buf,sizeof(buf));
  2298. dumpmsg(buf);
  2299. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  2300. return false;
  2301. }
  2302. }
  2303. else
  2304. break;
  2305. }
  2306. D3DLOCKED_BOX r;
  2307. if (D3D_OK != pNoiseTex->LockBox(0, &r, NULL, D3DLOCK_DISCARD))
  2308. {
  2309. WASABI_API_LNGSTRINGW_BUF(IDS_COULD_NOT_LOCK_3D_NOISE_TEXTURE,buf,sizeof(buf));
  2310. dumpmsg(buf);
  2311. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  2312. return false;
  2313. }
  2314. if (r.RowPitch < size*4 || r.SlicePitch < size*size*4)
  2315. {
  2316. WASABI_API_LNGSTRINGW_BUF(IDS_3D_NOISE_TEXTURE_BYTE_LAYOUT_NOT_RECOGNISED,buf,sizeof(buf));
  2317. dumpmsg(buf);
  2318. MessageBoxW(GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  2319. return false;
  2320. }
  2321. // write to the bits...
  2322. int dwords_per_slice = r.SlicePitch / sizeof(DWORD);
  2323. int dwords_per_line = r.RowPitch / sizeof(DWORD);
  2324. int RANGE = (zoom_factor > 1) ? 216 : 256;
  2325. for (int z=0; z<size; z++) {
  2326. DWORD* dst = (DWORD*)r.pBits + z*dwords_per_slice;
  2327. for (int y=0; y<size; y++) {
  2328. LARGE_INTEGER q;
  2329. QueryPerformanceCounter(&q);
  2330. srand(q.LowPart ^ q.HighPart ^ warand());
  2331. int x = 0;
  2332. for (x=0; x<size; x++) {
  2333. dst[x] = (((DWORD)(warand() % RANGE)+RANGE/2) << 24) |
  2334. (((DWORD)(warand() % RANGE)+RANGE/2) << 16) |
  2335. (((DWORD)(warand() % RANGE)+RANGE/2) << 8) |
  2336. (((DWORD)(warand() % RANGE)+RANGE/2) );
  2337. }
  2338. // swap some pixels randomly, to improve 'randomness'
  2339. for (x=0; x<size; x++)
  2340. {
  2341. int x1 = (warand() ^ q.LowPart ) % size;
  2342. int x2 = (warand() ^ q.HighPart) % size;
  2343. DWORD temp = dst[x2];
  2344. dst[x2] = dst[x1];
  2345. dst[x1] = temp;
  2346. }
  2347. dst += dwords_per_line;
  2348. }
  2349. }
  2350. // smoothing
  2351. if (zoom_factor > 1)
  2352. {
  2353. // first go ACROSS, blending cubically on X, but only on the main lines.
  2354. DWORD* dst = (DWORD*)r.pBits;
  2355. for (int z=0; z<size; z+=zoom_factor)
  2356. for (int y=0; y<size; y+=zoom_factor)
  2357. for (int x=0; x<size; x++)
  2358. if (x % zoom_factor)
  2359. {
  2360. int base_x = (x/zoom_factor)*zoom_factor + size;
  2361. int base_y = z*dwords_per_slice + y*dwords_per_line;
  2362. DWORD y0 = dst[ base_y + ((base_x - zoom_factor ) % size) ];
  2363. DWORD y1 = dst[ base_y + ((base_x ) % size) ];
  2364. DWORD y2 = dst[ base_y + ((base_x + zoom_factor ) % size) ];
  2365. DWORD y3 = dst[ base_y + ((base_x + zoom_factor*2) % size) ];
  2366. float t = (x % zoom_factor)/(float)zoom_factor;
  2367. DWORD result = dwCubicInterpolate(y0, y1, y2, y3, t);
  2368. dst[ z*dwords_per_slice + y*dwords_per_line + x ] = result;
  2369. }
  2370. // next go down, doing cubic interp along Y, on the main slices.
  2371. for (int z=0; z<size; z+=zoom_factor)
  2372. for (int x=0; x<size; x++)
  2373. for (int y=0; y<size; y++)
  2374. if (y % zoom_factor)
  2375. {
  2376. int base_y = (y/zoom_factor)*zoom_factor + size;
  2377. int base_z = z*dwords_per_slice;
  2378. DWORD y0 = dst[ ((base_y - zoom_factor ) % size)*dwords_per_line + base_z + x ];
  2379. DWORD y1 = dst[ ((base_y ) % size)*dwords_per_line + base_z + x ];
  2380. DWORD y2 = dst[ ((base_y + zoom_factor ) % size)*dwords_per_line + base_z + x ];
  2381. DWORD y3 = dst[ ((base_y + zoom_factor*2) % size)*dwords_per_line + base_z + x ];
  2382. float t = (y % zoom_factor)/(float)zoom_factor;
  2383. DWORD result = dwCubicInterpolate(y0, y1, y2, y3, t);
  2384. dst[ y*dwords_per_line + base_z + x ] = result;
  2385. }
  2386. // next go through, doing cubic interp along Z, everywhere.
  2387. for (int x=0; x<size; x++)
  2388. for (int y=0; y<size; y++)
  2389. for (int z=0; z<size; z++)
  2390. if (z % zoom_factor)
  2391. {
  2392. int base_y = y*dwords_per_line;
  2393. int base_z = (z/zoom_factor)*zoom_factor + size;
  2394. DWORD y0 = dst[ ((base_z - zoom_factor ) % size)*dwords_per_slice + base_y + x ];
  2395. DWORD y1 = dst[ ((base_z ) % size)*dwords_per_slice + base_y + x ];
  2396. DWORD y2 = dst[ ((base_z + zoom_factor ) % size)*dwords_per_slice + base_y + x ];
  2397. DWORD y3 = dst[ ((base_z + zoom_factor*2) % size)*dwords_per_slice + base_y + x ];
  2398. float t = (z % zoom_factor)/(float)zoom_factor;
  2399. DWORD result = dwCubicInterpolate(y0, y1, y2, y3, t);
  2400. dst[ z*dwords_per_slice + base_y + x ] = result;
  2401. }
  2402. }
  2403. // unlock texture
  2404. pNoiseTex->UnlockBox(0);
  2405. // add it to m_textures[].
  2406. TexInfo x;
  2407. lstrcpyW(x.texname, szTexName);
  2408. x.texptr = pNoiseTex;
  2409. //x.texsize_param = NULL;
  2410. x.w = size;
  2411. x.h = size;
  2412. x.d = size;
  2413. x.bEvictable = false;
  2414. x.nAge = m_nPresetsLoadedTotal;
  2415. x.nSizeInBytes = 0;
  2416. m_textures.push_back(x);
  2417. return true;
  2418. }
  2419. void VShaderInfo::Clear()
  2420. {
  2421. SafeRelease(ptr);
  2422. SafeRelease(CT);
  2423. params.Clear();
  2424. }
  2425. void PShaderInfo::Clear()
  2426. {
  2427. SafeRelease(ptr);
  2428. SafeRelease(CT);
  2429. params.Clear();
  2430. }
  2431. // global_CShaderParams_master_list: a master list of all CShaderParams classes in existence.
  2432. // ** when we evict a texture, we need to NULL out any texptrs these guys have! **
  2433. CShaderParamsList global_CShaderParams_master_list;
  2434. CShaderParams::CShaderParams() {
  2435. global_CShaderParams_master_list.push_back(this);
  2436. }
  2437. CShaderParams::~CShaderParams() {
  2438. int N = global_CShaderParams_master_list.size();
  2439. for (int i=0; i<N; i++)
  2440. if (global_CShaderParams_master_list[i] == this)
  2441. {
  2442. global_CShaderParams_master_list.erase(global_CShaderParams_master_list.begin() + i);
  2443. break;
  2444. }
  2445. texsize_params.clear();
  2446. }
  2447. void CShaderParams::OnTextureEvict(LPDIRECT3DBASETEXTURE9 texptr)
  2448. {
  2449. for (int i=0; i<sizeof(m_texture_bindings)/sizeof(m_texture_bindings[0]); i++)
  2450. if (m_texture_bindings[i].texptr == texptr)
  2451. m_texture_bindings[i].texptr = NULL;
  2452. }
  2453. void CShaderParams::Clear()
  2454. {
  2455. // float4 handles:
  2456. rand_frame = NULL;
  2457. rand_preset = NULL;
  2458. ZeroMemory(rot_mat, sizeof(rot_mat));
  2459. ZeroMemory(const_handles, sizeof(const_handles));
  2460. ZeroMemory(q_const_handles, sizeof(q_const_handles));
  2461. texsize_params.clear();
  2462. // sampler stages for various PS texture bindings:
  2463. for (int i=0; i<sizeof(m_texture_bindings)/sizeof(m_texture_bindings[0]); i++)
  2464. {
  2465. m_texture_bindings[i].texptr = NULL;
  2466. m_texcode[i] = TEX_DISK;
  2467. }
  2468. }
  2469. bool CPlugin::EvictSomeTexture()
  2470. {
  2471. // note: this won't evict a texture whose age is zero,
  2472. // or whose reported size is zero!
  2473. #if _DEBUG
  2474. {
  2475. int nEvictableFiles = 0;
  2476. int nEvictableBytes = 0;
  2477. int N = m_textures.size();
  2478. for (int i=0; i<N; i++)
  2479. if (m_textures[i].bEvictable && m_textures[i].texptr)
  2480. {
  2481. nEvictableFiles++;
  2482. nEvictableBytes += m_textures[i].nSizeInBytes;
  2483. }
  2484. char buf[1024];
  2485. sprintf(buf, "evicting at %d textures, %.1f MB\n", nEvictableFiles, nEvictableBytes*0.000001f);
  2486. OutputDebugString(buf);
  2487. }
  2488. #endif
  2489. int N = m_textures.size();
  2490. // find age gap
  2491. int newest = 99999999;
  2492. int oldest = 0;
  2493. bool bAtLeastOneFound = false;
  2494. int i = 0;
  2495. for (i=0; i<N; i++)
  2496. if (m_textures[i].bEvictable && m_textures[i].nSizeInBytes>0 && m_textures[i].nAge < m_nPresetsLoadedTotal-1) // note: -1 here keeps images around for the blend-from preset, too...
  2497. {
  2498. newest = min(newest, m_textures[i].nAge);
  2499. oldest = max(oldest, m_textures[i].nAge);
  2500. bAtLeastOneFound = true;
  2501. }
  2502. if (!bAtLeastOneFound)
  2503. return false;
  2504. // find the "biggest" texture, but dilate things so that the newest textures
  2505. // are HALF as big as the oldest textures, and thus, less likely to get booted.
  2506. int biggest_bytes = 0;
  2507. int biggest_index = -1;
  2508. for (i=0; i<N; i++)
  2509. if (m_textures[i].bEvictable && m_textures[i].nSizeInBytes>0 && m_textures[i].nAge < m_nPresetsLoadedTotal-1) // note: -1 here keeps images around for the blend-from preset, too...
  2510. {
  2511. float size_mult = 1.0f + (m_textures[i].nAge - newest)/(float)(oldest-newest);
  2512. int bytes = (int)(m_textures[i].nSizeInBytes * size_mult);
  2513. if (bytes > biggest_bytes)
  2514. {
  2515. biggest_bytes = bytes;
  2516. biggest_index = i;
  2517. }
  2518. }
  2519. if (biggest_index == -1)
  2520. return false;
  2521. // evict that sucker
  2522. assert(m_textures[biggest_index].texptr);
  2523. // notify all CShaderParams classes that we're releasing a bindable texture!!
  2524. N = global_CShaderParams_master_list.size();
  2525. for (i=0; i<N; i++)
  2526. global_CShaderParams_master_list[i]->OnTextureEvict( m_textures[biggest_index].texptr );
  2527. // 2. erase the texture itself
  2528. SafeRelease(m_textures[biggest_index].texptr);
  2529. m_textures.erase(m_textures.begin() + biggest_index);
  2530. return true;
  2531. }
  2532. GString texture_exts[] = { L"jpg", L"dds", L"png", L"tga", L"bmp", L"dib", };
  2533. const wchar_t szExtsWithSlashes[] = L"jpg|png|dds|etc.";
  2534. typedef std::vector<GString> StringVec;
  2535. bool PickRandomTexture(const wchar_t* prefix, wchar_t* szRetTextureFilename) //should be MAX_PATH chars
  2536. {
  2537. static StringVec texfiles;
  2538. static DWORD texfiles_timestamp = 0; // update this a max of every ~2 seconds or so
  2539. // if it's been more than a few seconds since the last textures dir scan, redo it.
  2540. // (..just enough to make sure we don't do it more than once per preset load)
  2541. //DWORD t = timeGetTime(); // in milliseconds
  2542. //if (abs(t - texfiles_timestamp) > 2000)
  2543. if (g_plugin.m_bNeedRescanTexturesDir)
  2544. {
  2545. g_plugin.m_bNeedRescanTexturesDir = false;//texfiles_timestamp = t;
  2546. texfiles.clear();
  2547. wchar_t szMask[MAX_PATH];
  2548. swprintf(szMask, L"%stextures\\*.*", g_plugin.m_szMilkdrop2Path);
  2549. WIN32_FIND_DATAW ffd = {0};
  2550. HANDLE hFindFile = INVALID_HANDLE_VALUE;
  2551. if( (hFindFile = FindFirstFileW(szMask, &ffd )) == INVALID_HANDLE_VALUE ) // note: returns filename -without- path
  2552. return false;
  2553. // first, count valid texture files
  2554. do
  2555. {
  2556. if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  2557. continue;
  2558. wchar_t* ext = wcsrchr(ffd.cFileName, L'.');
  2559. if (!ext)
  2560. continue;
  2561. for (int i=0; i<sizeof(texture_exts)/sizeof(texture_exts[0]); i++)
  2562. if (!wcsicmp(texture_exts[i].c_str(), ext+1))
  2563. {
  2564. // valid texture found - add it to the list. ("heart.jpg", for example)
  2565. texfiles.push_back( ffd.cFileName );
  2566. continue;
  2567. }
  2568. }
  2569. while (FindNextFileW(hFindFile, &ffd));
  2570. FindClose(hFindFile);
  2571. }
  2572. if (texfiles.size() == 0)
  2573. return false;
  2574. // then randomly pick one
  2575. if (prefix==NULL || prefix[0]==0)
  2576. {
  2577. // pick randomly from entire list
  2578. int i = warand() % texfiles.size();
  2579. lstrcpyW(szRetTextureFilename, texfiles[i].c_str());
  2580. }
  2581. else
  2582. {
  2583. // only pick from files w/the right prefix
  2584. StringVec temp_list;
  2585. int N = texfiles.size();
  2586. int len = lstrlenW(prefix);
  2587. for (int i=0; i<N; i++)
  2588. if (!_wcsnicmp(prefix, texfiles[i].c_str(), len))
  2589. temp_list.push_back(texfiles[i]);
  2590. N = temp_list.size();
  2591. if (N==0)
  2592. return false;
  2593. // pick randomly from the subset
  2594. int i = warand() % temp_list.size();
  2595. lstrcpyW(szRetTextureFilename, temp_list[i].c_str());
  2596. }
  2597. return true;
  2598. }
  2599. void CShaderParams::CacheParams(LPD3DXCONSTANTTABLE pCT, bool bHardErrors)
  2600. {
  2601. Clear();
  2602. if (!pCT)
  2603. return;
  2604. D3DXCONSTANTTABLE_DESC d;
  2605. pCT->GetDesc(&d);
  2606. D3DXCONSTANT_DESC cd;
  2607. #define MAX_RAND_TEX 16
  2608. GString RandTexName[MAX_RAND_TEX];
  2609. // pass 1: find all the samplers (and texture bindings).
  2610. UINT i = 0;
  2611. for (i=0; i<d.Constants; i++)
  2612. {
  2613. D3DXHANDLE h = pCT->GetConstant(NULL, i);
  2614. unsigned int count = 1;
  2615. pCT->GetConstantDesc(h, &cd, &count);
  2616. // cd.Name = VS_Sampler
  2617. // cd.RegisterSet = D3DXRS_SAMPLER
  2618. // cd.RegisterIndex = 3
  2619. if (cd.RegisterSet == D3DXRS_SAMPLER && cd.RegisterIndex >= 0 && cd.RegisterIndex < sizeof(m_texture_bindings)/sizeof(m_texture_bindings[0]))
  2620. {
  2621. assert(m_texture_bindings[cd.RegisterIndex].texptr == NULL);
  2622. // remove "sampler_" prefix to create root file name. could still have "FW_" prefix or something like that.
  2623. wchar_t szRootName[MAX_PATH];
  2624. if (!strncmp(cd.Name, "sampler_", 8))
  2625. lstrcpyW(szRootName, AutoWide(&cd.Name[8]));
  2626. else
  2627. lstrcpyW(szRootName, AutoWide(cd.Name));
  2628. // also peel off "XY_" prefix, if it's there, to specify filtering & wrap mode.
  2629. bool bBilinear = true;
  2630. bool bWrap = true;
  2631. bool bWrapFilterSpecified = false;
  2632. if (lstrlenW(szRootName) > 3 && szRootName[2]==L'_')
  2633. {
  2634. wchar_t temp[3];
  2635. temp[0] = szRootName[0];
  2636. temp[1] = szRootName[1];
  2637. temp[2] = 0;
  2638. // convert to uppercase
  2639. if (temp[0] >= L'a' && temp[0] <= L'z')
  2640. temp[0] -= L'a' - L'A';
  2641. if (temp[1] >= L'a' && temp[1] <= L'z')
  2642. temp[1] -= L'a' - L'A';
  2643. if (!wcscmp(temp, L"FW")) { bWrapFilterSpecified = true; bBilinear = true; bWrap = true; }
  2644. else if (!wcscmp(temp, L"FC")) { bWrapFilterSpecified = true; bBilinear = true; bWrap = false; }
  2645. else if (!wcscmp(temp, L"PW")) { bWrapFilterSpecified = true; bBilinear = false; bWrap = true; }
  2646. else if (!wcscmp(temp, L"PC")) { bWrapFilterSpecified = true; bBilinear = false; bWrap = false; }
  2647. // also allow reverses:
  2648. else if (!wcscmp(temp, L"WF")) { bWrapFilterSpecified = true; bBilinear = true; bWrap = true; }
  2649. else if (!wcscmp(temp, L"CF")) { bWrapFilterSpecified = true; bBilinear = true; bWrap = false; }
  2650. else if (!wcscmp(temp, L"WP")) { bWrapFilterSpecified = true; bBilinear = false; bWrap = true; }
  2651. else if (!wcscmp(temp, L"CP")) { bWrapFilterSpecified = true; bBilinear = false; bWrap = false; }
  2652. // peel off the prefix
  2653. int i = 0;
  2654. while (szRootName[i+3])
  2655. {
  2656. szRootName[i] = szRootName[i+3];
  2657. i++;
  2658. }
  2659. szRootName[i] = 0;
  2660. }
  2661. m_texture_bindings[ cd.RegisterIndex ].bWrap = bWrap;
  2662. m_texture_bindings[ cd.RegisterIndex ].bBilinear = bBilinear;
  2663. // if <szFileName> is "main", map it to the VS...
  2664. if (!wcscmp(L"main", szRootName))
  2665. {
  2666. m_texture_bindings[ cd.RegisterIndex ].texptr = NULL;
  2667. m_texcode[ cd.RegisterIndex ] = TEX_VS;
  2668. }
  2669. #if (NUM_BLUR_TEX >= 2)
  2670. else if (!wcscmp(L"blur1", szRootName))
  2671. {
  2672. m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_lpBlur[1];
  2673. m_texcode [ cd.RegisterIndex ] = TEX_BLUR1;
  2674. if (!bWrapFilterSpecified) { // when sampling blur textures, default is CLAMP
  2675. m_texture_bindings[ cd.RegisterIndex ].bWrap = false;
  2676. m_texture_bindings[ cd.RegisterIndex ].bBilinear = true;
  2677. }
  2678. }
  2679. #endif
  2680. #if (NUM_BLUR_TEX >= 4)
  2681. else if (!wcscmp(L"blur2", szRootName))
  2682. {
  2683. m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_lpBlur[3];
  2684. m_texcode [ cd.RegisterIndex ] = TEX_BLUR2;
  2685. if (!bWrapFilterSpecified) { // when sampling blur textures, default is CLAMP
  2686. m_texture_bindings[ cd.RegisterIndex ].bWrap = false;
  2687. m_texture_bindings[ cd.RegisterIndex ].bBilinear = true;
  2688. }
  2689. }
  2690. #endif
  2691. #if (NUM_BLUR_TEX >= 6)
  2692. else if (!wcscmp(L"blur3", szRootName))
  2693. {
  2694. m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_lpBlur[5];
  2695. m_texcode [ cd.RegisterIndex ] = TEX_BLUR3;
  2696. if (!bWrapFilterSpecified) { // when sampling blur textures, default is CLAMP
  2697. m_texture_bindings[ cd.RegisterIndex ].bWrap = false;
  2698. m_texture_bindings[ cd.RegisterIndex ].bBilinear = true;
  2699. }
  2700. }
  2701. #endif
  2702. #if (NUM_BLUR_TEX >= 8)
  2703. else if (!wcscmp("blur4", szRootName))
  2704. {
  2705. m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_lpBlur[7];
  2706. m_texcode [ cd.RegisterIndex ] = TEX_BLUR4;
  2707. if (!bWrapFilterSpecified) { // when sampling blur textures, default is CLAMP
  2708. m_texture_bindings[ cd.RegisterIndex ].bWrap = false;
  2709. m_texture_bindings[ cd.RegisterIndex ].bBilinear = true;
  2710. }
  2711. }
  2712. #endif
  2713. #if (NUM_BLUR_TEX >= 10)
  2714. else if (!wcscmp("blur5", szRootName))
  2715. {
  2716. m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_lpBlur[9];
  2717. m_texcode [ cd.RegisterIndex ] = TEX_BLUR5;
  2718. if (!bWrapFilterSpecified) { // when sampling blur textures, default is CLAMP
  2719. m_texture_bindings[ cd.RegisterIndex ].bWrap = false;
  2720. m_texture_bindings[ cd.RegisterIndex ].bBilinear = true;
  2721. }
  2722. }
  2723. #endif
  2724. #if (NUM_BLUR_TEX >= 12)
  2725. else if (!wcscmp("blur6", szRootName))
  2726. {
  2727. m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_lpBlur[11];
  2728. m_texcode [ cd.RegisterIndex ] = TEX_BLUR6;
  2729. if (!bWrapFilterSpecified) { // when sampling blur textures, default is CLAMP
  2730. m_texture_bindings[ cd.RegisterIndex ].bWrap = false;
  2731. m_texture_bindings[ cd.RegisterIndex ].bBilinear = true;
  2732. }
  2733. }
  2734. #endif
  2735. else
  2736. {
  2737. m_texcode[ cd.RegisterIndex ] = TEX_DISK;
  2738. // check for request for random texture.
  2739. if (!wcsncmp(L"rand", szRootName, 4) &&
  2740. IsNumericChar(szRootName[4]) &&
  2741. IsNumericChar(szRootName[5]) &&
  2742. (szRootName[6]==0 || szRootName[6]=='_') )
  2743. {
  2744. int rand_slot = -1;
  2745. // peel off filename prefix ("rand13_smalltiled", for example)
  2746. wchar_t prefix[MAX_PATH];
  2747. if (szRootName[6]==L'_')
  2748. lstrcpyW(prefix, &szRootName[7]);
  2749. else
  2750. prefix[0] = 0;
  2751. szRootName[6] = 0;
  2752. swscanf(&szRootName[4], L"%d", &rand_slot);
  2753. if (rand_slot >= 0 && rand_slot <= 15) // otherwise, not a special filename - ignore it
  2754. {
  2755. if (!PickRandomTexture(prefix, szRootName))
  2756. {
  2757. if (prefix[0])
  2758. swprintf(szRootName, L"[rand%02d] %s*", rand_slot, prefix);
  2759. else
  2760. swprintf(szRootName, L"[rand%02d] *", rand_slot);
  2761. }
  2762. else
  2763. {
  2764. //chop off extension
  2765. wchar_t *p = wcsrchr(szRootName, L'.');
  2766. if (p)
  2767. *p = 0;
  2768. }
  2769. assert(RandTexName[rand_slot].GetLength() == 0);
  2770. RandTexName[rand_slot] = szRootName; // we'll need to remember this for texsize_ params!
  2771. }
  2772. }
  2773. // see if <szRootName>.tga or .jpg has already been loaded.
  2774. // (if so, grab a pointer to it)
  2775. // (if NOT, create & load it).
  2776. int N = g_plugin.m_textures.size();
  2777. for (int n=0; n<N; n++) {
  2778. if (!wcscmp(g_plugin.m_textures[n].texname, szRootName))
  2779. {
  2780. // found a match - texture was already loaded
  2781. m_texture_bindings[ cd.RegisterIndex ].texptr = g_plugin.m_textures[n].texptr;
  2782. // also bump its age down to zero! (for cache mgmt)
  2783. g_plugin.m_textures[n].nAge = g_plugin.m_nPresetsLoadedTotal;
  2784. break;
  2785. }
  2786. }
  2787. // if still not found, load it up / make a new texture
  2788. if (!m_texture_bindings[ cd.RegisterIndex ].texptr)
  2789. {
  2790. TexInfo x;
  2791. wcsncpy(x.texname, szRootName, 254);
  2792. x.texptr = NULL;
  2793. //x.texsize_param = NULL;
  2794. // check if we need to evict anything from the cache,
  2795. // due to our own cache constraints...
  2796. while (1)
  2797. {
  2798. int nTexturesCached = 0;
  2799. int nBytesCached = 0;
  2800. int N = g_plugin.m_textures.size();
  2801. for (int i=0; i<N; i++)
  2802. if (g_plugin.m_textures[i].bEvictable && g_plugin.m_textures[i].texptr)
  2803. {
  2804. nBytesCached += g_plugin.m_textures[i].nSizeInBytes;
  2805. nTexturesCached++;
  2806. }
  2807. if ( nTexturesCached < g_plugin.m_nMaxImages &&
  2808. nBytesCached < g_plugin.m_nMaxBytes )
  2809. break;
  2810. // otherwise, evict now - and loop until we are within the constraints
  2811. if (!g_plugin.EvictSomeTexture())
  2812. break; // or if there was nothing to evict, just give up
  2813. }
  2814. //load the texture
  2815. wchar_t szFilename[MAX_PATH];
  2816. for (int z=0; z<sizeof(texture_exts)/sizeof(texture_exts[0]); z++)
  2817. {
  2818. swprintf(szFilename, L"%stextures\\%s.%s", g_plugin.m_szMilkdrop2Path, szRootName, texture_exts[z].c_str());
  2819. if (GetFileAttributesW(szFilename) == 0xFFFFFFFF)
  2820. {
  2821. // try again, but in presets dir
  2822. swprintf(szFilename, L"%s%s.%s", g_plugin.m_szPresetDir, szRootName, texture_exts[z].c_str());
  2823. if (GetFileAttributesW(szFilename) == 0xFFFFFFFF)
  2824. continue;
  2825. }
  2826. D3DXIMAGE_INFO desc;
  2827. // keep trying to load it - if it fails due to memory, evict something and try again.
  2828. while (1)
  2829. {
  2830. HRESULT hr = pCreateTextureFromFileExW(g_plugin.GetDevice(),
  2831. szFilename,
  2832. D3DX_DEFAULT_NONPOW2, // w
  2833. D3DX_DEFAULT_NONPOW2, // h
  2834. D3DX_DEFAULT, // # mip levels to gen - all
  2835. 0, // usage flags
  2836. D3DFMT_UNKNOWN,
  2837. D3DPOOL_DEFAULT,
  2838. D3DX_DEFAULT, //filter
  2839. D3DX_DEFAULT, //mipfilter
  2840. 0, // color key
  2841. &desc,
  2842. NULL, //palette
  2843. (IDirect3DTexture9**)&x.texptr
  2844. );
  2845. if (hr==D3DERR_OUTOFVIDEOMEMORY || hr==E_OUTOFMEMORY)
  2846. {
  2847. // out of memory - try evicting something old and/or big
  2848. if (g_plugin.EvictSomeTexture())
  2849. continue;
  2850. }
  2851. if (hr==D3D_OK)
  2852. {
  2853. x.w = desc.Width;
  2854. x.h = desc.Height;
  2855. x.d = desc.Depth;
  2856. x.bEvictable = true;
  2857. x.nAge = g_plugin.m_nPresetsLoadedTotal;
  2858. int nPixels = desc.Width*desc.Height*max(1,desc.Depth);
  2859. int BitsPerPixel = GetDX9TexFormatBitsPerPixel(desc.Format);
  2860. x.nSizeInBytes = nPixels*BitsPerPixel/8 + 16384; //plus some overhead
  2861. }
  2862. break;
  2863. }
  2864. }
  2865. if (!x.texptr)
  2866. {
  2867. wchar_t buf[2048], title[64];
  2868. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_COULD_NOT_LOAD_TEXTURE_X), szRootName, szExtsWithSlashes);
  2869. g_plugin.dumpmsg(buf);
  2870. if (bHardErrors)
  2871. MessageBoxW(g_plugin.GetPluginWindow(), buf, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  2872. else {
  2873. g_plugin.AddError(buf, 6.0f, ERR_PRESET, true);
  2874. }
  2875. return;
  2876. }
  2877. g_plugin.m_textures.push_back(x);
  2878. m_texture_bindings[ cd.RegisterIndex ].texptr = x.texptr;
  2879. }
  2880. }
  2881. }
  2882. }
  2883. // pass 2: bind all the float4's. "texsize_XYZ" params will be filled out via knowledge of loaded texture sizes.
  2884. for (i=0; i<d.Constants; i++)
  2885. {
  2886. D3DXHANDLE h = pCT->GetConstant(NULL, i);
  2887. unsigned int count = 1;
  2888. pCT->GetConstantDesc(h, &cd, &count);
  2889. if (cd.RegisterSet == D3DXRS_FLOAT4)
  2890. {
  2891. if (cd.Class == D3DXPC_MATRIX_COLUMNS)
  2892. {
  2893. if (!strcmp(cd.Name, "rot_s1" )) rot_mat[0] = h;
  2894. else if (!strcmp(cd.Name, "rot_s2" )) rot_mat[1] = h;
  2895. else if (!strcmp(cd.Name, "rot_s3" )) rot_mat[2] = h;
  2896. else if (!strcmp(cd.Name, "rot_s4" )) rot_mat[3] = h;
  2897. else if (!strcmp(cd.Name, "rot_d1" )) rot_mat[4] = h;
  2898. else if (!strcmp(cd.Name, "rot_d2" )) rot_mat[5] = h;
  2899. else if (!strcmp(cd.Name, "rot_d3" )) rot_mat[6] = h;
  2900. else if (!strcmp(cd.Name, "rot_d4" )) rot_mat[7] = h;
  2901. else if (!strcmp(cd.Name, "rot_f1" )) rot_mat[8] = h;
  2902. else if (!strcmp(cd.Name, "rot_f2" )) rot_mat[9] = h;
  2903. else if (!strcmp(cd.Name, "rot_f3" )) rot_mat[10] = h;
  2904. else if (!strcmp(cd.Name, "rot_f4" )) rot_mat[11] = h;
  2905. else if (!strcmp(cd.Name, "rot_vf1")) rot_mat[12] = h;
  2906. else if (!strcmp(cd.Name, "rot_vf2")) rot_mat[13] = h;
  2907. else if (!strcmp(cd.Name, "rot_vf3")) rot_mat[14] = h;
  2908. else if (!strcmp(cd.Name, "rot_vf4")) rot_mat[15] = h;
  2909. else if (!strcmp(cd.Name, "rot_uf1")) rot_mat[16] = h;
  2910. else if (!strcmp(cd.Name, "rot_uf2")) rot_mat[17] = h;
  2911. else if (!strcmp(cd.Name, "rot_uf3")) rot_mat[18] = h;
  2912. else if (!strcmp(cd.Name, "rot_uf4")) rot_mat[19] = h;
  2913. else if (!strcmp(cd.Name, "rot_rand1")) rot_mat[20] = h;
  2914. else if (!strcmp(cd.Name, "rot_rand2")) rot_mat[21] = h;
  2915. else if (!strcmp(cd.Name, "rot_rand3")) rot_mat[22] = h;
  2916. else if (!strcmp(cd.Name, "rot_rand4")) rot_mat[23] = h;
  2917. }
  2918. else if (cd.Class == D3DXPC_VECTOR)
  2919. {
  2920. if (!strcmp(cd.Name, "rand_frame")) rand_frame = h;
  2921. else if (!strcmp(cd.Name, "rand_preset")) rand_preset = h;
  2922. else if (!strncmp(cd.Name, "texsize_", 8))
  2923. {
  2924. // remove "texsize_" prefix to find root file name.
  2925. wchar_t szRootName[MAX_PATH];
  2926. if (!strncmp(cd.Name, "texsize_", 8))
  2927. lstrcpyW(szRootName, AutoWide(&cd.Name[8]));
  2928. else
  2929. lstrcpyW(szRootName, AutoWide(cd.Name));
  2930. // check for request for random texture.
  2931. // it should be a previously-seen random index - just fetch/reuse the name.
  2932. if (!wcsncmp(L"rand", szRootName, 4) &&
  2933. IsNumericChar(szRootName[4]) &&
  2934. IsNumericChar(szRootName[5]) &&
  2935. (szRootName[6]==0 || szRootName[6]==L'_') )
  2936. {
  2937. int rand_slot = -1;
  2938. // ditch filename prefix ("rand13_smalltiled", for example)
  2939. // and just go by the slot
  2940. if (szRootName[6]==L'_')
  2941. szRootName[6] = 0;
  2942. swscanf(&szRootName[4], L"%d", &rand_slot);
  2943. if (rand_slot >= 0 && rand_slot <= 15) // otherwise, not a special filename - ignore it
  2944. if (RandTexName[rand_slot].GetLength() > 0)
  2945. lstrcpyW(szRootName, RandTexName[rand_slot].c_str());
  2946. }
  2947. // see if <szRootName>.tga or .jpg has already been loaded.
  2948. bool bTexFound = false;
  2949. int N = g_plugin.m_textures.size();
  2950. for (int n=0; n<N; n++) {
  2951. if (!wcscmp(g_plugin.m_textures[n].texname, szRootName))
  2952. {
  2953. // found a match - texture was loaded
  2954. TexSizeParamInfo y;
  2955. y.texname = szRootName; //for debugging
  2956. y.texsize_param = h;
  2957. y.w = g_plugin.m_textures[n].w;
  2958. y.h = g_plugin.m_textures[n].h;
  2959. texsize_params.push_back(y);
  2960. bTexFound = true;
  2961. break;
  2962. }
  2963. }
  2964. if (!bTexFound)
  2965. {
  2966. wchar_t buf[1024];
  2967. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_UNABLE_TO_RESOLVE_TEXSIZE_FOR_A_TEXTURE_NOT_IN_USE), cd.Name);
  2968. g_plugin.AddError(buf, 6.0f, ERR_PRESET, true);
  2969. }
  2970. }
  2971. else if (cd.Name[0] == '_' && cd.Name[1] == 'c')
  2972. {
  2973. int z;
  2974. if (sscanf(&cd.Name[2], "%d", &z)==1)
  2975. if (z >= 0 && z < sizeof(const_handles)/sizeof(const_handles[0]))
  2976. const_handles[z] = h;
  2977. }
  2978. else if (cd.Name[0] == '_' && cd.Name[1] == 'q')
  2979. {
  2980. int z = cd.Name[2] - 'a';
  2981. if (z >= 0 && z < sizeof(q_const_handles)/sizeof(q_const_handles[0]))
  2982. q_const_handles[z] = h;
  2983. }
  2984. }
  2985. }
  2986. }
  2987. }
  2988. //----------------------------------------------------------------------
  2989. bool CPlugin::RecompileVShader(const char* szShadersText, VShaderInfo *si, int shaderType, bool bHardErrors)
  2990. {
  2991. SafeRelease(si->ptr);
  2992. ZeroMemory(si, sizeof(VShaderInfo));
  2993. // LOAD SHADER
  2994. if (!LoadShaderFromMemory( szShadersText, "VS", "vs_1_1", &si->CT, (void**)&si->ptr, shaderType, bHardErrors && (GetScreenMode()==WINDOWED)))
  2995. return false;
  2996. // Track down texture & float4 param bindings for this shader.
  2997. // Also loads any textures that need loaded.
  2998. si->params.CacheParams(si->CT, bHardErrors);
  2999. return true;
  3000. }
  3001. bool CPlugin::RecompilePShader(const char* szShadersText, PShaderInfo *si, int shaderType, bool bHardErrors, int PSVersion)
  3002. {
  3003. assert(m_nMaxPSVersion > 0);
  3004. SafeRelease(si->ptr);
  3005. ZeroMemory(si, sizeof(PShaderInfo));
  3006. // LOAD SHADER
  3007. // note: ps_1_4 required for dependent texture lookups.
  3008. // ps_2_0 required for tex2Dbias.
  3009. char ver[16];
  3010. lstrcpy(ver, "ps_0_0");
  3011. switch(PSVersion) {
  3012. case MD2_PS_NONE:
  3013. // Even though the PRESET doesn't use shaders, if MilkDrop is running where it CAN do shaders,
  3014. // we run all the old presets through (shader) emulation.
  3015. // This way, during a MilkDrop session, we are always calling either WarpedBlit() or WarpedBlit_NoPixelShaders(),
  3016. // and blending always works.
  3017. lstrcpy(ver, "ps_2_0");
  3018. break;
  3019. case MD2_PS_2_0: lstrcpy(ver, "ps_2_0"); break;
  3020. case MD2_PS_2_X: lstrcpy(ver, "ps_2_a"); break; // we'll try ps_2_a first, LoadShaderFromMemory will try ps_2_b if compilation fails
  3021. case MD2_PS_3_0: lstrcpy(ver, "ps_3_0"); break;
  3022. case MD2_PS_4_0: lstrcpy(ver, "ps_4_0"); break;
  3023. default: assert(0); break;
  3024. }
  3025. if (!LoadShaderFromMemory( szShadersText, "PS", ver, &si->CT, (void**)&si->ptr, shaderType, bHardErrors && (GetScreenMode()==WINDOWED)))
  3026. return false;
  3027. // Track down texture & float4 param bindings for this shader.
  3028. // Also loads any textures that need loaded.
  3029. si->params.CacheParams(si->CT, bHardErrors);
  3030. return true;
  3031. }
  3032. bool CPlugin::LoadShaders(PShaderSet* sh, CState* pState, bool bTick)
  3033. {
  3034. if (m_nMaxPSVersion <= 0)
  3035. return true;
  3036. // load one of the pixel shaders
  3037. if (!sh->warp.ptr && pState->m_nWarpPSVersion > 0)
  3038. {
  3039. bool bOK = RecompilePShader(pState->m_szWarpShadersText, &sh->warp, SHADER_WARP, false, pState->m_nWarpPSVersion);
  3040. if (!bOK)
  3041. {
  3042. // switch to fallback shader
  3043. m_fallbackShaders_ps.warp.ptr->AddRef();
  3044. m_fallbackShaders_ps.warp.CT->AddRef();
  3045. memcpy(&sh->warp, &m_fallbackShaders_ps.warp, sizeof(PShaderInfo));
  3046. // cancel any slow-preset-load
  3047. //m_nLoadingPreset = 1000;
  3048. }
  3049. if (bTick)
  3050. return true;
  3051. }
  3052. if (!sh->comp.ptr && pState->m_nCompPSVersion > 0)
  3053. {
  3054. bool bOK = RecompilePShader(pState->m_szCompShadersText, &sh->comp, SHADER_COMP, false, pState->m_nCompPSVersion);
  3055. if (!bOK)
  3056. {
  3057. // switch to fallback shader
  3058. m_fallbackShaders_ps.comp.ptr->AddRef();
  3059. m_fallbackShaders_ps.comp.CT->AddRef();
  3060. memcpy(&sh->comp, &m_fallbackShaders_ps.comp, sizeof(PShaderInfo));
  3061. // cancel any slow-preset-load
  3062. //m_nLoadingPreset = 1000;
  3063. }
  3064. }
  3065. return true;
  3066. }
  3067. //----------------------------------------------------------------------
  3068. /*
  3069. bool CPlugin::LoadShaderFromFile( char* szFile, char* szFn, char* szProfile,
  3070. LPD3DXCONSTANTTABLE* ppConstTable, void** ppShader )
  3071. {
  3072. LPD3DXBUFFER pShaderByteCode;
  3073. char buf[32768];
  3074. if (D3D_OK != D3DXCompileShaderFromFile(
  3075. szFile,
  3076. NULL,//CONST D3DXMACRO* pDefines,
  3077. NULL,//LPD3DXINCLUDE pInclude,
  3078. szFn,
  3079. szProfile,
  3080. m_dwShaderFlags,
  3081. &pShaderByteCode,
  3082. &m_pShaderCompileErrors,
  3083. ppConstTable
  3084. ))
  3085. {
  3086. sprintf(buf, "error compiling shader:\n");
  3087. lstrcat(buf, szFile);
  3088. if (m_pShaderCompileErrors->GetBufferSize() < sizeof(buf) - 256)
  3089. {
  3090. lstrcat(buf, "\n\n");
  3091. lstrcat(buf, (const char *)(m_pShaderCompileErrors->GetBufferPointer()));
  3092. }
  3093. dumpmsg(buf);
  3094. MessageBox(GetPluginWindow(), buf, "MILKDROP ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  3095. return false;
  3096. }
  3097. HRESULT hr = 1;
  3098. if (szProfile[0] == 'v')
  3099. hr = GetDevice()->CreateVertexShader((const unsigned long *)(pShaderByteCode->GetBufferPointer()), (IDirect3DVertexShader9**)ppShader);
  3100. else if (szProfile[0] == 'p')
  3101. hr = GetDevice()->CreatePixelShader((const unsigned long *)(pShaderByteCode->GetBufferPointer()), (IDirect3DPixelShader9**)ppShader);
  3102. if (hr != D3D_OK)
  3103. {
  3104. sprintf(buf, "error creating shader:\n");
  3105. lstrcat(buf, szFile);
  3106. dumpmsg(buf);
  3107. MessageBox(GetPluginWindow(), buf, "MILKDROP ERROR", MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  3108. return false;
  3109. }
  3110. pShaderByteCode->Release();
  3111. return true;
  3112. }
  3113. */
  3114. bool CPlugin::LoadShaderFromMemory( const char* szOrigShaderText, char* szFn, char* szProfile,
  3115. LPD3DXCONSTANTTABLE* ppConstTable, void** ppShader, int shaderType, bool bHardErrors )
  3116. {
  3117. const char szWarpDefines[] = "#define rad _rad_ang.x\n"
  3118. "#define ang _rad_ang.y\n"
  3119. "#define uv _uv.xy\n"
  3120. "#define uv_orig _uv.zw\n";
  3121. const char szCompDefines[] = "#define rad _rad_ang.x\n"
  3122. "#define ang _rad_ang.y\n"
  3123. "#define uv _uv.xy\n"
  3124. "#define uv_orig _uv.xy\n" //[sic]
  3125. "#define hue_shader _vDiffuse.xyz\n";
  3126. const char szWarpParams[] = "float4 _vDiffuse : COLOR, float4 _uv : TEXCOORD0, float2 _rad_ang : TEXCOORD1, out float4 _return_value : COLOR0";
  3127. const char szCompParams[] = "float4 _vDiffuse : COLOR, float2 _uv : TEXCOORD0, float2 _rad_ang : TEXCOORD1, out float4 _return_value : COLOR0";
  3128. const char szFirstLine[] = " float3 ret = 0;";
  3129. const char szLastLine[] = " _return_value = float4(ret.xyz, _vDiffuse.w);";
  3130. char szWhichShader[64];
  3131. switch(shaderType)
  3132. {
  3133. case SHADER_WARP: lstrcpy(szWhichShader, "warp"); break;
  3134. case SHADER_COMP: lstrcpy(szWhichShader, "composite"); break;
  3135. case SHADER_BLUR: lstrcpy(szWhichShader, "blur"); break;
  3136. case SHADER_OTHER: lstrcpy(szWhichShader, "(other)"); break;
  3137. default: lstrcpy(szWhichShader, "(unknown)"); break;
  3138. }
  3139. LPD3DXBUFFER pShaderByteCode;
  3140. wchar_t title[64];
  3141. *ppShader = NULL;
  3142. *ppConstTable = NULL;
  3143. char szShaderText[128000];
  3144. char temp[128000];
  3145. int writePos = 0;
  3146. // paste the universal #include
  3147. lstrcpy(&szShaderText[writePos], m_szShaderIncludeText); // first, paste in the contents of 'inputs.fx' before the actual shader text. Has 13's and 10's.
  3148. writePos += m_nShaderIncludeTextLen;
  3149. // paste in any custom #defines for this shader type
  3150. if (shaderType == SHADER_WARP && szProfile[0]=='p')
  3151. {
  3152. lstrcpy(&szShaderText[writePos], szWarpDefines);
  3153. writePos += lstrlen(szWarpDefines);
  3154. }
  3155. else if (shaderType == SHADER_COMP && szProfile[0]=='p')
  3156. {
  3157. lstrcpy(&szShaderText[writePos], szCompDefines);
  3158. writePos += lstrlen(szCompDefines);
  3159. }
  3160. // paste in the shader itself - converting LCC's to 13+10's.
  3161. // avoid lstrcpy b/c it might not handle the linefeed stuff...?
  3162. int shaderStartPos = writePos;
  3163. {
  3164. const char *s = szOrigShaderText;
  3165. char *d = &szShaderText[writePos];
  3166. while (*s)
  3167. {
  3168. if (*s == LINEFEED_CONTROL_CHAR)
  3169. {
  3170. *d++ = 13; writePos++;
  3171. *d++ = 10; writePos++;
  3172. }
  3173. else
  3174. {
  3175. *d++ = *s; writePos++;
  3176. }
  3177. s++;
  3178. }
  3179. *d = 0; writePos++;
  3180. }
  3181. // strip out all comments - but cheat a little - start at the shader test.
  3182. // (the include file was already stripped of comments)
  3183. StripComments(&szShaderText[shaderStartPos]);
  3184. /*{
  3185. char* p = szShaderText;
  3186. while (*p)
  3187. {
  3188. char buf[32];
  3189. buf[0] = *p;
  3190. buf[1] = 0;
  3191. OutputDebugString(buf);
  3192. if ((rand() % 9) == 0)
  3193. Sleep(1);
  3194. p++;
  3195. }
  3196. OutputDebugString("\n");
  3197. }/**/
  3198. //note: only do this stuff if type is WARP or COMP shader... not for blur, etc!
  3199. //FIXME - hints on the inputs / output / samplers etc.
  3200. // can go in the menu header, NOT the preset! =)
  3201. //then update presets
  3202. // -> be sure to update the presets on disk AND THE DEFAULT SHADERS (for loading MD1 presets)
  3203. //FIXME - then update auth. guide w/new examples,
  3204. // and a list of the invisible inputs (and one output) to each shader!
  3205. // warp: float2 uv, float2 uv_orig, rad, ang
  3206. // comp: float2 uv, rad, ang, float3 hue_shader
  3207. // test all this string code in Debug mode - make sure nothing bad is happening
  3208. /*
  3209. 1. paste warp or comp #defines
  3210. 2. search for "void" + whitespace + szFn + [whitespace] + '('
  3211. 3. insert params
  3212. 4. search for [whitespace] + ')'.
  3213. 5. search for final '}' (strrchr)
  3214. 6. back up one char, insert the Last Line, and add '}' and that's it.
  3215. */
  3216. if ((shaderType == SHADER_WARP || shaderType == SHADER_COMP) && szProfile[0]=='p')
  3217. {
  3218. char* p = &szShaderText[shaderStartPos];
  3219. // seek to 'shader_body' and replace it with spaces
  3220. while (*p && strncmp(p, "shader_body", 11))
  3221. p++;
  3222. if (p)
  3223. {
  3224. for (int i=0; i<11; i++)
  3225. *p++ = ' ';
  3226. }
  3227. if (p)
  3228. {
  3229. // insert "void PS(...params...)\n"
  3230. lstrcpy(temp, p);
  3231. const char *params = (shaderType==SHADER_WARP) ? szWarpParams : szCompParams;
  3232. sprintf(p, "void %s( %s )\n", szFn, params);
  3233. p += lstrlen(p);
  3234. lstrcpy(p, temp);
  3235. // find the starting curly brace
  3236. p = strchr(p, '{');
  3237. if (p)
  3238. {
  3239. // skip over it
  3240. p++;
  3241. // then insert "float3 ret = 0;"
  3242. lstrcpy(temp, p);
  3243. sprintf(p, "%s\n", szFirstLine);
  3244. p += lstrlen(p);
  3245. lstrcpy(p, temp);
  3246. // find the ending curly brace
  3247. p = strrchr(p, '}');
  3248. // add the last line - " _return_value = float4(ret.xyz, _vDiffuse.w);"
  3249. if (p)
  3250. sprintf(p, " %s\n}\n", szLastLine);
  3251. }
  3252. }
  3253. if (!p)
  3254. {
  3255. wchar_t temp[512];
  3256. swprintf(temp, WASABI_API_LNGSTRINGW(IDS_ERROR_PARSING_X_X_SHADER), szProfile, szWhichShader);
  3257. dumpmsg(temp);
  3258. AddError(temp, 8.0f, ERR_PRESET, true);
  3259. return false;
  3260. }
  3261. }
  3262. // now really try to compile it.
  3263. bool failed=false;
  3264. int len = lstrlen(szShaderText);
  3265. if (D3D_OK != pCompileShader(
  3266. szShaderText,
  3267. len,
  3268. NULL,//CONST D3DXMACRO* pDefines,
  3269. NULL,//LPD3DXINCLUDE pInclude,
  3270. szFn,
  3271. szProfile,
  3272. m_dwShaderFlags,
  3273. &pShaderByteCode,
  3274. &m_pShaderCompileErrors,
  3275. ppConstTable
  3276. ))
  3277. {
  3278. failed=true;
  3279. }
  3280. // before we totally fail, let's try using ps_2_b instead of ps_2_a
  3281. if (failed && !strcmp(szProfile, "ps_2_a"))
  3282. {
  3283. SafeRelease(m_pShaderCompileErrors);
  3284. if (D3D_OK == pCompileShader(szShaderText, len, NULL, NULL, szFn,
  3285. "ps_2_b", m_dwShaderFlags, &pShaderByteCode, &m_pShaderCompileErrors, ppConstTable))
  3286. {
  3287. failed=false;
  3288. }
  3289. }
  3290. if (failed)
  3291. {
  3292. wchar_t temp[1024];
  3293. swprintf(temp, WASABI_API_LNGSTRINGW(IDS_ERROR_COMPILING_X_X_SHADER), szProfile, szWhichShader);
  3294. if (m_pShaderCompileErrors && m_pShaderCompileErrors->GetBufferSize() < sizeof(temp) - 256)
  3295. {
  3296. lstrcatW(temp, L"\n\n");
  3297. lstrcatW(temp, AutoWide((char*)m_pShaderCompileErrors->GetBufferPointer()));
  3298. }
  3299. SafeRelease(m_pShaderCompileErrors);
  3300. dumpmsg(temp);
  3301. if (bHardErrors)
  3302. MessageBoxW(GetPluginWindow(), temp, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  3303. else {
  3304. AddError(temp, 8.0f, ERR_PRESET, true);
  3305. }
  3306. return false;
  3307. }
  3308. HRESULT hr = 1;
  3309. if (szProfile[0] == 'v')
  3310. {
  3311. hr = GetDevice()->CreateVertexShader((const unsigned long *)(pShaderByteCode->GetBufferPointer()), (IDirect3DVertexShader9**)ppShader);
  3312. }
  3313. else if (szProfile[0] == 'p')
  3314. {
  3315. hr = GetDevice()->CreatePixelShader((const unsigned long *)(pShaderByteCode->GetBufferPointer()), (IDirect3DPixelShader9**)ppShader);
  3316. }
  3317. if (hr != D3D_OK)
  3318. {
  3319. wchar_t temp[512];
  3320. WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_CREATING_SHADER,temp,sizeof(temp));
  3321. dumpmsg(temp);
  3322. if (bHardErrors)
  3323. MessageBoxW(GetPluginWindow(), temp, WASABI_API_LNGSTRINGW_BUF(IDS_MILKDROP_ERROR,title,64), MB_OK|MB_SETFOREGROUND|MB_TOPMOST );
  3324. else {
  3325. AddError(temp, 6.0f, ERR_PRESET, true);
  3326. }
  3327. return false;
  3328. }
  3329. pShaderByteCode->Release();
  3330. return true;
  3331. }
  3332. //----------------------------------------------------------------------
  3333. void CPlugin::CleanUpMyDX9Stuff(int final_cleanup)
  3334. {
  3335. // Clean up all your DX9 and D3DX textures, fonts, buffers, etc. here.
  3336. // EVERYTHING CREATED IN ALLOCATEMYDX9STUFF() SHOULD BE CLEANED UP HERE.
  3337. // The input parameter, 'final_cleanup', will be 0 if this is
  3338. // a routine cleanup (part of a window resize or switch between
  3339. // fullscr/windowed modes), or 1 if this is the final cleanup
  3340. // and the plugin is exiting. Note that even if it is a routine
  3341. // cleanup, *you still have to release ALL your DirectX stuff,
  3342. // because the DirectX device is being destroyed and recreated!*
  3343. // Also set all the pointers back to NULL;
  3344. // this is important because if we go to reallocate the DX9
  3345. // stuff later, and something fails, then CleanUp will get called,
  3346. // but it will then be trying to clean up invalid pointers.)
  3347. // The SafeRelease() and SafeDelete() macros make your code prettier;
  3348. // they are defined here in utility.h as follows:
  3349. // #define SafeRelease(x) if (x) {x->Release(); x=NULL;}
  3350. // #define SafeDelete(x) if (x) {delete x; x=NULL;}
  3351. // IMPORTANT:
  3352. // This function ISN'T only called when the plugin exits!
  3353. // It is also called whenever the user toggles between fullscreen and
  3354. // windowed modes, or resizes the window. Basically, on these events,
  3355. // the base class calls CleanUpMyDX9Stuff before Reset()ing the DirectX
  3356. // device, and then calls AllocateMyDX9Stuff afterwards.
  3357. // One funky thing here: if we're switching between fullscreen and windowed,
  3358. // or doing any other thing that causes all this stuff to get reloaded in a second,
  3359. // then if we were blending 2 presets, jump fully to the new preset.
  3360. // Otherwise the old preset wouldn't get all reloaded, and it app would crash
  3361. // when trying to use its stuff.
  3362. if (m_nLoadingPreset != 0) {
  3363. // finish up the pre-load & start the official blend
  3364. m_nLoadingPreset = 8;
  3365. LoadPresetTick();
  3366. }
  3367. // just force this:
  3368. m_pState->m_bBlending = false;
  3369. for ( TexInfo &l_texture : m_textures )
  3370. {
  3371. if ( l_texture.texptr )
  3372. {
  3373. // notify all CShaderParams classes that we're releasing a bindable texture!!
  3374. for ( CShaderParams *l_shader_param : global_CShaderParams_master_list )
  3375. l_shader_param->OnTextureEvict( l_texture.texptr );
  3376. SafeRelease( l_texture.texptr );
  3377. }
  3378. }
  3379. m_textures.clear();
  3380. // DON'T RELEASE blur textures - they were already released because they're in m_textures[].
  3381. #if (NUM_BLUR_TEX>0)
  3382. for (int i=0; i<NUM_BLUR_TEX; i++)
  3383. m_lpBlur[i] = NULL;//SafeRelease(m_lpBlur[i]);
  3384. #endif
  3385. // NOTE: not necessary; shell does this for us.
  3386. /*if (GetDevice())
  3387. {
  3388. GetDevice()->SetTexture(0, NULL);
  3389. GetDevice()->SetTexture(1, NULL);
  3390. }*/
  3391. SafeRelease(m_pSpriteVertDecl);
  3392. SafeRelease(m_pWfVertDecl);
  3393. SafeRelease(m_pMyVertDecl);
  3394. m_shaders.comp.Clear();
  3395. m_shaders.warp.Clear();
  3396. m_OldShaders.comp.Clear();
  3397. m_OldShaders.warp.Clear();
  3398. m_NewShaders.comp.Clear();
  3399. m_NewShaders.warp.Clear();
  3400. m_fallbackShaders_vs.comp.Clear();
  3401. m_fallbackShaders_ps.comp.Clear();
  3402. m_fallbackShaders_vs.warp.Clear();
  3403. m_fallbackShaders_ps.warp.Clear();
  3404. m_BlurShaders[0].vs.Clear();
  3405. m_BlurShaders[0].ps.Clear();
  3406. m_BlurShaders[1].vs.Clear();
  3407. m_BlurShaders[1].ps.Clear();
  3408. /*
  3409. SafeRelease( m_shaders.comp.ptr );
  3410. SafeRelease( m_shaders.warp.ptr );
  3411. SafeRelease( m_OldShaders.comp.ptr );
  3412. SafeRelease( m_OldShaders.warp.ptr );
  3413. SafeRelease( m_NewShaders.comp.ptr );
  3414. SafeRelease( m_NewShaders.warp.ptr );
  3415. SafeRelease( m_fallbackShaders_vs.comp.ptr );
  3416. SafeRelease( m_fallbackShaders_ps.comp.ptr );
  3417. SafeRelease( m_fallbackShaders_vs.warp.ptr );
  3418. SafeRelease( m_fallbackShaders_ps.warp.ptr );
  3419. */
  3420. SafeRelease( m_pShaderCompileErrors );
  3421. //SafeRelease( m_pCompiledFragments );
  3422. //SafeRelease( m_pFragmentLinker );
  3423. // 2. release stuff
  3424. SafeRelease(m_lpVS[0]);
  3425. SafeRelease(m_lpVS[1]);
  3426. SafeRelease(m_lpDDSTitle);
  3427. SafeRelease(m_d3dx_title_font_doublesize);
  3428. // NOTE: THIS CODE IS IN THE RIGHT PLACE.
  3429. if (m_gdi_title_font_doublesize)
  3430. {
  3431. DeleteObject(m_gdi_title_font_doublesize);
  3432. m_gdi_title_font_doublesize = NULL;
  3433. }
  3434. m_texmgr.Finish();
  3435. if (m_verts != NULL)
  3436. {
  3437. delete m_verts;
  3438. m_verts = NULL;
  3439. }
  3440. if (m_verts_temp != NULL)
  3441. {
  3442. delete m_verts_temp;
  3443. m_verts_temp = NULL;
  3444. }
  3445. if (m_vertinfo != NULL)
  3446. {
  3447. delete m_vertinfo;
  3448. m_vertinfo = NULL;
  3449. }
  3450. if (m_indices_list != NULL)
  3451. {
  3452. delete m_indices_list;
  3453. m_indices_list = NULL;
  3454. }
  3455. if (m_indices_strip != NULL)
  3456. {
  3457. delete m_indices_strip;
  3458. m_indices_strip = NULL;
  3459. }
  3460. ClearErrors();
  3461. // This setting is closely tied to the modern skin "random" button.
  3462. // The "random" state should be preserved from session to session.
  3463. // It's pretty safe to do, because the Scroll Lock key is hard to
  3464. // accidentally click... :)
  3465. WritePrivateProfileIntW(m_bPresetLockedByUser,L"bPresetLockOnAtStartup", GetConfigIniFile(),L"settings");
  3466. }
  3467. //----------------------------------------------------------------------
  3468. //----------------------------------------------------------------------
  3469. //----------------------------------------------------------------------
  3470. void CPlugin::MyRenderFn(int redraw)
  3471. {
  3472. EnterCriticalSection(&g_cs);
  3473. // Render a frame of animation here.
  3474. // This function is called each frame just AFTER BeginScene().
  3475. // For timing information, call 'GetTime()' and 'GetFps()'.
  3476. // The usual formula is like this (but doesn't have to be):
  3477. // 1. take care of timing/other paperwork/etc. for new frame
  3478. // 2. clear the background
  3479. // 3. get ready for 3D drawing
  3480. // 4. draw your 3D stuff
  3481. // 5. call PrepareFor2DDrawing()
  3482. // 6. draw your 2D stuff (overtop of your 3D scene)
  3483. // If the 'redraw' flag is 1, you should try to redraw
  3484. // the last frame; GetTime, GetFps, and GetFrame should
  3485. // all return the same values as they did on the last
  3486. // call to MyRenderFn(). Otherwise, the redraw flag will
  3487. // be zero, and you can draw a new frame. The flag is
  3488. // used to force the desktop to repaint itself when
  3489. // running in desktop mode and Winamp is paused or stopped.
  3490. // 1. take care of timing/other paperwork/etc. for new frame
  3491. if (!redraw)
  3492. {
  3493. float dt = GetTime() - m_prev_time;
  3494. m_prev_time = GetTime(); // note: m_prev_time is not for general use!
  3495. m_bPresetLockedByCode = (m_UI_mode != UI_REGULAR);
  3496. if (m_bPresetLockedByUser || m_bPresetLockedByCode)
  3497. {
  3498. // to freeze time (at current preset time value) when menus are up or Scroll Lock is on:
  3499. //m_fPresetStartTime += dt;
  3500. //m_fNextPresetTime += dt;
  3501. // OR, to freeze time @ [preset] zero, so that when you exit menus,
  3502. // you don't run the risk of it changing the preset on you right away:
  3503. m_fPresetStartTime = GetTime();
  3504. m_fNextPresetTime = -1.0f; // flags UpdateTime() to recompute this.
  3505. }
  3506. //if (!m_bPresetListReady)
  3507. // UpdatePresetList(true);//UpdatePresetRatings(); // read in a few each frame, til they're all in
  3508. }
  3509. // 2. check for lost or gained kb focus:
  3510. // (note: can't use wm_setfocus or wm_killfocus because they don't work w/embedwnd)
  3511. if (GetFrame()==0)
  3512. {
  3513. // NOTE: we skip this if we've already gotten a WM_COMMAND/ID_VIS_RANDOM message
  3514. // from the skin - if that happened, we're running windowed with a fancy
  3515. // skin with a 'rand' button.
  3516. SetScrollLock(m_bPresetLockOnAtStartup, m_bPreventScollLockHandling);
  3517. // make sure the 'random' button on the skin shows the right thing:
  3518. // NEVERMIND - if it's a fancy skin, it'll send us WM_COMMAND/ID_VIS_RANDOM
  3519. // and we'll match the skin's Random button state.
  3520. //SendMessage(GetWinampWindow(),WM_WA_IPC,m_bMilkdropScrollLockState, IPC_CB_VISRANDOM);
  3521. }
  3522. else
  3523. {
  3524. m_bHadFocus = m_bHasFocus;
  3525. HWND winamp = GetWinampWindow();
  3526. HWND plugin = GetPluginWindow();
  3527. HWND focus = GetFocus();
  3528. HWND cur = plugin;
  3529. m_bHasFocus = false;
  3530. do
  3531. {
  3532. m_bHasFocus = (focus == cur);
  3533. if (m_bHasFocus)
  3534. break;
  3535. cur = GetParent(cur);
  3536. }
  3537. while (cur != NULL && cur != winamp);
  3538. if (m_hTextWnd && focus==m_hTextWnd)
  3539. m_bHasFocus = 1;
  3540. if (GetFocus()==NULL)
  3541. m_bHasFocus = 0;
  3542. ;
  3543. //HWND t1 = GetFocus();
  3544. //HWND t2 = GetPluginWindow();
  3545. //HWND t3 = GetParent(t2);
  3546. if (m_bHadFocus==1 && m_bHasFocus==0)
  3547. {
  3548. //m_bMilkdropScrollLockState = GetKeyState(VK_SCROLL) & 1;
  3549. SetScrollLock(m_bOrigScrollLockState, m_bPreventScollLockHandling);
  3550. }
  3551. else if (m_bHadFocus==0 && m_bHasFocus==1)
  3552. {
  3553. m_bOrigScrollLockState = GetKeyState(VK_SCROLL) & 1;
  3554. SetScrollLock(m_bPresetLockedByUser, m_bPreventScollLockHandling);
  3555. }
  3556. }
  3557. if (!redraw)
  3558. {
  3559. GetWinampSongTitle(GetWinampWindow(), m_szSongTitle, sizeof(m_szSongTitle)-1);
  3560. if (wcscmp(m_szSongTitle, m_szSongTitlePrev))
  3561. {
  3562. lstrcpynW(m_szSongTitlePrev, m_szSongTitle, 512);
  3563. if (m_bSongTitleAnims)
  3564. LaunchSongTitleAnim();
  3565. }
  3566. }
  3567. // 2. Clear the background:
  3568. //DWORD clear_color = (m_fog_enabled) ? FOG_COLOR : 0xFF000000;
  3569. //GetDevice()->Clear(0, 0, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, clear_color, 1.0f, 0);
  3570. // 5. switch to 2D drawing mode. 2D coord system:
  3571. // +--------+ Y=-1
  3572. // | |
  3573. // | screen | Z=0: front of scene
  3574. // | | Z=1: back of scene
  3575. // +--------+ Y=1
  3576. // X=-1 X=1
  3577. PrepareFor2DDrawing(GetDevice());
  3578. if (!redraw)
  3579. DoCustomSoundAnalysis(); // emulates old pre-vms milkdrop sound analysis
  3580. RenderFrame(redraw); // see milkdropfs.cpp
  3581. /*
  3582. for (int i=0; i<10; i++)
  3583. {
  3584. RECT r;
  3585. r.top = GetHeight()*i/10;
  3586. r.left = 0;
  3587. r.right = GetWidth();
  3588. r.bottom = r.top + GetFontHeight(DECORATIVE_FONT);
  3589. char buf[256];
  3590. switch(i)
  3591. {
  3592. case 0: lstrcpy(buf, "this is a test"); break;
  3593. case 1: lstrcpy(buf, "argh"); break;
  3594. case 2: lstrcpy(buf, "!!"); break;
  3595. case 3: lstrcpy(buf, "TESTING FONTS"); break;
  3596. case 4: lstrcpy(buf, "rancid bear grease"); break;
  3597. case 5: lstrcpy(buf, "whoppers and ding dongs"); break;
  3598. case 6: lstrcpy(buf, "billy & joey"); break;
  3599. case 7: lstrcpy(buf, "."); break;
  3600. case 8: lstrcpy(buf, "---"); break;
  3601. case 9: lstrcpy(buf, "test"); break;
  3602. }
  3603. int t = (int)( 54 + 18*sin(i/10.0f*53.7f + 1) - 28*sin(i/10.0f*39.4f + 3) );
  3604. if (((GetFrame() + i*107) % t) < t*8/9)
  3605. m_text.QueueText(GetFont(DECORATIVE_FONT), buf, r, 0, 0xFFFF00FF);
  3606. }
  3607. /**/
  3608. if (!redraw)
  3609. {
  3610. m_nFramesSinceResize++;
  3611. if (m_nLoadingPreset > 0)
  3612. {
  3613. LoadPresetTick();
  3614. }
  3615. }
  3616. LeaveCriticalSection(&g_cs);
  3617. }
  3618. //----------------------------------------------------------------------
  3619. //----------------------------------------------------------------------
  3620. //----------------------------------------------------------------------
  3621. //----------------------------------------------------------------------
  3622. void CPlugin::DrawTooltip(wchar_t* str, int xR, int yB)
  3623. {
  3624. // draws a string in the lower-right corner of the screen.
  3625. // note: ID3DXFont handles DT_RIGHT and DT_BOTTOM *very poorly*.
  3626. // it is best to calculate the size of the text first,
  3627. // then place it in the right spot.
  3628. // note: use DT_WORDBREAK instead of DT_WORD_ELLIPSES, otherwise certain fonts'
  3629. // calcrect (for the dark box) will be wrong.
  3630. RECT r, r2;
  3631. SetRect(&r, 0, 0, xR-TEXT_MARGIN*2, 2048);
  3632. m_text.DrawTextW(GetFont(TOOLTIP_FONT), str, -1, &r, DT_CALCRECT, 0xFFFFFFFF, false);
  3633. r2.bottom = yB - TEXT_MARGIN;
  3634. r2.right = xR - TEXT_MARGIN;
  3635. r2.left = r2.right - (r.right-r.left);
  3636. r2.top = r2.bottom - (r.bottom-r.top);
  3637. RECT r3 = r2; r3.left -= 4; r3.top -= 2; r3.right += 2; r3.bottom += 2;
  3638. DrawDarkTranslucentBox(&r3);
  3639. m_text.DrawTextW(GetFont(TOOLTIP_FONT), str, -1, &r2, 0, 0xFFFFFFFF, false);
  3640. }
  3641. #define MTO_UPPER_RIGHT 0
  3642. #define MTO_UPPER_LEFT 1
  3643. #define MTO_LOWER_RIGHT 2
  3644. #define MTO_LOWER_LEFT 3
  3645. #define SelectFont(n) { \
  3646. pFont = GetFont(n); \
  3647. h = GetFontHeight(n); \
  3648. }
  3649. #define MyTextOut_BGCOLOR(str, corner, bDarkBox, boxColor) { \
  3650. SetRect(&r, 0, 0, xR-xL, 2048); \
  3651. m_text.DrawTextW(pFont, str, -1, &r, DT_NOPREFIX | ((corner == MTO_UPPER_RIGHT)?0:DT_SINGLELINE) | DT_WORD_ELLIPSIS | DT_CALCRECT | ((corner == MTO_UPPER_RIGHT) ? DT_RIGHT : 0), 0xFFFFFFFF, false, boxColor); \
  3652. int w = r.right - r.left; \
  3653. if (corner == MTO_UPPER_LEFT ) SetRect(&r, xL, *upper_left_corner_y, xL+w, *upper_left_corner_y + h); \
  3654. else if (corner == MTO_UPPER_RIGHT) SetRect(&r, xR-w, *upper_right_corner_y, xR, *upper_right_corner_y + h); \
  3655. else if (corner == MTO_LOWER_LEFT ) SetRect(&r, xL, *lower_left_corner_y - h, xL+w, *lower_left_corner_y); \
  3656. else if (corner == MTO_LOWER_RIGHT) SetRect(&r, xR-w, *lower_right_corner_y - h, xR, *lower_right_corner_y); \
  3657. m_text.DrawTextW(pFont, str, -1, &r, DT_NOPREFIX | ((corner == MTO_UPPER_RIGHT)?0:DT_SINGLELINE) | DT_WORD_ELLIPSIS | ((corner == MTO_UPPER_RIGHT) ? DT_RIGHT: 0), 0xFFFFFFFF, bDarkBox, boxColor); \
  3658. if (corner == MTO_UPPER_LEFT ) *upper_left_corner_y += h; \
  3659. else if (corner == MTO_UPPER_RIGHT) *upper_right_corner_y += h; \
  3660. else if (corner == MTO_LOWER_LEFT ) *lower_left_corner_y -= h; \
  3661. else if (corner == MTO_LOWER_RIGHT) *lower_right_corner_y -= h; \
  3662. }
  3663. #define MyTextOut(str, corner, bDarkBox) MyTextOut_BGCOLOR(str, corner, bDarkBox, 0xFF000000)
  3664. #define MyTextOut_Shadow(str, corner) { \
  3665. /* calc rect size */ \
  3666. SetRect(&r, 0, 0, xR-xL, 2048); \
  3667. m_text.DrawTextW(pFont, (wchar_t*)str, -1, &r, DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_CALCRECT, 0xFFFFFFFF, false, 0xFF000000); \
  3668. int w = r.right - r.left; \
  3669. /* first the shadow */ \
  3670. if (corner == MTO_UPPER_LEFT ) SetRect(&r, xL, *upper_left_corner_y, xL+w, *upper_left_corner_y + h); \
  3671. else if (corner == MTO_UPPER_RIGHT) SetRect(&r, xR-w, *upper_right_corner_y, xR, *upper_right_corner_y + h); \
  3672. else if (corner == MTO_LOWER_LEFT ) SetRect(&r, xL, *lower_left_corner_y - h, xL+w, *lower_left_corner_y); \
  3673. else if (corner == MTO_LOWER_RIGHT) SetRect(&r, xR-w, *lower_right_corner_y - h, xR, *lower_right_corner_y); \
  3674. r.top += 1; r.left += 1; \
  3675. m_text.DrawTextW(pFont, (wchar_t*)str, -1, &r, DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS, 0xFF000000, false, 0xFF000000); \
  3676. /* now draw real text */ \
  3677. r.top -= 1; r.left -= 1; \
  3678. m_text.DrawTextW(pFont, (wchar_t*)str, -1, &r, DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS, 0xFFFFFFFF, false, 0xFF000000); \
  3679. if (corner == MTO_UPPER_LEFT ) *upper_left_corner_y += h; \
  3680. else if (corner == MTO_UPPER_RIGHT) *upper_right_corner_y += h; \
  3681. else if (corner == MTO_LOWER_LEFT ) *lower_left_corner_y -= h; \
  3682. else if (corner == MTO_LOWER_RIGHT) *lower_right_corner_y -= h; \
  3683. }
  3684. void CPlugin::OnAltK()
  3685. {
  3686. AddError(WASABI_API_LNGSTRINGW(IDS_PLEASE_EXIT_VIS_BEFORE_RUNNING_CONFIG_PANEL), 3.0f, ERR_NOTIFY, true);
  3687. }
  3688. void CPlugin::AddError(wchar_t* szMsg, float fDuration, int category, bool bBold)
  3689. {
  3690. if (category == ERR_NOTIFY)
  3691. ClearErrors(category);
  3692. assert(category != ERR_ALL);
  3693. ErrorMsg x;
  3694. x.msg = szMsg;
  3695. x.birthTime = GetTime();
  3696. x.expireTime = GetTime() + fDuration;
  3697. x.category = category;
  3698. x.bBold = bBold;
  3699. m_errors.push_back(x);
  3700. }
  3701. void CPlugin::ClearErrors(int category) // 0=all categories
  3702. {
  3703. int N = m_errors.size();
  3704. for (int i = 0; i < N; i++)
  3705. {
  3706. if (category == ERR_ALL || m_errors[i].category == category)
  3707. {
  3708. m_errors.erase(m_errors.begin() + i);
  3709. i--;
  3710. N--;
  3711. }
  3712. }
  3713. }
  3714. void CPlugin::MyRenderUI(
  3715. int *upper_left_corner_y, // increment me!
  3716. int *upper_right_corner_y, // increment me!
  3717. int *lower_left_corner_y, // decrement me!
  3718. int *lower_right_corner_y, // decrement me!
  3719. int xL,
  3720. int xR
  3721. )
  3722. {
  3723. // draw text messages directly to the back buffer.
  3724. // when you draw text into one of the four corners,
  3725. // draw the text at the current 'y' value for that corner
  3726. // (one of the first 4 params to this function),
  3727. // and then adjust that y value so that the next time
  3728. // text is drawn in that corner, it gets drawn above/below
  3729. // the previous text (instead of overtop of it).
  3730. // when drawing into the upper or lower LEFT corners,
  3731. // left-align your text to 'xL'.
  3732. // when drawing into the upper or lower RIGHT corners,
  3733. // right-align your text to 'xR'.
  3734. // note: try to keep the bounding rectangles on the text small;
  3735. // the smaller the area that has to be locked (to draw the text),
  3736. // the faster it will be. (on some cards, drawing text is
  3737. // ferociously slow, so even if it works okay on yours, it might
  3738. // not work on another video card.)
  3739. // note: if you want some text to be on the screen often, and the text
  3740. // won't be changing every frame, please consider the poor folks
  3741. // whose video cards hate that; in that case you should probably
  3742. // draw the text just once, to a texture, and then display the
  3743. // texture each frame. This is how the help screen is done; see
  3744. // pluginshell.cpp for example code.
  3745. RECT r = {0};
  3746. wchar_t buf[512] = {0};
  3747. LPD3DXFONT pFont = GetFont(DECORATIVE_FONT);
  3748. int h = GetFontHeight(DECORATIVE_FONT);
  3749. if (!pFont)
  3750. return;
  3751. if (!GetFont(DECORATIVE_FONT))
  3752. return;
  3753. // 1. render text in upper-right corner - EXCEPT USER MESSAGE - it goes last b/c it draws a box under itself
  3754. // and it should be visible over everything else (usually an error msg)
  3755. {
  3756. // a) preset name
  3757. if (m_bShowPresetInfo)
  3758. {
  3759. SelectFont(DECORATIVE_FONT);
  3760. swprintf(buf, L"%s ", (m_nLoadingPreset != 0) ? m_pNewState->m_szDesc : m_pState->m_szDesc);
  3761. MyTextOut_Shadow(buf, MTO_UPPER_RIGHT);
  3762. }
  3763. // b) preset rating
  3764. if (m_bShowRating || GetTime() < m_fShowRatingUntilThisTime)
  3765. {
  3766. // see also: SetCurrentPresetRating() in milkdrop.cpp
  3767. SelectFont(DECORATIVE_FONT);
  3768. swprintf(buf, L" %s: %d ", WASABI_API_LNGSTRINGW(IDS_RATING), (int)m_pState->m_fRating);
  3769. if (!m_bEnableRating) lstrcatW(buf, WASABI_API_LNGSTRINGW(IDS_DISABLED));
  3770. MyTextOut_Shadow(buf, MTO_UPPER_RIGHT);
  3771. }
  3772. // c) fps display
  3773. if (m_bShowFPS)
  3774. {
  3775. SelectFont(DECORATIVE_FONT);
  3776. swprintf(buf, L"%s: %4.2f ", WASABI_API_LNGSTRINGW(IDS_FPS), GetFps()); // leave extra space @ end, so italicized fonts don't get clipped
  3777. MyTextOut_Shadow(buf, MTO_UPPER_RIGHT);
  3778. }
  3779. // d) debug information
  3780. if (m_bShowDebugInfo)
  3781. {
  3782. SelectFont(SIMPLE_FONT);
  3783. swprintf(buf, L" %s: %6.4f ", WASABI_API_LNGSTRINGW(IDS_PF_MONITOR), (float)(*m_pState->var_pf_monitor));
  3784. MyTextOut_Shadow(buf, MTO_UPPER_RIGHT);
  3785. }
  3786. // NOTE: custom timed msg comes at the end!!
  3787. }
  3788. // 2. render text in lower-right corner
  3789. {
  3790. // waitstring tooltip:
  3791. if (m_waitstring.bActive && m_bShowMenuToolTips && m_waitstring.szToolTip[0])
  3792. {
  3793. DrawTooltip(m_waitstring.szToolTip, xR, *lower_right_corner_y);
  3794. }
  3795. }
  3796. // 3. render text in lower-left corner
  3797. {
  3798. wchar_t buf2[512] = {0};
  3799. wchar_t buf3[512+1] = {0}; // add two extra spaces to end, so italicized fonts don't get clipped
  3800. // render song title in lower-left corner:
  3801. if (m_bShowSongTitle)
  3802. {
  3803. wchar_t buf4[512] = {0};
  3804. SelectFont(DECORATIVE_FONT);
  3805. GetWinampSongTitle(GetWinampWindow(), buf4, sizeof(buf4)); // defined in utility.h/cpp
  3806. MyTextOut_Shadow(buf4, MTO_LOWER_LEFT);
  3807. }
  3808. // render song time & len above that:
  3809. if (m_bShowSongTime || m_bShowSongLen)
  3810. {
  3811. GetWinampSongPosAsText(GetWinampWindow(), buf); // defined in utility.h/cpp
  3812. GetWinampSongLenAsText(GetWinampWindow(), buf2); // defined in utility.h/cpp
  3813. if (m_bShowSongTime && m_bShowSongLen)
  3814. {
  3815. // only show playing position and track length if it is playing (buffer is valid)
  3816. if(buf[0])
  3817. swprintf(buf3, L"%s / %s ", buf, buf2);
  3818. else
  3819. lstrcpynW(buf3, buf2, 512);
  3820. }
  3821. else if (m_bShowSongTime)
  3822. lstrcpynW(buf3, buf, 512);
  3823. else
  3824. lstrcpynW(buf3, buf2, 512);
  3825. SelectFont(DECORATIVE_FONT);
  3826. MyTextOut_Shadow(buf3, MTO_LOWER_LEFT);
  3827. }
  3828. }
  3829. // 4. render text in upper-left corner
  3830. {
  3831. wchar_t buf[64000] = {0}; // must fit the longest strings (code strings are 32768 chars)
  3832. // AND leave extra space for &->&&, and [,[,& insertion
  3833. char bufA[64000] = {0};
  3834. SelectFont(SIMPLE_FONT);
  3835. // stuff for loading presets, menus, etc:
  3836. if (m_waitstring.bActive)
  3837. {
  3838. // 1. draw the prompt string
  3839. MyTextOut(m_waitstring.szPrompt, MTO_UPPER_LEFT, true);
  3840. // extra instructions:
  3841. bool bIsWarp = m_waitstring.bDisplayAsCode && (m_pCurMenu == &m_menuPreset) && !wcscmp(m_menuPreset.GetCurItem()->m_szName, L"[ edit warp shader ]");
  3842. bool bIsComp = m_waitstring.bDisplayAsCode && (m_pCurMenu == &m_menuPreset) && !wcscmp(m_menuPreset.GetCurItem()->m_szName, L"[ edit composite shader ]");
  3843. if (bIsWarp || bIsComp)
  3844. {
  3845. if (m_bShowShaderHelp) {
  3846. MyTextOut(WASABI_API_LNGSTRINGW(IDS_PRESS_F9_TO_HIDE_SHADER_QREF), MTO_UPPER_LEFT, true);
  3847. }
  3848. else {
  3849. MyTextOut(WASABI_API_LNGSTRINGW(IDS_PRESS_F9_TO_SHOW_SHADER_QREF), MTO_UPPER_LEFT, true);
  3850. }
  3851. *upper_left_corner_y += h*2/3;
  3852. if (m_bShowShaderHelp)
  3853. {
  3854. // draw dark box - based on longest line & # lines...
  3855. SetRect(&r, 0, 0, 2048, 2048);
  3856. m_text.DrawTextW(pFont, WASABI_API_LNGSTRINGW(IDS_STRING615), -1, &r, DT_NOPREFIX | DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_CALCRECT, 0xFFFFFFFF, false, 0xFF000000);
  3857. RECT darkbox;
  3858. SetRect(&darkbox, xL, *upper_left_corner_y-2, xL+r.right-r.left, *upper_left_corner_y + (r.bottom-r.top)*13 + 2);
  3859. DrawDarkTranslucentBox(&darkbox);
  3860. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING616), MTO_UPPER_LEFT, false);
  3861. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING617), MTO_UPPER_LEFT, false);
  3862. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING618), MTO_UPPER_LEFT, false);
  3863. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING619), MTO_UPPER_LEFT, false);
  3864. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING620), MTO_UPPER_LEFT, false);
  3865. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING621), MTO_UPPER_LEFT, false);
  3866. if (bIsWarp)
  3867. {
  3868. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING622), MTO_UPPER_LEFT, false);
  3869. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING623), MTO_UPPER_LEFT, false);
  3870. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING624), MTO_UPPER_LEFT, false);
  3871. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING625), MTO_UPPER_LEFT, false);
  3872. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING626), MTO_UPPER_LEFT, false);
  3873. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING627), MTO_UPPER_LEFT, false);
  3874. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING628), MTO_UPPER_LEFT, false);
  3875. }
  3876. else if (bIsComp)
  3877. {
  3878. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING629), MTO_UPPER_LEFT, false);
  3879. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING630), MTO_UPPER_LEFT, false);
  3880. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING631), MTO_UPPER_LEFT, false);
  3881. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING632), MTO_UPPER_LEFT, false);
  3882. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING633), MTO_UPPER_LEFT, false);
  3883. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING634), MTO_UPPER_LEFT, false);
  3884. MyTextOut(WASABI_API_LNGSTRINGW(IDS_STRING635), MTO_UPPER_LEFT, false);
  3885. }
  3886. *upper_left_corner_y += h*2/3;
  3887. }
  3888. }
  3889. else if (m_UI_mode == UI_SAVEAS && (m_bWarpShaderLock || m_bCompShaderLock))
  3890. {
  3891. wchar_t buf[256] = {0};
  3892. int shader_msg_id = IDS_COMPOSITE_SHADER_LOCKED;
  3893. if (m_bWarpShaderLock && m_bCompShaderLock)
  3894. shader_msg_id = IDS_WARP_AND_COMPOSITE_SHADERS_LOCKED;
  3895. else if (m_bWarpShaderLock && !m_bCompShaderLock)
  3896. shader_msg_id = IDS_WARP_SHADER_LOCKED;
  3897. else
  3898. shader_msg_id = IDS_COMPOSITE_SHADER_LOCKED;
  3899. WASABI_API_LNGSTRINGW_BUF(shader_msg_id, buf, 256);
  3900. MyTextOut_BGCOLOR(buf, MTO_UPPER_LEFT, true, 0xFF000000);
  3901. *upper_left_corner_y += h*2/3;
  3902. }
  3903. else
  3904. *upper_left_corner_y += h*2/3;
  3905. // 2. reformat the waitstring text for display
  3906. int bBrackets = m_waitstring.nSelAnchorPos != -1 && m_waitstring.nSelAnchorPos != m_waitstring.nCursorPos;
  3907. int bCursorBlink = ( !bBrackets &&
  3908. ((int)(GetTime()*270.0f) % 100 > 50)
  3909. //((GetFrame() % 3) >= 2)
  3910. );
  3911. lstrcpyW(buf, m_waitstring.szText);
  3912. lstrcpyA(bufA, (char*)m_waitstring.szText);
  3913. int temp_cursor_pos = m_waitstring.nCursorPos;
  3914. int temp_anchor_pos = m_waitstring.nSelAnchorPos;
  3915. if (bBrackets)
  3916. {
  3917. if (m_waitstring.bDisplayAsCode)
  3918. {
  3919. // insert [] around the selection
  3920. int start = (temp_cursor_pos < temp_anchor_pos) ? temp_cursor_pos : temp_anchor_pos;
  3921. int end = (temp_cursor_pos > temp_anchor_pos) ? temp_cursor_pos - 1 : temp_anchor_pos - 1;
  3922. int len = lstrlenA(bufA);
  3923. int i;
  3924. for (i=len; i>end; i--)
  3925. bufA[i+1] = bufA[i];
  3926. bufA[end+1] = ']';
  3927. len++;
  3928. for (i=len; i>=start; i--)
  3929. bufA[i+1] = bufA[i];
  3930. bufA[start] = '[';
  3931. len++;
  3932. }
  3933. else
  3934. {
  3935. // insert [] around the selection
  3936. int start = (temp_cursor_pos < temp_anchor_pos) ? temp_cursor_pos : temp_anchor_pos;
  3937. int end = (temp_cursor_pos > temp_anchor_pos) ? temp_cursor_pos - 1 : temp_anchor_pos - 1;
  3938. int len = lstrlenW(buf);
  3939. int i;
  3940. for (i=len; i>end; i--)
  3941. buf[i+1] = buf[i];
  3942. buf[end+1] = L']';
  3943. len++;
  3944. for (i=len; i>=start; i--)
  3945. buf[i+1] = buf[i];
  3946. buf[start] = L'[';
  3947. len++;
  3948. }
  3949. }
  3950. else
  3951. {
  3952. // underline the current cursor position by rapidly toggling the character with an underscore
  3953. if (m_waitstring.bDisplayAsCode)
  3954. {
  3955. if (bCursorBlink)
  3956. {
  3957. if (bufA[temp_cursor_pos] == 0)
  3958. {
  3959. bufA[temp_cursor_pos] = '_';
  3960. bufA[temp_cursor_pos+1] = 0;
  3961. }
  3962. else if (bufA[temp_cursor_pos] == LINEFEED_CONTROL_CHAR)
  3963. {
  3964. for (int i=strlen(bufA); i>=temp_cursor_pos; i--)
  3965. bufA[i+1] = bufA[i];
  3966. bufA[temp_cursor_pos] = '_';
  3967. }
  3968. else if (bufA[temp_cursor_pos] == '_')
  3969. bufA[temp_cursor_pos] = ' ';
  3970. else // it's a space or symbol or alphanumeric.
  3971. bufA[temp_cursor_pos] = '_';
  3972. }
  3973. else
  3974. {
  3975. if (bufA[temp_cursor_pos] == 0)
  3976. {
  3977. bufA[temp_cursor_pos] = ' ';
  3978. bufA[temp_cursor_pos+1] = 0;
  3979. }
  3980. else if (bufA[temp_cursor_pos] == LINEFEED_CONTROL_CHAR)
  3981. {
  3982. for (int i=strlen(bufA); i>=temp_cursor_pos; i--)
  3983. bufA[i+1] = bufA[i];
  3984. bufA[temp_cursor_pos] = ' ';
  3985. }
  3986. //else if (buf[temp_cursor_pos] == '_')
  3987. // do nothing
  3988. //else // it's a space or symbol or alphanumeric.
  3989. // do nothing
  3990. }
  3991. }
  3992. else
  3993. {
  3994. if (bCursorBlink)
  3995. {
  3996. if (buf[temp_cursor_pos] == 0)
  3997. {
  3998. buf[temp_cursor_pos] = L'_';
  3999. buf[temp_cursor_pos+1] = 0;
  4000. }
  4001. else if (buf[temp_cursor_pos] == LINEFEED_CONTROL_CHAR)
  4002. {
  4003. for (int i=wcslen(buf); i>=temp_cursor_pos; i--)
  4004. buf[i+1] = buf[i];
  4005. buf[temp_cursor_pos] = L'_';
  4006. }
  4007. else if (buf[temp_cursor_pos] == L'_')
  4008. buf[temp_cursor_pos] = L' ';
  4009. else // it's a space or symbol or alphanumeric.
  4010. buf[temp_cursor_pos] = L'_';
  4011. }
  4012. else
  4013. {
  4014. if (buf[temp_cursor_pos] == 0)
  4015. {
  4016. buf[temp_cursor_pos] = L' ';
  4017. buf[temp_cursor_pos+1] = 0;
  4018. }
  4019. else if (buf[temp_cursor_pos] == LINEFEED_CONTROL_CHAR)
  4020. {
  4021. for (int i=wcslen(buf); i>=temp_cursor_pos; i--)
  4022. buf[i+1] = buf[i];
  4023. buf[temp_cursor_pos] = L' ';
  4024. }
  4025. //else if (buf[temp_cursor_pos] == '_')
  4026. // do nothing
  4027. //else // it's a space or symbol or alphanumeric.
  4028. // do nothing
  4029. }
  4030. }
  4031. }
  4032. RECT rect = {0};
  4033. SetRect(&rect, xL, *upper_left_corner_y, xR, *lower_left_corner_y);
  4034. rect.top += PLAYLIST_INNER_MARGIN;
  4035. rect.left += PLAYLIST_INNER_MARGIN;
  4036. rect.right -= PLAYLIST_INNER_MARGIN;
  4037. rect.bottom -= PLAYLIST_INNER_MARGIN;
  4038. // then draw the edit string
  4039. if (m_waitstring.bDisplayAsCode)
  4040. {
  4041. char buf2[8192] = {0};
  4042. int top_of_page_pos = 0;
  4043. // compute top_of_page_pos so that the line the cursor is on will show.
  4044. // also compute dims of the black rectangle while we're at it.
  4045. {
  4046. int start = 0;
  4047. int pos = 0;
  4048. int ypixels = 0;
  4049. int page = 1;
  4050. int exit_on_next_page = 0;
  4051. RECT box = rect;
  4052. box.right = box.left;
  4053. box.bottom = box.top;
  4054. while (bufA[pos] != 0) // for each line of text... (note that it might wrap)
  4055. {
  4056. start = pos;
  4057. while (bufA[pos] != LINEFEED_CONTROL_CHAR && bufA[pos] != 0)
  4058. pos++;
  4059. char ch = bufA[pos];
  4060. bufA[pos] = 0;
  4061. sprintf(buf2, " %sX", &bufA[start]); // put a final 'X' instead of ' ' b/c CALCRECT returns w==0 if string is entirely whitespace!
  4062. RECT r2 = rect;
  4063. r2.bottom = 4096;
  4064. m_text.DrawTextA(GetFont(SIMPLE_FONT), buf2, -1, &r2, DT_CALCRECT /*| DT_WORDBREAK*/, 0xFFFFFFFF, false);
  4065. int h = r2.bottom-r2.top;
  4066. ypixels += h;
  4067. bufA[pos] = ch;
  4068. if (start > m_waitstring.nCursorPos) // make sure 'box' gets updated for each line on this page
  4069. exit_on_next_page = 1;
  4070. if (ypixels > rect.bottom-rect.top) // this line belongs on the next page
  4071. {
  4072. if (exit_on_next_page)
  4073. {
  4074. bufA[start] = 0; // so text stops where the box stops, when we draw the text
  4075. break;
  4076. }
  4077. ypixels = h;
  4078. top_of_page_pos = start;
  4079. page++;
  4080. box = rect;
  4081. box.right = box.left;
  4082. box.bottom = box.top;
  4083. }
  4084. box.bottom += h;
  4085. box.right = max(box.right, box.left + r2.right-r2.left);
  4086. if (bufA[pos]==0)
  4087. break;
  4088. pos++;
  4089. }
  4090. // use r2 to draw a dark box:
  4091. box.top -= PLAYLIST_INNER_MARGIN;
  4092. box.left -= PLAYLIST_INNER_MARGIN;
  4093. box.right += PLAYLIST_INNER_MARGIN;
  4094. box.bottom += PLAYLIST_INNER_MARGIN;
  4095. DrawDarkTranslucentBox(&box);
  4096. *upper_left_corner_y += box.bottom - box.top + PLAYLIST_INNER_MARGIN*3;
  4097. swprintf(m_waitstring.szToolTip, WASABI_API_LNGSTRINGW(IDS_PAGE_X), page);
  4098. }
  4099. // display multiline (replace all character 13's with a CR)
  4100. {
  4101. int start = top_of_page_pos;
  4102. int pos = top_of_page_pos;
  4103. while (bufA[pos] != 0)
  4104. {
  4105. while (bufA[pos] != LINEFEED_CONTROL_CHAR && bufA[pos] != 0)
  4106. pos++;
  4107. char ch = bufA[pos];
  4108. bufA[pos] = 0;
  4109. sprintf(buf2, " %s ", &bufA[start]);
  4110. DWORD color = MENU_COLOR;
  4111. if (m_waitstring.nCursorPos >= start && m_waitstring.nCursorPos <= pos)
  4112. color = MENU_HILITE_COLOR;
  4113. rect.top += m_text.DrawTextA(GetFont(SIMPLE_FONT), buf2, -1, &rect, 0/*DT_WORDBREAK*/, color, false);
  4114. bufA[pos] = ch;
  4115. if (rect.top > rect.bottom)
  4116. break;
  4117. if (bufA[pos] != 0) pos++;
  4118. start = pos;
  4119. }
  4120. }
  4121. // note: *upper_left_corner_y is updated above, when the dark box is drawn.
  4122. }
  4123. else
  4124. {
  4125. wchar_t buf2[8192] = {0};
  4126. // display on one line
  4127. RECT box = rect;
  4128. box.bottom = 4096;
  4129. swprintf(buf2, L" %sX", buf); // put a final 'X' instead of ' ' b/c CALCRECT returns w==0 if string is entirely whitespace!
  4130. m_text.DrawTextW(GetFont(SIMPLE_FONT), buf2, -1, &box, DT_CALCRECT, MENU_COLOR, false );
  4131. // use r2 to draw a dark box:
  4132. box.top -= PLAYLIST_INNER_MARGIN;
  4133. box.left -= PLAYLIST_INNER_MARGIN;
  4134. box.right += PLAYLIST_INNER_MARGIN;
  4135. box.bottom += PLAYLIST_INNER_MARGIN;
  4136. DrawDarkTranslucentBox(&box);
  4137. *upper_left_corner_y += box.bottom - box.top + PLAYLIST_INNER_MARGIN*3;
  4138. swprintf(buf2, L" %s ", buf);
  4139. m_text.DrawTextW(GetFont(SIMPLE_FONT), buf2, -1, &rect, 0, MENU_COLOR, false );
  4140. }
  4141. }
  4142. else if (m_UI_mode == UI_MENU)
  4143. {
  4144. assert(m_pCurMenu);
  4145. SetRect(&r, xL, *upper_left_corner_y, xR, *lower_left_corner_y);
  4146. RECT darkbox = {0};
  4147. m_pCurMenu->DrawMenu(r, xR, *lower_right_corner_y, 1, &darkbox);
  4148. *upper_left_corner_y += darkbox.bottom - darkbox.top + PLAYLIST_INNER_MARGIN*3;
  4149. darkbox.right += PLAYLIST_INNER_MARGIN*2;
  4150. darkbox.bottom += PLAYLIST_INNER_MARGIN*2;
  4151. DrawDarkTranslucentBox(&darkbox);
  4152. r.top += PLAYLIST_INNER_MARGIN;
  4153. r.left += PLAYLIST_INNER_MARGIN;
  4154. r.right += PLAYLIST_INNER_MARGIN;
  4155. r.bottom += PLAYLIST_INNER_MARGIN;
  4156. m_pCurMenu->DrawMenu(r, xR, *lower_right_corner_y);
  4157. }
  4158. else if (m_UI_mode == UI_UPGRADE_PIXEL_SHADER)
  4159. {
  4160. RECT rect = {0};
  4161. SetRect(&rect, xL, *upper_left_corner_y, xR, *lower_left_corner_y);
  4162. if (m_pState->m_nWarpPSVersion >= m_nMaxPSVersion &&
  4163. m_pState->m_nCompPSVersion >= m_nMaxPSVersion)
  4164. {
  4165. assert(m_pState->m_nMaxPSVersion == m_nMaxPSVersion);
  4166. wchar_t buf[1024] = {0};
  4167. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_PRESET_USES_HIGHEST_PIXEL_SHADER_VERSION), m_nMaxPSVersion);
  4168. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), buf, -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4169. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESS_ESC_TO_RETURN), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4170. }
  4171. else
  4172. {
  4173. if (m_pState->m_nMinPSVersion != m_pState->m_nMaxPSVersion)
  4174. {
  4175. switch(m_pState->m_nMinPSVersion)
  4176. {
  4177. case MD2_PS_NONE:
  4178. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_HAS_MIXED_VERSIONS_OF_SHADERS), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4179. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_SHADERS_TO_USE_PS2), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4180. break;
  4181. case MD2_PS_2_0:
  4182. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_HAS_MIXED_VERSIONS_OF_SHADERS), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4183. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_SHADERS_TO_USE_PS2X), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4184. break;
  4185. case MD2_PS_2_X:
  4186. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_HAS_MIXED_VERSIONS_OF_SHADERS), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4187. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_SHADERS_TO_USE_PS3), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4188. break;
  4189. case MD2_PS_3_0:
  4190. assert(false);
  4191. break;
  4192. default:
  4193. assert(0);
  4194. break;
  4195. }
  4196. }
  4197. else
  4198. {
  4199. switch(m_pState->m_nMinPSVersion)
  4200. {
  4201. case MD2_PS_NONE:
  4202. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_DOES_NOT_USE_PIXEL_SHADERS), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4203. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_TO_USE_PS2), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4204. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_WARNING_OLD_GPU_MIGHT_NOT_WORK_WITH_PRESET), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4205. break;
  4206. case MD2_PS_2_0:
  4207. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_CURRENTLY_USES_PS2), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4208. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_TO_USE_PS2X), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4209. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_WARNING_OLD_GPU_MIGHT_NOT_WORK_WITH_PRESET), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4210. break;
  4211. case MD2_PS_2_X:
  4212. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_CURRENTLY_USES_PS2X), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4213. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_TO_USE_PS3), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4214. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_WARNING_OLD_GPU_MIGHT_NOT_WORK_WITH_PRESET), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4215. break;
  4216. case MD2_PS_3_0:
  4217. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_PRESET_CURRENTLY_USES_PS3), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4218. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_UPGRADE_TO_USE_PS4), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4219. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_WARNING_OLD_GPU_MIGHT_NOT_WORK_WITH_PRESET), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4220. break;
  4221. default:
  4222. assert(0);
  4223. break;
  4224. }
  4225. }
  4226. }
  4227. *upper_left_corner_y = rect.top;
  4228. }
  4229. else if (m_UI_mode == UI_LOAD_DEL)
  4230. {
  4231. RECT rect;
  4232. SetRect(&rect, xL, *upper_left_corner_y, xR, *lower_left_corner_y);
  4233. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_ARE_YOU_SURE_YOU_WANT_TO_DELETE_PRESET), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4234. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_PRESET_TO_DELETE), m_presets[m_nPresetListCurPos].szFilename.c_str());
  4235. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), buf, -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4236. *upper_left_corner_y = rect.top;
  4237. }
  4238. else if (m_UI_mode == UI_SAVE_OVERWRITE)
  4239. {
  4240. RECT rect;
  4241. SetRect(&rect, xL, *upper_left_corner_y, xR, *lower_left_corner_y);
  4242. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_FILE_ALREADY_EXISTS_OVERWRITE_IT), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4243. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_FILE_IN_QUESTION_X_MILK), m_waitstring.szText);
  4244. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), buf, -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, MENU_COLOR, true);
  4245. if (m_bWarpShaderLock)
  4246. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_WARNING_DO_NOT_FORGET_WARP_SHADER_WAS_LOCKED), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, 0xFFFFFFFF, true, 0xFFCC0000);
  4247. if (m_bCompShaderLock)
  4248. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), WASABI_API_LNGSTRINGW(IDS_WARNING_DO_NOT_FORGET_COMPOSITE_SHADER_WAS_LOCKED), -1, &rect, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX, 0xFFFFFFFF, true, 0xFFCC0000);
  4249. *upper_left_corner_y = rect.top;
  4250. }
  4251. else if (m_UI_mode == UI_MASHUP)
  4252. {
  4253. if (m_nPresets-m_nDirs == 0)
  4254. {
  4255. // note: this error message is repeated in milkdrop.cpp in LoadRandomPreset()
  4256. wchar_t buf[1024];
  4257. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ERROR_NO_PRESET_FILE_FOUND_IN_X_MILK), m_szPresetDir);
  4258. AddError(buf, 6.0f, ERR_MISC, true);
  4259. m_UI_mode = UI_REGULAR;
  4260. }
  4261. else
  4262. {
  4263. UpdatePresetList(); // make sure list is completely ready
  4264. // quick checks
  4265. for (int mash=0; mash<MASH_SLOTS; mash++)
  4266. {
  4267. // check validity
  4268. if (m_nMashPreset[mash] < m_nDirs)
  4269. m_nMashPreset[mash] = m_nDirs;
  4270. if (m_nMashPreset[mash] >= m_nPresets)
  4271. m_nMashPreset[mash] = m_nPresets-1;
  4272. // apply changes, if it's time
  4273. if (m_nLastMashChangeFrame[mash]+MASH_APPLY_DELAY_FRAMES+1 == GetFrame())
  4274. {
  4275. // import just a fragment of a preset!!
  4276. DWORD ApplyFlags = 0;
  4277. switch(mash)
  4278. {
  4279. case 0: ApplyFlags = STATE_GENERAL; break;
  4280. case 1: ApplyFlags = STATE_MOTION; break;
  4281. case 2: ApplyFlags = STATE_WAVE; break;
  4282. case 3: ApplyFlags = STATE_WARP; break;
  4283. case 4: ApplyFlags = STATE_COMP; break;
  4284. }
  4285. wchar_t szFile[MAX_PATH];
  4286. swprintf(szFile, L"%s%s", m_szPresetDir, m_presets[m_nMashPreset[mash]].szFilename.c_str());
  4287. m_pState->Import(szFile, GetTime(), m_pState, ApplyFlags);
  4288. if (ApplyFlags & STATE_WARP)
  4289. SafeRelease( m_shaders.warp.ptr );
  4290. if (ApplyFlags & STATE_COMP)
  4291. SafeRelease( m_shaders.comp.ptr );
  4292. LoadShaders(&m_shaders, m_pState, false);
  4293. SetMenusForPresetVersion( m_pState->m_nWarpPSVersion, m_pState->m_nCompPSVersion );
  4294. }
  4295. }
  4296. MyTextOut(WASABI_API_LNGSTRINGW(IDS_PRESET_MASH_UP_TEXT1), MTO_UPPER_LEFT, true);
  4297. MyTextOut(WASABI_API_LNGSTRINGW(IDS_PRESET_MASH_UP_TEXT2), MTO_UPPER_LEFT, true);
  4298. MyTextOut(WASABI_API_LNGSTRINGW(IDS_PRESET_MASH_UP_TEXT3), MTO_UPPER_LEFT, true);
  4299. MyTextOut(WASABI_API_LNGSTRINGW(IDS_PRESET_MASH_UP_TEXT4), MTO_UPPER_LEFT, true);
  4300. *upper_left_corner_y += PLAYLIST_INNER_MARGIN;
  4301. RECT rect;
  4302. SetRect(&rect, xL, *upper_left_corner_y, xR, *lower_left_corner_y);
  4303. rect.top += PLAYLIST_INNER_MARGIN;
  4304. rect.left += PLAYLIST_INNER_MARGIN;
  4305. rect.right -= PLAYLIST_INNER_MARGIN;
  4306. rect.bottom -= PLAYLIST_INNER_MARGIN;
  4307. int lines_available = (rect.bottom - rect.top - PLAYLIST_INNER_MARGIN*2) / GetFontHeight(SIMPLE_FONT);
  4308. lines_available -= MASH_SLOTS;
  4309. if (lines_available < 10)
  4310. {
  4311. // force it
  4312. rect.bottom = rect.top + GetFontHeight(SIMPLE_FONT)*10 + 1;
  4313. lines_available = 10;
  4314. }
  4315. if (lines_available > 16)
  4316. lines_available = 16;
  4317. if (m_bUserPagedDown)
  4318. {
  4319. m_nMashPreset[m_nMashSlot] += lines_available;
  4320. if (m_nMashPreset[m_nMashSlot] >= m_nPresets)
  4321. m_nMashPreset[m_nMashSlot] = m_nPresets - 1;
  4322. m_bUserPagedDown = false;
  4323. }
  4324. if (m_bUserPagedUp)
  4325. {
  4326. m_nMashPreset[m_nMashSlot] -= lines_available;
  4327. if (m_nMashPreset[m_nMashSlot] < m_nDirs)
  4328. m_nMashPreset[m_nMashSlot] = m_nDirs;
  4329. m_bUserPagedUp = false;
  4330. }
  4331. int i;
  4332. int first_line = m_nMashPreset[m_nMashSlot] - (m_nMashPreset[m_nMashSlot] % lines_available);
  4333. int last_line = first_line + lines_available;
  4334. wchar_t str[512], str2[512];
  4335. if (last_line > m_nPresets)
  4336. last_line = m_nPresets;
  4337. // tooltip:
  4338. if (m_bShowMenuToolTips)
  4339. {
  4340. wchar_t buf[256];
  4341. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_PAGE_X_OF_X), m_nMashPreset[m_nMashSlot]/lines_available+1, (m_nPresets+lines_available-1)/lines_available);
  4342. DrawTooltip(buf, xR, *lower_right_corner_y);
  4343. }
  4344. RECT orig_rect = rect;
  4345. RECT box;
  4346. box.top = rect.top;
  4347. box.left = rect.left;
  4348. box.right = rect.left;
  4349. box.bottom = rect.top;
  4350. int mashNames[MASH_SLOTS] = { IDS_MASHUP_GENERAL_POSTPROC,
  4351. IDS_MASHUP_MOTION_EQUATIONS,
  4352. IDS_MASHUP_WAVEFORMS_SHAPES,
  4353. IDS_MASHUP_WARP_SHADER,
  4354. IDS_MASHUP_COMP_SHADER,
  4355. };
  4356. int pass = 0;
  4357. for (pass=0; pass<2; pass++)
  4358. {
  4359. box = orig_rect;
  4360. int w = 0;
  4361. int h = 0;
  4362. int start_y = orig_rect.top;
  4363. for (int mash=0; mash<MASH_SLOTS; mash++)
  4364. {
  4365. int idx = m_nMashPreset[mash];
  4366. wchar_t buf[1024];
  4367. swprintf(buf, L"%s%s", WASABI_API_LNGSTRINGW(mashNames[mash]), m_presets[idx].szFilename);
  4368. RECT r2 = orig_rect;
  4369. r2.top += h;
  4370. h += m_text.DrawTextW(GetFont(SIMPLE_FONT), buf, -1, &r2, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX | (pass==0 ? DT_CALCRECT : 0), (mash==m_nMashSlot) ? PLAYLIST_COLOR_HILITE_TRACK : PLAYLIST_COLOR_NORMAL, false);
  4371. w = max(w, r2.right - r2.left);
  4372. }
  4373. if (pass==0) {
  4374. box.right = box.left + w;
  4375. box.bottom = box.top + h;
  4376. DrawDarkTranslucentBox(&box);
  4377. }
  4378. else
  4379. orig_rect.top += h;
  4380. }
  4381. orig_rect.top += GetFontHeight(SIMPLE_FONT) + PLAYLIST_INNER_MARGIN;
  4382. box = orig_rect;
  4383. box.right = box.left;
  4384. box.bottom = box.top;
  4385. // draw a directory listing box right after...
  4386. for (pass=0; pass<2; pass++)
  4387. {
  4388. //if (pass==1)
  4389. // GetFont(SIMPLE_FONT)->Begin();
  4390. rect = orig_rect;
  4391. for (i=first_line; i<last_line; i++)
  4392. {
  4393. // remove the extension before displaying the filename. also pad w/spaces.
  4394. //lstrcpy(str, m_pPresetAddr[i]);
  4395. bool bIsDir = (m_presets[i].szFilename.c_str()[0] == '*');
  4396. bool bIsRunning = false;
  4397. bool bIsSelected = (i == m_nMashPreset[m_nMashSlot]);
  4398. if (bIsDir)
  4399. {
  4400. // directory
  4401. if (wcscmp(m_presets[i].szFilename.c_str()+1, L"..")==0)
  4402. swprintf(str2, L" [ %s ] (%s) ", m_presets[i].szFilename.c_str()+1, WASABI_API_LNGSTRINGW(IDS_PARENT_DIRECTORY));
  4403. else
  4404. swprintf(str2, L" [ %s ] ", m_presets[i].szFilename.c_str()+1);
  4405. }
  4406. else
  4407. {
  4408. // preset file
  4409. lstrcpyW(str, m_presets[i].szFilename.c_str());
  4410. RemoveExtension(str);
  4411. swprintf(str2, L" %s ", str);
  4412. if (wcscmp(m_presets[m_nMashPreset[m_nMashSlot]].szFilename.c_str(), str)==0)
  4413. bIsRunning = true;
  4414. }
  4415. if (bIsRunning && m_bPresetLockedByUser)
  4416. lstrcatW(str2, WASABI_API_LNGSTRINGW(IDS_LOCKED));
  4417. DWORD color = bIsDir ? DIR_COLOR : PLAYLIST_COLOR_NORMAL;
  4418. if (bIsRunning)
  4419. color = bIsSelected ? PLAYLIST_COLOR_BOTH : PLAYLIST_COLOR_PLAYING_TRACK;
  4420. else if (bIsSelected)
  4421. color = PLAYLIST_COLOR_HILITE_TRACK;
  4422. RECT r2 = rect;
  4423. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), str2, -1, &r2, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX | (pass==0 ? DT_CALCRECT : 0), color, false);
  4424. if (pass==0) // calculating dark box
  4425. {
  4426. box.right = max(box.right, box.left + r2.right-r2.left);
  4427. box.bottom += r2.bottom-r2.top;
  4428. }
  4429. }
  4430. //if (pass==1)
  4431. // GetFont(SIMPLE_FONT)->End();
  4432. if (pass==0) // calculating dark box
  4433. {
  4434. box.top -= PLAYLIST_INNER_MARGIN;
  4435. box.left -= PLAYLIST_INNER_MARGIN;
  4436. box.right += PLAYLIST_INNER_MARGIN;
  4437. box.bottom += PLAYLIST_INNER_MARGIN;
  4438. DrawDarkTranslucentBox(&box);
  4439. *upper_left_corner_y = box.bottom + PLAYLIST_INNER_MARGIN;
  4440. }
  4441. else
  4442. orig_rect.top += box.bottom-box.top;
  4443. }
  4444. orig_rect.top += PLAYLIST_INNER_MARGIN;
  4445. }
  4446. }
  4447. else if (m_UI_mode == UI_LOAD)
  4448. {
  4449. if (m_nPresets == 0)
  4450. {
  4451. // note: this error message is repeated in milkdrop.cpp in LoadRandomPreset()
  4452. wchar_t buf[1024];
  4453. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ERROR_NO_PRESET_FILE_FOUND_IN_X_MILK), m_szPresetDir);
  4454. AddError(buf, 6.0f, ERR_MISC, true);
  4455. m_UI_mode = UI_REGULAR;
  4456. }
  4457. else
  4458. {
  4459. MyTextOut(WASABI_API_LNGSTRINGW(IDS_LOAD_WHICH_PRESET_PLUS_COMMANDS), MTO_UPPER_LEFT, true);
  4460. wchar_t buf[MAX_PATH+64];
  4461. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_DIRECTORY_OF_X), m_szPresetDir);
  4462. MyTextOut(buf, MTO_UPPER_LEFT, true);
  4463. *upper_left_corner_y += h/2;
  4464. RECT rect;
  4465. SetRect(&rect, xL, *upper_left_corner_y, xR, *lower_left_corner_y);
  4466. rect.top += PLAYLIST_INNER_MARGIN;
  4467. rect.left += PLAYLIST_INNER_MARGIN;
  4468. rect.right -= PLAYLIST_INNER_MARGIN;
  4469. rect.bottom -= PLAYLIST_INNER_MARGIN;
  4470. int lines_available = (rect.bottom - rect.top - PLAYLIST_INNER_MARGIN*2) / GetFontHeight(SIMPLE_FONT);
  4471. if (lines_available < 1)
  4472. {
  4473. // force it
  4474. rect.bottom = rect.top + GetFontHeight(SIMPLE_FONT) + 1;
  4475. lines_available = 1;
  4476. }
  4477. if (lines_available > MAX_PRESETS_PER_PAGE)
  4478. lines_available = MAX_PRESETS_PER_PAGE;
  4479. if (m_bUserPagedDown)
  4480. {
  4481. m_nPresetListCurPos += lines_available;
  4482. if (m_nPresetListCurPos >= m_nPresets)
  4483. m_nPresetListCurPos = m_nPresets - 1;
  4484. // remember this preset's name so the next time they hit 'L' it jumps straight to it
  4485. //lstrcpy(m_szLastPresetSelected, m_presets[m_nPresetListCurPos].szFilename.c_str());
  4486. m_bUserPagedDown = false;
  4487. }
  4488. if (m_bUserPagedUp)
  4489. {
  4490. m_nPresetListCurPos -= lines_available;
  4491. if (m_nPresetListCurPos < 0)
  4492. m_nPresetListCurPos = 0;
  4493. // remember this preset's name so the next time they hit 'L' it jumps straight to it
  4494. //lstrcpy(m_szLastPresetSelected, m_presets[m_nPresetListCurPos].szFilename.c_str());
  4495. m_bUserPagedUp = false;
  4496. }
  4497. int i;
  4498. int first_line = m_nPresetListCurPos - (m_nPresetListCurPos % lines_available);
  4499. int last_line = first_line + lines_available;
  4500. wchar_t str[512], str2[512];
  4501. if (last_line > m_nPresets)
  4502. last_line = m_nPresets;
  4503. // tooltip:
  4504. if (m_bShowMenuToolTips)
  4505. {
  4506. wchar_t buf[256];
  4507. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_PAGE_X_OF_X), m_nPresetListCurPos/lines_available+1, (m_nPresets+lines_available-1)/lines_available);
  4508. DrawTooltip(buf, xR, *lower_right_corner_y);
  4509. }
  4510. RECT orig_rect = rect;
  4511. RECT box;
  4512. box.top = rect.top;
  4513. box.left = rect.left;
  4514. box.right = rect.left;
  4515. box.bottom = rect.top;
  4516. for (int pass=0; pass<2; pass++)
  4517. {
  4518. //if (pass==1)
  4519. // GetFont(SIMPLE_FONT)->Begin();
  4520. rect = orig_rect;
  4521. for (i=first_line; i<last_line; i++)
  4522. {
  4523. // remove the extension before displaying the filename. also pad w/spaces.
  4524. //lstrcpy(str, m_pPresetAddr[i]);
  4525. bool bIsDir = (m_presets[i].szFilename.c_str()[0] == '*');
  4526. bool bIsRunning = (i == m_nCurrentPreset);//false;
  4527. bool bIsSelected = (i == m_nPresetListCurPos);
  4528. if (bIsDir)
  4529. {
  4530. // directory
  4531. if (wcscmp(m_presets[i].szFilename.c_str()+1, L"..")==0)
  4532. swprintf(str2, L" [ %s ] (%s) ", m_presets[i].szFilename.c_str()+1, WASABI_API_LNGSTRINGW(IDS_PARENT_DIRECTORY));
  4533. else
  4534. swprintf(str2, L" [ %s ] ", m_presets[i].szFilename.c_str()+1);
  4535. }
  4536. else
  4537. {
  4538. // preset file
  4539. lstrcpyW(str, m_presets[i].szFilename.c_str());
  4540. RemoveExtension(str);
  4541. swprintf(str2, L" %s ", str);
  4542. //if (lstrcmp(m_pState->m_szDesc, str)==0)
  4543. // bIsRunning = true;
  4544. }
  4545. if (bIsRunning && m_bPresetLockedByUser)
  4546. lstrcatW(str2, WASABI_API_LNGSTRINGW(IDS_LOCKED));
  4547. DWORD color = bIsDir ? DIR_COLOR : PLAYLIST_COLOR_NORMAL;
  4548. if (bIsRunning)
  4549. color = bIsSelected ? PLAYLIST_COLOR_BOTH : PLAYLIST_COLOR_PLAYING_TRACK;
  4550. else if (bIsSelected)
  4551. color = PLAYLIST_COLOR_HILITE_TRACK;
  4552. RECT r2 = rect;
  4553. rect.top += m_text.DrawTextW(GetFont(SIMPLE_FONT), str2, -1, &r2, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX | (pass==0 ? DT_CALCRECT : 0), color, false);
  4554. if (pass==0) // calculating dark box
  4555. {
  4556. box.right = max(box.right, box.left + r2.right-r2.left);
  4557. box.bottom += r2.bottom-r2.top;
  4558. }
  4559. }
  4560. //if (pass==1)
  4561. // GetFont(SIMPLE_FONT)->End();
  4562. if (pass==0) // calculating dark box
  4563. {
  4564. box.top -= PLAYLIST_INNER_MARGIN;
  4565. box.left -= PLAYLIST_INNER_MARGIN;
  4566. box.right += PLAYLIST_INNER_MARGIN;
  4567. box.bottom += PLAYLIST_INNER_MARGIN;
  4568. DrawDarkTranslucentBox(&box);
  4569. *upper_left_corner_y = box.bottom + PLAYLIST_INNER_MARGIN;
  4570. }
  4571. }
  4572. }
  4573. }
  4574. }
  4575. // 5. render *remaining* text to upper-right corner
  4576. {
  4577. // e) custom timed message:
  4578. if (!m_bWarningsDisabled2)
  4579. {
  4580. wchar_t buf[512] = {0};
  4581. SelectFont(SIMPLE_FONT);
  4582. float t = GetTime();
  4583. int N = m_errors.size();
  4584. for (int i=0; i<N; i++)
  4585. {
  4586. if (t >= m_errors[i].birthTime && t < m_errors[i].expireTime)
  4587. {
  4588. swprintf(buf, L"%s ", m_errors[i].msg.c_str());
  4589. float age_rel = (t - m_errors[i].birthTime) / (m_errors[i].expireTime - m_errors[i].birthTime);
  4590. DWORD cr = (DWORD)(200 - 199*powf(age_rel,4));
  4591. DWORD cg = 0;//(DWORD)(136 - 135*powf(age_rel,1));
  4592. DWORD cb = 0;
  4593. DWORD z = 0xFF000000 | (cr<<16) | (cg<<8) | cb;
  4594. MyTextOut_BGCOLOR(buf, MTO_UPPER_RIGHT, true, m_errors[i].bBold ? z : 0xFF000000);
  4595. }
  4596. else
  4597. {
  4598. m_errors.erase(m_errors.begin() + i);
  4599. i--;
  4600. N--;
  4601. }
  4602. }
  4603. }
  4604. }
  4605. }
  4606. //----------------------------------------------------------------------
  4607. LRESULT CPlugin::MyWindowProc(HWND hWnd, unsigned uMsg, WPARAM wParam, LPARAM lParam)
  4608. {
  4609. // You can handle Windows messages here while the plugin is running,
  4610. // such as mouse events (WM_MOUSEMOVE/WM_LBUTTONDOWN), keypresses
  4611. // (WK_KEYDOWN/WM_CHAR), and so on.
  4612. // This function is threadsafe (thanks to Winamp's architecture),
  4613. // so you don't have to worry about using semaphores or critical
  4614. // sections to read/write your class member variables.
  4615. // If you don't handle a message, let it continue on the usual path
  4616. // (to Winamp) by returning DefWindowProc(hWnd,uMsg,wParam,lParam).
  4617. // If you do handle a message, prevent it from being handled again
  4618. // (by Winamp) by returning 0.
  4619. // IMPORTANT: For the WM_KEYDOWN, WM_KEYUP, and WM_CHAR messages,
  4620. // you must return 0 if you process the message (key),
  4621. // and 1 if you do not. DO NOT call DefWindowProc()
  4622. // for these particular messages!
  4623. USHORT mask = 1 << (sizeof(SHORT)*8 - 1);
  4624. bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0;
  4625. bool bCtrlHeldDown = (GetKeyState(VK_CONTROL) & mask) != 0;
  4626. int nRepeat = 1; //updated as appropriate
  4627. int rep;
  4628. switch (uMsg)
  4629. {
  4630. case WM_COMMAND:
  4631. switch (LOWORD(wParam))
  4632. {
  4633. case ID_VIS_NEXT:
  4634. NextPreset(m_fBlendTimeUser);
  4635. return 0;
  4636. case ID_VIS_PREV:
  4637. PrevPreset(m_fBlendTimeUser);
  4638. return 0;
  4639. case ID_VIS_RANDOM:
  4640. {
  4641. // note: when the vis is launched, if we're using a fancy modern skin
  4642. // (with a Random button), it will send us one of these...
  4643. // if it's NOT a fancy skin, we'll never get this message (confirmed).
  4644. USHORT v = HIWORD(wParam); // here, v is 0 (locked) or 1 (random) or 0xFFFF (don't know / startup!)
  4645. if (v==0xFFFF)
  4646. {
  4647. // plugin just launched or changed modes -
  4648. // Winamp wants to know what our saved Random state is...
  4649. SendMessage(GetWinampWindow(), WM_WA_IPC, (m_bPresetLockOnAtStartup ? 0 : 1) << 16, IPC_CB_VISRANDOM);
  4650. return 0;
  4651. }
  4652. // otherwise it's 0 or 1 - user clicked the button, we should respond.
  4653. v = v ? 1 : 0; // same here
  4654. //see also - IPC_CB_VISRANDOM
  4655. m_bPresetLockedByUser = (v == 0);
  4656. SetScrollLock(m_bPresetLockedByUser, m_bPreventScollLockHandling);
  4657. return 0;
  4658. }
  4659. case ID_VIS_FS:
  4660. PostMessage(hWnd, WM_USER + 1667, 0, 0);
  4661. return 0;
  4662. case ID_VIS_CFG:
  4663. ToggleHelp();
  4664. return 0;
  4665. case ID_VIS_MENU:
  4666. POINT pt;
  4667. GetCursorPos(&pt);
  4668. SendMessage(hWnd, WM_CONTEXTMENU, (WPARAM)hWnd, (pt.y << 16) | pt.x);
  4669. return 0;
  4670. }
  4671. break;
  4672. /*
  4673. case WM_SETFOCUS:
  4674. m_bOrigScrollLockState = GetKeyState(VK_SCROLL) & 1;
  4675. SetScrollLock(m_bMilkdropScrollLockState);
  4676. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  4677. case WM_KILLFOCUS:
  4678. m_bMilkdropScrollLockState = GetKeyState(VK_SCROLL) & 1;
  4679. SetScrollLock(m_bOrigScrollLockState);
  4680. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  4681. */
  4682. // this is used to work around a focusing issue when toggling fullscreen
  4683. // via the 'fullscreen' button in the bento (and most other) modern skin
  4684. case WM_USER+1667:
  4685. if (GetFrame() > 0) ToggleFullScreen();
  4686. return 0;
  4687. case WM_CHAR: // plain & simple alphanumeric keys
  4688. nRepeat = LOWORD(lParam);
  4689. if (m_waitstring.bActive) // if user is in the middle of editing a string
  4690. {
  4691. if ((wParam >= ' ' && wParam <= 'z') || wParam=='{' || wParam=='}')
  4692. {
  4693. int len;
  4694. if(m_waitstring.bDisplayAsCode)
  4695. len = lstrlenA((char*)m_waitstring.szText);
  4696. else
  4697. len = lstrlenW(m_waitstring.szText);
  4698. if (m_waitstring.bFilterBadChars &&
  4699. (wParam == '\"' ||
  4700. wParam == '\\' ||
  4701. wParam == '/' ||
  4702. wParam == ':' ||
  4703. wParam == '*' ||
  4704. wParam == '?' ||
  4705. wParam == '|' ||
  4706. wParam == '<' ||
  4707. wParam == '>' ||
  4708. wParam == '&')) // NOTE: '&' is legal in filenames, but we try to avoid it since during GDI display it acts as a control code (it will not show up, but instead, underline the character following it).
  4709. {
  4710. // illegal char
  4711. AddError(WASABI_API_LNGSTRINGW(IDS_ILLEGAL_CHARACTER), 2.5f, ERR_MISC, true);
  4712. }
  4713. else if (len+nRepeat >= m_waitstring.nMaxLen)
  4714. {
  4715. // m_waitstring.szText has reached its limit
  4716. AddError(WASABI_API_LNGSTRINGW(IDS_STRING_TOO_LONG), 2.5f, ERR_MISC, true);
  4717. }
  4718. else
  4719. {
  4720. //m_fShowUserMessageUntilThisTime = GetTime(); // if there was an error message already, clear it
  4721. if(m_waitstring.bDisplayAsCode)
  4722. {
  4723. char buf[16];
  4724. sprintf(buf, "%c", wParam);
  4725. if (m_waitstring.nSelAnchorPos != -1)
  4726. WaitString_NukeSelection();
  4727. if (m_waitstring.bOvertypeMode)
  4728. {
  4729. // overtype mode
  4730. for (rep=0; rep<nRepeat; rep++)
  4731. {
  4732. if (m_waitstring.nCursorPos == len)
  4733. {
  4734. lstrcatA((char*)m_waitstring.szText, buf);
  4735. len++;
  4736. }
  4737. else
  4738. {
  4739. char* ptr = (char*)m_waitstring.szText;
  4740. *(ptr + m_waitstring.nCursorPos) = buf[0];
  4741. }
  4742. m_waitstring.nCursorPos++;
  4743. }
  4744. }
  4745. else
  4746. {
  4747. // insert mode:
  4748. char* ptr = (char*)m_waitstring.szText;
  4749. for (rep=0; rep<nRepeat; rep++)
  4750. {
  4751. for (int i=len; i>=m_waitstring.nCursorPos; i--)
  4752. *(ptr + i+1) = *(ptr + i);
  4753. *(ptr + m_waitstring.nCursorPos) = buf[0];
  4754. m_waitstring.nCursorPos++;
  4755. len++;
  4756. }
  4757. }
  4758. }
  4759. else
  4760. {
  4761. wchar_t buf[16];
  4762. swprintf(buf, L"%c", wParam);
  4763. if (m_waitstring.nSelAnchorPos != -1)
  4764. WaitString_NukeSelection();
  4765. if (m_waitstring.bOvertypeMode)
  4766. {
  4767. // overtype mode
  4768. for (rep=0; rep<nRepeat; rep++)
  4769. {
  4770. if (m_waitstring.nCursorPos == len)
  4771. {
  4772. lstrcatW(m_waitstring.szText, buf);
  4773. len++;
  4774. }
  4775. else
  4776. m_waitstring.szText[m_waitstring.nCursorPos] = buf[0];
  4777. m_waitstring.nCursorPos++;
  4778. }
  4779. }
  4780. else
  4781. {
  4782. // insert mode:
  4783. for (rep=0; rep<nRepeat; rep++)
  4784. {
  4785. for (int i=len; i>=m_waitstring.nCursorPos; i--)
  4786. m_waitstring.szText[i+1] = m_waitstring.szText[i];
  4787. m_waitstring.szText[m_waitstring.nCursorPos] = buf[0];
  4788. m_waitstring.nCursorPos++;
  4789. len++;
  4790. }
  4791. }
  4792. }
  4793. }
  4794. }
  4795. return 0; // we processed (or absorbed) the key
  4796. }
  4797. else if (m_UI_mode == UI_LOAD_DEL) // waiting to confirm file delete
  4798. {
  4799. if (wParam == keyMappings[0] || wParam == keyMappings[1]) // 'y' or 'Y'
  4800. {
  4801. // first add pathname to filename
  4802. wchar_t szDelFile[512];
  4803. swprintf(szDelFile, L"%s%s", GetPresetDir(), m_presets[m_nPresetListCurPos].szFilename.c_str());
  4804. DeletePresetFile(szDelFile);
  4805. //m_nCurrentPreset = -1;
  4806. }
  4807. m_UI_mode = UI_LOAD;
  4808. return 0; // we processed (or absorbed) the key
  4809. }
  4810. else if (m_UI_mode == UI_UPGRADE_PIXEL_SHADER)
  4811. {
  4812. if (wParam == keyMappings[0] || wParam == keyMappings[1]) // 'y' or 'Y'
  4813. {
  4814. if (m_pState->m_nMinPSVersion == m_pState->m_nMaxPSVersion)
  4815. {
  4816. switch(m_pState->m_nMinPSVersion)
  4817. {
  4818. case MD2_PS_NONE:
  4819. m_pState->m_nWarpPSVersion = MD2_PS_2_0;
  4820. m_pState->m_nCompPSVersion = MD2_PS_2_0;
  4821. m_pState->GenDefaultWarpShader();
  4822. m_pState->GenDefaultCompShader();
  4823. break;
  4824. case MD2_PS_2_0:
  4825. m_pState->m_nWarpPSVersion = MD2_PS_2_X;
  4826. m_pState->m_nCompPSVersion = MD2_PS_2_X;
  4827. break;
  4828. case MD2_PS_2_X:
  4829. m_pState->m_nWarpPSVersion = MD2_PS_3_0;
  4830. m_pState->m_nCompPSVersion = MD2_PS_3_0;
  4831. break;
  4832. default:
  4833. assert(0);
  4834. break;
  4835. }
  4836. }
  4837. else
  4838. {
  4839. switch(m_pState->m_nMinPSVersion)
  4840. {
  4841. case MD2_PS_NONE:
  4842. if (m_pState->m_nWarpPSVersion < MD2_PS_2_0)
  4843. {
  4844. m_pState->m_nWarpPSVersion = MD2_PS_2_0;
  4845. m_pState->GenDefaultWarpShader();
  4846. }
  4847. if (m_pState->m_nCompPSVersion < MD2_PS_2_0)
  4848. {
  4849. m_pState->m_nCompPSVersion = MD2_PS_2_0;
  4850. m_pState->GenDefaultCompShader();
  4851. }
  4852. break;
  4853. case MD2_PS_2_0:
  4854. m_pState->m_nWarpPSVersion = max(m_pState->m_nWarpPSVersion, MD2_PS_2_X);
  4855. m_pState->m_nCompPSVersion = max(m_pState->m_nCompPSVersion, MD2_PS_2_X);
  4856. break;
  4857. case MD2_PS_2_X:
  4858. m_pState->m_nWarpPSVersion = max(m_pState->m_nWarpPSVersion, MD2_PS_3_0);
  4859. m_pState->m_nCompPSVersion = max(m_pState->m_nCompPSVersion, MD2_PS_3_0);
  4860. break;
  4861. default:
  4862. assert(0);
  4863. break;
  4864. }
  4865. }
  4866. m_pState->m_nMinPSVersion = min(m_pState->m_nWarpPSVersion, m_pState->m_nCompPSVersion);
  4867. m_pState->m_nMaxPSVersion = max(m_pState->m_nWarpPSVersion, m_pState->m_nCompPSVersion);
  4868. LoadShaders(&m_shaders, m_pState, false);
  4869. SetMenusForPresetVersion( m_pState->m_nWarpPSVersion, m_pState->m_nCompPSVersion );
  4870. }
  4871. if (wParam != 13)
  4872. m_UI_mode = UI_MENU;
  4873. return 0; // we processed (or absorbed) the key
  4874. }
  4875. else if (m_UI_mode == UI_SAVE_OVERWRITE) // waiting to confirm overwrite file on save
  4876. {
  4877. if (wParam == keyMappings[0] || wParam == keyMappings[1]) // 'y' or 'Y'
  4878. {
  4879. // first add pathname + extension to filename
  4880. wchar_t szNewFile[512];
  4881. swprintf(szNewFile, L"%s%s.milk", GetPresetDir(), m_waitstring.szText);
  4882. SavePresetAs(szNewFile);
  4883. // exit waitstring mode
  4884. m_UI_mode = UI_REGULAR;
  4885. m_waitstring.bActive = false;
  4886. //m_bPresetLockedByCode = false;
  4887. }
  4888. else if ((wParam >= ' ' && wParam <= 'z') || wParam == 27) // 27 is the ESCAPE key
  4889. {
  4890. // go back to SAVE AS mode
  4891. m_UI_mode = UI_SAVEAS;
  4892. m_waitstring.bActive = true;
  4893. }
  4894. return 0; // we processed (or absorbed) the key
  4895. }
  4896. else // normal handling of a simple key (all non-virtual-key hotkeys end up here)
  4897. {
  4898. if (HandleRegularKey(wParam)==0)
  4899. return 0;
  4900. }
  4901. return 1; // end case WM_CHAR
  4902. case WM_KEYDOWN: // virtual-key codes
  4903. // Note that some keys will never reach this point, since they are
  4904. // intercepted by the plugin shell (see PluginShellWindowProc(),
  4905. // at the end of pluginshell.cpp for which ones).
  4906. // For a complete list of virtual-key codes, look up the keyphrase
  4907. // "virtual-key codes [win32]" in the msdn help.
  4908. nRepeat = LOWORD(lParam);
  4909. switch(wParam)
  4910. {
  4911. case VK_F2: m_bShowSongTitle = !m_bShowSongTitle; return 0; // we processed (or absorbed) the key
  4912. case VK_F3:
  4913. if (m_bShowSongTime && m_bShowSongLen)
  4914. {
  4915. m_bShowSongTime = false;
  4916. m_bShowSongLen = false;
  4917. }
  4918. else if (m_bShowSongTime && !m_bShowSongLen)
  4919. {
  4920. m_bShowSongLen = true;
  4921. }
  4922. else
  4923. {
  4924. m_bShowSongTime = true;
  4925. m_bShowSongLen = false;
  4926. }
  4927. return 0; // we processed (or absorbed) the key
  4928. case VK_F4: m_bShowPresetInfo = !m_bShowPresetInfo; return 0; // we processed (or absorbed) the key
  4929. case VK_F5: m_bShowFPS = !m_bShowFPS; return 0; // we processed (or absorbed) the key
  4930. case VK_F6: m_bShowRating = !m_bShowRating; return 0; // we processed (or absorbed) the key
  4931. case VK_F7:
  4932. if (m_nNumericInputMode == NUMERIC_INPUT_MODE_CUST_MSG)
  4933. ReadCustomMessages(); // re-read custom messages
  4934. return 0; // we processed (or absorbed) the key
  4935. case VK_F8:
  4936. {
  4937. m_UI_mode = UI_CHANGEDIR;
  4938. // enter WaitString mode
  4939. m_waitstring.bActive = true;
  4940. m_waitstring.bFilterBadChars = false;
  4941. m_waitstring.bDisplayAsCode = false;
  4942. m_waitstring.nSelAnchorPos = -1;
  4943. m_waitstring.nMaxLen = min(sizeof(m_waitstring.szText)-1, MAX_PATH - 1);
  4944. lstrcpyW(m_waitstring.szText, GetPresetDir());
  4945. {
  4946. // for subtle beauty - remove the trailing '\' from the directory name (if it's not just "x:\")
  4947. int len = lstrlenW(m_waitstring.szText);
  4948. if (len > 3 && m_waitstring.szText[len-1] == '\\')
  4949. m_waitstring.szText[len-1] = 0;
  4950. }
  4951. WASABI_API_LNGSTRINGW_BUF(IDS_DIRECTORY_TO_JUMP_TO, m_waitstring.szPrompt, 512);
  4952. m_waitstring.szToolTip[0] = 0;
  4953. m_waitstring.nCursorPos = lstrlenW(m_waitstring.szText); // set the starting edit position
  4954. }
  4955. return 0; // we processed (or absorbed) the key
  4956. case VK_F9:
  4957. m_bShowShaderHelp = !m_bShowShaderHelp;
  4958. return FALSE;
  4959. case VK_SCROLL:
  4960. m_bPresetLockedByUser = GetKeyState(VK_SCROLL) & 1;
  4961. //SetScrollLock(m_bPresetLockedByUser);
  4962. SendMessage(GetWinampWindow(), WM_WA_IPC, (m_bPresetLockedByUser ? 0 : 1) << 16, IPC_CB_VISRANDOM);
  4963. //int set = m_bPresetLockedByUser ?
  4964. //PostMessage(GetWinampWindow(), WM_COMMAND, ID_VIS_RANDOM | (set << 16), 0);
  4965. return 0; // we processed (or absorbed) the key
  4966. //case VK_F6: break;
  4967. //case VK_F7: conflict
  4968. //case VK_F8: break;
  4969. //case VK_F9: conflict
  4970. }
  4971. // next handle the waitstring case (for string-editing),
  4972. // then the menu navigation case,
  4973. // then handle normal case (handle the message normally or pass on to winamp)
  4974. // case 1: waitstring mode
  4975. if (m_waitstring.bActive)
  4976. {
  4977. // handle arrow keys, home, end, etc.
  4978. USHORT mask = 1 << (sizeof(SHORT)*8 - 1); // we want the highest-order bit
  4979. bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0;
  4980. bool bCtrlHeldDown = (GetKeyState(VK_CONTROL) & mask) != 0;
  4981. if (wParam == VK_LEFT || wParam == VK_RIGHT ||
  4982. wParam == VK_HOME || wParam == VK_END ||
  4983. wParam == VK_UP || wParam == VK_DOWN)
  4984. {
  4985. if (bShiftHeldDown)
  4986. {
  4987. if (m_waitstring.nSelAnchorPos == -1)
  4988. m_waitstring.nSelAnchorPos = m_waitstring.nCursorPos;
  4989. }
  4990. else
  4991. {
  4992. m_waitstring.nSelAnchorPos = -1;
  4993. }
  4994. }
  4995. if (bCtrlHeldDown) // copy/cut/paste
  4996. {
  4997. switch(wParam)
  4998. {
  4999. case 'c':
  5000. case 'C':
  5001. case VK_INSERT:
  5002. WaitString_Copy();
  5003. return 0; // we processed (or absorbed) the key
  5004. case 'x':
  5005. case 'X':
  5006. WaitString_Cut();
  5007. return 0; // we processed (or absorbed) the key
  5008. case 'v':
  5009. case 'V':
  5010. WaitString_Paste();
  5011. return 0; // we processed (or absorbed) the key
  5012. case VK_LEFT: WaitString_SeekLeftWord(); return 0; // we processed (or absorbed) the key
  5013. case VK_RIGHT: WaitString_SeekRightWord(); return 0; // we processed (or absorbed) the key
  5014. case VK_HOME: m_waitstring.nCursorPos = 0; return 0; // we processed (or absorbed) the key
  5015. case VK_END:
  5016. if (m_waitstring.bDisplayAsCode)
  5017. {
  5018. m_waitstring.nCursorPos = lstrlenA((char*)m_waitstring.szText);
  5019. }
  5020. else
  5021. {
  5022. m_waitstring.nCursorPos = lstrlenW(m_waitstring.szText);
  5023. }
  5024. return 0; // we processed (or absorbed) the key
  5025. case VK_RETURN:
  5026. if (m_waitstring.bDisplayAsCode)
  5027. {
  5028. // CTRL+ENTER accepts the string -> finished editing
  5029. //assert(m_pCurMenu);
  5030. m_pCurMenu->OnWaitStringAccept(m_waitstring.szText);
  5031. // OnWaitStringAccept calls the callback function. See the
  5032. // calls to CMenu::AddItem from milkdrop.cpp to find the
  5033. // callback functions for different "waitstrings".
  5034. m_waitstring.bActive = false;
  5035. m_UI_mode = UI_MENU;
  5036. }
  5037. return 0; // we processed (or absorbed) the key
  5038. }
  5039. }
  5040. else // waitstring mode key pressed, and ctrl NOT held down
  5041. {
  5042. switch(wParam)
  5043. {
  5044. case VK_INSERT:
  5045. m_waitstring.bOvertypeMode = !m_waitstring.bOvertypeMode;
  5046. return 0; // we processed (or absorbed) the key
  5047. case VK_LEFT:
  5048. for (rep=0; rep<nRepeat; rep++)
  5049. if (m_waitstring.nCursorPos > 0)
  5050. m_waitstring.nCursorPos--;
  5051. return 0; // we processed (or absorbed) the key
  5052. case VK_RIGHT:
  5053. for (rep=0; rep<nRepeat; rep++)
  5054. {
  5055. if (m_waitstring.bDisplayAsCode)
  5056. {
  5057. if (m_waitstring.nCursorPos < (int)lstrlenA((char*)m_waitstring.szText))
  5058. m_waitstring.nCursorPos++;
  5059. }
  5060. else
  5061. {
  5062. if (m_waitstring.nCursorPos < (int)lstrlenW(m_waitstring.szText))
  5063. m_waitstring.nCursorPos++;
  5064. }
  5065. }
  5066. return 0; // we processed (or absorbed) the key
  5067. case VK_HOME:
  5068. m_waitstring.nCursorPos -= WaitString_GetCursorColumn();
  5069. return 0; // we processed (or absorbed) the key
  5070. case VK_END:
  5071. m_waitstring.nCursorPos += WaitString_GetLineLength() - WaitString_GetCursorColumn();
  5072. return 0; // we processed (or absorbed) the key
  5073. case VK_UP:
  5074. for (rep=0; rep<nRepeat; rep++)
  5075. WaitString_SeekUpOneLine();
  5076. return 0; // we processed (or absorbed) the key
  5077. case VK_DOWN:
  5078. for (rep=0; rep<nRepeat; rep++)
  5079. WaitString_SeekDownOneLine();
  5080. return 0; // we processed (or absorbed) the key
  5081. case VK_BACK:
  5082. if (m_waitstring.nSelAnchorPos != -1)
  5083. {
  5084. WaitString_NukeSelection();
  5085. }
  5086. else if (m_waitstring.nCursorPos > 0)
  5087. {
  5088. int len;
  5089. if (m_waitstring.bDisplayAsCode)
  5090. {
  5091. len = lstrlenA((char*)m_waitstring.szText);
  5092. }
  5093. else
  5094. {
  5095. len = lstrlenW(m_waitstring.szText);
  5096. }
  5097. int src_pos = m_waitstring.nCursorPos;
  5098. int dst_pos = m_waitstring.nCursorPos - nRepeat;
  5099. int gap = nRepeat;
  5100. int copy_chars = len - m_waitstring.nCursorPos + 1; // includes NULL @ end
  5101. if (dst_pos < 0)
  5102. {
  5103. gap += dst_pos;
  5104. //copy_chars += dst_pos;
  5105. dst_pos = 0;
  5106. }
  5107. if (m_waitstring.bDisplayAsCode)
  5108. {
  5109. char* ptr = (char*)m_waitstring.szText;
  5110. for (int i=0; i<copy_chars; i++)
  5111. *(ptr + dst_pos+i) = *(ptr + src_pos+i);
  5112. }
  5113. else
  5114. {
  5115. for (int i=0; i<copy_chars; i++)
  5116. m_waitstring.szText[dst_pos+i] = m_waitstring.szText[src_pos+i];
  5117. }
  5118. m_waitstring.nCursorPos -= gap;
  5119. }
  5120. return 0; // we processed (or absorbed) the key
  5121. case VK_DELETE:
  5122. if (m_waitstring.nSelAnchorPos != -1)
  5123. {
  5124. WaitString_NukeSelection();
  5125. }
  5126. else
  5127. {
  5128. if (m_waitstring.bDisplayAsCode)
  5129. {
  5130. int len = lstrlenA((char*)m_waitstring.szText);
  5131. char* ptr = (char*)m_waitstring.szText;
  5132. for (int i=m_waitstring.nCursorPos; i<=len - nRepeat; i++)
  5133. *(ptr + i) = *(ptr + i+nRepeat);
  5134. }
  5135. else
  5136. {
  5137. int len = lstrlenW(m_waitstring.szText);
  5138. for (int i=m_waitstring.nCursorPos; i<=len - nRepeat; i++)
  5139. m_waitstring.szText[i] = m_waitstring.szText[i+nRepeat];
  5140. }
  5141. }
  5142. return 0; // we processed (or absorbed) the key
  5143. case VK_RETURN:
  5144. if (m_UI_mode == UI_LOAD_RENAME) // rename (move) the file
  5145. {
  5146. // first add pathnames to filenames
  5147. wchar_t szOldFile[512];
  5148. wchar_t szNewFile[512];
  5149. lstrcpyW(szOldFile, GetPresetDir());
  5150. lstrcpyW(szNewFile, GetPresetDir());
  5151. lstrcatW(szOldFile, m_presets[m_nPresetListCurPos].szFilename.c_str());
  5152. lstrcatW(szNewFile, m_waitstring.szText);
  5153. lstrcatW(szNewFile, L".milk");
  5154. RenamePresetFile(szOldFile, szNewFile);
  5155. }
  5156. else if (m_UI_mode == UI_IMPORT_WAVE ||
  5157. m_UI_mode == UI_EXPORT_WAVE ||
  5158. m_UI_mode == UI_IMPORT_SHAPE ||
  5159. m_UI_mode == UI_EXPORT_SHAPE)
  5160. {
  5161. int bWave = (m_UI_mode == UI_IMPORT_WAVE || m_UI_mode == UI_EXPORT_WAVE);
  5162. int bImport = (m_UI_mode == UI_IMPORT_WAVE || m_UI_mode == UI_IMPORT_SHAPE);
  5163. int i = m_pCurMenu->GetCurItem()->m_lParam;
  5164. int ret;
  5165. switch(m_UI_mode)
  5166. {
  5167. case UI_IMPORT_WAVE : ret = m_pState->m_wave[i].Import(NULL, m_waitstring.szText, 0); break;
  5168. case UI_EXPORT_WAVE : ret = m_pState->m_wave[i].Export(NULL, m_waitstring.szText, 0); break;
  5169. case UI_IMPORT_SHAPE: ret = m_pState->m_shape[i].Import(NULL, m_waitstring.szText, 0); break;
  5170. case UI_EXPORT_SHAPE: ret = m_pState->m_shape[i].Export(NULL, m_waitstring.szText, 0); break;
  5171. }
  5172. if (bImport)
  5173. m_pState->RecompileExpressions(1);
  5174. //m_fShowUserMessageUntilThisTime = GetTime() - 1.0f; // if there was an error message already, clear it
  5175. if (!ret)
  5176. {
  5177. wchar_t buf[1024];
  5178. if (m_UI_mode==UI_IMPORT_WAVE || m_UI_mode==UI_IMPORT_SHAPE)
  5179. WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_IMPORTING_BAD_FILENAME, buf, 1024);
  5180. else
  5181. WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_IMPORTING_BAD_FILENAME_OR_NOT_OVERWRITEABLE, buf, 1024);
  5182. AddError(WASABI_API_LNGSTRINGW(IDS_STRING_TOO_LONG), 2.5f, ERR_MISC, true);
  5183. }
  5184. m_waitstring.bActive = false;
  5185. m_UI_mode = UI_MENU;
  5186. //m_bPresetLockedByCode = false;
  5187. }
  5188. else if (m_UI_mode == UI_SAVEAS)
  5189. {
  5190. // first add pathname + extension to filename
  5191. wchar_t szNewFile[512];
  5192. swprintf(szNewFile, L"%s%s.milk", GetPresetDir(), m_waitstring.szText);
  5193. if (GetFileAttributesW(szNewFile) != -1) // check if file already exists
  5194. {
  5195. // file already exists -> overwrite it?
  5196. m_waitstring.bActive = false;
  5197. m_UI_mode = UI_SAVE_OVERWRITE;
  5198. }
  5199. else
  5200. {
  5201. SavePresetAs(szNewFile);
  5202. // exit waitstring mode
  5203. m_UI_mode = UI_REGULAR;
  5204. m_waitstring.bActive = false;
  5205. //m_bPresetLockedByCode = false;
  5206. }
  5207. }
  5208. else if (m_UI_mode == UI_EDIT_MENU_STRING)
  5209. {
  5210. if (m_waitstring.bDisplayAsCode)
  5211. {
  5212. if (m_waitstring.nSelAnchorPos != -1)
  5213. WaitString_NukeSelection();
  5214. int len = lstrlenA((char*)m_waitstring.szText);
  5215. char* ptr = (char*)m_waitstring.szText;
  5216. if (len + 1 < m_waitstring.nMaxLen)
  5217. {
  5218. // insert a linefeed. Use CTRL+return to accept changes in this case.
  5219. for (int pos=len+1; pos > m_waitstring.nCursorPos; pos--)
  5220. *(ptr + pos) = *(ptr + pos - 1);
  5221. *(ptr + m_waitstring.nCursorPos++) = LINEFEED_CONTROL_CHAR;
  5222. //m_fShowUserMessageUntilThisTime = GetTime() - 1.0f; // if there was an error message already, clear it
  5223. }
  5224. else
  5225. {
  5226. // m_waitstring.szText has reached its limit
  5227. AddError(WASABI_API_LNGSTRINGW(IDS_STRING_TOO_LONG), 2.5f, ERR_MISC, true);
  5228. }
  5229. }
  5230. else
  5231. {
  5232. // finished editing
  5233. //assert(m_pCurMenu);
  5234. m_pCurMenu->OnWaitStringAccept(m_waitstring.szText);
  5235. // OnWaitStringAccept calls the callback function. See the
  5236. // calls to CMenu::AddItem from milkdrop.cpp to find the
  5237. // callback functions for different "waitstrings".
  5238. m_waitstring.bActive = false;
  5239. m_UI_mode = UI_MENU;
  5240. }
  5241. }
  5242. else if (m_UI_mode == UI_CHANGEDIR)
  5243. {
  5244. //m_fShowUserMessageUntilThisTime = GetTime(); // if there was an error message already, clear it
  5245. // change dir
  5246. wchar_t szOldDir[512];
  5247. wchar_t szNewDir[512];
  5248. lstrcpyW(szOldDir, g_plugin.m_szPresetDir);
  5249. lstrcpyW(szNewDir, m_waitstring.szText);
  5250. int len = lstrlenW(szNewDir);
  5251. if (len > 0 && szNewDir[len-1] != L'\\')
  5252. lstrcatW(szNewDir, L"\\");
  5253. lstrcpyW(g_plugin.m_szPresetDir, szNewDir);
  5254. bool bSuccess = true;
  5255. if (GetFileAttributesW(g_plugin.m_szPresetDir) == -1)
  5256. bSuccess = false;
  5257. if (bSuccess) {
  5258. UpdatePresetList(false,true,false);
  5259. bSuccess = (m_nPresets > 0);
  5260. }
  5261. if (!bSuccess)
  5262. {
  5263. // new dir. was invalid -> allow them to try again
  5264. lstrcpyW(g_plugin.m_szPresetDir, szOldDir);
  5265. // give them a warning
  5266. AddError(WASABI_API_LNGSTRINGW(IDS_INVALID_PATH), 3.5f, ERR_MISC, true);
  5267. }
  5268. else
  5269. {
  5270. // success
  5271. lstrcpyW(g_plugin.m_szPresetDir, szNewDir);
  5272. // save new path to registry
  5273. WritePrivateProfileStringW(L"settings",L"szPresetDir",g_plugin.m_szPresetDir,GetConfigIniFile());
  5274. // set current preset index to -1 because current preset is no longer in the list
  5275. m_nCurrentPreset = -1;
  5276. // go to file load menu
  5277. m_waitstring.bActive = false;
  5278. m_UI_mode = UI_LOAD;
  5279. ClearErrors(ERR_MISC);
  5280. }
  5281. }
  5282. return 0; // we processed (or absorbed) the key
  5283. case VK_ESCAPE:
  5284. if (m_UI_mode == UI_LOAD_RENAME)
  5285. {
  5286. m_waitstring.bActive = false;
  5287. m_UI_mode = UI_LOAD;
  5288. }
  5289. else if (
  5290. m_UI_mode == UI_SAVEAS ||
  5291. m_UI_mode == UI_SAVE_OVERWRITE ||
  5292. m_UI_mode == UI_EXPORT_SHAPE ||
  5293. m_UI_mode == UI_IMPORT_SHAPE ||
  5294. m_UI_mode == UI_EXPORT_WAVE ||
  5295. m_UI_mode == UI_IMPORT_WAVE)
  5296. {
  5297. //m_bPresetLockedByCode = false;
  5298. m_waitstring.bActive = false;
  5299. m_UI_mode = UI_REGULAR;
  5300. }
  5301. else if (m_UI_mode == UI_EDIT_MENU_STRING)
  5302. {
  5303. m_waitstring.bActive = false;
  5304. if (m_waitstring.bDisplayAsCode) // if were editing code...
  5305. m_UI_mode = UI_MENU; // return to menu
  5306. else
  5307. m_UI_mode = UI_REGULAR; // otherwise don't (we might have been editing a filename, for example)
  5308. }
  5309. else /*if (m_UI_mode == UI_EDIT_MENU_STRING || m_UI_mode == UI_CHANGEDIR || 1)*/
  5310. {
  5311. m_waitstring.bActive = false;
  5312. m_UI_mode = UI_REGULAR;
  5313. }
  5314. return 0; // we processed (or absorbed) the key
  5315. }
  5316. }
  5317. // don't let keys go anywhere else
  5318. return 0; // we processed (or absorbed) the key
  5319. }
  5320. // case 2: menu is up & gets the keyboard input
  5321. if (m_UI_mode == UI_MENU)
  5322. {
  5323. //assert(m_pCurMenu);
  5324. if (m_pCurMenu->HandleKeydown(hWnd, uMsg, wParam, lParam) == 0)
  5325. return 0; // we processed (or absorbed) the key
  5326. }
  5327. // case 3: handle non-character keys (virtual keys) and return 0.
  5328. // if we don't handle them, return 1, and the shell will
  5329. // (passing some to the shell's key bindings, some to Winamp,
  5330. // and some to DefWindowProc)
  5331. // note: regular hotkeys should be handled in HandleRegularKey.
  5332. switch(wParam)
  5333. {
  5334. case VK_LEFT:
  5335. case VK_RIGHT:
  5336. if (m_UI_mode == UI_LOAD)
  5337. {
  5338. // it's annoying when the music skips if you hit the left arrow from the Load menu, so instead, we exit the menu
  5339. if (wParam == VK_LEFT) m_UI_mode = UI_REGULAR;
  5340. return 0; // we processed (or absorbed) the key
  5341. }
  5342. else if (m_UI_mode == UI_UPGRADE_PIXEL_SHADER)
  5343. {
  5344. m_UI_mode = UI_MENU;
  5345. return 0; // we processed (or absorbed) the key
  5346. }
  5347. else if (m_UI_mode == UI_MASHUP)
  5348. {
  5349. if (wParam==VK_LEFT)
  5350. m_nMashSlot = max(0, m_nMashSlot-1);
  5351. else
  5352. m_nMashSlot = min(MASH_SLOTS-1, m_nMashSlot+1);
  5353. return 0; // we processed (or absorbed) the key
  5354. }
  5355. break;
  5356. case VK_ESCAPE:
  5357. if (m_UI_mode == UI_LOAD || m_UI_mode == UI_MENU || m_UI_mode == UI_MASHUP)
  5358. {
  5359. m_UI_mode = UI_REGULAR;
  5360. return 0; // we processed (or absorbed) the key
  5361. }
  5362. else if (m_UI_mode == UI_LOAD_DEL)
  5363. {
  5364. m_UI_mode = UI_LOAD;
  5365. return 0; // we processed (or absorbed) the key
  5366. }
  5367. else if (m_UI_mode == UI_UPGRADE_PIXEL_SHADER)
  5368. {
  5369. m_UI_mode = UI_MENU;
  5370. return 0; // we processed (or absorbed) the key
  5371. }
  5372. else if (m_UI_mode == UI_SAVE_OVERWRITE)
  5373. {
  5374. m_UI_mode = UI_SAVEAS;
  5375. // return to waitstring mode, leaving all the parameters as they were before:
  5376. m_waitstring.bActive = true;
  5377. return 0; // we processed (or absorbed) the key
  5378. }
  5379. /*else if (hwnd == GetPluginWindow()) // (don't close on ESC for text window)
  5380. {
  5381. dumpmsg("User pressed ESCAPE");
  5382. //m_bExiting = true;
  5383. PostMessage(hwnd, WM_CLOSE, 0, 0);
  5384. return 0; // we processed (or absorbed) the key
  5385. }*/
  5386. break;
  5387. case VK_UP:
  5388. if (m_UI_mode == UI_MASHUP)
  5389. {
  5390. for (rep=0; rep<nRepeat; rep++)
  5391. m_nMashPreset[m_nMashSlot] = max(m_nMashPreset[m_nMashSlot]-1, m_nDirs);
  5392. m_nLastMashChangeFrame[m_nMashSlot] = GetFrame(); // causes delayed apply
  5393. return 0; // we processed (or absorbed) the key
  5394. }
  5395. else if (m_UI_mode == UI_LOAD)
  5396. {
  5397. for (rep=0; rep<nRepeat; rep++)
  5398. if (m_nPresetListCurPos > 0)
  5399. m_nPresetListCurPos--;
  5400. return 0; // we processed (or absorbed) the key
  5401. // remember this preset's name so the next time they hit 'L' it jumps straight to it
  5402. //lstrcpy(m_szLastPresetSelected, m_presets[m_nPresetListCurPos].szFilename.c_str());
  5403. }
  5404. break;
  5405. case VK_DOWN:
  5406. if (m_UI_mode == UI_MASHUP)
  5407. {
  5408. for (rep=0; rep<nRepeat; rep++)
  5409. m_nMashPreset[m_nMashSlot] = min(m_nMashPreset[m_nMashSlot]+1, m_nPresets-1);
  5410. m_nLastMashChangeFrame[m_nMashSlot] = GetFrame(); // causes delayed apply
  5411. return 0; // we processed (or absorbed) the key
  5412. }
  5413. else if (m_UI_mode == UI_LOAD)
  5414. {
  5415. for (rep=0; rep<nRepeat; rep++)
  5416. if (m_nPresetListCurPos < m_nPresets - 1)
  5417. m_nPresetListCurPos++;
  5418. return 0; // we processed (or absorbed) the key
  5419. // remember this preset's name so the next time they hit 'L' it jumps straight to it
  5420. //lstrcpy(m_szLastPresetSelected, m_presets[m_nPresetListCurPos].szFilename.c_str());
  5421. }
  5422. break;
  5423. case VK_SPACE:
  5424. if (m_UI_mode == UI_LOAD)
  5425. goto HitEnterFromLoadMenu;
  5426. if (!m_bPresetLockedByCode)
  5427. {
  5428. LoadRandomPreset(m_fBlendTimeUser);
  5429. return 0; // we processed (or absorbed) the key
  5430. }
  5431. break;
  5432. case VK_PRIOR:
  5433. if (m_UI_mode == UI_LOAD || m_UI_mode == UI_MASHUP)
  5434. {
  5435. m_bUserPagedUp = true;
  5436. if (m_UI_mode == UI_MASHUP)
  5437. m_nLastMashChangeFrame[m_nMashSlot] = GetFrame(); // causes delayed apply
  5438. return 0; // we processed (or absorbed) the key
  5439. }
  5440. break;
  5441. case VK_NEXT:
  5442. if (m_UI_mode == UI_LOAD || m_UI_mode == UI_MASHUP)
  5443. {
  5444. m_bUserPagedDown = true;
  5445. if (m_UI_mode == UI_MASHUP)
  5446. m_nLastMashChangeFrame[m_nMashSlot] = GetFrame(); // causes delayed apply
  5447. return 0; // we processed (or absorbed) the key
  5448. }
  5449. break;
  5450. case VK_HOME:
  5451. if (m_UI_mode == UI_LOAD)
  5452. {
  5453. m_nPresetListCurPos = 0;
  5454. return 0; // we processed (or absorbed) the key
  5455. }
  5456. else if (m_UI_mode == UI_MASHUP)
  5457. {
  5458. m_nMashPreset[m_nMashSlot] = m_nDirs;
  5459. m_nLastMashChangeFrame[m_nMashSlot] = GetFrame(); // causes delayed apply
  5460. return 0; // we processed (or absorbed) the key
  5461. }
  5462. break;
  5463. case VK_END:
  5464. if (m_UI_mode == UI_LOAD)
  5465. {
  5466. m_nPresetListCurPos = m_nPresets - 1;
  5467. return 0; // we processed (or absorbed) the key
  5468. }
  5469. else if (m_UI_mode == UI_MASHUP)
  5470. {
  5471. m_nMashPreset[m_nMashSlot] = m_nPresets-1;
  5472. m_nLastMashChangeFrame[m_nMashSlot] = GetFrame(); // causes delayed apply
  5473. return 0; // we processed (or absorbed) the key
  5474. }
  5475. break;
  5476. case VK_DELETE:
  5477. if (m_UI_mode == UI_LOAD)
  5478. {
  5479. if (m_presets[m_nPresetListCurPos].szFilename.c_str()[0] != '*') // can't delete directories
  5480. m_UI_mode = UI_LOAD_DEL;
  5481. return 0; // we processed (or absorbed) the key
  5482. }
  5483. else //if (m_nNumericInputDigits == 0)
  5484. {
  5485. if (m_nNumericInputMode == NUMERIC_INPUT_MODE_CUST_MSG)
  5486. {
  5487. m_nNumericInputDigits = 0;
  5488. m_nNumericInputNum = 0;
  5489. // stop display of text message.
  5490. m_supertext.fStartTime = -1.0f;
  5491. return 0; // we processed (or absorbed) the key
  5492. }
  5493. else if (m_nNumericInputMode == NUMERIC_INPUT_MODE_SPRITE)
  5494. {
  5495. // kill newest sprite (regular DELETE key)
  5496. // oldest sprite (SHIFT + DELETE),
  5497. // or all sprites (CTRL + SHIFT + DELETE).
  5498. m_nNumericInputDigits = 0;
  5499. m_nNumericInputNum = 0;
  5500. USHORT mask = 1 << (sizeof(SHORT)*8 - 1); // we want the highest-order bit
  5501. bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0;
  5502. bool bCtrlHeldDown = (GetKeyState(VK_CONTROL) & mask) != 0;
  5503. if (bShiftHeldDown && bCtrlHeldDown)
  5504. {
  5505. for (int x=0; x<NUM_TEX; x++)
  5506. m_texmgr.KillTex(x);
  5507. }
  5508. else
  5509. {
  5510. int newest = -1;
  5511. int frame;
  5512. for (int x=0; x<NUM_TEX; x++)
  5513. {
  5514. if (m_texmgr.m_tex[x].pSurface)
  5515. {
  5516. if ((newest == -1) ||
  5517. (!bShiftHeldDown && m_texmgr.m_tex[x].nStartFrame > frame) ||
  5518. (bShiftHeldDown && m_texmgr.m_tex[x].nStartFrame < frame))
  5519. {
  5520. newest = x;
  5521. frame = m_texmgr.m_tex[x].nStartFrame;
  5522. }
  5523. }
  5524. }
  5525. if (newest != -1)
  5526. m_texmgr.KillTex(newest);
  5527. }
  5528. return 0; // we processed (or absorbed) the key
  5529. }
  5530. }
  5531. break;
  5532. case VK_INSERT: // RENAME
  5533. if (m_UI_mode == UI_LOAD)
  5534. {
  5535. if (m_presets[m_nPresetListCurPos].szFilename.c_str()[0] != '*') // can't rename directories
  5536. {
  5537. // go into RENAME mode
  5538. m_UI_mode = UI_LOAD_RENAME;
  5539. m_waitstring.bActive = true;
  5540. m_waitstring.bFilterBadChars = true;
  5541. m_waitstring.bDisplayAsCode = false;
  5542. m_waitstring.nSelAnchorPos = -1;
  5543. m_waitstring.nMaxLen = min(sizeof(m_waitstring.szText)-1, MAX_PATH - lstrlenW(GetPresetDir()) - 6); // 6 for the extension + null char. We set this because win32 LoadFile, MoveFile, etc. barf if the path+filename+ext are > MAX_PATH chars.
  5544. // initial string is the filename, minus the extension
  5545. lstrcpyW(m_waitstring.szText, m_presets[m_nPresetListCurPos].szFilename.c_str());
  5546. RemoveExtension(m_waitstring.szText);
  5547. // set the prompt & 'tooltip'
  5548. swprintf(m_waitstring.szPrompt, WASABI_API_LNGSTRINGW(IDS_ENTER_THE_NEW_NAME_FOR_X), m_waitstring.szText);
  5549. m_waitstring.szToolTip[0] = 0;
  5550. // set the starting edit position
  5551. m_waitstring.nCursorPos = lstrlenW(m_waitstring.szText);
  5552. }
  5553. return 0; // we processed (or absorbed) the key
  5554. }
  5555. break;
  5556. case VK_RETURN:
  5557. if (m_UI_mode == UI_MASHUP)
  5558. {
  5559. m_nLastMashChangeFrame[m_nMashSlot] = GetFrame() + MASH_APPLY_DELAY_FRAMES; // causes instant apply
  5560. return 0; // we processed (or absorbed) the key
  5561. }
  5562. else if (m_UI_mode == UI_LOAD)
  5563. {
  5564. HitEnterFromLoadMenu:
  5565. if (m_presets[m_nPresetListCurPos].szFilename.c_str()[0] == '*')
  5566. {
  5567. // CHANGE DIRECTORY
  5568. wchar_t *p = GetPresetDir();
  5569. if (wcscmp(m_presets[m_nPresetListCurPos].szFilename.c_str(), L"*..") == 0)
  5570. {
  5571. // back up one dir
  5572. wchar_t *p2 = wcsrchr(p, L'\\');
  5573. if (p2)
  5574. {
  5575. *p2 = 0;
  5576. p2 = wcsrchr(p, L'\\');
  5577. if (p2) *(p2+1) = 0;
  5578. }
  5579. }
  5580. else
  5581. {
  5582. // open subdir
  5583. lstrcatW(p, &m_presets[m_nPresetListCurPos].szFilename.c_str()[1]);
  5584. lstrcatW(p, L"\\");
  5585. }
  5586. WritePrivateProfileStringW(L"settings",L"szPresetDir",GetPresetDir(),GetConfigIniFile());
  5587. UpdatePresetList(false, true, false);
  5588. // set current preset index to -1 because current preset is no longer in the list
  5589. m_nCurrentPreset = -1;
  5590. }
  5591. else
  5592. {
  5593. // LOAD NEW PRESET
  5594. m_nCurrentPreset = m_nPresetListCurPos;
  5595. // first take the filename and prepend the path. (already has extension)
  5596. wchar_t s[MAX_PATH];
  5597. lstrcpyW(s, GetPresetDir()); // note: m_szPresetDir always ends with '\'
  5598. lstrcatW(s, m_presets[m_nCurrentPreset].szFilename.c_str());
  5599. // now load (and blend to) the new preset
  5600. m_presetHistoryPos = (m_presetHistoryPos+1) % PRESET_HIST_LEN;
  5601. LoadPreset(s, (wParam==VK_SPACE) ? m_fBlendTimeUser : 0);
  5602. }
  5603. return 0; // we processed (or absorbed) the key
  5604. }
  5605. break;
  5606. case VK_BACK:
  5607. // pass on to parent
  5608. //PostMessage(m_hWndParent,message,wParam,lParam);
  5609. PrevPreset(0);
  5610. m_fHardCutThresh *= 2.0f; // make it a little less likely that a random hard cut follows soon.
  5611. //m_nNumericInputDigits = 0;
  5612. //m_nNumericInputNum = 0;
  5613. return 0;
  5614. case 'T':
  5615. if (bCtrlHeldDown)
  5616. {
  5617. // stop display of custom message or song title.
  5618. m_supertext.fStartTime = -1.0f;
  5619. return 0;
  5620. }
  5621. break;
  5622. case 'K':
  5623. if (bCtrlHeldDown) // kill all sprites
  5624. {
  5625. for (int x=0; x<NUM_TEX; x++)
  5626. if (m_texmgr.m_tex[x].pSurface)
  5627. m_texmgr.KillTex(x);
  5628. return 0;
  5629. }
  5630. break;
  5631. /*case keyMappings[2]: // 'Y'
  5632. if (bCtrlHeldDown) // stop display of custom message or song title.
  5633. {
  5634. m_supertext.fStartTime = -1.0f;
  5635. return 0;
  5636. }
  5637. break;*/
  5638. }
  5639. if (wParam == keyMappings[2]) // 'Y'
  5640. {
  5641. if (bCtrlHeldDown) // stop display of custom message or song title.
  5642. {
  5643. m_supertext.fStartTime = -1.0f;
  5644. return 0;
  5645. }
  5646. }
  5647. return 1; // end case WM_KEYDOWN
  5648. case WM_KEYUP:
  5649. return 1;
  5650. break;
  5651. default:
  5652. return DefWindowProcW(hWnd, uMsg, wParam, lParam);
  5653. break;
  5654. }
  5655. return 0;
  5656. };
  5657. //----------------------------------------------------------------------
  5658. int CPlugin::HandleRegularKey(WPARAM wParam)
  5659. {
  5660. // here we handle all the normal keys for milkdrop-
  5661. // these are the hotkeys that are used when you're not
  5662. // in the middle of editing a string, navigating a menu, etc.
  5663. // do not make references to virtual keys here; only
  5664. // straight WM_CHAR messages should be sent in.
  5665. // return 0 if you process/absorb the key; otherwise return 1.
  5666. if (m_UI_mode == UI_LOAD && ((wParam >= 'A' && wParam <= 'Z') || (wParam >= 'a' && wParam <= 'z')))
  5667. {
  5668. SeekToPreset((char)wParam);
  5669. return 0; // we processed (or absorbed) the key
  5670. }
  5671. else if (m_UI_mode == UI_MASHUP && wParam >= '1' && wParam <= ('0' + MASH_SLOTS))
  5672. {
  5673. m_nMashSlot = wParam - '1';
  5674. }
  5675. else switch(wParam)
  5676. {
  5677. case '0':
  5678. case '1':
  5679. case '2':
  5680. case '3':
  5681. case '4':
  5682. case '5':
  5683. case '6':
  5684. case '7':
  5685. case '8':
  5686. case '9':
  5687. {
  5688. int digit = wParam - '0';
  5689. m_nNumericInputNum = (m_nNumericInputNum*10) + digit;
  5690. m_nNumericInputDigits++;
  5691. if (m_nNumericInputDigits >= 2)
  5692. {
  5693. if (m_nNumericInputMode == NUMERIC_INPUT_MODE_CUST_MSG)
  5694. LaunchCustomMessage(m_nNumericInputNum);
  5695. else if (m_nNumericInputMode == NUMERIC_INPUT_MODE_SPRITE)
  5696. LaunchSprite(m_nNumericInputNum, -1);
  5697. else if (m_nNumericInputMode == NUMERIC_INPUT_MODE_SPRITE_KILL)
  5698. {
  5699. for (int x=0; x<NUM_TEX; x++)
  5700. if (m_texmgr.m_tex[x].nUserData == m_nNumericInputNum)
  5701. m_texmgr.KillTex(x);
  5702. }
  5703. m_nNumericInputDigits = 0;
  5704. m_nNumericInputNum = 0;
  5705. }
  5706. }
  5707. return 0; // we processed (or absorbed) the key
  5708. // row 1 keys
  5709. case 'q':
  5710. m_pState->m_fVideoEchoZoom /= 1.05f;
  5711. return 0; // we processed (or absorbed) the key
  5712. case 'Q':
  5713. m_pState->m_fVideoEchoZoom *= 1.05f;
  5714. return 0; // we processed (or absorbed) the key
  5715. case 'w':
  5716. m_pState->m_nWaveMode++;
  5717. if (m_pState->m_nWaveMode >= NUM_WAVES) m_pState->m_nWaveMode = 0;
  5718. return 0; // we processed (or absorbed) the key
  5719. case 'W':
  5720. m_pState->m_nWaveMode--;
  5721. if (m_pState->m_nWaveMode < 0) m_pState->m_nWaveMode = NUM_WAVES - 1;
  5722. return 0; // we processed (or absorbed) the key
  5723. case 'e':
  5724. m_pState->m_fWaveAlpha -= 0.1f;
  5725. if (m_pState->m_fWaveAlpha.eval(-1) < 0.0f) m_pState->m_fWaveAlpha = 0.0f;
  5726. return 0; // we processed (or absorbed) the key
  5727. case 'E':
  5728. m_pState->m_fWaveAlpha += 0.1f;
  5729. //if (m_pState->m_fWaveAlpha.eval(-1) > 1.0f) m_pState->m_fWaveAlpha = 1.0f;
  5730. return 0; // we processed (or absorbed) the key
  5731. case 'I': m_pState->m_fZoom -= 0.01f; return 0; // we processed (or absorbed) the key
  5732. case 'i': m_pState->m_fZoom += 0.01f; return 0; // we processed (or absorbed) the key
  5733. case 'n':
  5734. case 'N':
  5735. m_bShowDebugInfo = !m_bShowDebugInfo;
  5736. return 0; // we processed (or absorbed) the key
  5737. case 'r':
  5738. m_bSequentialPresetOrder = !m_bSequentialPresetOrder;
  5739. {
  5740. wchar_t buf[1024], tmp[64];
  5741. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_PRESET_ORDER_IS_NOW_X),
  5742. WASABI_API_LNGSTRINGW_BUF((m_bSequentialPresetOrder) ? IDS_SEQUENTIAL : IDS_RANDOM, tmp, 64));
  5743. AddError(buf, 3.0f, ERR_NOTIFY, false);
  5744. }
  5745. // erase all history, too:
  5746. m_presetHistory[0] = m_szCurrentPresetFile;
  5747. m_presetHistoryPos = 0;
  5748. m_presetHistoryFwdFence = 1;
  5749. m_presetHistoryBackFence = 0;
  5750. return 0; // we processed (or absorbed) the key
  5751. case 'u':
  5752. case 'U':
  5753. if (SendMessage(GetWinampWindow(),WM_USER,0,250))
  5754. AddError(WASABI_API_LNGSTRINGW(IDS_SHUFFLE_IS_NOW_OFF), 3.0f, ERR_NOTIFY, false);
  5755. else
  5756. AddError(WASABI_API_LNGSTRINGW(IDS_SHUFFLE_IS_NOW_ON), 3.0f, ERR_NOTIFY, false);
  5757. //m_fShowUserMessageUntilThisTime = GetTime() + 4.0f;
  5758. // toggle shuffle
  5759. PostMessage(GetWinampWindow(),WM_COMMAND,40023,0);
  5760. return 0; // we processed (or absorbed) the key
  5761. /*
  5762. case 'u': m_pState->m_fWarpScale /= 1.1f; break;
  5763. case 'U': m_pState->m_fWarpScale *= 1.1f; break;
  5764. case 'i': m_pState->m_fWarpAnimSpeed /= 1.1f; break;
  5765. case 'I': m_pState->m_fWarpAnimSpeed *= 1.1f; break;
  5766. */
  5767. case 't':
  5768. case 'T':
  5769. LaunchSongTitleAnim();
  5770. return 0; // we processed (or absorbed) the key
  5771. case 'o': m_pState->m_fWarpAmount /= 1.1f; return 0; // we processed (or absorbed) the key
  5772. case 'O': m_pState->m_fWarpAmount *= 1.1f; return 0; // we processed (or absorbed) the key
  5773. case '!':
  5774. // randomize warp shader
  5775. {
  5776. bool bWarpLock = m_bWarpShaderLock;
  5777. wchar_t szOldPreset[MAX_PATH];
  5778. lstrcpyW(szOldPreset, m_szCurrentPresetFile);
  5779. m_bWarpShaderLock = false;
  5780. LoadRandomPreset(0.0f);
  5781. m_bWarpShaderLock = true;
  5782. LoadPreset(szOldPreset, 0.0f);
  5783. m_bWarpShaderLock = bWarpLock;
  5784. }
  5785. break;
  5786. case '@':
  5787. // randomize comp shader
  5788. {
  5789. bool bCompLock = m_bCompShaderLock;
  5790. wchar_t szOldPreset[MAX_PATH];
  5791. lstrcpyW(szOldPreset, m_szCurrentPresetFile);
  5792. m_bCompShaderLock = false;
  5793. LoadRandomPreset(0.0f);
  5794. m_bCompShaderLock = true;
  5795. LoadPreset(szOldPreset, 0.0f);
  5796. m_bCompShaderLock = bCompLock;
  5797. }
  5798. break;
  5799. case 'a':
  5800. case 'A':
  5801. // load a random preset, a random warp shader, and a random comp shader.
  5802. // not quite as extreme as a mash-up.
  5803. {
  5804. bool bCompLock = m_bCompShaderLock;
  5805. bool bWarpLock = m_bWarpShaderLock;
  5806. m_bCompShaderLock = false; m_bWarpShaderLock = false;
  5807. LoadRandomPreset(0.0f);
  5808. m_bCompShaderLock = true; m_bWarpShaderLock = false;
  5809. LoadRandomPreset(0.0f);
  5810. m_bCompShaderLock = false; m_bWarpShaderLock = true;
  5811. LoadRandomPreset(0.0f);
  5812. m_bCompShaderLock = bCompLock;
  5813. m_bWarpShaderLock = bWarpLock;
  5814. }
  5815. break;
  5816. case 'd':
  5817. case 'D':
  5818. if (!m_bCompShaderLock && !m_bWarpShaderLock) {
  5819. m_bCompShaderLock = true; m_bWarpShaderLock = false;
  5820. AddError(WASABI_API_LNGSTRINGW(IDS_COMPSHADER_LOCKED), 3.0f, ERR_NOTIFY, false);
  5821. } else if (m_bCompShaderLock && !m_bWarpShaderLock) {
  5822. m_bCompShaderLock = false; m_bWarpShaderLock = true;
  5823. AddError(WASABI_API_LNGSTRINGW(IDS_WARPSHADER_LOCKED), 3.0f, ERR_NOTIFY, false);
  5824. } else if (!m_bCompShaderLock && m_bWarpShaderLock) {
  5825. m_bCompShaderLock = true; m_bWarpShaderLock = true;
  5826. AddError(WASABI_API_LNGSTRINGW(IDS_ALLSHADERS_LOCKED), 3.0f, ERR_NOTIFY, false);
  5827. } else {
  5828. m_bCompShaderLock = false; m_bWarpShaderLock = false;
  5829. AddError(WASABI_API_LNGSTRINGW(IDS_ALLSHADERS_UNLOCKED), 3.0f, ERR_NOTIFY, false);
  5830. }
  5831. break;
  5832. // row 2 keys
  5833. // 'A' KEY IS FREE!!
  5834. // 'D' KEY IS FREE!!
  5835. /*case 'a':
  5836. m_pState->m_fVideoEchoAlpha -= 0.1f;
  5837. if (m_pState->m_fVideoEchoAlpha.eval(-1) < 0) m_pState->m_fVideoEchoAlpha = 0;
  5838. return 0; // we processed (or absorbed) the key
  5839. case 'A':
  5840. m_pState->m_fVideoEchoAlpha += 0.1f;
  5841. if (m_pState->m_fVideoEchoAlpha.eval(-1) > 1.0f) m_pState->m_fVideoEchoAlpha = 1.0f;
  5842. return 0; // we processed (or absorbed) the key
  5843. case 'd':
  5844. m_pState->m_fDecay += 0.01f;
  5845. if (m_pState->m_fDecay.eval(-1) > 1.0f) m_pState->m_fDecay = 1.0f;
  5846. return 0; // we processed (or absorbed) the key
  5847. case 'D':
  5848. m_pState->m_fDecay -= 0.01f;
  5849. if (m_pState->m_fDecay.eval(-1) < 0.9f) m_pState->m_fDecay = 0.9f;
  5850. return 0; // we processed (or absorbed) the key*/
  5851. case 'h':
  5852. case 'H':
  5853. // instant hard cut
  5854. if (m_UI_mode == UI_MASHUP)
  5855. {
  5856. if (wParam=='h')
  5857. {
  5858. m_nMashPreset[m_nMashSlot] = m_nDirs + (warand() % (m_nPresets-m_nDirs));
  5859. m_nLastMashChangeFrame[m_nMashSlot] = GetFrame() + MASH_APPLY_DELAY_FRAMES; // causes instant apply
  5860. }
  5861. else
  5862. {
  5863. for (int mash=0; mash<MASH_SLOTS; mash++)
  5864. {
  5865. m_nMashPreset[mash] = m_nDirs + (warand() % (m_nPresets-m_nDirs));
  5866. m_nLastMashChangeFrame[mash] = GetFrame() + MASH_APPLY_DELAY_FRAMES; // causes instant apply
  5867. }
  5868. }
  5869. }
  5870. else
  5871. {
  5872. NextPreset(0);
  5873. m_fHardCutThresh *= 2.0f; // make it a little less likely that a random hard cut follows soon.
  5874. }
  5875. return 0; // we processed (or absorbed) the key
  5876. case 'f':
  5877. case 'F':
  5878. m_pState->m_nVideoEchoOrientation = (m_pState->m_nVideoEchoOrientation + 1) % 4;
  5879. return 0; // we processed (or absorbed) the key
  5880. case 'g':
  5881. m_pState->m_fGammaAdj -= 0.1f;
  5882. if (m_pState->m_fGammaAdj.eval(-1) < 0.0f) m_pState->m_fGammaAdj = 0.0f;
  5883. return 0; // we processed (or absorbed) the key
  5884. case 'G':
  5885. m_pState->m_fGammaAdj += 0.1f;
  5886. //if (m_pState->m_fGammaAdj > 1.0f) m_pState->m_fGammaAdj = 1.0f;
  5887. return 0; // we processed (or absorbed) the key
  5888. case 'j':
  5889. m_pState->m_fWaveScale *= 0.9f;
  5890. return 0; // we processed (or absorbed) the key
  5891. case 'J':
  5892. m_pState->m_fWaveScale /= 0.9f;
  5893. return 0; // we processed (or absorbed) the key
  5894. case 'k':
  5895. case 'K':
  5896. {
  5897. USHORT mask = 1 << (sizeof(SHORT)*8 - 1); // we want the highest-order bit
  5898. bool bShiftHeldDown = (GetKeyState(VK_SHIFT) & mask) != 0;
  5899. if (bShiftHeldDown)
  5900. m_nNumericInputMode = NUMERIC_INPUT_MODE_SPRITE_KILL;
  5901. else
  5902. m_nNumericInputMode = NUMERIC_INPUT_MODE_SPRITE;
  5903. m_nNumericInputNum = 0;
  5904. m_nNumericInputDigits = 0;
  5905. }
  5906. return 0; // we processed (or absorbed) the key
  5907. // row 3/misc. keys
  5908. case '[':
  5909. m_pState->m_fXPush -= 0.005f;
  5910. return 0; // we processed (or absorbed) the key
  5911. case ']':
  5912. m_pState->m_fXPush += 0.005f;
  5913. return 0; // we processed (or absorbed) the key
  5914. case '{':
  5915. m_pState->m_fYPush -= 0.005f;
  5916. return 0; // we processed (or absorbed) the key
  5917. case '}':
  5918. m_pState->m_fYPush += 0.005f;
  5919. return 0; // we processed (or absorbed) the key
  5920. case '<':
  5921. m_pState->m_fRot += 0.02f;
  5922. return 0; // we processed (or absorbed) the key
  5923. case '>':
  5924. m_pState->m_fRot -= 0.02f;
  5925. return 0; // we processed (or absorbed) the key
  5926. case 's': // SAVE PRESET
  5927. case 'S':
  5928. if (m_UI_mode == UI_REGULAR)
  5929. {
  5930. //m_bPresetLockedByCode = true;
  5931. m_UI_mode = UI_SAVEAS;
  5932. // enter WaitString mode
  5933. m_waitstring.bActive = true;
  5934. m_waitstring.bFilterBadChars = true;
  5935. m_waitstring.bDisplayAsCode = false;
  5936. m_waitstring.nSelAnchorPos = -1;
  5937. m_waitstring.nMaxLen = min(sizeof(m_waitstring.szText)-1, MAX_PATH - lstrlenW(GetPresetDir()) - 6); // 6 for the extension + null char. We set this because win32 LoadFile, MoveFile, etc. barf if the path+filename+ext are > MAX_PATH chars.
  5938. lstrcpyW(m_waitstring.szText, m_pState->m_szDesc); // initial string is the filename, minus the extension
  5939. WASABI_API_LNGSTRINGW_BUF(IDS_SAVE_AS,m_waitstring.szPrompt,512);
  5940. m_waitstring.szToolTip[0] = 0;
  5941. m_waitstring.nCursorPos = lstrlenW(m_waitstring.szText); // set the starting edit position
  5942. return 0;
  5943. }
  5944. break;
  5945. case 'l': // LOAD PRESET
  5946. case 'L':
  5947. if (m_UI_mode == UI_LOAD)
  5948. {
  5949. m_UI_mode = UI_REGULAR;
  5950. return 0; // we processed (or absorbed) the key
  5951. }
  5952. else if (
  5953. m_UI_mode == UI_REGULAR ||
  5954. m_UI_mode == UI_MENU)
  5955. {
  5956. UpdatePresetList(); // make sure list is completely ready
  5957. m_UI_mode = UI_LOAD;
  5958. m_bUserPagedUp = false;
  5959. m_bUserPagedDown = false;
  5960. return 0; // we processed (or absorbed) the key
  5961. }
  5962. break;
  5963. case 'm':
  5964. case 'M':
  5965. if (m_UI_mode == UI_MENU)
  5966. m_UI_mode = UI_REGULAR;
  5967. else if (m_UI_mode == UI_REGULAR || m_UI_mode == UI_LOAD)
  5968. m_UI_mode = UI_MENU;
  5969. return 0; // we processed (or absorbed) the key
  5970. case '-':
  5971. SetCurrentPresetRating(m_pState->m_fRating - 1.0f);
  5972. return 0; // we processed (or absorbed) the key
  5973. case '+':
  5974. SetCurrentPresetRating(m_pState->m_fRating + 1.0f);
  5975. return 0; // we processed (or absorbed) the key
  5976. case '*':
  5977. m_nNumericInputDigits = 0;
  5978. m_nNumericInputNum = 0;
  5979. return 0;
  5980. }
  5981. if (wParam == keyMappings[3] || wParam == keyMappings[4]) // 'y' or 'Y'
  5982. {
  5983. m_nNumericInputMode = NUMERIC_INPUT_MODE_CUST_MSG;
  5984. m_nNumericInputNum = 0;
  5985. m_nNumericInputDigits = 0;
  5986. return 0; // we processed (or absorbed) the key
  5987. }
  5988. return 1;
  5989. }
  5990. //----------------------------------------------------------------------
  5991. void CPlugin::RefreshTab2(HWND hwnd)
  5992. {
  5993. ShowWindow(GetDlgItem(hwnd, IDC_BRIGHT_SLIDER), !m_bAutoGamma);
  5994. ShowWindow(GetDlgItem(hwnd, IDC_T1), !m_bAutoGamma);
  5995. ShowWindow(GetDlgItem(hwnd, IDC_T2), !m_bAutoGamma);
  5996. ShowWindow(GetDlgItem(hwnd, IDC_T3), !m_bAutoGamma);
  5997. ShowWindow(GetDlgItem(hwnd, IDC_T4), !m_bAutoGamma);
  5998. ShowWindow(GetDlgItem(hwnd, IDC_T5), !m_bAutoGamma);
  5999. }
  6000. int CALLBACK MyEnumFontsProc(
  6001. CONST LOGFONT *lplf, // logical-font data
  6002. CONST TEXTMETRIC *lptm, // physical-font data
  6003. DWORD dwType, // font type
  6004. LPARAM lpData // application-defined data
  6005. )
  6006. {
  6007. SendMessage( GetDlgItem( (HWND)lpData, IDC_FONT3), CB_ADDSTRING, 0, (LPARAM)(lplf->lfFaceName));
  6008. return 1;
  6009. }
  6010. /*
  6011. void DoColors(HWND hwnd, int *r, int *g, int *b)
  6012. {
  6013. static COLORREF acrCustClr[16];
  6014. CHOOSECOLOR cc;
  6015. ZeroMemory(&cc, sizeof(CHOOSECOLOR));
  6016. cc.lStructSize = sizeof(CHOOSECOLOR);
  6017. cc.hwndOwner = hwnd;//NULL;//hSaverMainWindow;
  6018. cc.Flags = CC_RGBINIT | CC_FULLOPEN;
  6019. cc.rgbResult = RGB(*r,*g,*b);
  6020. cc.lpCustColors = (LPDWORD)acrCustClr;
  6021. if (ChooseColor(&cc))
  6022. {
  6023. *r = GetRValue(cc.rgbResult);
  6024. *g = GetGValue(cc.rgbResult);
  6025. *b = GetBValue(cc.rgbResult);
  6026. }
  6027. }*/
  6028. wchar_t* FormImageCacheSizeString(wchar_t* itemStr, UINT sizeID)
  6029. {
  6030. static wchar_t cacheBuf[128] = {0};
  6031. StringCchPrintfW(cacheBuf, 128, L"%s %s", itemStr, WASABI_API_LNGSTRINGW(sizeID));
  6032. return cacheBuf;
  6033. }
  6034. //----------------------------------------------------------------------
  6035. BOOL CPlugin::MyConfigTabProc(int nPage, HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
  6036. {
  6037. // This is the only function you need to worry about for programming
  6038. // tabs 2 through 8 on the config panel. (Tab 1 contains settings
  6039. // that are common to all plugins, and the code is located in pluginshell.cpp).
  6040. // By default, only tab 2 is enabled; to enable tabes 3+, see
  6041. // 'Enabling Additional Tabs (pages) on the Config Panel' in DOCUMENTATION.TXT.
  6042. // You should always return 0 for this function.
  6043. // Note that you don't generally have to use critical sections or semaphores
  6044. // here; Winamp controls the plugin's message queue, and only gives it message
  6045. // in between frames.
  6046. //
  6047. // Incoming parameters:
  6048. // 'nPage' indicates which tab (aka 'property page') is currently showing: 2 through 5.
  6049. // 'hwnd' is the window handle of the property page (which is a dialog of its own,
  6050. // embedded in the config dialog).
  6051. // 'msg' is the windows message being sent. The main ones are:
  6052. //
  6053. // 1) WM_INITDIALOG: This means the page is being initialized, because the
  6054. // user clicked on it. When you get this message, you should initialize
  6055. // all the controls on the page, and set them to reflect the settings
  6056. // that are stored in member variables.
  6057. //
  6058. // 2) WM_DESTROY: This is sent when a tab disappears, either because another
  6059. // tab is about to be displayed, or because the user clicked OK or Cancel.
  6060. // In any case, you should read the current settings of all the controls
  6061. // on the page, and store them in member variables. (If the user clicked
  6062. // CANCEL, these values will not get saved to disk, but for simplicity,
  6063. // we always poll the controls here.)
  6064. //
  6065. // 3) WM_HELP: This is sent when the user clicks the '?' icon (in the
  6066. // titlebar of the config panel) and then clicks on a control. When you
  6067. // get this message, you should display a MessageBox telling the user
  6068. // a little bit about that control/setting.
  6069. //
  6070. // 4) WM_COMMAND: Advanced. This notifies you when the user clicks on a
  6071. // control. Use this if you need to do certain things when the user
  6072. // changes a setting. (For example, one control might only be enabled
  6073. // when a certain checkbox is enabled; you would use EnableWindow() for
  6074. // this.)
  6075. //
  6076. // For complete details on adding your own controls to one of the pages, please see
  6077. // 'Adding Controls to the Config Panel' in DOCUMENTATION.TXT.
  6078. int t;
  6079. float val;
  6080. if (nPage == 2)
  6081. {
  6082. switch(msg)
  6083. {
  6084. case WM_INITDIALOG: // initialize controls here
  6085. {
  6086. char buf[2048];
  6087. int nPos, i;
  6088. HWND ctrl;
  6089. //-------------- pixel shaders combo box ---------------------
  6090. ctrl = GetDlgItem( hwnd, IDC_SHADERS );
  6091. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_PS_AUTO_RECOMMENDED), -1);
  6092. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_PS_DISABLED), MD2_PS_NONE);
  6093. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_PS_SHADER_MODEL_2), MD2_PS_2_0);
  6094. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_PS_SHADER_MODEL_3), MD2_PS_3_0);
  6095. SelectItemByPos(ctrl, 0); //as a safe default
  6096. SelectItemByValue(ctrl, m_nMaxPSVersion_ConfigPanel);
  6097. //-------------- texture format combo box ---------------------
  6098. ctrl = GetDlgItem( hwnd, IDC_TEXFORMAT );
  6099. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_TX_8_BITS_PER_CHANNEL), 8);
  6100. //AddItem(ctrl, " 10 bits per channel", 10);
  6101. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_TX_16_BITS_PER_CHANNEL), 16);
  6102. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_TX_32_BITS_PER_CHANNEL), 32);
  6103. SelectItemByPos(ctrl, 0); //as a safe default
  6104. SelectItemByValue(ctrl, m_nTexBitsPerCh);
  6105. //-------------- mesh size combo box ---------------------
  6106. ctrl = GetDlgItem( hwnd, IDC_MESHSIZECOMBO );
  6107. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_8X6_FAST), 8);
  6108. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_16X12_FAST), 16);
  6109. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_24X18), 24);
  6110. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_32X24), 32);
  6111. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_40X30), 40);
  6112. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_48X36_DEFAULT), 48);
  6113. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_64X48_SLOW), 64);
  6114. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_80X60_SLOW), 80);
  6115. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_96X72_SLOW), 96);
  6116. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_128X96_SLOW), 128);
  6117. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_160X120_SLOW), 160);
  6118. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_192X144_SLOW), 192);
  6119. SelectItemByPos(ctrl, 0); //as a safe default
  6120. SelectItemByValue(ctrl, m_nGridX);
  6121. //-------------- canvas stretch combo box ---------------------
  6122. ctrl = GetDlgItem( hwnd, IDC_STRETCH );
  6123. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_AUTO), 0);
  6124. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_NONE_BEST_IMAGE_QUALITY), 100);
  6125. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_1_25_X), 125);
  6126. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_1_33_X), 133);
  6127. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_1_5_X), 150);
  6128. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_1_67_X), 167);
  6129. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_2_X), 200);
  6130. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_3_X), 300);
  6131. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_4_X), 400);
  6132. SelectItemByPos(ctrl, 0); //as a safe default
  6133. SelectItemByValue(ctrl, m_nCanvasStretch);
  6134. //-------------- texture size combo box ---------------------
  6135. for (i=0; i<5; i++)
  6136. {
  6137. int size = (int)pow(2., i+8);
  6138. sprintf(buf, " %4d x %4d ", size, size);
  6139. nPos = SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_ADDSTRING, 0, (LPARAM)buf);
  6140. SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_SETITEMDATA, nPos, size);
  6141. }
  6142. // throw the "Auto" option in there
  6143. nPos = SendMessageW( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_ADDSTRING, 0, (LPARAM)WASABI_API_LNGSTRINGW(IDS_NEAREST_POWER_OF_2));
  6144. SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_SETITEMDATA, nPos, -2);
  6145. nPos = SendMessageW( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_ADDSTRING, 0, (LPARAM)WASABI_API_LNGSTRINGW(IDS_EXACT_RECOMMENDED));
  6146. SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_SETITEMDATA, nPos, -1);
  6147. for (i=0; i<5+2; i++)
  6148. {
  6149. int size = SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_GETITEMDATA, i, 0);
  6150. if (size == m_nTexSizeX)
  6151. {
  6152. SendMessage( GetDlgItem( hwnd, IDC_TEXSIZECOMBO ), CB_SETCURSEL, i, 0);
  6153. }
  6154. }
  6155. //---------16-bit brightness slider--------------
  6156. SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER), TBM_SETRANGEMIN,
  6157. FALSE, (LPARAM)(0) );
  6158. SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER), TBM_SETRANGEMAX,
  6159. FALSE, (LPARAM)(4) );
  6160. SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER), TBM_SETPOS,
  6161. TRUE, (LPARAM)(m_n16BitGamma) );
  6162. for (i=0; i<5; i++)
  6163. SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER), TBM_SETTIC, 0, i);
  6164. // append debug output filename to the checkbox's text
  6165. GetWindowText( GetDlgItem(hwnd, IDC_CB_DEBUGOUTPUT), buf, 256);
  6166. lstrcat(buf, DEBUGFILE);
  6167. SetWindowText( GetDlgItem(hwnd, IDC_CB_DEBUGOUTPUT), buf);
  6168. // set checkboxes
  6169. CheckDlgButton(hwnd, IDC_CB_DEBUGOUTPUT, g_bDebugOutput);
  6170. //CheckDlgButton(hwnd, IDC_CB_PRESSF1, (!m_bShowPressF1ForHelp));
  6171. //CheckDlgButton(hwnd, IDC_CB_TOOLTIPS, m_bShowMenuToolTips);
  6172. //CheckDlgButton(hwnd, IDC_CB_ALWAYS3D, m_bAlways3D);
  6173. //CheckDlgButton(hwnd, IDC_CB_FIXSLOWTEXT, m_bFixSlowText);
  6174. //CheckDlgButton(hwnd, IDC_CB_TOP, m_bAlwaysOnTop);
  6175. //CheckDlgButton(hwnd, IDC_CB_CLS, !m_bClearScreenAtStartup);
  6176. //CheckDlgButton(hwnd, IDC_CB_NOWARN, m_bWarningsDisabled);
  6177. CheckDlgButton(hwnd, IDC_CB_NOWARN2, m_bWarningsDisabled2);
  6178. //CheckDlgButton(hwnd, IDC_CB_ANISO, m_bAnisotropicFiltering);
  6179. CheckDlgButton(hwnd, IDC_CB_SCROLLON, m_bPresetLockOnAtStartup);
  6180. CheckDlgButton(hwnd, IDC_CB_SCROLLON2, m_bPreventScollLockHandling);
  6181. //CheckDlgButton(hwnd, IDC_CB_PINKFIX, m_bFixPinkBug);
  6182. CheckDlgButton(hwnd, IDC_CB_NORATING, !m_bEnableRating);
  6183. CheckDlgButton(hwnd, IDC_CB_AUTOGAMMA, m_bAutoGamma);
  6184. RefreshTab2(hwnd);
  6185. }
  6186. break; // case WM_INITDIALOG
  6187. case WM_COMMAND:
  6188. {
  6189. int id = LOWORD(wParam);
  6190. //g_ignore_tab2_clicks = 1;
  6191. switch (id)
  6192. {
  6193. case IDC_CB_NORATING:
  6194. m_bEnableRating = !DlgItemIsChecked(hwnd, IDC_CB_NORATING);
  6195. RefreshTab2(hwnd);
  6196. break;
  6197. case IDC_CB_AUTOGAMMA:
  6198. m_bAutoGamma = DlgItemIsChecked(hwnd, IDC_CB_AUTOGAMMA);
  6199. RefreshTab2(hwnd);
  6200. break;
  6201. }
  6202. //g_ignore_tab2_clicks = 0;
  6203. } // end WM_COMMAND case
  6204. break;
  6205. case WM_DESTROY: // read controls here
  6206. {
  6207. ReadCBValue(hwnd, IDC_SHADERS , &m_nMaxPSVersion_ConfigPanel );
  6208. ReadCBValue(hwnd, IDC_TEXFORMAT , &m_nTexBitsPerCh );
  6209. ReadCBValue(hwnd, IDC_TEXSIZECOMBO , &m_nTexSizeX );
  6210. ReadCBValue(hwnd, IDC_MESHSIZECOMBO, &m_nGridX );
  6211. ReadCBValue(hwnd, IDC_STRETCH , &m_nCanvasStretch);
  6212. // 16-bit-brightness slider - this one doesn't use item values... just item pos.
  6213. t = SendMessage( GetDlgItem( hwnd, IDC_BRIGHT_SLIDER ), TBM_GETPOS, 0, 0);
  6214. if (t != CB_ERR) m_n16BitGamma = t;
  6215. // checkboxes
  6216. g_bDebugOutput = DlgItemIsChecked(hwnd, IDC_CB_DEBUGOUTPUT);
  6217. //m_bShowPressF1ForHelp = (!DlgItemIsChecked(hwnd, IDC_CB_PRESSF1));
  6218. //m_bShowMenuToolTips = DlgItemIsChecked(hwnd, IDC_CB_TOOLTIPS);
  6219. //m_bClearScreenAtStartup = !DlgItemIsChecked(hwnd, IDC_CB_CLS);
  6220. //m_bAlways3D = DlgItemIsChecked(hwnd, IDC_CB_ALWAYS3D);
  6221. //m_bFixSlowText = DlgItemIsChecked(hwnd, IDC_CB_FIXSLOWTEXT);
  6222. //m_bAlwaysOnTop = DlgItemIsChecked(hwnd, IDC_CB_TOP);
  6223. //m_bWarningsDisabled = DlgItemIsChecked(hwnd, IDC_CB_NOWARN);
  6224. m_bWarningsDisabled2 = DlgItemIsChecked(hwnd, IDC_CB_NOWARN2);
  6225. //m_bAnisotropicFiltering = DlgItemIsChecked(hwnd, IDC_CB_ANISO);
  6226. m_bPresetLockOnAtStartup = DlgItemIsChecked(hwnd, IDC_CB_SCROLLON);
  6227. m_bPreventScollLockHandling = DlgItemIsChecked(hwnd, IDC_CB_SCROLLON2);
  6228. //m_bFixPinkBug = DlgItemIsChecked(hwnd, IDC_CB_PINKFIX);
  6229. m_bEnableRating = !DlgItemIsChecked(hwnd, IDC_CB_NORATING);
  6230. m_bAutoGamma = DlgItemIsChecked(hwnd, IDC_CB_AUTOGAMMA);
  6231. }
  6232. break; // case WM_DESTROY
  6233. case WM_HELP: // give help box for controls here
  6234. if (lParam)
  6235. {
  6236. HELPINFO *ph = (HELPINFO*)lParam;
  6237. wchar_t title[1024], buf[2048], ctrl_name[1024];
  6238. GetWindowTextW(GetDlgItem(hwnd, ph->iCtrlId), ctrl_name, sizeof(ctrl_name)/sizeof(*ctrl_name));
  6239. RemoveSingleAmpersands(ctrl_name);
  6240. buf[0] = 0;
  6241. StringCbCopyW(title, sizeof(title), ctrl_name);
  6242. switch(ph->iCtrlId)
  6243. {
  6244. case IDC_SHADERS:
  6245. case IDC_SHADERS_CAPTION:
  6246. WASABI_API_LNGSTRINGW_BUF(IDS_PIXEL_SHADERS, title, sizeof(title)/sizeof(*title));
  6247. WASABI_API_LNGSTRINGW_BUF(IDS_PIXEL_SHADERS_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6248. break;
  6249. case IDC_TEXFORMAT:
  6250. case IDC_TEXFORMAT_CAPTION:
  6251. WASABI_API_LNGSTRINGW_BUF(IDS_TEXFORMAT, title, sizeof(title)/sizeof(*title));
  6252. WASABI_API_LNGSTRINGW_BUF(IDS_TEXFORMAT_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6253. break;
  6254. case IDC_TEXSIZECOMBO:
  6255. case IDC_TEXSIZECOMBO_CAPTION:
  6256. WASABI_API_LNGSTRINGW_BUF(IDS_CANVAS_SIZE, title, sizeof(title)/sizeof(*title));
  6257. WASABI_API_LNGSTRINGW_BUF(IDS_CANVAS_SIZE_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6258. break;
  6259. case IDC_STRETCH:
  6260. case IDC_STRETCH_CAPTION:
  6261. WASABI_API_LNGSTRINGW_BUF(IDS_CANVAS_STRETCH, title, sizeof(title)/sizeof(*title));
  6262. WASABI_API_LNGSTRINGW_BUF(IDS_CANVAS_STRETCH_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6263. break;
  6264. case IDC_MESHSIZECOMBO:
  6265. case IDC_MESHSIZECOMBO_CAPTION:
  6266. WASABI_API_LNGSTRINGW_BUF(IDS_MESH_SIZE, title, sizeof(title)/sizeof(*title));
  6267. WASABI_API_LNGSTRINGW_BUF(IDS_MESH_SIZE_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6268. break;
  6269. case IDC_CB_ALWAYS3D:
  6270. WASABI_API_LNGSTRINGW_BUF(IDS_CB_ALWAYS3D, buf, sizeof(buf)/sizeof(*buf));
  6271. break;
  6272. case IDC_CB_NORATING:
  6273. WASABI_API_LNGSTRINGW_BUF(IDS_DISABLE_PRESET_RATING, title, sizeof(title)/sizeof(*title));
  6274. WASABI_API_LNGSTRINGW_BUF(IDS_DISABLE_PRESET_RATING_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6275. break;
  6276. case IDC_CB_NOWARN2:
  6277. WASABI_API_LNGSTRINGW_BUF(IDS_CB_NOWARN2, buf, sizeof(buf)/sizeof(*buf));
  6278. break;
  6279. case IDC_CB_SCROLLON:
  6280. WASABI_API_LNGSTRINGW_BUF(IDS_START_WITH_PRESET_LOCK_ON, title, sizeof(title)/sizeof(*title));
  6281. WASABI_API_LNGSTRINGW_BUF(IDS_START_WITH_PRESET_LOCK_ON_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6282. break;
  6283. case IDC_BRIGHT_SLIDER:
  6284. case IDC_BRIGHT_SLIDER_BOX:
  6285. case IDC_T1:
  6286. case IDC_T2:
  6287. case IDC_T3:
  6288. case IDC_T4:
  6289. case IDC_T5:
  6290. case IDC_CB_AUTOGAMMA:
  6291. GetWindowTextW(GetDlgItem(hwnd, IDC_BRIGHT_SLIDER_BOX), title, sizeof(title)/sizeof(*title));
  6292. RemoveSingleAmpersands(title);
  6293. WASABI_API_LNGSTRINGW_BUF((ph->iCtrlId==IDC_CB_AUTOGAMMA?IDS_CB_AUTOGAMMA:IDS_BRIGHT_SLIDER), buf, sizeof(buf)/sizeof(*buf));
  6294. break;
  6295. }
  6296. if (buf[0])
  6297. MessageBoxW(hwnd, buf, title, MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL);
  6298. }
  6299. break; // case WM_HELP
  6300. }
  6301. }
  6302. else if (nPage==3)
  6303. {
  6304. switch(msg)
  6305. {
  6306. case WM_INITDIALOG:
  6307. {
  6308. char buf[2048];
  6309. HWND ctrl;
  6310. //-------------- image cache max. bytes combo box ---------------------
  6311. ctrl = GetDlgItem( hwnd, IDC_MAX_BYTES );
  6312. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_AUTO), -1);
  6313. AddItem(ctrl, FormImageCacheSizeString(L" 0", IDS_MB), 0);
  6314. AddItem(ctrl, FormImageCacheSizeString(L" 1", IDS_MB), 1000000);
  6315. AddItem(ctrl, FormImageCacheSizeString(L" 2", IDS_MB), 2000000);
  6316. AddItem(ctrl, FormImageCacheSizeString(L" 3", IDS_MB), 3000000);
  6317. AddItem(ctrl, FormImageCacheSizeString(L" 4", IDS_MB), 4000000);
  6318. AddItem(ctrl, FormImageCacheSizeString(L" 6", IDS_MB), 6000000);
  6319. AddItem(ctrl, FormImageCacheSizeString(L" 9", IDS_MB), 8000000);
  6320. AddItem(ctrl, FormImageCacheSizeString(L" 10", IDS_MB), 10000000);
  6321. AddItem(ctrl, FormImageCacheSizeString(L" 12", IDS_MB), 12000000);
  6322. AddItem(ctrl, FormImageCacheSizeString(L" 14", IDS_MB), 14000000);
  6323. AddItem(ctrl, FormImageCacheSizeString(L" 16", IDS_MB), 16000000);
  6324. AddItem(ctrl, FormImageCacheSizeString(L" 20", IDS_MB), 20000000);
  6325. AddItem(ctrl, FormImageCacheSizeString(L" 24", IDS_MB), 24000000);
  6326. AddItem(ctrl, FormImageCacheSizeString(L" 28", IDS_MB), 28000000);
  6327. AddItem(ctrl, FormImageCacheSizeString(L" 32", IDS_MB), 32000000);
  6328. AddItem(ctrl, FormImageCacheSizeString(L" 40", IDS_MB), 40000000);
  6329. AddItem(ctrl, FormImageCacheSizeString(L" 48", IDS_MB), 48000000);
  6330. AddItem(ctrl, FormImageCacheSizeString(L" 56", IDS_MB), 56000000);
  6331. AddItem(ctrl, FormImageCacheSizeString(L" 64", IDS_MB), 64000000);
  6332. AddItem(ctrl, FormImageCacheSizeString(L" 80", IDS_MB), 80000000);
  6333. AddItem(ctrl, FormImageCacheSizeString(L" 96", IDS_MB), 96000000);
  6334. AddItem(ctrl, FormImageCacheSizeString(L" 128", IDS_MB), 128000000);
  6335. AddItem(ctrl, FormImageCacheSizeString(L" 160", IDS_MB), 160000000);
  6336. AddItem(ctrl, FormImageCacheSizeString(L" 192", IDS_MB), 192000000);
  6337. AddItem(ctrl, FormImageCacheSizeString(L" 224", IDS_MB), 224000000);
  6338. AddItem(ctrl, FormImageCacheSizeString(L" 256", IDS_MB), 256000000);
  6339. AddItem(ctrl, FormImageCacheSizeString(L" 384", IDS_MB), 384000000);
  6340. AddItem(ctrl, FormImageCacheSizeString(L" 512", IDS_MB), 512000000);
  6341. AddItem(ctrl, FormImageCacheSizeString(L" 768", IDS_MB), 768000000);
  6342. AddItem(ctrl, FormImageCacheSizeString(L" 1", IDS_GB), 1000000000);
  6343. AddItem(ctrl, FormImageCacheSizeString(L"1.25", IDS_GB), 1250000000);
  6344. AddItem(ctrl, FormImageCacheSizeString(L" 1.5", IDS_GB), 1500000000);
  6345. AddItem(ctrl, FormImageCacheSizeString(L"1.75", IDS_GB), 1750000000);
  6346. AddItem(ctrl, FormImageCacheSizeString(L" 2", IDS_GB), 2000000000);
  6347. SelectItemByPos (ctrl, 0); //as a safe default
  6348. SelectItemByValue(ctrl, m_nMaxBytes);
  6349. //-------------- image cache max. # images combo box ---------------------
  6350. ctrl = GetDlgItem( hwnd, IDC_MAX_IMAGES );
  6351. AddItem(ctrl, WASABI_API_LNGSTRINGW(IDS_AUTO), -1);
  6352. AddItem(ctrl, L" 0 ", 0);
  6353. AddItem(ctrl, L" 1 ", 1);
  6354. AddItem(ctrl, L" 2 ", 2);
  6355. AddItem(ctrl, L" 3 ", 3);
  6356. AddItem(ctrl, L" 4 ", 4);
  6357. AddItem(ctrl, L" 6 ", 6);
  6358. AddItem(ctrl, L" 8 ", 8);
  6359. AddItem(ctrl, L" 10 ", 10);
  6360. AddItem(ctrl, L" 12 ", 12);
  6361. AddItem(ctrl, L" 14 ", 14);
  6362. AddItem(ctrl, L" 16 ", 16);
  6363. AddItem(ctrl, L" 20 ", 20);
  6364. AddItem(ctrl, L" 24 ", 24);
  6365. AddItem(ctrl, L" 28 ", 28);
  6366. AddItem(ctrl, L" 32 ", 32);
  6367. AddItem(ctrl, L" 40 ", 40);
  6368. AddItem(ctrl, L" 48 ", 48);
  6369. AddItem(ctrl, L" 56 ", 56);
  6370. AddItem(ctrl, L" 64 ", 64);
  6371. AddItem(ctrl, L" 80 ", 80);
  6372. AddItem(ctrl, L" 96 ", 96);
  6373. AddItem(ctrl, L" 128 ",128);
  6374. AddItem(ctrl, L" 160 ",160);
  6375. AddItem(ctrl, L" 192 ",192);
  6376. AddItem(ctrl, L" 224 ",224);
  6377. AddItem(ctrl, L" 256 ",256);
  6378. AddItem(ctrl, L" 384 ",384);
  6379. AddItem(ctrl, L" 512 ",512);
  6380. AddItem(ctrl, L" 768 ",768);
  6381. AddItem(ctrl, L" 1024 ",1024);
  6382. AddItem(ctrl, L" 1536 ",1536);
  6383. AddItem(ctrl, L" 2048 ",2048);
  6384. SelectItemByPos (ctrl, 0); //as a safe default
  6385. SelectItemByValue(ctrl, m_nMaxImages);
  6386. //sprintf(buf, " %3.2f", m_fStereoSep);
  6387. //SetWindowText( GetDlgItem( hwnd, IDC_3DSEP ), buf );
  6388. sprintf(buf, " %2.1f", m_fSongTitleAnimDuration);
  6389. SetWindowText(GetDlgItem( hwnd, IDC_SONGTITLEANIM_DURATION), buf);
  6390. sprintf(buf, " %2.1f", m_fTimeBetweenRandomSongTitles);
  6391. SetWindowText(GetDlgItem(hwnd, IDC_RAND_TITLE), buf);
  6392. sprintf(buf, " %2.1f", m_fTimeBetweenRandomCustomMsgs);
  6393. SetWindowText(GetDlgItem(hwnd, IDC_RAND_MSG), buf);
  6394. CheckDlgButton(hwnd, IDC_CB_TITLE_ANIMS, m_bSongTitleAnims);
  6395. }
  6396. break;
  6397. case WM_COMMAND:
  6398. {
  6399. int id = LOWORD(wParam);
  6400. //g_ignore_tab2_clicks = 1;
  6401. switch (id)
  6402. {
  6403. case ID_SPRITE:
  6404. {
  6405. wchar_t szPath[512], szFile[512];
  6406. lstrcpyW(szPath, GetConfigIniFile());
  6407. wchar_t *p = wcsrchr(szPath, L'\\');
  6408. if (p != NULL)
  6409. {
  6410. *(p+1) = 0;
  6411. lstrcpyW(szFile, szPath);
  6412. lstrcatW(szFile, IMG_INIFILE);
  6413. intptr_t ret = (intptr_t)ShellExecuteW(NULL, L"open", szFile, NULL, szPath, SW_SHOWNORMAL);
  6414. if (ret <= 32)
  6415. {
  6416. wchar_t* str = WASABI_API_LNGSTRINGW(IDS_ERROR_IN_SHELLEXECUTE);
  6417. MessageBoxW(hwnd, str, str, MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL);
  6418. }
  6419. }
  6420. }
  6421. break;
  6422. case ID_MSG:
  6423. {
  6424. wchar_t szPath[512], szFile[512];
  6425. lstrcpyW(szPath, GetConfigIniFile());
  6426. wchar_t *p = wcsrchr(szPath, L'\\');
  6427. if (p != NULL)
  6428. {
  6429. *(p+1) = 0;
  6430. lstrcpyW(szFile, szPath);
  6431. lstrcatW(szFile, MSG_INIFILE);
  6432. intptr_t ret = (intptr_t)ShellExecuteW(NULL, L"open", szFile, NULL, szPath, SW_SHOWNORMAL);
  6433. if (ret <= 32)
  6434. {
  6435. wchar_t* str = WASABI_API_LNGSTRINGW(IDS_ERROR_IN_SHELLEXECUTE);
  6436. MessageBoxW(hwnd, str, str, MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL);
  6437. }
  6438. }
  6439. }
  6440. break;
  6441. }
  6442. }
  6443. /*if (LOWORD(wParam)==IDLEFT)
  6444. DoColors(hwnd, &m_cLeftEye3DColor[0], &m_cLeftEye3DColor[1], &m_cLeftEye3DColor[2]);
  6445. if (LOWORD(wParam)==IDRIGHT)
  6446. DoColors(hwnd, &m_cRightEye3DColor[0], &m_cRightEye3DColor[1], &m_cRightEye3DColor[2]);
  6447. */
  6448. break;
  6449. case WM_DESTROY:
  6450. {
  6451. ReadCBValue(hwnd, IDC_MAX_BYTES , &m_nMaxBytes );
  6452. ReadCBValue(hwnd, IDC_MAX_IMAGES , &m_nMaxImages );
  6453. char buf[2048];
  6454. GetWindowText( GetDlgItem( hwnd, IDC_SONGTITLEANIM_DURATION ), buf, sizeof(buf));
  6455. if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1)
  6456. m_fSongTitleAnimDuration = val;
  6457. GetWindowText( GetDlgItem( hwnd, IDC_RAND_TITLE ), buf, sizeof(buf));
  6458. if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1)
  6459. m_fTimeBetweenRandomSongTitles = val;
  6460. GetWindowText( GetDlgItem( hwnd, IDC_RAND_MSG ), buf, sizeof(buf));
  6461. if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1)
  6462. m_fTimeBetweenRandomCustomMsgs = val;
  6463. m_bSongTitleAnims = DlgItemIsChecked(hwnd, IDC_CB_TITLE_ANIMS);
  6464. }
  6465. break;
  6466. case WM_HELP: // give help box for controls here
  6467. if (lParam)
  6468. {
  6469. HELPINFO *ph = (HELPINFO*)lParam;
  6470. wchar_t title[1024], buf[2048], ctrl_name[1024];
  6471. GetWindowTextW(GetDlgItem(hwnd, ph->iCtrlId), ctrl_name, sizeof(ctrl_name)/sizeof(*ctrl_name));
  6472. RemoveSingleAmpersands(ctrl_name);
  6473. buf[0] = 0;
  6474. StringCbCopyW(title, sizeof(title), ctrl_name);
  6475. switch(ph->iCtrlId)
  6476. {
  6477. case IDC_MAX_IMAGES:
  6478. case IDC_MAX_IMAGES_CAPTION:
  6479. case IDC_MAX_BYTES:
  6480. case IDC_MAX_BYTES_CAPTION:
  6481. WASABI_API_LNGSTRINGW_BUF(IDS_MAX_IMAGES_BYTES, title, sizeof(title)/sizeof(*title));
  6482. WASABI_API_LNGSTRINGW_BUF(IDS_MAX_IMAGES_BYTES_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6483. break;
  6484. case ID_SPRITE:
  6485. WASABI_API_LNGSTRINGW_BUF(IDS_SPRITE, buf, sizeof(buf)/sizeof(*buf));
  6486. break;
  6487. case ID_MSG:
  6488. WASABI_API_LNGSTRINGW_BUF(IDS_MSG, buf, sizeof(buf)/sizeof(*buf));
  6489. break;
  6490. case IDC_SONGTITLEANIM_DURATION:
  6491. case IDC_SONGTITLEANIM_DURATION_LABEL:
  6492. GetWindowTextW(GetDlgItem(hwnd, IDC_SONGTITLEANIM_DURATION_LABEL), title, sizeof(title)/sizeof(*title));
  6493. WASABI_API_LNGSTRINGW_BUF(IDS_SONGTITLEANIM_DURATION_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6494. break;
  6495. case IDC_RAND_TITLE:
  6496. case IDC_RAND_TITLE_LABEL:
  6497. WASABI_API_LNGSTRINGW_BUF(IDS_RAND_TITLE, title, sizeof(title)/sizeof(*title));
  6498. WASABI_API_LNGSTRINGW_BUF(IDS_RAND_TITLE_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6499. break;
  6500. case IDC_RAND_MSG:
  6501. case IDC_RAND_MSG_LABEL:
  6502. WASABI_API_LNGSTRINGW_BUF(IDS_RAND_MSG, title, sizeof(title)/sizeof(*title));
  6503. WASABI_API_LNGSTRINGW_BUF(IDS_RAND_MSG_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6504. break;
  6505. case IDC_CB_TITLE_ANIMS:
  6506. WASABI_API_LNGSTRINGW_BUF(IDS_TITLE_ANIMS_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6507. break;
  6508. }
  6509. if (buf[0])
  6510. MessageBoxW(hwnd, buf, title, MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL);
  6511. }
  6512. break; // case WM_HELP
  6513. }
  6514. }
  6515. else if (nPage==4)
  6516. {
  6517. switch(msg)
  6518. {
  6519. case WM_INITDIALOG:
  6520. {
  6521. char buf[2048];
  6522. // soft cuts
  6523. sprintf(buf, " %2.1f", m_fTimeBetweenPresets);
  6524. SetWindowText( GetDlgItem( hwnd, IDC_BETWEEN_TIME ), buf );
  6525. sprintf(buf, " %2.1f", m_fTimeBetweenPresetsRand);
  6526. SetWindowText( GetDlgItem( hwnd, IDC_BETWEEN_TIME_RANDOM ), buf );
  6527. sprintf(buf, " %2.1f", m_fBlendTimeUser);
  6528. SetWindowText( GetDlgItem( hwnd, IDC_BLEND_USER ), buf );
  6529. sprintf(buf, " %2.1f", m_fBlendTimeAuto);
  6530. SetWindowText( GetDlgItem( hwnd, IDC_BLEND_AUTO ), buf );
  6531. // hard cuts
  6532. sprintf(buf, " %2.1f", m_fHardCutHalflife);
  6533. SetWindowText( GetDlgItem( hwnd, IDC_HARDCUT_BETWEEN_TIME ), buf );
  6534. int n = (int)((m_fHardCutLoudnessThresh - 1.25f) * 10.0f);
  6535. if (n<0) n = 0;
  6536. if (n>20) n = 20;
  6537. SendMessage( GetDlgItem( hwnd, IDC_HARDCUT_LOUDNESS), TBM_SETRANGEMIN, FALSE, (LPARAM)(0) );
  6538. SendMessage( GetDlgItem( hwnd, IDC_HARDCUT_LOUDNESS), TBM_SETRANGEMAX, FALSE, (LPARAM)(20) );
  6539. SendMessage( GetDlgItem( hwnd, IDC_HARDCUT_LOUDNESS), TBM_SETPOS, TRUE, (LPARAM)(n) );
  6540. CheckDlgButton(hwnd, IDC_CB_HARDCUTS, m_bHardCutsDisabled);
  6541. }
  6542. break;
  6543. case WM_DESTROY:
  6544. {
  6545. char buf[2048];
  6546. // soft cuts
  6547. GetWindowText( GetDlgItem( hwnd, IDC_BETWEEN_TIME ), buf, sizeof(buf));
  6548. if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1)
  6549. m_fTimeBetweenPresets = val;
  6550. GetWindowText( GetDlgItem( hwnd, IDC_BETWEEN_TIME_RANDOM ), buf, sizeof(buf));
  6551. if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1)
  6552. m_fTimeBetweenPresetsRand = val;
  6553. GetWindowText( GetDlgItem( hwnd, IDC_BLEND_AUTO ), buf, sizeof(buf));
  6554. if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1)
  6555. m_fBlendTimeAuto = val;
  6556. GetWindowText( GetDlgItem( hwnd, IDC_BLEND_USER ), buf, sizeof(buf));
  6557. if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1)
  6558. m_fBlendTimeUser = val;
  6559. // hard cuts
  6560. GetWindowText( GetDlgItem( hwnd, IDC_HARDCUT_BETWEEN_TIME ), buf, sizeof(buf));
  6561. if (_sscanf_l(buf, "%f", g_use_C_locale, &val) == 1)
  6562. m_fHardCutHalflife = val;
  6563. t = SendMessage( GetDlgItem( hwnd, IDC_HARDCUT_LOUDNESS ), TBM_GETPOS, 0, 0);
  6564. if (t != CB_ERR) m_fHardCutLoudnessThresh = 1.25f + t/10.0f;
  6565. m_bHardCutsDisabled = DlgItemIsChecked(hwnd, IDC_CB_HARDCUTS);
  6566. }
  6567. break;
  6568. case WM_HELP:
  6569. if (lParam)
  6570. {
  6571. HELPINFO *ph = (HELPINFO*)lParam;
  6572. wchar_t title[1024], buf[2048], ctrl_name[1024];
  6573. GetWindowTextW(GetDlgItem(hwnd, ph->iCtrlId), ctrl_name, sizeof(ctrl_name)/sizeof(*ctrl_name));
  6574. RemoveSingleAmpersands(ctrl_name);
  6575. buf[0] = 0;
  6576. StringCbCopyW(title, sizeof(title), ctrl_name);
  6577. switch(ph->iCtrlId)
  6578. {
  6579. case IDC_BETWEEN_TIME:
  6580. case IDC_BETWEEN_TIME_LABEL:
  6581. GetWindowTextW(GetDlgItem(hwnd, IDC_BETWEEN_TIME_LABEL), title, sizeof(title)/sizeof(*title));
  6582. WASABI_API_LNGSTRINGW_BUF(IDS_BETWEEN_TIME_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6583. break;
  6584. case IDC_BETWEEN_TIME_RANDOM:
  6585. case IDC_BETWEEN_TIME_RANDOM_LABEL:
  6586. GetWindowTextW(GetDlgItem(hwnd, IDC_BETWEEN_TIME_RANDOM_LABEL), title, sizeof(title)/sizeof(*title));
  6587. WASABI_API_LNGSTRINGW_BUF(IDS_BETWEEN_TIME_RANDOM_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6588. break;
  6589. case IDC_BLEND_AUTO:
  6590. case IDC_BLEND_AUTO_LABEL:
  6591. GetWindowTextW(GetDlgItem(hwnd, IDC_BLEND_AUTO_LABEL), title, sizeof(title)/sizeof(*title));
  6592. WASABI_API_LNGSTRINGW_BUF(IDS_BLEND_AUTO_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6593. break;
  6594. case IDC_BLEND_USER:
  6595. case IDC_BLEND_USER_LABEL:
  6596. GetWindowTextW(GetDlgItem(hwnd, IDC_BLEND_USER_LABEL), title, sizeof(title)/sizeof(*title));
  6597. WASABI_API_LNGSTRINGW_BUF(IDS_BLEND_USER_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6598. break;
  6599. case IDC_HARDCUT_BETWEEN_TIME:
  6600. case IDC_HARDCUT_BETWEEN_TIME_LABEL:
  6601. GetWindowTextW(GetDlgItem(hwnd, IDC_HARDCUT_BETWEEN_TIME_LABEL), title, sizeof(title)/sizeof(*title));
  6602. WASABI_API_LNGSTRINGW_BUF(IDS_HARDCUT_BETWEEN_TIME_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6603. break;
  6604. case IDC_HARDCUT_LOUDNESS:
  6605. case IDC_HARDCUT_LOUDNESS_LABEL:
  6606. case IDC_HARDCUT_LOUDNESS_MIN:
  6607. case IDC_HARDCUT_LOUDNESS_MAX:
  6608. GetWindowTextW(GetDlgItem(hwnd, IDC_HARDCUT_LOUDNESS_LABEL), title, sizeof(title)/sizeof(*title));
  6609. WASABI_API_LNGSTRINGW_BUF(IDS_HARDCUT_LOUDNESS_TEXT, buf, sizeof(buf)/sizeof(*buf));
  6610. break;
  6611. case IDC_CB_HARDCUTS:
  6612. WASABI_API_LNGSTRINGW_BUF(IDS_CB_HARDCUTS, buf, sizeof(buf)/sizeof(*buf));
  6613. break;
  6614. }
  6615. if (buf[0])
  6616. MessageBoxW(hwnd, buf, title, MB_OK|MB_SETFOREGROUND|MB_TOPMOST|MB_TASKMODAL);
  6617. }
  6618. break;
  6619. }
  6620. }
  6621. return false;
  6622. }
  6623. //----------------------------------------------------------------------
  6624. void CPlugin::Randomize()
  6625. {
  6626. srand((int)(GetTime()*100));
  6627. //m_fAnimTime = (warand() % 51234L)*0.01f;
  6628. m_fRandStart[0] = (warand() % 64841L)*0.01f;
  6629. m_fRandStart[1] = (warand() % 53751L)*0.01f;
  6630. m_fRandStart[2] = (warand() % 42661L)*0.01f;
  6631. m_fRandStart[3] = (warand() % 31571L)*0.01f;
  6632. //CState temp;
  6633. //temp.Randomize(warand() % NUM_MODES);
  6634. //m_pState->StartBlend(&temp, m_fAnimTime, m_fBlendTimeUser);
  6635. }
  6636. //----------------------------------------------------------------------
  6637. void CPlugin::SetMenusForPresetVersion(int WarpPSVersion, int CompPSVersion)
  6638. {
  6639. int MaxPSVersion = max(WarpPSVersion, CompPSVersion);
  6640. m_menuPreset.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_WARP_SHADER), WarpPSVersion > 0);
  6641. m_menuPreset.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_COMPOSITE_SHADER), CompPSVersion > 0);
  6642. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_SUSTAIN_LEVEL), WarpPSVersion==0);
  6643. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_TEXTURE_WRAP), WarpPSVersion==0);
  6644. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_GAMMA_ADJUSTMENT), CompPSVersion==0);
  6645. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_HUE_SHADER), CompPSVersion==0);
  6646. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_VIDEO_ECHO_ALPHA), CompPSVersion==0);
  6647. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_VIDEO_ECHO_ZOOM), CompPSVersion==0);
  6648. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_VIDEO_ECHO_ORIENTATION), CompPSVersion==0);
  6649. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_FILTER_INVERT), CompPSVersion==0);
  6650. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_FILTER_BRIGHTEN), CompPSVersion==0);
  6651. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_FILTER_DARKEN), CompPSVersion==0);
  6652. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_FILTER_SOLARIZE), CompPSVersion==0);
  6653. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR1_EDGE_DARKEN_AMOUNT), MaxPSVersion > 0);
  6654. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR1_MIN_COLOR_VALUE), MaxPSVersion > 0);
  6655. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR1_MAX_COLOR_VALUE), MaxPSVersion > 0);
  6656. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR2_MIN_COLOR_VALUE), MaxPSVersion > 0);
  6657. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR2_MAX_COLOR_VALUE), MaxPSVersion > 0);
  6658. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR3_MIN_COLOR_VALUE), MaxPSVersion > 0);
  6659. m_menuPost.EnableItem(WASABI_API_LNGSTRINGW(IDS_MENU_BLUR3_MAX_COLOR_VALUE), MaxPSVersion > 0);
  6660. }
  6661. void CPlugin::BuildMenus()
  6662. {
  6663. wchar_t buf[1024];
  6664. m_pCurMenu = &m_menuPreset;//&m_menuMain;
  6665. m_menuPreset .Init(WASABI_API_LNGSTRINGW(IDS_EDIT_CURRENT_PRESET));
  6666. m_menuMotion .Init(WASABI_API_LNGSTRINGW(IDS_MOTION));
  6667. m_menuCustomShape.Init(WASABI_API_LNGSTRINGW(IDS_DRAWING_CUSTOM_SHAPES));
  6668. m_menuCustomWave .Init(WASABI_API_LNGSTRINGW(IDS_DRAWING_CUSTOM_WAVES));
  6669. m_menuWave .Init(WASABI_API_LNGSTRINGW(IDS_DRAWING_SIMPLE_WAVEFORM));
  6670. m_menuAugment .Init(WASABI_API_LNGSTRINGW(IDS_DRAWING_BORDERS_MOTION_VECTORS));
  6671. m_menuPost .Init(WASABI_API_LNGSTRINGW(IDS_POST_PROCESSING_MISC));
  6672. int i = 0;
  6673. for (i=0; i<MAX_CUSTOM_WAVES; i++)
  6674. {
  6675. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_CUSTOM_WAVE_X), i+1);
  6676. m_menuWavecode[i].Init(buf);
  6677. }
  6678. for (i=0; i<MAX_CUSTOM_SHAPES; i++)
  6679. {
  6680. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_CUSTOM_SHAPE_X), i+1);
  6681. m_menuShapecode[i].Init(buf);
  6682. }
  6683. //-------------------------------------------
  6684. // MAIN MENU / menu hierarchy
  6685. m_menuPreset.AddChildMenu(&m_menuMotion);
  6686. m_menuPreset.AddChildMenu(&m_menuCustomShape);
  6687. m_menuPreset.AddChildMenu(&m_menuCustomWave);
  6688. m_menuPreset.AddChildMenu(&m_menuWave);
  6689. m_menuPreset.AddChildMenu(&m_menuAugment);
  6690. m_menuPreset.AddChildMenu(&m_menuPost);
  6691. for (i=0; i<MAX_CUSTOM_SHAPES; i++)
  6692. m_menuCustomShape.AddChildMenu(&m_menuShapecode[i]);
  6693. for (i=0; i<MAX_CUSTOM_WAVES; i++)
  6694. m_menuCustomWave.AddChildMenu(&m_menuWavecode[i]);
  6695. // NOTE: all of the eval menuitems use a CALLBACK function to register the user's changes (see last param)
  6696. m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_PRESET_INIT_CODE),
  6697. &m_pState->m_szPerFrameInit, MENUITEMTYPE_STRING,
  6698. WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_PRESET_INIT_CODE_TT, buf, 1024),
  6699. 256, 0, &OnUserEditedPresetInit, sizeof(m_pState->m_szPerFrameInit), 0);
  6700. m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_PER_FRAME_EQUATIONS),
  6701. &m_pState->m_szPerFrameExpr, MENUITEMTYPE_STRING,
  6702. WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_PER_FRAME_EQUATIONS_TT, buf, 1024),
  6703. 256, 0, &OnUserEditedPerFrame, sizeof(m_pState->m_szPerFrameExpr), 0);
  6704. m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_PER_VERTEX_EQUATIONS),
  6705. &m_pState->m_szPerPixelExpr, MENUITEMTYPE_STRING,
  6706. WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_PER_VERTEX_EQUATIONS_TT, buf, 1024),
  6707. 256, 0, &OnUserEditedPerPixel, sizeof(m_pState->m_szPerPixelExpr), 0);
  6708. m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_WARP_SHADER),
  6709. &m_pState->m_szWarpShadersText, MENUITEMTYPE_STRING,
  6710. WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_WARP_SHADER_TT, buf, 1024),
  6711. 256, 0, &OnUserEditedWarpShaders, sizeof(m_pState->m_szWarpShadersText), 0);
  6712. m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_COMPOSITE_SHADER),
  6713. &m_pState->m_szCompShadersText, MENUITEMTYPE_STRING,
  6714. WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_COMPOSITE_SHADER_TT, buf, 1024),
  6715. 256, 0, &OnUserEditedCompShaders, sizeof(m_pState->m_szCompShadersText), 0);
  6716. m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_UPGRADE_PRESET_PS_VERSION),
  6717. (void*)UI_UPGRADE_PIXEL_SHADER, MENUITEMTYPE_UIMODE,
  6718. WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_UPGRADE_PRESET_PS_VERSION_TT, buf, 1024),
  6719. 0, 0, NULL, UI_UPGRADE_PIXEL_SHADER, 0);
  6720. m_menuPreset.AddItem(WASABI_API_LNGSTRINGW(IDS_MENU_EDIT_DO_A_PRESET_MASH_UP),
  6721. (void*)UI_MASHUP, MENUITEMTYPE_UIMODE,
  6722. WASABI_API_LNGSTRINGW_BUF(IDS_MENU_EDIT_DO_A_PRESET_MASH_UP_TT, buf, 1024),
  6723. 0, 0, NULL, UI_MASHUP, 0);
  6724. //-------------------------------------------
  6725. // menu items
  6726. #define MEN_T(id) WASABI_API_LNGSTRINGW(id)
  6727. #define MEN_TT(id) WASABI_API_LNGSTRINGW_BUF(id, buf, 1024)
  6728. m_menuWave.AddItem(MEN_T(IDS_MENU_WAVE_TYPE), &m_pState->m_nWaveMode, MENUITEMTYPE_INT, MEN_TT(IDS_MENU_WAVE_TYPE_TT), 0, NUM_WAVES-1);
  6729. m_menuWave.AddItem(MEN_T(IDS_MENU_SIZE), &m_pState->m_fWaveScale, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_SIZE_TT));
  6730. m_menuWave.AddItem(MEN_T(IDS_MENU_SMOOTH), &m_pState->m_fWaveSmoothing,MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_SMOOTH_TT), 0.0f, 0.9f);
  6731. m_menuWave.AddItem(MEN_T(IDS_MENU_MYSTERY_PARAMETER), &m_pState->m_fWaveParam, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_MYSTERY_PARAMETER_TT), -1.0f, 1.0f);
  6732. m_menuWave.AddItem(MEN_T(IDS_MENU_POSITION_X), &m_pState->m_fWaveX, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_POSITION_X_TT), 0, 1);
  6733. m_menuWave.AddItem(MEN_T(IDS_MENU_POSITION_Y), &m_pState->m_fWaveY, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_POSITION_Y_TT), 0, 1);
  6734. m_menuWave.AddItem(MEN_T(IDS_MENU_COLOR_RED), &m_pState->m_fWaveR, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_RED_TT), 0, 1);
  6735. m_menuWave.AddItem(MEN_T(IDS_MENU_COLOR_GREEN), &m_pState->m_fWaveG, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_GREEN_TT), 0, 1);
  6736. m_menuWave.AddItem(MEN_T(IDS_MENU_COLOR_BLUE), &m_pState->m_fWaveB, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_BLUE_TT), 0, 1);
  6737. m_menuWave.AddItem(MEN_T(IDS_MENU_OPACITY), &m_pState->m_fWaveAlpha, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_OPACITY_TT), 0.001f, 100.0f);
  6738. m_menuWave.AddItem(MEN_T(IDS_MENU_USE_DOTS), &m_pState->m_bWaveDots, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_USE_DOTS_TT));
  6739. m_menuWave.AddItem(MEN_T(IDS_MENU_DRAW_THICK), &m_pState->m_bWaveThick, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_DRAW_THICK_TT));
  6740. m_menuWave.AddItem(MEN_T(IDS_MENU_MODULATE_OPACITY_BY_VOLUME), &m_pState->m_bModWaveAlphaByVolume, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_MODULATE_OPACITY_BY_VOLUME_TT));
  6741. m_menuWave.AddItem(MEN_T(IDS_MENU_MODULATION_TRANSPARENT_VOLUME), &m_pState->m_fModWaveAlphaStart, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_MODULATION_TRANSPARENT_VOLUME_TT), 0.0f, 2.0f);
  6742. m_menuWave.AddItem(MEN_T(IDS_MENU_MODULATION_OPAQUE_VOLUME), &m_pState->m_fModWaveAlphaEnd, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_MODULATION_OPAQUE_VOLUME_TT), 0.0f, 2.0f);
  6743. m_menuWave.AddItem(MEN_T(IDS_MENU_ADDITIVE_DRAWING), &m_pState->m_bAdditiveWaves, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_ADDITIVE_DRAWING_TT));
  6744. m_menuWave.AddItem(MEN_T(IDS_MENU_COLOR_BRIGHTENING), &m_pState->m_bMaximizeWaveColor, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_COLOR_BRIGHTENING_TT));
  6745. m_menuAugment.AddItem(MEN_T(IDS_MENU_OUTER_BORDER_THICKNESS), &m_pState->m_fOuterBorderSize, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_OUTER_BORDER_THICKNESS_TT), 0, 0.5f);
  6746. m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_RED_OUTER), &m_pState->m_fOuterBorderR, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_RED_OUTER_TT), 0, 1);
  6747. m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_GREEN_OUTER), &m_pState->m_fOuterBorderG, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_GREEN_OUTER_TT), 0, 1);
  6748. m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_BLUE_OUTER), &m_pState->m_fOuterBorderB, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_BLUE_OUTER_TT), 0, 1);
  6749. m_menuAugment.AddItem(MEN_T(IDS_MENU_OPACITY_OUTER), &m_pState->m_fOuterBorderA, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_OPACITY_OUTER_TT), 0, 1);
  6750. m_menuAugment.AddItem(MEN_T(IDS_MENU_INNER_BORDER_THICKNESS), &m_pState->m_fInnerBorderSize, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_INNER_BORDER_THICKNESS_TT), 0, 0.5f);
  6751. m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_RED_OUTER), &m_pState->m_fInnerBorderR, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_RED_INNER_TT), 0, 1);
  6752. m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_GREEN_OUTER), &m_pState->m_fInnerBorderG, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_GREEN_INNER_TT), 0, 1);
  6753. m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_BLUE_OUTER), &m_pState->m_fInnerBorderB, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_BLUE_INNER_TT), 0, 1);
  6754. m_menuAugment.AddItem(MEN_T(IDS_MENU_OPACITY_OUTER), &m_pState->m_fInnerBorderA, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_OPACITY_INNER_TT), 0, 1);
  6755. m_menuAugment.AddItem(MEN_T(IDS_MENU_MOTION_VECTOR_OPACITY), &m_pState->m_fMvA, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_MOTION_VECTOR_OPACITY_TT), 0, 1);
  6756. m_menuAugment.AddItem(MEN_T(IDS_MENU_NUM_MOT_VECTORS_X), &m_pState->m_fMvX, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_NUM_MOT_VECTORS_X_TT), 0, 64);
  6757. m_menuAugment.AddItem(MEN_T(IDS_MENU_NUM_MOT_VECTORS_Y), &m_pState->m_fMvY, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_NUM_MOT_VECTORS_Y_TT), 0, 48);
  6758. m_menuAugment.AddItem(MEN_T(IDS_MENU_OFFSET_X), &m_pState->m_fMvDX, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_OFFSET_X_TT), -1, 1);
  6759. m_menuAugment.AddItem(MEN_T(IDS_MENU_OFFSET_Y), &m_pState->m_fMvDY, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_OFFSET_Y_TT), -1, 1);
  6760. m_menuAugment.AddItem(MEN_T(IDS_MENU_TRAIL_LENGTH), &m_pState->m_fMvL, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_TRAIL_LENGTH_TT), 0, 5);
  6761. m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_RED_OUTER), &m_pState->m_fMvR, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_RED_MOTION_VECTOR_TT), 0, 1);
  6762. m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_GREEN_OUTER), &m_pState->m_fMvG, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_GREEN_MOTION_VECTOR_TT), 0, 1);
  6763. m_menuAugment.AddItem(MEN_T(IDS_MENU_COLOR_BLUE_OUTER), &m_pState->m_fMvB, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_COLOR_BLUE_MOTION_VECTOR_TT), 0, 1);
  6764. m_menuMotion.AddItem(MEN_T(IDS_MENU_ZOOM_AMOUNT), &m_pState->m_fZoom, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_ZOOM_AMOUNT_TT));
  6765. m_menuMotion.AddItem(MEN_T(IDS_MENU_ZOOM_EXPONENT), &m_pState->m_fZoomExponent, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_ZOOM_EXPONENT_TT));
  6766. m_menuMotion.AddItem(MEN_T(IDS_MENU_WARP_AMOUNT), &m_pState->m_fWarpAmount, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_WARP_AMOUNT_TT));
  6767. m_menuMotion.AddItem(MEN_T(IDS_MENU_WARP_SCALE), &m_pState->m_fWarpScale, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_WARP_SCALE_TT));
  6768. m_menuMotion.AddItem(MEN_T(IDS_MENU_WARP_SPEED), &m_pState->m_fWarpAnimSpeed, MENUITEMTYPE_LOGFLOAT, MEN_TT(IDS_MENU_WARP_SPEED_TT));
  6769. m_menuMotion.AddItem(MEN_T(IDS_MENU_ROTATION_AMOUNT), &m_pState->m_fRot, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_ROTATION_AMOUNT_TT), -1.00f, 1.00f);
  6770. m_menuMotion.AddItem(MEN_T(IDS_MENU_ROTATION_CENTER_OF_X), &m_pState->m_fRotCX, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_ROTATION_CENTER_OF_X_TT), -1.0f, 2.0f);
  6771. m_menuMotion.AddItem(MEN_T(IDS_MENU_ROTATION_CENTER_OF_Y), &m_pState->m_fRotCY, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_ROTATION_CENTER_OF_Y_TT), -1.0f, 2.0f);
  6772. m_menuMotion.AddItem(MEN_T(IDS_MENU_TRANSLATION_X), &m_pState->m_fXPush, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_TRANSLATION_X_TT), -1.0f, 1.0f);
  6773. m_menuMotion.AddItem(MEN_T(IDS_MENU_TRANSLATION_Y), &m_pState->m_fYPush, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_TRANSLATION_Y_TT), -1.0f, 1.0f);
  6774. m_menuMotion.AddItem(MEN_T(IDS_MENU_SCALING_X), &m_pState->m_fStretchX, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_SCALING_X_TT));
  6775. m_menuMotion.AddItem(MEN_T(IDS_MENU_SCALING_Y), &m_pState->m_fStretchY, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_SCALING_Y_TT));
  6776. m_menuPost.AddItem(MEN_T(IDS_MENU_SUSTAIN_LEVEL), &m_pState->m_fDecay, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_SUSTAIN_LEVEL_TT), 0.50f, 1.0f);
  6777. m_menuPost.AddItem(MEN_T(IDS_MENU_DARKEN_CENTER), &m_pState->m_bDarkenCenter, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_DARKEN_CENTER_TT));
  6778. m_menuPost.AddItem(MEN_T(IDS_MENU_GAMMA_ADJUSTMENT), &m_pState->m_fGammaAdj, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_GAMMA_ADJUSTMENT_TT), 1.0f, 8.0f);
  6779. m_menuPost.AddItem(MEN_T(IDS_MENU_HUE_SHADER), &m_pState->m_fShader, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_HUE_SHADER_TT), 0.0f, 1.0f);
  6780. m_menuPost.AddItem(MEN_T(IDS_MENU_VIDEO_ECHO_ALPHA), &m_pState->m_fVideoEchoAlpha, MENUITEMTYPE_BLENDABLE, MEN_TT(IDS_MENU_VIDEO_ECHO_ALPHA_TT), 0.0f, 1.0f);
  6781. m_menuPost.AddItem(MEN_T(IDS_MENU_VIDEO_ECHO_ZOOM), &m_pState->m_fVideoEchoZoom, MENUITEMTYPE_LOGBLENDABLE, MEN_TT(IDS_MENU_VIDEO_ECHO_ZOOM_TT));
  6782. m_menuPost.AddItem(MEN_T(IDS_MENU_VIDEO_ECHO_ORIENTATION), &m_pState->m_nVideoEchoOrientation, MENUITEMTYPE_INT, MEN_TT(IDS_MENU_VIDEO_ECHO_ORIENTATION_TT), 0.0f, 3.0f);
  6783. m_menuPost.AddItem(MEN_T(IDS_MENU_TEXTURE_WRAP), &m_pState->m_bTexWrap, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_TEXTURE_WRAP_TT));
  6784. //m_menuPost.AddItem("stereo 3D", &m_pState->m_bRedBlueStereo, MENUITEMTYPE_BOOL, "displays the image in stereo 3D; you need 3D glasses (with red and blue lenses) for this.");
  6785. m_menuPost.AddItem(MEN_T(IDS_MENU_FILTER_INVERT), &m_pState->m_bInvert, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_FILTER_INVERT_TT));
  6786. m_menuPost.AddItem(MEN_T(IDS_MENU_FILTER_BRIGHTEN), &m_pState->m_bBrighten, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_FILTER_BRIGHTEN_TT));
  6787. m_menuPost.AddItem(MEN_T(IDS_MENU_FILTER_DARKEN), &m_pState->m_bDarken, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_FILTER_DARKEN_TT));
  6788. m_menuPost.AddItem(MEN_T(IDS_MENU_FILTER_SOLARIZE), &m_pState->m_bSolarize, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_FILTER_SOLARIZE_TT));
  6789. m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR1_EDGE_DARKEN_AMOUNT),&m_pState->m_fBlur1EdgeDarken, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR1_EDGE_DARKEN_AMOUNT_TT), 0.0f, 1.0f);
  6790. m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR1_MIN_COLOR_VALUE), &m_pState->m_fBlur1Min, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR1_MIN_COLOR_VALUE_TT), 0.0f, 1.0f);
  6791. m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR1_MAX_COLOR_VALUE), &m_pState->m_fBlur1Max, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR1_MAX_COLOR_VALUE_TT), 0.0f, 1.0f);
  6792. m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR2_MIN_COLOR_VALUE), &m_pState->m_fBlur2Min, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR2_MIN_COLOR_VALUE_TT), 0.0f, 1.0f);
  6793. m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR2_MAX_COLOR_VALUE), &m_pState->m_fBlur2Max, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR2_MAX_COLOR_VALUE_TT), 0.0f, 1.0f);
  6794. m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR3_MIN_COLOR_VALUE), &m_pState->m_fBlur3Min, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR3_MIN_COLOR_VALUE_TT), 0.0f, 1.0f);
  6795. m_menuPost.AddItem(MEN_T(IDS_MENU_BLUR3_MAX_COLOR_VALUE), &m_pState->m_fBlur3Max, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BLUR3_MAX_COLOR_VALUE_TT), 0.0f, 1.0f);
  6796. for (i=0; i<MAX_CUSTOM_WAVES; i++)
  6797. {
  6798. // blending: do both; fade opacities in/out (w/exagerrated weighting)
  6799. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_ENABLED), &m_pState->m_wave[i].enabled, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_ENABLED_TT)); // bool
  6800. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_NUMBER_OF_SAMPLES),&m_pState->m_wave[i].samples, MENUITEMTYPE_INT, MEN_TT(IDS_MENU_NUMBER_OF_SAMPLES_TT), 2, 512); // 0-512
  6801. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_L_R_SEPARATION), &m_pState->m_wave[i].sep, MENUITEMTYPE_INT, MEN_TT(IDS_MENU_L_R_SEPARATION_TT), 0, 256); // 0-512
  6802. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_SCALING), &m_pState->m_wave[i].scaling, MENUITEMTYPE_LOGFLOAT, MEN_TT(IDS_MENU_SCALING_TT));
  6803. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_SMOOTH), &m_pState->m_wave[i].smoothing, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_SMOOTHING_TT), 0, 1);
  6804. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_COLOR_RED), &m_pState->m_wave[i].r, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_COLOR_RED_TT), 0, 1);
  6805. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_COLOR_GREEN), &m_pState->m_wave[i].g, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_COLOR_GREEN_TT), 0, 1);
  6806. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_COLOR_BLUE), &m_pState->m_wave[i].b, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_COLOR_BLUE_TT), 0, 1);
  6807. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_OPACITY), &m_pState->m_wave[i].a, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_OPACITY_WAVE_TT), 0, 1);
  6808. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_USE_SPECTRUM), &m_pState->m_wave[i].bSpectrum, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_USE_SPECTRUM_TT)); // 0-5 [0=wave left, 1=wave center, 2=wave right; 3=spectrum left, 4=spec center, 5=spec right]
  6809. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_USE_DOTS), &m_pState->m_wave[i].bUseDots, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_USE_DOTS_WAVE_TT)); // bool
  6810. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_DRAW_THICK), &m_pState->m_wave[i].bDrawThick,MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_DRAW_THICK_WAVE_TT)); // bool
  6811. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_ADDITIVE_DRAWING), &m_pState->m_wave[i].bAdditive, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_ADDITIVE_DRAWING_WAVE_TT)); // bool
  6812. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_EXPORT_TO_FILE), (void*)UI_EXPORT_WAVE, MENUITEMTYPE_UIMODE,MEN_TT(IDS_MENU_EXPORT_TO_FILE_TT), 0, 0, NULL, UI_EXPORT_WAVE, i);
  6813. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_IMPORT_FROM_FILE), (void*)UI_IMPORT_WAVE, MENUITEMTYPE_UIMODE,MEN_TT(IDS_MENU_IMPORT_FROM_FILE_TT), 0, 0, NULL, UI_IMPORT_WAVE, i);
  6814. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_EDIT_INIT_CODE), &m_pState->m_wave[i].m_szInit, MENUITEMTYPE_STRING,MEN_TT(IDS_MENU_EDIT_INIT_CODE_TT), 256, 0, &OnUserEditedWavecodeInit, sizeof(m_pState->m_wave[i].m_szInit), 0);
  6815. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_EDIT_PER_FRAME_CODE), &m_pState->m_wave[i].m_szPerFrame, MENUITEMTYPE_STRING, MEN_TT(IDS_MENU_EDIT_PER_FRAME_CODE_TT), 256, 0, &OnUserEditedWavecode, sizeof(m_pState->m_wave[i].m_szPerFrame), 0);
  6816. m_menuWavecode[i].AddItem(MEN_T(IDS_MENU_EDIT_PER_POINT_CODE), &m_pState->m_wave[i].m_szPerPoint, MENUITEMTYPE_STRING, MEN_TT(IDS_MENU_EDIT_PER_POINT_CODE_TT), 256, 0, &OnUserEditedWavecode, sizeof(m_pState->m_wave[i].m_szPerPoint), 0);
  6817. }
  6818. for (i=0; i<MAX_CUSTOM_SHAPES; i++)
  6819. {
  6820. // blending: do both; fade opacities in/out (w/exagerrated weighting)
  6821. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_ENABLED), &m_pState->m_shape[i].enabled, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_ENABLED_SHAPE_TT)); // bool
  6822. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_NUMBER_OF_INSTANCES), &m_pState->m_shape[i].instances,MENUITEMTYPE_INT, MEN_TT(IDS_MENU_NUMBER_OF_INSTANCES_TT), 1, 1024);
  6823. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_NUMBER_OF_SIDES), &m_pState->m_shape[i].sides, MENUITEMTYPE_INT, MEN_TT(IDS_MENU_NUMBER_OF_SIDES_TT), 3, 100);
  6824. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_DRAW_THICK), &m_pState->m_shape[i].thickOutline, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_DRAW_THICK_SHAPE_TT)); // bool
  6825. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_ADDITIVE_DRAWING), &m_pState->m_shape[i].additive, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_ADDITIVE_DRAWING_SHAPE_TT)); // bool
  6826. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_X_POSITION), &m_pState->m_shape[i].x, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_X_POSITION_TT), 0, 1);
  6827. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_Y_POSITION), &m_pState->m_shape[i].y, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_Y_POSITION_TT), 0, 1);
  6828. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_RADIUS), &m_pState->m_shape[i].rad, MENUITEMTYPE_LOGFLOAT, MEN_TT(IDS_MENU_RADIUS_TT));
  6829. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_ANGLE), &m_pState->m_shape[i].ang, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_ANGLE_TT), 0, 3.1415927f*2.0f);
  6830. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_TEXTURED), &m_pState->m_shape[i].textured, MENUITEMTYPE_BOOL, MEN_TT(IDS_MENU_TEXTURED_TT)); // bool
  6831. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_TEXTURE_ZOOM), &m_pState->m_shape[i].tex_zoom, MENUITEMTYPE_LOGFLOAT, MEN_TT(IDS_MENU_TEXTURE_ZOOM_TT)); // bool
  6832. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_TEXTURE_ANGLE), &m_pState->m_shape[i].tex_ang, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_TEXTURE_ANGLE_TT), 0, 3.1415927f*2.0f); // bool
  6833. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_INNER_COLOR_RED), &m_pState->m_shape[i].r, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_INNER_COLOR_RED_TT), 0, 1);
  6834. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_INNER_COLOR_GREEN), &m_pState->m_shape[i].g, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_INNER_COLOR_GREEN_TT), 0, 1);
  6835. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_INNER_COLOR_BLUE), &m_pState->m_shape[i].b, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_INNER_COLOR_BLUE_TT), 0, 1);
  6836. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_INNER_OPACITY), &m_pState->m_shape[i].a, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_INNER_OPACITY_TT), 0, 1);
  6837. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_OUTER_COLOR_RED), &m_pState->m_shape[i].r2, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_OUTER_COLOR_RED_TT), 0, 1);
  6838. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_OUTER_COLOR_GREEN), &m_pState->m_shape[i].g2, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_OUTER_COLOR_GREEN_TT), 0, 1);
  6839. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_OUTER_COLOR_BLUE), &m_pState->m_shape[i].b2, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_OUTER_COLOR_BLUE_TT), 0, 1);
  6840. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_OUTER_OPACITY), &m_pState->m_shape[i].a2, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_OUTER_OPACITY_TT), 0, 1);
  6841. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_BORDER_COLOR_RED), &m_pState->m_shape[i].border_r, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BORDER_COLOR_RED_TT), 0, 1);
  6842. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_BORDER_COLOR_GREEN), &m_pState->m_shape[i].border_g, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BORDER_COLOR_GREEN_TT), 0, 1);
  6843. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_BORDER_COLOR_BLUE), &m_pState->m_shape[i].border_b, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BORDER_COLOR_BLUE_TT), 0, 1);
  6844. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_BORDER_OPACITY), &m_pState->m_shape[i].border_a, MENUITEMTYPE_FLOAT, MEN_TT(IDS_MENU_BORDER_OPACITY_TT), 0, 1);
  6845. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_EXPORT_TO_FILE), NULL, MENUITEMTYPE_UIMODE, MEN_TT(IDS_MENU_EXPORT_TO_FILE_SHAPE_TT), 0, 0, NULL, UI_EXPORT_SHAPE, i);
  6846. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_IMPORT_FROM_FILE), NULL, MENUITEMTYPE_UIMODE, MEN_TT(IDS_MENU_IMPORT_FROM_FILE_SHAPE_TT), 0, 0, NULL, UI_IMPORT_SHAPE, i);
  6847. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_EDIT_INIT_CODE), &m_pState->m_shape[i].m_szInit, MENUITEMTYPE_STRING, MEN_TT(IDS_MENU_EDIT_INIT_CODE_SHAPE_TT), 256, 0, &OnUserEditedShapecodeInit, sizeof(m_pState->m_shape[i].m_szInit), 0);
  6848. m_menuShapecode[i].AddItem(MEN_T(IDS_MENU_EDIT_PER_FRAME_INSTANCE_CODE), &m_pState->m_shape[i].m_szPerFrame, MENUITEMTYPE_STRING, MEN_TT(IDS_MENU_EDIT_PER_FRAME_INSTANCE_CODE_TT), 256, 0, &OnUserEditedShapecode, sizeof(m_pState->m_shape[i].m_szPerFrame), 0);
  6849. //m_menuShapecode[i].AddItem("[ edit per-point code ]",&m_pState->m_shape[i].m_szPerPoint, MENUITEMTYPE_STRING, "IN: sample [0..1]; value1 [left ch], value2 [right ch], plus all vars for per-frame code / OUT: x,y; r,g,b,a; t1-t8", 256, 0, &OnUserEditedWavecode);
  6850. }
  6851. }
  6852. void CPlugin::WriteRealtimeConfig()
  6853. {
  6854. WritePrivateProfileIntW(m_bShowFPS, L"bShowFPS",GetConfigIniFile(), L"settings");
  6855. WritePrivateProfileIntW(m_bShowRating, L"bShowRating",GetConfigIniFile(), L"settings");
  6856. WritePrivateProfileIntW(m_bShowPresetInfo, L"bShowPresetInfo",GetConfigIniFile(), L"settings");
  6857. WritePrivateProfileIntW(m_bShowSongTitle, L"bShowSongTitle",GetConfigIniFile(), L"settings");
  6858. WritePrivateProfileIntW(m_bShowSongTime, L"bShowSongTime",GetConfigIniFile(), L"settings");
  6859. WritePrivateProfileIntW(m_bShowSongLen, L"bShowSongLen",GetConfigIniFile(), L"settings");
  6860. }
  6861. void CPlugin::dumpmsg(wchar_t *s)
  6862. {
  6863. #if _DEBUG
  6864. OutputDebugStringW(s);
  6865. if (s[0])
  6866. {
  6867. int len = lstrlenW(s);
  6868. if (s[len-1] != L'\n')
  6869. OutputDebugStringW(L"\n");
  6870. }
  6871. #endif
  6872. }
  6873. void CPlugin::PrevPreset(float fBlendTime)
  6874. {
  6875. if (m_bSequentialPresetOrder)
  6876. {
  6877. m_nCurrentPreset--;
  6878. if (m_nCurrentPreset < m_nDirs)
  6879. m_nCurrentPreset = m_nPresets-1;
  6880. if (m_nCurrentPreset >= m_nPresets) // just in case
  6881. m_nCurrentPreset = m_nDirs;
  6882. wchar_t szFile[MAX_PATH];
  6883. lstrcpyW(szFile, m_szPresetDir); // note: m_szPresetDir always ends with '\'
  6884. lstrcatW(szFile, m_presets[m_nCurrentPreset].szFilename.c_str());
  6885. LoadPreset(szFile, fBlendTime);
  6886. }
  6887. else
  6888. {
  6889. int prev = (m_presetHistoryPos-1 + PRESET_HIST_LEN) % PRESET_HIST_LEN;
  6890. if (m_presetHistoryPos != m_presetHistoryBackFence)
  6891. {
  6892. m_presetHistoryPos = prev;
  6893. LoadPreset( m_presetHistory[m_presetHistoryPos].c_str(), fBlendTime);
  6894. }
  6895. }
  6896. }
  6897. void CPlugin::NextPreset(float fBlendTime) // if not retracing our former steps, it will choose a random one.
  6898. {
  6899. LoadRandomPreset(fBlendTime);
  6900. }
  6901. void CPlugin::LoadRandomPreset(float fBlendTime)
  6902. {
  6903. // make sure file list is ok
  6904. if (m_nPresets - m_nDirs == 0)
  6905. {
  6906. if (m_nPresets - m_nDirs == 0)
  6907. {
  6908. // note: this error message is repeated in milkdropfs.cpp in DrawText()
  6909. wchar_t buf[1024];
  6910. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ERROR_NO_PRESET_FILE_FOUND_IN_X_MILK), m_szPresetDir);
  6911. AddError(buf, 6.0f, ERR_MISC, true);
  6912. // also bring up the dir. navigation menu...
  6913. if (m_UI_mode == UI_REGULAR || m_UI_mode == UI_MENU)
  6914. {
  6915. m_UI_mode = UI_LOAD;
  6916. m_bUserPagedUp = false;
  6917. m_bUserPagedDown = false;
  6918. }
  6919. return;
  6920. }
  6921. }
  6922. bool bHistoryEmpty = (m_presetHistoryFwdFence==m_presetHistoryBackFence);
  6923. // if we have history to march back forward through, do that first
  6924. if (!m_bSequentialPresetOrder)
  6925. {
  6926. int next = (m_presetHistoryPos+1) % PRESET_HIST_LEN;
  6927. if (next != m_presetHistoryFwdFence && !bHistoryEmpty)
  6928. {
  6929. m_presetHistoryPos = next;
  6930. LoadPreset( m_presetHistory[m_presetHistoryPos].c_str(), fBlendTime);
  6931. return;
  6932. }
  6933. }
  6934. // --TEMPORARY--
  6935. // this comes in handy if you want to mass-modify a batch of presets;
  6936. // just automatically tweak values in Import, then they immediately get exported to a .MILK in a new dir.
  6937. /*
  6938. for (int i=0; i<m_nPresets; i++)
  6939. {
  6940. char szPresetFile[512];
  6941. lstrcpy(szPresetFile, m_szPresetDir); // note: m_szPresetDir always ends with '\'
  6942. lstrcat(szPresetFile, m_pPresetAddr[i]);
  6943. //CState newstate;
  6944. m_state2.Import(szPresetFile, GetTime());
  6945. lstrcpy(szPresetFile, "c:\\t7\\");
  6946. lstrcat(szPresetFile, m_pPresetAddr[i]);
  6947. m_state2.Export(szPresetFile);
  6948. }
  6949. */
  6950. // --[END]TEMPORARY--
  6951. if (m_bSequentialPresetOrder)
  6952. {
  6953. m_nCurrentPreset++;
  6954. if (m_nCurrentPreset < m_nDirs || m_nCurrentPreset >= m_nPresets)
  6955. m_nCurrentPreset = m_nDirs;
  6956. }
  6957. else
  6958. {
  6959. // pick a random file
  6960. if (!m_bEnableRating || (m_presets[m_nPresets - 1].fRatingCum < 0.1f))// || (m_nRatingReadProgress < m_nPresets))
  6961. {
  6962. m_nCurrentPreset = m_nDirs + (warand() % (m_nPresets - m_nDirs));
  6963. }
  6964. else
  6965. {
  6966. float cdf_pos = (warand() % 14345)/14345.0f*m_presets[m_nPresets - 1].fRatingCum;
  6967. /*
  6968. char buf[512];
  6969. sprintf(buf, "max = %f, rand = %f, \tvalues: ", m_presets[m_nPresets - 1].fRatingCum, cdf_pos);
  6970. for (int i=m_nDirs; i<m_nPresets; i++)
  6971. {
  6972. char buf2[32];
  6973. sprintf(buf2, "%3.1f ", m_presets[i].fRatingCum);
  6974. lstrcat(buf, buf2);
  6975. }
  6976. dumpmsg(buf);
  6977. */
  6978. if (cdf_pos < m_presets[m_nDirs].fRatingCum)
  6979. {
  6980. m_nCurrentPreset = m_nDirs;
  6981. }
  6982. else
  6983. {
  6984. int lo = m_nDirs;
  6985. int hi = m_nPresets;
  6986. while (lo + 1 < hi)
  6987. {
  6988. int mid = (lo+hi)/2;
  6989. if (m_presets[mid].fRatingCum > cdf_pos)
  6990. hi = mid;
  6991. else
  6992. lo = mid;
  6993. }
  6994. m_nCurrentPreset = hi;
  6995. }
  6996. }
  6997. }
  6998. // m_pPresetAddr[m_nCurrentPreset] points to the preset file to load (w/o the path);
  6999. // first prepend the path, then load section [preset00] within that file
  7000. wchar_t szFile[MAX_PATH] = {0};
  7001. lstrcpyW(szFile, m_szPresetDir); // note: m_szPresetDir always ends with '\'
  7002. lstrcatW(szFile, m_presets[m_nCurrentPreset].szFilename.c_str());
  7003. if (!bHistoryEmpty)
  7004. m_presetHistoryPos = (m_presetHistoryPos+1) % PRESET_HIST_LEN;
  7005. LoadPreset(szFile, fBlendTime);
  7006. }
  7007. void CPlugin::RandomizeBlendPattern()
  7008. {
  7009. if (!m_vertinfo)
  7010. return;
  7011. // note: we now avoid constant uniform blend b/c it's half-speed for shader blending.
  7012. // (both old & new shaders would have to run on every pixel...)
  7013. int mixtype = 1 + (warand()%3);//warand()%4;
  7014. if (mixtype==0)
  7015. {
  7016. // constant, uniform blend
  7017. int nVert = 0;
  7018. for (int y=0; y<=m_nGridY; y++)
  7019. {
  7020. for (int x=0; x<=m_nGridX; x++)
  7021. {
  7022. m_vertinfo[nVert].a = 1;
  7023. m_vertinfo[nVert].c = 0;
  7024. nVert++;
  7025. }
  7026. }
  7027. }
  7028. else if (mixtype==1)
  7029. {
  7030. // directional wipe
  7031. float ang = FRAND*6.28f;
  7032. float vx = cosf(ang);
  7033. float vy = sinf(ang);
  7034. float band = 0.1f + 0.2f*FRAND; // 0.2 is good
  7035. float inv_band = 1.0f/band;
  7036. int nVert = 0;
  7037. for (int y=0; y<=m_nGridY; y++)
  7038. {
  7039. float fy = (y/(float)m_nGridY)*m_fAspectY;
  7040. for (int x=0; x<=m_nGridX; x++)
  7041. {
  7042. float fx = (x/(float)m_nGridX)*m_fAspectX;
  7043. // at t==0, mix rangse from -10..0
  7044. // at t==1, mix ranges from 1..11
  7045. float t = (fx-0.5f)*vx + (fy-0.5f)*vy + 0.5f;
  7046. t = (t-0.5f)/sqrtf(2.0f) + 0.5f;
  7047. m_vertinfo[nVert].a = inv_band * (1 + band);
  7048. m_vertinfo[nVert].c = -inv_band + inv_band*t;//(x/(float)m_nGridX - 0.5f)/band;
  7049. nVert++;
  7050. }
  7051. }
  7052. }
  7053. else if (mixtype==2)
  7054. {
  7055. // plasma transition
  7056. float band = 0.12f + 0.13f*FRAND;//0.02f + 0.18f*FRAND;
  7057. float inv_band = 1.0f/band;
  7058. // first generate plasma array of height values
  7059. m_vertinfo[ 0].c = FRAND;
  7060. m_vertinfo[ m_nGridX].c = FRAND;
  7061. m_vertinfo[m_nGridY*(m_nGridX+1) ].c = FRAND;
  7062. m_vertinfo[m_nGridY*(m_nGridX+1) + m_nGridX].c = FRAND;
  7063. GenPlasma(0, m_nGridX, 0, m_nGridY, 0.25f);
  7064. // then find min,max so we can normalize to [0..1] range and then to the proper 'constant offset' range.
  7065. float minc = m_vertinfo[0].c;
  7066. float maxc = m_vertinfo[0].c;
  7067. int x,y,nVert;
  7068. nVert = 0;
  7069. for (y=0; y<=m_nGridY; y++)
  7070. {
  7071. for (x=0; x<=m_nGridX; x++)
  7072. {
  7073. if (minc > m_vertinfo[nVert].c)
  7074. minc = m_vertinfo[nVert].c;
  7075. if (maxc < m_vertinfo[nVert].c)
  7076. maxc = m_vertinfo[nVert].c;
  7077. nVert++;
  7078. }
  7079. }
  7080. float mult = 1.0f/(maxc-minc);
  7081. nVert = 0;
  7082. for (y=0; y<=m_nGridY; y++)
  7083. {
  7084. for (x=0; x<=m_nGridX; x++)
  7085. {
  7086. float t = (m_vertinfo[nVert].c - minc)*mult;
  7087. m_vertinfo[nVert].a = inv_band * (1 + band);
  7088. m_vertinfo[nVert].c = -inv_band + inv_band*t;
  7089. nVert++;
  7090. }
  7091. }
  7092. }
  7093. else if (mixtype==3)
  7094. {
  7095. // radial blend
  7096. float band = 0.02f + 0.14f*FRAND + 0.34f*FRAND;
  7097. float inv_band = 1.0f/band;
  7098. float dir = (float)((warand()%2)*2 - 1); // 1=outside-in, -1=inside-out
  7099. int nVert = 0;
  7100. for (int y=0; y<=m_nGridY; y++)
  7101. {
  7102. float dy = (y/(float)m_nGridY - 0.5f)*m_fAspectY;
  7103. for (int x=0; x<=m_nGridX; x++)
  7104. {
  7105. float dx = (x/(float)m_nGridX - 0.5f)*m_fAspectX;
  7106. float t = sqrtf(dx*dx + dy*dy)*1.41421f;
  7107. if (dir==-1)
  7108. t = 1-t;
  7109. m_vertinfo[nVert].a = inv_band * (1 + band);
  7110. m_vertinfo[nVert].c = -inv_band + inv_band*t;
  7111. nVert++;
  7112. }
  7113. }
  7114. }
  7115. }
  7116. void CPlugin::GenPlasma(int x0, int x1, int y0, int y1, float dt)
  7117. {
  7118. int midx = (x0+x1)/2;
  7119. int midy = (y0+y1)/2;
  7120. float t00 = m_vertinfo[y0*(m_nGridX+1) + x0].c;
  7121. float t01 = m_vertinfo[y0*(m_nGridX+1) + x1].c;
  7122. float t10 = m_vertinfo[y1*(m_nGridX+1) + x0].c;
  7123. float t11 = m_vertinfo[y1*(m_nGridX+1) + x1].c;
  7124. if (y1-y0 >= 2)
  7125. {
  7126. if (x0==0)
  7127. m_vertinfo[midy*(m_nGridX+1) + x0].c = 0.5f*(t00 + t10) + (FRAND*2-1)*dt*m_fAspectY;
  7128. m_vertinfo[midy*(m_nGridX+1) + x1].c = 0.5f*(t01 + t11) + (FRAND*2-1)*dt*m_fAspectY;
  7129. }
  7130. if (x1-x0 >= 2)
  7131. {
  7132. if (y0==0)
  7133. m_vertinfo[y0*(m_nGridX+1) + midx].c = 0.5f*(t00 + t01) + (FRAND*2-1)*dt*m_fAspectX;
  7134. m_vertinfo[y1*(m_nGridX+1) + midx].c = 0.5f*(t10 + t11) + (FRAND*2-1)*dt*m_fAspectX;
  7135. }
  7136. if (y1-y0 >= 2 && x1-x0 >= 2)
  7137. {
  7138. // do midpoint & recurse:
  7139. t00 = m_vertinfo[midy*(m_nGridX+1) + x0].c;
  7140. t01 = m_vertinfo[midy*(m_nGridX+1) + x1].c;
  7141. t10 = m_vertinfo[y0*(m_nGridX+1) + midx].c;
  7142. t11 = m_vertinfo[y1*(m_nGridX+1) + midx].c;
  7143. m_vertinfo[midy*(m_nGridX+1) + midx].c = 0.25f*(t10 + t11 + t00 + t01) + (FRAND*2-1)*dt;
  7144. GenPlasma(x0, midx, y0, midy, dt*0.5f);
  7145. GenPlasma(midx, x1, y0, midy, dt*0.5f);
  7146. GenPlasma(x0, midx, midy, y1, dt*0.5f);
  7147. GenPlasma(midx, x1, midy, y1, dt*0.5f);
  7148. }
  7149. }
  7150. void CPlugin::LoadPreset(const wchar_t *szPresetFilename, float fBlendTime)
  7151. {
  7152. // clear old error msg...
  7153. if (m_nFramesSinceResize > 4)
  7154. ClearErrors(ERR_PRESET);
  7155. // make sure preset still exists. (might not if they are using the "back"/fwd buttons
  7156. // in RANDOM preset order and a file was renamed or deleted!)
  7157. if (GetFileAttributesW(szPresetFilename) == 0xFFFFFFFF)
  7158. {
  7159. const wchar_t *p = wcsrchr(szPresetFilename, L'\\');
  7160. p = (p) ? p+1 : szPresetFilename;
  7161. wchar_t buf[1024];
  7162. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ERROR_PRESET_NOT_FOUND_X), p);
  7163. AddError(buf, 6.0f, ERR_PRESET, true);
  7164. return;
  7165. }
  7166. if ( !m_bSequentialPresetOrder )
  7167. {
  7168. // save preset in the history. keep in mind - maybe we are searching back through it already!
  7169. if ( m_presetHistoryFwdFence == m_presetHistoryPos )
  7170. {
  7171. // we're at the forward frontier; add to history
  7172. m_presetHistory[m_presetHistoryPos] = szPresetFilename;
  7173. m_presetHistoryFwdFence = (m_presetHistoryFwdFence+1) % PRESET_HIST_LEN;
  7174. // don't let the two fences touch
  7175. if (m_presetHistoryBackFence == m_presetHistoryFwdFence)
  7176. m_presetHistoryBackFence = (m_presetHistoryBackFence+1) % PRESET_HIST_LEN;
  7177. }
  7178. else
  7179. {
  7180. // we're retracing our steps, either forward or backward...
  7181. }
  7182. }
  7183. // if no preset was valid before, make sure there is no blend, because there is nothing valid to blend from.
  7184. if (!wcscmp(m_pState->m_szDesc, INVALID_PRESET_DESC))
  7185. fBlendTime = 0;
  7186. if (fBlendTime == 0)
  7187. {
  7188. // do it all NOW!
  7189. if (szPresetFilename != m_szCurrentPresetFile) //[sic]
  7190. lstrcpyW(m_szCurrentPresetFile, szPresetFilename);
  7191. CState *temp = m_pState;
  7192. m_pState = m_pOldState;
  7193. m_pOldState = temp;
  7194. DWORD ApplyFlags = STATE_ALL;
  7195. ApplyFlags ^= (m_bWarpShaderLock ? STATE_WARP : 0);
  7196. ApplyFlags ^= (m_bCompShaderLock ? STATE_COMP : 0);
  7197. m_pState->Import(m_szCurrentPresetFile, GetTime(), m_pOldState, ApplyFlags);
  7198. if (fBlendTime >= 0.001f)
  7199. {
  7200. RandomizeBlendPattern();
  7201. m_pState->StartBlendFrom(m_pOldState, GetTime(), fBlendTime);
  7202. }
  7203. m_fPresetStartTime = GetTime();
  7204. m_fNextPresetTime = -1.0f; // flags UpdateTime() to recompute this
  7205. // release stuff from m_OldShaders, then move m_shaders to m_OldShaders, then load the new shaders.
  7206. SafeRelease( m_OldShaders.comp.ptr );
  7207. SafeRelease( m_OldShaders.warp.ptr );
  7208. SafeRelease( m_OldShaders.comp.CT );
  7209. SafeRelease( m_OldShaders.warp.CT );
  7210. m_OldShaders = m_shaders;
  7211. ZeroMemory(&m_shaders, sizeof(PShaderSet));
  7212. LoadShaders(&m_shaders, m_pState, false);
  7213. OnFinishedLoadingPreset();
  7214. }
  7215. else
  7216. {
  7217. // set ourselves up to load the preset (and esp. compile shaders) a little bit at a time
  7218. SafeRelease( m_NewShaders.comp.ptr );
  7219. SafeRelease( m_NewShaders.warp.ptr );
  7220. ZeroMemory(&m_NewShaders, sizeof(PShaderSet));
  7221. DWORD ApplyFlags = STATE_ALL;
  7222. ApplyFlags ^= (m_bWarpShaderLock ? STATE_WARP : 0);
  7223. ApplyFlags ^= (m_bCompShaderLock ? STATE_COMP : 0);
  7224. m_pNewState->Import(szPresetFilename, GetTime(), m_pOldState, ApplyFlags);
  7225. m_nLoadingPreset = 1; // this will cause LoadPresetTick() to get called over the next few frames...
  7226. m_fLoadingPresetBlendTime = fBlendTime;
  7227. lstrcpyW(m_szLoadingPreset, szPresetFilename);
  7228. }
  7229. }
  7230. void CPlugin::OnFinishedLoadingPreset()
  7231. {
  7232. // note: only used this if you loaded the preset *intact* (or mostly intact)
  7233. SetMenusForPresetVersion( m_pState->m_nWarpPSVersion, m_pState->m_nCompPSVersion );
  7234. m_nPresetsLoadedTotal++; //only increment this on COMPLETION of the load.
  7235. for (int mash=0; mash<MASH_SLOTS; mash++)
  7236. m_nMashPreset[mash] = m_nCurrentPreset;
  7237. }
  7238. void CPlugin::LoadPresetTick()
  7239. {
  7240. if (m_nLoadingPreset == 2 || m_nLoadingPreset == 5)
  7241. {
  7242. // just loads one shader (warp or comp) then returns.
  7243. LoadShaders(&m_NewShaders, m_pNewState, true);
  7244. }
  7245. else if (m_nLoadingPreset == 8)
  7246. {
  7247. // finished loading the shaders - apply the preset!
  7248. lstrcpyW(m_szCurrentPresetFile, m_szLoadingPreset);
  7249. m_szLoadingPreset[0] = 0;
  7250. CState *temp = m_pState;
  7251. m_pState = m_pOldState;
  7252. m_pOldState = temp;
  7253. temp = m_pState;
  7254. m_pState = m_pNewState;
  7255. m_pNewState = temp;
  7256. RandomizeBlendPattern();
  7257. //if (fBlendTime >= 0.001f)
  7258. m_pState->StartBlendFrom(m_pOldState, GetTime(), m_fLoadingPresetBlendTime);
  7259. m_fPresetStartTime = GetTime();
  7260. m_fNextPresetTime = -1.0f; // flags UpdateTime() to recompute this
  7261. // release stuff from m_OldShaders, then move m_shaders to m_OldShaders, then load the new shaders.
  7262. SafeRelease( m_OldShaders.comp.ptr );
  7263. SafeRelease( m_OldShaders.warp.ptr );
  7264. m_OldShaders = m_shaders;
  7265. m_shaders = m_NewShaders;
  7266. ZeroMemory(&m_NewShaders, sizeof(PShaderSet));
  7267. // end slow-preset-load mode
  7268. m_nLoadingPreset = 0;
  7269. OnFinishedLoadingPreset();
  7270. }
  7271. if (m_nLoadingPreset > 0)
  7272. m_nLoadingPreset++;
  7273. }
  7274. void CPlugin::SeekToPreset(wchar_t cStartChar)
  7275. {
  7276. if (cStartChar >= L'a' && cStartChar <= L'z')
  7277. cStartChar -= L'a' - L'A';
  7278. for (int i = m_nDirs; i < m_nPresets; i++)
  7279. {
  7280. wchar_t ch = m_presets[i].szFilename.c_str()[0];
  7281. if (ch >= L'a' && ch <= L'z')
  7282. ch -= L'a' - L'A';
  7283. if (ch == cStartChar)
  7284. {
  7285. m_nPresetListCurPos = i;
  7286. return;
  7287. }
  7288. }
  7289. }
  7290. void CPlugin::FindValidPresetDir()
  7291. {
  7292. swprintf(m_szPresetDir, L"%spresets\\", m_szMilkdrop2Path );
  7293. if (GetFileAttributesW(m_szPresetDir) != -1)
  7294. return;
  7295. lstrcpyW(m_szPresetDir, m_szMilkdrop2Path);
  7296. if (GetFileAttributesW(m_szPresetDir) != -1)
  7297. return;
  7298. lstrcpyW(m_szPresetDir, GetPluginsDirPath());
  7299. if (GetFileAttributesW(m_szPresetDir) != -1)
  7300. return;
  7301. lstrcpyW(m_szPresetDir, L"c:\\program files\\winamp\\"); //getting desperate here
  7302. if (GetFileAttributesW(m_szPresetDir) != -1)
  7303. return;
  7304. lstrcpyW(m_szPresetDir, L"c:\\program files\\"); //getting desperate here
  7305. if (GetFileAttributesW(m_szPresetDir) != -1)
  7306. return;
  7307. lstrcpyW(m_szPresetDir, L"c:\\");
  7308. }
  7309. char* NextLine(char* p)
  7310. {
  7311. // p points to the beginning of a line
  7312. // we'll return a pointer to the first char of the next line
  7313. // if we hit a NULL char before that, we'll return NULL.
  7314. if (!p)
  7315. return NULL;
  7316. char* s = p;
  7317. while (*s != '\r' && *s != '\n' && *s != 0)
  7318. s++;
  7319. while (*s == '\r' || *s == '\n')
  7320. s++;
  7321. if (*s==0)
  7322. return NULL;
  7323. return s;
  7324. }
  7325. static unsigned int WINAPI __UpdatePresetList(void* lpVoid)
  7326. {
  7327. // NOTE - this is run in a separate thread!!!
  7328. DWORD flags = (DWORD)lpVoid;
  7329. bool bForce = (flags & 1) ? true : false;
  7330. bool bTryReselectCurrentPreset = (flags & 2) ? true : false;
  7331. WIN32_FIND_DATAW fd;
  7332. ZeroMemory(&fd, sizeof(fd));
  7333. HANDLE h = INVALID_HANDLE_VALUE;
  7334. int nTry = 0;
  7335. bool bRetrying = false;
  7336. EnterCriticalSection(&g_cs);
  7337. retry:
  7338. // make sure the path exists; if not, go to winamp plugins dir
  7339. if (GetFileAttributesW(g_plugin.m_szPresetDir) == -1)
  7340. {
  7341. //FIXME...
  7342. g_plugin.FindValidPresetDir();
  7343. }
  7344. // if Mask (dir) changed, do a full re-scan;
  7345. // if not, just finish our old scan.
  7346. wchar_t szMask[MAX_PATH];
  7347. swprintf(szMask, L"%s*.*", g_plugin.m_szPresetDir); // cuz dirnames could have extensions, etc.
  7348. if (bForce || !g_plugin.m_szUpdatePresetMask[0] || wcscmp(szMask, g_plugin.m_szUpdatePresetMask))
  7349. {
  7350. // if old dir was "" or the dir changed, reset our search
  7351. if (h != INVALID_HANDLE_VALUE)
  7352. FindClose(h);
  7353. h = INVALID_HANDLE_VALUE;
  7354. g_plugin.m_bPresetListReady = false;
  7355. lstrcpyW(g_plugin.m_szUpdatePresetMask, szMask);
  7356. ZeroMemory(&fd, sizeof(fd));
  7357. g_plugin.m_nPresets = 0;
  7358. g_plugin.m_nDirs = 0;
  7359. g_plugin.m_presets.clear();
  7360. // find first .MILK file
  7361. //if( (hFile = _findfirst(szMask, &c_file )) != -1L ) // note: returns filename -without- path
  7362. if( (h = FindFirstFileW(g_plugin.m_szUpdatePresetMask, &fd )) == INVALID_HANDLE_VALUE ) // note: returns filename -without- path
  7363. {
  7364. // --> revert back to plugins dir
  7365. wchar_t buf[1024];
  7366. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ERROR_NO_PRESET_FILES_OR_DIRS_FOUND_IN_X), g_plugin.m_szPresetDir);
  7367. g_plugin.AddError(buf, 4.0f, ERR_MISC, true);
  7368. if (bRetrying)
  7369. {
  7370. LeaveCriticalSection(&g_cs);
  7371. g_bThreadAlive = false;
  7372. _endthreadex(0);
  7373. return 0;
  7374. }
  7375. g_plugin.FindValidPresetDir();
  7376. bRetrying = true;
  7377. goto retry;
  7378. }
  7379. g_plugin.AddError(WASABI_API_LNGSTRINGW(IDS_SCANNING_PRESETS), 8.0f, ERR_SCANNING_PRESETS, false);
  7380. }
  7381. if (g_plugin.m_bPresetListReady)
  7382. {
  7383. LeaveCriticalSection(&g_cs);
  7384. g_bThreadAlive = false;
  7385. _endthreadex(0);
  7386. return 0;
  7387. }
  7388. int nMaxPSVersion = g_plugin.m_nMaxPSVersion;
  7389. wchar_t szPresetDir[MAX_PATH];
  7390. lstrcpyW(szPresetDir, g_plugin.m_szPresetDir);
  7391. LeaveCriticalSection(&g_cs);
  7392. PresetList temp_presets;
  7393. int temp_nDirs = 0;
  7394. int temp_nPresets = 0;
  7395. // scan for the desired # of presets, this call...
  7396. while (!g_bThreadShouldQuit && h != INVALID_HANDLE_VALUE)
  7397. {
  7398. bool bSkip = false;
  7399. bool bIsDir = (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
  7400. float fRating = 0;
  7401. wchar_t szFilename[512];
  7402. lstrcpyW(szFilename, fd.cFileName);
  7403. if (bIsDir)
  7404. {
  7405. // skip "." directory
  7406. if (wcscmp(fd.cFileName, L".")==0)// || lstrlen(ffd.cFileName) < 1)
  7407. bSkip = true;
  7408. else
  7409. swprintf(szFilename, L"*%s", fd.cFileName);
  7410. }
  7411. else
  7412. {
  7413. // skip normal files not ending in ".milk"
  7414. int len = lstrlenW(fd.cFileName);
  7415. if (len < 5 || wcsicmp(fd.cFileName + len - 5, L".milk") != 0)
  7416. bSkip = true;
  7417. // if it is .milk, make sure we know how to run its pixel shaders -
  7418. // otherwise we don't want to show it in the preset list!
  7419. if (!bSkip)
  7420. {
  7421. // If the first line of the file is not "MILKDROP_PRESET_VERSION XXX",
  7422. // then it's a MilkDrop 1 era preset, so it is definitely runnable. (no shaders)
  7423. // Otherwise, check for the value "PSVERSION". It will be 0, 2, or 3.
  7424. // If missing, assume it is 2.
  7425. wchar_t szFullPath[MAX_PATH];
  7426. swprintf(szFullPath, L"%s%s", szPresetDir, fd.cFileName);
  7427. FILE* f = _wfopen(szFullPath, L"r");
  7428. if (!f)
  7429. bSkip = true;
  7430. else {
  7431. #define PRESET_HEADER_SCAN_BYTES 160
  7432. char szLine[PRESET_HEADER_SCAN_BYTES];
  7433. char *p = szLine;
  7434. int bytes_to_read = sizeof(szLine)-1;
  7435. int count = fread(szLine, bytes_to_read, 1, f);
  7436. if (count < 1) {
  7437. fseek(f, SEEK_SET, 0);
  7438. count = fread(szLine, 1, bytes_to_read, f);
  7439. szLine[ count ] = 0;
  7440. }
  7441. else
  7442. szLine[bytes_to_read-1] = 0;
  7443. bool bScanForPreset00AndRating = false;
  7444. bool bRatingKnown = false;
  7445. // try to read the PSVERSION and the fRating= value.
  7446. // most presets (unless hand-edited) will have these right at the top.
  7447. // if not, [at least for fRating] use GetPrivateProfileFloat to search whole file.
  7448. // read line 1
  7449. //p = NextLine(p);//fgets(p, sizeof(p)-1, f);
  7450. if (!strncmp(p, "MILKDROP_PRESET_VERSION", 23))
  7451. {
  7452. p = NextLine(p);//fgets(p, sizeof(p)-1, f);
  7453. int ps_version = 2;
  7454. if (p && !strncmp(p, "PSVERSION", 9))
  7455. {
  7456. sscanf(&p[10], "%d", &ps_version);
  7457. if (ps_version > nMaxPSVersion)
  7458. bSkip = true;
  7459. else
  7460. {
  7461. p = NextLine(p);//fgets(p, sizeof(p)-1, f);
  7462. bScanForPreset00AndRating = true;
  7463. }
  7464. }
  7465. }
  7466. else
  7467. {
  7468. // otherwise it's a MilkDrop 1 preset - we can run it.
  7469. bScanForPreset00AndRating = true;
  7470. }
  7471. // scan up to 10 more lines in the file, looking for [preset00] and fRating=...
  7472. // (this is WAY faster than GetPrivateProfileFloat, when it works!)
  7473. int reps = (bScanForPreset00AndRating) ? 10 : 0;
  7474. for (int z=0; z<reps; z++)
  7475. {
  7476. if (p && !strncmp(p, "[preset00]", 10))
  7477. {
  7478. p = NextLine(p);
  7479. if (p && !strncmp(p, "fRating=", 8))
  7480. {
  7481. _sscanf_l(&p[8], "%f", g_use_C_locale, &fRating);
  7482. bRatingKnown = true;
  7483. break;
  7484. }
  7485. }
  7486. p = NextLine(p);
  7487. }
  7488. fclose(f);
  7489. if (!bRatingKnown)
  7490. fRating = GetPrivateProfileFloatW(L"preset00", L"fRating", 3.0f, szFullPath);
  7491. fRating = max(0.0f, min(5.0f, fRating));
  7492. }
  7493. }
  7494. }
  7495. if (!bSkip)
  7496. {
  7497. float fPrevPresetRatingCum = 0;
  7498. if (temp_nPresets > 0)
  7499. fPrevPresetRatingCum += temp_presets[temp_nPresets-1].fRatingCum;
  7500. PresetInfo x;
  7501. x.szFilename = szFilename;
  7502. x.fRatingThis = fRating;
  7503. x.fRatingCum = fPrevPresetRatingCum + fRating;
  7504. temp_presets.push_back(x);
  7505. temp_nPresets++;
  7506. if (bIsDir)
  7507. temp_nDirs++;
  7508. }
  7509. if (!FindNextFileW(h, &fd))
  7510. {
  7511. FindClose(h);
  7512. h = INVALID_HANDLE_VALUE;
  7513. break;
  7514. }
  7515. // every so often, add some presets...
  7516. #define PRESET_UPDATE_INTERVAL 64
  7517. if (temp_nPresets == 30 || ((temp_nPresets % PRESET_UPDATE_INTERVAL)==0))
  7518. {
  7519. EnterCriticalSection(&g_cs);
  7520. //g_plugin.m_presets = temp_presets;
  7521. for (int i=g_plugin.m_nPresets; i<temp_nPresets; i++)
  7522. g_plugin.m_presets.push_back(temp_presets[i]);
  7523. g_plugin.m_nPresets = temp_nPresets;
  7524. g_plugin.m_nDirs = temp_nDirs;
  7525. LeaveCriticalSection(&g_cs);
  7526. }
  7527. }
  7528. if (g_bThreadShouldQuit)
  7529. {
  7530. // just abort... we are exiting the program or restarting the scan.
  7531. g_bThreadAlive = false;
  7532. _endthreadex(0);
  7533. return 0;
  7534. }
  7535. EnterCriticalSection(&g_cs);
  7536. //g_plugin.m_presets = temp_presets;
  7537. for (int i=g_plugin.m_nPresets; i<temp_nPresets; i++)
  7538. g_plugin.m_presets.push_back(temp_presets[i]);
  7539. g_plugin.m_nPresets = temp_nPresets;
  7540. g_plugin.m_nDirs = temp_nDirs;
  7541. g_plugin.m_bPresetListReady = true;
  7542. if (g_plugin.m_bPresetListReady && g_plugin.m_nPresets == 0)
  7543. {
  7544. // no presets OR directories found - weird - but it happens.
  7545. // --> revert back to plugins dir
  7546. wchar_t buf[1024];
  7547. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_ERROR_NO_PRESET_FILES_OR_DIRS_FOUND_IN_X), g_plugin.m_szPresetDir);
  7548. g_plugin.AddError(buf, 4.0f, ERR_MISC, true);
  7549. if (bRetrying)
  7550. {
  7551. LeaveCriticalSection(&g_cs);
  7552. g_bThreadAlive = false;
  7553. _endthreadex(0);
  7554. return 0;
  7555. }
  7556. g_plugin.FindValidPresetDir();
  7557. bRetrying = true;
  7558. goto retry;
  7559. }
  7560. if (g_plugin.m_bPresetListReady)
  7561. {
  7562. g_plugin.MergeSortPresets(0, g_plugin.m_nPresets-1);
  7563. // update cumulative ratings, since order changed...
  7564. g_plugin.m_presets[0].fRatingCum = g_plugin.m_presets[0].fRatingThis;
  7565. for (int i=0; i<g_plugin.m_nPresets; i++)
  7566. g_plugin.m_presets[i].fRatingCum = g_plugin.m_presets[i-1].fRatingCum + g_plugin.m_presets[i].fRatingThis;
  7567. // clear the "scanning presets" msg
  7568. g_plugin.ClearErrors(ERR_SCANNING_PRESETS);
  7569. // finally, try to re-select the most recently-used preset in the list
  7570. g_plugin.m_nPresetListCurPos = 0;
  7571. if (bTryReselectCurrentPreset)
  7572. {
  7573. if (g_plugin.m_szCurrentPresetFile[0])
  7574. {
  7575. // try to automatically seek to the last preset loaded
  7576. wchar_t *p = wcsrchr(g_plugin.m_szCurrentPresetFile, L'\\');
  7577. p = (p) ? (p+1) : g_plugin.m_szCurrentPresetFile;
  7578. for (int i=g_plugin.m_nDirs; i<g_plugin.m_nPresets; i++)
  7579. {
  7580. if (wcscmp(p, g_plugin.m_presets[i].szFilename.c_str())==0) {
  7581. g_plugin.m_nPresetListCurPos = i;
  7582. break;
  7583. }
  7584. }
  7585. }
  7586. }
  7587. }
  7588. LeaveCriticalSection(&g_cs);
  7589. g_bThreadAlive = false;
  7590. _endthreadex(0);
  7591. return 0;
  7592. }
  7593. void CPlugin::UpdatePresetList(bool bBackground, bool bForce, bool bTryReselectCurrentPreset)
  7594. {
  7595. // note: if dir changed, make sure bForce is true!
  7596. if (bForce)
  7597. {
  7598. if (g_bThreadAlive)
  7599. CancelThread(3000); // flags it to exit; the param is the # of ms to wait before forcefully killing it
  7600. }
  7601. else
  7602. {
  7603. if (bBackground && (g_bThreadAlive || m_bPresetListReady))
  7604. return;
  7605. if (!bBackground && m_bPresetListReady)
  7606. return;
  7607. }
  7608. assert(!g_bThreadAlive);
  7609. // spawn new thread:
  7610. DWORD flags = (bForce ? 1 : 0) | (bTryReselectCurrentPreset ? 2 : 0);
  7611. g_bThreadShouldQuit = false;
  7612. g_bThreadAlive = true;
  7613. g_hThread = (HANDLE)_beginthreadex(NULL,0,__UpdatePresetList,(void*)flags,0,0);
  7614. if (!bBackground)
  7615. {
  7616. // crank up priority, wait for it to finish, and then return
  7617. SetThreadPriority(g_hThread,THREAD_PRIORITY_HIGHEST); //THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_HIGHEST,
  7618. // wait for it to finish
  7619. while (g_bThreadAlive)
  7620. Sleep(30);
  7621. assert(g_hThread != INVALID_HANDLE_VALUE);
  7622. CloseHandle(g_hThread);
  7623. g_hThread = INVALID_HANDLE_VALUE;
  7624. }
  7625. else
  7626. {
  7627. // it will just run in the background til it finishes.
  7628. // however, we want to wait until at least ~32 presets are found (or failure) before returning,
  7629. // so we know we have *something* in the preset list to start with.
  7630. SetThreadPriority(g_hThread,THREAD_PRIORITY_HIGHEST); //THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_HIGHEST,
  7631. // wait until either the thread exits, or # of presets is >32, before returning.
  7632. // also make sure you enter the CS whenever you check on it!
  7633. // (thread will update preset list every so often, with the newest presets scanned in...)
  7634. while (g_bThreadAlive)
  7635. {
  7636. Sleep(30);
  7637. EnterCriticalSection(&g_cs);
  7638. int nPresets = g_plugin.m_nPresets;
  7639. LeaveCriticalSection(&g_cs);
  7640. if (nPresets >= 30)
  7641. break;
  7642. }
  7643. if (g_bThreadAlive)
  7644. {
  7645. // the load still takes a while even at THREAD_PRIORITY_ABOVE_NORMAL,
  7646. // because it is waiting on the HDD so much...
  7647. // but the OS is smart, and the CPU stays nice and zippy in other threads =)
  7648. SetThreadPriority(g_hThread,THREAD_PRIORITY_ABOVE_NORMAL); //THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_HIGHEST,
  7649. }
  7650. }
  7651. return;
  7652. }
  7653. void CPlugin::MergeSortPresets(int left, int right)
  7654. {
  7655. // note: left..right range is inclusive
  7656. int nItems = right-left+1;
  7657. if (nItems > 2)
  7658. {
  7659. // recurse to sort 2 halves (but don't actually recurse on a half if it only has 1 element)
  7660. int mid = (left+right)/2;
  7661. /*if (mid != left) */ MergeSortPresets(left, mid);
  7662. /*if (mid+1 != right)*/ MergeSortPresets(mid+1, right);
  7663. // then merge results
  7664. int a = left;
  7665. int b = mid + 1;
  7666. while (a <= mid && b <= right)
  7667. {
  7668. bool bSwap;
  7669. // merge the sorted arrays; give preference to strings that start with a '*' character
  7670. int nSpecial = 0;
  7671. if (m_presets[a].szFilename.c_str()[0] == '*') nSpecial++;
  7672. if (m_presets[b].szFilename.c_str()[0] == '*') nSpecial++;
  7673. if (nSpecial == 1)
  7674. {
  7675. bSwap = (m_presets[b].szFilename.c_str()[0] == '*');
  7676. }
  7677. else
  7678. {
  7679. bSwap = (mystrcmpiW(m_presets[a].szFilename.c_str(), m_presets[b].szFilename.c_str()) > 0);
  7680. }
  7681. if (bSwap)
  7682. {
  7683. PresetInfo temp = m_presets[b];
  7684. for (int k=b; k>a; k--)
  7685. m_presets[k] = m_presets[k-1];
  7686. m_presets[a] = temp;
  7687. mid++;
  7688. b++;
  7689. }
  7690. a++;
  7691. }
  7692. }
  7693. else if (nItems == 2)
  7694. {
  7695. // sort 2 items; give preference to 'special' strings that start with a '*' character
  7696. int nSpecial = 0;
  7697. if (m_presets[left].szFilename.c_str()[0] == '*') nSpecial++;
  7698. if (m_presets[right].szFilename.c_str()[0] == '*') nSpecial++;
  7699. if (nSpecial == 1)
  7700. {
  7701. if (m_presets[right].szFilename.c_str()[0] == '*')
  7702. {
  7703. PresetInfo temp = m_presets[left];
  7704. m_presets[left] = m_presets[right];
  7705. m_presets[right] = temp;
  7706. }
  7707. }
  7708. else if (mystrcmpiW(m_presets[left].szFilename.c_str(), m_presets[right].szFilename.c_str()) > 0)
  7709. {
  7710. PresetInfo temp = m_presets[left];
  7711. m_presets[left] = m_presets[right];
  7712. m_presets[right] = temp;
  7713. }
  7714. }
  7715. }
  7716. void CPlugin::WaitString_NukeSelection()
  7717. {
  7718. if (m_waitstring.bActive &&
  7719. m_waitstring.nSelAnchorPos != -1)
  7720. {
  7721. // nuke selection. note: start & end are INCLUSIVE.
  7722. int start = (m_waitstring.nCursorPos < m_waitstring.nSelAnchorPos) ? m_waitstring.nCursorPos : m_waitstring.nSelAnchorPos;
  7723. int end = (m_waitstring.nCursorPos > m_waitstring.nSelAnchorPos) ? m_waitstring.nCursorPos - 1 : m_waitstring.nSelAnchorPos - 1;
  7724. int len = (m_waitstring.bDisplayAsCode ? lstrlenA((char*)m_waitstring.szText) : lstrlenW(m_waitstring.szText));
  7725. int how_far_to_shift = end - start + 1;
  7726. int num_chars_to_shift = len - end; // includes NULL char
  7727. if (m_waitstring.bDisplayAsCode)
  7728. {
  7729. char* ptr = (char*)m_waitstring.szText;
  7730. for (int i=0; i<num_chars_to_shift; i++)
  7731. *(ptr + start + i) = *(ptr + start + i + how_far_to_shift);
  7732. }
  7733. else
  7734. {
  7735. for (int i=0; i<num_chars_to_shift; i++)
  7736. m_waitstring.szText[start + i] = m_waitstring.szText[start + i + how_far_to_shift];
  7737. }
  7738. // clear selection
  7739. m_waitstring.nCursorPos = start;
  7740. m_waitstring.nSelAnchorPos = -1;
  7741. }
  7742. }
  7743. void CPlugin::WaitString_Cut()
  7744. {
  7745. if (m_waitstring.bActive &&
  7746. m_waitstring.nSelAnchorPos != -1)
  7747. {
  7748. WaitString_Copy();
  7749. WaitString_NukeSelection();
  7750. }
  7751. }
  7752. void CPlugin::WaitString_Copy()
  7753. {
  7754. if (m_waitstring.bActive &&
  7755. m_waitstring.nSelAnchorPos != -1)
  7756. {
  7757. // note: start & end are INCLUSIVE.
  7758. int start = (m_waitstring.nCursorPos < m_waitstring.nSelAnchorPos) ? m_waitstring.nCursorPos : m_waitstring.nSelAnchorPos;
  7759. int end = (m_waitstring.nCursorPos > m_waitstring.nSelAnchorPos) ? m_waitstring.nCursorPos - 1 : m_waitstring.nSelAnchorPos - 1;
  7760. int chars_to_copy = end - start + 1;
  7761. if (m_waitstring.bDisplayAsCode)
  7762. {
  7763. char* ptr = (char*)m_waitstring.szText;
  7764. for (int i=0; i<chars_to_copy; i++)
  7765. m_waitstring.szClipboard[i] = *(ptr + start + i);
  7766. m_waitstring.szClipboard[chars_to_copy] = 0;
  7767. char tmp[64000];
  7768. ConvertLFCToCRsA(m_waitstring.szClipboard, tmp);
  7769. copyStringToClipboardA(tmp);
  7770. }
  7771. else
  7772. {
  7773. for (int i=0; i<chars_to_copy; i++)
  7774. m_waitstring.szClipboardW[i] = m_waitstring.szText[start + i];
  7775. m_waitstring.szClipboardW[chars_to_copy] = 0;
  7776. wchar_t tmp[64000];
  7777. ConvertLFCToCRsW(m_waitstring.szClipboardW, tmp);
  7778. copyStringToClipboardW(tmp);
  7779. }
  7780. }
  7781. }
  7782. void CPlugin::WaitString_Paste()
  7783. {
  7784. // NOTE: if there is a selection, it is wiped out, and replaced with the clipboard contents.
  7785. if (m_waitstring.bActive)
  7786. {
  7787. WaitString_NukeSelection();
  7788. if (m_waitstring.bDisplayAsCode)
  7789. {
  7790. char tmp[64000];
  7791. lstrcpyA(tmp, getStringFromClipboardA());
  7792. ConvertCRsToLFCA(tmp, m_waitstring.szClipboard);
  7793. }
  7794. else
  7795. {
  7796. wchar_t tmp[64000];
  7797. lstrcpyW(tmp, getStringFromClipboardW());
  7798. ConvertCRsToLFCW(tmp, m_waitstring.szClipboardW);
  7799. }
  7800. int len;
  7801. int chars_to_insert;
  7802. if (m_waitstring.bDisplayAsCode)
  7803. {
  7804. len = lstrlenA((char*)m_waitstring.szText);
  7805. chars_to_insert = lstrlenA(m_waitstring.szClipboard);
  7806. }
  7807. else
  7808. {
  7809. len = lstrlenW(m_waitstring.szText);
  7810. chars_to_insert = lstrlenW(m_waitstring.szClipboardW);
  7811. }
  7812. if (len + chars_to_insert + 1 >= m_waitstring.nMaxLen)
  7813. {
  7814. chars_to_insert = m_waitstring.nMaxLen - len - 1;
  7815. // inform user
  7816. AddError(WASABI_API_LNGSTRINGW(IDS_STRING_TOO_LONG), 2.5f, ERR_MISC, true);
  7817. }
  7818. else
  7819. {
  7820. //m_fShowUserMessageUntilThisTime = GetTime(); // if there was an error message already, clear it
  7821. }
  7822. int i;
  7823. if (m_waitstring.bDisplayAsCode)
  7824. {
  7825. char* ptr = (char*)m_waitstring.szText;
  7826. for (i=len; i >= m_waitstring.nCursorPos; i--)
  7827. *(ptr + i + chars_to_insert) = *(ptr + i);
  7828. for (i=0; i < chars_to_insert; i++)
  7829. *(ptr + i + m_waitstring.nCursorPos) = m_waitstring.szClipboard[i];
  7830. }
  7831. else
  7832. {
  7833. for (i=len; i >= m_waitstring.nCursorPos; i--)
  7834. m_waitstring.szText[i + chars_to_insert] = m_waitstring.szText[i];
  7835. for (i=0; i < chars_to_insert; i++)
  7836. m_waitstring.szText[i + m_waitstring.nCursorPos] = m_waitstring.szClipboardW[i];
  7837. }
  7838. m_waitstring.nCursorPos += chars_to_insert;
  7839. }
  7840. }
  7841. void CPlugin::WaitString_SeekLeftWord()
  7842. {
  7843. // move to beginning of prior word
  7844. if (m_waitstring.bDisplayAsCode)
  7845. {
  7846. char* ptr = (char*)m_waitstring.szText;
  7847. while (m_waitstring.nCursorPos > 0 &&
  7848. !IsAlphanumericChar(*(ptr + m_waitstring.nCursorPos-1)))
  7849. m_waitstring.nCursorPos--;
  7850. while (m_waitstring.nCursorPos > 0 &&
  7851. IsAlphanumericChar(*(ptr + m_waitstring.nCursorPos-1)))
  7852. m_waitstring.nCursorPos--;
  7853. }
  7854. else
  7855. {
  7856. while (m_waitstring.nCursorPos > 0 &&
  7857. !IsAlphanumericChar(m_waitstring.szText[m_waitstring.nCursorPos-1]))
  7858. m_waitstring.nCursorPos--;
  7859. while (m_waitstring.nCursorPos > 0 &&
  7860. IsAlphanumericChar(m_waitstring.szText[m_waitstring.nCursorPos-1]))
  7861. m_waitstring.nCursorPos--;
  7862. }
  7863. }
  7864. void CPlugin::WaitString_SeekRightWord()
  7865. {
  7866. // move to beginning of next word
  7867. //testing lotsa stuff
  7868. if (m_waitstring.bDisplayAsCode)
  7869. {
  7870. int len = lstrlenA((char*)m_waitstring.szText);
  7871. char* ptr = (char*)m_waitstring.szText;
  7872. while (m_waitstring.nCursorPos < len &&
  7873. IsAlphanumericChar(*(ptr + m_waitstring.nCursorPos)))
  7874. m_waitstring.nCursorPos++;
  7875. while (m_waitstring.nCursorPos < len &&
  7876. !IsAlphanumericChar(*(ptr + m_waitstring.nCursorPos)))
  7877. m_waitstring.nCursorPos++;
  7878. }
  7879. else
  7880. {
  7881. int len = lstrlenW(m_waitstring.szText);
  7882. while (m_waitstring.nCursorPos < len &&
  7883. IsAlphanumericChar(m_waitstring.szText[m_waitstring.nCursorPos]))
  7884. m_waitstring.nCursorPos++;
  7885. while (m_waitstring.nCursorPos < len &&
  7886. !IsAlphanumericChar(m_waitstring.szText[m_waitstring.nCursorPos]))
  7887. m_waitstring.nCursorPos++;
  7888. }
  7889. }
  7890. int CPlugin::WaitString_GetCursorColumn()
  7891. {
  7892. if (m_waitstring.bDisplayAsCode)
  7893. {
  7894. int column = 0;
  7895. char* ptr = (char*)m_waitstring.szText;
  7896. while (m_waitstring.nCursorPos - column - 1 >= 0 &&
  7897. *(ptr + m_waitstring.nCursorPos - column - 1) != LINEFEED_CONTROL_CHAR)
  7898. column++;
  7899. return column;
  7900. }
  7901. else
  7902. {
  7903. return m_waitstring.nCursorPos;
  7904. }
  7905. }
  7906. int CPlugin::WaitString_GetLineLength()
  7907. {
  7908. int line_start = m_waitstring.nCursorPos - WaitString_GetCursorColumn();
  7909. int line_length = 0;
  7910. if (m_waitstring.bDisplayAsCode)
  7911. {
  7912. char* ptr = (char*)m_waitstring.szText;
  7913. while (*(ptr + line_start + line_length) != 0 &&
  7914. *(ptr + line_start + line_length) != LINEFEED_CONTROL_CHAR)
  7915. line_length++;
  7916. }
  7917. else
  7918. {
  7919. while (m_waitstring.szText[line_start + line_length] != 0 &&
  7920. m_waitstring.szText[line_start + line_length] != LINEFEED_CONTROL_CHAR)
  7921. line_length++;
  7922. }
  7923. return line_length;
  7924. }
  7925. void CPlugin::WaitString_SeekUpOneLine()
  7926. {
  7927. int column = g_plugin.WaitString_GetCursorColumn();
  7928. if (column != m_waitstring.nCursorPos)
  7929. {
  7930. // seek to very end of previous line (cursor will be at the semicolon)
  7931. m_waitstring.nCursorPos -= column + 1;
  7932. int new_column = g_plugin.WaitString_GetCursorColumn();
  7933. if (new_column > column)
  7934. m_waitstring.nCursorPos -= (new_column - column);
  7935. }
  7936. }
  7937. void CPlugin::WaitString_SeekDownOneLine()
  7938. {
  7939. int column = g_plugin.WaitString_GetCursorColumn();
  7940. int newpos = m_waitstring.nCursorPos;
  7941. char* ptr = (char*)m_waitstring.szText;
  7942. while (*(ptr + newpos) != 0 && *(ptr + newpos) != LINEFEED_CONTROL_CHAR)
  7943. newpos++;
  7944. if (*(ptr + newpos) != 0)
  7945. {
  7946. m_waitstring.nCursorPos = newpos + 1;
  7947. while ( column > 0 &&
  7948. *(ptr + m_waitstring.nCursorPos) != LINEFEED_CONTROL_CHAR &&
  7949. *(ptr + m_waitstring.nCursorPos) != 0)
  7950. {
  7951. m_waitstring.nCursorPos++;
  7952. column--;
  7953. }
  7954. }
  7955. }
  7956. void CPlugin::SavePresetAs(wchar_t *szNewFile)
  7957. {
  7958. // overwrites the file if it was already there,
  7959. // so you should check if the file exists first & prompt user to overwrite,
  7960. // before calling this function
  7961. if (!m_pState->Export(szNewFile))
  7962. {
  7963. // error
  7964. AddError(WASABI_API_LNGSTRINGW(IDS_ERROR_UNABLE_TO_SAVE_THE_FILE), 6.0f, ERR_PRESET, true);
  7965. }
  7966. else
  7967. {
  7968. // pop up confirmation
  7969. AddError(WASABI_API_LNGSTRINGW(IDS_SAVE_SUCCESSFUL), 3.0f, ERR_NOTIFY, false);
  7970. // update m_pState->m_szDesc with the new name
  7971. lstrcpyW(m_pState->m_szDesc, m_waitstring.szText);
  7972. // refresh file listing
  7973. UpdatePresetList(false,true);
  7974. }
  7975. }
  7976. void CPlugin::DeletePresetFile(wchar_t *szDelFile)
  7977. {
  7978. // NOTE: this function additionally assumes that m_nPresetListCurPos indicates
  7979. // the slot that the to-be-deleted preset occupies!
  7980. // delete file
  7981. if (!DeleteFileW(szDelFile))
  7982. {
  7983. // error
  7984. AddError(WASABI_API_LNGSTRINGW(IDS_ERROR_UNABLE_TO_DELETE_THE_FILE), 6.0f, ERR_MISC, true);
  7985. }
  7986. else
  7987. {
  7988. // pop up confirmation
  7989. wchar_t buf[1024];
  7990. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_PRESET_X_DELETED), m_presets[m_nPresetListCurPos].szFilename.c_str());
  7991. AddError(buf, 3.0f, ERR_NOTIFY, false);
  7992. // refresh file listing & re-select the next file after the one deleted
  7993. int newPos = m_nPresetListCurPos;
  7994. UpdatePresetList(false,true);
  7995. m_nPresetListCurPos = max(0, min(m_nPresets-1, newPos));
  7996. }
  7997. }
  7998. void CPlugin::RenamePresetFile(wchar_t *szOldFile, wchar_t *szNewFile)
  7999. {
  8000. // NOTE: this function additionally assumes that m_nPresetListCurPos indicates
  8001. // the slot that the to-be-renamed preset occupies!
  8002. if (GetFileAttributesW(szNewFile) != -1) // check if file already exists
  8003. {
  8004. // error
  8005. AddError(WASABI_API_LNGSTRINGW(IDS_ERROR_A_FILE_ALREADY_EXISTS_WITH_THAT_FILENAME), 6.0f, ERR_PRESET, true);
  8006. // (user remains in UI_LOAD_RENAME mode to try another filename)
  8007. }
  8008. else
  8009. {
  8010. // rename
  8011. if (!MoveFileW(szOldFile, szNewFile))
  8012. {
  8013. // error
  8014. AddError(WASABI_API_LNGSTRINGW(IDS_ERROR_UNABLE_TO_RENAME_FILE), 6.0f, ERR_MISC, true);
  8015. }
  8016. else
  8017. {
  8018. // pop up confirmation
  8019. AddError(WASABI_API_LNGSTRINGW(IDS_RENAME_SUCCESSFUL), 3.0f, ERR_NOTIFY, false);
  8020. // if this preset was the active one, update m_pState->m_szDesc with the new name
  8021. wchar_t buf[512];
  8022. swprintf(buf, L"%s.milk", m_pState->m_szDesc);
  8023. if (wcscmp(m_presets[m_nPresetListCurPos].szFilename.c_str(), buf) == 0)
  8024. {
  8025. lstrcpyW(m_pState->m_szDesc, m_waitstring.szText);
  8026. }
  8027. // refresh file listing & do a trick to make it re-select the renamed file
  8028. wchar_t buf2[512];
  8029. lstrcpyW(buf2, m_waitstring.szText);
  8030. lstrcatW(buf2, L".milk");
  8031. m_presets[m_nPresetListCurPos].szFilename = buf2;
  8032. UpdatePresetList(false,true,false);
  8033. // jump to (highlight) the new file:
  8034. m_nPresetListCurPos = 0;
  8035. wchar_t* p = wcsrchr(szNewFile, L'\\');
  8036. if (p)
  8037. {
  8038. p++;
  8039. for (int i=m_nDirs; i<m_nPresets; i++)
  8040. {
  8041. if (wcscmp(p, m_presets[i].szFilename.c_str())==0) {
  8042. m_nPresetListCurPos = i;
  8043. break;
  8044. }
  8045. }
  8046. }
  8047. }
  8048. // exit waitstring mode (return to load menu)
  8049. m_UI_mode = UI_LOAD;
  8050. m_waitstring.bActive = false;
  8051. }
  8052. }
  8053. /*
  8054. void CPlugin::UpdatePresetRatings()
  8055. {
  8056. if (!m_bEnableRating)
  8057. return;
  8058. if (m_nRatingReadProgress==-1 || m_nRatingReadProgress==m_nPresets)
  8059. return;
  8060. int k;
  8061. if (m_nRatingReadProgress==0 && m_nDirs>0)
  8062. {
  8063. for (k=0; k<m_nDirs; k++)
  8064. {
  8065. m_presets[m_nRatingReadProgress].fRatingCum = 0.0f;
  8066. m_nRatingReadProgress++;
  8067. }
  8068. if (!m_bInstaScan)
  8069. return;
  8070. }
  8071. int presets_per_frame = m_bInstaScan ? 4096 : 1;
  8072. int k1 = m_nRatingReadProgress;
  8073. int k2 = min(m_nRatingReadProgress + presets_per_frame, m_nPresets);
  8074. for (k=k1; k<k2; k++)
  8075. {
  8076. char szFullPath[512];
  8077. sprintf(szFullPath, "%s%s", m_szPresetDir, m_presets[k].szFilename.c_str());
  8078. float f = GetPrivateProfileFloat("preset00", "fRating", 3.0f, szFullPath);
  8079. if (f < 0) f = 0;
  8080. if (f > 5) f = 5;
  8081. if (k==0)
  8082. m_presets[k].fRatingCum = f;
  8083. else
  8084. m_presets[k].fRatingCum = m_presets[k-1].fRatingCum + f;
  8085. m_nRatingReadProgress++;
  8086. }
  8087. }
  8088. */
  8089. void CPlugin::SetCurrentPresetRating(float fNewRating)
  8090. {
  8091. if (!m_bEnableRating)
  8092. return;
  8093. if (fNewRating < 0) fNewRating = 0;
  8094. if (fNewRating > 5) fNewRating = 5;
  8095. float change = (fNewRating - m_pState->m_fRating);
  8096. // update the file on disk:
  8097. //char szPresetFileNoPath[512];
  8098. //char szPresetFileWithPath[512];
  8099. //sprintf(szPresetFileNoPath, "%s.milk", m_pState->m_szDesc);
  8100. //sprintf(szPresetFileWithPath, "%s%s.milk", GetPresetDir(), m_pState->m_szDesc);
  8101. WritePrivateProfileFloatW(fNewRating, L"fRating", m_szCurrentPresetFile, L"preset00");
  8102. // update the copy of the preset in memory
  8103. m_pState->m_fRating = fNewRating;
  8104. // update the cumulative internal listing:
  8105. m_presets[m_nCurrentPreset].fRatingThis += change;
  8106. if (m_nCurrentPreset != -1)// && m_nRatingReadProgress >= m_nCurrentPreset) // (can be -1 if dir. changed but no new preset was loaded yet)
  8107. for (int i=m_nCurrentPreset; i<m_nPresets; i++)
  8108. m_presets[i].fRatingCum += change;
  8109. /* keep in view:
  8110. -test switching dirs w/o loading a preset, and trying to change the rating
  8111. ->m_nCurrentPreset is out of range!
  8112. -soln: when adjusting rating:
  8113. 1. file to modify is m_szCurrentPresetFile
  8114. 2. only update CDF if m_nCurrentPreset is not -1
  8115. -> set m_nCurrentPreset to -1 whenever dir. changes
  8116. -> set m_szCurrentPresetFile whenever you load a preset
  8117. */
  8118. // show a message
  8119. if (!m_bShowRating)
  8120. {
  8121. // see also: DrawText() in milkdropfs.cpp
  8122. m_fShowRatingUntilThisTime = GetTime() + 2.0f;
  8123. }
  8124. }
  8125. void CPlugin::ReadCustomMessages()
  8126. {
  8127. int n;
  8128. // First, clear all old data
  8129. for (n=0; n<MAX_CUSTOM_MESSAGE_FONTS; n++)
  8130. {
  8131. wcscpy(m_CustomMessageFont[n].szFace, L"arial");
  8132. m_CustomMessageFont[n].bBold = false;
  8133. m_CustomMessageFont[n].bItal = false;
  8134. m_CustomMessageFont[n].nColorR = 255;
  8135. m_CustomMessageFont[n].nColorG = 255;
  8136. m_CustomMessageFont[n].nColorB = 255;
  8137. }
  8138. for (n=0; n<MAX_CUSTOM_MESSAGES; n++)
  8139. {
  8140. m_CustomMessage[n].szText[0] = 0;
  8141. m_CustomMessage[n].nFont = 0;
  8142. m_CustomMessage[n].fSize = 50.0f; // [0..100] note that size is not absolute, but relative to the size of the window
  8143. m_CustomMessage[n].x = 0.5f;
  8144. m_CustomMessage[n].y = 0.5f;
  8145. m_CustomMessage[n].randx = 0;
  8146. m_CustomMessage[n].randy = 0;
  8147. m_CustomMessage[n].growth = 1.0f;
  8148. m_CustomMessage[n].fTime = 1.5f;
  8149. m_CustomMessage[n].fFade = 0.2f;
  8150. m_CustomMessage[n].bOverrideBold = false;
  8151. m_CustomMessage[n].bOverrideItal = false;
  8152. m_CustomMessage[n].bOverrideFace = false;
  8153. m_CustomMessage[n].bOverrideColorR = false;
  8154. m_CustomMessage[n].bOverrideColorG = false;
  8155. m_CustomMessage[n].bOverrideColorB = false;
  8156. m_CustomMessage[n].bBold = false;
  8157. m_CustomMessage[n].bItal = false;
  8158. wcscpy(m_CustomMessage[n].szFace, L"arial");
  8159. m_CustomMessage[n].nColorR = 255;
  8160. m_CustomMessage[n].nColorG = 255;
  8161. m_CustomMessage[n].nColorB = 255;
  8162. m_CustomMessage[n].nRandR = 0;
  8163. m_CustomMessage[n].nRandG = 0;
  8164. m_CustomMessage[n].nRandB = 0;
  8165. }
  8166. // Then read in the new file
  8167. for (n=0; n<MAX_CUSTOM_MESSAGE_FONTS; n++)
  8168. {
  8169. wchar_t szSectionName[32];
  8170. swprintf(szSectionName, L"font%02d", n);
  8171. // get face, bold, italic, x, y for this custom message FONT
  8172. GetPrivateProfileStringW(szSectionName,L"face",L"arial",m_CustomMessageFont[n].szFace,sizeof(m_CustomMessageFont[n].szFace), m_szMsgIniFile);
  8173. m_CustomMessageFont[n].bBold = GetPrivateProfileBoolW(szSectionName,L"bold",m_CustomMessageFont[n].bBold, m_szMsgIniFile);
  8174. m_CustomMessageFont[n].bItal = GetPrivateProfileBoolW(szSectionName,L"ital",m_CustomMessageFont[n].bItal, m_szMsgIniFile);
  8175. m_CustomMessageFont[n].nColorR = GetPrivateProfileIntW (szSectionName,L"r" ,m_CustomMessageFont[n].nColorR, m_szMsgIniFile);
  8176. m_CustomMessageFont[n].nColorG = GetPrivateProfileIntW (szSectionName,L"g" ,m_CustomMessageFont[n].nColorG, m_szMsgIniFile);
  8177. m_CustomMessageFont[n].nColorB = GetPrivateProfileIntW (szSectionName,L"b" ,m_CustomMessageFont[n].nColorB, m_szMsgIniFile);
  8178. }
  8179. for (n=0; n<MAX_CUSTOM_MESSAGES; n++)
  8180. {
  8181. wchar_t szSectionName[64];
  8182. swprintf(szSectionName, L"message%02d", n);
  8183. // get fontID, size, text, etc. for this custom message:
  8184. GetPrivateProfileStringW(szSectionName,L"text",L"",m_CustomMessage[n].szText,sizeof(m_CustomMessage[n].szText), m_szMsgIniFile);
  8185. if (m_CustomMessage[n].szText[0])
  8186. {
  8187. m_CustomMessage[n].nFont = GetPrivateProfileIntW (szSectionName,L"font" ,m_CustomMessage[n].nFont, m_szMsgIniFile);
  8188. m_CustomMessage[n].fSize = GetPrivateProfileFloatW(szSectionName,L"size" ,m_CustomMessage[n].fSize, m_szMsgIniFile);
  8189. m_CustomMessage[n].x = GetPrivateProfileFloatW(szSectionName,L"x" ,m_CustomMessage[n].x, m_szMsgIniFile);
  8190. m_CustomMessage[n].y = GetPrivateProfileFloatW(szSectionName,L"y" ,m_CustomMessage[n].y, m_szMsgIniFile);
  8191. m_CustomMessage[n].randx = GetPrivateProfileFloatW(szSectionName,L"randx" ,m_CustomMessage[n].randx, m_szMsgIniFile);
  8192. m_CustomMessage[n].randy = GetPrivateProfileFloatW(szSectionName,L"randy" ,m_CustomMessage[n].randy, m_szMsgIniFile);
  8193. m_CustomMessage[n].growth = GetPrivateProfileFloatW(szSectionName,L"growth",m_CustomMessage[n].growth, m_szMsgIniFile);
  8194. m_CustomMessage[n].fTime = GetPrivateProfileFloatW(szSectionName,L"time" ,m_CustomMessage[n].fTime, m_szMsgIniFile);
  8195. m_CustomMessage[n].fFade = GetPrivateProfileFloatW(szSectionName,L"fade" ,m_CustomMessage[n].fFade, m_szMsgIniFile);
  8196. m_CustomMessage[n].nColorR = GetPrivateProfileIntW (szSectionName,L"r" ,m_CustomMessage[n].nColorR, m_szMsgIniFile);
  8197. m_CustomMessage[n].nColorG = GetPrivateProfileIntW (szSectionName,L"g" ,m_CustomMessage[n].nColorG, m_szMsgIniFile);
  8198. m_CustomMessage[n].nColorB = GetPrivateProfileIntW (szSectionName,L"b" ,m_CustomMessage[n].nColorB, m_szMsgIniFile);
  8199. m_CustomMessage[n].nRandR = GetPrivateProfileIntW (szSectionName,L"randr" ,m_CustomMessage[n].nRandR, m_szMsgIniFile);
  8200. m_CustomMessage[n].nRandG = GetPrivateProfileIntW (szSectionName,L"randg" ,m_CustomMessage[n].nRandG, m_szMsgIniFile);
  8201. m_CustomMessage[n].nRandB = GetPrivateProfileIntW (szSectionName,L"randb" ,m_CustomMessage[n].nRandB, m_szMsgIniFile);
  8202. // overrides: r,g,b,face,bold,ital
  8203. GetPrivateProfileStringW(szSectionName,L"face",L"",m_CustomMessage[n].szFace,sizeof(m_CustomMessage[n].szFace), m_szMsgIniFile);
  8204. m_CustomMessage[n].bBold = GetPrivateProfileIntW (szSectionName, L"bold", -1, m_szMsgIniFile);
  8205. m_CustomMessage[n].bItal = GetPrivateProfileIntW (szSectionName, L"ital", -1, m_szMsgIniFile);
  8206. m_CustomMessage[n].nColorR = GetPrivateProfileIntW (szSectionName, L"r" , -1, m_szMsgIniFile);
  8207. m_CustomMessage[n].nColorG = GetPrivateProfileIntW (szSectionName, L"g" , -1, m_szMsgIniFile);
  8208. m_CustomMessage[n].nColorB = GetPrivateProfileIntW (szSectionName, L"b" , -1, m_szMsgIniFile);
  8209. m_CustomMessage[n].bOverrideFace = (m_CustomMessage[n].szFace[0] != 0);
  8210. m_CustomMessage[n].bOverrideBold = (m_CustomMessage[n].bBold != -1);
  8211. m_CustomMessage[n].bOverrideItal = (m_CustomMessage[n].bItal != -1);
  8212. m_CustomMessage[n].bOverrideColorR = (m_CustomMessage[n].nColorR != -1);
  8213. m_CustomMessage[n].bOverrideColorG = (m_CustomMessage[n].nColorG != -1);
  8214. m_CustomMessage[n].bOverrideColorB = (m_CustomMessage[n].nColorB != -1);
  8215. }
  8216. }
  8217. }
  8218. void CPlugin::LaunchCustomMessage(int nMsgNum)
  8219. {
  8220. if (nMsgNum > 99)
  8221. nMsgNum = 99;
  8222. if (nMsgNum < 0)
  8223. {
  8224. int count=0;
  8225. // choose randomly
  8226. for (nMsgNum=0; nMsgNum<100; nMsgNum++)
  8227. if (m_CustomMessage[nMsgNum].szText[0])
  8228. count++;
  8229. int sel = (warand()%count)+1;
  8230. count = 0;
  8231. for (nMsgNum=0; nMsgNum<100; nMsgNum++)
  8232. {
  8233. if (m_CustomMessage[nMsgNum].szText[0])
  8234. count++;
  8235. if (count==sel)
  8236. break;
  8237. }
  8238. }
  8239. if (nMsgNum < 0 ||
  8240. nMsgNum >= MAX_CUSTOM_MESSAGES ||
  8241. m_CustomMessage[nMsgNum].szText[0]==0)
  8242. {
  8243. return;
  8244. }
  8245. int fontID = m_CustomMessage[nMsgNum].nFont;
  8246. m_supertext.bRedrawSuperText = true;
  8247. m_supertext.bIsSongTitle = false;
  8248. lstrcpyW(m_supertext.szTextW, m_CustomMessage[nMsgNum].szText);
  8249. // regular properties:
  8250. m_supertext.fFontSize = m_CustomMessage[nMsgNum].fSize;
  8251. m_supertext.fX = m_CustomMessage[nMsgNum].x + m_CustomMessage[nMsgNum].randx * ((warand()%1037)/1037.0f*2.0f - 1.0f);
  8252. m_supertext.fY = m_CustomMessage[nMsgNum].y + m_CustomMessage[nMsgNum].randy * ((warand()%1037)/1037.0f*2.0f - 1.0f);
  8253. m_supertext.fGrowth = m_CustomMessage[nMsgNum].growth;
  8254. m_supertext.fDuration = m_CustomMessage[nMsgNum].fTime;
  8255. m_supertext.fFadeTime = m_CustomMessage[nMsgNum].fFade;
  8256. // overrideables:
  8257. if (m_CustomMessage[nMsgNum].bOverrideFace)
  8258. lstrcpyW(m_supertext.nFontFace, m_CustomMessage[nMsgNum].szFace);
  8259. else
  8260. lstrcpyW(m_supertext.nFontFace, m_CustomMessageFont[fontID].szFace);
  8261. m_supertext.bItal = (m_CustomMessage[nMsgNum].bOverrideItal) ? (m_CustomMessage[nMsgNum].bItal != 0) : (m_CustomMessageFont[fontID].bItal != 0);
  8262. m_supertext.bBold = (m_CustomMessage[nMsgNum].bOverrideBold) ? (m_CustomMessage[nMsgNum].bBold != 0) : (m_CustomMessageFont[fontID].bBold != 0);
  8263. m_supertext.nColorR = (m_CustomMessage[nMsgNum].bOverrideColorR) ? m_CustomMessage[nMsgNum].nColorR : m_CustomMessageFont[fontID].nColorR;
  8264. m_supertext.nColorG = (m_CustomMessage[nMsgNum].bOverrideColorG) ? m_CustomMessage[nMsgNum].nColorG : m_CustomMessageFont[fontID].nColorG;
  8265. m_supertext.nColorB = (m_CustomMessage[nMsgNum].bOverrideColorB) ? m_CustomMessage[nMsgNum].nColorB : m_CustomMessageFont[fontID].nColorB;
  8266. // randomize color
  8267. m_supertext.nColorR += (int)(m_CustomMessage[nMsgNum].nRandR * ((warand()%1037)/1037.0f*2.0f - 1.0f));
  8268. m_supertext.nColorG += (int)(m_CustomMessage[nMsgNum].nRandG * ((warand()%1037)/1037.0f*2.0f - 1.0f));
  8269. m_supertext.nColorB += (int)(m_CustomMessage[nMsgNum].nRandB * ((warand()%1037)/1037.0f*2.0f - 1.0f));
  8270. if (m_supertext.nColorR < 0) m_supertext.nColorR = 0;
  8271. if (m_supertext.nColorG < 0) m_supertext.nColorG = 0;
  8272. if (m_supertext.nColorB < 0) m_supertext.nColorB = 0;
  8273. if (m_supertext.nColorR > 255) m_supertext.nColorR = 255;
  8274. if (m_supertext.nColorG > 255) m_supertext.nColorG = 255;
  8275. if (m_supertext.nColorB > 255) m_supertext.nColorB = 255;
  8276. // fix &'s for display:
  8277. /*
  8278. {
  8279. int pos = 0;
  8280. int len = lstrlen(m_supertext.szText);
  8281. while (m_supertext.szText[pos] && pos<255)
  8282. {
  8283. if (m_supertext.szText[pos] == '&')
  8284. {
  8285. for (int x=len; x>=pos; x--)
  8286. m_supertext.szText[x+1] = m_supertext.szText[x];
  8287. len++;
  8288. pos++;
  8289. }
  8290. pos++;
  8291. }
  8292. }*/
  8293. m_supertext.fStartTime = GetTime();
  8294. }
  8295. void CPlugin::LaunchSongTitleAnim()
  8296. {
  8297. m_supertext.bRedrawSuperText = true;
  8298. m_supertext.bIsSongTitle = true;
  8299. lstrcpyW(m_supertext.szTextW, m_szSongTitle);
  8300. //lstrcpy(m_supertext.szText, " ");
  8301. lstrcpyW(m_supertext.nFontFace, m_fontinfo[SONGTITLE_FONT].szFace);
  8302. m_supertext.fFontSize = (float)m_fontinfo[SONGTITLE_FONT].nSize;
  8303. m_supertext.bBold = m_fontinfo[SONGTITLE_FONT].bBold;
  8304. m_supertext.bItal = m_fontinfo[SONGTITLE_FONT].bItalic;
  8305. m_supertext.fX = 0.5f;
  8306. m_supertext.fY = 0.5f;
  8307. m_supertext.fGrowth = 1.0f;
  8308. m_supertext.fDuration = m_fSongTitleAnimDuration;
  8309. m_supertext.nColorR = 255;
  8310. m_supertext.nColorG = 255;
  8311. m_supertext.nColorB = 255;
  8312. m_supertext.fStartTime = GetTime();
  8313. }
  8314. bool CPlugin::LaunchSprite(int nSpriteNum, int nSlot)
  8315. {
  8316. char initcode[8192], code[8192], sectionA[64];
  8317. char szTemp[8192];
  8318. wchar_t img[512], section[64];
  8319. initcode[0] = 0;
  8320. code[0] = 0;
  8321. img[0] = 0;
  8322. swprintf(section, L"img%02d", nSpriteNum);
  8323. sprintf(sectionA, "img%02d", nSpriteNum);
  8324. // 1. read in image filename
  8325. GetPrivateProfileStringW(section, L"img", L"", img, sizeof(img)-1, m_szImgIniFile);
  8326. if (img[0] == 0)
  8327. {
  8328. wchar_t buf[1024];
  8329. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SPRITE_X_ERROR_COULD_NOT_FIND_IMG_OR_NOT_DEFINED), nSpriteNum);
  8330. AddError(buf, 7.0f, ERR_MISC, false);
  8331. return false;
  8332. }
  8333. if (img[1] != L':')// || img[2] != '\\')
  8334. {
  8335. // it's not in the form "x:\blah\billy.jpg" so prepend plugin dir path.
  8336. wchar_t temp[512];
  8337. wcscpy(temp, img);
  8338. swprintf(img, L"%s%s", m_szMilkdrop2Path, temp);
  8339. }
  8340. // 2. get color key
  8341. //unsigned int ck_lo = (unsigned int)GetPrivateProfileInt(section, "colorkey_lo", 0x00000000, m_szImgIniFile);
  8342. //unsigned int ck_hi = (unsigned int)GetPrivateProfileInt(section, "colorkey_hi", 0x00202020, m_szImgIniFile);
  8343. // FIRST try 'colorkey_lo' (for backwards compatibility) and then try 'colorkey'
  8344. unsigned int ck = (unsigned int)GetPrivateProfileIntW(section, L"colorkey_lo", 0x00000000, m_szImgIniFile/*GetConfigIniFile()*/);
  8345. ck = (unsigned int)GetPrivateProfileIntW(section, L"colorkey", ck, m_szImgIniFile/*GetConfigIniFile()*/);
  8346. // 3. read in init code & per-frame code
  8347. for (int n=0; n<2; n++)
  8348. {
  8349. char *pStr = (n==0) ? initcode : code;
  8350. char szLineName[32];
  8351. int len;
  8352. int line = 1;
  8353. int char_pos = 0;
  8354. bool bDone = false;
  8355. while (!bDone)
  8356. {
  8357. if (n==0)
  8358. sprintf(szLineName, "init_%d", line);
  8359. else
  8360. sprintf(szLineName, "code_%d", line);
  8361. GetPrivateProfileString(sectionA, szLineName, "~!@#$", szTemp, 8192, AutoCharFn(m_szImgIniFile)); // fixme
  8362. len = lstrlen(szTemp);
  8363. if ((strcmp(szTemp, "~!@#$")==0) || // if the key was missing,
  8364. (len >= 8191-char_pos-1)) // or if we're out of space
  8365. {
  8366. bDone = true;
  8367. }
  8368. else
  8369. {
  8370. sprintf(&pStr[char_pos], "%s%c", szTemp, LINEFEED_CONTROL_CHAR);
  8371. }
  8372. char_pos += len + 1;
  8373. line++;
  8374. }
  8375. pStr[char_pos++] = 0; // null-terminate
  8376. }
  8377. if (nSlot == -1)
  8378. {
  8379. // find first empty slot; if none, chuck the oldest sprite & take its slot.
  8380. int oldest_index = 0;
  8381. int oldest_frame = m_texmgr.m_tex[0].nStartFrame;
  8382. for (int x=0; x<NUM_TEX; x++)
  8383. {
  8384. if (!m_texmgr.m_tex[x].pSurface)
  8385. {
  8386. nSlot = x;
  8387. break;
  8388. }
  8389. else if (m_texmgr.m_tex[x].nStartFrame < oldest_frame)
  8390. {
  8391. oldest_index = x;
  8392. oldest_frame = m_texmgr.m_tex[x].nStartFrame;
  8393. }
  8394. }
  8395. if (nSlot == -1)
  8396. {
  8397. nSlot = oldest_index;
  8398. m_texmgr.KillTex(nSlot);
  8399. }
  8400. }
  8401. int ret = m_texmgr.LoadTex(img, nSlot, initcode, code, GetTime(), GetFrame(), ck);
  8402. m_texmgr.m_tex[nSlot].nUserData = nSpriteNum;
  8403. wchar_t buf[1024];
  8404. switch(ret & TEXMGR_ERROR_MASK)
  8405. {
  8406. case TEXMGR_ERR_SUCCESS:
  8407. switch(ret & TEXMGR_WARNING_MASK)
  8408. {
  8409. case TEXMGR_WARN_ERROR_IN_INIT_CODE:
  8410. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SPRITE_X_WARNING_ERROR_IN_INIT_CODE), nSpriteNum);
  8411. AddError(buf, 6.0f, ERR_MISC, true);
  8412. break;
  8413. case TEXMGR_WARN_ERROR_IN_REG_CODE:
  8414. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SPRITE_X_WARNING_ERROR_IN_PER_FRAME_CODE), nSpriteNum);
  8415. AddError(buf, 6.0f, ERR_MISC, true);
  8416. break;
  8417. default:
  8418. // success; no errors OR warnings.
  8419. break;
  8420. }
  8421. break;
  8422. case TEXMGR_ERR_BAD_INDEX:
  8423. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SPRITE_X_ERROR_BAD_SLOT_INDEX), nSpriteNum);
  8424. AddError(buf, 6.0f, ERR_MISC, true);
  8425. break;
  8426. /*
  8427. case TEXMGR_ERR_OPENING: sprintf(m_szUserMessage, "sprite #%d error: unable to open imagefile", nSpriteNum); break;
  8428. case TEXMGR_ERR_FORMAT: sprintf(m_szUserMessage, "sprite #%d error: file is corrupt or non-jpeg image", nSpriteNum); break;
  8429. case TEXMGR_ERR_IMAGE_NOT_24_BIT: sprintf(m_szUserMessage, "sprite #%d error: image does not have 3 color channels", nSpriteNum); break;
  8430. case TEXMGR_ERR_IMAGE_TOO_LARGE: sprintf(m_szUserMessage, "sprite #%d error: image is too large", nSpriteNum); break;
  8431. case TEXMGR_ERR_CREATESURFACE_FAILED: sprintf(m_szUserMessage, "sprite #%d error: createsurface() failed", nSpriteNum); break;
  8432. case TEXMGR_ERR_LOCKSURFACE_FAILED: sprintf(m_szUserMessage, "sprite #%d error: lock() failed", nSpriteNum); break;
  8433. case TEXMGR_ERR_CORRUPT_JPEG: sprintf(m_szUserMessage, "sprite #%d error: jpeg is corrupt", nSpriteNum); break;
  8434. */
  8435. case TEXMGR_ERR_BADFILE:
  8436. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SPRITE_X_ERROR_IMAGE_FILE_MISSING_OR_CORRUPT), nSpriteNum);
  8437. AddError(buf, 6.0f, ERR_MISC, true);
  8438. break;
  8439. case TEXMGR_ERR_OUTOFMEM:
  8440. swprintf(buf, WASABI_API_LNGSTRINGW(IDS_SPRITE_X_ERROR_OUT_OF_MEM), nSpriteNum);
  8441. AddError(buf, 6.0f, ERR_MISC, true);
  8442. break;
  8443. }
  8444. return (ret & TEXMGR_ERROR_MASK) ? false : true;
  8445. }
  8446. void CPlugin::KillSprite(int iSlot)
  8447. {
  8448. m_texmgr.KillTex(iSlot);
  8449. }
  8450. void CPlugin::DoCustomSoundAnalysis()
  8451. {
  8452. memcpy(mysound.fWave[0], m_sound.fWaveform[0], sizeof(float)*576);
  8453. memcpy(mysound.fWave[1], m_sound.fWaveform[1], sizeof(float)*576);
  8454. // do our own [UN-NORMALIZED] fft
  8455. float fWaveLeft[576];
  8456. int i = 0;
  8457. for (i=0; i<576; i++)
  8458. fWaveLeft[i] = m_sound.fWaveform[0][i];
  8459. memset(mysound.fSpecLeft, 0, sizeof(float)*MY_FFT_SAMPLES);
  8460. myfft.time_to_frequency_domain(fWaveLeft, mysound.fSpecLeft);
  8461. //for (i=0; i<MY_FFT_SAMPLES; i++) fSpecLeft[i] = sqrtf(fSpecLeft[i]*fSpecLeft[i] + fSpecTemp[i]*fSpecTemp[i]);
  8462. // sum spectrum up into 3 bands
  8463. for (i=0; i<3; i++)
  8464. {
  8465. // note: only look at bottom half of spectrum! (hence divide by 6 instead of 3)
  8466. int start = MY_FFT_SAMPLES*i/6;
  8467. int end = MY_FFT_SAMPLES*(i+1)/6;
  8468. int j;
  8469. mysound.imm[i] = 0;
  8470. for (j=start; j<end; j++)
  8471. mysound.imm[i] += mysound.fSpecLeft[j];
  8472. }
  8473. // do temporal blending to create attenuated and super-attenuated versions
  8474. for (i=0; i<3; i++)
  8475. {
  8476. float rate;
  8477. if (mysound.imm[i] > mysound.avg[i])
  8478. rate = 0.2f;
  8479. else
  8480. rate = 0.5f;
  8481. rate = AdjustRateToFPS(rate, 30.0f, GetFps());
  8482. mysound.avg[i] = mysound.avg[i]*rate + mysound.imm[i]*(1-rate);
  8483. if (GetFrame() < 50)
  8484. rate = 0.9f;
  8485. else
  8486. rate = 0.992f;
  8487. rate = AdjustRateToFPS(rate, 30.0f, GetFps());
  8488. mysound.long_avg[i] = mysound.long_avg[i]*rate + mysound.imm[i]*(1-rate);
  8489. // also get bass/mid/treble levels *relative to the past*
  8490. if (fabsf(mysound.long_avg[i]) < 0.001f)
  8491. mysound.imm_rel[i] = 1.0f;
  8492. else
  8493. mysound.imm_rel[i] = mysound.imm[i] / mysound.long_avg[i];
  8494. if (fabsf(mysound.long_avg[i]) < 0.001f)
  8495. mysound.avg_rel[i] = 1.0f;
  8496. else
  8497. mysound.avg_rel[i] = mysound.avg[i] / mysound.long_avg[i];
  8498. }
  8499. }
  8500. void CPlugin::GenWarpPShaderText(char *szShaderText, float decay, bool bWrap)
  8501. {
  8502. // find the pixel shader body and replace it with custom code.
  8503. lstrcpy(szShaderText, m_szDefaultWarpPShaderText);
  8504. char LF = LINEFEED_CONTROL_CHAR;
  8505. char *p = strrchr( szShaderText, '{' );
  8506. if (!p)
  8507. return;
  8508. p++;
  8509. p += sprintf(p, "%c", 1);
  8510. p += sprintf(p, " // sample previous frame%c", LF);
  8511. p += sprintf(p, " ret = tex2D( sampler%s_main, uv ).xyz;%c", bWrap ? L"" : L"_fc", LF);
  8512. p += sprintf(p, " %c", LF);
  8513. p += sprintf(p, " // darken (decay) over time%c", LF);
  8514. p += sprintf(p, " ret *= %.2f; //or try: ret -= 0.004;%c", decay, LF);
  8515. //p += sprintf(p, " %c", LF);
  8516. //p += sprintf(p, " ret.w = vDiffuse.w; // pass alpha along - req'd for preset blending%c", LF);
  8517. p += sprintf(p, "}%c", LF);
  8518. }
  8519. void CPlugin::GenCompPShaderText(char *szShaderText, float brightness, float ve_alpha, float ve_zoom, int ve_orient, float hue_shader, bool bBrighten, bool bDarken, bool bSolarize, bool bInvert)
  8520. {
  8521. // find the pixel shader body and replace it with custom code.
  8522. lstrcpy(szShaderText, m_szDefaultCompPShaderText);
  8523. char LF = LINEFEED_CONTROL_CHAR;
  8524. char *p = strrchr( szShaderText, '{' );
  8525. if (!p)
  8526. return;
  8527. p++;
  8528. p += sprintf(p, "%c", 1);
  8529. if (ve_alpha > 0.001f)
  8530. {
  8531. int orient_x = (ve_orient % 2) ? -1 : 1;
  8532. int orient_y = (ve_orient >= 2) ? -1 : 1;
  8533. p += sprintf(p, " float2 uv_echo = (uv - 0.5)*%.3f*float2(%d,%d) + 0.5;%c", 1.0f/ve_zoom, orient_x, orient_y, LF);
  8534. p += sprintf(p, " ret = lerp( tex2D(sampler_main, uv).xyz, %c", LF);
  8535. p += sprintf(p, " tex2D(sampler_main, uv_echo).xyz, %c", LF);
  8536. p += sprintf(p, " %.2f %c", ve_alpha, LF);
  8537. p += sprintf(p, " ); //video echo%c", LF);
  8538. p += sprintf(p, " ret *= %.2f; //gamma%c", brightness, LF);
  8539. }
  8540. else
  8541. {
  8542. p += sprintf(p, " ret = tex2D(sampler_main, uv).xyz;%c", LF);
  8543. p += sprintf(p, " ret *= %.2f; //gamma%c", brightness, LF);
  8544. }
  8545. if (hue_shader >= 1.0f)
  8546. p += sprintf(p, " ret *= hue_shader; //old hue shader effect%c", LF);
  8547. else if (hue_shader > 0.001f)
  8548. p += sprintf(p, " ret *= %.2f + %.2f*hue_shader; //old hue shader effect%c", 1-hue_shader, hue_shader, LF);
  8549. if (bBrighten)
  8550. p += sprintf(p, " ret = sqrt(ret); //brighten%c", LF);
  8551. if (bDarken)
  8552. p += sprintf(p, " ret *= ret; //darken%c", LF);
  8553. if (bSolarize)
  8554. p += sprintf(p, " ret = ret*(1-ret)*4; //solarize%c", LF);
  8555. if (bInvert)
  8556. p += sprintf(p, " ret = 1 - ret; //invert%c", LF);
  8557. //p += sprintf(p, " ret.w = vDiffuse.w; // pass alpha along - req'd for preset blending%c", LF);
  8558. p += sprintf(p, "}%c", LF);
  8559. }