GR32_ColorGradients.pas 147 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183
  1. unit GR32_ColorGradients;
  2. (* ***** BEGIN LICENSE BLOCK ***************************************************
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception *
  4. * *
  5. * The contents of this file are subject to the Mozilla Public License Version *
  6. * 1.1 (the "License"); you may not use this file except in compliance with *
  7. * the License. You may obtain a copy of the License at *
  8. * http://www.mozilla.org/MPL/ *
  9. * *
  10. * Software distributed under the License is distributed on an "AS IS" basis, *
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License *
  12. * for the specific language governing rights and limitations under the *
  13. * License. *
  14. * *
  15. * Alternatively, the contents of this file may be used under the terms of the *
  16. * Free Pascal modified version of the GNU Lesser General Public License *
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions *
  18. * of this license are applicable instead of those above. *
  19. * Please see the file LICENSE.txt for additional information concerning this *
  20. * license. *
  21. * *
  22. * The Original Code is Color Gradients for Graphics32 *
  23. * *
  24. * The Initial Developer of the Original Code is *
  25. * Angus Johnson *
  26. * Christian Budde *
  27. * Anders Melander *
  28. * *
  29. * Portions created by the Initial Developer are Copyright (C) 2008-2024 *
  30. * the Initial Developer. All Rights Reserved. *
  31. * *
  32. * ***** END LICENSE BLOCK *****************************************************)
  33. interface
  34. {$include GR32.inc}
  35. uses
  36. Types, Classes, SysUtils, Math,
  37. GR32,
  38. GR32_Polygons,
  39. GR32_VectorUtils,
  40. {$if defined(UseInlining)}
  41. // Needed in interface for inlining
  42. GR32_Blend,
  43. {$ifend}
  44. GR32_Bindings;
  45. //------------------------------------------------------------------------------
  46. //
  47. // TColor32LookupTable
  48. //
  49. //------------------------------------------------------------------------------
  50. type
  51. TColor32LookupTable = class(TPersistent)
  52. private
  53. FGradientLUT: PColor32Array;
  54. FOrder: Byte;
  55. FMask: Cardinal;
  56. FSize: Cardinal;
  57. FOnOrderChanged: TNotifyEvent;
  58. procedure SetOrder(const Value: Byte);
  59. function GetColor32(Index: Integer): TColor32; {$IFDEF USEINLINING} inline; {$ENDIF}
  60. procedure SetColor32(Index: Integer; const Value: TColor32);
  61. protected
  62. procedure OrderChanged;
  63. procedure AssignTo(Dest: TPersistent); override;
  64. public
  65. constructor Create(Order: Byte = 9); virtual;
  66. destructor Destroy; override;
  67. property Order: Byte read FOrder write SetOrder;
  68. property Size: Cardinal read FSize;
  69. property Mask: Cardinal read FMask;
  70. property Color32[Index: Integer]: TColor32 read GetColor32 write SetColor32;
  71. property Color32Ptr: PColor32Array read FGradientLUT;
  72. property OnOrderChanged: TNotifyEvent read FOnOrderChanged write FOnOrderChanged;
  73. end;
  74. //------------------------------------------------------------------------------
  75. //
  76. // TColor32Gradient
  77. //
  78. //------------------------------------------------------------------------------
  79. type
  80. TColor32GradientStop = record
  81. Offset: TFloat; //expected range between 0.0 and 1.0
  82. Color32: TColor32;
  83. end;
  84. TArrayOfColor32GradientStop = array of TColor32GradientStop;
  85. TColor32FloatPoint = record
  86. Point: TFloatPoint;
  87. Color32: TColor32;
  88. end;
  89. TArrayOfColor32FloatPoint = array of TColor32FloatPoint;
  90. TColor32Gradient = class(TInterfacedPersistent, IStreamPersist)
  91. private
  92. FGradientColors: TArrayOfColor32GradientStop;
  93. FOnGradientColorsChanged: TNotifyEvent;
  94. function GetGradientEntry(Index: Integer): TColor32GradientStop;
  95. function GetGradientCount: Integer; {$IFDEF USEINLINING}inline;{$ENDIF}
  96. function GetStartColor: TColor32;
  97. function GetEndColor: TColor32;
  98. procedure SetEndColor(const Value: TColor32);
  99. procedure SetStartColor(const Value: TColor32);
  100. protected
  101. procedure GradientColorsChanged; virtual;
  102. procedure AssignTo(Dest: TPersistent); override;
  103. public
  104. constructor Create(Color: TColor32); overload;
  105. constructor Create(StartColor, EndColor: TColor32); overload;
  106. constructor Create(const GradientColors: TArrayOfColor32GradientStop); overload;
  107. procedure LoadFromStream(Stream: TStream);
  108. procedure SaveToStream(Stream: TStream);
  109. procedure ClearColorStops; overload;
  110. procedure ClearColorStops(Color: TColor32); overload;
  111. procedure AddColorStop(Offset: TFloat; Color: TColor32); overload; virtual;
  112. procedure AddColorStop(ColorStop: TColor32GradientStop); overload; virtual;
  113. procedure SetColors(const GradientColors: array of const); overload;
  114. procedure SetColors(const GradientColors: TArrayOfColor32GradientStop); overload;
  115. procedure SetColors(const GradientColors: TArrayOfColor32); overload;
  116. procedure SetColors(const Palette: TPalette32); overload;
  117. function GetColorAt(Offset: TFloat): TColor32;
  118. procedure FillColorLookUpTable(var ColorLUT: array of TColor32); overload;
  119. procedure FillColorLookUpTable(ColorLUT: PColor32Array; Count: Integer); overload;
  120. procedure FillColorLookUpTable(ColorLUT: TColor32LookupTable); overload;
  121. property GradientEntry[Index: Integer]: TColor32GradientStop read GetGradientEntry;
  122. property GradientCount: Integer read GetGradientCount;
  123. property StartColor: TColor32 read GetStartColor write SetStartColor;
  124. property EndColor: TColor32 read GetEndColor write SetEndColor;
  125. property OnGradientColorsChanged: TNotifyEvent read FOnGradientColorsChanged write FOnGradientColorsChanged;
  126. end;
  127. //------------------------------------------------------------------------------
  128. //
  129. // TCustomSparsePointGradientSampler
  130. //
  131. //------------------------------------------------------------------------------
  132. type
  133. TCustomSparsePointGradientSampler = class(TCustomSampler)
  134. protected
  135. function GetCount: Integer; virtual; abstract;
  136. function GetColor(Index: Integer): TColor32; virtual; abstract;
  137. function GetPoint(Index: Integer): TFloatPoint; virtual; abstract;
  138. function GetColorPoint(Index: Integer): TColor32FloatPoint; virtual; abstract;
  139. procedure SetColor(Index: Integer; const Value: TColor32); virtual; abstract;
  140. procedure SetColorPoint(Index: Integer; const Value: TColor32FloatPoint); virtual; abstract;
  141. procedure SetPoint(Index: Integer; const Value: TFloatPoint); virtual; abstract;
  142. public
  143. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  144. function GetSampleInt(X, Y: Integer): TColor32; override;
  145. procedure SetPoints(Points: TArrayOfFloatPoint); virtual; abstract;
  146. procedure SetColorPoints(ColorPoints: TArrayOfColor32FloatPoint); overload; virtual; abstract;
  147. procedure SetColorPoints(Points: TArrayOfFloatPoint; Colors: TArrayOfColor32); overload; virtual; abstract;
  148. property Color[Index: Integer]: TColor32 read GetColor write SetColor;
  149. property Point[Index: Integer]: TFloatPoint read GetPoint write SetPoint;
  150. property ColorPoint[Index: Integer]: TColor32FloatPoint read GetColorPoint write SetColorPoint;
  151. property Count: Integer read GetCount;
  152. end;
  153. //------------------------------------------------------------------------------
  154. //
  155. // TBarycentricGradientSampler
  156. //
  157. //------------------------------------------------------------------------------
  158. type
  159. TBarycentricGradientSampler = class(TCustomSparsePointGradientSampler)
  160. protected
  161. FColorPoints: array [0 .. 2] of TColor32FloatPoint;
  162. FDists: array [0 .. 1] of TFloatPoint;
  163. function GetCount: Integer; override;
  164. function GetColor(Index: Integer): TColor32; override;
  165. function GetColorPoint(Index: Integer): TColor32FloatPoint; override;
  166. function GetPoint(Index: Integer): TFloatPoint; override;
  167. procedure SetColor(Index: Integer; const Value: TColor32); override;
  168. procedure SetColorPoint(Index: Integer; const Value: TColor32FloatPoint); override;
  169. procedure SetPoint(Index: Integer; const Value: TFloatPoint); override;
  170. procedure AssignTo(Dest: TPersistent); override;
  171. procedure CalculateBarycentricCoordinates(X, Y: TFloat; out U, V, W: TFloat); {$IFDEF USEINLINING} inline; {$ENDIF}
  172. public
  173. constructor Create(P1, P2, P3: TColor32FloatPoint); overload; virtual;
  174. function IsPointInTriangle(X, Y: TFloat): Boolean; overload;
  175. function IsPointInTriangle(const Point: TFloatPoint): Boolean; overload;
  176. procedure SetPoints(Points: TArrayOfFloatPoint); override;
  177. procedure SetColorPoints(ColorPoints: TArrayOfColor32FloatPoint); override;
  178. procedure SetColorPoints(Points: TArrayOfFloatPoint; Colors: TArrayOfColor32); override;
  179. procedure PrepareSampling; override;
  180. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  181. function GetSampleFloatInTriangle(X, Y: TFloat): TColor32;
  182. end;
  183. //------------------------------------------------------------------------------
  184. //
  185. // TBilinearGradientSampler
  186. //
  187. //------------------------------------------------------------------------------
  188. type
  189. TBilinearGradientSampler = class(TCustomSparsePointGradientSampler)
  190. protected
  191. FColorPoints: array [0 .. 3] of TColor32FloatPoint;
  192. FDists: array [0 .. 2] of TFloatPoint;
  193. FDot: TFloat;
  194. FBiasK0: TFloat;
  195. FBiasU: TFloat;
  196. FK2Sign: Integer;
  197. FK2Value: TFloat;
  198. function GetCount: Integer; override;
  199. function GetColor(Index: Integer): TColor32; override;
  200. function GetColorPoint(Index: Integer): TColor32FloatPoint; override;
  201. function GetPoint(Index: Integer): TFloatPoint; override;
  202. procedure SetColor(Index: Integer; const Value: TColor32); override;
  203. procedure SetColorPoint(Index: Integer; const Value: TColor32FloatPoint); override;
  204. procedure SetPoint(Index: Integer; const Value: TFloatPoint); override;
  205. procedure AssignTo(Dest: TPersistent); override;
  206. public
  207. procedure SetPoints(Points: TArrayOfFloatPoint); override;
  208. procedure SetColorPoints(ColorPoints: TArrayOfColor32FloatPoint); override;
  209. procedure SetColorPoints(Points: TArrayOfFloatPoint; Colors: TArrayOfColor32); override;
  210. procedure PrepareSampling; override;
  211. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  212. end;
  213. //------------------------------------------------------------------------------
  214. //
  215. // TCustomArbitrarySparsePointGradientSampler
  216. //
  217. //------------------------------------------------------------------------------
  218. type
  219. TCustomArbitrarySparsePointGradientSampler = class(TCustomSparsePointGradientSampler)
  220. private
  221. FColorPoints: TArrayOfColor32FloatPoint;
  222. protected
  223. procedure AssignTo(Dest: TPersistent); override;
  224. function GetCount: Integer; override;
  225. function GetColor(Index: Integer): TColor32; override;
  226. function GetColorPoint(Index: Integer): TColor32FloatPoint; override;
  227. function GetPoint(Index: Integer): TFloatPoint; override;
  228. procedure SetColor(Index: Integer; const Value: TColor32); override;
  229. procedure SetColorPoint(Index: Integer; const Value: TColor32FloatPoint); override;
  230. procedure SetPoint(Index: Integer; const Value: TFloatPoint); override;
  231. public
  232. procedure Add(Point: TFloatPoint; Color: TColor32); overload; virtual;
  233. procedure Add(const ColorPoint: TColor32FloatPoint); overload; virtual;
  234. procedure SetColorPoints(ColorPoints: TArrayOfColor32FloatPoint); override;
  235. procedure SetColorPoints(Points: TArrayOfFloatPoint; Colors: TArrayOfColor32); override;
  236. procedure SetPoints(Points: TArrayOfFloatPoint); override;
  237. procedure Clear; virtual;
  238. end;
  239. //------------------------------------------------------------------------------
  240. //
  241. // TInvertedDistanceWeightingSampler
  242. //
  243. //------------------------------------------------------------------------------
  244. type
  245. TInvertedDistanceWeightingSampler = class(TCustomArbitrarySparsePointGradientSampler)
  246. private
  247. FDists: TArrayOfFloat;
  248. FUsePower: Boolean;
  249. FPower: TFloat;
  250. FScaledPower: TFloat;
  251. public
  252. constructor Create; virtual;
  253. procedure PrepareSampling; override;
  254. procedure FinalizeSampling; override;
  255. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  256. property Power: TFloat read FPower write FPower;
  257. end;
  258. //------------------------------------------------------------------------------
  259. //
  260. // TVoronoiSampler
  261. //
  262. //------------------------------------------------------------------------------
  263. type
  264. TVoronoiMetric = (vmEuclidean, vmManhattan, vmCustom);
  265. TVoronoiMetricFunc = function (X, Y: TFloat; Point: TFloatPoint): TFloat;
  266. TVoronoiSampler = class(TCustomArbitrarySparsePointGradientSampler)
  267. private
  268. FMetric: TVoronoiMetric;
  269. FMetricFunc: TVoronoiMetricFunc;
  270. procedure SetMetric(const Value: TVoronoiMetric);
  271. procedure MetricChanged;
  272. procedure SetMetricFunc(const Value: TVoronoiMetricFunc);
  273. public
  274. constructor Create(Metric: TVoronoiMetric = vmEuclidean); virtual;
  275. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  276. property Metric: TVoronoiMetric read FMetric write SetMetric;
  277. property MetricFunc: TVoronoiMetricFunc read FMetricFunc write SetMetricFunc;
  278. end;
  279. //------------------------------------------------------------------------------
  280. //
  281. // TGourandShadedDelaunayTrianglesSampler
  282. //
  283. //------------------------------------------------------------------------------
  284. type
  285. TGourandShadedDelaunayTrianglesSampler = class(TCustomArbitrarySparsePointGradientSampler)
  286. private
  287. FTriangles: TArrayOfTriangleVertexIndices;
  288. FBarycentric: array of TBarycentricGradientSampler;
  289. public
  290. procedure PrepareSampling; override;
  291. procedure FinalizeSampling; override;
  292. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  293. end;
  294. //------------------------------------------------------------------------------
  295. //
  296. // TCustomGradientSampler
  297. //
  298. //------------------------------------------------------------------------------
  299. type
  300. TCustomGradientSampler = class(TCustomSampler)
  301. private
  302. FGradient: TColor32Gradient;
  303. FWrapMode: TWrapMode;
  304. procedure SetGradient(const Value: TColor32Gradient);
  305. procedure SetWrapMode(const Value: TWrapMode);
  306. protected
  307. FInitialized: Boolean;
  308. procedure AssignTo(Dest: TPersistent); override;
  309. procedure GradientChangedHandler(Sender: TObject);
  310. procedure GradientSamplerChanged; //de-initializes sampler
  311. procedure WrapModeChanged; virtual;
  312. procedure UpdateInternals; virtual; abstract;
  313. property Initialized: Boolean read FInitialized;
  314. public
  315. constructor Create(WrapMode: TWrapMode = wmMirror); overload; virtual;
  316. constructor Create(ColorGradient: TColor32Gradient); overload; virtual;
  317. destructor Destroy; override;
  318. procedure PrepareSampling; override;
  319. function GetSampleInt(X, Y: Integer): TColor32; override;
  320. function GetSampleFixed(X, Y: TFixed): TColor32; override;
  321. property Gradient: TColor32Gradient read FGradient write SetGradient;
  322. property WrapMode: TWrapMode read FWrapMode write SetWrapMode;
  323. end;
  324. //------------------------------------------------------------------------------
  325. //
  326. // TCustomGradientLookUpTableSampler
  327. //
  328. //------------------------------------------------------------------------------
  329. type
  330. TCustomGradientLookUpTableSampler = class(TCustomGradientSampler)
  331. private
  332. FGradientLUT: TColor32LookupTable;
  333. FLutPtr: PColor32Array;
  334. FLutMask: Integer;
  335. FWrapProc: TWrapProc;
  336. protected
  337. procedure AssignTo(Dest: TPersistent); override;
  338. procedure WrapModeChanged; override;
  339. procedure UpdateInternals; override;
  340. property LutPtr: PColor32Array read FLutPtr;
  341. property LutMask: Integer read FLutMask;
  342. property WrapProc: TWrapProc read FWrapProc;
  343. public
  344. constructor Create(WrapMode: TWrapMode = wmMirror); override;
  345. destructor Destroy; override;
  346. end;
  347. //------------------------------------------------------------------------------
  348. //
  349. // TCustomCenterLutGradientSampler
  350. //
  351. //------------------------------------------------------------------------------
  352. type
  353. TCustomCenterLutGradientSampler = class(TCustomGradientLookUpTableSampler)
  354. private
  355. FCenter: TFloatPoint;
  356. protected
  357. procedure AssignTo(Dest: TPersistent); override;
  358. procedure Transform(var X, Y: TFloat); virtual;
  359. public
  360. constructor Create(WrapMode: TWrapMode = wmMirror); override;
  361. property Center: TFloatPoint read FCenter write FCenter;
  362. end;
  363. //------------------------------------------------------------------------------
  364. //
  365. // TConicGradientSampler
  366. //
  367. //------------------------------------------------------------------------------
  368. type
  369. TConicGradientSampler = class(TCustomCenterLutGradientSampler)
  370. private
  371. FScale: TFloat;
  372. FAngle: TFloat;
  373. protected
  374. procedure AssignTo(Dest: TPersistent); override;
  375. procedure UpdateInternals; override;
  376. public
  377. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  378. property Angle: TFloat read FAngle write FAngle;
  379. end;
  380. //------------------------------------------------------------------------------
  381. //
  382. // TCustomCenterRadiusLutGradientSampler
  383. //
  384. //------------------------------------------------------------------------------
  385. type
  386. TCustomCenterRadiusLutGradientSampler = class(TCustomCenterLutGradientSampler)
  387. private
  388. FRadius: TFloat;
  389. procedure SetRadius(const Value: TFloat);
  390. protected
  391. procedure AssignTo(Dest: TPersistent); override;
  392. procedure RadiusChanged; virtual;
  393. public
  394. constructor Create(WrapMode: TWrapMode = wmMirror); override;
  395. property Radius: TFloat read FRadius write SetRadius;
  396. end;
  397. //------------------------------------------------------------------------------
  398. //
  399. // TRadialGradientSampler
  400. //
  401. //------------------------------------------------------------------------------
  402. type
  403. TRadialGradientSampler = class(TCustomCenterRadiusLutGradientSampler)
  404. private
  405. FScale: TFloat;
  406. protected
  407. procedure UpdateInternals; override;
  408. public
  409. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  410. end;
  411. //------------------------------------------------------------------------------
  412. //
  413. // TRadialExGradientSampler
  414. //
  415. //------------------------------------------------------------------------------
  416. // HTML5 radial gradient.
  417. // Provides gradation of colors along a cylinder defined by two circles.
  418. // Also knows as "two point conical gradient"
  419. //------------------------------------------------------------------------------
  420. //
  421. // References:
  422. // - HTML Canvas Radial Gradients, The createRadialGradient() Method
  423. // https://www.w3schools.com/graphics/canvas_radial_gradients.asp
  424. //
  425. // - Microsoft Typography, COLR — Color Table, Graphic compositions, Gradients, Radial gradients
  426. // https://learn.microsoft.com/en-us/typography/opentype/spec/colr#radial-gradients
  427. //
  428. //------------------------------------------------------------------------------
  429. type
  430. TRadialExGradientSampler = class(TCustomGradientLookUpTableSampler)
  431. private
  432. FCenter1: TFloatPoint;
  433. FRadius1: TFloat;
  434. FCenter2: TFloatPoint;
  435. FRadius2: TFloat;
  436. FDeltaCenter: TFloatPoint;
  437. FDeltaRadius: TFloat;
  438. FPolynomA: TFloat;
  439. FPolynomAInv: TFLoat;
  440. FRadius12: TFloat;
  441. FRadius1Sqr: TFloat;
  442. procedure SetRadius1(const Value: TFloat);
  443. procedure SetRadius2(const Value: TFloat);
  444. procedure SetCenter1(const Value: TFloatPoint);
  445. procedure SetCenter2(const Value: TFloatPoint);
  446. protected
  447. procedure AssignTo(Dest: TPersistent); override;
  448. procedure UpdateInternals; override;
  449. procedure Transform(var X, Y: TFloat); virtual;
  450. public
  451. constructor Create(WrapMode: TWrapMode = wmMirror); override;
  452. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  453. // Center and radius of start circle
  454. property Center1: TFloatPoint read FCenter1 write SetCenter1;
  455. property Radius1: TFloat read FRadius1 write SetRadius1;
  456. // Center and radius of end circle
  457. property Center2: TFloatPoint read FCenter2 write SetCenter2;
  458. property Radius2: TFloat read FRadius2 write SetRadius2;
  459. end;
  460. //------------------------------------------------------------------------------
  461. //
  462. // TCustomCenterRadiusAngleLutGradientSampler
  463. //
  464. //------------------------------------------------------------------------------
  465. type
  466. TCustomCenterRadiusAngleLutGradientSampler = class(TCustomCenterRadiusLutGradientSampler)
  467. private
  468. FAngle: TFloat;
  469. FSinCos: TFloatPoint;
  470. procedure SetAngle(const Value: TFloat);
  471. protected
  472. procedure AssignTo(Dest: TPersistent); override;
  473. procedure AngleChanged; virtual;
  474. procedure RadiusChanged; override;
  475. procedure Transform(var X, Y: TFloat); override;
  476. public
  477. constructor Create(WrapMode: TWrapMode = wmMirror); override;
  478. property Angle: TFloat read FAngle write SetAngle;
  479. end;
  480. //------------------------------------------------------------------------------
  481. //
  482. // TDiamondGradientSampler
  483. //
  484. //------------------------------------------------------------------------------
  485. type
  486. TDiamondGradientSampler = class(TCustomCenterRadiusAngleLutGradientSampler)
  487. private
  488. FScale: TFloat;
  489. protected
  490. procedure UpdateInternals; override;
  491. public
  492. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  493. end;
  494. //------------------------------------------------------------------------------
  495. //
  496. // TXGradientSampler
  497. // TLinearGradientSampler
  498. //
  499. //------------------------------------------------------------------------------
  500. type
  501. TXGradientSampler = class(TCustomCenterRadiusAngleLutGradientSampler)
  502. private
  503. FScale: TFloat;
  504. function GetEndPoint: TFloatPoint;
  505. function GetStartPoint: TFloatPoint;
  506. procedure SetEndPoint(const Value: TFloatPoint);
  507. procedure SetStartPoint(const Value: TFloatPoint);
  508. protected
  509. procedure UpdateInternals; override;
  510. public
  511. procedure SimpleGradient(const StartPoint: TFloatPoint; StartColor: TColor32;
  512. const EndPoint: TFloatPoint; EndColor: TColor32); virtual;
  513. procedure SetPoints(const StartPoint, EndPoint: TFloatPoint); virtual;
  514. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  515. public
  516. property StartPoint: TFloatPoint read GetStartPoint write SetStartPoint;
  517. property EndPoint: TFloatPoint read GetEndPoint write SetEndPoint;
  518. end;
  519. type
  520. TLinearGradientSampler = class(TXGradientSampler);
  521. //------------------------------------------------------------------------------
  522. //
  523. // TXYGradientSampler
  524. //
  525. //------------------------------------------------------------------------------
  526. type
  527. TXYGradientSampler = class(TCustomCenterRadiusAngleLutGradientSampler)
  528. private
  529. FScale: TFloat;
  530. protected
  531. procedure UpdateInternals; override;
  532. public
  533. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  534. end;
  535. //------------------------------------------------------------------------------
  536. //
  537. // TXYSqrtGradientSampler
  538. //
  539. //------------------------------------------------------------------------------
  540. type
  541. TXYSqrtGradientSampler = class(TCustomCenterRadiusAngleLutGradientSampler)
  542. private
  543. FScale: TFloat;
  544. protected
  545. procedure UpdateInternals; override;
  546. public
  547. function GetSampleFloat(X, Y: TFloat): TColor32; override;
  548. end;
  549. //------------------------------------------------------------------------------
  550. //
  551. // TCustomSparsePointGradientPolygonFiller
  552. //
  553. //------------------------------------------------------------------------------
  554. type
  555. TCustomSparsePointGradientPolygonFiller = class(TCustomPolygonFiller)
  556. protected
  557. function GetCount: Integer; virtual; abstract;
  558. function GetColor(Index: Integer): TColor32; virtual; abstract;
  559. function GetPoint(Index: Integer): TFloatPoint; virtual; abstract;
  560. function GetColorPoint(Index: Integer): TColor32FloatPoint; virtual; abstract;
  561. procedure SetColor(Index: Integer; const Value: TColor32); virtual; abstract;
  562. procedure SetColorPoint(Index: Integer; const Value: TColor32FloatPoint); virtual; abstract;
  563. procedure SetPoint(Index: Integer; const Value: TFloatPoint); virtual; abstract;
  564. public
  565. procedure SetPoints(Points: TArrayOfFloatPoint); virtual; abstract;
  566. procedure SetColorPoints(ColorPoints: TArrayOfColor32FloatPoint); overload; virtual; abstract;
  567. procedure SetColorPoints(Points: TArrayOfFloatPoint; Colors: TArrayOfColor32); overload; virtual; abstract;
  568. property Color[Index: Integer]: TColor32 read GetColor write SetColor;
  569. property Point[Index: Integer]: TFloatPoint read GetPoint write SetPoint;
  570. property ColorPoint[Index: Integer]: TColor32FloatPoint read GetColorPoint write SetColorPoint;
  571. property Count: Integer read GetCount;
  572. end;
  573. //------------------------------------------------------------------------------
  574. //
  575. // TBarycentricGradientPolygonFiller
  576. //
  577. //------------------------------------------------------------------------------
  578. type
  579. TBarycentricGradientPolygonFiller = class(TCustomSparsePointGradientPolygonFiller)
  580. protected
  581. FColorPoints: array [0 .. 2] of TColor32FloatPoint;
  582. FDists: array [0 .. 1] of TFloatPoint;
  583. function GetCount: Integer; override;
  584. function GetColor(Index: Integer): TColor32; override;
  585. function GetPoint(Index: Integer): TFloatPoint; override;
  586. function GetColorPoint(Index: Integer): TColor32FloatPoint; override;
  587. procedure SetColor(Index: Integer; const Value: TColor32); override;
  588. procedure SetColorPoint(Index: Integer; const Value: TColor32FloatPoint); override;
  589. procedure SetPoint(Index: Integer; const Value: TFloatPoint); override;
  590. function GetFillLine: TFillLineEvent; override;
  591. procedure FillLine(Dst: PColor32; DstX, DstY, Length: Integer;
  592. AlphaValues: PColor32; CombineMode: TCombineMode);
  593. class function Linear3PointInterpolation(A, B, C: TColor32;
  594. WeightA, WeightB, WeightC: Single): TColor32;
  595. public
  596. procedure BeginRendering; override;
  597. procedure SetPoints(Points: TArrayOfFloatPoint); override;
  598. procedure SetColorPoints(ColorPoints: TArrayOfColor32FloatPoint); overload; override;
  599. procedure SetColorPoints(Points: TArrayOfFloatPoint; Colors: TArrayOfColor32); overload; override;
  600. end;
  601. //------------------------------------------------------------------------------
  602. //
  603. // TCustomArbitrarySparsePointGradientPolygonFiller
  604. //
  605. //------------------------------------------------------------------------------
  606. type
  607. TCustomArbitrarySparsePointGradientPolygonFiller = class(TCustomSparsePointGradientPolygonFiller)
  608. private
  609. FColorPoints: TArrayOfColor32FloatPoint;
  610. protected
  611. function GetCount: Integer; override;
  612. function GetColor(Index: Integer): TColor32; override;
  613. function GetColorPoint(Index: Integer): TColor32FloatPoint; override;
  614. function GetPoint(Index: Integer): TFloatPoint; override;
  615. procedure SetColor(Index: Integer; const Value: TColor32); override;
  616. procedure SetColorPoint(Index: Integer; const Value: TColor32FloatPoint); override;
  617. procedure SetPoint(Index: Integer; const Value: TFloatPoint); override;
  618. public
  619. procedure Add(const Point: TFloatPoint; Color: TColor32); overload; virtual;
  620. procedure Add(const ColorPoint: TColor32FloatPoint); overload; virtual;
  621. procedure SetColorPoints(ColorPoints: TArrayOfColor32FloatPoint); override;
  622. procedure SetColorPoints(Points: TArrayOfFloatPoint; Colors: TArrayOfColor32); override;
  623. procedure SetPoints(Points: TArrayOfFloatPoint); override;
  624. procedure Clear; virtual;
  625. end;
  626. //------------------------------------------------------------------------------
  627. //
  628. // TGourandShadedDelaunayTrianglesPolygonFiller
  629. //
  630. //------------------------------------------------------------------------------
  631. type
  632. TGourandShadedDelaunayTrianglesPolygonFiller = class(TCustomArbitrarySparsePointGradientPolygonFiller)
  633. private
  634. FTriangles: TArrayOfTriangleVertexIndices;
  635. FBarycentric: array of TBarycentricGradientSampler;
  636. protected
  637. function GetFillLine: TFillLineEvent; override;
  638. procedure FillLine3(Dst: PColor32; DstX, DstY, Count: Integer;
  639. AlphaValues: PColor32; CombineMode: TCombineMode);
  640. procedure FillLine(Dst: PColor32; DstX, DstY, Count: Integer;
  641. AlphaValues: PColor32; CombineMode: TCombineMode);
  642. public
  643. procedure BeginRendering; override;
  644. end;
  645. //------------------------------------------------------------------------------
  646. //
  647. // TCustomGradientPolygonFiller
  648. //
  649. //------------------------------------------------------------------------------
  650. type
  651. TCustomGradientPolygonFiller = class(TCustomPolygonFiller)
  652. private
  653. FGradient: TColor32Gradient;
  654. FOwnsGradient: Boolean;
  655. FWrapMode: TWrapMode;
  656. FWrapProc: TWrapProc;
  657. procedure SetWrapMode(const Value: TWrapMode);
  658. protected
  659. procedure GradientColorsChangedHandler(Sender: TObject);
  660. procedure FillLineNone(Dst: PColor32; DstX, DstY, Length: Integer;
  661. AlphaValues: PColor32; CombineMode: TCombineMode);
  662. procedure FillLineSolid(Dst: PColor32; DstX, DstY, Length: Integer;
  663. AlphaValues: PColor32; CombineMode: TCombineMode);
  664. procedure GradientFillerChanged; virtual;
  665. procedure WrapModeChanged; virtual;
  666. public
  667. constructor Create; overload;
  668. constructor Create(ColorGradient: TColor32Gradient); overload; virtual;
  669. destructor Destroy; override;
  670. property Gradient: TColor32Gradient read FGradient;
  671. property WrapMode: TWrapMode read FWrapMode write SetWrapMode;
  672. end;
  673. //------------------------------------------------------------------------------
  674. //
  675. // TCustomGradientLookupTablePolygonFiller
  676. //
  677. //------------------------------------------------------------------------------
  678. type
  679. TCustomGradientLookupTablePolygonFiller = class(TCustomGradientPolygonFiller)
  680. private
  681. FLUTNeedsUpdate: Boolean;
  682. FOwnsLUT: Boolean;
  683. FGradientLUT: TColor32LookupTable;
  684. FUseLookUpTable: Boolean;
  685. function GetLUTNeedsUpdate: Boolean;
  686. procedure SetUseLookUpTable(const Value: Boolean);
  687. procedure SetGradientLUT(const Value: TColor32LookupTable);
  688. protected
  689. procedure GradientFillerChanged; override;
  690. procedure UseLookUpTableChanged; virtual;
  691. procedure LookUpTableChangedHandler(Sender: TObject);
  692. property LookUpTableNeedsUpdate: Boolean read GetLUTNeedsUpdate;
  693. public
  694. constructor Create; reintroduce; overload;
  695. constructor Create(LookupTable: TColor32LookupTable); overload; virtual;
  696. destructor Destroy; override;
  697. property GradientLUT: TColor32LookupTable read FGradientLUT write SetGradientLUT;
  698. property UseLookUpTable: Boolean read FUseLookUpTable write SetUseLookUpTable;
  699. end;
  700. //------------------------------------------------------------------------------
  701. //
  702. // TCustomLinearGradientPolygonFiller
  703. //
  704. //------------------------------------------------------------------------------
  705. type
  706. TCustomLinearGradientPolygonFiller = class(TCustomGradientLookupTablePolygonFiller)
  707. private
  708. FIncline: TFloat;
  709. FStartPoint: TFloatPoint;
  710. FEndPoint: TFloatPoint;
  711. procedure SetStartPoint(const Value: TFloatPoint);
  712. procedure SetEndPoint(const Value: TFloatPoint);
  713. procedure UpdateIncline;
  714. protected
  715. procedure EndPointChanged;
  716. procedure StartPointChanged;
  717. public
  718. procedure SimpleGradient(const StartPoint: TFloatPoint; StartColor: TColor32;
  719. const EndPoint: TFloatPoint; EndColor: TColor32); virtual;
  720. procedure SimpleGradientX(const StartX: TFloat; StartColor: TColor32;
  721. const EndX: TFloat; EndColor: TColor32);
  722. procedure SimpleGradientY(const StartY: TFloat; StartColor: TColor32;
  723. const EndY: TFloat; EndColor: TColor32);
  724. procedure SetPoints(const StartPoint, EndPoint: TFloatPoint); virtual;
  725. property StartPoint: TFloatPoint read FStartPoint write SetStartPoint;
  726. property EndPoint: TFloatPoint read FEndPoint write SetEndPoint;
  727. end;
  728. //------------------------------------------------------------------------------
  729. //
  730. // TLinearGradientPolygonFiller
  731. //
  732. //------------------------------------------------------------------------------
  733. type
  734. TLinearGradientPolygonFiller = class(TCustomLinearGradientPolygonFiller)
  735. private
  736. function ColorStopToScanLine(Index: Integer; Y: Integer): TFloat;
  737. protected
  738. function GetFillLine: TFillLineEvent; override;
  739. procedure FillLineNegative(Dst: PColor32; DstX, DstY, Length: Integer;
  740. AlphaValues: PColor32;
  741. CombineMode: TCombineMode);
  742. procedure FillLinePositive(Dst: PColor32; DstX, DstY, Length: Integer;
  743. AlphaValues: PColor32;
  744. CombineMode: TCombineMode);
  745. procedure FillLineVertical(Dst: PColor32;
  746. DstX, DstY, Length: Integer; AlphaValues: PColor32;
  747. CombineMode: TCombineMode);
  748. procedure FillLineVerticalExtreme(Dst: PColor32; DstX, DstY,
  749. Length: Integer; AlphaValues: PColor32;
  750. CombineMode: TCombineMode);
  751. procedure FillLineVerticalPad(Dst: PColor32;
  752. DstX, DstY, Length: Integer; AlphaValues: PColor32;
  753. CombineMode: TCombineMode);
  754. procedure FillLineVerticalPadExtreme(Dst: PColor32; DstX, DstY,
  755. Length: Integer; AlphaValues: PColor32;
  756. CombineMode: TCombineMode);
  757. procedure FillLineVerticalWrap(Dst: PColor32;
  758. DstX, DstY, Length: Integer; AlphaValues: PColor32;
  759. CombineMode: TCombineMode);
  760. procedure FillLineHorizontalPadPos(Dst: PColor32;
  761. DstX, DstY, Length: Integer; AlphaValues: PColor32;
  762. CombineMode: TCombineMode);
  763. procedure FillLineHorizontalPadNeg(Dst: PColor32; DstX, DstY,
  764. Length: Integer; AlphaValues: PColor32;
  765. CombineMode: TCombineMode);
  766. procedure FillLineHorizontalWrapNeg(Dst: PColor32; DstX, DstY,
  767. Length: Integer; AlphaValues: PColor32;
  768. CombineMode: TCombineMode);
  769. procedure FillLineHorizontalWrapPos(Dst: PColor32; DstX, DstY,
  770. Length: Integer; AlphaValues: PColor32;
  771. CombineMode: TCombineMode);
  772. procedure UseLookUpTableChanged; override;
  773. procedure WrapModeChanged; override;
  774. public
  775. constructor Create(ColorGradient: TColor32Gradient); overload; override;
  776. constructor Create(ColorGradient: TColor32Gradient; UseLookupTable: Boolean); overload; virtual;
  777. procedure BeginRendering; override; //flags initialized
  778. end;
  779. //------------------------------------------------------------------------------
  780. //
  781. // TCustomRadialGradientPolygonFiller
  782. //
  783. //------------------------------------------------------------------------------
  784. type
  785. TCustomRadialGradientPolygonFiller = class(TCustomGradientLookupTablePolygonFiller)
  786. private
  787. FEllipseBounds: TFloatRect;
  788. procedure SetEllipseBounds(const Value: TFloatRect);
  789. protected
  790. procedure EllipseBoundsChanged; virtual; abstract;
  791. public
  792. property EllipseBounds: TFloatRect read FEllipseBounds write SetEllipseBounds;
  793. end;
  794. //------------------------------------------------------------------------------
  795. //
  796. // TRadialGradientPolygonFiller
  797. //
  798. //------------------------------------------------------------------------------
  799. type
  800. TRadialGradientPolygonFiller = class(TCustomRadialGradientPolygonFiller)
  801. private
  802. FCenter: TFloatPoint;
  803. FRadius: TFloatPoint;
  804. FRadScale: TFloat;
  805. FRadXInv: TFloat;
  806. procedure SetCenter(const Value: TFloatPoint);
  807. procedure SetRadius(const Value: TFloatPoint);
  808. procedure UpdateEllipseBounds;
  809. procedure UpdateRadiusScale;
  810. protected
  811. function GetFillLine: TFillLineEvent; override;
  812. procedure EllipseBoundsChanged; override;
  813. procedure FillLineClamp(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  814. procedure FillLineRepeat(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  815. procedure FillLineMirror(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  816. procedure FillLineReflect(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  817. public
  818. constructor Create(Radius: TFloatPoint); overload;
  819. constructor Create(BoundingBox: TFloatRect); overload;
  820. constructor Create(Radius, Center: TFloatPoint); overload;
  821. procedure BeginRendering; override;
  822. property Radius: TFloatPoint read FRadius write SetRadius;
  823. property Center: TFloatPoint read FCenter write SetCenter;
  824. end;
  825. //------------------------------------------------------------------------------
  826. //
  827. // TSVGRadialGradientPolygonFiller
  828. //
  829. //------------------------------------------------------------------------------
  830. type
  831. TSVGRadialGradientPolygonFiller = class(TCustomRadialGradientPolygonFiller)
  832. private
  833. FOffset: TFloatPoint;
  834. FRadius: TFloatPoint;
  835. FCenter: TFloatPoint;
  836. FFocalPt: TFloatPoint;
  837. FVertDist: TFloat;
  838. FFocalPointNative: TFloatPoint;
  839. procedure SetFocalPoint(const Value: TFloatPoint);
  840. procedure InitMembers;
  841. protected
  842. function GetFillLine: TFillLineEvent; override;
  843. procedure EllipseBoundsChanged; override;
  844. procedure FillLineEllipse(Dst: PColor32; DstX, DstY, Length: Integer;
  845. AlphaValues: PColor32; CombineMode: TCombineMode);
  846. public
  847. constructor Create(EllipseBounds: TFloatRect); overload;
  848. constructor Create(EllipseBounds: TFloatRect; FocalPoint: TFloatPoint); overload;
  849. procedure BeginRendering; override;
  850. procedure SetParameters(EllipseBounds: TFloatRect); overload;
  851. procedure SetParameters(EllipseBounds: TFloatRect; FocalPoint: TFloatPoint); overload;
  852. property FocalPoint: TFloatPoint read FFocalPointNative write SetFocalPoint;
  853. end;
  854. //------------------------------------------------------------------------------
  855. //
  856. // Utilities
  857. //
  858. //------------------------------------------------------------------------------
  859. function Color32FloatPoint(Color: TColor32; Point: TFloatPoint): TColor32FloatPoint; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  860. function Color32FloatPoint(Color: TColor32; X, Y: TFloat): TColor32FloatPoint; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  861. function Color32GradientStop(Offset: TFloat; Color: TColor32): TColor32GradientStop; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
  862. //------------------------------------------------------------------------------
  863. //
  864. // Bindings
  865. //
  866. //------------------------------------------------------------------------------
  867. const
  868. FID_LINEAR3 = 0;
  869. FID_LINEAR4 = 1;
  870. type
  871. TLinear3PointInterpolation = function (A, B, C: TColor32; WA, WB, WC: Single): TColor32;
  872. TLinear4PointInterpolation = function (A, B, C, D: TColor32; WA, WB, WC, WD: Single): TColor32;
  873. var
  874. // Linear interpolation of 3 colors
  875. Linear3PointInterpolation: TLinear3PointInterpolation;
  876. // Linear interpolation of 4 colors
  877. Linear4PointInterpolation: TLinear4PointInterpolation;
  878. var
  879. GradientRegistry: TFunctionRegistry;
  880. //------------------------------------------------------------------------------
  881. //------------------------------------------------------------------------------
  882. //------------------------------------------------------------------------------
  883. implementation
  884. uses
  885. {$if not defined(UseInlining)}
  886. GR32_Blend,
  887. {$ifend}
  888. GR32_LowLevel,
  889. GR32_Math,
  890. GR32_Geometry;
  891. resourcestring
  892. RCStrIndexOutOfBounds = 'Index out of bounds (%d)';
  893. RCStrWrongFormat = 'Wrong format';
  894. RCStrOnlyExactly3Point = 'Only exactly 3 points expected!';
  895. RCStrPointCountMismatch = 'Point count mismatch';
  896. RCStrNoTColor32LookupTable = 'No TColor32LookupTable object specified';
  897. RCStrNoTColor32Gradient = 'No TColor32Gradient specified';
  898. RCStrNoLookupTablePassed = 'No lookup table passed!';
  899. const
  900. CFloatTolerance = 0.001;
  901. procedure FillLineAlpha(var Dst, AlphaValues: PColor32; Count: Integer;
  902. Color: TColor32; CombineMode: TCombineMode); {$IFDEF USEINLINING}inline;{$ENDIF}
  903. var
  904. X: Integer;
  905. BlendMemEx: TBlendMemEx;
  906. begin
  907. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  908. for X := 0 to Count - 1 do
  909. begin
  910. BlendMemEx(Color, Dst^, AlphaValues^);
  911. Inc(Dst);
  912. Inc(AlphaValues);
  913. end;
  914. end;
  915. function Color32FloatPoint(Color: TColor32; Point: TFloatPoint): TColor32FloatPoint;
  916. begin
  917. Result.Point := Point;
  918. Result.Color32 := Color;
  919. end;
  920. function Color32FloatPoint(Color: TColor32; X, Y: TFloat): TColor32FloatPoint;
  921. begin
  922. Result.Point := FloatPoint(X, Y);
  923. Result.Color32 := Color;
  924. end;
  925. function Color32GradientStop(Offset: TFloat; Color: TColor32): TColor32GradientStop;
  926. begin
  927. Result.Offset := Offset;
  928. Result.Color32 := Color;
  929. end;
  930. function Linear3PointInterpolation_Pas(A, B, C: TColor32; WA, WB, WC: Single): TColor32;
  931. var
  932. Clr: TColor32Entry absolute Result;
  933. begin
  934. Clr.B := Clamp(Round(
  935. WA * TColor32Entry(A).B +
  936. WB * TColor32Entry(B).B +
  937. WC * TColor32Entry(C).B));
  938. Clr.G := Clamp(Round(
  939. WA * TColor32Entry(A).G +
  940. WB * TColor32Entry(B).G +
  941. WC * TColor32Entry(C).G));
  942. Clr.R := Clamp(Round(
  943. WA * TColor32Entry(A).R +
  944. WB * TColor32Entry(B).R +
  945. WC * TColor32Entry(C).R));
  946. Clr.A := Clamp(Round(
  947. WA * TColor32Entry(A).A +
  948. WB * TColor32Entry(B).A +
  949. WC * TColor32Entry(C).A));
  950. end;
  951. function Linear4PointInterpolation_Pas(A, B, C, D: TColor32; WA, WB, WC,
  952. WD: Single): TColor32;
  953. var
  954. Clr: TColor32Entry absolute Result;
  955. begin
  956. Clr.B := Clamp(Round(
  957. WA * TColor32Entry(A).B +
  958. WB * TColor32Entry(B).B +
  959. WC * TColor32Entry(C).B +
  960. WD * TColor32Entry(D).B));
  961. Clr.G := Clamp(Round(
  962. WA * TColor32Entry(A).G +
  963. WB * TColor32Entry(B).G +
  964. WC * TColor32Entry(C).G +
  965. WD * TColor32Entry(D).G));
  966. Clr.R := Clamp(Round(
  967. WA * TColor32Entry(A).R +
  968. WB * TColor32Entry(B).R +
  969. WC * TColor32Entry(C).R +
  970. WD * TColor32Entry(D).R));
  971. Clr.A := Clamp(Round(
  972. WA * TColor32Entry(A).A +
  973. WB * TColor32Entry(B).A +
  974. WC * TColor32Entry(C).A +
  975. WD * TColor32Entry(D).A));
  976. end;
  977. {$IFNDEF OMIT_SSE2}
  978. {$IFNDEF PUREPASCAL}
  979. function Linear3PointInterpolation_SSE2(A, B, C: TColor32; WA, WB, WC: Single): TColor32; {$IFDEF FPC}assembler; {$ENDIF}
  980. asm
  981. {$IFDEF TARGET_X86}
  982. PXOR XMM3,XMM3
  983. MOVD XMM0,EAX
  984. PUNPCKLBW XMM0,XMM3
  985. PUNPCKLWD XMM0,XMM3
  986. CVTDQ2PS XMM0,XMM0
  987. MOVD XMM1,EDX
  988. PUNPCKLBW XMM1,XMM3
  989. PUNPCKLWD XMM1,XMM3
  990. CVTDQ2PS XMM1,XMM1
  991. MOVD XMM2,ECX
  992. PUNPCKLBW XMM2,XMM3
  993. PUNPCKLWD XMM2,XMM3
  994. CVTDQ2PS XMM2,XMM2
  995. MOV EAX, WA
  996. MOV EDX, WB
  997. MOV ECX, WC
  998. MOVD XMM4,EAX
  999. SHUFPS XMM4,XMM4,0
  1000. MOVD XMM5,EDX
  1001. SHUFPS XMM5,XMM5,0
  1002. MOVD XMM6,ECX
  1003. SHUFPS XMM6,XMM6,0
  1004. MULPS XMM0,XMM4
  1005. MULPS XMM1,XMM5
  1006. MULPS XMM2,XMM6
  1007. ADDPS XMM0,XMM1
  1008. ADDPS XMM0,XMM2
  1009. CVTPS2DQ XMM0,XMM0
  1010. PACKSSDW XMM0,XMM3
  1011. PACKUSWB XMM0,XMM3
  1012. MOVD EAX,XMM0
  1013. {$ENDIF}
  1014. {$IFDEF TARGET_X64}
  1015. MOVQ XMM0,XMM3
  1016. SHUFPS XMM0,XMM0,0
  1017. {$IFDEF FPC}
  1018. MOVD XMM1,[RBP + $30]
  1019. {$ELSE}
  1020. MOVD XMM1,WB
  1021. {$ENDIF}
  1022. SHUFPS XMM1,XMM1,0
  1023. {$IFDEF FPC}
  1024. MOVD XMM2,[RBP + $38]
  1025. {$ELSE}
  1026. MOVD XMM2,WC
  1027. {$ENDIF}
  1028. SHUFPS XMM2,XMM2,0
  1029. PXOR XMM3,XMM3
  1030. MOVD XMM4,ECX
  1031. PUNPCKLBW XMM4,XMM3
  1032. PUNPCKLWD XMM4,XMM3
  1033. CVTDQ2PS XMM4,XMM4
  1034. MOVD XMM5,EDX
  1035. PUNPCKLBW XMM5,XMM3
  1036. PUNPCKLWD XMM5,XMM3
  1037. CVTDQ2PS XMM5,XMM5
  1038. MOVD XMM6,R8D
  1039. PUNPCKLBW XMM6,XMM3
  1040. PUNPCKLWD XMM6,XMM3
  1041. CVTDQ2PS XMM6,XMM6
  1042. MULPS XMM0,XMM4
  1043. MULPS XMM1,XMM5
  1044. MULPS XMM2,XMM6
  1045. ADDPS XMM0,XMM1
  1046. ADDPS XMM0,XMM2
  1047. CVTPS2DQ XMM0,XMM0
  1048. PACKSSDW XMM0,XMM3
  1049. PACKUSWB XMM0,XMM3
  1050. MOVD EAX,XMM0
  1051. {$ENDIF}
  1052. end;
  1053. function Linear4PointInterpolation_SSE2(A, B, C, D: TColor32; WA, WB, WC, WD: Single): TColor32; {$IFDEF FPC}assembler; {$ENDIF}
  1054. asm
  1055. {$IFDEF TARGET_X86}
  1056. PXOR XMM7,XMM7
  1057. MOVD XMM0,EAX
  1058. PUNPCKLBW XMM0,XMM7
  1059. PUNPCKLWD XMM0,XMM7
  1060. CVTDQ2PS XMM0,XMM0
  1061. MOVD XMM1,EDX
  1062. PUNPCKLBW XMM1,XMM7
  1063. PUNPCKLWD XMM1,XMM7
  1064. CVTDQ2PS XMM1,XMM1
  1065. MOV EAX, WA
  1066. MOVD XMM4,EAX
  1067. SHUFPS XMM4,XMM4,0
  1068. MULPS XMM0,XMM4
  1069. MOV EDX, WB
  1070. MOVD XMM5,EDX
  1071. SHUFPS XMM5,XMM5,0
  1072. MULPS XMM1,XMM5
  1073. ADDPS XMM0,XMM1
  1074. MOVD XMM2,ECX
  1075. PUNPCKLBW XMM2,XMM7
  1076. PUNPCKLWD XMM2,XMM7
  1077. CVTDQ2PS XMM2,XMM2
  1078. MOVD XMM3,D
  1079. PUNPCKLBW XMM3,XMM7
  1080. PUNPCKLWD XMM3,XMM7
  1081. CVTDQ2PS XMM3,XMM3
  1082. MOV EAX, WC
  1083. MOVD XMM4,EAX
  1084. SHUFPS XMM4,XMM4,0
  1085. MULPS XMM2,XMM4
  1086. MOV EDX, WD
  1087. MOVD XMM5,EDX
  1088. SHUFPS XMM5,XMM5,0
  1089. MULPS XMM3,XMM5
  1090. ADDPS XMM2,XMM3
  1091. ADDPS XMM0,XMM2
  1092. CVTPS2DQ XMM0,XMM0
  1093. PACKSSDW XMM0,XMM7
  1094. PACKUSWB XMM0,XMM7
  1095. MOVD EAX,XMM0
  1096. {$ENDIF}
  1097. {$IFDEF TARGET_X64}
  1098. PXOR XMM7,XMM7
  1099. MOVD XMM0,A
  1100. PUNPCKLBW XMM0,XMM7
  1101. PUNPCKLWD XMM0,XMM7
  1102. CVTDQ2PS XMM0,XMM0
  1103. MOVD XMM1,B
  1104. PUNPCKLBW XMM1,XMM7
  1105. PUNPCKLWD XMM1,XMM7
  1106. CVTDQ2PS XMM1,XMM1
  1107. {$IFDEF FPC}
  1108. MOV EAX, [RBP + $30]
  1109. {$ELSE}
  1110. MOV EAX, WA
  1111. {$ENDIF}
  1112. MOVD XMM4,EAX
  1113. SHUFPS XMM4,XMM4,0
  1114. MULPS XMM0,XMM4
  1115. {$IFDEF FPC}
  1116. MOV EDX, [RBP + $38]
  1117. {$ELSE}
  1118. MOV EDX, WB
  1119. {$ENDIF}
  1120. MOVD XMM5,EDX
  1121. SHUFPS XMM5,XMM5,0
  1122. MULPS XMM1,XMM5
  1123. ADDPS XMM0,XMM1
  1124. MOVD XMM2,C
  1125. PUNPCKLBW XMM2,XMM7
  1126. PUNPCKLWD XMM2,XMM7
  1127. CVTDQ2PS XMM2,XMM2
  1128. MOVD XMM3,D
  1129. PUNPCKLBW XMM3,XMM7
  1130. PUNPCKLWD XMM3,XMM7
  1131. CVTDQ2PS XMM3,XMM3
  1132. {$IFDEF FPC}
  1133. MOV EAX, [RBP + $40]
  1134. {$ELSE}
  1135. MOV EAX, WC
  1136. {$ENDIF}
  1137. MOVD XMM4,EAX
  1138. SHUFPS XMM4,XMM4,0
  1139. MULPS XMM2,XMM4
  1140. {$IFDEF FPC}
  1141. MOV EDX, [RBP + $48]
  1142. {$ELSE}
  1143. MOV EDX, WD
  1144. {$ENDIF}
  1145. MOVD XMM5,EDX
  1146. SHUFPS XMM5,XMM5,0
  1147. MULPS XMM3,XMM5
  1148. ADDPS XMM2,XMM3
  1149. ADDPS XMM0,XMM2
  1150. CVTPS2DQ XMM0,XMM0
  1151. PACKSSDW XMM0,XMM7
  1152. PACKUSWB XMM0,XMM7
  1153. MOVD EAX,XMM0
  1154. {$ENDIF}
  1155. end;
  1156. {$ENDIF}
  1157. {$ENDIF}
  1158. { TColor32LookupTable }
  1159. constructor TColor32LookupTable.Create(Order: Byte);
  1160. begin
  1161. inherited Create;
  1162. FOrder := Order;
  1163. OrderChanged;
  1164. end;
  1165. destructor TColor32LookupTable.Destroy;
  1166. begin
  1167. {$WARNINGS OFF}
  1168. FreeMem(FGradientLUT);
  1169. {$WARNINGS ON}
  1170. inherited;
  1171. end;
  1172. procedure TColor32LookupTable.AssignTo(Dest: TPersistent);
  1173. begin
  1174. if Dest is TColor32LookupTable then
  1175. with TColor32LookupTable(Dest) do
  1176. begin
  1177. FOrder := Self.FOrder;
  1178. OrderChanged;
  1179. Move(Self.FGradientLUT^, FGradientLUT^, FSize * SizeOf(TColor32));
  1180. end
  1181. else
  1182. inherited;
  1183. end;
  1184. function TColor32LookupTable.GetColor32(Index: Integer): TColor32;
  1185. begin
  1186. Result := FGradientLUT^[Index and FMask];
  1187. end;
  1188. procedure TColor32LookupTable.OrderChanged;
  1189. begin
  1190. FSize := 1 shl FOrder;
  1191. FMask := FSize - 1;
  1192. {$WARNINGS OFF}
  1193. ReallocMem(FGradientLUT, FSize * SizeOf(TColor32));
  1194. {$WARNINGS ON}
  1195. if Assigned(FOnOrderChanged) then
  1196. FOnOrderChanged(Self);
  1197. end;
  1198. procedure TColor32LookupTable.SetColor32(Index: Integer; const Value: TColor32);
  1199. begin
  1200. if (Index < 0) or (Index > Integer(FMask)) then
  1201. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index])
  1202. else
  1203. FGradientLUT^[Index] := Value;
  1204. end;
  1205. procedure TColor32LookupTable.SetOrder(const Value: Byte);
  1206. begin
  1207. if FOrder <> Value then
  1208. begin
  1209. FOrder := Value;
  1210. OrderChanged;
  1211. end;
  1212. end;
  1213. { TColor32Gradient; }
  1214. constructor TColor32Gradient.Create(Color: TColor32);
  1215. begin
  1216. Create(Color, Color);
  1217. end;
  1218. constructor TColor32Gradient.Create(StartColor, EndColor: TColor32);
  1219. var
  1220. Temp: TArrayOfColor32GradientStop;
  1221. begin
  1222. // simple gradient using 2 color stops
  1223. SetLength(Temp, 2);
  1224. Temp[0].Offset := 0;
  1225. Temp[0].Color32 := StartColor;
  1226. Temp[1].Offset := 1;
  1227. Temp[1].Color32 := EndColor;
  1228. Create(Temp);
  1229. end;
  1230. constructor TColor32Gradient.Create(const GradientColors: TArrayOfColor32GradientStop);
  1231. begin
  1232. inherited Create;
  1233. SetColors(GradientColors);
  1234. end;
  1235. procedure TColor32Gradient.AssignTo(Dest: TPersistent);
  1236. begin
  1237. if Dest is TColor32Gradient then
  1238. TColor32Gradient(Dest).SetColors(Self.FGradientColors)
  1239. else
  1240. inherited;
  1241. end;
  1242. procedure TColor32Gradient.AddColorStop(ColorStop: TColor32GradientStop);
  1243. begin
  1244. AddColorStop(ColorStop.Offset, ColorStop.Color32);
  1245. end;
  1246. procedure TColor32Gradient.AddColorStop(Offset: TFloat; Color: TColor32);
  1247. var
  1248. Index, OldCount: Integer;
  1249. begin
  1250. OldCount := Length(FGradientColors);
  1251. Index := 0;
  1252. // navigate to index where the color stop shall be inserted
  1253. while (Index < OldCount) and (Offset >= FGradientColors[Index].Offset) do
  1254. Inc(Index);
  1255. SetLength(FGradientColors, OldCount + 1);
  1256. // move existing color stops to make space for the new color stop
  1257. if (Index < OldCount) then
  1258. Move(FGradientColors[Index], FGradientColors[Index + 1],
  1259. (OldCount - Index) * SizeOf(TColor32GradientStop));
  1260. // finally insert new color stop
  1261. FGradientColors[Index].Offset := Offset;
  1262. FGradientColors[Index].Color32 := Color;
  1263. GradientColorsChanged;
  1264. end;
  1265. procedure TColor32Gradient.ClearColorStops(Color: TColor32);
  1266. begin
  1267. SetLength(FGradientColors, 1);
  1268. FGradientColors[0].Offset := 0;
  1269. FGradientColors[0].Color32 := Color;
  1270. GradientColorsChanged;
  1271. end;
  1272. procedure TColor32Gradient.ClearColorStops;
  1273. begin
  1274. SetLength(FGradientColors, 0);
  1275. GradientColorsChanged;
  1276. end;
  1277. procedure TColor32Gradient.SetColors(const GradientColors: array of const);
  1278. var
  1279. Index: Integer;
  1280. Scale: TFloat;
  1281. begin
  1282. if Length(GradientColors) = 0 then
  1283. begin
  1284. // no colors specified
  1285. if Length(FGradientColors) > 0 then
  1286. ClearColorStops;
  1287. end else
  1288. begin
  1289. SetLength(FGradientColors, Length(GradientColors));
  1290. if Length(GradientColors) > 1 then
  1291. begin
  1292. // several colors (at least 2)
  1293. Scale := 1 / High(GradientColors);
  1294. for Index := 0 to High(GradientColors) do
  1295. begin
  1296. Assert(GradientColors[Index].VType = vtInteger);
  1297. FGradientColors[Index].Color32 := GradientColors[Index].VInteger;
  1298. FGradientColors[Index].Offset := Index * Scale;
  1299. end;
  1300. end
  1301. else
  1302. begin
  1303. // only 1 color
  1304. Assert(GradientColors[0].VType = vtInteger);
  1305. FGradientColors[0].Color32 := GradientColors[0].VInteger;
  1306. FGradientColors[0].Offset := 0;
  1307. end;
  1308. GradientColorsChanged;
  1309. end;
  1310. end;
  1311. procedure TColor32Gradient.SetColors(const GradientColors: TArrayOfColor32GradientStop);
  1312. var
  1313. Index: Integer;
  1314. begin
  1315. if Length(GradientColors) = 0 then
  1316. begin
  1317. if Length(FGradientColors) > 0 then
  1318. ClearColorStops;
  1319. end else
  1320. begin
  1321. SetLength(FGradientColors, Length(GradientColors));
  1322. for Index := 0 to High(GradientColors) do
  1323. FGradientColors[Index] := GradientColors[Index];
  1324. GradientColorsChanged;
  1325. end;
  1326. end;
  1327. procedure TColor32Gradient.SetColors(const GradientColors: TArrayOfColor32);
  1328. var
  1329. Index: Integer;
  1330. Scale: TFloat;
  1331. begin
  1332. if Length(GradientColors) = 0 then
  1333. begin
  1334. // no colors specified
  1335. if Length(FGradientColors) > 0 then
  1336. ClearColorStops;
  1337. end else
  1338. begin
  1339. SetLength(FGradientColors, Length(GradientColors));
  1340. if Length(GradientColors) > 1 then
  1341. begin
  1342. // several colors (at least 2)
  1343. Scale := 1 / High(GradientColors);
  1344. for Index := 0 to High(GradientColors) do
  1345. begin
  1346. FGradientColors[Index].Color32 := GradientColors[Index];
  1347. FGradientColors[Index].Offset := Index * Scale;
  1348. end;
  1349. end
  1350. else
  1351. begin
  1352. // only 1 color
  1353. FGradientColors[0].Color32 := GradientColors[0];
  1354. FGradientColors[0].Offset := 0;
  1355. end;
  1356. GradientColorsChanged;
  1357. end;
  1358. end;
  1359. procedure TColor32Gradient.SetColors(const Palette: TPalette32);
  1360. var
  1361. Index: Integer;
  1362. Scale: TFloat;
  1363. begin
  1364. // TPalette32 contains 256 colors
  1365. SetLength(FGradientColors, Length(Palette));
  1366. Scale := 1 / High(Palette);
  1367. for Index := 0 to High(Palette) do
  1368. begin
  1369. FGradientColors[Index].Color32 := Palette[Index];
  1370. FGradientColors[Index].Offset := Index * Scale;
  1371. end;
  1372. GradientColorsChanged;
  1373. end;
  1374. procedure TColor32Gradient.SetStartColor(const Value: TColor32);
  1375. var
  1376. HasChanged: Boolean;
  1377. begin
  1378. HasChanged := False;
  1379. if Length(FGradientColors) = 0 then
  1380. begin
  1381. SetLength(FGradientColors, 1);
  1382. HasChanged := True;
  1383. end;
  1384. if FGradientColors[0].Offset <> 0 then
  1385. begin
  1386. FGradientColors[0].Offset := 0;
  1387. HasChanged := True;
  1388. end;
  1389. if FGradientColors[0].Color32 <> Value then
  1390. begin
  1391. FGradientColors[0].Color32 := Value;
  1392. HasChanged := True;
  1393. end;
  1394. if HasChanged then
  1395. GradientColorsChanged;
  1396. end;
  1397. procedure TColor32Gradient.SetEndColor(const Value: TColor32);
  1398. var
  1399. HasChanged: Boolean;
  1400. begin
  1401. HasChanged := False;
  1402. if Length(FGradientColors) = 1 then
  1403. begin
  1404. SetLength(FGradientColors, 2);
  1405. HasChanged := True;
  1406. end;
  1407. if FGradientColors[High(FGradientColors)].Offset <> 1 then
  1408. begin
  1409. FGradientColors[High(FGradientColors)].Offset := 1;
  1410. HasChanged := True;
  1411. end;
  1412. if FGradientColors[High(FGradientColors)].Color32 <> Value then
  1413. begin
  1414. FGradientColors[High(FGradientColors)].Color32 := Value;
  1415. HasChanged := True;
  1416. end;
  1417. if HasChanged then
  1418. GradientColorsChanged;
  1419. end;
  1420. function TColor32Gradient.GetGradientCount: Integer;
  1421. begin
  1422. Result := Length(FGradientColors);
  1423. end;
  1424. function TColor32Gradient.GetGradientEntry(Index: Integer): TColor32GradientStop;
  1425. begin
  1426. if Index > Length(FGradientColors) then
  1427. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1428. Result := FGradientColors[Index];
  1429. end;
  1430. function TColor32Gradient.GetStartColor: TColor32;
  1431. begin
  1432. if Length(FGradientColors) = 0 then
  1433. Result := clNone32
  1434. else
  1435. Result := FGradientColors[0].Color32;
  1436. end;
  1437. function TColor32Gradient.GetEndColor: TColor32;
  1438. var
  1439. Count: Integer;
  1440. begin
  1441. Count := Length(FGradientColors);
  1442. if Count = 0 then
  1443. Result := clNone32
  1444. else
  1445. Result := FGradientColors[Count - 1].Color32;
  1446. end;
  1447. function TColor32Gradient.GetColorAt(Offset: TFloat): TColor32;
  1448. var
  1449. Index, Count: Integer;
  1450. begin
  1451. Count := GradientCount;
  1452. if (Count = 0) or (Offset <= FGradientColors[0].Offset) then
  1453. Result := StartColor
  1454. else
  1455. if (Offset >= FGradientColors[Count - 1].Offset) then
  1456. Result := EndColor
  1457. else
  1458. begin
  1459. Index := 1;
  1460. // find color index for a given offset (between 0 and 1)
  1461. while (Index < Count) and (Offset > FGradientColors[Index].Offset) do
  1462. Inc(Index);
  1463. // calculate new offset (between two colors before and at 'Index')
  1464. Offset := (Offset - FGradientColors[Index - 1].Offset) / (FGradientColors[Index].Offset - FGradientColors[Index - 1].Offset);
  1465. // check if offset is out of bounds
  1466. if Offset <= 0 then
  1467. Result := FGradientColors[Index - 1].Color32
  1468. else
  1469. if Offset >= 1 then
  1470. Result := FGradientColors[Index].Color32
  1471. else
  1472. // interpolate color
  1473. Result := CombineReg(FGradientColors[Index].Color32, FGradientColors[Index - 1].Color32, Round($FF * Offset));
  1474. end;
  1475. end;
  1476. procedure TColor32Gradient.FillColorLookUpTable(ColorLUT: TColor32LookupTable);
  1477. begin
  1478. FillColorLookUpTable(ColorLUT.Color32Ptr, ColorLUT.Size);
  1479. end;
  1480. procedure TColor32Gradient.FillColorLookUpTable(var ColorLUT: array of TColor32);
  1481. begin
  1482. {$WARNINGS OFF}
  1483. FillColorLookUpTable(@ColorLUT[0], Length(ColorLUT));
  1484. {$WARNINGS ON}
  1485. end;
  1486. procedure TColor32Gradient.FillColorLookUpTable(ColorLUT: PColor32Array;
  1487. Count: Integer);
  1488. var
  1489. LutIndex, StopIndex, GradCount: Integer;
  1490. RecalculateScale: Boolean;
  1491. Fraction, LocalFraction, Delta, Scale: TFloat;
  1492. begin
  1493. GradCount := GradientCount;
  1494. //check trivial case
  1495. if (GradCount < 2) or (Count < 2) then
  1496. begin
  1497. for LutIndex := 0 to Count - 1 do
  1498. ColorLUT^[LutIndex] := StartColor;
  1499. Exit;
  1500. end;
  1501. // set first (start) and last (end) color
  1502. ColorLUT^[0] := StartColor;
  1503. ColorLUT^[Count - 1] := EndColor;
  1504. Delta := 1 / Count;
  1505. Fraction := Delta;
  1506. LutIndex := 1;
  1507. while Fraction <= FGradientColors[0].Offset do
  1508. begin
  1509. ColorLUT^[LutIndex] := ColorLUT^[0];
  1510. Fraction := Fraction + Delta;
  1511. Inc(LutIndex);
  1512. end;
  1513. Scale := 1;
  1514. StopIndex := 1;
  1515. RecalculateScale := True;
  1516. for LutIndex := LutIndex to Count - 2 do
  1517. begin
  1518. // eventually search next stop
  1519. while (Fraction > FGradientColors[StopIndex].Offset) do
  1520. begin
  1521. Inc(StopIndex);
  1522. if (StopIndex >= GradCount) then
  1523. Break;
  1524. RecalculateScale := True;
  1525. end;
  1526. // eventually fill remaining LUT
  1527. if StopIndex = GradCount then
  1528. begin
  1529. for StopIndex := LutIndex to Count - 2 do
  1530. ColorLUT^[StopIndex] := ColorLUT^[Count - 1];
  1531. Break;
  1532. end;
  1533. // eventually recalculate scale
  1534. if RecalculateScale then
  1535. Scale := 1 / (FGradientColors[StopIndex].Offset - FGradientColors[StopIndex - 1].Offset);
  1536. // calculate current color
  1537. LocalFraction := (Fraction - FGradientColors[StopIndex - 1].Offset) * Scale;
  1538. if LocalFraction <= 0 then
  1539. ColorLUT^[LutIndex] := FGradientColors[StopIndex - 1].Color32
  1540. else
  1541. if LocalFraction >= 1 then
  1542. ColorLUT^[LutIndex] := FGradientColors[StopIndex].Color32
  1543. else
  1544. ColorLUT^[LutIndex] := CombineReg(FGradientColors[StopIndex].Color32, FGradientColors[StopIndex - 1].Color32, Round($FF * LocalFraction));
  1545. Fraction := Fraction + Delta;
  1546. end;
  1547. end;
  1548. procedure TColor32Gradient.GradientColorsChanged;
  1549. begin
  1550. if Assigned(FOnGradientColorsChanged) then
  1551. FOnGradientColorsChanged(Self);
  1552. end;
  1553. procedure TColor32Gradient.LoadFromStream(Stream: TStream);
  1554. var
  1555. Index: Integer;
  1556. ChunkName: array [0..3] of AnsiChar;
  1557. ValueInt: Integer;
  1558. ValueFloat: Single;
  1559. begin
  1560. // read simple header
  1561. Stream.Read(ChunkName, 4);
  1562. if ChunkName <> 'Grad' then
  1563. raise Exception.Create(RCStrWrongFormat);
  1564. Stream.Read(ValueInt, 4);
  1565. SetLength(FGradientColors, ValueInt);
  1566. // read data
  1567. for Index := 0 to Length(FGradientColors) - 1 do
  1568. begin
  1569. ValueFloat := FGradientColors[Index].Offset;
  1570. Stream.Read(ValueFloat, 4);
  1571. ValueInt := FGradientColors[Index].Color32;
  1572. Stream.Read(ValueInt, 4);
  1573. end;
  1574. GradientColorsChanged;
  1575. end;
  1576. procedure TColor32Gradient.SaveToStream(Stream: TStream);
  1577. var
  1578. Index: Integer;
  1579. ChunkName: array [0..3] of AnsiChar;
  1580. ValueInt: Integer;
  1581. ValueFloat: Single;
  1582. begin
  1583. // write simple header
  1584. ChunkName := 'Grad';
  1585. Stream.Write(ChunkName, 4);
  1586. ValueInt := Length(FGradientColors);
  1587. Stream.Write(ValueInt, 4);
  1588. // write data
  1589. for Index := 0 to Length(FGradientColors) - 1 do
  1590. begin
  1591. ValueFloat := FGradientColors[Index].Offset;
  1592. Stream.Write(ValueFloat, 4);
  1593. ValueInt := FGradientColors[Index].Color32;
  1594. Stream.Write(ValueInt, 4);
  1595. end;
  1596. end;
  1597. { TCustomSparsePointGradientSampler }
  1598. function TCustomSparsePointGradientSampler.GetSampleFixed(X, Y: TFixed): TColor32;
  1599. begin
  1600. Result := GetSampleFloat(X * FixedToFloat, Y * FixedToFloat);
  1601. end;
  1602. function TCustomSparsePointGradientSampler.GetSampleInt(X, Y: Integer): TColor32;
  1603. begin
  1604. Result := GetSampleFloat(X, Y);
  1605. end;
  1606. { TBarycentricGradientSampler }
  1607. constructor TBarycentricGradientSampler.Create(P1, P2, P3: TColor32FloatPoint);
  1608. begin
  1609. FColorPoints[0] := P1;
  1610. FColorPoints[1] := P2;
  1611. FColorPoints[2] := P3;
  1612. inherited Create;
  1613. end;
  1614. procedure TBarycentricGradientSampler.AssignTo(Dest: TPersistent);
  1615. begin
  1616. if Dest is TBarycentricGradientSampler then
  1617. with TBarycentricGradientSampler(Dest) do
  1618. FColorPoints := Self.FColorPoints
  1619. else
  1620. inherited;
  1621. end;
  1622. function TBarycentricGradientSampler.GetColor(Index: Integer): TColor32;
  1623. begin
  1624. if Index in [0 .. 2] then
  1625. Result := FColorPoints[Index].Color32
  1626. else
  1627. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1628. end;
  1629. function TBarycentricGradientSampler.GetColorPoint(
  1630. Index: Integer): TColor32FloatPoint;
  1631. begin
  1632. if Index in [0 .. 2] then
  1633. Result := FColorPoints[Index]
  1634. else
  1635. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1636. end;
  1637. function TBarycentricGradientSampler.GetCount: Integer;
  1638. begin
  1639. Result := 3;
  1640. end;
  1641. function TBarycentricGradientSampler.GetPoint(Index: Integer): TFloatPoint;
  1642. begin
  1643. if Index in [0 .. 2] then
  1644. Result := FColorPoints[Index].Point
  1645. else
  1646. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1647. end;
  1648. procedure TBarycentricGradientSampler.CalculateBarycentricCoordinates(
  1649. X, Y: TFloat; out U, V, W: TFloat);
  1650. var
  1651. Temp: TFloatPoint;
  1652. begin
  1653. Temp.X := X - FColorPoints[2].Point.X;
  1654. Temp.Y := Y - FColorPoints[2].Point.Y;
  1655. U := FDists[0].Y * Temp.X + FDists[0].X * Temp.Y;
  1656. V := FDists[1].Y * Temp.X + FDists[1].X * Temp.Y;
  1657. W := 1.0 - U - V;
  1658. end;
  1659. function TBarycentricGradientSampler.GetSampleFloat(X, Y: TFloat): TColor32;
  1660. var
  1661. U, V, W: TFloat;
  1662. begin
  1663. CalculateBarycentricCoordinates(X, Y, U, V, W);
  1664. Result := Linear3PointInterpolation(FColorPoints[0].Color32,
  1665. FColorPoints[1].Color32, FColorPoints[2].Color32, U, V, W);
  1666. end;
  1667. function TBarycentricGradientSampler.GetSampleFloatInTriangle(X,
  1668. Y: TFloat): TColor32;
  1669. var
  1670. U, V, W: TFloat;
  1671. begin
  1672. CalculateBarycentricCoordinates(X, Y, U, V, W);
  1673. if U < 0 then
  1674. begin
  1675. U := (V + W);
  1676. V := V / U;
  1677. W := W / U;
  1678. U := 0;
  1679. end;
  1680. if V < 0 then
  1681. begin
  1682. V := (U + W);
  1683. U := U / V;
  1684. W := W / V;
  1685. V := 0;
  1686. end;
  1687. if V < 0 then
  1688. begin
  1689. W := (U + V);
  1690. U := U / W;
  1691. V := V / W;
  1692. W := 0;
  1693. end;
  1694. Result := Linear3PointInterpolation(FColorPoints[0].Color32,
  1695. FColorPoints[1].Color32, FColorPoints[2].Color32, U, V, W);
  1696. end;
  1697. function TBarycentricGradientSampler.IsPointInTriangle(
  1698. const Point: TFloatPoint): Boolean;
  1699. var
  1700. U, V, W: TFloat;
  1701. begin
  1702. CalculateBarycentricCoordinates(Point.X, Point.Y, U, V, W);
  1703. Result := (U >= 0) and (V >= 0) and (W >= 0);
  1704. end;
  1705. function TBarycentricGradientSampler.IsPointInTriangle(X, Y: TFloat): Boolean;
  1706. var
  1707. U, V, W: TFloat;
  1708. begin
  1709. CalculateBarycentricCoordinates(X, Y, U, V, W);
  1710. Result := (U >= 0) and (V >= 0) and (W >= 0);
  1711. end;
  1712. procedure TBarycentricGradientSampler.PrepareSampling;
  1713. var
  1714. NormScale: TFloat;
  1715. begin
  1716. NormScale := 1 / ((FColorPoints[1].Point.Y - FColorPoints[2].Point.Y) *
  1717. (FColorPoints[0].Point.X - FColorPoints[2].Point.X) +
  1718. (FColorPoints[2].Point.X - FColorPoints[1].Point.X) *
  1719. (FColorPoints[0].Point.Y - FColorPoints[2].Point.Y));
  1720. FDists[0].X := NormScale * (FColorPoints[2].Point.X - FColorPoints[1].Point.X);
  1721. FDists[0].Y := NormScale * (FColorPoints[1].Point.Y - FColorPoints[2].Point.Y);
  1722. FDists[1].X := NormScale * (FColorPoints[0].Point.X - FColorPoints[2].Point.X);
  1723. FDists[1].Y := NormScale * (FColorPoints[2].Point.Y - FColorPoints[0].Point.Y);
  1724. end;
  1725. procedure TBarycentricGradientSampler.SetColor(Index: Integer;
  1726. const Value: TColor32);
  1727. begin
  1728. if Index in [0 .. 2] then
  1729. FColorPoints[Index].Color32 := Value
  1730. else
  1731. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1732. end;
  1733. procedure TBarycentricGradientSampler.SetColorPoint(Index: Integer;
  1734. const Value: TColor32FloatPoint);
  1735. begin
  1736. if Index in [0 .. 2] then
  1737. FColorPoints[Index] := Value
  1738. else
  1739. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1740. end;
  1741. procedure TBarycentricGradientSampler.SetColorPoints(
  1742. ColorPoints: TArrayOfColor32FloatPoint);
  1743. begin
  1744. if Length(ColorPoints) <> 3 then
  1745. raise Exception.Create(RCStrOnlyExactly3Point);
  1746. FColorPoints[0] := ColorPoints[0];
  1747. FColorPoints[1] := ColorPoints[1];
  1748. FColorPoints[2] := ColorPoints[2];
  1749. end;
  1750. procedure TBarycentricGradientSampler.SetColorPoints(Points: TArrayOfFloatPoint;
  1751. Colors: TArrayOfColor32);
  1752. begin
  1753. if (Length(Points) <> 3) or (Length(Colors) <> 3) then
  1754. raise Exception.Create(RCStrOnlyExactly3Point);
  1755. FColorPoints[0] := Color32FloatPoint(Colors[0], Points[0]);
  1756. FColorPoints[1] := Color32FloatPoint(Colors[1], Points[1]);
  1757. FColorPoints[2] := Color32FloatPoint(Colors[2], Points[2]);
  1758. end;
  1759. procedure TBarycentricGradientSampler.SetPoint(Index: Integer;
  1760. const Value: TFloatPoint);
  1761. begin
  1762. if Index in [0 .. 2] then
  1763. FColorPoints[Index].Point := Value
  1764. else
  1765. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1766. end;
  1767. procedure TBarycentricGradientSampler.SetPoints(Points: TArrayOfFloatPoint);
  1768. begin
  1769. if Length(Points) <> 3 then
  1770. raise Exception.Create(RCStrOnlyExactly3Point);
  1771. FColorPoints[0].Point := Points[0];
  1772. FColorPoints[1].Point := Points[1];
  1773. FColorPoints[2].Point := Points[2];
  1774. end;
  1775. { TBilinearGradientSampler }
  1776. procedure TBilinearGradientSampler.AssignTo(Dest: TPersistent);
  1777. begin
  1778. if Dest is TBilinearGradientSampler then
  1779. with TBilinearGradientSampler(Dest) do
  1780. FColorPoints := Self.FColorPoints
  1781. else
  1782. inherited;
  1783. end;
  1784. function TBilinearGradientSampler.GetColor(Index: Integer): TColor32;
  1785. begin
  1786. if Index in [0 .. 3] then
  1787. Result := FColorPoints[Index].Color32
  1788. else
  1789. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1790. end;
  1791. function TBilinearGradientSampler.GetColorPoint(
  1792. Index: Integer): TColor32FloatPoint;
  1793. begin
  1794. if Index in [0 .. 3] then
  1795. Result := FColorPoints[Index]
  1796. else
  1797. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1798. end;
  1799. function TBilinearGradientSampler.GetCount: Integer;
  1800. begin
  1801. Result := 4;
  1802. end;
  1803. function TBilinearGradientSampler.GetPoint(Index: Integer): TFloatPoint;
  1804. begin
  1805. if Index in [0 .. 3] then
  1806. Result := FColorPoints[Index].Point
  1807. else
  1808. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1809. end;
  1810. function TBilinearGradientSampler.GetSampleFloat(X, Y: TFloat): TColor32;
  1811. var
  1812. u, v, t, k0, k1: Double;
  1813. begin
  1814. k1 := FDot + X * FDists[2].Y - Y * FDists[2].X;
  1815. k0 := FBiasK0 + X * FDists[0].Y - Y * FDists[0].X;
  1816. t := Sqr(k1) - 2 * k0 * FK2Value;
  1817. if FK2Value = 0 then
  1818. v := -k0 / k1
  1819. else
  1820. v := (FK2Sign * Sqrt(Abs(t)) - k1) / FK2Value;
  1821. u := (X - FBiasU - FDists[1].X * v) / (FDists[0].X + FDists[2].X * v);
  1822. Result := Linear4PointInterpolation(FColorPoints[0].Color32,
  1823. FColorPoints[1].Color32, FColorPoints[2].Color32, FColorPoints[3].Color32,
  1824. (1.0 - u) * (1.0 - v), u * (1.0 - v), u * v, (1.0 - u) * v);
  1825. end;
  1826. procedure TBilinearGradientSampler.PrepareSampling;
  1827. var
  1828. v, i, j: Integer;
  1829. Orientation: array [0 .. 3] of Boolean;
  1830. Indices: array [0 .. 1] of Integer;
  1831. TempPoint: TColor32FloatPoint;
  1832. begin
  1833. Orientation[0] := (FColorPoints[0].Point.X - FColorPoints[3].Point.X) *
  1834. (FColorPoints[1].Point.Y - FColorPoints[0].Point.Y) -
  1835. (FColorPoints[0].Point.Y - FColorPoints[3].Point.Y) *
  1836. (FColorPoints[1].Point.X - FColorPoints[0].Point.X) < 0;
  1837. Orientation[1] := (FColorPoints[1].Point.X - FColorPoints[0].Point.X) *
  1838. (FColorPoints[2].Point.Y - FColorPoints[1].Point.Y) -
  1839. (FColorPoints[1].Point.Y - FColorPoints[0].Point.Y) *
  1840. (FColorPoints[2].Point.X - FColorPoints[1].Point.X) < 0;
  1841. Orientation[2] := (FColorPoints[2].Point.X - FColorPoints[1].Point.X) *
  1842. (FColorPoints[3].Point.Y - FColorPoints[2].Point.Y) -
  1843. (FColorPoints[2].Point.Y - FColorPoints[1].Point.Y) *
  1844. (FColorPoints[3].Point.X - FColorPoints[2].Point.X) < 0;
  1845. Orientation[3] := (FColorPoints[3].Point.X - FColorPoints[2].Point.X) *
  1846. (FColorPoints[0].Point.Y - FColorPoints[3].Point.Y) -
  1847. (FColorPoints[3].Point.Y - FColorPoints[2].Point.Y) *
  1848. (FColorPoints[0].Point.X - FColorPoints[3].Point.X) < 0;
  1849. if Orientation[0] then v := -1 else v := 1;
  1850. if Orientation[1] then Dec(v) else Inc(v);
  1851. if Orientation[2] then Dec(v) else Inc(v);
  1852. if Orientation[3] then Dec(v) else Inc(v);
  1853. FK2Sign := Sign(v);
  1854. if v = 0 then
  1855. begin
  1856. // correct complex case
  1857. i := 0;
  1858. j := 0;
  1859. repeat
  1860. if Orientation[j] then
  1861. begin
  1862. Indices[i] := j;
  1863. Inc(i);
  1864. end;
  1865. Inc(j);
  1866. until i = 2;
  1867. // exchange color points
  1868. TempPoint := FColorPoints[Indices[0]];
  1869. FColorPoints[Indices[0]] := FColorPoints[Indices[1]];
  1870. FColorPoints[Indices[1]] := TempPoint;
  1871. FK2Sign := 1;
  1872. end;
  1873. FDists[0].X := FColorPoints[1].Point.X - FColorPoints[0].Point.X;
  1874. FDists[0].Y := FColorPoints[1].Point.Y - FColorPoints[0].Point.Y;
  1875. FDists[1].X := FColorPoints[3].Point.X - FColorPoints[0].Point.X;
  1876. FDists[1].Y := FColorPoints[3].Point.Y - FColorPoints[0].Point.Y;
  1877. FDists[2].X := FColorPoints[0].Point.X - FColorPoints[1].Point.X +
  1878. FColorPoints[2].Point.X - FColorPoints[3].Point.X;
  1879. FDists[2].Y := FColorPoints[0].Point.Y - FColorPoints[1].Point.Y +
  1880. FColorPoints[2].Point.Y - FColorPoints[3].Point.Y;
  1881. FK2Value := 2 * (FDists[2].X * FDists[1].Y - FDists[2].Y * FDists[1].X);
  1882. FDot := FDists[0].X * FDists[1].Y - FDists[0].Y * FDists[1].X -
  1883. FColorPoints[0].Point.X * FDists[2].Y + FColorPoints[0].Point.Y * FDists[2].X;
  1884. FBiasK0 := FColorPoints[0].Point.Y * FDists[0].X -
  1885. FColorPoints[0].Point.X * FDists[0].Y;
  1886. FBiasU := FColorPoints[0].Point.X;
  1887. end;
  1888. procedure TBilinearGradientSampler.SetColor(Index: Integer;
  1889. const Value: TColor32);
  1890. begin
  1891. if Index in [0 .. 3] then
  1892. FColorPoints[Index].Color32 := Value
  1893. else
  1894. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1895. end;
  1896. procedure TBilinearGradientSampler.SetColorPoint(Index: Integer;
  1897. const Value: TColor32FloatPoint);
  1898. begin
  1899. if Index in [0 .. 3] then
  1900. FColorPoints[Index] := Value
  1901. else
  1902. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1903. end;
  1904. procedure TBilinearGradientSampler.SetColorPoints(
  1905. ColorPoints: TArrayOfColor32FloatPoint);
  1906. begin
  1907. if Length(ColorPoints) <> 4 then
  1908. raise Exception.Create(RCStrOnlyExactly3Point);
  1909. FColorPoints[0] := ColorPoints[0];
  1910. FColorPoints[1] := ColorPoints[1];
  1911. FColorPoints[2] := ColorPoints[2];
  1912. FColorPoints[3] := ColorPoints[3];
  1913. end;
  1914. procedure TBilinearGradientSampler.SetColorPoints(Points: TArrayOfFloatPoint;
  1915. Colors: TArrayOfColor32);
  1916. begin
  1917. if (Length(Points) <> 3) or (Length(Colors) <> 3) then
  1918. raise Exception.Create(RCStrOnlyExactly3Point);
  1919. FColorPoints[0] := Color32FloatPoint(Colors[0], Points[0]);
  1920. FColorPoints[1] := Color32FloatPoint(Colors[1], Points[1]);
  1921. FColorPoints[2] := Color32FloatPoint(Colors[2], Points[2]);
  1922. FColorPoints[3] := Color32FloatPoint(Colors[3], Points[3]);
  1923. end;
  1924. procedure TBilinearGradientSampler.SetPoint(Index: Integer;
  1925. const Value: TFloatPoint);
  1926. begin
  1927. if Index in [0 .. 3] then
  1928. FColorPoints[Index].Point := Value
  1929. else
  1930. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1931. end;
  1932. procedure TBilinearGradientSampler.SetPoints(Points: TArrayOfFloatPoint);
  1933. begin
  1934. if Length(Points) <> 4 then
  1935. raise Exception.Create(RCStrOnlyExactly3Point);
  1936. FColorPoints[0].Point := Points[0];
  1937. FColorPoints[1].Point := Points[1];
  1938. FColorPoints[2].Point := Points[2];
  1939. FColorPoints[3].Point := Points[3];
  1940. end;
  1941. { TCustomArbitrarySparsePointGradientSampler }
  1942. procedure TCustomArbitrarySparsePointGradientSampler.AssignTo(Dest: TPersistent);
  1943. begin
  1944. if Dest is TCustomArbitrarySparsePointGradientSampler then
  1945. with TCustomArbitrarySparsePointGradientSampler(Dest) do
  1946. begin
  1947. FColorPoints := Self.FColorPoints;
  1948. end
  1949. else
  1950. inherited;
  1951. end;
  1952. procedure TCustomArbitrarySparsePointGradientSampler.Add(Point: TFloatPoint;
  1953. Color: TColor32);
  1954. var
  1955. Index: Integer;
  1956. begin
  1957. Index := Length(FColorPoints);
  1958. SetLength(FColorPoints, Index + 1);
  1959. FColorPoints[Index].Point := Point;
  1960. FColorPoints[Index].Color32 := Color;
  1961. end;
  1962. procedure TCustomArbitrarySparsePointGradientSampler.Add(
  1963. const ColorPoint: TColor32FloatPoint);
  1964. var
  1965. Index: Integer;
  1966. begin
  1967. Index := Length(FColorPoints);
  1968. SetLength(FColorPoints, Index + 1);
  1969. FColorPoints[Index].Point := ColorPoint.Point;
  1970. FColorPoints[Index].Color32 := ColorPoint.Color32;
  1971. end;
  1972. procedure TCustomArbitrarySparsePointGradientSampler.Clear;
  1973. begin
  1974. SetLength(FColorPoints, 0);
  1975. end;
  1976. function TCustomArbitrarySparsePointGradientSampler.GetColor(
  1977. Index: Integer): TColor32;
  1978. begin
  1979. if (Index >= 0) and (Index < Length(FColorPoints)) then
  1980. Result := FColorPoints[Index].Color32
  1981. else
  1982. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1983. end;
  1984. function TCustomArbitrarySparsePointGradientSampler.GetColorPoint(
  1985. Index: Integer): TColor32FloatPoint;
  1986. begin
  1987. if (Index >= 0) and (Index < Length(FColorPoints)) then
  1988. Result := FColorPoints[Index]
  1989. else
  1990. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  1991. end;
  1992. function TCustomArbitrarySparsePointGradientSampler.GetCount: Integer;
  1993. begin
  1994. Result := Length(FColorPoints);
  1995. end;
  1996. function TCustomArbitrarySparsePointGradientSampler.GetPoint(
  1997. Index: Integer): TFloatPoint;
  1998. begin
  1999. if (Index >= 0) and (Index < Length(FColorPoints)) then
  2000. Result := FColorPoints[Index].Point
  2001. else
  2002. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  2003. end;
  2004. procedure TCustomArbitrarySparsePointGradientSampler.SetColor(Index: Integer;
  2005. const Value: TColor32);
  2006. begin
  2007. if (Index >= 0) and (Index < Length(FColorPoints)) then
  2008. FColorPoints[Index].Color32 := Value
  2009. else
  2010. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  2011. end;
  2012. procedure TCustomArbitrarySparsePointGradientSampler.SetColorPoint(
  2013. Index: Integer; const Value: TColor32FloatPoint);
  2014. begin
  2015. if (Index >= 0) and (Index < Length(FColorPoints)) then
  2016. FColorPoints[Index] := Value
  2017. else
  2018. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  2019. end;
  2020. procedure TCustomArbitrarySparsePointGradientSampler.SetPoint(Index: Integer;
  2021. const Value: TFloatPoint);
  2022. begin
  2023. if (Index >= 0) and (Index < Length(FColorPoints)) then
  2024. FColorPoints[Index].Point := Value
  2025. else
  2026. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  2027. end;
  2028. procedure TCustomArbitrarySparsePointGradientSampler.SetColorPoints(
  2029. ColorPoints: TArrayOfColor32FloatPoint);
  2030. var
  2031. Index: Integer;
  2032. begin
  2033. SetLength(FColorPoints, Length(ColorPoints));
  2034. for Index := 0 to High(FColorPoints) do
  2035. FColorPoints[Index] := ColorPoints[Index];
  2036. end;
  2037. procedure TCustomArbitrarySparsePointGradientSampler.SetColorPoints(
  2038. Points: TArrayOfFloatPoint; Colors: TArrayOfColor32);
  2039. var
  2040. Index: Integer;
  2041. begin
  2042. if Length(Points) <> Length(Colors) then
  2043. raise Exception.Create(RCStrPointCountMismatch);
  2044. SetLength(FColorPoints, Length(Points));
  2045. for Index := 0 to High(FColorPoints) do
  2046. begin
  2047. FColorPoints[Index].Point := Points[Index];
  2048. FColorPoints[Index].Color32 := Colors[Index];
  2049. end;
  2050. end;
  2051. procedure TCustomArbitrarySparsePointGradientSampler.SetPoints(
  2052. Points: TArrayOfFloatPoint);
  2053. var
  2054. Index: Integer;
  2055. begin
  2056. if Length(FColorPoints) <> Length(Points) then
  2057. raise Exception.Create(RCStrPointCountMismatch);
  2058. for Index := 0 to High(Points) do
  2059. FColorPoints[Index].Point := Points[Index];
  2060. end;
  2061. { TInvertedDistanceWeightingSampler }
  2062. constructor TInvertedDistanceWeightingSampler.Create;
  2063. begin
  2064. inherited;
  2065. FPower := 2;
  2066. FScaledPower := 0.5 * FPower;
  2067. end;
  2068. procedure TInvertedDistanceWeightingSampler.FinalizeSampling;
  2069. begin
  2070. inherited;
  2071. Finalize(FDists);
  2072. end;
  2073. function TInvertedDistanceWeightingSampler.GetSampleFloat(X, Y: TFloat): TColor32;
  2074. var
  2075. Index: Integer;
  2076. Temp, DistSum, Scale: Double;
  2077. R, G, B, A: TFloat;
  2078. begin
  2079. if Count = 1 then
  2080. begin
  2081. Result := FColorPoints[0].Color32;
  2082. Exit;
  2083. end;
  2084. with FColorPoints[0] do
  2085. Temp := Sqr(X - Point.X) + Sqr(Y - Point.Y);
  2086. if FUsePower then
  2087. Temp := Math.Power(Temp, FScaledPower);
  2088. if Abs(Temp) > MaxSingle then
  2089. FDists[0] := 0
  2090. else
  2091. FDists[0] := 1 / Max(1.0, Temp);
  2092. DistSum := FDists[0];
  2093. for Index := 1 to Count - 1 do
  2094. with FColorPoints[Index] do
  2095. begin
  2096. Temp := Sqr(X - Point.X) + Sqr(Y - Point.Y);
  2097. if FUsePower then
  2098. Temp := Math.Power(Temp, FScaledPower);
  2099. if Abs(Temp) > MaxSingle then
  2100. FDists[Index] := 0
  2101. else
  2102. FDists[Index] := 1 / Max(1.0, Temp);
  2103. DistSum := DistSum + FDists[Index];
  2104. end;
  2105. DistSum := 1.0 / (1E-30 + DistSum);
  2106. Scale := FDists[0] * DistSum;
  2107. case Count of
  2108. 3:
  2109. begin
  2110. // optimization for 3-Point interpolation
  2111. Result := Linear3PointInterpolation(FColorPoints[0].Color32,
  2112. FColorPoints[1].Color32, FColorPoints[2].Color32, FDists[0] * DistSum,
  2113. FDists[1] * DistSum, FDists[2] * DistSum);
  2114. Exit;
  2115. end;
  2116. 4:
  2117. begin
  2118. // optimization for 4-Point interpolation
  2119. Result := Linear4PointInterpolation(FColorPoints[0].Color32,
  2120. FColorPoints[1].Color32, FColorPoints[2].Color32,
  2121. FColorPoints[3].Color32, FDists[0] * DistSum, FDists[1] * DistSum,
  2122. FDists[2] * DistSum, FDists[3] * DistSum);
  2123. Exit;
  2124. end;
  2125. end;
  2126. // general n-Point interpolation
  2127. R := Scale * TColor32Entry(FColorPoints[0].Color32).R;
  2128. G := Scale * TColor32Entry(FColorPoints[0].Color32).G;
  2129. B := Scale * TColor32Entry(FColorPoints[0].Color32).B;
  2130. A := Scale * TColor32Entry(FColorPoints[0].Color32).A;
  2131. for Index := 1 to Count - 1 do
  2132. begin
  2133. Scale := FDists[Index] * DistSum;
  2134. R := R + Scale * TColor32Entry(FColorPoints[Index].Color32).R;
  2135. G := G + Scale * TColor32Entry(FColorPoints[Index].Color32).G;
  2136. B := B + Scale * TColor32Entry(FColorPoints[Index].Color32).B;
  2137. A := A + Scale * TColor32Entry(FColorPoints[Index].Color32).A;
  2138. end;
  2139. Result := Color32(Clamp(Round(R)), Clamp(Round(G)), Clamp(Round(B)),
  2140. Clamp(Round(A)));
  2141. end;
  2142. procedure TInvertedDistanceWeightingSampler.PrepareSampling;
  2143. begin
  2144. SetLength(FDists, Count);
  2145. FUsePower := FPower <> 2;
  2146. FScaledPower := 0.5 * FPower;
  2147. inherited;
  2148. end;
  2149. function EuclideanMetric(X, Y: TFloat; Point: TFloatPoint): TFloat;
  2150. begin
  2151. Result := Sqr(X - Point.X) + Sqr(Y - Point.Y);
  2152. end;
  2153. function ManhattanMetric(X, Y: TFloat; Point: TFloatPoint): TFloat;
  2154. begin
  2155. Result := Abs(X - Point.X) + Abs(Y - Point.Y);
  2156. end;
  2157. { TVoronoiSampler }
  2158. constructor TVoronoiSampler.Create(Metric: TVoronoiMetric = vmEuclidean);
  2159. begin
  2160. FMetric := Metric;
  2161. FMetricFunc := EuclideanMetric;
  2162. case FMetric of
  2163. vmEuclidean:
  2164. FMetricFunc := @EuclideanMetric;
  2165. vmManhattan:
  2166. FMetricFunc := @ManhattanMetric;
  2167. vmCustom:
  2168. raise Exception.Create('Invalid metric');
  2169. end;
  2170. end;
  2171. function TVoronoiSampler.GetSampleFloat(X, Y: TFloat): TColor32;
  2172. var
  2173. Index, NearestIndex: Integer;
  2174. Distance: TFloat;
  2175. NearestDistance: TFloat;
  2176. begin
  2177. NearestIndex := 0;
  2178. NearestDistance := FMetricFunc(X, Y, FColorPoints[0].Point);
  2179. for Index := 1 to High(FColorPoints) do
  2180. begin
  2181. Distance := FMetricFunc(X, Y, FColorPoints[Index].Point);
  2182. if Distance < NearestDistance then
  2183. begin
  2184. NearestDistance := Distance;
  2185. NearestIndex := Index;
  2186. end;
  2187. end;
  2188. Result := FColorPoints[NearestIndex].Color32;
  2189. end;
  2190. procedure TVoronoiSampler.SetMetric(const Value: TVoronoiMetric);
  2191. begin
  2192. if FMetric <> Value then
  2193. begin
  2194. FMetric := Value;
  2195. case FMetric of
  2196. vmEuclidean:
  2197. FMetricFunc := @EuclideanMetric;
  2198. vmManhattan:
  2199. FMetricFunc := @ManhattanMetric;
  2200. end;
  2201. MetricChanged;
  2202. end;
  2203. end;
  2204. procedure TVoronoiSampler.SetMetricFunc(const Value: TVoronoiMetricFunc);
  2205. begin
  2206. FMetricFunc := Value;
  2207. Metric := vmCustom;
  2208. end;
  2209. procedure TVoronoiSampler.MetricChanged;
  2210. begin
  2211. Changed;
  2212. end;
  2213. { TDelaunaySampler }
  2214. procedure FastMergeSortX(const Values: TArrayOfColor32FloatPoint;
  2215. out Indexes: TArrayOfInteger; out Bounds: TFloatRect);
  2216. var
  2217. Temp: TArrayOfInteger;
  2218. procedure Merge(I1, I2, J1, J2: Integer);
  2219. var
  2220. I, J, K: Integer;
  2221. begin
  2222. if Values[Indexes[I2]].Point.X < Values[Indexes[J1]].Point.X then
  2223. Exit;
  2224. I := I1;
  2225. J := J1;
  2226. K := 0;
  2227. repeat
  2228. if Values[Indexes[I]].Point.X < Values[Indexes[J]].Point.X then
  2229. begin
  2230. Temp[K] := Indexes[I];
  2231. Inc(I);
  2232. end
  2233. else
  2234. begin
  2235. Temp[K] := Indexes[J];
  2236. Inc(J);
  2237. end;
  2238. Inc(K);
  2239. until (I > I2) or (J > J2);
  2240. while I <= I2 do
  2241. begin
  2242. Temp[K] := Indexes[I];
  2243. Inc(I); Inc(K);
  2244. end;
  2245. while J <= J2 do
  2246. begin
  2247. Temp[K] := Indexes[J];
  2248. Inc(J); Inc(K);
  2249. end;
  2250. for I := 0 to K - 1 do
  2251. begin
  2252. Indexes[I + I1] := Temp[I];
  2253. end;
  2254. end;
  2255. procedure Recurse(I1, I2: Integer);
  2256. var
  2257. I, IX: Integer;
  2258. begin
  2259. if I1 = I2 then
  2260. Indexes[I1] := I1
  2261. else if Indexes[I1] = Indexes[I2] then
  2262. begin
  2263. if Values[I1].Point.X <= Values[I2].Point.X then
  2264. begin
  2265. for I := I1 to I2 do Indexes[I] := I;
  2266. end
  2267. else
  2268. begin
  2269. IX := I1 + I2;
  2270. for I := I1 to I2 do Indexes[I] := IX - I;
  2271. end;
  2272. end
  2273. else
  2274. begin
  2275. IX := (I1 + I2) div 2;
  2276. Recurse(I1, IX);
  2277. Recurse(IX + 1, I2);
  2278. Merge(I1, IX, IX + 1, I2);
  2279. end;
  2280. end;
  2281. var
  2282. I, Index, S: Integer;
  2283. begin
  2284. SetLength(Temp, Length(Values));
  2285. SetLength(Indexes, Length(Values));
  2286. Index := 0;
  2287. S := Math.Sign(Values[1].Point.X - Values[0].Point.X);
  2288. if S = 0 then S := 1;
  2289. Indexes[0] := 0;
  2290. // initialize bounds
  2291. Bounds.Left := Values[0].Point.X;
  2292. Bounds.Top := Values[0].Point.Y;
  2293. Bounds.Right := Bounds.Left;
  2294. Bounds.Bottom := Bounds.Top;
  2295. for I := 1 to High(Values) do
  2296. begin
  2297. if Math.Sign(Values[I].Point.X - Values[I - 1].Point.X) = -S then
  2298. begin
  2299. S := -S;
  2300. Inc(Index);
  2301. end;
  2302. // determine bounds
  2303. if Values[I].Point.X < Bounds.Left then
  2304. Bounds.Left := Values[I].Point.X;
  2305. if Values[I].Point.Y < Bounds.Top then
  2306. Bounds.Top := Values[I].Point.Y;
  2307. if Values[I].Point.X > Bounds.Right then
  2308. Bounds.Right := Values[I].Point.X;
  2309. if Values[I].Point.Y > Bounds.Bottom then
  2310. Bounds.Bottom := Values[I].Point.Y;
  2311. Indexes[I] := Index;
  2312. end;
  2313. Recurse(0, High(Values));
  2314. end;
  2315. // Note: GR32_VectorUtils contains a generic version of this function. Keep both in sync.
  2316. function DelaunayTriangulation(Points: TArrayOfColor32FloatPoint): TArrayOfTriangleVertexIndices;
  2317. var
  2318. Complete: array of Byte;
  2319. Edges: array of array [0 .. 1] of Integer;
  2320. ByteIndex, Bit: Byte;
  2321. MaxVerticesCount, EdgeCount, MaxEdgeCount, MaxTriangleCount: Integer;
  2322. // For super triangle
  2323. ScaledDeltaMax: TFloat;
  2324. Mid: TFloatPoint;
  2325. Bounds: TFloatRect;
  2326. // General Variables
  2327. SortedVertexIndices: TArrayOfInteger;
  2328. TriangleCount, VertexCount, I, J, K: Integer;
  2329. CenterX, CenterY, RadSqr: TFloat;
  2330. Inside: Boolean;
  2331. const
  2332. CSuperTriangleCount = 3; // -> super triangle
  2333. CTolerance = 0.000001;
  2334. function InCircle(Pt, Pt1, Pt2, Pt3: TFloatPoint): Boolean;
  2335. // Return TRUE if the point Pt(x, y) lies inside the circumcircle made up by
  2336. // points Pt1(x, y) Pt2(x, y) Pt3(x, y)
  2337. // The circumcircle centre is returned in (CenterX, CenterY) and the radius r
  2338. // NOTE: A point on the edge is inside the circumcircle
  2339. var
  2340. M1, M2, MX1, MY1, MX2, MY2: Double;
  2341. DeltaX, DeltaY, DeltaRadSqr, AbsY1Y2, AbsY2Y3: Double;
  2342. begin
  2343. AbsY1Y2 := Abs(Pt1.Y - Pt2.Y);
  2344. AbsY2Y3 := Abs(Pt2.Y - Pt3.Y);
  2345. // check for coincident points
  2346. if (AbsY1Y2 < CTolerance) and (AbsY2Y3 < CTolerance) then
  2347. begin
  2348. Result := False;
  2349. Exit;
  2350. end;
  2351. if AbsY1Y2 < CTolerance then
  2352. begin
  2353. M2 := -(Pt3.X - Pt2.X) / (Pt3.Y - Pt2.Y);
  2354. MX2 := (Pt2.X + Pt3.X) * 0.5;
  2355. MY2 := (Pt2.Y + Pt3.Y) * 0.5;
  2356. CenterX := (Pt2.X + Pt1.X) * 0.5;
  2357. CenterY := M2 * (CenterX - MX2) + MY2;
  2358. end
  2359. else if AbsY2Y3 < CTolerance then
  2360. begin
  2361. M1 := -(Pt2.X - Pt1.X) / (Pt2.Y - Pt1.Y);
  2362. MX1 := (Pt1.X + Pt2.X) * 0.5;
  2363. MY1 := (Pt1.Y + Pt2.Y) * 0.5;
  2364. CenterX := (Pt3.X + Pt2.X) * 0.5;
  2365. CenterY := M1 * (CenterX - MX1) + MY1;
  2366. end
  2367. else
  2368. begin
  2369. M1 := -(Pt2.X - Pt1.X) / (Pt2.Y - Pt1.Y);
  2370. M2 := -(Pt3.X - Pt2.X) / (Pt3.Y - Pt2.Y);
  2371. if Abs(M1 - M2) < CTolerance then
  2372. begin
  2373. Result := False;
  2374. Exit;
  2375. end;
  2376. MX1 := (Pt1.X + Pt2.X) * 0.5;
  2377. MX2 := (Pt2.X + Pt3.X) * 0.5;
  2378. MY1 := (Pt1.Y + Pt2.Y) * 0.5;
  2379. MY2 := (Pt2.Y + Pt3.Y) * 0.5;
  2380. CenterX := (M1 * MX1 - M2 * Mx2 + My2 - MY1) / (M1 - M2);
  2381. if (AbsY1Y2 > AbsY2Y3) then
  2382. CenterY := M1 * (CenterX - MX1) + MY1
  2383. else
  2384. CenterY := M2 * (CenterX - MX2) + MY2;
  2385. end;
  2386. DeltaX := Pt2.X - CenterX;
  2387. DeltaY := Pt2.Y - CenterY;
  2388. RadSqr := DeltaX * DeltaX + DeltaY * DeltaY;
  2389. DeltaX := Pt.X - CenterX;
  2390. DeltaY := Pt.Y - CenterY;
  2391. DeltaRadSqr := Sqr(DeltaX) + Sqr(DeltaY);
  2392. Result := (DeltaRadSqr - RadSqr) <= CTolerance;
  2393. end;
  2394. begin
  2395. VertexCount := Length(Points);
  2396. MaxVerticesCount := VertexCount + CSuperTriangleCount;
  2397. // Sort points by x value and find maximum and minimum vertex bounds.
  2398. FastMergeSortX(Points, SortedVertexIndices, Bounds);
  2399. SetLength(Points, MaxVerticesCount);
  2400. MaxTriangleCount := 2 * (MaxVerticesCount - 1);
  2401. SetLength(Result, MaxTriangleCount);
  2402. MaxEdgeCount := 3 * (MaxVerticesCount - 1);
  2403. SetLength(Edges, MaxEdgeCount);
  2404. SetLength(Complete, (MaxTriangleCount + 7) shr 3);
  2405. // This is to allow calculation of the bounding triangle
  2406. with Bounds do
  2407. begin
  2408. ScaledDeltaMax := 30 * Max(Right - Left, Bottom - Top);
  2409. Mid := FloatPoint((Left + Right) * 0.5, (Top + Bottom) * 0.5);
  2410. end;
  2411. // Set up the super triangle
  2412. // This is a triangle which encompasses all the sample points. The super
  2413. // triangle coordinates are added to the end of the vertex list. The super
  2414. // triangle is the first triangle in the triangle list.
  2415. Points[VertexCount].Point := FloatPoint(Mid.X - ScaledDeltaMax, Mid.Y - ScaledDeltaMax);
  2416. Points[VertexCount + 1].Point := FloatPoint(Mid.X + ScaledDeltaMax, Mid.Y);
  2417. Points[VertexCount + 2].Point := FloatPoint(Mid.X, Mid.Y + ScaledDeltaMax);
  2418. Result[0, 0] := VertexCount;
  2419. Result[0, 1] := VertexCount + 1;
  2420. Result[0, 2] := VertexCount + 2;
  2421. Complete[0] := 0;
  2422. TriangleCount := 1;
  2423. // Include each point one at a time into the existing mesh
  2424. for I := 0 to VertexCount - 1 do
  2425. begin
  2426. EdgeCount := 0;
  2427. // Set up the edge buffer.
  2428. // If the point [x, y] lies inside the circumcircle then the hree edges of
  2429. // that triangle are added to the edge buffer.
  2430. J := 0;
  2431. repeat
  2432. if Complete[J shr 3] and (1 shl (J and $7)) = 0 then
  2433. begin
  2434. Inside := InCircle(Points[SortedVertexIndices[I]].Point,
  2435. Points[Result[J, 0]].Point, Points[Result[J, 1]].Point,
  2436. Points[Result[J, 2]].Point);
  2437. ByteIndex := J shr 3;
  2438. Bit := 1 shl (J and $7);
  2439. if (CenterX < Points[SortedVertexIndices[I]].Point.X) and
  2440. ((Sqr(Points[SortedVertexIndices[I]].Point.X - CenterX)) > RadSqr) then
  2441. Complete[ByteIndex] := Complete[ByteIndex] or Bit
  2442. else
  2443. if Inside then
  2444. begin
  2445. Edges[EdgeCount + 0, 0] := Result[J, 0];
  2446. Edges[EdgeCount + 0, 1] := Result[J, 1];
  2447. Edges[EdgeCount + 1, 0] := Result[J, 1];
  2448. Edges[EdgeCount + 1, 1] := Result[J, 2];
  2449. Edges[EdgeCount + 2, 0] := Result[J, 2];
  2450. Edges[EdgeCount + 2, 1] := Result[J, 0];
  2451. EdgeCount := EdgeCount + 3;
  2452. Assert(EdgeCount <= MaxEdgeCount);
  2453. TriangleCount := TriangleCount - 1;
  2454. Result[J] := Result[TriangleCount];
  2455. Complete[ByteIndex] := (Complete[ByteIndex] and (not Bit))
  2456. or (Complete[TriangleCount shr 3] and Bit);
  2457. Continue;
  2458. end;
  2459. end;
  2460. J := J + 1;
  2461. until J >= TriangleCount;
  2462. // Tag multiple edges
  2463. // Note: if all triangles are specified anticlockwise then all
  2464. // interior edges are opposite pointing in direction.
  2465. for J := 0 to EdgeCount - 2 do
  2466. begin
  2467. if (Edges[J, 0] <> -1) or (Edges[J, 1] <> -1) then
  2468. begin
  2469. for K := J + 1 to EdgeCount - 1 do
  2470. begin
  2471. if (Edges[K, 0] <> -1) or (Edges[K, 1] <> -1) then
  2472. begin
  2473. if (Edges[J, 0] = Edges[K, 1]) and
  2474. (Edges[J, 1] = Edges[K, 0]) then
  2475. begin
  2476. Edges[J, 0] := -1;
  2477. Edges[J, 1] := -1;
  2478. Edges[K, 1] := -1;
  2479. Edges[K, 0] := -1;
  2480. end;
  2481. end;
  2482. end;
  2483. end;
  2484. end;
  2485. // Form new triangles for the current point.
  2486. // Skipping over any tagged edges. All edges are arranged in clockwise
  2487. // order.
  2488. for J := 0 to EdgeCount - 1 do
  2489. begin
  2490. if (Edges[J, 0] <> -1) or (Edges[J, 1] <> -1) then
  2491. begin
  2492. Result[TriangleCount, 0] := Edges[J, 0];
  2493. Result[TriangleCount, 1] := Edges[J, 1];
  2494. Result[TriangleCount, 2] := SortedVertexIndices[I];
  2495. ByteIndex := TriangleCount shr 3;
  2496. Bit := 1 shl (TriangleCount and $7);
  2497. Complete[ByteIndex] := Complete[ByteIndex] and not Bit;
  2498. Inc(TriangleCount);
  2499. Assert(TriangleCount <= MaxTriangleCount);
  2500. end;
  2501. end;
  2502. end;
  2503. // Remove triangles with supertriangle vertices
  2504. // These are triangles which have a vertex number greater than VertexCount
  2505. I := 0;
  2506. repeat
  2507. if (Result[I, 0] >= VertexCount) or
  2508. (Result[I, 1] >= VertexCount) or
  2509. (Result[I, 2] >= VertexCount) then
  2510. begin
  2511. TriangleCount := TriangleCount - 1;
  2512. Result[I, 0] := Result[TriangleCount, 0];
  2513. Result[I, 1] := Result[TriangleCount, 1];
  2514. Result[I, 2] := Result[TriangleCount, 2];
  2515. I := I - 1;
  2516. end;
  2517. I := I + 1;
  2518. until I >= TriangleCount;
  2519. SetLength(Points, Length(Points) - 3);
  2520. SetLength(Result, TriangleCount);
  2521. end;
  2522. procedure TGourandShadedDelaunayTrianglesSampler.PrepareSampling;
  2523. var
  2524. Index: Integer;
  2525. begin
  2526. inherited;
  2527. // perform triangulation
  2528. FTriangles := DelaunayTriangulation(FColorPoints);
  2529. // setup internal barycentric samplers
  2530. SetLength(FBarycentric, Length(FTriangles));
  2531. for Index := 0 to Length(FTriangles) - 1 do
  2532. begin
  2533. FBarycentric[Index] := TBarycentricGradientSampler.Create(
  2534. FColorPoints[FTriangles[Index, 0]], FColorPoints[FTriangles[Index, 1]],
  2535. FColorPoints[FTriangles[Index, 2]]);
  2536. FBarycentric[Index].PrepareSampling;
  2537. end;
  2538. SetLength(FTriangles, 0);
  2539. end;
  2540. function TGourandShadedDelaunayTrianglesSampler.GetSampleFloat(X, Y: TFloat): TColor32;
  2541. var
  2542. Index: Integer;
  2543. U, V, W: TFloat;
  2544. Dist, MinDist: TFloat;
  2545. MinIndex: Integer;
  2546. begin
  2547. if Length(FBarycentric) = 0 then
  2548. begin
  2549. Result := clRed32;
  2550. Exit;
  2551. end;
  2552. // check first barycentric interpolator
  2553. FBarycentric[0].CalculateBarycentricCoordinates(X, Y, U, V, W);
  2554. if (U >= 0) and (V >= 0) and (W >= 0) then
  2555. begin
  2556. Result := Linear3PointInterpolation(FBarycentric[0].Color[0],
  2557. FBarycentric[0].Color[1], FBarycentric[0].Color[2], U, V, W);
  2558. Exit;
  2559. end;
  2560. // calculate minimum distance
  2561. MinDist := Sqr(U - 0.5) + Sqr(V - 0.5) + Sqr(W - 0.5);
  2562. MinIndex := 0;
  2563. for Index := 1 to High(FBarycentric) do
  2564. begin
  2565. // check barycentric interpolator
  2566. FBarycentric[Index].CalculateBarycentricCoordinates(X, Y, U, V, W);
  2567. if (U >= 0) and (V >= 0) and (W >= 0) then
  2568. begin
  2569. Result := Linear3PointInterpolation(FBarycentric[Index].Color[0],
  2570. FBarycentric[Index].Color[1], FBarycentric[Index].Color[2], U, V, W);
  2571. Exit;
  2572. end;
  2573. // calculate distance and eventually update minimum distance
  2574. Dist := Sqr(U - 0.5) + Sqr(V - 0.5) + Sqr(W - 0.5);
  2575. if Dist < MinDist then
  2576. begin
  2577. MinDist := Dist;
  2578. MinIndex := Index;
  2579. end;
  2580. end;
  2581. FBarycentric[MinIndex].CalculateBarycentricCoordinates(X, Y, U, V, W);
  2582. Result := Linear3PointInterpolation(FBarycentric[MinIndex].Color[0],
  2583. FBarycentric[MinIndex].Color[1], FBarycentric[MinIndex].Color[2], U, V, W);
  2584. end;
  2585. procedure TGourandShadedDelaunayTrianglesSampler.FinalizeSampling;
  2586. var
  2587. Index: Integer;
  2588. begin
  2589. inherited;
  2590. for Index := 0 to Length(FBarycentric) - 1 do
  2591. begin
  2592. FBarycentric[Index].FinalizeSampling;
  2593. FBarycentric[Index].Free;
  2594. end;
  2595. end;
  2596. { TCustomGradientSampler }
  2597. constructor TCustomGradientSampler.Create(WrapMode: TWrapMode);
  2598. begin
  2599. inherited Create;
  2600. FGradient := TColor32Gradient.Create(clNone32);
  2601. FGradient.OnGradientColorsChanged := GradientChangedHandler;
  2602. FWrapMode := WrapMode;
  2603. WrapModeChanged;
  2604. end;
  2605. constructor TCustomGradientSampler.Create(ColorGradient: TColor32Gradient);
  2606. begin
  2607. Create;
  2608. if Assigned(ColorGradient) then
  2609. FGradient.Assign(ColorGradient);
  2610. end;
  2611. destructor TCustomGradientSampler.Destroy;
  2612. begin
  2613. FreeAndNil(FGradient);
  2614. inherited;
  2615. end;
  2616. procedure TCustomGradientSampler.AssignTo(Dest: TPersistent);
  2617. begin
  2618. if Dest is TCustomGradientSampler then
  2619. with TCustomGradientSampler(Dest) do
  2620. begin
  2621. FGradient.Assign(Self.FGradient);
  2622. FInitialized := False;
  2623. FWrapMode := Self.WrapMode;
  2624. end
  2625. else
  2626. inherited;
  2627. end;
  2628. procedure TCustomGradientSampler.SetGradient(const Value: TColor32Gradient);
  2629. begin
  2630. if not Assigned(Value) then
  2631. FGradient.ClearColorStops
  2632. else
  2633. Value.AssignTo(Self);
  2634. GradientSamplerChanged;
  2635. end;
  2636. procedure TCustomGradientSampler.SetWrapMode(const Value: TWrapMode);
  2637. begin
  2638. if FWrapMode <> Value then
  2639. begin
  2640. FWrapMode := Value;
  2641. WrapModeChanged;
  2642. end;
  2643. end;
  2644. procedure TCustomGradientSampler.WrapModeChanged;
  2645. begin
  2646. end;
  2647. function TCustomGradientSampler.GetSampleFixed(X, Y: TFixed): TColor32;
  2648. begin
  2649. Result := GetSampleFloat(X * FixedToFloat, Y * FixedToFloat);
  2650. end;
  2651. function TCustomGradientSampler.GetSampleInt(X, Y: Integer): TColor32;
  2652. begin
  2653. Result := GetSampleFloat(X, Y);
  2654. end;
  2655. procedure TCustomGradientSampler.GradientChangedHandler(Sender: TObject);
  2656. begin
  2657. GradientSamplerChanged;
  2658. end;
  2659. procedure TCustomGradientSampler.GradientSamplerChanged;
  2660. begin
  2661. FInitialized := False;
  2662. end;
  2663. procedure TCustomGradientSampler.PrepareSampling;
  2664. begin
  2665. inherited;
  2666. if not FInitialized then
  2667. begin
  2668. UpdateInternals;
  2669. FInitialized := True;
  2670. end;
  2671. end;
  2672. { TCustomGradientLookUpTableSampler }
  2673. procedure TCustomGradientLookUpTableSampler.AssignTo(Dest: TPersistent);
  2674. begin
  2675. inherited;
  2676. if Dest is TCustomGradientLookUpTableSampler then
  2677. with TCustomGradientLookUpTableSampler(Dest) do
  2678. begin
  2679. FGradientLUT.Assign(Self.FGradientLUT);
  2680. FWrapProc := Self.FWrapProc;
  2681. end
  2682. end;
  2683. constructor TCustomGradientLookUpTableSampler.Create(WrapMode: TWrapMode = wmMirror);
  2684. begin
  2685. FGradientLUT := TColor32LookupTable.Create;
  2686. inherited Create(WrapMode);
  2687. end;
  2688. destructor TCustomGradientLookUpTableSampler.Destroy;
  2689. begin
  2690. FGradientLUT.Free;
  2691. inherited;
  2692. end;
  2693. procedure TCustomGradientLookUpTableSampler.UpdateInternals;
  2694. begin
  2695. FGradient.FillColorLookUpTable(FGradientLUT);
  2696. FLutPtr := FGradientLUT.Color32Ptr;
  2697. FLutMask := FGradientLUT.Mask;
  2698. FWrapProc := GetWrapProc(WrapMode, FGradientLUT.Mask);
  2699. end;
  2700. procedure TCustomGradientLookUpTableSampler.WrapModeChanged;
  2701. begin
  2702. inherited;
  2703. FWrapProc := GetWrapProc(WrapMode);
  2704. end;
  2705. { TCustomCenterLutGradientSampler }
  2706. constructor TCustomCenterLutGradientSampler.Create(WrapMode: TWrapMode = wmMirror);
  2707. begin
  2708. inherited Create(WrapMode);
  2709. FCenter := FloatPoint(0, 0);
  2710. end;
  2711. procedure TCustomCenterLutGradientSampler.AssignTo(Dest: TPersistent);
  2712. begin
  2713. inherited;
  2714. if Dest is TCustomCenterLutGradientSampler then
  2715. TCustomCenterLutGradientSampler(Dest).FCenter := Self.FCenter;
  2716. end;
  2717. procedure TCustomCenterLutGradientSampler.Transform(var X, Y: TFloat);
  2718. begin
  2719. X := X - FCenter.X;
  2720. Y := Y - FCenter.Y;
  2721. inherited;
  2722. end;
  2723. { TConicGradientSampler }
  2724. procedure TConicGradientSampler.AssignTo(Dest: TPersistent);
  2725. begin
  2726. inherited;
  2727. if Dest is TConicGradientSampler then
  2728. TConicGradientSampler(Dest).FAngle := Self.FAngle;
  2729. end;
  2730. function TConicGradientSampler.GetSampleFloat(X, Y: TFloat): TColor32;
  2731. begin
  2732. Transform(X, Y);
  2733. Result := FLutPtr^[FWrapProc(Round(FScale * Abs(FAngle + ArcTan2(Y, X))),
  2734. FLutMask)];
  2735. end;
  2736. procedure TConicGradientSampler.UpdateInternals;
  2737. begin
  2738. inherited;
  2739. FLutMask := FGradientLUT.Mask;
  2740. FScale := FLutMask / Pi;
  2741. end;
  2742. { TCustomCenterRadiusLutGradientSampler }
  2743. constructor TCustomCenterRadiusLutGradientSampler.Create(WrapMode: TWrapMode = wmMirror);
  2744. begin
  2745. inherited Create(WrapMode);
  2746. FRadius := 1;
  2747. RadiusChanged;
  2748. end;
  2749. procedure TCustomCenterRadiusLutGradientSampler.AssignTo(Dest: TPersistent);
  2750. begin
  2751. inherited;
  2752. if Dest is TCustomCenterRadiusLutGradientSampler then
  2753. TCustomCenterRadiusLutGradientSampler(Dest).FRadius := Self.FRadius;
  2754. end;
  2755. procedure TCustomCenterRadiusLutGradientSampler.RadiusChanged;
  2756. begin
  2757. FInitialized := False;
  2758. end;
  2759. procedure TCustomCenterRadiusLutGradientSampler.SetRadius(
  2760. const Value: TFloat);
  2761. begin
  2762. if (FRadius <> Value) and (Value > 0) then
  2763. begin
  2764. FRadius := Value;
  2765. RadiusChanged;
  2766. end;
  2767. end;
  2768. { TRadialGradientSampler }
  2769. function TRadialGradientSampler.GetSampleFloat(X, Y: TFloat): TColor32;
  2770. begin
  2771. Transform(X, Y);
  2772. Result := FGradientLUT.Color32Ptr^[
  2773. FWrapProc(Round(Sqrt(Sqr(X) + Sqr(Y)) * FScale), FLutMask)];
  2774. end;
  2775. procedure TRadialGradientSampler.UpdateInternals;
  2776. begin
  2777. inherited;
  2778. FScale := FLutMask / FRadius;
  2779. end;
  2780. { TRadialExGradientSampler }
  2781. constructor TRadialExGradientSampler.Create(WrapMode: TWrapMode);
  2782. begin
  2783. inherited Create(WrapMode);
  2784. FRadius1 := 1;
  2785. FRadius2 := 1;
  2786. end;
  2787. procedure TRadialExGradientSampler.AssignTo(Dest: TPersistent);
  2788. begin
  2789. inherited;
  2790. if Dest is TRadialExGradientSampler then
  2791. begin
  2792. TRadialExGradientSampler(Dest).FCenter1 := Self.FCenter1;
  2793. TRadialExGradientSampler(Dest).FCenter2 := Self.FCenter2;
  2794. TRadialExGradientSampler(Dest).FRadius1 := Self.FRadius1;
  2795. TRadialExGradientSampler(Dest).FRadius2 := Self.FRadius2;
  2796. end;
  2797. end;
  2798. procedure TRadialExGradientSampler.SetCenter1(const Value: TFloatPoint);
  2799. begin
  2800. FCenter1 := Value;
  2801. FInitialized := False;
  2802. end;
  2803. procedure TRadialExGradientSampler.SetCenter2(const Value: TFloatPoint);
  2804. begin
  2805. FCenter2 := Value;
  2806. FInitialized := False;
  2807. end;
  2808. procedure TRadialExGradientSampler.SetRadius1(const Value: TFloat);
  2809. begin
  2810. if (FRadius1 <> Value) and (Value > 0) then
  2811. begin
  2812. FRadius1 := Value;
  2813. FInitialized := False;
  2814. end;
  2815. end;
  2816. procedure TRadialExGradientSampler.SetRadius2(const Value: TFloat);
  2817. begin
  2818. if (FRadius2 <> Value) and (Value > 0) then
  2819. begin
  2820. FRadius2 := Value;
  2821. FInitialized := False;
  2822. end;
  2823. end;
  2824. procedure TRadialExGradientSampler.Transform(var X, Y: TFloat);
  2825. begin
  2826. X := X - FCenter1.X;
  2827. Y := Y - FCenter1.Y;
  2828. inherited;
  2829. end;
  2830. procedure TRadialExGradientSampler.UpdateInternals;
  2831. begin
  2832. inherited;
  2833. // Calculate difference between the two circles
  2834. FDeltaCenter := FCenter2 - FCenter1;
  2835. FDeltaRadius := FRadius2 - FRadius1;
  2836. FPolynomA := Sqr(FDeltaCenter.x) + Sqr(FDeltaCenter.y) - Sqr(FDeltaRadius);
  2837. FPolynomAInv := 1 / FPolynomA;
  2838. FRadius12 := FRadius1 * FDeltaRadius;
  2839. FRadius1Sqr := Sqr(FRadius1);
  2840. end;
  2841. function TRadialExGradientSampler.GetSampleFloat(X, Y: TFloat): TColor32;
  2842. var
  2843. p: TFloatPoint;
  2844. B, C, D: TFloat;
  2845. Omega: TFloat;
  2846. SqrtD: TFloat;
  2847. Index: integer;
  2848. begin
  2849. Transform(X, Y);
  2850. p := FloatPoint(X, Y);
  2851. B := Dot(p, FDeltaCenter) + FRadius12;
  2852. C := Dot(p, p) - FRadius1Sqr;
  2853. if (Abs(FPolynomA) > 0.0000001) then
  2854. begin
  2855. // Discriminant
  2856. D := Sqr(B) - (FPolynomA * C);
  2857. if (D < 0) then
  2858. Exit(FGradientLUT.Color32Ptr^[FLutMask]);
  2859. SqrtD := Sqrt(D);
  2860. // First root
  2861. Omega := (B + SqrtD) * FPolynomAInv;
  2862. if (Omega < 0) or (Omega > 1) then
  2863. // Second root
  2864. Omega := (B - SqrtD) * FPolynomAInv;
  2865. end else
  2866. begin
  2867. Omega := 0.5 * C / B;
  2868. if (Omega < 0) or (Omega > 1) then
  2869. Exit(0);
  2870. end;
  2871. Index := Round(Omega * FLutMask);
  2872. Result := FGradientLUT.Color32Ptr^[FWrapProc(Index, FLutMask)];
  2873. end;
  2874. { TCustomCenterRadiusAngleLutGradientSampler }
  2875. constructor TCustomCenterRadiusAngleLutGradientSampler.Create(WrapMode: TWrapMode = wmMirror);
  2876. begin
  2877. inherited Create(WrapMode);
  2878. FAngle := 0;
  2879. FSinCos.X := 1;
  2880. FSinCos.Y := 0;
  2881. end;
  2882. procedure TCustomCenterRadiusAngleLutGradientSampler.AssignTo(
  2883. Dest: TPersistent);
  2884. begin
  2885. inherited;
  2886. if Dest is TCustomCenterRadiusAngleLutGradientSampler then
  2887. with TCustomCenterRadiusAngleLutGradientSampler(Dest) do
  2888. begin
  2889. FAngle := Self.FAngle;
  2890. FSinCos := Self.FSinCos;
  2891. end;
  2892. end;
  2893. procedure TCustomCenterRadiusAngleLutGradientSampler.RadiusChanged;
  2894. begin
  2895. inherited;
  2896. FInitialized := False;
  2897. end;
  2898. procedure TCustomCenterRadiusAngleLutGradientSampler.AngleChanged;
  2899. begin
  2900. GR32_Math.SinCos(FAngle, FSinCos.X, FSinCos.Y);
  2901. end;
  2902. procedure TCustomCenterRadiusAngleLutGradientSampler.SetAngle(
  2903. const Value: TFloat);
  2904. begin
  2905. if FAngle <> Value then
  2906. begin
  2907. FAngle := Value;
  2908. AngleChanged;
  2909. end;
  2910. end;
  2911. procedure TCustomCenterRadiusAngleLutGradientSampler.Transform(var X,
  2912. Y: TFloat);
  2913. var
  2914. Temp: TFloat;
  2915. begin
  2916. X := X - FCenter.X;
  2917. Y := Y - FCenter.Y;
  2918. Temp := X * FSinCos.X + Y * FSinCos.Y;
  2919. Y := X * FSinCos.Y - Y * FSinCos.X;
  2920. X := Temp;
  2921. end;
  2922. { TDiamondGradientSampler }
  2923. function TDiamondGradientSampler.GetSampleFloat(X, Y: TFloat): TColor32;
  2924. begin
  2925. Transform(X, Y);
  2926. Result := FLutPtr^[FWrapProc(Round(Max(Abs(X), Abs(Y)) * FScale), FLutMask)];
  2927. end;
  2928. procedure TDiamondGradientSampler.UpdateInternals;
  2929. begin
  2930. inherited;
  2931. FScale := FLutMask / FRadius;
  2932. end;
  2933. { TXGradientSampler }
  2934. function TXGradientSampler.GetSampleFloat(X, Y: TFloat): TColor32;
  2935. begin
  2936. Transform(X, Y);
  2937. Result := FLutPtr^[FWrapProc(Round(X * FScale), FLutMask)];
  2938. end;
  2939. function TXGradientSampler.GetStartPoint: TFloatPoint;
  2940. begin
  2941. Result := FCenter;
  2942. end;
  2943. function TXGradientSampler.GetEndPoint: TFloatPoint;
  2944. var
  2945. X, Y: TFloat;
  2946. begin
  2947. GR32_Math.SinCos(Angle - 0.5 * Pi, X, Y);
  2948. Result := FloatPoint(FCenter.X + X, FCenter.Y + Y);
  2949. end;
  2950. procedure TXGradientSampler.SetEndPoint(const Value: TFloatPoint);
  2951. begin
  2952. SetPoints(StartPoint, Value);
  2953. end;
  2954. procedure TXGradientSampler.SetPoints(const StartPoint, EndPoint: TFloatPoint);
  2955. begin
  2956. FCenter := StartPoint;
  2957. Radius := Distance(EndPoint, StartPoint);
  2958. Angle := 0.5 * Pi + GetAngleOfPt2FromPt1(EndPoint, StartPoint);
  2959. end;
  2960. procedure TXGradientSampler.SetStartPoint(const Value: TFloatPoint);
  2961. begin
  2962. SetPoints(Value, EndPoint);
  2963. end;
  2964. procedure TXGradientSampler.SimpleGradient(
  2965. const StartPoint: TFloatPoint; StartColor: TColor32;
  2966. const EndPoint: TFloatPoint; EndColor: TColor32);
  2967. begin
  2968. SetPoints(StartPoint, EndPoint);
  2969. if Assigned(FGradient) then
  2970. begin
  2971. FGradient.ClearColorStops;
  2972. FGradient.StartColor := StartColor;
  2973. FGradient.EndColor := EndColor;
  2974. end;
  2975. end;
  2976. procedure TXGradientSampler.UpdateInternals;
  2977. begin
  2978. inherited;
  2979. FScale := FLutMask / FRadius;
  2980. end;
  2981. { TXYGradientSampler }
  2982. function TXYGradientSampler.GetSampleFloat(X, Y: TFloat): TColor32;
  2983. begin
  2984. Transform(X, Y);
  2985. Result := FLutPtr^[FWrapProc(Round((Abs(X) * Abs(Y)) * FScale), FLutMask)];
  2986. end;
  2987. procedure TXYGradientSampler.UpdateInternals;
  2988. begin
  2989. inherited;
  2990. FScale := FLutMask / Sqr(FRadius);
  2991. end;
  2992. { TXYSqrtGradientSampler }
  2993. function TXYSqrtGradientSampler.GetSampleFloat(X, Y: TFloat): TColor32;
  2994. begin
  2995. Transform(X, Y);
  2996. Result := FLutPtr^[FWrapProc(Round(Sqrt(Abs(X) * Abs(Y)) * FScale), FLutMask)];
  2997. end;
  2998. procedure TXYSqrtGradientSampler.UpdateInternals;
  2999. begin
  3000. inherited;
  3001. FScale := FLutMask / FRadius;
  3002. end;
  3003. {TCustomGradientPolygonFiller}
  3004. constructor TCustomGradientPolygonFiller.Create;
  3005. begin
  3006. Create(TColor32Gradient.Create(clNone32));
  3007. FGradient.OnGradientColorsChanged := GradientColorsChangedHandler;
  3008. FOwnsGradient := True;
  3009. FWrapMode := wmClamp;
  3010. FWrapProc := Clamp;
  3011. end;
  3012. constructor TCustomGradientPolygonFiller.Create(ColorGradient: TColor32Gradient);
  3013. begin
  3014. FOwnsGradient := False;
  3015. FGradient := ColorGradient;
  3016. inherited Create;
  3017. FWrapMode := wmClamp;
  3018. FWrapProc := Clamp;
  3019. end;
  3020. destructor TCustomGradientPolygonFiller.Destroy;
  3021. begin
  3022. if Assigned(FGradient) then
  3023. if FOwnsGradient then
  3024. FGradient.Free
  3025. else
  3026. FGradient.OnGradientColorsChanged := nil;
  3027. inherited;
  3028. end;
  3029. procedure TCustomGradientPolygonFiller.FillLineNone(Dst: PColor32; DstX,
  3030. DstY, Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  3031. begin
  3032. // do nothing!
  3033. end;
  3034. procedure TCustomGradientPolygonFiller.FillLineSolid(Dst: PColor32; DstX,
  3035. DstY, Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  3036. begin
  3037. FillLineAlpha(Dst, AlphaValues, Length, FGradient.StartColor, CombineMode);
  3038. end;
  3039. procedure TCustomGradientPolygonFiller.GradientColorsChangedHandler(
  3040. Sender: TObject);
  3041. begin
  3042. GradientFillerChanged;
  3043. end;
  3044. procedure TCustomGradientPolygonFiller.GradientFillerChanged;
  3045. begin
  3046. // do nothing
  3047. end;
  3048. procedure TCustomGradientPolygonFiller.SetWrapMode(const Value: TWrapMode);
  3049. begin
  3050. if FWrapMode <> Value then
  3051. begin
  3052. FWrapMode := Value;
  3053. WrapModeChanged;
  3054. end;
  3055. end;
  3056. procedure TCustomGradientPolygonFiller.WrapModeChanged;
  3057. begin
  3058. FWrapProc := GetWrapProc(FWrapMode);
  3059. end;
  3060. { TBarycentricGradientPolygonFiller }
  3061. procedure TBarycentricGradientPolygonFiller.BeginRendering;
  3062. var
  3063. NormScale: TFloat;
  3064. begin
  3065. inherited;
  3066. NormScale := 1 / ((FColorPoints[1].Point.Y - FColorPoints[2].Point.Y) *
  3067. (FColorPoints[0].Point.X - FColorPoints[2].Point.X) +
  3068. (FColorPoints[2].Point.X - FColorPoints[1].Point.X) *
  3069. (FColorPoints[0].Point.Y - FColorPoints[2].Point.Y));
  3070. FDists[0].X := NormScale * (FColorPoints[2].Point.X - FColorPoints[1].Point.X);
  3071. FDists[0].Y := NormScale * (FColorPoints[1].Point.Y - FColorPoints[2].Point.Y);
  3072. FDists[1].X := NormScale * (FColorPoints[0].Point.X - FColorPoints[2].Point.X);
  3073. FDists[1].Y := NormScale * (FColorPoints[2].Point.Y - FColorPoints[0].Point.Y);
  3074. end;
  3075. procedure TBarycentricGradientPolygonFiller.FillLine(Dst: PColor32; DstX, DstY,
  3076. Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  3077. var
  3078. X: Integer;
  3079. Color32: TColor32;
  3080. Temp, DotY1, DotY2: TFloat;
  3081. Barycentric: array [0..1] of TFloat;
  3082. BlendMemEx: TBlendMemEx;
  3083. begin
  3084. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3085. Temp := DstY - FColorPoints[2].Point.Y;
  3086. DotY1 := FDists[0].X * Temp;
  3087. DotY2 := FDists[1].X * Temp;
  3088. for X := DstX to DstX + Length - 1 do
  3089. begin
  3090. Temp := (X - FColorPoints[2].Point.X);
  3091. Barycentric[0] := FDists[0].Y * Temp + DotY1;
  3092. Barycentric[1] := FDists[1].Y * Temp + DotY2;
  3093. Color32 := Linear3PointInterpolation(FColorPoints[0].Color32,
  3094. FColorPoints[1].Color32, FColorPoints[2].Color32,
  3095. Barycentric[0], Barycentric[1], 1 - Barycentric[1] - Barycentric[0]);
  3096. BlendMemEx(Color32, Dst^, AlphaValues^);
  3097. Inc(Dst);
  3098. Inc(AlphaValues);
  3099. end;
  3100. end;
  3101. function TBarycentricGradientPolygonFiller.GetColor(Index: Integer): TColor32;
  3102. begin
  3103. if Index in [0 .. 2] then
  3104. Result := FColorPoints[Index].Color32
  3105. else
  3106. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  3107. end;
  3108. function TBarycentricGradientPolygonFiller.GetColorPoint(
  3109. Index: Integer): TColor32FloatPoint;
  3110. begin
  3111. if Index in [0 .. 2] then
  3112. Result := FColorPoints[Index]
  3113. else
  3114. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  3115. end;
  3116. function TBarycentricGradientPolygonFiller.GetCount: Integer;
  3117. begin
  3118. Result := 3;
  3119. end;
  3120. function TBarycentricGradientPolygonFiller.GetFillLine: TFillLineEvent;
  3121. begin
  3122. Result := FillLine;
  3123. end;
  3124. function TBarycentricGradientPolygonFiller.GetPoint(
  3125. Index: Integer): TFloatPoint;
  3126. begin
  3127. if Index in [0 .. 2] then
  3128. Result := FColorPoints[Index].Point
  3129. else
  3130. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  3131. end;
  3132. class function TBarycentricGradientPolygonFiller.Linear3PointInterpolation(
  3133. A, B, C: TColor32; WeightA, WeightB, WeightC: Single): TColor32;
  3134. begin
  3135. Result := Linear3PointInterpolation(A, B, C, WeightA, WeightB, WeightC);
  3136. end;
  3137. procedure TBarycentricGradientPolygonFiller.SetColor(Index: Integer;
  3138. const Value: TColor32);
  3139. begin
  3140. if Index in [0 .. 2] then
  3141. FColorPoints[Index].Color32 := Value
  3142. else
  3143. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  3144. end;
  3145. procedure TBarycentricGradientPolygonFiller.SetColorPoints(
  3146. ColorPoints: TArrayOfColor32FloatPoint);
  3147. begin
  3148. if Length(ColorPoints) <> 3 then
  3149. raise Exception.Create(RCStrOnlyExactly3Point);
  3150. FColorPoints[0] := ColorPoints[0];
  3151. FColorPoints[1] := ColorPoints[1];
  3152. FColorPoints[2] := ColorPoints[2];
  3153. end;
  3154. procedure TBarycentricGradientPolygonFiller.SetColorPoint(Index: Integer;
  3155. const Value: TColor32FloatPoint);
  3156. begin
  3157. if Index in [0 .. 2] then
  3158. FColorPoints[Index] := Value
  3159. else
  3160. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  3161. end;
  3162. procedure TBarycentricGradientPolygonFiller.SetColorPoints(
  3163. Points: TArrayOfFloatPoint; Colors: TArrayOfColor32);
  3164. begin
  3165. if (Length(Points) <> 3) or (Length(Colors) <> 3) then
  3166. raise Exception.Create(RCStrOnlyExactly3Point);
  3167. FColorPoints[0] := Color32FloatPoint(Colors[0], Points[0]);
  3168. FColorPoints[1] := Color32FloatPoint(Colors[1], Points[1]);
  3169. FColorPoints[2] := Color32FloatPoint(Colors[2], Points[2]);
  3170. end;
  3171. procedure TBarycentricGradientPolygonFiller.SetPoint(Index: Integer;
  3172. const Value: TFloatPoint);
  3173. begin
  3174. if Index in [0 .. 2] then
  3175. FColorPoints[Index].Point := Value
  3176. else
  3177. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  3178. end;
  3179. procedure TBarycentricGradientPolygonFiller.SetPoints(
  3180. Points: TArrayOfFloatPoint);
  3181. var
  3182. Index: Integer;
  3183. begin
  3184. if Length(Points) <> 3 then
  3185. raise Exception.Create(RCStrOnlyExactly3Point);
  3186. for Index := 0 to 2 do
  3187. FColorPoints[Index].Point := Points[Index];
  3188. end;
  3189. { TCustomArbitrarySparsePointGradientPolygonFiller }
  3190. procedure TCustomArbitrarySparsePointGradientPolygonFiller.Add(
  3191. const Point: TFloatPoint;
  3192. Color: TColor32);
  3193. var
  3194. Index: Integer;
  3195. begin
  3196. Index := Length(FColorPoints);
  3197. SetLength(FColorPoints, Index + 1);
  3198. FColorPoints[Index].Point := Point;
  3199. FColorPoints[Index].Color32 := Color;
  3200. end;
  3201. procedure TCustomArbitrarySparsePointGradientPolygonFiller.Add(
  3202. const ColorPoint: TColor32FloatPoint);
  3203. var
  3204. Index: Integer;
  3205. begin
  3206. Index := Length(FColorPoints);
  3207. SetLength(FColorPoints, Index + 1);
  3208. FColorPoints[Index].Point := ColorPoint.Point;
  3209. FColorPoints[Index].Color32 := ColorPoint.Color32;
  3210. end;
  3211. procedure TCustomArbitrarySparsePointGradientPolygonFiller.Clear;
  3212. begin
  3213. SetLength(FColorPoints, 0);
  3214. end;
  3215. function TCustomArbitrarySparsePointGradientPolygonFiller.GetColor(
  3216. Index: Integer): TColor32;
  3217. begin
  3218. if (Index >= 0) and (Index < Length(FColorPoints)) then
  3219. Result := FColorPoints[Index].Color32
  3220. else
  3221. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  3222. end;
  3223. function TCustomArbitrarySparsePointGradientPolygonFiller.GetColorPoint(
  3224. Index: Integer): TColor32FloatPoint;
  3225. begin
  3226. if (Index >= 0) and (Index < Length(FColorPoints)) then
  3227. Result := FColorPoints[Index]
  3228. else
  3229. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  3230. end;
  3231. function TCustomArbitrarySparsePointGradientPolygonFiller.GetCount: Integer;
  3232. begin
  3233. Result := Length(FColorPoints);
  3234. end;
  3235. function TCustomArbitrarySparsePointGradientPolygonFiller.GetPoint(
  3236. Index: Integer): TFloatPoint;
  3237. begin
  3238. if (Index >= 0) and (Index < Length(FColorPoints)) then
  3239. Result := FColorPoints[Index].Point
  3240. else
  3241. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  3242. end;
  3243. procedure TCustomArbitrarySparsePointGradientPolygonFiller.SetColor(Index: Integer;
  3244. const Value: TColor32);
  3245. begin
  3246. if (Index >= 0) and (Index < Length(FColorPoints)) then
  3247. FColorPoints[Index].Color32 := Value
  3248. else
  3249. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  3250. end;
  3251. procedure TCustomArbitrarySparsePointGradientPolygonFiller.SetColorPoint(
  3252. Index: Integer; const Value: TColor32FloatPoint);
  3253. begin
  3254. if (Index >= 0) and (Index < Length(FColorPoints)) then
  3255. FColorPoints[Index] := Value
  3256. else
  3257. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  3258. end;
  3259. procedure TCustomArbitrarySparsePointGradientPolygonFiller.SetPoint(Index: Integer;
  3260. const Value: TFloatPoint);
  3261. begin
  3262. if (Index >= 0) and (Index < Length(FColorPoints)) then
  3263. FColorPoints[Index].Point := Value
  3264. else
  3265. raise Exception.CreateFmt(RCStrIndexOutOfBounds, [Index]);
  3266. end;
  3267. procedure TCustomArbitrarySparsePointGradientPolygonFiller.SetColorPoints(
  3268. ColorPoints: TArrayOfColor32FloatPoint);
  3269. var
  3270. Index: Integer;
  3271. begin
  3272. SetLength(FColorPoints, Length(ColorPoints));
  3273. for Index := 0 to High(FColorPoints) do
  3274. FColorPoints[Index] := ColorPoints[Index];
  3275. end;
  3276. procedure TCustomArbitrarySparsePointGradientPolygonFiller.SetColorPoints(
  3277. Points: TArrayOfFloatPoint; Colors: TArrayOfColor32);
  3278. var
  3279. Index: Integer;
  3280. begin
  3281. if Length(Points) <> Length(Colors) then
  3282. raise Exception.Create(RCStrPointCountMismatch);
  3283. SetLength(FColorPoints, Length(Points));
  3284. for Index := 0 to High(FColorPoints) do
  3285. begin
  3286. FColorPoints[Index].Point := Points[Index];
  3287. FColorPoints[Index].Color32 := Colors[Index];
  3288. end;
  3289. end;
  3290. procedure TCustomArbitrarySparsePointGradientPolygonFiller.SetPoints(
  3291. Points: TArrayOfFloatPoint);
  3292. var
  3293. Index: Integer;
  3294. begin
  3295. if Length(FColorPoints) <> Length(Points) then
  3296. raise Exception.Create(RCStrPointCountMismatch);
  3297. for Index := 0 to High(Points) do
  3298. FColorPoints[Index].Point := Points[Index];
  3299. end;
  3300. { TGourandShadedDelaunayTrianglesPolygonFiller }
  3301. procedure TGourandShadedDelaunayTrianglesPolygonFiller.BeginRendering;
  3302. var
  3303. Index: Integer;
  3304. begin
  3305. inherited;
  3306. // perform triangulation
  3307. FTriangles := DelaunayTriangulation(FColorPoints);
  3308. // setup internal barycentric samplers
  3309. SetLength(FBarycentric, Length(FTriangles));
  3310. for Index := 0 to Length(FTriangles) - 1 do
  3311. begin
  3312. FBarycentric[Index] := TBarycentricGradientSampler.Create(
  3313. FColorPoints[FTriangles[Index, 0]], FColorPoints[FTriangles[Index, 1]],
  3314. FColorPoints[FTriangles[Index, 2]]);
  3315. FBarycentric[Index].PrepareSampling;
  3316. end;
  3317. SetLength(FTriangles, 0);
  3318. end;
  3319. procedure TGourandShadedDelaunayTrianglesPolygonFiller.FillLine3(Dst: PColor32;
  3320. DstX, DstY, Count: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  3321. var
  3322. X: Integer;
  3323. BlendMemEx: TBlendMemEx;
  3324. begin
  3325. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3326. for X := DstX to DstX + Count - 1 do
  3327. begin
  3328. BlendMemEx(FBarycentric[0].GetSampleFloat(X, DstY), Dst^, AlphaValues^);
  3329. Inc(Dst);
  3330. Inc(AlphaValues);
  3331. end;
  3332. end;
  3333. procedure TGourandShadedDelaunayTrianglesPolygonFiller.FillLine(Dst: PColor32;
  3334. DstX, DstY, Count: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  3335. var
  3336. Index: Integer;
  3337. U, V, W: TFloat;
  3338. Dist, MinDist: TFloat;
  3339. MinIndex: Integer;
  3340. X: Integer;
  3341. Color32: TColor32;
  3342. BlendMemEx: TBlendMemEx;
  3343. label
  3344. DrawColor;
  3345. begin
  3346. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3347. for X := DstX to DstX + Count - 1 do
  3348. begin
  3349. // check first barycentric interpolator
  3350. FBarycentric[0].CalculateBarycentricCoordinates(X, DstY, U, V, W);
  3351. if (U >= 0) and (V >= 0) and (W >= 0) then
  3352. begin
  3353. Color32 := Linear3PointInterpolation(FBarycentric[0].Color[0],
  3354. FBarycentric[0].Color[1], FBarycentric[0].Color[2], U, V, W);
  3355. goto DrawColor;
  3356. end;
  3357. // calculate minimum distance
  3358. MinDist := Sqr(U - 0.5) + Sqr(V - 0.5) + Sqr(W - 0.5);
  3359. MinIndex := 0;
  3360. for Index := 1 to High(FBarycentric) do
  3361. begin
  3362. // check barycentric interpolator
  3363. FBarycentric[Index].CalculateBarycentricCoordinates(X, DstY, U, V, W);
  3364. if (U >= 0) and (V >= 0) and (W >= 0) then
  3365. begin
  3366. Color32 := Linear3PointInterpolation(FBarycentric[Index].Color[0],
  3367. FBarycentric[Index].Color[1], FBarycentric[Index].Color[2], U, V, W);
  3368. goto DrawColor;
  3369. end;
  3370. // calculate distance and eventually update minimum distance
  3371. Dist := Sqr(U - 0.5) + Sqr(V - 0.5) + Sqr(W - 0.5);
  3372. if Dist < MinDist then
  3373. begin
  3374. MinDist := Dist;
  3375. MinIndex := Index;
  3376. end;
  3377. end;
  3378. FBarycentric[MinIndex].CalculateBarycentricCoordinates(X, DstY, U, V, W);
  3379. Color32 := Linear3PointInterpolation(FBarycentric[MinIndex].Color[0],
  3380. FBarycentric[MinIndex].Color[1], FBarycentric[MinIndex].Color[2], U, V, W);
  3381. DrawColor:
  3382. BlendMemEx(Color32, Dst^, AlphaValues^);
  3383. Inc(Dst);
  3384. Inc(AlphaValues);
  3385. end;
  3386. end;
  3387. function TGourandShadedDelaunayTrianglesPolygonFiller.GetFillLine: TFillLineEvent;
  3388. begin
  3389. case Count of
  3390. 0 .. 2:
  3391. raise Exception.Create('Too few color points available');
  3392. 3:
  3393. Result := FillLine3;
  3394. else
  3395. Result := FillLine;
  3396. end;
  3397. end;
  3398. { TCustomGradientLookupTablePolygonFiller }
  3399. constructor TCustomGradientLookupTablePolygonFiller.Create;
  3400. begin
  3401. inherited Create;
  3402. FUseLookUpTable := True;
  3403. // eventually create lookup table if not specified otherwise
  3404. if not Assigned(FGradientLUT) then
  3405. begin
  3406. FGradientLUT := TColor32LookupTable.Create;
  3407. FGradientLUT.OnOrderChanged := LookUpTableChangedHandler;
  3408. FOwnsLUT := True;
  3409. end;
  3410. end;
  3411. constructor TCustomGradientLookupTablePolygonFiller.Create(
  3412. LookupTable: TColor32LookupTable);
  3413. begin
  3414. if not Assigned(LookupTable) then
  3415. raise Exception.Create(RCStrNoLookupTablePassed);
  3416. FGradientLUT := LookupTable;
  3417. FUseLookUpTable := True;
  3418. FOwnsLUT := False;
  3419. FGradient := nil;
  3420. FOwnsGradient := False;
  3421. FWrapMode := wmClamp;
  3422. FWrapProc := Clamp;
  3423. end;
  3424. destructor TCustomGradientLookupTablePolygonFiller.Destroy;
  3425. begin
  3426. if FOwnsLUT and Assigned(FGradientLUT) then
  3427. FGradientLUT.Free;
  3428. inherited;
  3429. end;
  3430. function TCustomGradientLookupTablePolygonFiller.GetLUTNeedsUpdate: Boolean;
  3431. begin
  3432. Result := FLUTNeedsUpdate or (FUseLookUpTable and (not FOwnsLUT));
  3433. end;
  3434. procedure TCustomGradientLookupTablePolygonFiller.GradientFillerChanged;
  3435. begin
  3436. FLUTNeedsUpdate := True;
  3437. end;
  3438. procedure TCustomGradientLookupTablePolygonFiller.SetGradientLUT(
  3439. const Value: TColor32LookupTable);
  3440. begin
  3441. if FGradientLUT <> Value then
  3442. begin
  3443. // check whether current look up table is owned and eventually free it
  3444. if FOwnsLUT then
  3445. FGradientLUT.Free;
  3446. // set link to passed look up table
  3447. FGradientLUT := Value;
  3448. // if no look up table is specified don't use a look up table
  3449. if not Assigned(FGradientLUT) then
  3450. UseLookUpTable := False;
  3451. end;
  3452. end;
  3453. procedure TCustomGradientLookupTablePolygonFiller.SetUseLookUpTable(
  3454. const Value: Boolean);
  3455. begin
  3456. if FUseLookUpTable <> Value then
  3457. begin
  3458. FUseLookUpTable := Value;
  3459. UseLookUpTableChanged;
  3460. end;
  3461. end;
  3462. procedure TCustomGradientLookupTablePolygonFiller.UseLookUpTableChanged;
  3463. begin
  3464. if FUseLookUpTable then
  3465. if not Assigned(FGradientLUT) then
  3466. begin
  3467. FGradientLUT := TColor32LookupTable.Create;
  3468. FGradientLUT.OnOrderChanged := LookUpTableChangedHandler;
  3469. FOwnsLUT := True;
  3470. end
  3471. else
  3472. else
  3473. if FOwnsLUT then
  3474. begin
  3475. if Assigned(FGradientLUT) then
  3476. FreeAndNil(FGradientLUT);
  3477. FOwnsLUT := False;
  3478. end
  3479. end;
  3480. procedure TCustomGradientLookupTablePolygonFiller.LookUpTableChangedHandler(Sender: TObject);
  3481. begin
  3482. FLUTNeedsUpdate := True;
  3483. end;
  3484. { TCustomLinearGradientPolygonFiller }
  3485. procedure TCustomLinearGradientPolygonFiller.SetStartPoint(
  3486. const Value: TFloatPoint);
  3487. begin
  3488. if (FStartPoint.X <> Value.X) or (FStartPoint.Y <> Value.Y) then
  3489. begin
  3490. FStartPoint := Value;
  3491. StartPointChanged;
  3492. end;
  3493. end;
  3494. procedure TCustomLinearGradientPolygonFiller.SimpleGradient(
  3495. const StartPoint: TFloatPoint; StartColor: TColor32;
  3496. const EndPoint: TFloatPoint; EndColor: TColor32);
  3497. begin
  3498. SetPoints(StartPoint, EndPoint);
  3499. if Assigned(FGradient) then
  3500. begin
  3501. FGradient.ClearColorStops;
  3502. FGradient.StartColor := StartColor;
  3503. FGradient.EndColor := EndColor;
  3504. end;
  3505. end;
  3506. procedure TCustomLinearGradientPolygonFiller.SimpleGradientX(
  3507. const StartX: TFloat; StartColor: TColor32; const EndX: TFloat;
  3508. EndColor: TColor32);
  3509. begin
  3510. SimpleGradient(
  3511. FloatPoint(StartX, 0), StartColor,
  3512. FloatPoint(EndX, 0), EndColor);
  3513. end;
  3514. procedure TCustomLinearGradientPolygonFiller.SimpleGradientY(
  3515. const StartY: TFloat; StartColor: TColor32; const EndY: TFloat;
  3516. EndColor: TColor32);
  3517. begin
  3518. SimpleGradient(
  3519. FloatPoint(0, StartY), StartColor,
  3520. FloatPoint(0, EndY), EndColor);
  3521. end;
  3522. procedure TCustomLinearGradientPolygonFiller.SetEndPoint(
  3523. const Value: TFloatPoint);
  3524. begin
  3525. if (FEndPoint.X <> Value.X) or (FEndPoint.Y <> Value.Y) then
  3526. begin
  3527. FEndPoint := Value;
  3528. EndPointChanged;
  3529. end;
  3530. end;
  3531. procedure TCustomLinearGradientPolygonFiller.SetPoints(const StartPoint,
  3532. EndPoint: TFloatPoint);
  3533. begin
  3534. FStartPoint := StartPoint;
  3535. FEndPoint := EndPoint;
  3536. GradientFillerChanged;
  3537. UpdateIncline;
  3538. end;
  3539. procedure TCustomLinearGradientPolygonFiller.StartPointChanged;
  3540. begin
  3541. GradientFillerChanged;
  3542. UpdateIncline;
  3543. end;
  3544. procedure TCustomLinearGradientPolygonFiller.EndPointChanged;
  3545. begin
  3546. GradientFillerChanged;
  3547. UpdateIncline;
  3548. end;
  3549. procedure TCustomLinearGradientPolygonFiller.UpdateIncline;
  3550. begin
  3551. if (FEndPoint.X - FStartPoint.X) <> 0 then
  3552. FIncline := (FEndPoint.Y - FStartPoint.Y) / (FEndPoint.X - FStartPoint.X)
  3553. else
  3554. if (FEndPoint.Y - FStartPoint.Y) <> 0 then
  3555. FIncline := 1 / (FEndPoint.Y - FStartPoint.Y);
  3556. end;
  3557. { TLinearGradientPolygonFiller }
  3558. constructor TLinearGradientPolygonFiller.Create(ColorGradient: TColor32Gradient);
  3559. begin
  3560. Create(ColorGradient, True);
  3561. end;
  3562. constructor TLinearGradientPolygonFiller.Create(ColorGradient: TColor32Gradient; UseLookupTable: Boolean);
  3563. begin
  3564. // create lookup table (and set 'own' & 'use' flags)
  3565. FGradientLUT := TColor32LookupTable.Create;
  3566. FGradientLUT.OnOrderChanged := LookUpTableChangedHandler;
  3567. FOwnsLUT := True;
  3568. FUseLookUpTable := UseLookupTable;
  3569. inherited Create(ColorGradient);
  3570. FGradient.OnGradientColorsChanged := GradientColorsChangedHandler;
  3571. end;
  3572. function TLinearGradientPolygonFiller.ColorStopToScanLine(Index, Y: Integer): TFloat;
  3573. var
  3574. Offset: array [0 .. 1] of TFloat;
  3575. begin
  3576. Offset[0] := FGradient.FGradientColors[Index].Offset;
  3577. Offset[1] := 1.0 - Offset[0];
  3578. Result :=
  3579. Offset[1] * FStartPoint.X +
  3580. Offset[0] * FEndPoint.X +
  3581. FIncline * (
  3582. Offset[1] * (FStartPoint.Y - Y) +
  3583. Offset[0] * (FEndPoint.Y - Y)
  3584. );
  3585. end;
  3586. procedure TLinearGradientPolygonFiller.UseLookUpTableChanged;
  3587. begin
  3588. inherited;
  3589. // Perfect gradients are only implemented for WrapMode = wmClamp
  3590. if (not FUseLookUpTable) and (WrapMode <> wmClamp) then
  3591. WrapMode := wmClamp;
  3592. end;
  3593. procedure TLinearGradientPolygonFiller.WrapModeChanged;
  3594. begin
  3595. inherited;
  3596. // Perfect gradients are only implemented for WrapMode = wmClamp
  3597. if (not FUseLookUpTable) and (WrapMode <> wmClamp) then
  3598. UseLookUpTable := True;
  3599. end;
  3600. function TLinearGradientPolygonFiller.GetFillLine: TFillLineEvent;
  3601. var
  3602. GradientCount: Integer;
  3603. begin
  3604. if (FGradient <> nil) then
  3605. GradientCount := FGradient.GradientCount
  3606. else
  3607. GradientCount := FGradientLUT.Size;
  3608. case GradientCount of
  3609. 0:
  3610. Result := FillLineNone;
  3611. 1:
  3612. Result := FillLineSolid;
  3613. else
  3614. if FUseLookUpTable then
  3615. begin
  3616. if (FWrapMode = wmClamp) then
  3617. begin
  3618. if FStartPoint.X = FEndPoint.X then
  3619. if FStartPoint.Y = FEndPoint.Y then
  3620. Result := FillLineVerticalPadExtreme
  3621. else
  3622. Result := FillLineVerticalPad
  3623. else
  3624. if FStartPoint.X < FEndPoint.X then
  3625. Result := FillLineHorizontalPadPos
  3626. else
  3627. Result := FillLineHorizontalPadNeg;
  3628. end else
  3629. // wmMirror, wmRepeat, wmReflect
  3630. begin
  3631. if FStartPoint.X = FEndPoint.X then
  3632. Result := FillLineVerticalWrap
  3633. else
  3634. if FStartPoint.X < FEndPoint.X then
  3635. Result := FillLineHorizontalWrapPos
  3636. else
  3637. Result := FillLineHorizontalWrapNeg;
  3638. end;
  3639. end else
  3640. if FStartPoint.X = FEndPoint.X then
  3641. begin
  3642. if FStartPoint.Y = FEndPoint.Y then
  3643. Result := FillLineVerticalExtreme
  3644. else
  3645. Result := FillLineVertical;
  3646. end else
  3647. if FStartPoint.X < FEndPoint.X then
  3648. Result := FillLinePositive
  3649. else
  3650. Result := FillLineNegative;
  3651. end;
  3652. end;
  3653. procedure TLinearGradientPolygonFiller.FillLineVertical(Dst: PColor32; DstX,
  3654. DstY, Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  3655. var
  3656. X: Integer;
  3657. Color32: TColor32;
  3658. BlendMemEx: TBlendMemEx;
  3659. begin
  3660. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3661. Color32 := FGradient.GetColorAt((DstY - FStartPoint.Y) * FIncline);
  3662. for X := DstX to DstX + Length - 1 do
  3663. begin
  3664. BlendMemEx(Color32, Dst^, AlphaValues^);
  3665. Inc(Dst);
  3666. Inc(AlphaValues);
  3667. end;
  3668. end;
  3669. procedure TLinearGradientPolygonFiller.FillLineVerticalExtreme(Dst: PColor32;
  3670. DstX, DstY, Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  3671. var
  3672. X: Integer;
  3673. Color32: TColor32;
  3674. BlendMemEx: TBlendMemEx;
  3675. begin
  3676. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3677. if DstY < FStartPoint.Y then
  3678. Color32 := FGradient.StartColor
  3679. else
  3680. Color32 := FGradient.EndColor;
  3681. for X := DstX to DstX + Length - 1 do
  3682. begin
  3683. BlendMemEx(Color32, Dst^, AlphaValues^);
  3684. Inc(Dst);
  3685. Inc(AlphaValues);
  3686. end;
  3687. end;
  3688. procedure TLinearGradientPolygonFiller.FillLinePositive(Dst: PColor32; DstX,
  3689. DstY, Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  3690. var
  3691. X, Index: Integer;
  3692. IntScale, IntValue: Integer;
  3693. Colors: array [0..1] of TColor32;
  3694. Scale: TFloat;
  3695. XOffset: array [0..1] of TFloat;
  3696. XPos: array [0..2] of Integer;
  3697. BlendMemEx: TBlendMemEx;
  3698. begin
  3699. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3700. // set first offset/position
  3701. XOffset[0] := ColorStopToScanLine(0, DstY);
  3702. XPos[0] := Round(XOffset[0]);
  3703. XPos[2] := DstX + Length;
  3704. // check if only a solid start color should be drawn.
  3705. if XPos[0] >= XPos[2] - 1 then
  3706. begin
  3707. FillLineSolid(Dst, DstX, DstY, Length, AlphaValues, CombineMode);
  3708. Exit;
  3709. end;
  3710. // set start color
  3711. Colors[0] := FGradient.FGradientColors[0].Color32;
  3712. // eventually draw solid start color
  3713. FillLineAlpha(Dst, AlphaValues, XPos[0] - DstX, Colors[0], CombineMode);
  3714. Index := 1;
  3715. repeat
  3716. // set start position to be at least DstX
  3717. if XPos[0] < DstX then
  3718. XPos[0] := DstX;
  3719. // set destination color and offset
  3720. Colors[1] := FGradient.FGradientColors[Index].Color32;
  3721. XOffset[1] := ColorStopToScanLine(Index, DstY);
  3722. // calculate destination pixel position
  3723. XPos[1] := Round(XOffset[1]);
  3724. if XPos[1] > XPos[2] then
  3725. XPos[1] := XPos[2];
  3726. // check whether
  3727. if XPos[1] > XPos[0] then
  3728. begin
  3729. Scale := 1 / (XOffset[1] - XOffset[0]);
  3730. IntScale := Round($7FFFFFFF * Scale);
  3731. IntValue := Round($7FFFFFFF * (XPos[0] - XOffset[0]) * Scale);
  3732. for X := XPos[0] to XPos[1] - 1 do
  3733. begin
  3734. BlendMemEx(CombineReg(Colors[1], Colors[0], IntValue shr 23),
  3735. Dst^, AlphaValues^);
  3736. IntValue := IntValue + IntScale;
  3737. Inc(Dst);
  3738. Inc(AlphaValues);
  3739. end;
  3740. end;
  3741. // check whether further drawing is still necessary
  3742. if XPos[1] = XPos[2] then
  3743. Exit;
  3744. Inc(Index);
  3745. XPos[0] := XPos[1];
  3746. XOffset[0] := XOffset[1];
  3747. Colors[0] := Colors[1];
  3748. until (Index = FGradient.GradientCount);
  3749. if XPos[0] < DstX then
  3750. XPos[0] := DstX;
  3751. FillLineAlpha(Dst, AlphaValues, XPos[2] - XPos[0], Colors[0], CombineMode);
  3752. end;
  3753. procedure TLinearGradientPolygonFiller.FillLineNegative(Dst: PColor32; DstX,
  3754. DstY, Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  3755. var
  3756. X, Index: Integer;
  3757. IntScale, IntValue: Integer;
  3758. Colors: array [0..1] of TColor32;
  3759. Scale: TFloat;
  3760. XOffset: array [0..1] of TFloat;
  3761. XPos: array [0..2] of Integer;
  3762. BlendMemEx: TBlendMemEx;
  3763. begin
  3764. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3765. Index := FGradient.GradientCount - 1;
  3766. // set first offset/position
  3767. XOffset[0] := ColorStopToScanLine(Index, DstY);
  3768. XPos[0] := Round(XOffset[0]);
  3769. XPos[2] := DstX + Length;
  3770. // set start color
  3771. Colors[0] := FGradient.FGradientColors[Index].Color32;
  3772. // check if only a solid start color should be drawn.
  3773. if XPos[0] >= XPos[2] - 1 then
  3774. begin
  3775. FillLineAlpha(Dst, AlphaValues, Length, Colors[0], CombineMode);
  3776. Exit;
  3777. end;
  3778. // eventually draw solid start color
  3779. FillLineAlpha(Dst, AlphaValues, XPos[0] - DstX, Colors[0], CombineMode);
  3780. Dec(Index);
  3781. repeat
  3782. // set start position to be at least DstX
  3783. if XPos[0] < DstX then
  3784. XPos[0] := DstX;
  3785. // set destination color and offset
  3786. Colors[1] := FGradient.FGradientColors[Index].Color32;
  3787. XOffset[1] := ColorStopToScanLine(Index, DstY);
  3788. // calculate destination pixel position
  3789. XPos[1] := Round(XOffset[1]);
  3790. if XPos[1] > XPos[2] then
  3791. XPos[1] := XPos[2];
  3792. // check whether next color needs to be drawn
  3793. if XPos[1] > XPos[0] then
  3794. begin
  3795. Scale := 1 / (XOffset[1] - XOffset[0]);
  3796. IntScale := Round($7FFFFFFF * Scale);
  3797. IntValue := Round($7FFFFFFF * (XPos[0] - XOffset[0]) * Scale);
  3798. for X := XPos[0] to XPos[1] - 1 do
  3799. begin
  3800. BlendMemEx(CombineReg(Colors[1], Colors[0], IntValue shr 23),
  3801. Dst^, AlphaValues^);
  3802. IntValue := IntValue + IntScale;
  3803. Inc(Dst);
  3804. Inc(AlphaValues);
  3805. end;
  3806. end;
  3807. // check whether further drawing is still necessary
  3808. if XPos[1] = XPos[2] then
  3809. Exit;
  3810. Dec(Index);
  3811. XPos[0] := XPos[1];
  3812. XOffset[0] := XOffset[1];
  3813. Colors[0] := Colors[1];
  3814. until (Index < 0);
  3815. if XPos[0] < DstX then
  3816. XPos[0] := DstX;
  3817. FillLineAlpha(Dst, AlphaValues, XPos[2] - XPos[0], Colors[0], CombineMode);
  3818. end;
  3819. procedure TLinearGradientPolygonFiller.FillLineVerticalPad(
  3820. Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32;
  3821. CombineMode: TCombineMode);
  3822. var
  3823. X: Integer;
  3824. Color32: TColor32;
  3825. BlendMemEx: TBlendMemEx;
  3826. begin
  3827. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3828. Color32 := FGradientLUT.Color32Ptr^[FWrapProc(Round(FGradientLUT.Mask *
  3829. (DstY - FStartPoint.Y) * FIncline), FGradientLUT.Mask)];
  3830. for X := DstX to DstX + Length - 1 do
  3831. begin
  3832. BlendMemEx(Color32, Dst^, AlphaValues^);
  3833. Inc(Dst);
  3834. Inc(AlphaValues);
  3835. end;
  3836. end;
  3837. procedure TLinearGradientPolygonFiller.FillLineVerticalPadExtreme(
  3838. Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32;
  3839. CombineMode: TCombineMode);
  3840. var
  3841. X: Integer;
  3842. Color32: TColor32;
  3843. BlendMemEx: TBlendMemEx;
  3844. begin
  3845. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3846. if DstY < FStartPoint.Y then
  3847. Color32 := FGradientLUT.Color32Ptr^[0]
  3848. else
  3849. Color32 := FGradientLUT.Color32Ptr^[FGradientLUT.Mask];
  3850. for X := DstX to DstX + Length - 1 do
  3851. begin
  3852. BlendMemEx(Color32, Dst^, AlphaValues^);
  3853. Inc(Dst);
  3854. Inc(AlphaValues);
  3855. end;
  3856. end;
  3857. procedure TLinearGradientPolygonFiller.FillLineVerticalWrap(
  3858. Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32;
  3859. CombineMode: TCombineMode);
  3860. var
  3861. X: Integer;
  3862. Color32: TColor32;
  3863. BlendMemEx: TBlendMemEx;
  3864. begin
  3865. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3866. X := Round(FGradientLUT.Mask * (DstY - FStartPoint.Y) * FIncline);
  3867. Color32 := FGradientLUT.Color32Ptr^[FWrapProc(X, Integer(FGradientLUT.Mask))];
  3868. for X := DstX to DstX + Length - 1 do
  3869. begin
  3870. BlendMemEx(Color32, Dst^, AlphaValues^);
  3871. Inc(Dst);
  3872. Inc(AlphaValues);
  3873. end;
  3874. end;
  3875. procedure TLinearGradientPolygonFiller.FillLineHorizontalPadPos(
  3876. Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32;
  3877. CombineMode: TCombineMode);
  3878. var
  3879. X, XPos, Count, Mask: Integer;
  3880. ColorLUT: PColor32Array;
  3881. Scale: TFloat;
  3882. XOffset: array [0..1] of TFloat;
  3883. BlendMemEx: TBlendMemEx;
  3884. begin
  3885. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3886. XOffset[0] := FStartPoint.X + (FStartPoint.Y - DstY) * FIncline;
  3887. XOffset[1] := FEndPoint.X + (FEndPoint.Y - DstY) * FIncline;
  3888. XPos := Round(XOffset[0]);
  3889. Count := Round(XOffset[1]) - XPos;
  3890. ColorLUT := FGradientLUT.Color32Ptr;
  3891. // check if only a solid start color should be drawn.
  3892. if XPos >= DstX + Length then
  3893. begin
  3894. FillLineAlpha(Dst, AlphaValues, Length, ColorLUT^[0], CombineMode);
  3895. Exit;
  3896. end;
  3897. Mask := FGradientLUT.Mask;
  3898. // check if only a solid end color should be drawn.
  3899. if XPos + Count < DstX then
  3900. begin
  3901. FillLineAlpha(Dst, AlphaValues, Length, ColorLUT^[Mask], CombineMode);
  3902. Exit;
  3903. end;
  3904. Scale := Mask / (XOffset[1] - XOffset[0]);
  3905. for X := DstX to DstX + Length - 1 do
  3906. begin
  3907. BlendMemEx(ColorLUT^[FWrapProc(Round((X - XOffset[0]) * Scale), Mask)], Dst^, AlphaValues^);
  3908. Inc(Dst);
  3909. Inc(AlphaValues);
  3910. end;
  3911. end;
  3912. procedure TLinearGradientPolygonFiller.FillLineHorizontalPadNeg(
  3913. Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32;
  3914. CombineMode: TCombineMode);
  3915. var
  3916. X, XPos, Count, Mask: Integer;
  3917. ColorLUT: PColor32Array;
  3918. Scale: TFloat;
  3919. XOffset: array [0..1] of TFloat;
  3920. BlendMemEx: TBlendMemEx;
  3921. begin
  3922. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3923. XOffset[0] := FEndPoint.X + (FEndPoint.Y - DstY) * FIncline;
  3924. XOffset[1] := FStartPoint.X + (FStartPoint.Y - DstY) * FIncline;
  3925. XPos := Round(XOffset[0]);
  3926. Count := Round(XOffset[1]) - XPos;
  3927. Mask := FGradientLUT.Mask;
  3928. ColorLUT := FGradientLUT.Color32Ptr;
  3929. // check if only a solid start color should be drawn.
  3930. if XPos >= DstX + Length then
  3931. begin
  3932. FillLineAlpha(Dst, AlphaValues, Length, ColorLUT^[Mask], CombineMode);
  3933. Exit;
  3934. end;
  3935. // check if only a solid end color should be drawn.
  3936. if XPos + Count < DstX then
  3937. begin
  3938. FillLineAlpha(Dst, AlphaValues, Length, ColorLUT^[0], CombineMode);
  3939. Exit;
  3940. end;
  3941. Scale := Mask / (XOffset[1] - XOffset[0]);
  3942. for X := DstX to DstX + Length - 1 do
  3943. begin
  3944. BlendMemEx(ColorLUT^[FWrapProc(Round((XOffset[1] - X) * Scale), Mask)], Dst^, AlphaValues^);
  3945. Inc(Dst);
  3946. Inc(AlphaValues);
  3947. end;
  3948. end;
  3949. procedure TLinearGradientPolygonFiller.FillLineHorizontalWrapPos(
  3950. Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32;
  3951. CombineMode: TCombineMode);
  3952. var
  3953. X, Index, Mask: Integer;
  3954. ColorLUT: PColor32Array;
  3955. Scale: TFloat;
  3956. XOffset: array [0..1] of TFloat;
  3957. BlendMemEx: TBlendMemEx;
  3958. begin
  3959. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3960. XOffset[0] := FStartPoint.X + (FStartPoint.Y - DstY) * FIncline;
  3961. XOffset[1] := FEndPoint.X + (FEndPoint.Y - DstY) * FIncline;
  3962. Mask := Integer(FGradientLUT.Mask);
  3963. ColorLUT := FGradientLUT.Color32Ptr;
  3964. Scale := Mask / (XOffset[1] - XOffset[0]);
  3965. for X := DstX to DstX + Length - 1 do
  3966. begin
  3967. Index := Round((X - XOffset[0]) * Scale);
  3968. BlendMemEx(ColorLUT^[FWrapProc(Index, Mask)], Dst^, AlphaValues^);
  3969. Inc(Dst);
  3970. Inc(AlphaValues);
  3971. end;
  3972. end;
  3973. procedure TLinearGradientPolygonFiller.FillLineHorizontalWrapNeg(
  3974. Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32;
  3975. CombineMode: TCombineMode);
  3976. var
  3977. X, Index, Mask: Integer;
  3978. ColorLUT: PColor32Array;
  3979. Scale: TFloat;
  3980. XOffset: array [0..1] of TFloat;
  3981. BlendMemEx: TBlendMemEx;
  3982. begin
  3983. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  3984. XOffset[0] := FEndPoint.X + (FEndPoint.Y - DstY) * FIncline;
  3985. XOffset[1] := FStartPoint.X + (FStartPoint.Y - DstY) * FIncline;
  3986. Mask := Integer(FGradientLUT.Mask);
  3987. ColorLUT := FGradientLUT.Color32Ptr;
  3988. Scale := Mask / (XOffset[1] - XOffset[0]);
  3989. for X := DstX to DstX + Length - 1 do
  3990. begin
  3991. Index := Round((XOffset[1] - X) * Scale);
  3992. BlendMemEx(ColorLUT^[FWrapProc(Index, Mask)], Dst^, AlphaValues^);
  3993. Inc(Dst);
  3994. Inc(AlphaValues);
  3995. end;
  3996. end;
  3997. procedure TLinearGradientPolygonFiller.BeginRendering;
  3998. begin
  3999. if LookUpTableNeedsUpdate then
  4000. begin
  4001. if FUseLookUpTable then
  4002. begin
  4003. if not Assigned(FGradientLUT) then
  4004. raise Exception.Create(RCStrNoTColor32LookupTable);
  4005. if Assigned(FGradient) then
  4006. FGradient.FillColorLookUpTable(FGradientLUT);
  4007. end
  4008. else
  4009. if not Assigned(FGradient) then
  4010. raise Exception.Create(RCStrNoTColor32Gradient);
  4011. inherited;
  4012. end;
  4013. end;
  4014. { TCustomRadialGradientPolygonFiller }
  4015. procedure TCustomRadialGradientPolygonFiller.SetEllipseBounds(
  4016. const Value: TFloatRect);
  4017. begin
  4018. if (FEllipseBounds.Left <> Value.Left) or (FEllipseBounds.Top <> Value.Top) or
  4019. (FEllipseBounds.Right <> Value.Right) or
  4020. (FEllipseBounds.Bottom <> Value.Bottom) then
  4021. begin
  4022. FEllipseBounds := Value;
  4023. EllipseBoundsChanged;
  4024. end;
  4025. end;
  4026. { TRadialGradientPolygonFiller }
  4027. constructor TRadialGradientPolygonFiller.Create(Radius: TFloatPoint);
  4028. begin
  4029. inherited Create;
  4030. FRadius := Radius;
  4031. UpdateEllipseBounds;
  4032. UpdateRadiusScale;
  4033. end;
  4034. constructor TRadialGradientPolygonFiller.Create(Radius, Center: TFloatPoint);
  4035. begin
  4036. inherited Create;
  4037. FRadius := Radius;
  4038. FCenter := Center;
  4039. UpdateEllipseBounds;
  4040. UpdateRadiusScale;
  4041. end;
  4042. constructor TRadialGradientPolygonFiller.Create(BoundingBox: TFloatRect);
  4043. begin
  4044. Create(FloatPoint(0.5 * (BoundingBox.Right - BoundingBox.Left),
  4045. 0.5 * (BoundingBox.Bottom - BoundingBox.Top)),
  4046. FloatPoint(0.5 * (BoundingBox.Right + BoundingBox.Left),
  4047. 0.5 * (BoundingBox.Bottom + BoundingBox.Top)));
  4048. end;
  4049. procedure TRadialGradientPolygonFiller.EllipseBoundsChanged;
  4050. begin
  4051. with FEllipseBounds do
  4052. begin
  4053. FCenter := FloatPoint((Left + Right) * 0.5, (Top + Bottom) * 0.5);
  4054. FRadius.X := System.Round((Right - Left) * 0.5);
  4055. FRadius.Y := System.Round((Bottom - Top) * 0.5);
  4056. end;
  4057. UpdateRadiusScale;
  4058. end;
  4059. procedure TRadialGradientPolygonFiller.SetCenter(const Value: TFloatPoint);
  4060. begin
  4061. if (FCenter.X <> Value.X) or (FCenter.Y <> Value.Y) then
  4062. begin
  4063. FCenter := Value;
  4064. UpdateEllipseBounds;
  4065. end;
  4066. end;
  4067. procedure TRadialGradientPolygonFiller.SetRadius(const Value: TFloatPoint);
  4068. begin
  4069. if (FRadius.X <> Value.X) or (FRadius.Y <> Value.Y) then
  4070. begin
  4071. FRadius := Value;
  4072. UpdateRadiusScale;
  4073. UpdateEllipseBounds;
  4074. end;
  4075. end;
  4076. procedure TRadialGradientPolygonFiller.UpdateEllipseBounds;
  4077. begin
  4078. with FEllipseBounds do
  4079. begin
  4080. Left := FCenter.X - FRadius.X;
  4081. Top := FCenter.X + FRadius.X;
  4082. Right := FCenter.Y - FRadius.Y;
  4083. Bottom := FCenter.Y + FRadius.Y;
  4084. end;
  4085. end;
  4086. procedure TRadialGradientPolygonFiller.UpdateRadiusScale;
  4087. begin
  4088. FRadScale := FRadius.X / FRadius.Y;
  4089. FRadXInv := 1 / FRadius.X;
  4090. end;
  4091. procedure TRadialGradientPolygonFiller.BeginRendering;
  4092. begin
  4093. if LookUpTableNeedsUpdate then
  4094. begin
  4095. if FUseLookUpTable then
  4096. begin
  4097. if not Assigned(FGradientLUT) then
  4098. raise Exception.Create(RCStrNoTColor32LookupTable);
  4099. if Assigned(FGradient) then
  4100. FGradient.FillColorLookUpTable(FGradientLUT);
  4101. end
  4102. else
  4103. if not Assigned(FGradient) then
  4104. raise Exception.Create(RCStrNoTColor32Gradient);
  4105. inherited;
  4106. end;
  4107. end;
  4108. function TRadialGradientPolygonFiller.GetFillLine: TFillLineEvent;
  4109. begin
  4110. case FWrapMode of
  4111. wmClamp:
  4112. Result := FillLineClamp;
  4113. wmMirror:
  4114. Result := FillLineMirror;
  4115. wmRepeat:
  4116. Result := FillLineRepeat;
  4117. {$ifdef GR32_WRAPMODE_REFLECT}
  4118. wmReflect:
  4119. Result := FillLineReflect;
  4120. {$endif}
  4121. end;
  4122. end;
  4123. procedure TRadialGradientPolygonFiller.FillLineClamp(Dst: PColor32; DstX,
  4124. DstY, Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  4125. var
  4126. X, Index, Count, Mask: Integer;
  4127. SqrRelRad, RadMax: TFloat;
  4128. ColorLUT: PColor32Array;
  4129. YDist, SqrInvRadius: TFloat;
  4130. Color32: TColor32;
  4131. BlendMemEx: TBlendMemEx;
  4132. begin
  4133. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  4134. Mask := Integer(FGradientLUT.Mask);
  4135. ColorLUT := FGradientLUT.Color32Ptr;
  4136. // small optimization
  4137. Index := Ceil(FCenter.X - FRadius.X);
  4138. if Index > DstX then
  4139. begin
  4140. Count := Min((Index - DstX), Length);
  4141. FillLineAlpha(Dst, AlphaValues, Count, ColorLUT^[Mask], CombineMode);
  4142. Length := Length - Count;
  4143. if Length = 0 then
  4144. Exit;
  4145. DstX := Index;
  4146. end;
  4147. // further optimization
  4148. if Abs(DstY - FCenter.Y) > FRadius.Y then
  4149. begin
  4150. FillLineAlpha(Dst, AlphaValues, Length, ColorLUT^[Mask], CombineMode);
  4151. Exit;
  4152. end;
  4153. SqrInvRadius := Sqr(FRadXInv);
  4154. YDist := Sqr((DstY - FCenter.Y) * FRadScale);
  4155. RadMax := (Sqr(FRadius.X) + YDist) * SqrInvRadius;
  4156. for X := DstX to DstX + Length - 1 do
  4157. begin
  4158. SqrRelRad := (Sqr(X - FCenter.X) + YDist) * SqrInvRadius;
  4159. // Clamp
  4160. if SqrRelRad > RadMax then
  4161. Index := Mask
  4162. else
  4163. Index := Min(Round(Mask * FastSqrt(SqrRelRad)), Mask);
  4164. Color32 := ColorLUT^[Index];
  4165. BlendMemEx(Color32, Dst^, AlphaValues^);
  4166. Inc(Dst);
  4167. Inc(AlphaValues);
  4168. end;
  4169. end;
  4170. procedure TRadialGradientPolygonFiller.FillLineReflect(Dst: PColor32;
  4171. DstX, DstY, Length: Integer; AlphaValues: PColor32;
  4172. CombineMode: TCombineMode);
  4173. var
  4174. X, Index, Mask: Integer;
  4175. SqrInvRadius: TFloat;
  4176. YDist: TFloat;
  4177. ColorLUT: PColor32Array;
  4178. ReflectProc: TWrapProc;
  4179. Color32: TColor32;
  4180. BlendMemEx: TBlendMemEx;
  4181. begin
  4182. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  4183. SqrInvRadius := Sqr(FRadXInv);
  4184. YDist := Sqr((DstY - FCenter.Y) * FRadScale);
  4185. Mask := Integer(FGradientLUT.Mask);
  4186. ColorLUT := FGradientLUT.Color32Ptr;
  4187. ReflectProc := GetOptimalReflect(FGradientLUT.Size-1);
  4188. for X := DstX to DstX + Length - 1 do
  4189. begin
  4190. Index := Round(Mask * FastSqrt((Sqr(X - FCenter.X) + YDist) * SqrInvRadius));
  4191. // Reflect
  4192. Index := ReflectProc(Index, FGradientLUT.Size-1);
  4193. (*
  4194. DivResult := DivMod(Index, FGradientLUT.Size, Index);
  4195. if Odd(DivResult) then
  4196. Index := Mask - Index;
  4197. *)
  4198. Color32 := ColorLUT^[Index];
  4199. BlendMemEx(Color32, Dst^, AlphaValues^);
  4200. Inc(Dst);
  4201. Inc(AlphaValues);
  4202. end;
  4203. end;
  4204. procedure TRadialGradientPolygonFiller.FillLineMirror(Dst: PColor32;
  4205. DstX, DstY, Length: Integer; AlphaValues: PColor32;
  4206. CombineMode: TCombineMode);
  4207. var
  4208. X, Index, Mask: Integer;
  4209. SqrInvRadius: TFloat;
  4210. YDist: TFloat;
  4211. ColorLUT: PColor32Array;
  4212. Color32: TColor32;
  4213. BlendMemEx: TBlendMemEx;
  4214. begin
  4215. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  4216. SqrInvRadius := Sqr(FRadXInv);
  4217. YDist := Sqr((DstY - FCenter.Y) * FRadScale);
  4218. Mask := Integer(FGradientLUT.Mask);
  4219. ColorLUT := FGradientLUT.Color32Ptr;
  4220. for X := DstX to DstX + Length - 1 do
  4221. begin
  4222. Index := Round(Mask * FastSqrt((Sqr(X - FCenter.X) + YDist) * SqrInvRadius));
  4223. // Mirror
  4224. Index := Mirror(Index, FGradientLUT.Size-1);
  4225. Color32 := ColorLUT^[Index];
  4226. BlendMemEx(Color32, Dst^, AlphaValues^);
  4227. Inc(Dst);
  4228. Inc(AlphaValues);
  4229. end;
  4230. end;
  4231. procedure TRadialGradientPolygonFiller.FillLineRepeat(Dst: PColor32;
  4232. DstX, DstY, Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
  4233. var
  4234. X, Mask: Integer;
  4235. Index: Integer;
  4236. YDist, SqrInvRadius: TFloat;
  4237. ColorLUT: PColor32Array;
  4238. WrapProc: TWrapProc;
  4239. Color32: TColor32;
  4240. BlendMemEx: TBlendMemEx;
  4241. begin
  4242. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  4243. SqrInvRadius := Sqr(FRadXInv);
  4244. YDist := Sqr((DstY - FCenter.Y) * FRadScale);
  4245. Mask := Integer(FGradientLUT.Mask);
  4246. ColorLUT := FGradientLUT.Color32Ptr;
  4247. WrapProc := GetOptimalWrap(FGradientLUT.Size-1);
  4248. for X := DstX to DstX + Length - 1 do
  4249. begin
  4250. // Wrap
  4251. Index := WrapProc(Round(Mask * FastSqrt((Sqr(X - FCenter.X) + YDist) * SqrInvRadius)), FGradientLUT.Size-1);
  4252. // Index := Round(Mask * FastSqrt((Sqr(X - FCenter.X) + YDist) * SqrInvRadius)) mod FGradientLUT.Size;
  4253. Color32 := ColorLUT^[Index];
  4254. BlendMemEx(Color32, Dst^, AlphaValues^);
  4255. Inc(Dst);
  4256. Inc(AlphaValues);
  4257. end;
  4258. end;
  4259. { TSVGRadialGradientPolygonFiller }
  4260. constructor TSVGRadialGradientPolygonFiller.Create(EllipseBounds: TFloatRect);
  4261. begin
  4262. inherited Create;
  4263. SetParameters(EllipseBounds);
  4264. end;
  4265. constructor TSVGRadialGradientPolygonFiller.Create(EllipseBounds: TFloatRect;
  4266. FocalPoint: TFloatPoint);
  4267. begin
  4268. inherited Create;
  4269. SetParameters(EllipseBounds, FocalPoint);
  4270. end;
  4271. procedure TSVGRadialGradientPolygonFiller.EllipseBoundsChanged;
  4272. begin
  4273. GradientFillerChanged;
  4274. end;
  4275. procedure TSVGRadialGradientPolygonFiller.SetFocalPoint(const Value: TFloatPoint);
  4276. begin
  4277. if (FFocalPointNative.X <> Value.X) and (FFocalPointNative.Y <> Value.Y) then
  4278. begin
  4279. FFocalPointNative := Value;
  4280. GradientFillerChanged;
  4281. end;
  4282. end;
  4283. procedure TSVGRadialGradientPolygonFiller.SetParameters(
  4284. EllipseBounds: TFloatRect);
  4285. begin
  4286. FEllipseBounds := EllipseBounds;
  4287. FFocalPointNative := FloatPoint(
  4288. 0.5 * (FEllipseBounds.Left + FEllipseBounds.Right),
  4289. 0.5 * (FEllipseBounds.Top + FEllipseBounds.Bottom));
  4290. GradientFillerChanged;
  4291. end;
  4292. procedure TSVGRadialGradientPolygonFiller.SetParameters(
  4293. EllipseBounds: TFloatRect; FocalPoint: TFloatPoint);
  4294. begin
  4295. FEllipseBounds := EllipseBounds;
  4296. FFocalPointNative := FocalPoint;
  4297. GradientFillerChanged;
  4298. end;
  4299. procedure TSVGRadialGradientPolygonFiller.InitMembers;
  4300. var
  4301. X, Y: TFloat;
  4302. Temp: TFloat;
  4303. begin
  4304. FRadius.X := (FEllipseBounds.Right - FEllipseBounds.Left) * 0.5;
  4305. FRadius.Y := (FEllipseBounds.Bottom - FEllipseBounds.Top) * 0.5;
  4306. FCenter.X := (FEllipseBounds.Right + FEllipseBounds.Left) * 0.5;
  4307. FCenter.Y := (FEllipseBounds.Bottom + FEllipseBounds.Top) * 0.5;
  4308. FOffset.X := FEllipseBounds.Left;
  4309. FOffset.Y := FEllipseBounds.Top;
  4310. // make FFocalPoint relative to the ellipse midpoint ...
  4311. FFocalPt.X := FFocalPointNative.X - FCenter.X;
  4312. FFocalPt.Y := FFocalPointNative.Y - FCenter.Y;
  4313. // make sure the focal point stays within the bounding ellipse ...
  4314. if Abs(FFocalPt.X) < CFloatTolerance then
  4315. begin
  4316. X := 0;
  4317. if FFocalPt.Y < 0 then
  4318. Y := -1
  4319. else
  4320. Y := 1;
  4321. end
  4322. else
  4323. begin
  4324. Temp := FRadius.X * FFocalPt.Y / (FRadius.Y * FFocalPt.X);
  4325. X := 1 / FastSqrtBab1(1 + Sqr(Temp));
  4326. Y := Temp * X;
  4327. end;
  4328. if FFocalPt.X < 0 then
  4329. begin
  4330. X := -X;
  4331. Y := -Y;
  4332. end;
  4333. X := X * FRadius.X;
  4334. Y := Y * FRadius.Y;
  4335. if (Y * Y + X * X) < (Sqr(FFocalPt.X) + Sqr(FFocalPt.Y)) then
  4336. begin
  4337. FFocalPt.X := 0.999 * X;
  4338. FFocalPt.Y := 0.999 * Y;
  4339. end;
  4340. // Because the slope of vertical lines is infinite, we need to find where a
  4341. // vertical line through the FocalPoint intersects with the Ellipse, and
  4342. // store the distances from the focal point to these 2 intersections points
  4343. FVertDist := FRadius.Y * FastSqrtBab1(1.0 - Sqr(FFocalPt.X) / Sqr(FRadius.X));
  4344. end;
  4345. procedure TSVGRadialGradientPolygonFiller.BeginRendering;
  4346. begin
  4347. if LookUpTableNeedsUpdate then
  4348. begin
  4349. if FUseLookUpTable then
  4350. begin
  4351. if not Assigned(FGradientLUT) then
  4352. raise Exception.Create(RCStrNoTColor32LookupTable);
  4353. if Assigned(FGradient) then
  4354. FGradient.FillColorLookUpTable(FGradientLUT);
  4355. end
  4356. else
  4357. if not Assigned(FGradient) then
  4358. raise Exception.Create(RCStrNoTColor32Gradient);
  4359. inherited;
  4360. end;
  4361. InitMembers;
  4362. end;
  4363. function TSVGRadialGradientPolygonFiller.GetFillLine: TFillLineEvent;
  4364. begin
  4365. Result := FillLineEllipse;
  4366. end;
  4367. procedure TSVGRadialGradientPolygonFiller.FillLineEllipse(Dst: PColor32;
  4368. DstX, DstY, Length: Integer; AlphaValues: PColor32;
  4369. CombineMode: TCombineMode);
  4370. var
  4371. X, Mask: Integer;
  4372. ColorLUT: PColor32Array;
  4373. Rad, Rad2, X2, Y2: TFloat;
  4374. m, b, Qa, Qb, Qc, Qz, XSqr: Double;
  4375. RelPos: TFloatPoint;
  4376. Color32: TColor32;
  4377. BlendMemEx: TBlendMemEx;
  4378. begin
  4379. BlendMemEx := BLEND_MEM_EX[CombineMode]^;
  4380. if (FRadius.X = 0) or (FRadius.Y = 0) then
  4381. Exit;
  4382. ColorLUT := FGradientLUT.Color32Ptr;
  4383. RelPos.Y := DstY - FCenter.Y - FFocalPt.Y;
  4384. Mask := Integer(FGradientLUT.Mask);
  4385. // check if out of bounds (vertically)
  4386. if (DstY < FOffset.Y) or (DstY >= (FRadius.Y * 2) + 1 + FOffset.Y) then
  4387. begin
  4388. FillLineAlpha(Dst, AlphaValues, Length, ColorLUT^[Mask], CombineMode);
  4389. Exit;
  4390. end;
  4391. for X := DstX to DstX + Length - 1 do
  4392. begin
  4393. // check if out of bounds (horizontally)
  4394. if (X < FOffset.X) or (X >= (FRadius.X * 2) + 1 + FOffset.X) then
  4395. Color32 := ColorLUT^[Mask]
  4396. else
  4397. begin
  4398. RelPos.X := X - FCenter.X - FFocalPt.X;
  4399. if Abs(RelPos.X) < CFloatTolerance then //ie on the vertical line (see above)
  4400. begin
  4401. Assert(Abs(X - FCenter.X) <= FRadius.X);
  4402. Rad := Abs(RelPos.Y);
  4403. if Abs(Abs(X - FCenter.X)) <= FRadius.X then
  4404. begin
  4405. if RelPos.Y < 0 then
  4406. Rad2 := Abs(-FVertDist - FFocalPt.Y)
  4407. else
  4408. Rad2 := Abs( FVertDist - FFocalPt.Y);
  4409. if Rad >= Rad2 then
  4410. Color32 := ColorLUT^[Mask]
  4411. else
  4412. Color32 := ColorLUT^[Round(Mask * Rad / Rad2)];
  4413. end else
  4414. Color32 := ColorLUT^[Mask];
  4415. end
  4416. else
  4417. begin
  4418. m := RelPos.Y / RelPos.X;
  4419. b := FFocalPt.Y - m * FFocalPt.X;
  4420. XSqr := Sqr(FRadius.X);
  4421. // apply quadratic equation ...
  4422. Qa := 2 * (Sqr(FRadius.Y) + XSqr * m * m);
  4423. Qb := XSqr * 2 * m * b;
  4424. Qc := XSqr * (b * b - Sqr(FRadius.Y));
  4425. Qz := Qb * Qb - 2 * Qa * Qc;
  4426. if Qz >= 0 then
  4427. begin
  4428. Qz := FastSqrtBab2(Qz);
  4429. Qa := 1 / Qa;
  4430. X2 := (-Qb + Qz) * Qa;
  4431. if (FFocalPt.X > X2) = (RelPos.X > 0) then
  4432. X2 := -(Qb + Qz) * Qa;
  4433. Y2 := m * X2 + b;
  4434. Rad := Sqr(RelPos.X) + Sqr(RelPos.Y);
  4435. Rad2 := Sqr(X2 - FFocalPt.X) + Sqr(Y2 - FFocalPt.Y);
  4436. if Rad >= Rad2 then
  4437. Color32 := ColorLUT^[Mask]
  4438. else
  4439. Color32 := ColorLUT^[Round(Mask * FastSqrtBab1(Rad / Rad2))];
  4440. end else
  4441. Color32 := ColorLUT^[Mask]
  4442. end;
  4443. end;
  4444. BlendMemEx(Color32, Dst^, AlphaValues^);
  4445. Inc(Dst);
  4446. Inc(AlphaValues);
  4447. end;
  4448. end;
  4449. procedure RegisterBindings;
  4450. begin
  4451. GradientRegistry := NewRegistry('GR32_ColorGradients bindings');
  4452. GradientRegistry.RegisterBinding(FID_LINEAR3, @@Linear3PointInterpolation, 'Linear3PointInterpolation');
  4453. GradientRegistry.RegisterBinding(FID_LINEAR4, @@Linear4PointInterpolation, 'Linear4PointInterpolation');
  4454. // Pure pascal
  4455. GradientRegistry[@@Linear3PointInterpolation].Add(@Linear3PointInterpolation_Pas, [isPascal]).name := 'Linear3PointInterpolation_Pas';
  4456. GradientRegistry[@@Linear4PointInterpolation].Add(@Linear4PointInterpolation_Pas, [isPascal]).Name := 'Linear4PointInterpolation_Pas';
  4457. {$IFNDEF PUREPASCAL}
  4458. {$IFNDEF OMIT_SSE2}
  4459. GradientRegistry[@@Linear3PointInterpolation].Add(@Linear3PointInterpolation_SSE2, [isSSE2]).Name := 'Linear3PointInterpolation_SSE2';
  4460. GradientRegistry[@@Linear4PointInterpolation].Add(@Linear4PointInterpolation_SSE2, [isSSE2]).Name := 'Linear4PointInterpolation_SSE2';
  4461. {$ENDIF}
  4462. {$ENDIF}
  4463. GradientRegistry.RebindAll;
  4464. end;
  4465. initialization
  4466. RegisterBindings;
  4467. end.