GR32_ColorGradients.pas 134 KB

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